1<?php 2/** 3 @version v5.21.0-dev ??-???-2016 4 @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved. 5 @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community 6 7 Released under both BSD license and Lesser GPL library license. 8 Whenever there is any discrepancy between the two licenses, 9 the BSD license will take precedence. 10 11 Set tabs to 4 for best viewing. 12 13 Latest version is available at http://adodb.sourceforge.net 14 15 Requires ODBC. Works on Windows and Unix. 16 17 Problems: 18 Where is float/decimal type in pdo_param_type 19 LOB handling for CLOB/BLOB differs significantly 20*/ 21 22// security - hide paths 23if (!defined('ADODB_DIR')) die(); 24 25 26/* 27enum pdo_param_type { 28PDO::PARAM_NULL, 0 29 30/* int as in long (the php native int type). 31 * If you mark a column as an int, PDO expects get_col to return 32 * a pointer to a long 33PDO::PARAM_INT, 1 34 35/* get_col ptr should point to start of the string buffer 36PDO::PARAM_STR, 2 37 38/* get_col: when len is 0 ptr should point to a php_stream *, 39 * otherwise it should behave like a string. Indicate a NULL field 40 * value by setting the ptr to NULL 41PDO::PARAM_LOB, 3 42 43/* get_col: will expect the ptr to point to a new PDOStatement object handle, 44 * but this isn't wired up yet 45PDO::PARAM_STMT, 4 /* hierarchical result set 46 47/* get_col ptr should point to a zend_bool 48PDO::PARAM_BOOL, 5 49 50 51/* magic flag to denote a parameter as being input/output 52PDO::PARAM_INPUT_OUTPUT = 0x80000000 53}; 54*/ 55 56function adodb_pdo_type($t) 57{ 58 switch($t) { 59 case 2: return 'VARCHAR'; 60 case 3: return 'BLOB'; 61 default: return 'NUMERIC'; 62 } 63} 64 65/*----------------------------------------------------------------------------*/ 66 67 68class ADODB_pdo extends ADOConnection { 69 var $databaseType = "pdo"; 70 var $dataProvider = "pdo"; 71 var $fmtDate = "'Y-m-d'"; 72 var $fmtTimeStamp = "'Y-m-d, h:i:sA'"; 73 var $replaceQuote = "''"; // string to use to replace quotes 74 var $hasAffectedRows = true; 75 var $_bindInputArray = true; 76 var $_genIDSQL; 77 var $_genSeqSQL = "create table %s (id integer)"; 78 var $_dropSeqSQL; 79 var $_autocommit = true; 80 var $_haserrorfunctions = true; 81 var $_lastAffectedRows = 0; 82 83 var $_errormsg = false; 84 var $_errorno = false; 85 86 var $dsnType = ''; 87 var $stmt = false; 88 var $_driver; 89 90 function _UpdatePDO() 91 { 92 $d = $this->_driver; 93 $this->fmtDate = $d->fmtDate; 94 $this->fmtTimeStamp = $d->fmtTimeStamp; 95 $this->replaceQuote = $d->replaceQuote; 96 $this->sysDate = $d->sysDate; 97 $this->sysTimeStamp = $d->sysTimeStamp; 98 $this->random = $d->random; 99 $this->concat_operator = $d->concat_operator; 100 $this->nameQuote = $d->nameQuote; 101 102 $this->hasGenID = $d->hasGenID; 103 $this->_genIDSQL = $d->_genIDSQL; 104 $this->_genSeqSQL = $d->_genSeqSQL; 105 $this->_dropSeqSQL = $d->_dropSeqSQL; 106 107 $d->_init($this); 108 } 109 110 function Time() 111 { 112 if (!empty($this->_driver->_hasdual)) { 113 $sql = "select $this->sysTimeStamp from dual"; 114 } 115 else { 116 $sql = "select $this->sysTimeStamp"; 117 } 118 119 $rs = $this->_Execute($sql); 120 if ($rs && !$rs->EOF) { 121 return $this->UnixTimeStamp(reset($rs->fields)); 122 } 123 124 return false; 125 } 126 127 // returns true or false 128 function _connect($argDSN, $argUsername, $argPassword, $argDatabasename, $persist=false) 129 { 130 $at = strpos($argDSN,':'); 131 $this->dsnType = substr($argDSN,0,$at); 132 133 if ($argDatabasename) { 134 switch($this->dsnType){ 135 case 'sqlsrv': 136 $argDSN .= ';database='.$argDatabasename; 137 break; 138 case 'mssql': 139 case 'mysql': 140 case 'oci': 141 case 'pgsql': 142 case 'sqlite': 143 default: 144 $argDSN .= ';dbname='.$argDatabasename; 145 } 146 } 147 try { 148 $this->_connectionID = new PDO($argDSN, $argUsername, $argPassword); 149 } catch (Exception $e) { 150 $this->_connectionID = false; 151 $this->_errorno = -1; 152 //var_dump($e); 153 $this->_errormsg = 'Connection attempt failed: '.$e->getMessage(); 154 return false; 155 } 156 157 if ($this->_connectionID) { 158 switch(ADODB_ASSOC_CASE){ 159 case ADODB_ASSOC_CASE_LOWER: 160 $m = PDO::CASE_LOWER; 161 break; 162 case ADODB_ASSOC_CASE_UPPER: 163 $m = PDO::CASE_UPPER; 164 break; 165 default: 166 case ADODB_ASSOC_CASE_NATIVE: 167 $m = PDO::CASE_NATURAL; 168 break; 169 } 170 171 //$this->_connectionID->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_SILENT ); 172 $this->_connectionID->setAttribute(PDO::ATTR_CASE,$m); 173 174 $class = 'ADODB_pdo_'.$this->dsnType; 175 //$this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,true); 176 switch($this->dsnType) { 177 case 'mssql': 178 case 'mysql': 179 case 'oci': 180 case 'pgsql': 181 case 'sqlite': 182 case 'sqlsrv': 183 include_once(ADODB_DIR.'/drivers/adodb-pdo_'.$this->dsnType.'.inc.php'); 184 break; 185 } 186 if (class_exists($class)) { 187 $this->_driver = new $class(); 188 } 189 else { 190 $this->_driver = new ADODB_pdo_base(); 191 } 192 193 $this->_driver->_connectionID = $this->_connectionID; 194 $this->_UpdatePDO(); 195 return true; 196 } 197 $this->_driver = new ADODB_pdo_base(); 198 return false; 199 } 200 201 function Concat() 202 { 203 $args = func_get_args(); 204 if(method_exists($this->_driver, 'Concat')) { 205 return call_user_func_array(array($this->_driver, 'Concat'), $args); 206 } 207 208 if (PHP_VERSION >= 5.3) { 209 return call_user_func_array('parent::Concat', $args); 210 } 211 return call_user_func_array(array($this,'parent::Concat'), $args); 212 } 213 214 // returns true or false 215 function _pconnect($argDSN, $argUsername, $argPassword, $argDatabasename) 216 { 217 return $this->_connect($argDSN, $argUsername, $argPassword, $argDatabasename, true); 218 } 219 220 /*------------------------------------------------------------------------------*/ 221 222 223 function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) 224 { 225 $save = $this->_driver->fetchMode; 226 $this->_driver->fetchMode = $this->fetchMode; 227 $this->_driver->debug = $this->debug; 228 $ret = $this->_driver->SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); 229 $this->_driver->fetchMode = $save; 230 return $ret; 231 } 232 233 234 function ServerInfo() 235 { 236 return $this->_driver->ServerInfo(); 237 } 238 239 function MetaTables($ttype=false,$showSchema=false,$mask=false) 240 { 241 return $this->_driver->MetaTables($ttype,$showSchema,$mask); 242 } 243 244 function MetaColumns($table,$normalize=true) 245 { 246 return $this->_driver->MetaColumns($table,$normalize); 247 } 248 249 function InParameter(&$stmt,&$var,$name,$maxLen=4000,$type=false) 250 { 251 $obj = $stmt[1]; 252 if ($type) { 253 $obj->bindParam($name, $var, $type, $maxLen); 254 } 255 else { 256 $obj->bindParam($name, $var); 257 } 258 } 259 260 function OffsetDate($dayFraction,$date=false) 261 { 262 return $this->_driver->OffsetDate($dayFraction,$date); 263 } 264 265 function ErrorMsg() 266 { 267 if ($this->_errormsg !== false) { 268 return $this->_errormsg; 269 } 270 if (!empty($this->_stmt)) { 271 $arr = $this->_stmt->errorInfo(); 272 } 273 else if (!empty($this->_connectionID)) { 274 $arr = $this->_connectionID->errorInfo(); 275 } 276 else { 277 return 'No Connection Established'; 278 } 279 280 if ($arr) { 281 if (sizeof($arr)<2) { 282 return ''; 283 } 284 if ((integer)$arr[0]) { 285 return $arr[2]; 286 } 287 else { 288 return ''; 289 } 290 } 291 else { 292 return '-1'; 293 } 294 } 295 296 297 function ErrorNo() 298 { 299 if ($this->_errorno !== false) { 300 return $this->_errorno; 301 } 302 if (!empty($this->_stmt)) { 303 $err = $this->_stmt->errorCode(); 304 } 305 else if (!empty($this->_connectionID)) { 306 $arr = $this->_connectionID->errorInfo(); 307 if (isset($arr[0])) { 308 $err = $arr[0]; 309 } 310 else { 311 $err = -1; 312 } 313 } else { 314 return 0; 315 } 316 317 if ($err == '00000') { 318 return 0; // allows empty check 319 } 320 return $err; 321 } 322 323 function SetTransactionMode($transaction_mode) 324 { 325 if(method_exists($this->_driver, 'SetTransactionMode')) { 326 return $this->_driver->SetTransactionMode($transaction_mode); 327 } 328 329 return parent::SetTransactionMode($seqname); 330 } 331 332 function BeginTrans() 333 { 334 if(method_exists($this->_driver, 'BeginTrans')) { 335 return $this->_driver->BeginTrans(); 336 } 337 338 if (!$this->hasTransactions) { 339 return false; 340 } 341 if ($this->transOff) { 342 return true; 343 } 344 $this->transCnt += 1; 345 $this->_autocommit = false; 346 $this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,false); 347 348 return $this->_connectionID->beginTransaction(); 349 } 350 351 function CommitTrans($ok=true) 352 { 353 if(method_exists($this->_driver, 'CommitTrans')) { 354 return $this->_driver->CommitTrans($ok); 355 } 356 357 if (!$this->hasTransactions) { 358 return false; 359 } 360 if ($this->transOff) { 361 return true; 362 } 363 if (!$ok) { 364 return $this->RollbackTrans(); 365 } 366 if ($this->transCnt) { 367 $this->transCnt -= 1; 368 } 369 $this->_autocommit = true; 370 371 $ret = $this->_connectionID->commit(); 372 $this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,true); 373 return $ret; 374 } 375 376 function RollbackTrans() 377 { 378 if(method_exists($this->_driver, 'RollbackTrans')) { 379 return $this->_driver->RollbackTrans(); 380 } 381 382 if (!$this->hasTransactions) { 383 return false; 384 } 385 if ($this->transOff) { 386 return true; 387 } 388 if ($this->transCnt) { 389 $this->transCnt -= 1; 390 } 391 $this->_autocommit = true; 392 393 $ret = $this->_connectionID->rollback(); 394 $this->_connectionID->setAttribute(PDO::ATTR_AUTOCOMMIT,true); 395 return $ret; 396 } 397 398 function Prepare($sql) 399 { 400 $this->_stmt = $this->_connectionID->prepare($sql); 401 if ($this->_stmt) { 402 return array($sql,$this->_stmt); 403 } 404 405 return false; 406 } 407 408 function PrepareStmt($sql) 409 { 410 $stmt = $this->_connectionID->prepare($sql); 411 if (!$stmt) { 412 return false; 413 } 414 $obj = new ADOPDOStatement($stmt,$this); 415 return $obj; 416 } 417 418 function CreateSequence($seqname='adodbseq',$startID=1) 419 { 420 if(method_exists($this->_driver, 'CreateSequence')) { 421 return $this->_driver->CreateSequence($seqname, $startID); 422 } 423 424 return parent::CreateSequence($seqname, $startID); 425 } 426 427 function DropSequence($seqname='adodbseq') 428 { 429 if(method_exists($this->_driver, 'DropSequence')) { 430 return $this->_driver->DropSequence($seqname); 431 } 432 433 return parent::DropSequence($seqname); 434 } 435 436 function GenID($seqname='adodbseq',$startID=1) 437 { 438 if(method_exists($this->_driver, 'GenID')) { 439 return $this->_driver->GenID($seqname, $startID); 440 } 441 442 return parent::GenID($seqname, $startID); 443 } 444 445 446 /* returns queryID or false */ 447 function _query($sql,$inputarr=false) 448 { 449 if (is_array($sql)) { 450 $stmt = $sql[1]; 451 } else { 452 $stmt = $this->_connectionID->prepare($sql); 453 } 454 #adodb_backtrace(); 455 #var_dump($this->_bindInputArray); 456 if ($stmt) { 457 $this->_driver->debug = $this->debug; 458 if ($inputarr) { 459 $ok = $stmt->execute($inputarr); 460 } 461 else { 462 $ok = $stmt->execute(); 463 } 464 } 465 466 467 $this->_errormsg = false; 468 $this->_errorno = false; 469 470 if ($ok) { 471 $this->_stmt = $stmt; 472 return $stmt; 473 } 474 475 if ($stmt) { 476 477 $arr = $stmt->errorinfo(); 478 if ((integer)$arr[1]) { 479 $this->_errormsg = $arr[2]; 480 $this->_errorno = $arr[1]; 481 } 482 483 } else { 484 $this->_errormsg = false; 485 $this->_errorno = false; 486 } 487 return false; 488 } 489 490 // returns true or false 491 function _close() 492 { 493 $this->_stmt = false; 494 return true; 495 } 496 497 function _affectedrows() 498 { 499 return ($this->_stmt) ? $this->_stmt->rowCount() : 0; 500 } 501 502 function _insertid() 503 { 504 return ($this->_connectionID) ? $this->_connectionID->lastInsertId() : 0; 505 } 506} 507 508class ADODB_pdo_base extends ADODB_pdo { 509 510 var $sysDate = "'?'"; 511 var $sysTimeStamp = "'?'"; 512 513 514 function _init($parentDriver) 515 { 516 $parentDriver->_bindInputArray = true; 517 #$parentDriver->_connectionID->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY,true); 518 } 519 520 function ServerInfo() 521 { 522 return ADOConnection::ServerInfo(); 523 } 524 525 function SelectLimit($sql,$nrows=-1,$offset=-1,$inputarr=false,$secs2cache=0) 526 { 527 $ret = ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache); 528 return $ret; 529 } 530 531 function MetaTables($ttype=false,$showSchema=false,$mask=false) 532 { 533 return false; 534 } 535 536 function MetaColumns($table,$normalize=true) 537 { 538 return false; 539 } 540} 541 542class ADOPDOStatement { 543 544 var $databaseType = "pdo"; 545 var $dataProvider = "pdo"; 546 var $_stmt; 547 var $_connectionID; 548 549 function __construct($stmt,$connection) 550 { 551 $this->_stmt = $stmt; 552 $this->_connectionID = $connection; 553 } 554 555 function Execute($inputArr=false) 556 { 557 $savestmt = $this->_connectionID->_stmt; 558 $rs = $this->_connectionID->Execute(array(false,$this->_stmt),$inputArr); 559 $this->_connectionID->_stmt = $savestmt; 560 return $rs; 561 } 562 563 function InParameter(&$var,$name,$maxLen=4000,$type=false) 564 { 565 566 if ($type) { 567 $this->_stmt->bindParam($name,$var,$type,$maxLen); 568 } 569 else { 570 $this->_stmt->bindParam($name, $var); 571 } 572 } 573 574 function Affected_Rows() 575 { 576 return ($this->_stmt) ? $this->_stmt->rowCount() : 0; 577 } 578 579 function ErrorMsg() 580 { 581 if ($this->_stmt) { 582 $arr = $this->_stmt->errorInfo(); 583 } 584 else { 585 $arr = $this->_connectionID->errorInfo(); 586 } 587 588 if (is_array($arr)) { 589 if ((integer) $arr[0] && isset($arr[2])) { 590 return $arr[2]; 591 } 592 else { 593 return ''; 594 } 595 } else { 596 return '-1'; 597 } 598 } 599 600 function NumCols() 601 { 602 return ($this->_stmt) ? $this->_stmt->columnCount() : 0; 603 } 604 605 function ErrorNo() 606 { 607 if ($this->_stmt) { 608 return $this->_stmt->errorCode(); 609 } 610 else { 611 return $this->_connectionID->errorInfo(); 612 } 613 } 614} 615 616/*-------------------------------------------------------------------------------------- 617 Class Name: Recordset 618--------------------------------------------------------------------------------------*/ 619 620class ADORecordSet_pdo extends ADORecordSet { 621 622 var $bind = false; 623 var $databaseType = "pdo"; 624 var $dataProvider = "pdo"; 625 626 function __construct($id,$mode=false) 627 { 628 if ($mode === false) { 629 global $ADODB_FETCH_MODE; 630 $mode = $ADODB_FETCH_MODE; 631 } 632 $this->adodbFetchMode = $mode; 633 switch($mode) { 634 case ADODB_FETCH_NUM: $mode = PDO::FETCH_NUM; break; 635 case ADODB_FETCH_ASSOC: $mode = PDO::FETCH_ASSOC; break; 636 637 case ADODB_FETCH_BOTH: 638 default: $mode = PDO::FETCH_BOTH; break; 639 } 640 $this->fetchMode = $mode; 641 642 $this->_queryID = $id; 643 parent::__construct($id); 644 } 645 646 647 function Init() 648 { 649 if ($this->_inited) { 650 return; 651 } 652 $this->_inited = true; 653 if ($this->_queryID) { 654 @$this->_initrs(); 655 } 656 else { 657 $this->_numOfRows = 0; 658 $this->_numOfFields = 0; 659 } 660 if ($this->_numOfRows != 0 && $this->_currentRow == -1) { 661 $this->_currentRow = 0; 662 if ($this->EOF = ($this->_fetch() === false)) { 663 $this->_numOfRows = 0; // _numOfRows could be -1 664 } 665 } else { 666 $this->EOF = true; 667 } 668 } 669 670 function _initrs() 671 { 672 global $ADODB_COUNTRECS; 673 674 $this->_numOfRows = ($ADODB_COUNTRECS) ? @$this->_queryID->rowCount() : -1; 675 if (!$this->_numOfRows) { 676 $this->_numOfRows = -1; 677 } 678 $this->_numOfFields = $this->_queryID->columnCount(); 679 } 680 681 // returns the field object 682 function FetchField($fieldOffset = -1) 683 { 684 $off=$fieldOffset+1; // offsets begin at 1 685 686 $o= new ADOFieldObject(); 687 $arr = @$this->_queryID->getColumnMeta($fieldOffset); 688 if (!$arr) { 689 $o->name = 'bad getColumnMeta()'; 690 $o->max_length = -1; 691 $o->type = 'VARCHAR'; 692 $o->precision = 0; 693 # $false = false; 694 return $o; 695 } 696 //adodb_pr($arr); 697 $o->name = $arr['name']; 698 if (isset($arr['native_type']) && $arr['native_type'] <> "null") { 699 $o->type = $arr['native_type']; 700 } 701 else { 702 $o->type = adodb_pdo_type($arr['pdo_type']); 703 } 704 $o->max_length = $arr['len']; 705 $o->precision = $arr['precision']; 706 707 switch(ADODB_ASSOC_CASE) { 708 case ADODB_ASSOC_CASE_LOWER: 709 $o->name = strtolower($o->name); 710 break; 711 case ADODB_ASSOC_CASE_UPPER: 712 $o->name = strtoupper($o->name); 713 break; 714 } 715 return $o; 716 } 717 718 function _seek($row) 719 { 720 return false; 721 } 722 723 function _fetch() 724 { 725 if (!$this->_queryID) { 726 return false; 727 } 728 729 $this->fields = $this->_queryID->fetch($this->fetchMode); 730 return !empty($this->fields); 731 } 732 733 function _close() 734 { 735 $this->_queryID = false; 736 } 737 738 function Fields($colname) 739 { 740 if ($this->adodbFetchMode != ADODB_FETCH_NUM) { 741 return @$this->fields[$colname]; 742 } 743 744 if (!$this->bind) { 745 $this->bind = array(); 746 for ($i=0; $i < $this->_numOfFields; $i++) { 747 $o = $this->FetchField($i); 748 $this->bind[strtoupper($o->name)] = $i; 749 } 750 } 751 return $this->fields[$this->bind[strtoupper($colname)]]; 752 } 753 754} 755