1<?php 2/* 3V4.98 13 Feb 2008 (c) 2000-2008 John Lim (jlim#natsoft.com.my). 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 $_genSeqCountSQL = "select count(*) from %s"; 255 var $_genSeq2SQL = "insert into %s values (%s)"; 256 var $_dropSeqSQL = "drop table %s"; 257 258 function CreateSequence($seqname='adodbseq',$startID=1) 259 { 260 if (empty($this->_genSeqSQL)) return false; 261 $u = strtoupper($seqname); 262 263 $ok = $this->Execute(sprintf($this->_genSeqSQL,$seqname)); 264 if (!$ok) return false; 265 return $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); 266 } 267 268 function GenID($seqname='adodbseq',$startID=1) 269 { 270 // post-nuke sets hasGenID to false 271 if (!$this->hasGenID) return false; 272 273 $getnext = sprintf($this->_genIDSQL,$seqname); 274 $holdtransOK = $this->_transOK; // save the current status 275 $rs = @$this->Execute($getnext); 276 if (!$rs) { 277 if ($holdtransOK) $this->_transOK = true; //if the status was ok before reset 278 $u = strtoupper($seqname); 279 $this->Execute(sprintf($this->_genSeqSQL,$seqname)); 280 $cnt = $this->GetOne(sprintf($this->_genSeqCountSQL,$seqname)); 281 if (!$cnt) $this->Execute(sprintf($this->_genSeq2SQL,$seqname,$startID-1)); 282 $rs = $this->Execute($getnext); 283 } 284 285 if ($rs) { 286 $this->genID = mysqli_insert_id($this->_connectionID); 287 $rs->Close(); 288 } else 289 $this->genID = 0; 290 291 return $this->genID; 292 } 293 294 function &MetaDatabases() 295 { 296 $query = "SHOW DATABASES"; 297 $ret =& $this->Execute($query); 298 if ($ret && is_object($ret)){ 299 $arr = array(); 300 while (!$ret->EOF){ 301 $db = $ret->Fields('Database'); 302 if ($db != 'mysql') $arr[] = $db; 303 $ret->MoveNext(); 304 } 305 return $arr; 306 } 307 return $ret; 308 } 309 310 311 function &MetaIndexes ($table, $primary = FALSE) 312 { 313 // save old fetch mode 314 global $ADODB_FETCH_MODE; 315 316 $false = false; 317 $save = $ADODB_FETCH_MODE; 318 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 319 if ($this->fetchMode !== FALSE) { 320 $savem = $this->SetFetchMode(FALSE); 321 } 322 323 // get index details 324 $rs = $this->Execute(sprintf('SHOW INDEXES FROM %s',$table)); 325 326 // restore fetchmode 327 if (isset($savem)) { 328 $this->SetFetchMode($savem); 329 } 330 $ADODB_FETCH_MODE = $save; 331 332 if (!is_object($rs)) { 333 return $false; 334 } 335 336 $indexes = array (); 337 338 // parse index data into array 339 while ($row = $rs->FetchRow()) { 340 if ($primary == FALSE AND $row[2] == 'PRIMARY') { 341 continue; 342 } 343 344 if (!isset($indexes[$row[2]])) { 345 $indexes[$row[2]] = array( 346 'unique' => ($row[1] == 0), 347 'columns' => array() 348 ); 349 } 350 351 $indexes[$row[2]]['columns'][$row[3] - 1] = $row[4]; 352 } 353 354 // sort columns by order in the index 355 foreach ( array_keys ($indexes) as $index ) 356 { 357 ksort ($indexes[$index]['columns']); 358 } 359 360 return $indexes; 361 } 362 363 364 // Format date column in sql string given an input format that understands Y M D 365 function SQLDate($fmt, $col=false) 366 { 367 if (!$col) $col = $this->sysTimeStamp; 368 $s = 'DATE_FORMAT('.$col.",'"; 369 $concat = false; 370 $len = strlen($fmt); 371 for ($i=0; $i < $len; $i++) { 372 $ch = $fmt[$i]; 373 switch($ch) { 374 case 'Y': 375 case 'y': 376 $s .= '%Y'; 377 break; 378 case 'Q': 379 case 'q': 380 $s .= "'),Quarter($col)"; 381 382 if ($len > $i+1) $s .= ",DATE_FORMAT($col,'"; 383 else $s .= ",('"; 384 $concat = true; 385 break; 386 case 'M': 387 $s .= '%b'; 388 break; 389 390 case 'm': 391 $s .= '%m'; 392 break; 393 case 'D': 394 case 'd': 395 $s .= '%d'; 396 break; 397 398 case 'H': 399 $s .= '%H'; 400 break; 401 402 case 'h': 403 $s .= '%I'; 404 break; 405 406 case 'i': 407 $s .= '%i'; 408 break; 409 410 case 's': 411 $s .= '%s'; 412 break; 413 414 case 'a': 415 case 'A': 416 $s .= '%p'; 417 break; 418 419 case 'w': 420 $s .= '%w'; 421 break; 422 423 case 'l': 424 $s .= '%W'; 425 break; 426 427 default: 428 429 if ($ch == '\\') { 430 $i++; 431 $ch = substr($fmt,$i,1); 432 } 433 $s .= $ch; 434 break; 435 } 436 } 437 $s.="')"; 438 if ($concat) $s = "CONCAT($s)"; 439 return $s; 440 } 441 442 // returns concatenated string 443 // much easier to run "mysqld --ansi" or "mysqld --sql-mode=PIPES_AS_CONCAT" and use || operator 444 function Concat() 445 { 446 $s = ""; 447 $arr = func_get_args(); 448 449 // suggestion by andrew005@mnogo.ru 450 $s = implode(',',$arr); 451 if (strlen($s) > 0) return "CONCAT($s)"; 452 else return ''; 453 } 454 455 // dayFraction is a day in floating point 456 function OffsetDate($dayFraction,$date=false) 457 { 458 if (!$date) $date = $this->sysDate; 459 460 $fraction = $dayFraction * 24 * 3600; 461 return $date . ' + INTERVAL ' . $fraction.' SECOND'; 462 463// return "from_unixtime(unix_timestamp($date)+$fraction)"; 464 } 465 466 function &MetaTables($ttype=false,$showSchema=false,$mask=false) 467 { 468 $save = $this->metaTablesSQL; 469 if ($showSchema && is_string($showSchema)) { 470 $this->metaTablesSQL .= " from $showSchema"; 471 } 472 473 if ($mask) { 474 $mask = $this->qstr($mask); 475 $this->metaTablesSQL .= " like $mask"; 476 } 477 $ret =& ADOConnection::MetaTables($ttype,$showSchema); 478 479 $this->metaTablesSQL = $save; 480 return $ret; 481 } 482 483 // "Innox - Juan Carlos Gonzalez" <jgonzalez#innox.com.mx> 484 function MetaForeignKeys( $table, $owner = FALSE, $upper = FALSE, $associative = FALSE ) 485 { 486 global $ADODB_FETCH_MODE; 487 488 if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC || $this->fetchMode == ADODB_FETCH_ASSOC) $associative = true; 489 490 if ( !empty($owner) ) { 491 $table = "$owner.$table"; 492 } 493 $a_create_table = $this->getRow(sprintf('SHOW CREATE TABLE %s', $table)); 494 if ($associative) $create_sql = $a_create_table["Create Table"]; 495 else $create_sql = $a_create_table[1]; 496 497 $matches = array(); 498 499 if (!preg_match_all("/FOREIGN KEY \(`(.*?)`\) REFERENCES `(.*?)` \(`(.*?)`\)/", $create_sql, $matches)) return false; 500 $foreign_keys = array(); 501 $num_keys = count($matches[0]); 502 for ( $i = 0; $i < $num_keys; $i ++ ) { 503 $my_field = explode('`, `', $matches[1][$i]); 504 $ref_table = $matches[2][$i]; 505 $ref_field = explode('`, `', $matches[3][$i]); 506 507 if ( $upper ) { 508 $ref_table = strtoupper($ref_table); 509 } 510 511 $foreign_keys[$ref_table] = array(); 512 $num_fields = count($my_field); 513 for ( $j = 0; $j < $num_fields; $j ++ ) { 514 if ( $associative ) { 515 $foreign_keys[$ref_table][$ref_field[$j]] = $my_field[$j]; 516 } else { 517 $foreign_keys[$ref_table][] = "{$my_field[$j]}={$ref_field[$j]}"; 518 } 519 } 520 } 521 522 return $foreign_keys; 523 } 524 525 function &MetaColumns($table) 526 { 527 $false = false; 528 if (!$this->metaColumnsSQL) 529 return $false; 530 531 global $ADODB_FETCH_MODE; 532 $save = $ADODB_FETCH_MODE; 533 $ADODB_FETCH_MODE = ADODB_FETCH_NUM; 534 if ($this->fetchMode !== false) 535 $savem = $this->SetFetchMode(false); 536 $rs = $this->Execute(sprintf($this->metaColumnsSQL,$table)); 537 if (isset($savem)) $this->SetFetchMode($savem); 538 $ADODB_FETCH_MODE = $save; 539 if (!is_object($rs)) 540 return $false; 541 542 $retarr = array(); 543 while (!$rs->EOF) { 544 $fld = new ADOFieldObject(); 545 $fld->name = $rs->fields[0]; 546 $type = $rs->fields[1]; 547 548 // split type into type(length): 549 $fld->scale = null; 550 if (preg_match("/^(.+)\((\d+),(\d+)/", $type, $query_array)) { 551 $fld->type = $query_array[1]; 552 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; 553 $fld->scale = is_numeric($query_array[3]) ? $query_array[3] : -1; 554 } elseif (preg_match("/^(.+)\((\d+)/", $type, $query_array)) { 555 $fld->type = $query_array[1]; 556 $fld->max_length = is_numeric($query_array[2]) ? $query_array[2] : -1; 557 } elseif (preg_match("/^(enum)\((.*)\)$/i", $type, $query_array)) { 558 $fld->type = $query_array[1]; 559 $fld->max_length = max(array_map("strlen",explode(",",$query_array[2]))) - 2; // PHP >= 4.0.6 560 $fld->max_length = ($fld->max_length == 0 ? 1 : $fld->max_length); 561 } else { 562 $fld->type = $type; 563 $fld->max_length = -1; 564 } 565 $fld->not_null = ($rs->fields[2] != 'YES'); 566 $fld->primary_key = ($rs->fields[3] == 'PRI'); 567 $fld->auto_increment = (strpos($rs->fields[5], 'auto_increment') !== false); 568 $fld->binary = (strpos($type,'blob') !== false); 569 $fld->unsigned = (strpos($type,'unsigned') !== false); 570 $fld->zerofill = (strpos($type,'zerofill') !== false); 571 572 if (!$fld->binary) { 573 $d = $rs->fields[4]; 574 if ($d != '' && $d != 'NULL') { 575 $fld->has_default = true; 576 $fld->default_value = $d; 577 } else { 578 $fld->has_default = false; 579 } 580 } 581 582 if ($save == ADODB_FETCH_NUM) { 583 $retarr[] = $fld; 584 } else { 585 $retarr[strtoupper($fld->name)] = $fld; 586 } 587 $rs->MoveNext(); 588 } 589 590 $rs->Close(); 591 return $retarr; 592 } 593 594 // returns true or false 595 function SelectDB($dbName) 596 { 597// $this->_connectionID = $this->mysqli_resolve_link($this->_connectionID); 598 $this->database = $dbName; 599 $this->databaseName = $dbName; # obsolete, retained for compat with older adodb versions 600 601 if ($this->_connectionID) { 602 $result = @mysqli_select_db($this->_connectionID, $dbName); 603 if (!$result) { 604 ADOConnection::outp("Select of database " . $dbName . " failed. " . $this->ErrorMsg()); 605 } 606 return $result; 607 } 608 return false; 609 } 610 611 // parameters use PostgreSQL convention, not MySQL 612 function &SelectLimit($sql, 613 $nrows = -1, 614 $offset = -1, 615 $inputarr = false, 616 $secs = 0) 617 { 618 $offsetStr = ($offset >= 0) ? "$offset," : ''; 619 if ($nrows < 0) $nrows = '18446744073709551615'; 620 621 if ($secs) 622 $rs =& $this->CacheExecute($secs, $sql . " LIMIT $offsetStr$nrows" , $inputarr); 623 else 624 $rs =& $this->Execute($sql . " LIMIT $offsetStr$nrows" , $inputarr); 625 626 return $rs; 627 } 628 629 630 function Prepare($sql) 631 { 632 return $sql; 633 634 $stmt = $this->_connectionID->prepare($sql); 635 if (!$stmt) { 636 echo $this->ErrorMsg(); 637 return $sql; 638 } 639 return array($sql,$stmt); 640 } 641 642 643 // returns queryID or false 644 function _query($sql, $inputarr) 645 { 646 global $ADODB_COUNTRECS; 647 648 if (is_array($sql)) { 649 $stmt = $sql[1]; 650 $a = ''; 651 foreach($inputarr as $k => $v) { 652 if (is_string($v)) $a .= 's'; 653 else if (is_integer($v)) $a .= 'i'; 654 else $a .= 'd'; 655 } 656 657 $fnarr = array_merge( array($stmt,$a) , $inputarr); 658 $ret = call_user_func_array('mysqli_stmt_bind_param',$fnarr); 659 660 $ret = mysqli_stmt_execute($stmt); 661 return $ret; 662 } 663 if (!$mysql_res = mysqli_query($this->_connectionID, $sql, ($ADODB_COUNTRECS) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT)) { 664 if ($this->debug) ADOConnection::outp("Query: " . $sql . " failed. " . $this->ErrorMsg()); 665 return false; 666 } 667 668 return $mysql_res; 669 } 670 671 /* Returns: the last error message from previous database operation */ 672 function ErrorMsg() 673 { 674 if (empty($this->_connectionID)) 675 $this->_errorMsg = @mysqli_connect_error(); 676 else 677 $this->_errorMsg = @mysqli_error($this->_connectionID); 678 return $this->_errorMsg; 679 } 680 681 /* Returns: the last error number from previous database operation */ 682 function ErrorNo() 683 { 684 if(extension_loaded("mysqli")) { 685 if (empty($this->_connectionID)) 686 return @mysqli_connect_errno(); 687 else 688 return @mysqli_errno($this->_connectionID); 689 } else { 690 return parent::ErrorNo(); 691 } 692 } 693 694 // returns true or false 695 function _close() 696 { 697 @mysqli_close($this->_connectionID); 698 $this->_connectionID = false; 699 } 700 701 /* 702 * Maximum size of C field 703 */ 704 function CharMax() 705 { 706 return 255; 707 } 708 709 /* 710 * Maximum size of X field 711 */ 712 function TextMax() 713 { 714 return 4294967295; 715 } 716 717 718 719 // this is a set of functions for managing client encoding - very important if the encodings 720 // of your database and your output target (i.e. HTML) don't match 721 // for instance, you may have UTF8 database and server it on-site as latin1 etc. 722 // GetCharSet - get the name of the character set the client is using now 723 // Under Windows, the functions should work with MySQL 4.1.11 and above, the set of charsets supported 724 // depends on compile flags of mysql distribution 725 726 function GetCharSet() 727 { 728 //we will use ADO's builtin property charSet 729 if (!method_exists($this->_connectionID,'character_set_name')) 730 return false; 731 732 $this->charSet = @$this->_connectionID->character_set_name(); 733 if (!$this->charSet) { 734 return false; 735 } else { 736 return $this->charSet; 737 } 738 } 739 740 // SetCharSet - switch the client encoding 741 function SetCharSet($charset_name) 742 { 743 if (!method_exists($this->_connectionID,'set_charset')) 744 return false; 745 746 if ($this->charSet !== $charset_name) { 747 $if = @$this->_connectionID->set_charset($charset_name); 748 if ($if == "0" & $this->GetCharSet() == $charset_name) { 749 return true; 750 } else return false; 751 } else return true; 752 } 753 754 755 756 757} 758 759/*-------------------------------------------------------------------------------------- 760 Class Name: Recordset 761--------------------------------------------------------------------------------------*/ 762 763class ADORecordSet_mysqli extends ADORecordSet{ 764 765 var $databaseType = "mysqli"; 766 var $canSeek = true; 767 768 function ADORecordSet_mysqli($queryID, $mode = false) 769 { 770 if ($mode === false) 771 { 772 global $ADODB_FETCH_MODE; 773 $mode = $ADODB_FETCH_MODE; 774 } 775 776 switch ($mode) 777 { 778 case ADODB_FETCH_NUM: 779 $this->fetchMode = MYSQLI_NUM; 780 break; 781 case ADODB_FETCH_ASSOC: 782 $this->fetchMode = MYSQLI_ASSOC; 783 break; 784 case ADODB_FETCH_DEFAULT: 785 case ADODB_FETCH_BOTH: 786 default: 787 $this->fetchMode = MYSQLI_BOTH; 788 break; 789 } 790 $this->adodbFetchMode = $mode; 791 $this->ADORecordSet($queryID); 792 } 793 794 function _initrs() 795 { 796 global $ADODB_COUNTRECS; 797 798 $this->_numOfRows = $ADODB_COUNTRECS ? @mysqli_num_rows($this->_queryID) : -1; 799 $this->_numOfFields = @mysqli_num_fields($this->_queryID); 800 } 801 802/* 8031 = MYSQLI_NOT_NULL_FLAG 8042 = MYSQLI_PRI_KEY_FLAG 8054 = MYSQLI_UNIQUE_KEY_FLAG 8068 = MYSQLI_MULTIPLE_KEY_FLAG 80716 = MYSQLI_BLOB_FLAG 80832 = MYSQLI_UNSIGNED_FLAG 80964 = MYSQLI_ZEROFILL_FLAG 810128 = MYSQLI_BINARY_FLAG 811256 = MYSQLI_ENUM_FLAG 812512 = MYSQLI_AUTO_INCREMENT_FLAG 8131024 = MYSQLI_TIMESTAMP_FLAG 8142048 = MYSQLI_SET_FLAG 81532768 = MYSQLI_NUM_FLAG 81616384 = MYSQLI_PART_KEY_FLAG 81732768 = MYSQLI_GROUP_FLAG 81865536 = MYSQLI_UNIQUE_FLAG 819131072 = MYSQLI_BINCMP_FLAG 820*/ 821 822 function &FetchField($fieldOffset = -1) 823 { 824 $fieldnr = $fieldOffset; 825 if ($fieldOffset != -1) { 826 $fieldOffset = mysqli_field_seek($this->_queryID, $fieldnr); 827 } 828 $o = mysqli_fetch_field($this->_queryID); 829 /* Properties of an ADOFieldObject as set by MetaColumns */ 830 $o->primary_key = $o->flags & MYSQLI_PRI_KEY_FLAG; 831 $o->not_null = $o->flags & MYSQLI_NOT_NULL_FLAG; 832 $o->auto_increment = $o->flags & MYSQLI_AUTO_INCREMENT_FLAG; 833 $o->binary = $o->flags & MYSQLI_BINARY_FLAG; 834 // $o->blob = $o->flags & MYSQLI_BLOB_FLAG; /* not returned by MetaColumns */ 835 $o->unsigned = $o->flags & MYSQLI_UNSIGNED_FLAG; 836 837 return $o; 838 } 839 840 function &GetRowAssoc($upper = true) 841 { 842 if ($this->fetchMode == MYSQLI_ASSOC && !$upper) 843 return $this->fields; 844 $row =& ADORecordSet::GetRowAssoc($upper); 845 return $row; 846 } 847 848 /* Use associative array to get fields array */ 849 function Fields($colname) 850 { 851 if ($this->fetchMode != MYSQLI_NUM) 852 return @$this->fields[$colname]; 853 854 if (!$this->bind) { 855 $this->bind = array(); 856 for ($i = 0; $i < $this->_numOfFields; $i++) { 857 $o = $this->FetchField($i); 858 $this->bind[strtoupper($o->name)] = $i; 859 } 860 } 861 return $this->fields[$this->bind[strtoupper($colname)]]; 862 } 863 864 function _seek($row) 865 { 866 if ($this->_numOfRows == 0) 867 return false; 868 869 if ($row < 0) 870 return false; 871 872 mysqli_data_seek($this->_queryID, $row); 873 $this->EOF = false; 874 return true; 875 } 876 877 // 10% speedup to move MoveNext to child class 878 // This is the only implementation that works now (23-10-2003). 879 // Other functions return no or the wrong results. 880 function MoveNext() 881 { 882 if ($this->EOF) return false; 883 $this->_currentRow++; 884 $this->fields = @mysqli_fetch_array($this->_queryID,$this->fetchMode); 885 886 if (is_array($this->fields)) return true; 887 $this->EOF = true; 888 return false; 889 } 890 891 function _fetch() 892 { 893 $this->fields = mysqli_fetch_array($this->_queryID,$this->fetchMode); 894 return is_array($this->fields); 895 } 896 897 function _close() 898 { 899 mysqli_free_result($this->_queryID); 900 $this->_queryID = false; 901 } 902 903/* 904 9050 = MYSQLI_TYPE_DECIMAL 9061 = MYSQLI_TYPE_CHAR 9071 = MYSQLI_TYPE_TINY 9082 = MYSQLI_TYPE_SHORT 9093 = MYSQLI_TYPE_LONG 9104 = MYSQLI_TYPE_FLOAT 9115 = MYSQLI_TYPE_DOUBLE 9126 = MYSQLI_TYPE_NULL 9137 = MYSQLI_TYPE_TIMESTAMP 9148 = MYSQLI_TYPE_LONGLONG 9159 = MYSQLI_TYPE_INT24 91610 = MYSQLI_TYPE_DATE 91711 = MYSQLI_TYPE_TIME 91812 = MYSQLI_TYPE_DATETIME 91913 = MYSQLI_TYPE_YEAR 92014 = MYSQLI_TYPE_NEWDATE 921247 = MYSQLI_TYPE_ENUM 922248 = MYSQLI_TYPE_SET 923249 = MYSQLI_TYPE_TINY_BLOB 924250 = MYSQLI_TYPE_MEDIUM_BLOB 925251 = MYSQLI_TYPE_LONG_BLOB 926252 = MYSQLI_TYPE_BLOB 927253 = MYSQLI_TYPE_VAR_STRING 928254 = MYSQLI_TYPE_STRING 929255 = MYSQLI_TYPE_GEOMETRY 930*/ 931 932 function MetaType($t, $len = -1, $fieldobj = false) 933 { 934 if (is_object($t)) { 935 $fieldobj = $t; 936 $t = $fieldobj->type; 937 $len = $fieldobj->max_length; 938 } 939 940 941 $len = -1; // mysql max_length is not accurate 942 switch (strtoupper($t)) { 943 case 'STRING': 944 case 'CHAR': 945 case 'VARCHAR': 946 case 'TINYBLOB': 947 case 'TINYTEXT': 948 case 'ENUM': 949 case 'SET': 950 951 case MYSQLI_TYPE_TINY_BLOB : 952 #case MYSQLI_TYPE_CHAR : 953 case MYSQLI_TYPE_STRING : 954 case MYSQLI_TYPE_ENUM : 955 case MYSQLI_TYPE_SET : 956 case 253 : 957 if ($len <= $this->blobSize) return 'C'; 958 959 case 'TEXT': 960 case 'LONGTEXT': 961 case 'MEDIUMTEXT': 962 return 'X'; 963 964 965 // php_mysql extension always returns 'blob' even if 'text' 966 // so we have to check whether binary... 967 case 'IMAGE': 968 case 'LONGBLOB': 969 case 'BLOB': 970 case 'MEDIUMBLOB': 971 972 case MYSQLI_TYPE_BLOB : 973 case MYSQLI_TYPE_LONG_BLOB : 974 case MYSQLI_TYPE_MEDIUM_BLOB : 975 976 return !empty($fieldobj->binary) ? 'B' : 'X'; 977 case 'YEAR': 978 case 'DATE': 979 case MYSQLI_TYPE_DATE : 980 case MYSQLI_TYPE_YEAR : 981 982 return 'D'; 983 984 case 'TIME': 985 case 'DATETIME': 986 case 'TIMESTAMP': 987 988 case MYSQLI_TYPE_DATETIME : 989 case MYSQLI_TYPE_NEWDATE : 990 case MYSQLI_TYPE_TIME : 991 case MYSQLI_TYPE_TIMESTAMP : 992 993 return 'T'; 994 995 case 'INT': 996 case 'INTEGER': 997 case 'BIGINT': 998 case 'TINYINT': 999 case 'MEDIUMINT': 1000 case 'SMALLINT': 1001 1002 case MYSQLI_TYPE_INT24 : 1003 case MYSQLI_TYPE_LONG : 1004 case MYSQLI_TYPE_LONGLONG : 1005 case MYSQLI_TYPE_SHORT : 1006 case MYSQLI_TYPE_TINY : 1007 1008 if (!empty($fieldobj->primary_key)) return 'R'; 1009 1010 return 'I'; 1011 1012 1013 // Added floating-point types 1014 // Maybe not necessery. 1015 case 'FLOAT': 1016 case 'DOUBLE': 1017 // case 'DOUBLE PRECISION': 1018 case 'DECIMAL': 1019 case 'DEC': 1020 case 'FIXED': 1021 default: 1022 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>"; 1023 return 'N'; 1024 } 1025 } // function 1026 1027 1028} // rs class 1029 1030} 1031 1032class ADORecordSet_array_mysqli extends ADORecordSet_array { 1033 function ADORecordSet_array_mysqli($id=-1,$mode=false) 1034 { 1035 $this->ADORecordSet_array($id,$mode); 1036 } 1037 1038 1039 function MetaType($t, $len = -1, $fieldobj = false) 1040 { 1041 if (is_object($t)) { 1042 $fieldobj = $t; 1043 $t = $fieldobj->type; 1044 $len = $fieldobj->max_length; 1045 } 1046 1047 1048 $len = -1; // mysql max_length is not accurate 1049 switch (strtoupper($t)) { 1050 case 'STRING': 1051 case 'CHAR': 1052 case 'VARCHAR': 1053 case 'TINYBLOB': 1054 case 'TINYTEXT': 1055 case 'ENUM': 1056 case 'SET': 1057 1058 case MYSQLI_TYPE_TINY_BLOB : 1059 #case MYSQLI_TYPE_CHAR : 1060 case MYSQLI_TYPE_STRING : 1061 case MYSQLI_TYPE_ENUM : 1062 case MYSQLI_TYPE_SET : 1063 case 253 : 1064 if ($len <= $this->blobSize) return 'C'; 1065 1066 case 'TEXT': 1067 case 'LONGTEXT': 1068 case 'MEDIUMTEXT': 1069 return 'X'; 1070 1071 1072 // php_mysql extension always returns 'blob' even if 'text' 1073 // so we have to check whether binary... 1074 case 'IMAGE': 1075 case 'LONGBLOB': 1076 case 'BLOB': 1077 case 'MEDIUMBLOB': 1078 1079 case MYSQLI_TYPE_BLOB : 1080 case MYSQLI_TYPE_LONG_BLOB : 1081 case MYSQLI_TYPE_MEDIUM_BLOB : 1082 1083 return !empty($fieldobj->binary) ? 'B' : 'X'; 1084 case 'YEAR': 1085 case 'DATE': 1086 case MYSQLI_TYPE_DATE : 1087 case MYSQLI_TYPE_YEAR : 1088 1089 return 'D'; 1090 1091 case 'TIME': 1092 case 'DATETIME': 1093 case 'TIMESTAMP': 1094 1095 case MYSQLI_TYPE_DATETIME : 1096 case MYSQLI_TYPE_NEWDATE : 1097 case MYSQLI_TYPE_TIME : 1098 case MYSQLI_TYPE_TIMESTAMP : 1099 1100 return 'T'; 1101 1102 case 'INT': 1103 case 'INTEGER': 1104 case 'BIGINT': 1105 case 'TINYINT': 1106 case 'MEDIUMINT': 1107 case 'SMALLINT': 1108 1109 case MYSQLI_TYPE_INT24 : 1110 case MYSQLI_TYPE_LONG : 1111 case MYSQLI_TYPE_LONGLONG : 1112 case MYSQLI_TYPE_SHORT : 1113 case MYSQLI_TYPE_TINY : 1114 1115 if (!empty($fieldobj->primary_key)) return 'R'; 1116 1117 return 'I'; 1118 1119 1120 // Added floating-point types 1121 // Maybe not necessery. 1122 case 'FLOAT': 1123 case 'DOUBLE': 1124 // case 'DOUBLE PRECISION': 1125 case 'DECIMAL': 1126 case 'DEC': 1127 case 'FIXED': 1128 default: 1129 //if (!is_numeric($t)) echo "<p>--- Error in type matching $t -----</p>"; 1130 return 'N'; 1131 } 1132 } // function 1133 1134} 1135 1136?> 1137