[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * @package dbal 5 * @version $Id$ 6 * @copyright (c) 2005 phpBB Group 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 8 * 9 */ 10 11 /** 12 * @ignore 13 */ 14 if (!defined('IN_PHPBB')) 15 { 16 exit; 17 } 18 19 include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); 20 21 /** 22 * MySQLi Database Abstraction Layer 23 * mysqli-extension has to be compiled with: 24 * MySQL 4.1+ or MySQL 5.0+ 25 * @package dbal 26 */ 27 class dbal_mysqli extends dbal 28 { 29 var $multi_insert = true; 30 var $connect_error = ''; 31 32 /** 33 * Connect to server 34 */ 35 function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false , $new_link = false) 36 { 37 if (!function_exists('mysqli_connect')) 38 { 39 $this->connect_error = 'mysqli_connect function does not exist, is mysqli extension installed?'; 40 return $this->sql_error(''); 41 } 42 43 // Mysqli extension supports persistent connection since PHP 5.3.0 44 $this->persistency = (version_compare(PHP_VERSION, '5.3.0', '>=')) ? $persistency : false; 45 $this->user = $sqluser; 46 47 // If persistent connection, set dbhost to localhost when empty and prepend it with 'p:' prefix 48 $this->server = ($this->persistency) ? 'p:' . (($sqlserver) ? $sqlserver : 'localhost') : $sqlserver; 49 50 $this->dbname = $database; 51 $port = (!$port) ? NULL : $port; 52 53 // If port is set and it is not numeric, most likely mysqli socket is set. 54 // Try to map it to the $socket parameter. 55 $socket = NULL; 56 if ($port) 57 { 58 if (is_numeric($port)) 59 { 60 $port = (int) $port; 61 } 62 else 63 { 64 $socket = $port; 65 $port = NULL; 66 } 67 } 68 69 $this->db_connect_id = @mysqli_connect($this->server, $this->user, $sqlpassword, $this->dbname, $port, $socket); 70 71 if ($this->db_connect_id && $this->dbname != '') 72 { 73 @mysqli_query($this->db_connect_id, "SET NAMES 'utf8'"); 74 75 // enforce strict mode on databases that support it 76 if (version_compare($this->sql_server_info(true), '5.0.2', '>=')) 77 { 78 $result = @mysqli_query($this->db_connect_id, 'SELECT @@session.sql_mode AS sql_mode'); 79 $row = @mysqli_fetch_assoc($result); 80 @mysqli_free_result($result); 81 82 $modes = array_map('trim', explode(',', $row['sql_mode'])); 83 84 // TRADITIONAL includes STRICT_ALL_TABLES and STRICT_TRANS_TABLES 85 if (!in_array('TRADITIONAL', $modes)) 86 { 87 if (!in_array('STRICT_ALL_TABLES', $modes)) 88 { 89 $modes[] = 'STRICT_ALL_TABLES'; 90 } 91 92 if (!in_array('STRICT_TRANS_TABLES', $modes)) 93 { 94 $modes[] = 'STRICT_TRANS_TABLES'; 95 } 96 } 97 98 $mode = implode(',', $modes); 99 @mysqli_query($this->db_connect_id, "SET SESSION sql_mode='{$mode}'"); 100 } 101 return $this->db_connect_id; 102 } 103 104 return $this->sql_error(''); 105 } 106 107 /** 108 * Version information about used database 109 * @param bool $use_cache If true, it is safe to retrieve the value from the cache 110 * @return string sql server version 111 */ 112 function sql_server_info($raw = false, $use_cache = true) 113 { 114 global $cache; 115 116 if (!$use_cache || empty($cache) || ($this->sql_server_version = $cache->get('mysqli_version')) === false) 117 { 118 $result = @mysqli_query($this->db_connect_id, 'SELECT VERSION() AS version'); 119 $row = @mysqli_fetch_assoc($result); 120 @mysqli_free_result($result); 121 122 $this->sql_server_version = $row['version']; 123 124 if (!empty($cache) && $use_cache) 125 { 126 $cache->put('mysqli_version', $this->sql_server_version); 127 } 128 } 129 130 return ($raw) ? $this->sql_server_version : 'MySQL(i) ' . $this->sql_server_version; 131 } 132 133 /** 134 * SQL Transaction 135 * @access private 136 */ 137 function _sql_transaction($status = 'begin') 138 { 139 switch ($status) 140 { 141 case 'begin': 142 return @mysqli_autocommit($this->db_connect_id, false); 143 break; 144 145 case 'commit': 146 $result = @mysqli_commit($this->db_connect_id); 147 @mysqli_autocommit($this->db_connect_id, true); 148 return $result; 149 break; 150 151 case 'rollback': 152 $result = @mysqli_rollback($this->db_connect_id); 153 @mysqli_autocommit($this->db_connect_id, true); 154 return $result; 155 break; 156 } 157 158 return true; 159 } 160 161 /** 162 * Base query method 163 * 164 * @param string $query Contains the SQL query which shall be executed 165 * @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache 166 * @return mixed When casted to bool the returned value returns true on success and false on failure 167 * 168 * @access public 169 */ 170 function sql_query($query = '', $cache_ttl = 0) 171 { 172 if ($query != '') 173 { 174 global $cache; 175 176 // EXPLAIN only in extra debug mode 177 if (defined('DEBUG_EXTRA')) 178 { 179 $this->sql_report('start', $query); 180 } 181 182 $this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; 183 $this->sql_add_num_queries($this->query_result); 184 185 if ($this->query_result === false) 186 { 187 if (($this->query_result = @mysqli_query($this->db_connect_id, $query)) === false) 188 { 189 $this->sql_error($query); 190 } 191 192 if (defined('DEBUG_EXTRA')) 193 { 194 $this->sql_report('stop', $query); 195 } 196 197 if ($cache_ttl && method_exists($cache, 'sql_save')) 198 { 199 $cache->sql_save($query, $this->query_result, $cache_ttl); 200 } 201 } 202 else if (defined('DEBUG_EXTRA')) 203 { 204 $this->sql_report('fromcache', $query); 205 } 206 } 207 else 208 { 209 return false; 210 } 211 212 return $this->query_result; 213 } 214 215 /** 216 * Build LIMIT query 217 */ 218 function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) 219 { 220 $this->query_result = false; 221 222 // if $total is set to 0 we do not want to limit the number of rows 223 if ($total == 0) 224 { 225 // MySQL 4.1+ no longer supports -1 in limit queries 226 $total = '18446744073709551615'; 227 } 228 229 $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total); 230 231 return $this->sql_query($query, $cache_ttl); 232 } 233 234 /** 235 * Return number of affected rows 236 */ 237 function sql_affectedrows() 238 { 239 return ($this->db_connect_id) ? @mysqli_affected_rows($this->db_connect_id) : false; 240 } 241 242 /** 243 * Fetch current row 244 */ 245 function sql_fetchrow($query_id = false) 246 { 247 global $cache; 248 249 if ($query_id === false) 250 { 251 $query_id = $this->query_result; 252 } 253 254 if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) 255 { 256 return $cache->sql_fetchrow($query_id); 257 } 258 259 if ($query_id !== false) 260 { 261 $result = @mysqli_fetch_assoc($query_id); 262 return $result !== null ? $result : false; 263 } 264 265 return false; 266 } 267 268 /** 269 * Seek to given row number 270 * rownum is zero-based 271 */ 272 function sql_rowseek($rownum, &$query_id) 273 { 274 global $cache; 275 276 if ($query_id === false) 277 { 278 $query_id = $this->query_result; 279 } 280 281 if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) 282 { 283 return $cache->sql_rowseek($rownum, $query_id); 284 } 285 286 return ($query_id !== false) ? @mysqli_data_seek($query_id, $rownum) : false; 287 } 288 289 /** 290 * Get last inserted id after insert statement 291 */ 292 function sql_nextid() 293 { 294 return ($this->db_connect_id) ? @mysqli_insert_id($this->db_connect_id) : false; 295 } 296 297 /** 298 * Free sql result 299 */ 300 function sql_freeresult($query_id = false) 301 { 302 global $cache; 303 304 if ($query_id === false) 305 { 306 $query_id = $this->query_result; 307 } 308 309 if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])) 310 { 311 return $cache->sql_freeresult($query_id); 312 } 313 314 return @mysqli_free_result($query_id); 315 } 316 317 /** 318 * Escape string used in sql query 319 */ 320 function sql_escape($msg) 321 { 322 return @mysqli_real_escape_string($this->db_connect_id, $msg); 323 } 324 325 /** 326 * Gets the estimated number of rows in a specified table. 327 * 328 * @param string $table_name Table name 329 * 330 * @return string Number of rows in $table_name. 331 * Prefixed with ~ if estimated (otherwise exact). 332 * 333 * @access public 334 */ 335 function get_estimated_row_count($table_name) 336 { 337 $table_status = $this->get_table_status($table_name); 338 339 if (isset($table_status['Engine'])) 340 { 341 if ($table_status['Engine'] === 'MyISAM') 342 { 343 return $table_status['Rows']; 344 } 345 else if ($table_status['Engine'] === 'InnoDB' && $table_status['Rows'] > 100000) 346 { 347 return '~' . $table_status['Rows']; 348 } 349 } 350 351 return parent::get_row_count($table_name); 352 } 353 354 /** 355 * Gets the exact number of rows in a specified table. 356 * 357 * @param string $table_name Table name 358 * 359 * @return string Exact number of rows in $table_name. 360 * 361 * @access public 362 */ 363 function get_row_count($table_name) 364 { 365 $table_status = $this->get_table_status($table_name); 366 367 if (isset($table_status['Engine']) && $table_status['Engine'] === 'MyISAM') 368 { 369 return $table_status['Rows']; 370 } 371 372 return parent::get_row_count($table_name); 373 } 374 375 /** 376 * Gets some information about the specified table. 377 * 378 * @param string $table_name Table name 379 * 380 * @return array 381 * 382 * @access protected 383 */ 384 function get_table_status($table_name) 385 { 386 $sql = "SHOW TABLE STATUS 387 LIKE '" . $this->sql_escape($table_name) . "'"; 388 $result = $this->sql_query($sql); 389 $table_status = $this->sql_fetchrow($result); 390 $this->sql_freeresult($result); 391 392 return $table_status; 393 } 394 395 /** 396 * Build LIKE expression 397 * @access private 398 */ 399 function _sql_like_expression($expression) 400 { 401 return $expression; 402 } 403 404 /** 405 * Build db-specific query data 406 * @access private 407 */ 408 function _sql_custom_build($stage, $data) 409 { 410 switch ($stage) 411 { 412 case 'FROM': 413 $data = '(' . $data . ')'; 414 break; 415 } 416 417 return $data; 418 } 419 420 /** 421 * return sql error array 422 * @access private 423 */ 424 function _sql_error() 425 { 426 if ($this->db_connect_id) 427 { 428 $error = array( 429 'message' => @mysqli_error($this->db_connect_id), 430 'code' => @mysqli_errno($this->db_connect_id) 431 ); 432 } 433 else if (function_exists('mysqli_connect_error')) 434 { 435 $error = array( 436 'message' => @mysqli_connect_error(), 437 'code' => @mysqli_connect_errno(), 438 ); 439 } 440 else 441 { 442 $error = array( 443 'message' => $this->connect_error, 444 'code' => '', 445 ); 446 } 447 448 return $error; 449 } 450 451 /** 452 * Close sql connection 453 * @access private 454 */ 455 function _sql_close() 456 { 457 return @mysqli_close($this->db_connect_id); 458 } 459 460 /** 461 * Build db-specific report 462 * @access private 463 */ 464 function _sql_report($mode, $query = '') 465 { 466 static $test_prof; 467 468 // current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING 469 if ($test_prof === null) 470 { 471 $test_prof = false; 472 if (strpos(mysqli_get_server_info($this->db_connect_id), 'community') !== false) 473 { 474 $ver = mysqli_get_server_version($this->db_connect_id); 475 if ($ver >= 50037 && $ver < 50100) 476 { 477 $test_prof = true; 478 } 479 } 480 } 481 482 switch ($mode) 483 { 484 case 'start': 485 486 $explain_query = $query; 487 if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) 488 { 489 $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; 490 } 491 else if (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)) 492 { 493 $explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2]; 494 } 495 496 if (preg_match('/^SELECT/', $explain_query)) 497 { 498 $html_table = false; 499 500 // begin profiling 501 if ($test_prof) 502 { 503 @mysqli_query($this->db_connect_id, 'SET profiling = 1;'); 504 } 505 506 if ($result = @mysqli_query($this->db_connect_id, "EXPLAIN $explain_query")) 507 { 508 while ($row = @mysqli_fetch_assoc($result)) 509 { 510 $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); 511 } 512 } 513 @mysqli_free_result($result); 514 515 if ($html_table) 516 { 517 $this->html_hold .= '</table>'; 518 } 519 520 if ($test_prof) 521 { 522 $html_table = false; 523 524 // get the last profile 525 if ($result = @mysqli_query($this->db_connect_id, 'SHOW PROFILE ALL;')) 526 { 527 $this->html_hold .= '<br />'; 528 while ($row = @mysqli_fetch_assoc($result)) 529 { 530 // make <unknown> HTML safe 531 if (!empty($row['Source_function'])) 532 { 533 $row['Source_function'] = str_replace(array('<', '>'), array('<', '>'), $row['Source_function']); 534 } 535 536 // remove unsupported features 537 foreach ($row as $key => $val) 538 { 539 if ($val === null) 540 { 541 unset($row[$key]); 542 } 543 } 544 $html_table = $this->sql_report('add_select_row', $query, $html_table, $row); 545 } 546 } 547 @mysqli_free_result($result); 548 549 if ($html_table) 550 { 551 $this->html_hold .= '</table>'; 552 } 553 554 @mysqli_query($this->db_connect_id, 'SET profiling = 0;'); 555 } 556 } 557 558 break; 559 560 case 'fromcache': 561 $endtime = explode(' ', microtime()); 562 $endtime = $endtime[0] + $endtime[1]; 563 564 $result = @mysqli_query($this->db_connect_id, $query); 565 while ($void = @mysqli_fetch_assoc($result)) 566 { 567 // Take the time spent on parsing rows into account 568 } 569 @mysqli_free_result($result); 570 571 $splittime = explode(' ', microtime()); 572 $splittime = $splittime[0] + $splittime[1]; 573 574 $this->sql_report('record_fromcache', $query, $endtime, $splittime); 575 576 break; 577 } 578 } 579 } 580 581 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Oct 2 15:03:47 2013 | Cross-referenced by PHPXref 0.7.1 |