1<?php 2/* 3v4.992 10 Nov 2009 (c) 2000-2009 John Lim (jlim#natsoft.com). All rights reserved. 4 Released under both BSD license and Lesser GPL library license. 5 Whenever there is any discrepancy between the two licenses, 6 the BSD license will take precedence. 7 Set tabs to 8. 8 9 MySQL code that does not support transactions. Use mysqlt if you need transactions. 10 Requires mysql client. Works on Windows and Unix. 11 1221 October 2003: MySQLi extension implementation by Arjen de Rijke (a.de.rijke@xs4all.nl) 13Based on adodb 3.40 14*/ 15 16// security - hide paths 17if (!defined('ADODB_DIR')) die(); 18 19if (! defined("_ADODB_MYSQLI_LAYER")) { 20 define("_ADODB_MYSQLI_LAYER", 1 ); 21 22 // PHP5 compat... 23 if (! defined("MYSQLI_BINARY_FLAG")) define("MYSQLI_BINARY_FLAG", 128); 24 if (!defined('MYSQLI_READ_DEFAULT_GROUP')) define('MYSQLI_READ_DEFAULT_GROUP',1); 25 26 // disable adodb extension - currently incompatible. 27 global $ADODB_EXTENSION; $ADODB_EXTENSION = false; 28 29class ADODB_mysqli extends ADOConnection { 30 var $databaseType = 'mysqli'; 31 var $dataProvider = 'native'; 32 var $hasInsertID = true; 33 var $hasAffectedRows = true; 34 var $metaTablesSQL = "SHOW TABLES"; 35 var $metaColumnsSQL = "SHOW COLUMNS FROM `%s`"; 36 var $fmtTimeStamp = "'Y-m-d H:i:s'"; 37 var $hasLimit = true; 38 var $hasMoveFirst = true; 39 var $hasGenID = true; 40 var $isoDates = true; // accepts dates in ISO format 41 var $sysDate = 'CURDATE()'; 42 var $sysTimeStamp = 'NOW()'; 43 var $hasTransactions = true; 44 var $forceNewConnect = false; 45 var $poorAffectedRows = true; 46 var $clientFlags = 0; 47 var $substr = "substring"; 48 var $port = false; 49 var $socket = false; 50 var $_bindInputArray = false; 51 var $nameQuote = '`'; /// string to use to quote identifiers and names 52 var $optionFlags = array(array(MYSQLI_READ_DEFAULT_GROUP,0)); 53 var $arrayClass = 'ADORecordSet_array_mysqli'; 54 55 function ADODB_mysqli() 56 { 57 // if(!extension_loaded("mysqli")) 58 ;//trigger_error("You must have the mysqli extension installed.", E_USER_ERROR); 59 60 } 61 62 function SetTransactionMode( $transaction_mode ) 63 { 64 $this->_transmode = $transaction_mode; 65 if (empty($transaction_mode)) { 66 $this->Execute('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ'); 67 return; 68 } 69 if (!stristr($transaction_mode,'isolation')) $transaction_mode = 'ISOLATION LEVEL '.$transaction_mode; 70 $this->Execute("SET SESSION TRANSACTION ".$transaction_mode); 71 } 72 73 // returns true or false 74 // To add: parameter int $port, 75 // parameter string $socket 76 function _connect($argHostname = NULL, 77 $argUsername = NULL, 78 $argPassword = NULL, 79 $argDatabasename = NULL, $persist=false) 80 { 81 if(!extension_loaded("mysqli")) { 82 return null; 83 } 84 $this->_connectionID = @mysqli_init(); 85 86 if (is_null($this->_connectionID)) { 87 // mysqli_init only fails if insufficient memory 88 if ($this->debug) 89 ADOConnection::outp("mysqli_init() failed : " . $this->ErrorMsg()); 90 return false; 91 } 92 /* 93 I suggest a simple fix which would enable adodb and mysqli driver to 94 read connection options from the standard mysql configuration file 95 /etc/my.cnf - "Bastien Duclaux" <bduclaux#yahoo.com> 96 */ 97 foreach($this->optionFlags as $arr) { 98 mysqli_options($this->_connectionID,$arr[0],$arr[1]); 99 } 100 101 #if (!empty($this->port)) $argHostname .= ":".$this->port; 102 $ok = mysqli_real_connect($this->_connectionID, 103 $argHostname, 104 $argUsername, 105 $argPassword, 106 $argDatabasename, 107 $this->port, 108 $this->socket, 109 $this->clientFlags); 110 111 if ($ok) { 112 if ($argDatabasename) return $this->SelectDB($argDatabasename); 113 return true; 114 } else { 115 if ($this->debug) 116 ADOConnection::outp("Could't connect : " . $this->ErrorMsg()); 117 $this->_connectionID = null; 118 return false; 119 } 120 } 121 122 // returns true or false 123 // How to force a persistent connection 124 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 125 { 126 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, true); 127 128 } 129 130 // When is this used? Close old connection first? 131 // In _connect(), check $this->forceNewConnect? 132 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 133 { 134 $this->forceNewConnect = true; 135 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename); 136 } 137 138 function IfNull( $field, $ifNull ) 139 { 140 return " IFNULL($field, $ifNull) "; // if MySQL 141 } 142 143 // do not use $ADODB_COUNTRECS 144 function GetOne($sql,$inputarr=false) 145 { 146 $ret = false; 147 $rs = &$this->Execute($sql,$inputarr); 148 if ($rs) { 149 if (!$rs->EOF) $ret = reset($rs->fields); 150 $rs->Close(); 151 } 152 return $ret; 153 } 154 155 function ServerInfo() 156 { 157 $arr['description'] = $this->GetOne("select version()"); 158 $arr['version'] = ADOConnection::_findvers($arr['description']); 159 return $arr; 160 } 161 162 163 function BeginTrans() 164 { 165 if ($this->transOff) return true; 166 $this->transCnt += 1; 167 168 //$this->Execute('SET AUTOCOMMIT=0'); 169 mysqli_autocommit($this->_connectionID, false); 170 $this->Execute('BEGIN'); 171 return true; 172 } 173 174 function CommitTrans($ok=true) 175 { 176 if ($this->transOff) return true; 177 if (!$ok) return $this->RollbackTrans(); 178 179 if ($this->transCnt) $this->transCnt -= 1; 180 $this->Execute('COMMIT'); 181 182 //$this->Execute('SET AUTOCOMMIT=1'); 183 mysqli_autocommit($this->_connectionID, true); 184 return true; 185 } 186 187 function RollbackTrans() 188 { 189 if ($this->transOff) return true; 190 if ($this->transCnt) $this->transCnt -= 1; 191 $this->Execute('ROLLBACK'); 192 //$this->Execute('SET AUTOCOMMIT=1'); 193 mysqli_autocommit($this->_connectionID, true); 194 return true; 195 } 196 197 function RowLock($tables,$where='',$flds='1 as adodb_ignore') 198 { 199 if ($this->transCnt==0) $this->BeginTrans(); 200 if ($where) $where = ' where '.$where; 201 $rs =& $this->Execute("select $flds from $tables $where for update"); 202 return !empty($rs); 203 } 204 205 // if magic quotes disabled, use mysql_real_escape_string() 206 // From readme.htm: 207 // Quotes a string to be sent to the database. The $magic_quotes_enabled 208 // parameter may look funny, but the idea is if you are quoting a 209 // string extracted from a POST/GET variable, then 210 // pass get_magic_quotes_gpc() as the second parameter. This will 211 // ensure that the variable is not quoted twice, once by qstr and once 212 // by the magic_quotes_gpc. 213 // 214 //Eg. $s = $db->qstr(_GET['name'],get_magic_quotes_gpc()); 215 function qstr($s, $magic_quotes = false) 216 { 217 if (is_null($s)) return 'NULL'; 218 if (!$magic_quotes) { 219 if (PHP_VERSION >= 5) 220 return "'" . mysqli_real_escape_string($this->_connectionID, $s) . "'"; 221 222 if ($this->replaceQuote[0] == '\\') 223 $s = adodb_str_replace(array('\\',"\0"),array('\\\\',"\\\0"),$s); 224 return "'".str_replace("'",$this->replaceQuote,$s)."'"; 225 } 226 // undo magic quotes for " 227 $s = str_replace('\\"','"',$s); 228 return "'$s'"; 229 } 230 231 function _insertid() 232 { 233 $result = @mysqli_insert_id($this->_connectionID); 234 if ($result == -1){ 235 if ($this->debug) ADOConnection::outp("mysqli_insert_id() failed : " . $this->ErrorMsg()); 236 } 237 return $result; 238 } 239 240 // Only works for INSERT, UPDATE and DELETE query's 241 function _affectedrows() 242 { 243 $result = @mysqli_affected_rows($this->_connectionID); 244 if ($result == -1) { 245 if ($this->debug) ADOConnection::outp("mysqli_affected_rows() failed : " . $this->ErrorMsg()); 246 } 247 return $result; 248 } 249 250 // See http://www.mysql.com/doc/M/i/Miscellaneous_functions.html 251 // Reference on Last_Insert_ID on the recommended way to simulate sequences 252 var $_genIDSQL = "update %s set id=LAST_INSERT_ID(id+1);"; 253 var $_genSeqSQL = "create table %s (id int not null)"; 254 var $_genSeq2SQL = "insert into %s values (%s)"; 255 var $_dropSeqSQL = "drop table %s"; 256 257 function CreateSequence($seqname='adodbseq',$startID=1) 258 { 259 if (empty($this->_genSeqSQL)) return false; 260 $u = strtoupper($seqname); 261 262 $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname)); 263 if (!$ok) return false; 264 return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); 265 } 266 267 function GenID($seqname='adodbseq',$startID=1) 268 { 269 // post-nuke sets hasGenID to false 270 if (!$this->hasGenID) return false; 271 272 $getnext = sprintf($this->_genIDSQL,$seqname); 273 $holdtransOK = $this->_transOK; // save the current status 274 $rs = @$this->Execute($getnext); 275 if (!$rs) { 276 if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset 277 $u = strtoupper($seqname); 278 $this->Execute(sprintf($this->_genSeqSQL,$seqname)); 279 $cnt = $this->GetOne(sprintf($this->_genSeqCountSQL,$seqname)); 280 if (!$cnt) $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); 281 $rs = $this->Execute($getnext); 282 } 283 284 if ($rs) { 285 $this->genID = mysqli_insert_id($this->_connectionID); 286 $rs->Close(); 287 } else 288 $this->genID = 0; 289 290 return $this->genID; 291 } 292 293 function &MetaDatabases() 294 { 295 $query = "SHOW DATABASES"; 296 $ret =& $this->Execute($query); 297 if ($ret && is_object($ret)){ 298 $arr = array(); 299 while (!$ret->EOF){ 300 $db = $ret->Fields('Database'); 301 if ($db != 'mysql') $arr[] = $db; 302 $ret->MoveNext(); 303 } 304 return $arr; 305 } 306 return $ret; 307 } 308 309 310 function &MetaIndexes ($table, $primary = FALSE) 311 { 312 // save old fetch mode 313 global $ADODB_FETCH_MODE; 314 315 $false = false; 316 $save = $ADODB_FETCH_MODE; 317 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 318 if ($this->fetchMode !== FALSE) { 319 $savem = $this->SetFetchMode(FALSE); 320 } 321 322 // get index details 323 $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table)); 324 325 // restore fetchmode 326 if (isset($savem)) { 327 $this->SetFetchMode($savem); 328 } 329 $ADODB_FETCH_MODE = $save; 330 331 if (!is_object($rs)) { 332 return $false; 333 } 334 335 $indexes = array (); 336 337 // parse index data into array 338 while ($row = $rs->FetchRow()) { 339 if ($primary == FALSE AND $row[2] == 'PRIMARY') { 340 continue; 341 } 342 343 if (!isset($indexes[$row[2]])) { 344 $indexes[$row[2]] = array( 345 'unique' => ($row[1] == 0), 346 'columns' => array() 347 ); 348 } 349 350 $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4]; 351 } 352 353 // sort columns by order in the index 354 foreach ( array_keys ($indexes) as $index ) 355 { 356 ksort ($indexes[$index]['columns']); 357 } 358 359 return $indexes; 360 } 361 362 363 // Format date column in sql string given an input format that understands Y M D 364 function SQLDate($fmt, $col=false) 365 { 366 if (!$col) $col = $this->sysTimeStamp; 367 $s = 'DATE_FORMAT('.$col.",'"; 368 $concat = false; 369 $len = strlen($fmt); 370 for ($i=0; $i < $len; $i++) { 371 $ch = $fmt[$i]; 372 switch($ch) { 373 case 'Y': 374 case 'y': 375 $s .= '%Y'; 376 break; 377 case 'Q': 378 case 'q': 379 $s .= "'),Quarter($col)"; 380 381 if ($len > $i+1) $s .= ",DATE_FORMAT($col,'"; 382 else $s .= ",('"; 383 $concat = true; 384 break; 385 case 'M': 386 $s .= '%b'; 387 break; 388 389 case 'm': 390 $s .= '%m'; 391 break; 392 case 'D': 393 case 'd': 394 $s .= '%d'; 395 break; 396 397 case 'H': 398 $s .= '%H'; 399 break; 400 401 case 'h': 402 $s .= '%I'; 403 break; 404 405 case 'i': 406 $s .= '%i'; 407 break; 408 409 case 's': 410 $s .= '%s'; 411 break; 412 413 case 'a': 414 case 'A': 415 $s .= '%p'; 416 break; 417 418 case 'w': 419 $s .= '%w'; 420 break; 421 422 case 'l': 423 $s .= '%W'; 424 break; 425 426 default: 427 428 if ($ch == '\\') { 429 $i++; 430 $ch = substr($fmt,$i,1); 431 } 432 $s .= $ch; 433 break; 434 } 435 } 436 $s.="')"; 437 if ($concat) $s = "CONCAT($s)"; 438 return $s; 439 } 440 441 // returns concatenated string 442 // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator 443 function Concat() 444 { 445 $s = ""; 446 $arr = func_get_args(); 447 448 // suggestion by andrew005@mnogo.ru 449 $s = implode(',',$arr); 450 if (strlen($s) > 0) return "CONCAT($s)"; 451 else return ''; 452 } 453 454 // dayFraction is a day in floating point 455 function OffsetDate($dayFraction,$date=false) 456 { 457 if (!$date) $date = $this->sysDate; 458 459 $fraction = $dayFraction * 24 * 3600; 460 return $date . ' + INTERVAL ' . $fraction.' SECOND'; 461 462// return "from_unixtime(unix_timestamp($date)+$fraction)"; 463 } 464 465 function &MetaTables($ttype=false,$showSchema=false,$mask=false) 466 { 467 $save = $this->metaTablesSQL; 468 if ($showSchema && is_string($showSchema)) { 469 $this->metaTablesSQL .= " from $showSchema"; 470 } 471 472 if ($mask) { 473 $mask = $this->qstr($mask); 474 $this->metaTablesSQL .= " like $mask"; 475 } 476 $ret =& ADOConnection::MetaTables($ttype,$showSchema); 477 478 $this->metaTablesSQL = $save; 479 return $ret; 480 } 481 482 // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx> 483 function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE ) 484 { 485 global $ADODB_FETCH_MODE; 486 487 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true; 488 489 if ( !empty($owner) ) { 490 $table = "$owner.$table"; 491 } 492 $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table)); 493 if ($associative) $create_sql = $a_create_table["Create Table"]; 494 else $create_sql = $a_create_table[1]; 495 496 $matches = array(); 497 498 if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false; 499 $foreign_keys = array(); 500 $num_keys = count($matches[0]); 501 for ( $i = 0; $i < $num_keys; $i ++ ) { 502 $my_field = explode('`, `', $matches[1][$i]); 503 $ref_table = $matches[2][$i]; 504 $ref_field = explode('`, `', $matches[3][$i]); 505 506 if ( $upper ) { 507 $ref_table = strtoupper($ref_table); 508 } 509 510 $foreign_keys[$ref_table] = array(); 511 $num_fields = count($my_field); 512 for ( $j = 0; $j < $num_fields; $j ++ ) { 513 if ( $associative ) { 514 $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j]; 515 } else { 516 $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}"; 517 } 518 } 519 } 520 521 return $foreign_keys; 522 } 523 524 function &MetaColumns($table) 525 { 526 $false = false; 527 if (!$this->metaColumnsSQL) 528 return $false; 529 530 global $ADODB_FETCH_MODE; 531 $save = $ADODB_FETCH_MODE; 532 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 533 if ($this->fetchMode !== false) 534 $savem = $this->SetFetchMode(false); 535 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); 536 if (isset($savem)) $this->SetFetchMode($savem); 537 $ADODB_FETCH_MODE = $save; 538 if (!is_object($rs)) 539 return $false; 540 541 $retarr = array(); 542 while (!$rs->EOF) { 543 $fld = new ADOFieldObject(); 544 $fld->name = $rs->fields[0]; 545 $type = $rs->fields[1]; 546 547 // split type into type(length): 548 $fld->scale = null; 549 if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) { 550 $fld->type = $query_array[1]; 551 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; 552 $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1; 553 } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { 554 $fld->type = $query_array[1]; 555 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; 556 } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) { 557 $fld->type = $query_array[1]; 558 $fld->max_length = max(array_map("strlen",explode(",",$query_array[2]))) - 2; // PHP >= 4.0.6 559 $fld->max_length = ($fld->max_length == 0 ? 1 : $fld->max_length); 560 } else { 561 $fld->type = $type; 562 $fld->max_length = -1; 563 } 564 $fld->not_null = ($rs->fields[2] != 'YES'); 565 $fld->primary_key = ($rs->fields[3] == 'PRI'); 566 $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false); 567 $fld->binary = (strpos($type,'blob') !== false); 568 $fld->unsigned = (strpos($type,'unsigned') !== false); 569 $fld->zerofill = (strpos($type,'zerofill') !== false); 570 571 if (!$fld->binary) { 572 $d = $rs->fields[4]; 573 if ($d != '' && $d != 'NULL') { 574 $fld->has_default = true; 575 $fld->default_value = $d; 576 } else { 577 $fld->has_default = false; 578 } 579 } 580 581 if ($save == ADODB_FETCH_NUM) { 582 $retarr[] = $fld; 583 } else { 584 $retarr[strtoupper($fld->name)] = $fld; 585 } 586 $rs->MoveNext(); 587 } 588 589 $rs->Close(); 590 return $retarr; 591 } 592 593 // returns true or false 594 function SelectDB($dbName) 595 { 596// $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID); 597 $this->database = $dbName; 598 $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions 599 600 if ($this->_connectionID) { 601 $result = @mysqli_select_db($this->_connectionID, $dbName); 602 if (!$result) { 603 ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg()); 604 } 605 return $result; 606 } 607 return false; 608 } 609 610 // parameters use PostgreSQL convention, not MySQL 611 function &SelectLimit($sql, 612 $nrows = -1, 613 $offset = -1, 614 $inputarr = false, 615 $secs = 0) 616 { 617 $offsetStr = ($offset >= 0) ? "$offset," : ''; 618 if ($nrows < 0) $nrows = '18446744073709551615'; 619 620 if ($secs) 621 $rs =& $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr); 622 else 623 $rs =& $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr); 624 625 return $rs; 626 } 627 628 629 function Prepare($sql) 630 { 631 return $sql; 632 633 $stmt = $this->_connectionID->prepare($sql); 634 if (!$stmt) { 635 echo $this->ErrorMsg(); 636 return $sql; 637 } 638 return array($sql,$stmt); 639 } 640 641 642 // returns queryID or false 643 function _query($sql, $inputarr) 644 { 645 global $ADODB_COUNTRECS; 646 // Move to the next recordset, or return false if there is none. In a stored proc 647 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result 648 // returns false. I think this is because the last "recordset" is actually just the 649 // return value of the stored proc (ie the number of rows affected). 650 // Commented out for reasons of performance. You should retrieve every recordset yourself. 651 // if (!mysqli_next_result($this->connection->_connectionID)) return false; 652 653 if (is_array($sql)) { 654 $stmt = $sql[1]; 655 $a = ''; 656 foreach($inputarr as $k => $v) { 657 if (is_string($v)) $a .= 's'; 658 else if (is_integer($v)) $a .= 'i'; 659 else $a .= 'd'; 660 } 661 662 $fnarr = array_merge( array($stmt,$a) , $inputarr); 663 $ret = call_user_func_array('mysqli_stmt_bind_param',$fnarr); 664 665 $ret = mysqli_stmt_execute($stmt); 666 return $ret; 667 } 668 669 /* 670 if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) { 671 if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg()); 672 return false; 673 } 674 675 return $mysql_res; 676 */ 677 678 if( $rs = mysqli_multi_query($this->_connectionID, $sql.';') )//Contributed by "Geisel Sierote" <geisel#4up.com.br> 679 { 680 $rs = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->_connectionID ) : @mysqli_use_result( $this->_connectionID ); 681 return $rs ? $rs : true; // mysqli_more_results( $this->_connectionID ) 682 } else { 683 if($this->debug) 684 ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg()); 685 return false; 686 } 687 } 688 689 /* Returns: the last error message from previous database operation */ 690 function ErrorMsg() 691 { 692 if (empty($this->_connectionID)) 693 $this->_errorMsg = @mysqli_connect_error(); 694 else 695 $this->_errorMsg = @mysqli_error($this->_connectionID); 696 return $this->_errorMsg; 697 } 698 699 /* Returns: the last error number from previous database operation */ 700 function ErrorNo() 701 { 702 if (empty($this->_connectionID)) 703 return @mysqli_connect_errno(); 704 else 705 return @mysqli_errno($this->_connectionID); 706 } 707 708 // returns true or false 709 function _close() 710 { 711 @mysqli_close($this->_connectionID); 712 $this->_connectionID = false; 713 } 714 715 /* 716 * Maximum size of C field 717 */ 718 function CharMax() 719 { 720 return 255; 721 } 722 723 /* 724 * Maximum size of X field 725 */ 726 function TextMax() 727 { 728 return 4294967295; 729 } 730 731 732 733 // this is a set of functions for managing client encoding - very important if the encodings 734 // of your database and your output target (i.e. HTML) don't match 735 // for instance, you may have UTF8 database and server it on-site as latin1 etc. 736 // GetCharSet - get the name of the character set the client is using now 737 // Under Windows, the functions should work with MySQL 4.1.11 and above, the set of charsets supported 738 // depends on compile flags of mysql distribution 739 740 function GetCharSet() 741 { 742 //we will use ADO's builtin property charSet 743 if (!method_exists($this->_connectionID,'character_set_name')) 744 return false; 745 746 $this->charSet = @$this->_connectionID->character_set_name(); 747 if (!$this->charSet) { 748 return false; 749 } else { 750 return $this->charSet; 751 } 752 } 753 754 // SetCharSet - switch the client encoding 755 function SetCharSet($charset_name) 756 { 757 if (!method_exists($this->_connectionID,'set_charset')) 758 return false; 759 760 if ($this->charSet !== $charset_name) { 761 $if = @$this->_connectionID->set_charset($charset_name); 762 if ($if == "0" & $this->GetCharSet() == $charset_name) { 763 return true; 764 } else return false; 765 } else return true; 766 } 767 768 769 770 771} 772 773/*-------------------------------------------------------------------------------------- 774 Class Name: Recordset 775--------------------------------------------------------------------------------------*/ 776 777class ADORecordSet_mysqli extends ADORecordSet{ 778 779 var $databaseType = "mysqli"; 780 var $canSeek = true; 781 782 function ADORecordSet_mysqli($queryID, $mode = false) 783 { 784 if ($mode === false) 785 { 786 global $ADODB_FETCH_MODE; 787 $mode = $ADODB_FETCH_MODE; 788 } 789 790 switch ($mode) 791 { 792 case ADODB_FETCH_NUM: 793 $this->fetchMode = MYSQLI_NUM; 794 break; 795 case ADODB_FETCH_ASSOC: 796 $this->fetchMode = MYSQLI_ASSOC; 797 break; 798 case ADODB_FETCH_DEFAULT: 799 case ADODB_FETCH_BOTH: 800 default: 801 $this->fetchMode = MYSQLI_BOTH; 802 break; 803 } 804 $this->adodbFetchMode = $mode; 805 $this->ADORecordSet($queryID); 806 } 807 808 function _initrs() 809 { 810 global $ADODB_COUNTRECS; 811 812 $this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1; 813 $this->_numOfFields = @mysqli_num_fields($this->_queryID); 814 } 815 816/* 8171 = MYSQLI_NOT_NULL_FLAG 8182 = MYSQLI_PRI_KEY_FLAG 8194 = MYSQLI_UNIQUE_KEY_FLAG 8208 = MYSQLI_MULTIPLE_KEY_FLAG 82116 = MYSQLI_BLOB_FLAG 82232 = MYSQLI_UNSIGNED_FLAG 82364 = MYSQLI_ZEROFILL_FLAG 824128 = MYSQLI_BINARY_FLAG 825256 = MYSQLI_ENUM_FLAG 826512 = MYSQLI_AUTO_INCREMENT_FLAG 8271024 = MYSQLI_TIMESTAMP_FLAG 8282048 = MYSQLI_SET_FLAG 82932768 = MYSQLI_NUM_FLAG 83016384 = MYSQLI_PART_KEY_FLAG 83132768 = MYSQLI_GROUP_FLAG 83265536 = MYSQLI_UNIQUE_FLAG 833131072 = MYSQLI_BINCMP_FLAG 834*/ 835 836 function &FetchField($fieldOffset = -1) 837 { 838 $fieldnr = $fieldOffset; 839 if ($fieldOffset != -1) { 840 $fieldOffset = @mysqli_field_seek($this->_queryID, $fieldnr); 841 } 842 $o = @mysqli_fetch_field($this->_queryID); 843 if (!$o) {$false = false; return $false;} 844 /* Properties of an ADOFieldObject as set by MetaColumns */ 845 $o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG; 846 $o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG; 847 $o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG; 848 $o->binary = $o->flags & MYSQLI_BINARY_FLAG; 849 // $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */ 850 $o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG; 851 852 return $o; 853 } 854 855 function &GetRowAssoc($upper = true) 856 { 857 if ($this->fetchMode == MYSQLI_ASSOC && !$upper) 858 return $this->fields; 859 $row =& ADORecordSet::GetRowAssoc($upper); 860 return $row; 861 } 862 863 /* Use associative array to get fields array */ 864 function Fields($colname) 865 { 866 if ($this->fetchMode != MYSQLI_NUM) 867 return @$this->fields[$colname]; 868 869 if (!$this->bind) { 870 $this->bind = array(); 871 for ($i = 0; $i < $this->_numOfFields; $i++) { 872 $o = $this->FetchField($i); 873 $this->bind[strtoupper($o->name)] = $i; 874 } 875 } 876 return $this->fields[$this->bind[strtoupper($colname)]]; 877 } 878 879 function _seek($row) 880 { 881 if ($this->_numOfRows == 0) 882 return false; 883 884 if ($row < 0) 885 return false; 886 887 mysqli_data_seek($this->_queryID, $row); 888 $this->EOF = false; 889 return true; 890 } 891 892 893 function NextRecordSet() 894 { 895 global $ADODB_COUNTRECS; 896 897 mysqli_free_result($this->_queryID); 898 $this->_queryID = -1; 899 // Move to the next recordset, or return false if there is none. In a stored proc 900 // call, mysqli_next_result returns true for the last "recordset", but mysqli_store_result 901 // returns false. I think this is because the last "recordset" is actually just the 902 // return value of the stored proc (ie the number of rows affected). 903 if(!mysqli_next_result($this->connection->_connectionID)) { 904 return false; 905 } 906 // CD: There is no $this->_connectionID variable, at least in the ADO version I'm using 907 $this->_queryID = ($ADODB_COUNTRECS) ? @mysqli_store_result( $this->connection->_connectionID ) 908 : @mysqli_use_result( $this->connection->_connectionID ); 909 if(!$this->_queryID) { 910 return false; 911 } 912 $this->_inited = false; 913 $this->bind = false; 914 $this->_currentRow = -1; 915 $this->Init(); 916 return true; 917 } 918 919 // 10% speedup to move MoveNext to child class 920 // This is the only implementation that works now (23-10-2003). 921 // Other functions return no or the wrong results. 922 function MoveNext() 923 { 924 if ($this->EOF) return false; 925 $this->_currentRow++; 926 $this->fields = @mysqli_fetch_array($this->_queryID,$this->fetchMode); 927 928 if (is_array($this->fields)) return true; 929 $this->EOF = true; 930 return false; 931 } 932 933 function _fetch() 934 { 935 $this->fields = mysqli_fetch_array($this->_queryID,$this->fetchMode); 936 return is_array($this->fields); 937 } 938 939 function _close() 940 { 941 mysqli_free_result($this->_queryID); 942 $this->_queryID = false; 943 } 944 945/* 946 9470 = MYSQLI_TYPE_DECIMAL 9481 = MYSQLI_TYPE_CHAR 9491 = MYSQLI_TYPE_TINY 9502 = MYSQLI_TYPE_SHORT 9513 = MYSQLI_TYPE_LONG 9524 = MYSQLI_TYPE_FLOAT 9535 = MYSQLI_TYPE_DOUBLE 9546 = MYSQLI_TYPE_NULL 9557 = MYSQLI_TYPE_TIMESTAMP 9568 = MYSQLI_TYPE_LONGLONG 9579 = MYSQLI_TYPE_INT24 95810 = MYSQLI_TYPE_DATE 95911 = MYSQLI_TYPE_TIME 96012 = MYSQLI_TYPE_DATETIME 96113 = MYSQLI_TYPE_YEAR 96214 = MYSQLI_TYPE_NEWDATE 963247 = MYSQLI_TYPE_ENUM 964248 = MYSQLI_TYPE_SET 965249 = MYSQLI_TYPE_TINY_BLOB 966250 = MYSQLI_TYPE_MEDIUM_BLOB 967251 = MYSQLI_TYPE_LONG_BLOB 968252 = MYSQLI_TYPE_BLOB 969253 = MYSQLI_TYPE_VAR_STRING 970254 = MYSQLI_TYPE_STRING 971255 = MYSQLI_TYPE_GEOMETRY 972*/ 973 974 function MetaType($t, $len = -1, $fieldobj = false) 975 { 976 if (is_object($t)) { 977 $fieldobj = $t; 978 $t = $fieldobj->type; 979 $len = $fieldobj->max_length; 980 } 981 982 983 $len = -1; // mysql max_length is not accurate 984 switch (strtoupper($t)) { 985 case 'STRING': 986 case 'CHAR': 987 case 'VARCHAR': 988 case 'TINYBLOB': 989 case 'TINYTEXT': 990 case 'ENUM': 991 case 'SET': 992 993 case MYSQLI_TYPE_TINY_BLOB : 994 #case MYSQLI_TYPE_CHAR : 995 case MYSQLI_TYPE_STRING : 996 case MYSQLI_TYPE_ENUM : 997 case MYSQLI_TYPE_SET : 998 case 253 : 999 if ($len <= $this->blobSize) return 'C'; 1000 1001 case 'TEXT': 1002 case 'LONGTEXT': 1003 case 'MEDIUMTEXT': 1004 return 'X'; 1005 1006 1007 // php_mysql extension always returns 'blob' even if 'text' 1008 // so we have to check whether binary... 1009 case 'IMAGE': 1010 case 'LONGBLOB': 1011 case 'BLOB': 1012 case 'MEDIUMBLOB': 1013 1014 case MYSQLI_TYPE_BLOB : 1015 case MYSQLI_TYPE_LONG_BLOB : 1016 case MYSQLI_TYPE_MEDIUM_BLOB : 1017 1018 return !empty($fieldobj->binary) ? 'B' : 'X'; 1019 case 'YEAR': 1020 case 'DATE': 1021 case MYSQLI_TYPE_DATE : 1022 case MYSQLI_TYPE_YEAR : 1023 1024 return 'D'; 1025 1026 case 'TIME': 1027 case 'DATETIME': 1028 case 'TIMESTAMP': 1029 1030 case MYSQLI_TYPE_DATETIME : 1031 case MYSQLI_TYPE_NEWDATE : 1032 case MYSQLI_TYPE_TIME : 1033 case MYSQLI_TYPE_TIMESTAMP : 1034 1035 return 'T'; 1036 1037 case 'INT': 1038 case 'INTEGER': 1039 case 'BIGINT': 1040 case 'TINYINT': 1041 case 'MEDIUMINT': 1042 case 'SMALLINT': 1043 1044 case MYSQLI_TYPE_INT24 : 1045 case MYSQLI_TYPE_LONG : 1046 case MYSQLI_TYPE_LONGLONG : 1047 case MYSQLI_TYPE_SHORT : 1048 case MYSQLI_TYPE_TINY : 1049 1050 if (!empty($fieldobj->primary_key)) return 'R'; 1051 1052 return 'I'; 1053 1054 1055 // Added floating-point types 1056 // Maybe not necessery. 1057 case 'FLOAT': 1058 case 'DOUBLE': 1059 // case 'DOUBLE PRECISION': 1060 case 'DECIMAL': 1061 case 'DEC': 1062 case 'FIXED': 1063 default: 1064 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>"; 1065 return 'N'; 1066 } 1067 } // function 1068 1069 1070} // rs class 1071 1072} 1073 1074class ADORecordSet_array_mysqli extends ADORecordSet_array { 1075 function ADORecordSet_array_mysqli($id=-1,$mode=false) 1076 { 1077 $this->ADORecordSet_array($id,$mode); 1078 } 1079 1080 1081 function MetaType($t, $len = -1, $fieldobj = false) 1082 { 1083 if (is_object($t)) { 1084 $fieldobj = $t; 1085 $t = $fieldobj->type; 1086 $len = $fieldobj->max_length; 1087 } 1088 1089 1090 $len = -1; // mysql max_length is not accurate 1091 switch (strtoupper($t)) { 1092 case 'STRING': 1093 case 'CHAR': 1094 case 'VARCHAR': 1095 case 'TINYBLOB': 1096 case 'TINYTEXT': 1097 case 'ENUM': 1098 case 'SET': 1099 1100 case MYSQLI_TYPE_TINY_BLOB : 1101 #case MYSQLI_TYPE_CHAR : 1102 case MYSQLI_TYPE_STRING : 1103 case MYSQLI_TYPE_ENUM : 1104 case MYSQLI_TYPE_SET : 1105 case 253 : 1106 if ($len <= $this->blobSize) return 'C'; 1107 1108 case 'TEXT': 1109 case 'LONGTEXT': 1110 case 'MEDIUMTEXT': 1111 return 'X'; 1112 1113 1114 // php_mysql extension always returns 'blob' even if 'text' 1115 // so we have to check whether binary... 1116 case 'IMAGE': 1117 case 'LONGBLOB': 1118 case 'BLOB': 1119 case 'MEDIUMBLOB': 1120 1121 case MYSQLI_TYPE_BLOB : 1122 case MYSQLI_TYPE_LONG_BLOB : 1123 case MYSQLI_TYPE_MEDIUM_BLOB : 1124 1125 return !empty($fieldobj->binary) ? 'B' : 'X'; 1126 case 'YEAR': 1127 case 'DATE': 1128 case MYSQLI_TYPE_DATE : 1129 case MYSQLI_TYPE_YEAR : 1130 1131 return 'D'; 1132 1133 case 'TIME': 1134 case 'DATETIME': 1135 case 'TIMESTAMP': 1136 1137 case MYSQLI_TYPE_DATETIME : 1138 case MYSQLI_TYPE_NEWDATE : 1139 case MYSQLI_TYPE_TIME : 1140 case MYSQLI_TYPE_TIMESTAMP : 1141 1142 return 'T'; 1143 1144 case 'INT': 1145 case 'INTEGER': 1146 case 'BIGINT': 1147 case 'TINYINT': 1148 case 'MEDIUMINT': 1149 case 'SMALLINT': 1150 1151 case MYSQLI_TYPE_INT24 : 1152 case MYSQLI_TYPE_LONG : 1153 case MYSQLI_TYPE_LONGLONG : 1154 case MYSQLI_TYPE_SHORT : 1155 case MYSQLI_TYPE_TINY : 1156 1157 if (!empty($fieldobj->primary_key)) return 'R'; 1158 1159 return 'I'; 1160 1161 1162 // Added floating-point types 1163 // Maybe not necessery. 1164 case 'FLOAT': 1165 case 'DOUBLE': 1166 // case 'DOUBLE PRECISION': 1167 case 'DECIMAL': 1168 case 'DEC': 1169 case 'FIXED': 1170 default: 1171 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>"; 1172 return 'N'; 1173 } 1174 } // function 1175 1176} 1177 1178?>