|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // security - hide paths 00003 if (!defined('ADODB_DIR')) die(); 00004 00005 global $ADODB_INCLUDED_LIB; 00006 $ADODB_INCLUDED_LIB = 1; 00007 00008 /* 00009 @version V5.14 8 Sept 2011 (c) 2000-2011 John Lim (jlim#natsoft.com). All rights reserved. 00010 Released under both BSD license and Lesser GPL library license. 00011 Whenever there is any discrepancy between the two licenses, 00012 the BSD license will take precedence. See License.txt. 00013 Set tabs to 4 for best viewing. 00014 00015 Less commonly used functions are placed here to reduce size of adodb.inc.php. 00016 */ 00017 00018 function adodb_strip_order_by($sql) 00019 { 00020 $rez = preg_match('/(\sORDER\s+BY\s[^)]*)/is',$sql,$arr); 00021 if ($arr) 00022 if (strpos($arr[0],'(') !== false) { 00023 $at = strpos($sql,$arr[0]); 00024 $cntin = 0; 00025 for ($i=$at, $max=strlen($sql); $i < $max; $i++) { 00026 $ch = $sql[$i]; 00027 if ($ch == '(') { 00028 $cntin += 1; 00029 } elseif($ch == ')') { 00030 $cntin -= 1; 00031 if ($cntin < 0) { 00032 break; 00033 } 00034 } 00035 } 00036 $sql = substr($sql,0,$at).substr($sql,$i); 00037 } else 00038 $sql = str_replace($arr[0], '', $sql); 00039 return $sql; 00040 } 00041 00042 if (false) { 00043 $sql = 'select * from (select a from b order by a(b),b(c) desc)'; 00044 $sql = '(select * from abc order by 1)'; 00045 die(adodb_strip_order_by($sql)); 00046 } 00047 00048 function adodb_probetypes(&$array,&$types,$probe=8) 00049 { 00050 // probe and guess the type 00051 $types = array(); 00052 if ($probe > sizeof($array)) $max = sizeof($array); 00053 else $max = $probe; 00054 00055 00056 for ($j=0;$j < $max; $j++) { 00057 $row = $array[$j]; 00058 if (!$row) break; 00059 $i = -1; 00060 foreach($row as $v) { 00061 $i += 1; 00062 00063 if (isset($types[$i]) && $types[$i]=='C') continue; 00064 00065 //print " ($i ".$types[$i]. "$v) "; 00066 $v = trim($v); 00067 00068 if (!preg_match('/^[+-]{0,1}[0-9\.]+$/',$v)) { 00069 $types[$i] = 'C'; // once C, always C 00070 00071 continue; 00072 } 00073 if ($j == 0) { 00074 // If empty string, we presume is character 00075 // test for integer for 1st row only 00076 // after that it is up to testing other rows to prove 00077 // that it is not an integer 00078 if (strlen($v) == 0) $types[$i] = 'C'; 00079 if (strpos($v,'.') !== false) $types[$i] = 'N'; 00080 else $types[$i] = 'I'; 00081 continue; 00082 } 00083 00084 if (strpos($v,'.') !== false) $types[$i] = 'N'; 00085 00086 } 00087 } 00088 00089 } 00090 00091 function adodb_transpose(&$arr, &$newarr, &$hdr, &$fobjs) 00092 { 00093 $oldX = sizeof(reset($arr)); 00094 $oldY = sizeof($arr); 00095 00096 if ($hdr) { 00097 $startx = 1; 00098 $hdr = array('Fields'); 00099 for ($y = 0; $y < $oldY; $y++) { 00100 $hdr[] = $arr[$y][0]; 00101 } 00102 } else 00103 $startx = 0; 00104 00105 for ($x = $startx; $x < $oldX; $x++) { 00106 if ($fobjs) { 00107 $o = $fobjs[$x]; 00108 $newarr[] = array($o->name); 00109 } else 00110 $newarr[] = array(); 00111 00112 for ($y = 0; $y < $oldY; $y++) { 00113 $newarr[$x-$startx][] = $arr[$y][$x]; 00114 } 00115 } 00116 } 00117 00118 // Force key to upper. 00119 // See also http://www.php.net/manual/en/function.array-change-key-case.php 00120 function _array_change_key_case($an_array) 00121 { 00122 if (is_array($an_array)) { 00123 $new_array = array(); 00124 foreach($an_array as $key=>$value) 00125 $new_array[strtoupper($key)] = $value; 00126 00127 return $new_array; 00128 } 00129 00130 return $an_array; 00131 } 00132 00133 function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc) 00134 { 00135 if (count($fieldArray) == 0) return 0; 00136 $first = true; 00137 $uSet = ''; 00138 00139 if (!is_array($keyCol)) { 00140 $keyCol = array($keyCol); 00141 } 00142 foreach($fieldArray as $k => $v) { 00143 if ($v === null) { 00144 $v = 'NULL'; 00145 $fieldArray[$k] = $v; 00146 } else if ($autoQuote && strcasecmp($v,$zthis->null2null)!=0) { 00147 $v = $zthis->qstr($v); 00148 $fieldArray[$k] = $v; 00149 } 00150 if (in_array($k,$keyCol)) continue; // skip UPDATE if is key 00151 00152 if ($first) { 00153 $first = false; 00154 $uSet = "$k=$v"; 00155 } else 00156 $uSet .= ",$k=$v"; 00157 } 00158 00159 $where = false; 00160 foreach ($keyCol as $v) { 00161 if (isset($fieldArray[$v])) { 00162 if ($where) $where .= ' and '.$v.'='.$fieldArray[$v]; 00163 else $where = $v.'='.$fieldArray[$v]; 00164 } 00165 } 00166 00167 if ($uSet && $where) { 00168 $update = "UPDATE $table SET $uSet WHERE $where"; 00169 00170 $rs = $zthis->Execute($update); 00171 00172 00173 if ($rs) { 00174 if ($zthis->poorAffectedRows) { 00175 /* 00176 The Select count(*) wipes out any errors that the update would have returned. 00177 http://phplens.com/lens/lensforum/msgs.php?id=5696 00178 */ 00179 if ($zthis->ErrorNo()<>0) return 0; 00180 00181 # affected_rows == 0 if update field values identical to old values 00182 # for mysql - which is silly. 00183 00184 $cnt = $zthis->GetOne("select count(*) from $table where $where"); 00185 if ($cnt > 0) return 1; // record already exists 00186 } else { 00187 if (($zthis->Affected_Rows()>0)) return 1; 00188 } 00189 } else 00190 return 0; 00191 } 00192 00193 // print "<p>Error=".$this->ErrorNo().'<p>'; 00194 $first = true; 00195 foreach($fieldArray as $k => $v) { 00196 if ($has_autoinc && in_array($k,$keyCol)) continue; // skip autoinc col 00197 00198 if ($first) { 00199 $first = false; 00200 $iCols = "$k"; 00201 $iVals = "$v"; 00202 } else { 00203 $iCols .= ",$k"; 00204 $iVals .= ",$v"; 00205 } 00206 } 00207 $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)"; 00208 $rs = $zthis->Execute($insert); 00209 return ($rs) ? 2 : 0; 00210 } 00211 00212 // Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM 00213 function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false, 00214 $size=0, $selectAttr='',$compareFields0=true) 00215 { 00216 $hasvalue = false; 00217 00218 if ($multiple or is_array($defstr)) { 00219 if ($size==0) $size=5; 00220 $attr = ' multiple size="'.$size.'"'; 00221 if (!strpos($name,'[]')) $name .= '[]'; 00222 } else if ($size) $attr = ' size="'.$size.'"'; 00223 else $attr =''; 00224 00225 $s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>'; 00226 if ($blank1stItem) 00227 if (is_string($blank1stItem)) { 00228 $barr = explode(':',$blank1stItem); 00229 if (sizeof($barr) == 1) $barr[] = ''; 00230 $s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>"; 00231 } else $s .= "\n<option></option>"; 00232 00233 if ($zthis->FieldCount() > 1) $hasvalue=true; 00234 else $compareFields0 = true; 00235 00236 $value = ''; 00237 $optgroup = null; 00238 $firstgroup = true; 00239 $fieldsize = $zthis->FieldCount(); 00240 while(!$zthis->EOF) { 00241 $zval = rtrim(reset($zthis->fields)); 00242 00243 if ($blank1stItem && $zval=="") { 00244 $zthis->MoveNext(); 00245 continue; 00246 } 00247 00248 if ($fieldsize > 1) { 00249 if (isset($zthis->fields[1])) 00250 $zval2 = rtrim($zthis->fields[1]); 00251 else 00252 $zval2 = rtrim(next($zthis->fields)); 00253 } 00254 $selected = ($compareFields0) ? $zval : $zval2; 00255 00256 $group = ''; 00257 if ($fieldsize > 2) { 00258 $group = rtrim($zthis->fields[2]); 00259 } 00260 /* 00261 if ($optgroup != $group) { 00262 $optgroup = $group; 00263 if ($firstgroup) { 00264 $firstgroup = false; 00265 $s .="\n<optgroup label='". htmlspecialchars($group) ."'>"; 00266 } else { 00267 $s .="\n</optgroup>"; 00268 $s .="\n<optgroup label='". htmlspecialchars($group) ."'>"; 00269 } 00270 } 00271 */ 00272 if ($hasvalue) 00273 $value = " value='".htmlspecialchars($zval2)."'"; 00274 00275 if (is_array($defstr)) { 00276 00277 if (in_array($selected,$defstr)) 00278 $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>'; 00279 else 00280 $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>'; 00281 } 00282 else { 00283 if (strcasecmp($selected,$defstr)==0) 00284 $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>'; 00285 else 00286 $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>'; 00287 } 00288 $zthis->MoveNext(); 00289 } // while 00290 00291 // closing last optgroup 00292 if($optgroup != null) { 00293 $s .= "\n</optgroup>"; 00294 } 00295 return $s ."\n</select>\n"; 00296 } 00297 00298 // Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM 00299 function _adodb_getmenu_gp(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false, 00300 $size=0, $selectAttr='',$compareFields0=true) 00301 { 00302 $hasvalue = false; 00303 00304 if ($multiple or is_array($defstr)) { 00305 if ($size==0) $size=5; 00306 $attr = ' multiple size="'.$size.'"'; 00307 if (!strpos($name,'[]')) $name .= '[]'; 00308 } else if ($size) $attr = ' size="'.$size.'"'; 00309 else $attr =''; 00310 00311 $s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>'; 00312 if ($blank1stItem) 00313 if (is_string($blank1stItem)) { 00314 $barr = explode(':',$blank1stItem); 00315 if (sizeof($barr) == 1) $barr[] = ''; 00316 $s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>"; 00317 } else $s .= "\n<option></option>"; 00318 00319 if ($zthis->FieldCount() > 1) $hasvalue=true; 00320 else $compareFields0 = true; 00321 00322 $value = ''; 00323 $optgroup = null; 00324 $firstgroup = true; 00325 $fieldsize = sizeof($zthis->fields); 00326 while(!$zthis->EOF) { 00327 $zval = rtrim(reset($zthis->fields)); 00328 00329 if ($blank1stItem && $zval=="") { 00330 $zthis->MoveNext(); 00331 continue; 00332 } 00333 00334 if ($fieldsize > 1) { 00335 if (isset($zthis->fields[1])) 00336 $zval2 = rtrim($zthis->fields[1]); 00337 else 00338 $zval2 = rtrim(next($zthis->fields)); 00339 } 00340 $selected = ($compareFields0) ? $zval : $zval2; 00341 00342 $group = ''; 00343 if (isset($zthis->fields[2])) { 00344 $group = rtrim($zthis->fields[2]); 00345 } 00346 00347 if ($optgroup != $group) { 00348 $optgroup = $group; 00349 if ($firstgroup) { 00350 $firstgroup = false; 00351 $s .="\n<optgroup label='". htmlspecialchars($group) ."'>"; 00352 } else { 00353 $s .="\n</optgroup>"; 00354 $s .="\n<optgroup label='". htmlspecialchars($group) ."'>"; 00355 } 00356 } 00357 00358 if ($hasvalue) 00359 $value = " value='".htmlspecialchars($zval2)."'"; 00360 00361 if (is_array($defstr)) { 00362 00363 if (in_array($selected,$defstr)) 00364 $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>'; 00365 else 00366 $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>'; 00367 } 00368 else { 00369 if (strcasecmp($selected,$defstr)==0) 00370 $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>'; 00371 else 00372 $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>'; 00373 } 00374 $zthis->MoveNext(); 00375 } // while 00376 00377 // closing last optgroup 00378 if($optgroup != null) { 00379 $s .= "\n</optgroup>"; 00380 } 00381 return $s ."\n</select>\n"; 00382 } 00383 00384 00385 /* 00386 Count the number of records this sql statement will return by using 00387 query rewriting heuristics... 00388 00389 Does not work with UNIONs, except with postgresql and oracle. 00390 00391 Usage: 00392 00393 $conn->Connect(...); 00394 $cnt = _adodb_getcount($conn, $sql); 00395 00396 */ 00397 function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0) 00398 { 00399 $qryRecs = 0; 00400 00401 if (!empty($zthis->_nestedSQL) || preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) || 00402 preg_match('/\s+GROUP\s+BY\s+/is',$sql) || 00403 preg_match('/\s+UNION\s+/is',$sql)) { 00404 00405 $rewritesql = adodb_strip_order_by($sql); 00406 00407 // ok, has SELECT DISTINCT or GROUP BY so see if we can use a table alias 00408 // but this is only supported by oracle and postgresql... 00409 if ($zthis->dataProvider == 'oci8') { 00410 // Allow Oracle hints to be used for query optimization, Chris Wrye 00411 if (preg_match('#/\\*+.*?\\*\\/#', $sql, $hint)) { 00412 $rewritesql = "SELECT ".$hint[0]." COUNT(*) FROM (".$rewritesql.")"; 00413 } else 00414 $rewritesql = "SELECT COUNT(*) FROM (".$rewritesql.")"; 00415 00416 } else if (strncmp($zthis->databaseType,'postgres',8) == 0 || strncmp($zthis->databaseType,'mysql',5) == 0) { 00417 $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) _ADODB_ALIAS_"; 00418 } else { 00419 $rewritesql = "SELECT COUNT(*) FROM ($rewritesql)"; 00420 } 00421 } else { 00422 // now replace SELECT ... FROM with SELECT COUNT(*) FROM 00423 $rewritesql = preg_replace( 00424 '/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql); 00425 // fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails 00426 // with mssql, access and postgresql. Also a good speedup optimization - skips sorting! 00427 // also see http://phplens.com/lens/lensforum/msgs.php?id=12752 00428 $rewritesql = adodb_strip_order_by($rewritesql); 00429 } 00430 00431 if (isset($rewritesql) && $rewritesql != $sql) { 00432 if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0]; 00433 00434 if ($secs2cache) { 00435 // we only use half the time of secs2cache because the count can quickly 00436 // become inaccurate if new records are added 00437 $qryRecs = $zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr); 00438 00439 } else { 00440 $qryRecs = $zthis->GetOne($rewritesql,$inputarr); 00441 } 00442 if ($qryRecs !== false) return $qryRecs; 00443 } 00444 //-------------------------------------------- 00445 // query rewrite failed - so try slower way... 00446 00447 00448 // strip off unneeded ORDER BY if no UNION 00449 if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql; 00450 else $rewritesql = $rewritesql = adodb_strip_order_by($sql); 00451 00452 if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0]; 00453 00454 if ($secs2cache) { 00455 $rstest = $zthis->CacheExecute($secs2cache,$rewritesql,$inputarr); 00456 if (!$rstest) $rstest = $zthis->CacheExecute($secs2cache,$sql,$inputarr); 00457 } else { 00458 $rstest = $zthis->Execute($rewritesql,$inputarr); 00459 if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr); 00460 } 00461 if ($rstest) { 00462 $qryRecs = $rstest->RecordCount(); 00463 if ($qryRecs == -1) { 00464 global $ADODB_EXTENSION; 00465 // some databases will return -1 on MoveLast() - change to MoveNext() 00466 if ($ADODB_EXTENSION) { 00467 while(!$rstest->EOF) { 00468 adodb_movenext($rstest); 00469 } 00470 } else { 00471 while(!$rstest->EOF) { 00472 $rstest->MoveNext(); 00473 } 00474 } 00475 $qryRecs = $rstest->_currentRow; 00476 } 00477 $rstest->Close(); 00478 if ($qryRecs == -1) return 0; 00479 } 00480 return $qryRecs; 00481 } 00482 00483 /* 00484 Code originally from "Cornel G" <conyg@fx.ro> 00485 00486 This code might not work with SQL that has UNION in it 00487 00488 Also if you are using CachePageExecute(), there is a strong possibility that 00489 data will get out of synch. use CachePageExecute() only with tables that 00490 rarely change. 00491 */ 00492 function _adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page, 00493 $inputarr=false, $secs2cache=0) 00494 { 00495 $atfirstpage = false; 00496 $atlastpage = false; 00497 $lastpageno=1; 00498 00499 // If an invalid nrows is supplied, 00500 // we assume a default value of 10 rows per page 00501 if (!isset($nrows) || $nrows <= 0) $nrows = 10; 00502 00503 $qryRecs = false; //count records for no offset 00504 00505 $qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache); 00506 $lastpageno = (int) ceil($qryRecs / $nrows); 00507 $zthis->_maxRecordCount = $qryRecs; 00508 00509 00510 00511 // ***** Here we check whether $page is the last page or 00512 // whether we are trying to retrieve 00513 // a page number greater than the last page number. 00514 if ($page >= $lastpageno) { 00515 $page = $lastpageno; 00516 $atlastpage = true; 00517 } 00518 00519 // If page number <= 1, then we are at the first page 00520 if (empty($page) || $page <= 1) { 00521 $page = 1; 00522 $atfirstpage = true; 00523 } 00524 00525 // We get the data we want 00526 $offset = $nrows * ($page-1); 00527 if ($secs2cache > 0) 00528 $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr); 00529 else 00530 $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache); 00531 00532 00533 // Before returning the RecordSet, we set the pagination properties we need 00534 if ($rsreturn) { 00535 $rsreturn->_maxRecordCount = $qryRecs; 00536 $rsreturn->rowsPerPage = $nrows; 00537 $rsreturn->AbsolutePage($page); 00538 $rsreturn->AtFirstPage($atfirstpage); 00539 $rsreturn->AtLastPage($atlastpage); 00540 $rsreturn->LastPageNo($lastpageno); 00541 } 00542 return $rsreturn; 00543 } 00544 00545 // Iván Oliva version 00546 function _adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0) 00547 { 00548 00549 $atfirstpage = false; 00550 $atlastpage = false; 00551 00552 if (!isset($page) || $page <= 1) { // If page number <= 1, then we are at the first page 00553 $page = 1; 00554 $atfirstpage = true; 00555 } 00556 if ($nrows <= 0) $nrows = 10; // If an invalid nrows is supplied, we assume a default value of 10 rows per page 00557 00558 // ***** Here we check whether $page is the last page or whether we are trying to retrieve a page number greater than 00559 // the last page number. 00560 $pagecounter = $page + 1; 00561 $pagecounteroffset = ($pagecounter * $nrows) - $nrows; 00562 if ($secs2cache>0) $rstest = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr); 00563 else $rstest = $zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache); 00564 if ($rstest) { 00565 while ($rstest && $rstest->EOF && $pagecounter>0) { 00566 $atlastpage = true; 00567 $pagecounter--; 00568 $pagecounteroffset = $nrows * ($pagecounter - 1); 00569 $rstest->Close(); 00570 if ($secs2cache>0) $rstest = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr); 00571 else $rstest = $zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache); 00572 } 00573 if ($rstest) $rstest->Close(); 00574 } 00575 if ($atlastpage) { // If we are at the last page or beyond it, we are going to retrieve it 00576 $page = $pagecounter; 00577 if ($page == 1) $atfirstpage = true; // We have to do this again in case the last page is the same as the first 00578 //... page, that is, the recordset has only 1 page. 00579 } 00580 00581 // We get the data we want 00582 $offset = $nrows * ($page-1); 00583 if ($secs2cache > 0) $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr); 00584 else $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache); 00585 00586 // Before returning the RecordSet, we set the pagination properties we need 00587 if ($rsreturn) { 00588 $rsreturn->rowsPerPage = $nrows; 00589 $rsreturn->AbsolutePage($page); 00590 $rsreturn->AtFirstPage($atfirstpage); 00591 $rsreturn->AtLastPage($atlastpage); 00592 } 00593 return $rsreturn; 00594 } 00595 00596 function _adodb_getupdatesql(&$zthis,&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=2) 00597 { 00598 global $ADODB_QUOTE_FIELDNAMES; 00599 00600 if (!$rs) { 00601 printf(ADODB_BAD_RS,'GetUpdateSQL'); 00602 return false; 00603 } 00604 00605 $fieldUpdatedCount = 0; 00606 $arrFields = _array_change_key_case($arrFields); 00607 00608 $hasnumeric = isset($rs->fields[0]); 00609 $setFields = ''; 00610 00611 // Loop through all of the fields in the recordset 00612 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) { 00613 // Get the field from the recordset 00614 $field = $rs->FetchField($i); 00615 00616 // If the recordset field is one 00617 // of the fields passed in then process. 00618 $upperfname = strtoupper($field->name); 00619 if (adodb_key_exists($upperfname,$arrFields,$force)) { 00620 00621 // If the existing field value in the recordset 00622 // is different from the value passed in then 00623 // go ahead and append the field name and new value to 00624 // the update query. 00625 00626 if ($hasnumeric) $val = $rs->fields[$i]; 00627 else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname]; 00628 else if (isset($rs->fields[$field->name])) $val = $rs->fields[$field->name]; 00629 else if (isset($rs->fields[strtolower($upperfname)])) $val = $rs->fields[strtolower($upperfname)]; 00630 else $val = ''; 00631 00632 00633 if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) { 00634 // Set the counter for the number of fields that will be updated. 00635 $fieldUpdatedCount++; 00636 00637 // Based on the datatype of the field 00638 // Format the value properly for the database 00639 $type = $rs->MetaType($field->type); 00640 00641 00642 if ($type == 'null') { 00643 $type = 'C'; 00644 } 00645 00646 if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES)) { 00647 switch (ADODB_QUOTE_FIELDNAMES) { 00648 case 'LOWER': 00649 $fnameq = $zthis->nameQuote.strtolower($field->name).$zthis->nameQuote;break; 00650 case 'NATIVE': 00651 $fnameq = $zthis->nameQuote.$field->name.$zthis->nameQuote;break; 00652 case 'UPPER': 00653 default: 00654 $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;break; 00655 } 00656 } else 00657 $fnameq = $upperfname; 00658 00659 00660 // is_null requires php 4.0.4 00661 //********************************************************// 00662 if (is_null($arrFields[$upperfname]) 00663 || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0) 00664 || $arrFields[$upperfname] === $zthis->null2null 00665 ) 00666 { 00667 switch ($force) { 00668 00669 //case 0: 00670 // //Ignore empty values. This is allready handled in "adodb_key_exists" function. 00671 //break; 00672 00673 case 1: 00674 //Set null 00675 $setFields .= $field->name . " = null, "; 00676 break; 00677 00678 case 2: 00679 //Set empty 00680 $arrFields[$upperfname] = ""; 00681 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq); 00682 break; 00683 default: 00684 case 3: 00685 //Set the value that was given in array, so you can give both null and empty values 00686 if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) { 00687 $setFields .= $field->name . " = null, "; 00688 } else { 00689 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq); 00690 } 00691 break; 00692 } 00693 //********************************************************// 00694 } else { 00695 //we do this so each driver can customize the sql for 00696 //DB specific column types. 00697 //Oracle needs BLOB types to be handled with a returning clause 00698 //postgres has special needs as well 00699 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq, 00700 $arrFields, $magicq); 00701 } 00702 } 00703 } 00704 } 00705 00706 // If there were any modified fields then build the rest of the update query. 00707 if ($fieldUpdatedCount > 0 || $forceUpdate) { 00708 // Get the table name from the existing query. 00709 if (!empty($rs->tableName)) $tableName = $rs->tableName; 00710 else { 00711 preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName); 00712 $tableName = $tableName[1]; 00713 } 00714 // Get the full where clause excluding the word "WHERE" from 00715 // the existing query. 00716 preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause); 00717 00718 $discard = false; 00719 // not a good hack, improvements? 00720 if ($whereClause) { 00721 #var_dump($whereClause); 00722 if (preg_match('/\s(ORDER\s.*)/is', $whereClause[1], $discard)); 00723 else if (preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard)); 00724 else if (preg_match('/\s(FOR UPDATE.*)/is', $whereClause[1], $discard)); 00725 else preg_match('/\s.*(\) WHERE .*)/is', $whereClause[1], $discard); # see http://sourceforge.net/tracker/index.php?func=detail&aid=1379638&group_id=42718&atid=433976 00726 } else 00727 $whereClause = array(false,false); 00728 00729 if ($discard) 00730 $whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1])); 00731 00732 $sql = 'UPDATE '.$tableName.' SET '.substr($setFields, 0, -2); 00733 if (strlen($whereClause[1]) > 0) 00734 $sql .= ' WHERE '.$whereClause[1]; 00735 00736 return $sql; 00737 00738 } else { 00739 return false; 00740 } 00741 } 00742 00743 function adodb_key_exists($key, &$arr,$force=2) 00744 { 00745 if ($force<=0) { 00746 // the following is the old behaviour where null or empty fields are ignored 00747 return (!empty($arr[$key])) || (isset($arr[$key]) && strlen($arr[$key])>0); 00748 } 00749 00750 if (isset($arr[$key])) return true; 00751 ## null check below 00752 if (ADODB_PHPVER >= 0x4010) return array_key_exists($key,$arr); 00753 return false; 00754 } 00755 00763 function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2) 00764 { 00765 static $cacheRS = false; 00766 static $cacheSig = 0; 00767 static $cacheCols; 00768 global $ADODB_QUOTE_FIELDNAMES; 00769 00770 $tableName = ''; 00771 $values = ''; 00772 $fields = ''; 00773 $recordSet = null; 00774 $arrFields = _array_change_key_case($arrFields); 00775 $fieldInsertedCount = 0; 00776 00777 if (is_string($rs)) { 00778 //ok we have a table name 00779 //try and get the column info ourself. 00780 $tableName = $rs; 00781 00782 //we need an object for the recordSet 00783 //because we have to call MetaType. 00784 //php can't do a $rsclass::MetaType() 00785 $rsclass = $zthis->rsPrefix.$zthis->databaseType; 00786 $recordSet = new $rsclass(-1,$zthis->fetchMode); 00787 $recordSet->connection = $zthis; 00788 00789 if (is_string($cacheRS) && $cacheRS == $rs) { 00790 $columns = $cacheCols; 00791 } else { 00792 $columns = $zthis->MetaColumns( $tableName ); 00793 $cacheRS = $tableName; 00794 $cacheCols = $columns; 00795 } 00796 } else if (is_subclass_of($rs, 'adorecordset')) { 00797 if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS == $rs->insertSig) { 00798 $columns = $cacheCols; 00799 } else { 00800 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) 00801 $columns[] = $rs->FetchField($i); 00802 $cacheRS = $cacheSig; 00803 $cacheCols = $columns; 00804 $rs->insertSig = $cacheSig++; 00805 } 00806 $recordSet = $rs; 00807 00808 } else { 00809 printf(ADODB_BAD_RS,'GetInsertSQL'); 00810 return false; 00811 } 00812 00813 // Loop through all of the fields in the recordset 00814 foreach( $columns as $field ) { 00815 $upperfname = strtoupper($field->name); 00816 if (adodb_key_exists($upperfname,$arrFields,$force)) { 00817 $bad = false; 00818 if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES)) { 00819 switch (ADODB_QUOTE_FIELDNAMES) { 00820 case 'LOWER': 00821 $fnameq = $zthis->nameQuote.strtolower($field->name).$zthis->nameQuote;break; 00822 case 'NATIVE': 00823 $fnameq = $zthis->nameQuote.$field->name.$zthis->nameQuote;break; 00824 case 'UPPER': 00825 default: 00826 $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;break; 00827 } 00828 } else 00829 $fnameq = $upperfname; 00830 00831 $type = $recordSet->MetaType($field->type); 00832 00833 /********************************************************/ 00834 if (is_null($arrFields[$upperfname]) 00835 || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0) 00836 || $arrFields[$upperfname] === $zthis->null2null 00837 ) 00838 { 00839 switch ($force) { 00840 00841 case 0: // we must always set null if missing 00842 $bad = true; 00843 break; 00844 00845 case 1: 00846 $values .= "null, "; 00847 break; 00848 00849 case 2: 00850 //Set empty 00851 $arrFields[$upperfname] = ""; 00852 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,$arrFields, $magicq); 00853 break; 00854 00855 default: 00856 case 3: 00857 //Set the value that was given in array, so you can give both null and empty values 00858 if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) { 00859 $values .= "null, "; 00860 } else { 00861 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields, $magicq); 00862 } 00863 break; 00864 } // switch 00865 00866 /*********************************************************/ 00867 } else { 00868 //we do this so each driver can customize the sql for 00869 //DB specific column types. 00870 //Oracle needs BLOB types to be handled with a returning clause 00871 //postgres has special needs as well 00872 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, 00873 $arrFields, $magicq); 00874 } 00875 00876 if ($bad) continue; 00877 // Set the counter for the number of fields that will be inserted. 00878 $fieldInsertedCount++; 00879 00880 00881 // Get the name of the fields to insert 00882 $fields .= $fnameq . ", "; 00883 } 00884 } 00885 00886 00887 // If there were any inserted fields then build the rest of the insert query. 00888 if ($fieldInsertedCount <= 0) return false; 00889 00890 // Get the table name from the existing query. 00891 if (!$tableName) { 00892 if (!empty($rs->tableName)) $tableName = $rs->tableName; 00893 else if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName)) 00894 $tableName = $tableName[1]; 00895 else 00896 return false; 00897 } 00898 00899 // Strip off the comma and space on the end of both the fields 00900 // and their values. 00901 $fields = substr($fields, 0, -2); 00902 $values = substr($values, 0, -2); 00903 00904 // Append the fields and their values to the insert query. 00905 return 'INSERT INTO '.$tableName.' ( '.$fields.' ) VALUES ( '.$values.' )'; 00906 } 00907 00908 00924 function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFields, $magicq) 00925 { 00926 $sql = ''; 00927 00928 // Based on the datatype of the field 00929 // Format the value properly for the database 00930 switch($type) { 00931 case 'B': 00932 //in order to handle Blobs correctly, we need 00933 //to do some magic for Oracle 00934 00935 //we need to create a new descriptor to handle 00936 //this properly 00937 if (!empty($zthis->hasReturningInto)) { 00938 if ($action == 'I') { 00939 $sql = 'empty_blob(), '; 00940 } else { 00941 $sql = $fnameq. '=empty_blob(), '; 00942 } 00943 //add the variable to the returning clause array 00944 //so the user can build this later in 00945 //case they want to add more to it 00946 $zthis->_returningArray[$fname] = ':xx'.$fname.'xx'; 00947 } else if (empty($arrFields[$fname])){ 00948 if ($action == 'I') { 00949 $sql = 'empty_blob(), '; 00950 } else { 00951 $sql = $fnameq. '=empty_blob(), '; 00952 } 00953 } else { 00954 //this is to maintain compatibility 00955 //with older adodb versions. 00956 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false); 00957 } 00958 break; 00959 00960 case "X": 00961 //we need to do some more magic here for long variables 00962 //to handle these correctly in oracle. 00963 00964 //create a safe bind var name 00965 //to avoid conflicts w/ dupes. 00966 if (!empty($zthis->hasReturningInto)) { 00967 if ($action == 'I') { 00968 $sql = ':xx'.$fname.'xx, '; 00969 } else { 00970 $sql = $fnameq.'=:xx'.$fname.'xx, '; 00971 } 00972 //add the variable to the returning clause array 00973 //so the user can build this later in 00974 //case they want to add more to it 00975 $zthis->_returningArray[$fname] = ':xx'.$fname.'xx'; 00976 } else { 00977 //this is to maintain compatibility 00978 //with older adodb versions. 00979 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false); 00980 } 00981 break; 00982 00983 default: 00984 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false); 00985 break; 00986 } 00987 00988 return $sql; 00989 } 00990 00991 function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq, $recurse=true) 00992 { 00993 00994 if ($recurse) { 00995 switch($zthis->dataProvider) { 00996 case 'postgres': 00997 if ($type == 'L') $type = 'C'; 00998 break; 00999 case 'oci8': 01000 return _adodb_column_sql_oci8($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq); 01001 01002 } 01003 } 01004 01005 switch($type) { 01006 case "C": 01007 case "X": 01008 case 'B': 01009 $val = $zthis->qstr($arrFields[$fname],$magicq); 01010 break; 01011 01012 case "D": 01013 $val = $zthis->DBDate($arrFields[$fname]); 01014 break; 01015 01016 case "T": 01017 $val = $zthis->DBTimeStamp($arrFields[$fname]); 01018 break; 01019 01020 case "N": 01021 $val = $arrFields[$fname]; 01022 if (!is_numeric($val)) $val = str_replace(',', '.', (float)$val); 01023 break; 01024 01025 case "I": 01026 case "R": 01027 $val = $arrFields[$fname]; 01028 if (!is_numeric($val)) $val = (integer) $val; 01029 break; 01030 01031 default: 01032 $val = str_replace(array("'"," ","("),"",$arrFields[$fname]); // basic sql injection defence 01033 if (empty($val)) $val = '0'; 01034 break; 01035 } 01036 01037 if ($action == 'I') return $val . ", "; 01038 01039 01040 return $fnameq . "=" . $val . ", "; 01041 01042 } 01043 01044 01045 01046 function _adodb_debug_execute(&$zthis, $sql, $inputarr) 01047 { 01048 $ss = ''; 01049 if ($inputarr) { 01050 foreach($inputarr as $kk=>$vv) { 01051 if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...'; 01052 if (is_null($vv)) $ss .= "($kk=>null) "; 01053 else $ss .= "($kk=>'$vv') "; 01054 } 01055 $ss = "[ $ss ]"; 01056 } 01057 $sqlTxt = is_array($sql) ? $sql[0] : $sql; 01058 /*str_replace(', ','##1#__^LF',is_array($sql) ? $sql[0] : $sql); 01059 $sqlTxt = str_replace(',',', ',$sqlTxt); 01060 $sqlTxt = str_replace('##1#__^LF', ', ' ,$sqlTxt); 01061 */ 01062 // check if running from browser or command-line 01063 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']); 01064 01065 $dbt = $zthis->databaseType; 01066 if (isset($zthis->dsnType)) $dbt .= '-'.$zthis->dsnType; 01067 if ($inBrowser) { 01068 if ($ss) { 01069 $ss = '<code>'.htmlspecialchars($ss).'</code>'; 01070 } 01071 if ($zthis->debug === -1) 01072 ADOConnection::outp( "<br>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<br>\n",false); 01073 else if ($zthis->debug !== -99) 01074 ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<hr>\n",false); 01075 } else { 01076 $ss = "\n ".$ss; 01077 if ($zthis->debug !== -99) 01078 ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt." $ss\n-----<hr>\n",false); 01079 } 01080 01081 $qID = $zthis->_query($sql,$inputarr); 01082 01083 /* 01084 Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql 01085 because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion 01086 */ 01087 if ($zthis->databaseType == 'mssql') { 01088 // ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6 01089 01090 if($emsg = $zthis->ErrorMsg()) { 01091 if ($err = $zthis->ErrorNo()) { 01092 if ($zthis->debug === -99) 01093 ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<hr>\n",false); 01094 01095 ADOConnection::outp($err.': '.$emsg); 01096 } 01097 } 01098 } else if (!$qID) { 01099 01100 if ($zthis->debug === -99) 01101 if ($inBrowser) ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<hr>\n",false); 01102 else ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt."$ss\n-----<hr>\n",false); 01103 01104 ADOConnection::outp($zthis->ErrorNo() .': '. $zthis->ErrorMsg()); 01105 } 01106 01107 if ($zthis->debug === 99) _adodb_backtrace(true,9999,2); 01108 return $qID; 01109 } 01110 01111 # pretty print the debug_backtrace function 01112 function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0,$ishtml=null) 01113 { 01114 if (!function_exists('debug_backtrace')) return ''; 01115 01116 if ($ishtml === null) $html = (isset($_SERVER['HTTP_USER_AGENT'])); 01117 else $html = $ishtml; 01118 01119 $fmt = ($html) ? "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s"; 01120 01121 $MAXSTRLEN = 128; 01122 01123 $s = ($html) ? '<pre align=left>' : ''; 01124 01125 if (is_array($printOrArr)) $traceArr = $printOrArr; 01126 else $traceArr = debug_backtrace(); 01127 array_shift($traceArr); 01128 array_shift($traceArr); 01129 $tabs = sizeof($traceArr)-2; 01130 01131 foreach ($traceArr as $arr) { 01132 if ($skippy) {$skippy -= 1; continue;} 01133 $levels -= 1; 01134 if ($levels < 0) break; 01135 01136 $args = array(); 01137 for ($i=0; $i < $tabs; $i++) $s .= ($html) ? ' ' : "\t"; 01138 $tabs -= 1; 01139 if ($html) $s .= '<font face="Courier New,Courier">'; 01140 if (isset($arr['class'])) $s .= $arr['class'].'.'; 01141 if (isset($arr['args'])) 01142 foreach($arr['args'] as $v) { 01143 if (is_null($v)) $args[] = 'null'; 01144 else if (is_array($v)) $args[] = 'Array['.sizeof($v).']'; 01145 else if (is_object($v)) $args[] = 'Object:'.get_class($v); 01146 else if (is_bool($v)) $args[] = $v ? 'true' : 'false'; 01147 else { 01148 $v = (string) @$v; 01149 $str = htmlspecialchars(str_replace(array("\r","\n"),' ',substr($v,0,$MAXSTRLEN))); 01150 if (strlen($v) > $MAXSTRLEN) $str .= '...'; 01151 $args[] = $str; 01152 } 01153 } 01154 $s .= $arr['function'].'('.implode(', ',$args).')'; 01155 01156 01157 $s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file'])); 01158 01159 $s .= "\n"; 01160 } 01161 if ($html) $s .= '</pre>'; 01162 if ($printOrArr) print $s; 01163 01164 return $s; 01165 } 01166 /* 01167 function _adodb_find_from($sql) 01168 { 01169 01170 $sql = str_replace(array("\n","\r"), ' ', $sql); 01171 $charCount = strlen($sql); 01172 01173 $inString = false; 01174 $quote = ''; 01175 $parentheseCount = 0; 01176 $prevChars = ''; 01177 $nextChars = ''; 01178 01179 01180 for($i = 0; $i < $charCount; $i++) { 01181 01182 $char = substr($sql,$i,1); 01183 $prevChars = substr($sql,0,$i); 01184 $nextChars = substr($sql,$i+1); 01185 01186 if((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === false) { 01187 $quote = $char; 01188 $inString = true; 01189 } 01190 01191 elseif((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === true && $quote == $char) { 01192 $quote = ""; 01193 $inString = false; 01194 } 01195 01196 elseif($char == "(" && $inString === false) 01197 $parentheseCount++; 01198 01199 elseif($char == ")" && $inString === false && $parentheseCount > 0) 01200 $parentheseCount--; 01201 01202 elseif($parentheseCount <= 0 && $inString === false && $char == " " && strtoupper(substr($prevChars,-5,5)) == " FROM") 01203 return $i; 01204 01205 } 01206 } 01207 */ 01208 01209 ?>