Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
1 <?php 2 // security - hide paths 3 if (!defined('ADODB_DIR')) die(); 4 5 global $ADODB_INCLUDED_LIB; 6 $ADODB_INCLUDED_LIB = 1; 7 8 /* 9 @version v5.21.0 2021-02-27 10 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved. 11 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community 12 Released under both BSD license and Lesser GPL library license. 13 Whenever there is any discrepancy between the two licenses, 14 the BSD license will take precedence. See License.txt. 15 Set tabs to 4 for best viewing. 16 17 Less commonly used functions are placed here to reduce size of adodb.inc.php. 18 */ 19 20 function adodb_strip_order_by($sql) 21 { 22 $rez = preg_match_all('/(\sORDER\s+BY\s(?:[^)](?!LIMIT))*)/is', $sql, $arr); 23 if ($arr) 24 { 25 $tmp = array_pop($arr); 26 $arr = [1=>array_pop($tmp)]; 27 } 28 if ($arr) 29 if (strpos($arr[1], '(') !== false) { 30 $at = strpos($sql, $arr[1]); 31 $cntin = 0; 32 for ($i=$at, $max=strlen($sql); $i < $max; $i++) { 33 $ch = $sql[$i]; 34 if ($ch == '(') { 35 $cntin += 1; 36 } elseif($ch == ')') { 37 $cntin -= 1; 38 if ($cntin < 0) { 39 break; 40 } 41 } 42 } 43 $sql = substr($sql,0,$at).substr($sql,$i); 44 } else { 45 $sql = str_replace($arr[1], '', $sql); 46 } 47 48 return $sql; 49 } 50 51 if (false) { 52 $sql = 'select * from (select a from b order by a(b),b(c) desc)'; 53 $sql = '(select * from abc order by 1)'; 54 die(adodb_strip_order_by($sql)); 55 } 56 57 function adodb_probetypes(&$array,&$types,$probe=8) 58 { 59 // probe and guess the type 60 $types = array(); 61 if ($probe > sizeof($array)) $max = sizeof($array); 62 else $max = $probe; 63 64 65 for ($j=0;$j < $max; $j++) { 66 $row = $array[$j]; 67 if (!$row) break; 68 $i = -1; 69 foreach($row as $v) { 70 $i += 1; 71 72 if (isset($types[$i]) && $types[$i]=='C') continue; 73 74 //print " ($i ".$types[$i]. "$v) "; 75 $v = trim($v); 76 77 if (!preg_match('/^[+-]{0,1}[0-9\.]+$/',$v)) { 78 $types[$i] = 'C'; // once C, always C 79 80 continue; 81 } 82 if ($j == 0) { 83 // If empty string, we presume is character 84 // test for integer for 1st row only 85 // after that it is up to testing other rows to prove 86 // that it is not an integer 87 if (strlen($v) == 0) $types[$i] = 'C'; 88 if (strpos($v,'.') !== false) $types[$i] = 'N'; 89 else $types[$i] = 'I'; 90 continue; 91 } 92 93 if (strpos($v,'.') !== false) $types[$i] = 'N'; 94 95 } 96 } 97 98 } 99 100 function adodb_transpose(&$arr, &$newarr, &$hdr, &$fobjs) 101 { 102 $oldX = sizeof(reset($arr)); 103 $oldY = sizeof($arr); 104 105 if ($hdr) { 106 $startx = 1; 107 $hdr = array('Fields'); 108 for ($y = 0; $y < $oldY; $y++) { 109 $hdr[] = $arr[$y][0]; 110 } 111 } else 112 $startx = 0; 113 114 for ($x = $startx; $x < $oldX; $x++) { 115 if ($fobjs) { 116 $o = $fobjs[$x]; 117 $newarr[] = array($o->name); 118 } else 119 $newarr[] = array(); 120 121 for ($y = 0; $y < $oldY; $y++) { 122 $newarr[$x-$startx][] = $arr[$y][$x]; 123 } 124 } 125 } 126 127 128 function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc) 129 { 130 // Add Quote around table name to support use of spaces / reserved keywords 131 $table=sprintf('%s%s%s', $zthis->nameQuote,$table,$zthis->nameQuote); 132 133 if (count($fieldArray) == 0) return 0; 134 135 if (!is_array($keyCol)) { 136 $keyCol = array($keyCol); 137 } 138 $uSet = ''; 139 foreach($fieldArray as $k => $v) { 140 if ($v === null) { 141 $v = 'NULL'; 142 $fieldArray[$k] = $v; 143 } else if ($autoQuote && /*!is_numeric($v) /*and strncmp($v,"'",1) !== 0 -- sql injection risk*/ strcasecmp($v,$zthis->null2null)!=0) { 144 $v = $zthis->qstr($v); 145 $fieldArray[$k] = $v; 146 } 147 if (in_array($k,$keyCol)) continue; // skip UPDATE if is key 148 149 // Add Quote around column name to support use of spaces / reserved keywords 150 $uSet .= sprintf(',%s%s%s=%s',$zthis->nameQuote,$k,$zthis->nameQuote,$v); 151 } 152 $uSet = ltrim($uSet, ','); 153 154 // Add Quote around column name in where clause 155 $where = ''; 156 foreach ($keyCol as $v) { 157 if (isset($fieldArray[$v])) { 158 $where .= sprintf(' and %s%s%s=%s ', $zthis->nameQuote,$v,$zthis->nameQuote,$fieldArray[$v]); 159 } 160 } 161 if ($where) { 162 $where = substr($where, 5); 163 } 164 165 if ($uSet && $where) { 166 $update = "UPDATE $table SET $uSet WHERE $where"; 167 $rs = $zthis->Execute($update); 168 169 if ($rs) { 170 if ($zthis->poorAffectedRows) { 171 // The Select count(*) wipes out any errors that the update would have returned. 172 // PHPLens Issue No: 5696 173 if ($zthis->ErrorNo()<>0) return 0; 174 175 // affected_rows == 0 if update field values identical to old values 176 // for mysql - which is silly. 177 $cnt = $zthis->GetOne("select count(*) from $table where $where"); 178 if ($cnt > 0) return 1; // record already exists 179 } else { 180 if (($zthis->Affected_Rows()>0)) return 1; 181 } 182 } else 183 return 0; 184 } 185 186 $iCols = $iVals = ''; 187 foreach($fieldArray as $k => $v) { 188 if ($has_autoinc && in_array($k,$keyCol)) continue; // skip autoinc col 189 190 // Add Quote around Column Name 191 $iCols .= sprintf(',%s%s%s',$zthis->nameQuote,$k,$zthis->nameQuote); 192 $iVals .= ",$v"; 193 } 194 $iCols = ltrim($iCols, ','); 195 $iVals = ltrim($iVals, ','); 196 197 $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)"; 198 $rs = $zthis->Execute($insert); 199 return ($rs) ? 2 : 0; 200 } 201 202 function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false, 203 $size=0, $selectAttr='',$compareFields0=true) 204 { 205 global $ADODB_FETCH_MODE; 206 207 $s = _adodb_getmenu_select($name, $defstr, $blank1stItem, $multiple, $size, $selectAttr); 208 209 $hasvalue = $zthis->FieldCount() > 1; 210 if (!$hasvalue) { 211 $compareFields0 = true; 212 } 213 214 $value = ''; 215 while(!$zthis->EOF) { 216 $zval = rtrim(reset($zthis->fields)); 217 218 if ($blank1stItem && $zval == "") { 219 $zthis->MoveNext(); 220 continue; 221 } 222 223 if ($hasvalue) { 224 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC) { 225 // Get 2nd field's value regardless of its name 226 $zval2 = current(array_slice($zthis->fields, 1, 1)); 227 } else { 228 // With NUM or BOTH fetch modes, we have a numeric index 229 $zval2 = $zthis->fields[1]; 230 } 231 $zval2 = trim($zval2); 232 $value = 'value="' . htmlspecialchars($zval2) . '"'; 233 } 234 235 $s .= _adodb_getmenu_option($defstr, $compareFields0 ? $zval : $zval2, $value, $zval); 236 237 $zthis->MoveNext(); 238 } // while 239 240 return $s ."\n</select>\n"; 241 } 242 243 function _adodb_getmenu_gp(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false, 244 $size=0, $selectAttr='',$compareFields0=true) 245 { 246 global $ADODB_FETCH_MODE; 247 248 $s = _adodb_getmenu_select($name, $defstr, $blank1stItem, $multiple, $size, $selectAttr); 249 250 $hasvalue = $zthis->FieldCount() > 1; 251 $hasgroup = $zthis->FieldCount() > 2; 252 if (!$hasvalue) { 253 $compareFields0 = true; 254 } 255 256 $value = ''; 257 $optgroup = null; 258 $firstgroup = true; 259 while(!$zthis->EOF) { 260 $zval = rtrim(reset($zthis->fields)); 261 $group = ''; 262 263 if ($blank1stItem && $zval=="") { 264 $zthis->MoveNext(); 265 continue; 266 } 267 268 if ($hasvalue) { 269 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC) { 270 // Get 2nd field's value regardless of its name 271 $fields = array_slice($zthis->fields, 1); 272 $zval2 = current($fields); 273 if ($hasgroup) { 274 $group = trim(next($fields)); 275 } 276 } else { 277 // With NUM or BOTH fetch modes, we have a numeric index 278 $zval2 = $zthis->fields[1]; 279 if ($hasgroup) { 280 $group = trim($zthis->fields[2]); 281 } 282 } 283 $zval2 = trim($zval2); 284 $value = "value='".htmlspecialchars($zval2)."'"; 285 } 286 287 if ($optgroup != $group) { 288 $optgroup = $group; 289 if ($firstgroup) { 290 $firstgroup = false; 291 } else { 292 $s .="\n</optgroup>"; 293 } 294 $s .="\n<optgroup label='". htmlspecialchars($group) ."'>"; 295 } 296 297 $s .= _adodb_getmenu_option($defstr, $compareFields0 ? $zval : $zval2, $value, $zval); 298 299 $zthis->MoveNext(); 300 } // while 301 302 // closing last optgroup 303 if($optgroup != null) { 304 $s .= "\n</optgroup>"; 305 } 306 return $s ."\n</select>\n"; 307 } 308 309 /** 310 * Generate the opening SELECT tag for getmenu functions. 311 * 312 * ADOdb internal function, used by _adodb_getmenu() and _adodb_getmenu_gp(). 313 * 314 * @param string $name 315 * @param string $defstr 316 * @param bool $blank1stItem 317 * @param bool $multiple 318 * @param int $size 319 * @param string $selectAttr 320 * 321 * @return string HTML 322 */ 323 function _adodb_getmenu_select($name, $defstr = '', $blank1stItem = true, 324 $multiple = false, $size = 0, $selectAttr = '') 325 { 326 if ($multiple || is_array($defstr)) { 327 if ($size == 0 ) { 328 $size = 5; 329 } 330 $attr = ' multiple size="' . $size . '"'; 331 if (!strpos($name,'[]')) { 332 $name .= '[]'; 333 } 334 } elseif ($size) { 335 $attr = ' size="' . $size . '"'; 336 } else { 337 $attr = ''; 338 } 339 340 $html = '<select name="' . $name . '"' . $attr . ' ' . $selectAttr . '>'; 341 if ($blank1stItem) { 342 if (is_string($blank1stItem)) { 343 $barr = explode(':',$blank1stItem); 344 if (sizeof($barr) == 1) { 345 $barr[] = ''; 346 } 347 $html .= "\n<option value=\"" . $barr[0] . "\">" . $barr[1] . "</option>"; 348 } else { 349 $html .= "\n<option></option>"; 350 } 351 } 352 353 return $html; 354 } 355 356 /** 357 * Print the OPTION tags for getmenu functions. 358 * 359 * ADOdb internal function, used by _adodb_getmenu() and _adodb_getmenu_gp(). 360 * 361 * @param string $defstr Default values 362 * @param string $compare Value to compare against defaults 363 * @param string $value Ready-to-print `value="xxx"` (or empty) string 364 * @param string $display Display value 365 * 366 * @return string HTML 367 */ 368 function _adodb_getmenu_option($defstr, $compare, $value, $display) 369 { 370 if ( is_array($defstr) && in_array($compare, $defstr) 371 || !is_array($defstr) && strcasecmp($compare, $defstr) == 0 372 ) { 373 $selected = ' selected="selected"'; 374 } else { 375 $selected = ''; 376 } 377 378 return "\n<option $value$selected>" . htmlspecialchars($display) . '</option>'; 379 } 380 381 /* 382 Count the number of records this sql statement will return by using 383 query rewriting heuristics... 384 385 Does not work with UNIONs, except with postgresql and oracle. 386 387 Usage: 388 389 $conn->Connect(...); 390 $cnt = _adodb_getcount($conn, $sql); 391 392 */ 393 function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0) 394 { 395 $qryRecs = 0; 396 397 if (!empty($zthis->_nestedSQL) || preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) || 398 preg_match('/\s+GROUP\s+BY\s+/is',$sql) || 399 preg_match('/\s+UNION\s+/is',$sql)) { 400 401 $rewritesql = adodb_strip_order_by($sql); 402 403 // ok, has SELECT DISTINCT or GROUP BY so see if we can use a table alias 404 // but this is only supported by oracle and postgresql... 405 if ($zthis->dataProvider == 'oci8') { 406 // Allow Oracle hints to be used for query optimization, Chris Wrye 407 if (preg_match('#/\\*+.*?\\*\\/#', $sql, $hint)) { 408 $rewritesql = "SELECT ".$hint[0]." COUNT(*) FROM (".$rewritesql.")"; 409 } else 410 $rewritesql = "SELECT COUNT(*) FROM (".$rewritesql.")"; 411 412 } else if (strncmp($zthis->databaseType,'postgres',8) == 0 413 || strncmp($zthis->databaseType,'mysql',5) == 0 414 || strncmp($zthis->databaseType,'mssql',5) == 0 415 || strncmp($zthis->dsnType,'sqlsrv',5) == 0 416 || strncmp($zthis->dsnType,'mssql',5) == 0 417 ){ 418 $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) _ADODB_ALIAS_"; 419 } else { 420 $rewritesql = "SELECT COUNT(*) FROM ($rewritesql)"; 421 } 422 } else { 423 // now replace SELECT ... FROM with SELECT COUNT(*) FROM 424 if ( strpos($sql, '_ADODB_COUNT') !== FALSE ) { 425 $rewritesql = preg_replace('/^\s*?SELECT\s+_ADODB_COUNT(.*)_ADODB_COUNT\s/is','SELECT COUNT(*) ',$sql); 426 } else { 427 $rewritesql = preg_replace('/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql); 428 } 429 // fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails 430 // with mssql, access and postgresql. Also a good speedup optimization - skips sorting! 431 // also see PHPLens Issue No: 12752 432 $rewritesql = adodb_strip_order_by($rewritesql); 433 } 434 435 if (isset($rewritesql) && $rewritesql != $sql) { 436 if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0]; 437 438 if ($secs2cache) { 439 // we only use half the time of secs2cache because the count can quickly 440 // become inaccurate if new records are added 441 $qryRecs = $zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr); 442 443 } else { 444 $qryRecs = $zthis->GetOne($rewritesql,$inputarr); 445 } 446 if ($qryRecs !== false) return $qryRecs; 447 } 448 //-------------------------------------------- 449 // query rewrite failed - so try slower way... 450 451 452 // strip off unneeded ORDER BY if no UNION 453 if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql; 454 else $rewritesql = $rewritesql = adodb_strip_order_by($sql); 455 456 if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0]; 457 458 if ($secs2cache) { 459 $rstest = $zthis->CacheExecute($secs2cache,$rewritesql,$inputarr); 460 if (!$rstest) $rstest = $zthis->CacheExecute($secs2cache,$sql,$inputarr); 461 } else { 462 $rstest = $zthis->Execute($rewritesql,$inputarr); 463 if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr); 464 } 465 if ($rstest) { 466 $qryRecs = $rstest->RecordCount(); 467 if ($qryRecs == -1) { 468 // some databases will return -1 on MoveLast() - change to MoveNext() 469 while(!$rstest->EOF) { 470 $rstest->MoveNext(); 471 } 472 $qryRecs = $rstest->_currentRow; 473 } 474 $rstest->Close(); 475 if ($qryRecs == -1) return 0; 476 } 477 return $qryRecs; 478 } 479 480 /* 481 Code originally from "Cornel G" <conyg@fx.ro> 482 483 This code might not work with SQL that has UNION in it 484 485 Also if you are using CachePageExecute(), there is a strong possibility that 486 data will get out of synch. use CachePageExecute() only with tables that 487 rarely change. 488 */ 489 function _adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page, 490 $inputarr=false, $secs2cache=0) 491 { 492 $atfirstpage = false; 493 $atlastpage = false; 494 $lastpageno=1; 495 496 // If an invalid nrows is supplied, 497 // we assume a default value of 10 rows per page 498 if (!isset($nrows) || $nrows <= 0) $nrows = 10; 499 500 $qryRecs = false; //count records for no offset 501 502 $qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache); 503 $lastpageno = (int) ceil($qryRecs / $nrows); 504 $zthis->_maxRecordCount = $qryRecs; 505 506 507 508 // ***** Here we check whether $page is the last page or 509 // whether we are trying to retrieve 510 // a page number greater than the last page number. 511 if ($page >= $lastpageno) { 512 $page = $lastpageno; 513 $atlastpage = true; 514 } 515 516 // If page number <= 1, then we are at the first page 517 if (empty($page) || $page <= 1) { 518 $page = 1; 519 $atfirstpage = true; 520 } 521 522 // We get the data we want 523 $offset = $nrows * ($page-1); 524 if ($secs2cache > 0) 525 $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr); 526 else 527 $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache); 528 529 530 // Before returning the RecordSet, we set the pagination properties we need 531 if ($rsreturn) { 532 $rsreturn->_maxRecordCount = $qryRecs; 533 $rsreturn->rowsPerPage = $nrows; 534 $rsreturn->AbsolutePage($page); 535 $rsreturn->AtFirstPage($atfirstpage); 536 $rsreturn->AtLastPage($atlastpage); 537 $rsreturn->LastPageNo($lastpageno); 538 } 539 return $rsreturn; 540 } 541 542 // Iván Oliva version 543 function _adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0) 544 { 545 546 $atfirstpage = false; 547 $atlastpage = false; 548 549 if (!isset($page) || $page <= 1) { 550 // If page number <= 1, then we are at the first page 551 $page = 1; 552 $atfirstpage = true; 553 } 554 if ($nrows <= 0) { 555 // If an invalid nrows is supplied, we assume a default value of 10 rows per page 556 $nrows = 10; 557 } 558 559 $pagecounteroffset = ($page * $nrows) - $nrows; 560 561 // To find out if there are more pages of rows, simply increase the limit or 562 // nrows by 1 and see if that number of records was returned. If it was, 563 // then we know there is at least one more page left, otherwise we are on 564 // the last page. Therefore allow non-Count() paging with single queries 565 // rather than three queries as was done before. 566 $test_nrows = $nrows + 1; 567 if ($secs2cache > 0) { 568 $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr); 569 } else { 570 $rsreturn = $zthis->SelectLimit($sql, $test_nrows, $pagecounteroffset, $inputarr, $secs2cache); 571 } 572 573 // Now check to see if the number of rows returned was the higher value we asked for or not. 574 if ( $rsreturn->_numOfRows == $test_nrows ) { 575 // Still at least 1 more row, so we are not on last page yet... 576 // Remove the last row from the RS. 577 $rsreturn->_numOfRows = ( $rsreturn->_numOfRows - 1 ); 578 } elseif ( $rsreturn->_numOfRows == 0 && $page > 1 ) { 579 // Likely requested a page that doesn't exist, so need to find the last 580 // page and return it. Revert to original method and loop through pages 581 // until we find some data... 582 $pagecounter = $page + 1; 583 $pagecounteroffset = ($pagecounter * $nrows) - $nrows; 584 585 $rstest = $rsreturn; 586 if ($rstest) { 587 while ($rstest && $rstest->EOF && $pagecounter > 0) { 588 $atlastpage = true; 589 $pagecounter--; 590 $pagecounteroffset = $nrows * ($pagecounter - 1); 591 $rstest->Close(); 592 if ($secs2cache>0) { 593 $rstest = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr); 594 } 595 else { 596 $rstest = $zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache); 597 } 598 } 599 if ($rstest) $rstest->Close(); 600 } 601 if ($atlastpage) { 602 // If we are at the last page or beyond it, we are going to retrieve it 603 $page = $pagecounter; 604 if ($page == 1) { 605 // We have to do this again in case the last page is the same as 606 // the first page, that is, the recordset has only 1 page. 607 $atfirstpage = true; 608 } 609 } 610 // We get the data we want 611 $offset = $nrows * ($page-1); 612 if ($secs2cache > 0) { 613 $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr); 614 } 615 else { 616 $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache); 617 } 618 } elseif ( $rsreturn->_numOfRows < $test_nrows ) { 619 // Rows is less than what we asked for, so must be at the last page. 620 $atlastpage = true; 621 } 622 623 // Before returning the RecordSet, we set the pagination properties we need 624 if ($rsreturn) { 625 $rsreturn->rowsPerPage = $nrows; 626 $rsreturn->AbsolutePage($page); 627 $rsreturn->AtFirstPage($atfirstpage); 628 $rsreturn->AtLastPage($atlastpage); 629 } 630 return $rsreturn; 631 } 632 633 function _adodb_getupdatesql(&$zthis, &$rs, $arrFields, $forceUpdate=false, $force=2) 634 { 635 global $ADODB_QUOTE_FIELDNAMES; 636 637 if (!$rs) { 638 printf(ADODB_BAD_RS,'GetUpdateSQL'); 639 return false; 640 } 641 642 $fieldUpdatedCount = 0; 643 if (is_array($arrFields)) 644 $arrFields = array_change_key_case($arrFields,CASE_UPPER); 645 646 $hasnumeric = isset($rs->fields[0]); 647 $setFields = ''; 648 649 // Loop through all of the fields in the recordset 650 for ($i=0, $max=$rs->fieldCount(); $i < $max; $i++) { 651 // Get the field from the recordset 652 $field = $rs->fetchField($i); 653 654 // If the recordset field is one 655 // of the fields passed in then process. 656 $upperfname = strtoupper($field->name); 657 if (adodb_key_exists($upperfname, $arrFields, $force)) { 658 659 // If the existing field value in the recordset 660 // is different from the value passed in then 661 // go ahead and append the field name and new value to 662 // the update query. 663 664 if ($hasnumeric) $val = $rs->fields[$i]; 665 else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname]; 666 else if (isset($rs->fields[$field->name])) $val = $rs->fields[$field->name]; 667 else if (isset($rs->fields[strtolower($upperfname)])) $val = $rs->fields[strtolower($upperfname)]; 668 else $val = ''; 669 670 if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) { 671 // Set the counter for the number of fields that will be updated. 672 $fieldUpdatedCount++; 673 674 // Based on the datatype of the field 675 // Format the value properly for the database 676 $type = $rs->metaType($field->type); 677 678 if ($type == 'null') { 679 $type = 'C'; 680 } 681 682 if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES)) { 683 switch ($ADODB_QUOTE_FIELDNAMES) { 684 case 'BRACKETS': 685 $fnameq = $zthis->leftBracket.$upperfname.$zthis->rightBracket;break; 686 case 'LOWER': 687 $fnameq = $zthis->nameQuote.strtolower($field->name).$zthis->nameQuote;break; 688 case 'NATIVE': 689 $fnameq = $zthis->nameQuote.$field->name.$zthis->nameQuote;break; 690 case 'UPPER': 691 default: 692 $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;break; 693 } 694 } else { 695 $fnameq = $upperfname; 696 } 697 698 //********************************************************// 699 if (is_null($arrFields[$upperfname]) 700 || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0) 701 || $arrFields[$upperfname] === $zthis->null2null 702 ) { 703 704 switch ($force) { 705 706 //case 0: 707 // // Ignore empty values. This is already handled in "adodb_key_exists" function. 708 // break; 709 710 case 1: 711 // set null 712 $setFields .= $fnameq . " = null, "; 713 break; 714 715 case 2: 716 // set empty 717 $arrFields[$upperfname] = ""; 718 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq, $arrFields); 719 break; 720 721 default: 722 case 3: 723 // set the value that was given in array, so you can give both null and empty values 724 if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) { 725 $setFields .= $fnameq . " = null, "; 726 } else { 727 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq, $arrFields); 728 } 729 break; 730 731 case ADODB_FORCE_NULL_AND_ZERO: 732 733 switch ($type) { 734 case 'N': 735 case 'I': 736 case 'L': 737 $setFields .= $fnameq . ' = 0, '; 738 break; 739 default: 740 $setFields .= $fnameq . ' = null, '; 741 break; 742 } 743 break; 744 745 } 746 //********************************************************// 747 } else { 748 // we do this so each driver can customize the sql for 749 // DB specific column types. 750 // Oracle needs BLOB types to be handled with a returning clause 751 // postgres has special needs as well 752 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq, $arrFields); 753 } 754 } 755 } 756 } 757 758 // If there were any modified fields then build the rest of the update query. 759 if ($fieldUpdatedCount > 0 || $forceUpdate) { 760 // Get the table name from the existing query. 761 if (!empty($rs->tableName)) { 762 $tableName = $rs->tableName; 763 } else { 764 preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName); 765 $tableName = $tableName[1]; 766 } 767 768 // Get the full where clause excluding the word "WHERE" from the existing query. 769 preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause); 770 771 $discard = false; 772 // not a good hack, improvements? 773 if ($whereClause) { 774 #var_dump($whereClause); 775 if (preg_match('/\s(ORDER\s.*)/is', $whereClause[1], $discard)); 776 else if (preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard)); 777 else if (preg_match('/\s(FOR UPDATE.*)/is', $whereClause[1], $discard)); 778 else preg_match('/\s.*(\) WHERE .*)/is', $whereClause[1], $discard); # see https://sourceforge.net/p/adodb/bugs/37/ 779 } else { 780 $whereClause = array(false, false); 781 } 782 783 if ($discard) { 784 $whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1])); 785 } 786 787 $sql = 'UPDATE '.$tableName.' SET '.substr($setFields, 0, -2); 788 if (strlen($whereClause[1]) > 0) { 789 $sql .= ' WHERE '.$whereClause[1]; 790 } 791 return $sql; 792 } else { 793 return false; 794 } 795 } 796 797 function adodb_key_exists($key, &$arr,$force=2) 798 { 799 if ($force<=0) { 800 // the following is the old behaviour where null or empty fields are ignored 801 return (!empty($arr[$key])) || (isset($arr[$key]) && strlen($arr[$key])>0); 802 } 803 804 if (isset($arr[$key])) 805 return true; 806 ## null check below 807 return array_key_exists($key,$arr); 808 } 809 810 /** 811 * There is a special case of this function for the oci8 driver. 812 * The proper way to handle an insert w/ a blob in oracle requires 813 * a returning clause with bind variables and a descriptor blob. 814 * 815 * 816 */ 817 function _adodb_getinsertsql(&$zthis, &$rs, $arrFields, $force=2) 818 { 819 static $cacheRS = false; 820 static $cacheSig = 0; 821 static $cacheCols; 822 global $ADODB_QUOTE_FIELDNAMES; 823 824 $tableName = ''; 825 $values = ''; 826 $fields = ''; 827 $recordSet = null; 828 if (is_array($arrFields)) 829 $arrFields = array_change_key_case($arrFields,CASE_UPPER); 830 $fieldInsertedCount = 0; 831 832 if (is_string($rs)) { 833 //ok we have a table name 834 //try and get the column info ourself. 835 $tableName = $rs; 836 837 //we need an object for the recordSet 838 //because we have to call MetaType. 839 //php can't do a $rsclass::MetaType() 840 $rsclass = $zthis->rsPrefix.$zthis->databaseType; 841 $recordSet = new $rsclass(-1,$zthis->fetchMode); 842 $recordSet->connection = $zthis; 843 844 if (is_string($cacheRS) && $cacheRS == $rs) { 845 $columns = $cacheCols; 846 } else { 847 $columns = $zthis->MetaColumns( $tableName ); 848 $cacheRS = $tableName; 849 $cacheCols = $columns; 850 } 851 } else if (is_subclass_of($rs, 'adorecordset')) { 852 if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS == $rs->insertSig) { 853 $columns = $cacheCols; 854 } else { 855 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) 856 $columns[] = $rs->FetchField($i); 857 $cacheRS = $cacheSig; 858 $cacheCols = $columns; 859 $rs->insertSig = $cacheSig++; 860 } 861 $recordSet = $rs; 862 863 } else { 864 printf(ADODB_BAD_RS,'GetInsertSQL'); 865 return false; 866 } 867 868 // Loop through all of the fields in the recordset 869 foreach( $columns as $field ) { 870 $upperfname = strtoupper($field->name); 871 if (adodb_key_exists($upperfname,$arrFields,$force)) { 872 $bad = false; 873 if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES)) { 874 switch ($ADODB_QUOTE_FIELDNAMES) { 875 case 'BRACKETS': 876 $fnameq = $zthis->leftBracket.$upperfname.$zthis->rightBracket;break; 877 case 'LOWER': 878 $fnameq = $zthis->nameQuote.strtolower($field->name).$zthis->nameQuote;break; 879 case 'NATIVE': 880 $fnameq = $zthis->nameQuote.$field->name.$zthis->nameQuote;break; 881 case 'UPPER': 882 default: 883 $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;break; 884 } 885 } else 886 $fnameq = $upperfname; 887 888 $type = $recordSet->MetaType($field->type); 889 890 /********************************************************/ 891 if (is_null($arrFields[$upperfname]) 892 || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0) 893 || $arrFields[$upperfname] === $zthis->null2null 894 ) 895 { 896 switch ($force) { 897 898 case ADODB_FORCE_IGNORE: // we must always set null if missing 899 $bad = true; 900 break; 901 902 case ADODB_FORCE_NULL: 903 $values .= "null, "; 904 break; 905 906 case ADODB_FORCE_EMPTY: 907 //Set empty 908 $arrFields[$upperfname] = ""; 909 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields); 910 break; 911 912 default: 913 case ADODB_FORCE_VALUE: 914 //Set the value that was given in array, so you can give both null and empty values 915 if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) { 916 $values .= "null, "; 917 } else { 918 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields); 919 } 920 break; 921 922 case ADODB_FORCE_NULL_AND_ZERO: 923 switch ($type) 924 { 925 case 'N': 926 case 'I': 927 case 'L': 928 $values .= '0, '; 929 break; 930 default: 931 $values .= "null, "; 932 break; 933 } 934 break; 935 936 } // switch 937 938 /*********************************************************/ 939 } else { 940 //we do this so each driver can customize the sql for 941 //DB specific column types. 942 //Oracle needs BLOB types to be handled with a returning clause 943 //postgres has special needs as well 944 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields); 945 } 946 947 if ($bad) continue; 948 // Set the counter for the number of fields that will be inserted. 949 $fieldInsertedCount++; 950 951 952 // Get the name of the fields to insert 953 $fields .= $fnameq . ", "; 954 } 955 } 956 957 958 // If there were any inserted fields then build the rest of the insert query. 959 if ($fieldInsertedCount <= 0) return false; 960 961 // Get the table name from the existing query. 962 if (!$tableName) { 963 if (!empty($rs->tableName)) $tableName = $rs->tableName; 964 else if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName)) 965 $tableName = $tableName[1]; 966 else 967 return false; 968 } 969 970 // Strip off the comma and space on the end of both the fields 971 // and their values. 972 $fields = substr($fields, 0, -2); 973 $values = substr($values, 0, -2); 974 975 // Append the fields and their values to the insert query. 976 return 'INSERT INTO '.$tableName.' ( '.$fields.' ) VALUES ( '.$values.' )'; 977 } 978 979 980 /** 981 * This private method is used to help construct 982 * the update/sql which is generated by GetInsertSQL and GetUpdateSQL. 983 * It handles the string construction of 1 column -> sql string based on 984 * the column type. We want to do 'safe' handling of BLOBs 985 * 986 * @param string the type of sql we are trying to create 987 * 'I' or 'U'. 988 * @param string column data type from the db::MetaType() method 989 * @param string the column name 990 * @param array the column value 991 * 992 * @return string 993 * 994 */ 995 function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFields) 996 { 997 $sql = ''; 998 999 // Based on the datatype of the field 1000 // Format the value properly for the database 1001 switch($type) { 1002 case 'B': 1003 //in order to handle Blobs correctly, we need 1004 //to do some magic for Oracle 1005 1006 //we need to create a new descriptor to handle 1007 //this properly 1008 if (!empty($zthis->hasReturningInto)) { 1009 if ($action == 'I') { 1010 $sql = 'empty_blob(), '; 1011 } else { 1012 $sql = $fnameq. '=empty_blob(), '; 1013 } 1014 //add the variable to the returning clause array 1015 //so the user can build this later in 1016 //case they want to add more to it 1017 $zthis->_returningArray[$fname] = ':xx'.$fname.'xx'; 1018 } else if (empty($arrFields[$fname])){ 1019 if ($action == 'I') { 1020 $sql = 'empty_blob(), '; 1021 } else { 1022 $sql = $fnameq. '=empty_blob(), '; 1023 } 1024 } else { 1025 //this is to maintain compatibility 1026 //with older adodb versions. 1027 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false); 1028 } 1029 break; 1030 1031 case "X": 1032 //we need to do some more magic here for long variables 1033 //to handle these correctly in oracle. 1034 1035 //create a safe bind var name 1036 //to avoid conflicts w/ dupes. 1037 if (!empty($zthis->hasReturningInto)) { 1038 if ($action == 'I') { 1039 $sql = ':xx'.$fname.'xx, '; 1040 } else { 1041 $sql = $fnameq.'=:xx'.$fname.'xx, '; 1042 } 1043 //add the variable to the returning clause array 1044 //so the user can build this later in 1045 //case they want to add more to it 1046 $zthis->_returningArray[$fname] = ':xx'.$fname.'xx'; 1047 } else { 1048 //this is to maintain compatibility 1049 //with older adodb versions. 1050 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false); 1051 } 1052 break; 1053 1054 default: 1055 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, false); 1056 break; 1057 } 1058 1059 return $sql; 1060 } 1061 1062 function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields, $recurse=true) 1063 { 1064 1065 if ($recurse) { 1066 switch($zthis->dataProvider) { 1067 case 'postgres': 1068 if ($type == 'L') $type = 'C'; 1069 break; 1070 case 'oci8': 1071 return _adodb_column_sql_oci8($zthis, $action, $type, $fname, $fnameq, $arrFields); 1072 1073 } 1074 } 1075 1076 switch($type) { 1077 case "C": 1078 case "X": 1079 case 'B': 1080 $val = $zthis->qstr($arrFields[$fname]); 1081 break; 1082 1083 case "D": 1084 $val = $zthis->DBDate($arrFields[$fname]); 1085 break; 1086 1087 case "T": 1088 $val = $zthis->DBTimeStamp($arrFields[$fname]); 1089 break; 1090 1091 case "N": 1092 $val = $arrFields[$fname]; 1093 if (!is_numeric($val)) $val = str_replace(',', '.', (float)$val); 1094 break; 1095 1096 case "I": 1097 case "R": 1098 $val = $arrFields[$fname]; 1099 if (!is_numeric($val)) $val = (integer) $val; 1100 break; 1101 1102 default: 1103 $val = str_replace(array("'"," ","("),"",$arrFields[$fname]); // basic sql injection defence 1104 if (empty($val)) $val = '0'; 1105 break; 1106 } 1107 1108 if ($action == 'I') return $val . ", "; 1109 1110 return $fnameq . "=" . $val . ", "; 1111 } 1112 1113 1114 1115 function _adodb_debug_execute(&$zthis, $sql, $inputarr) 1116 { 1117 $ss = ''; 1118 if ($inputarr) { 1119 foreach($inputarr as $kk=>$vv) { 1120 if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...'; 1121 if (is_null($vv)) $ss .= "($kk=>null) "; 1122 else $ss .= "($kk=>'$vv') "; 1123 } 1124 $ss = "[ $ss ]"; 1125 } 1126 $sqlTxt = is_array($sql) ? $sql[0] : $sql; 1127 /*str_replace(', ','##1#__^LF',is_array($sql) ? $sql[0] : $sql); 1128 $sqlTxt = str_replace(',',', ',$sqlTxt); 1129 $sqlTxt = str_replace('##1#__^LF', ', ' ,$sqlTxt); 1130 */ 1131 // check if running from browser or command-line 1132 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']); 1133 1134 $dbt = $zthis->databaseType; 1135 if (isset($zthis->dsnType)) $dbt .= '-'.$zthis->dsnType; 1136 if ($inBrowser) { 1137 if ($ss) { 1138 $ss = '<code>'.htmlspecialchars($ss).'</code>'; 1139 } 1140 if ($zthis->debug === -1) 1141 ADOConnection::outp( "<br>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<br>\n",false); 1142 else if ($zthis->debug !== -99) 1143 ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<hr>\n",false); 1144 } else { 1145 $ss = "\n ".$ss; 1146 if ($zthis->debug !== -99) 1147 ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt." $ss\n-----<hr>\n",false); 1148 } 1149 1150 $qID = $zthis->_query($sql,$inputarr); 1151 1152 /* 1153 Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql 1154 because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion 1155 */ 1156 if ($zthis->databaseType == 'mssql') { 1157 // ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6 1158 1159 if($emsg = $zthis->ErrorMsg()) { 1160 if ($err = $zthis->ErrorNo()) { 1161 if ($zthis->debug === -99) 1162 ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<hr>\n",false); 1163 1164 ADOConnection::outp($err.': '.$emsg); 1165 } 1166 } 1167 } else if (!$qID) { 1168 1169 if ($zthis->debug === -99) 1170 if ($inBrowser) ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." $ss\n<hr>\n",false); 1171 else ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt."$ss\n-----<hr>\n",false); 1172 1173 ADOConnection::outp($zthis->ErrorNo() .': '. $zthis->ErrorMsg()); 1174 } 1175 1176 if ($zthis->debug === 99) _adodb_backtrace(true,9999,2); 1177 return $qID; 1178 } 1179 1180 # pretty print the debug_backtrace function 1181 function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0,$ishtml=null) 1182 { 1183 if (!function_exists('debug_backtrace')) return ''; 1184 1185 if ($ishtml === null) $html = (isset($_SERVER['HTTP_USER_AGENT'])); 1186 else $html = $ishtml; 1187 1188 $fmt = ($html) ? "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s"; 1189 1190 $MAXSTRLEN = 128; 1191 1192 $s = ($html) ? '<pre align=left>' : ''; 1193 1194 if (is_array($printOrArr)) $traceArr = $printOrArr; 1195 else $traceArr = debug_backtrace(); 1196 array_shift($traceArr); 1197 array_shift($traceArr); 1198 $tabs = sizeof($traceArr)-2; 1199 1200 foreach ($traceArr as $arr) { 1201 if ($skippy) {$skippy -= 1; continue;} 1202 $levels -= 1; 1203 if ($levels < 0) break; 1204 1205 $args = array(); 1206 for ($i=0; $i < $tabs; $i++) $s .= ($html) ? ' ' : "\t"; 1207 $tabs -= 1; 1208 if ($html) $s .= '<font face="Courier New,Courier">'; 1209 if (isset($arr['class'])) $s .= $arr['class'].'.'; 1210 if (isset($arr['args'])) 1211 foreach($arr['args'] as $v) { 1212 if (is_null($v)) $args[] = 'null'; 1213 else if (is_array($v)) $args[] = 'Array['.sizeof($v).']'; 1214 else if (is_object($v)) $args[] = 'Object:'.get_class($v); 1215 else if (is_bool($v)) $args[] = $v ? 'true' : 'false'; 1216 else { 1217 $v = (string) @$v; 1218 $str = htmlspecialchars(str_replace(array("\r","\n"),' ',substr($v,0,$MAXSTRLEN))); 1219 if (strlen($v) > $MAXSTRLEN) $str .= '...'; 1220 $args[] = $str; 1221 } 1222 } 1223 $s .= $arr['function'].'('.implode(', ',$args).')'; 1224 1225 1226 $s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file'])); 1227 1228 $s .= "\n"; 1229 } 1230 if ($html) $s .= '</pre>'; 1231 if ($printOrArr) print $s; 1232 1233 return $s; 1234 } 1235 /* 1236 function _adodb_find_from($sql) 1237 { 1238 1239 $sql = str_replace(array("\n","\r"), ' ', $sql); 1240 $charCount = strlen($sql); 1241 1242 $inString = false; 1243 $quote = ''; 1244 $parentheseCount = 0; 1245 $prevChars = ''; 1246 $nextChars = ''; 1247 1248 1249 for($i = 0; $i < $charCount; $i++) { 1250 1251 $char = substr($sql,$i,1); 1252 $prevChars = substr($sql,0,$i); 1253 $nextChars = substr($sql,$i+1); 1254 1255 if((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === false) { 1256 $quote = $char; 1257 $inString = true; 1258 } 1259 1260 elseif((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === true && $quote == $char) { 1261 $quote = ""; 1262 $inString = false; 1263 } 1264 1265 elseif($char == "(" && $inString === false) 1266 $parentheseCount++; 1267 1268 elseif($char == ")" && $inString === false && $parentheseCount > 0) 1269 $parentheseCount--; 1270 1271 elseif($parentheseCount <= 0 && $inString === false && $char == " " && strtoupper(substr($prevChars,-5,5)) == " FROM") 1272 return $i; 1273 1274 } 1275 } 1276 */
title
Description
Body
title
Description
Body
title
Description
Body
title
Body