[ Index ]

PHP Cross Reference of phpBB-3.1.12-deutsch

title

Body

[close]

/phpbb/db/driver/ -> driver.php (source)

   1  <?php
   2  /**
   3  *
   4  * This file is part of the phpBB Forum Software package.
   5  *
   6  * @copyright (c) phpBB Limited <https://www.phpbb.com>
   7  * @license GNU General Public License, version 2 (GPL-2.0)
   8  *
   9  * For full copyright and license information, please see
  10  * the docs/CREDITS.txt file.
  11  *
  12  */
  13  
  14  namespace phpbb\db\driver;
  15  
  16  /**
  17  * Database Abstraction Layer
  18  */
  19  abstract class driver implements driver_interface
  20  {
  21      var $db_connect_id;
  22      var $query_result;
  23      var $return_on_error = false;
  24      var $transaction = false;
  25      var $sql_time = 0;
  26      var $num_queries = array();
  27      var $open_queries = array();
  28  
  29      var $curtime = 0;
  30      var $query_hold = '';
  31      var $html_hold = '';
  32      var $sql_report = '';
  33  
  34      var $persistency = false;
  35      var $user = '';
  36      var $server = '';
  37      var $dbname = '';
  38  
  39      // Set to true if error triggered
  40      var $sql_error_triggered = false;
  41  
  42      // Holding the last sql query on sql error
  43      var $sql_error_sql = '';
  44      // Holding the error information - only populated if sql_error_triggered is set
  45      var $sql_error_returned = array();
  46  
  47      // Holding transaction count
  48      var $transactions = 0;
  49  
  50      // Supports multi inserts?
  51      var $multi_insert = false;
  52  
  53      /**
  54      * Current sql layer
  55      */
  56      var $sql_layer = '';
  57  
  58      /**
  59      * Wildcards for matching any (%) or exactly one (_) character within LIKE expressions
  60      */
  61      var $any_char;
  62      var $one_char;
  63  
  64      /**
  65      * Exact version of the DBAL, directly queried
  66      */
  67      var $sql_server_version = false;
  68  
  69      /**
  70      * Constructor
  71      */
  72  	function __construct()
  73      {
  74          $this->num_queries = array(
  75              'cached'    => 0,
  76              'normal'    => 0,
  77              'total'        => 0,
  78          );
  79  
  80          // Fill default sql layer based on the class being called.
  81          // This can be changed by the specified layer itself later if needed.
  82          $this->sql_layer = substr(get_class($this), strlen('phpbb\db\driver\\'));
  83  
  84          // Do not change this please! This variable is used to easy the use of it - and is hardcoded.
  85          $this->any_char = chr(0) . '%';
  86          $this->one_char = chr(0) . '_';
  87      }
  88  
  89      /**
  90      * {@inheritdoc}
  91      */
  92  	public function get_sql_layer()
  93      {
  94          return $this->sql_layer;
  95      }
  96  
  97      /**
  98      * {@inheritdoc}
  99      */
 100  	public function get_db_name()
 101      {
 102          return $this->dbname;
 103      }
 104  
 105      /**
 106      * {@inheritdoc}
 107      */
 108  	public function get_any_char()
 109      {
 110          return $this->any_char;
 111      }
 112  
 113      /**
 114      * {@inheritdoc}
 115      */
 116  	public function get_one_char()
 117      {
 118          return $this->one_char;
 119      }
 120  
 121      /**
 122      * {@inheritdoc}
 123      */
 124  	public function get_db_connect_id()
 125      {
 126          return $this->db_connect_id;
 127      }
 128  
 129      /**
 130      * {@inheritdoc}
 131      */
 132  	public function get_sql_error_triggered()
 133      {
 134          return $this->sql_error_triggered;
 135      }
 136  
 137      /**
 138      * {@inheritdoc}
 139      */
 140  	public function get_sql_error_sql()
 141      {
 142          return $this->sql_error_sql;
 143      }
 144  
 145      /**
 146      * {@inheritdoc}
 147      */
 148  	public function get_transaction()
 149      {
 150          return $this->transaction;
 151      }
 152  
 153      /**
 154      * {@inheritdoc}
 155      */
 156  	public function get_sql_time()
 157      {
 158          return $this->sql_time;
 159      }
 160  
 161      /**
 162      * {@inheritdoc}
 163      */
 164  	public function get_sql_error_returned()
 165      {
 166          return $this->sql_error_returned;
 167      }
 168  
 169      /**
 170      * {@inheritdoc}
 171      */
 172  	public function get_multi_insert()
 173      {
 174          return $this->multi_insert;
 175      }
 176  
 177      /**
 178      * {@inheritdoc}
 179      */
 180  	public function set_multi_insert($multi_insert)
 181      {
 182          $this->multi_insert = $multi_insert;
 183      }
 184  
 185      /**
 186      * {@inheritDoc}
 187      */
 188  	function sql_return_on_error($fail = false)
 189      {
 190          $this->sql_error_triggered = false;
 191          $this->sql_error_sql = '';
 192  
 193          $this->return_on_error = $fail;
 194      }
 195  
 196      /**
 197      * {@inheritDoc}
 198      */
 199  	function sql_num_queries($cached = false)
 200      {
 201          return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal'];
 202      }
 203  
 204      /**
 205      * {@inheritDoc}
 206      */
 207  	function sql_add_num_queries($cached = false)
 208      {
 209          $this->num_queries['cached'] += ($cached !== false) ? 1 : 0;
 210          $this->num_queries['normal'] += ($cached !== false) ? 0 : 1;
 211          $this->num_queries['total'] += 1;
 212      }
 213  
 214      /**
 215      * {@inheritDoc}
 216      */
 217  	function sql_close()
 218      {
 219          if (!$this->db_connect_id)
 220          {
 221              return false;
 222          }
 223  
 224          if ($this->transaction)
 225          {
 226              do
 227              {
 228                  $this->sql_transaction('commit');
 229              }
 230              while ($this->transaction);
 231          }
 232  
 233          foreach ($this->open_queries as $query_id)
 234          {
 235              $this->sql_freeresult($query_id);
 236          }
 237  
 238          // Connection closed correctly. Set db_connect_id to false to prevent errors
 239          if ($result = $this->_sql_close())
 240          {
 241              $this->db_connect_id = false;
 242          }
 243  
 244          return $result;
 245      }
 246  
 247      /**
 248      * {@inheritDoc}
 249      */
 250  	function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
 251      {
 252          if (empty($query))
 253          {
 254              return false;
 255          }
 256  
 257          // Never use a negative total or offset
 258          $total = ($total < 0) ? 0 : $total;
 259          $offset = ($offset < 0) ? 0 : $offset;
 260  
 261          return $this->_sql_query_limit($query, $total, $offset, $cache_ttl);
 262      }
 263  
 264      /**
 265      * {@inheritDoc}
 266      */
 267  	function sql_fetchrowset($query_id = false)
 268      {
 269          if ($query_id === false)
 270          {
 271              $query_id = $this->query_result;
 272          }
 273  
 274          if ($query_id !== false)
 275          {
 276              $result = array();
 277              while ($row = $this->sql_fetchrow($query_id))
 278              {
 279                  $result[] = $row;
 280              }
 281  
 282              return $result;
 283          }
 284  
 285          return false;
 286      }
 287  
 288      /**
 289      * {@inheritDoc}
 290      */
 291  	function sql_rowseek($rownum, &$query_id)
 292      {
 293          global $cache;
 294  
 295          if ($query_id === false)
 296          {
 297              $query_id = $this->query_result;
 298          }
 299  
 300          if ($cache && $cache->sql_exists($query_id))
 301          {
 302              return $cache->sql_rowseek($rownum, $query_id);
 303          }
 304  
 305          if ($query_id === false)
 306          {
 307              return false;
 308          }
 309  
 310          $this->sql_freeresult($query_id);
 311          $query_id = $this->sql_query($this->last_query_text);
 312  
 313          if ($query_id === false)
 314          {
 315              return false;
 316          }
 317  
 318          // We do not fetch the row for rownum == 0 because then the next resultset would be the second row
 319          for ($i = 0; $i < $rownum; $i++)
 320          {
 321              if (!$this->sql_fetchrow($query_id))
 322              {
 323                  return false;
 324              }
 325          }
 326  
 327          return true;
 328      }
 329  
 330      /**
 331      * {@inheritDoc}
 332      */
 333  	function sql_fetchfield($field, $rownum = false, $query_id = false)
 334      {
 335          global $cache;
 336  
 337          if ($query_id === false)
 338          {
 339              $query_id = $this->query_result;
 340          }
 341  
 342          if ($query_id !== false)
 343          {
 344              if ($rownum !== false)
 345              {
 346                  $this->sql_rowseek($rownum, $query_id);
 347              }
 348  
 349              if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
 350              {
 351                  return $cache->sql_fetchfield($query_id, $field);
 352              }
 353  
 354              $row = $this->sql_fetchrow($query_id);
 355              return (isset($row[$field])) ? $row[$field] : false;
 356          }
 357  
 358          return false;
 359      }
 360  
 361      /**
 362      * {@inheritDoc}
 363      */
 364  	function sql_like_expression($expression)
 365      {
 366          $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression);
 367          $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);
 368  
 369          return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\'');
 370      }
 371  
 372      /**
 373      * {@inheritDoc}
 374      */
 375  	function sql_not_like_expression($expression)
 376      {
 377          $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression);
 378          $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);
 379  
 380          return $this->_sql_not_like_expression('NOT LIKE \'' . $this->sql_escape($expression) . '\'');
 381      }
 382  
 383      /**
 384      * {@inheritDoc}
 385      */
 386  	public function sql_case($condition, $action_true, $action_false = false)
 387      {
 388          $sql_case = 'CASE WHEN ' . $condition;
 389          $sql_case .= ' THEN ' . $action_true;
 390          $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : '';
 391          $sql_case .= ' END';
 392          return $sql_case;
 393      }
 394  
 395      /**
 396      * {@inheritDoc}
 397      */
 398  	public function sql_concatenate($expr1, $expr2)
 399      {
 400          return $expr1 . ' || ' . $expr2;
 401      }
 402  
 403      /**
 404      * {@inheritDoc}
 405      */
 406  	function sql_buffer_nested_transactions()
 407      {
 408          return false;
 409      }
 410  
 411      /**
 412      * {@inheritDoc}
 413      */
 414  	function sql_transaction($status = 'begin')
 415      {
 416          switch ($status)
 417          {
 418              case 'begin':
 419                  // If we are within a transaction we will not open another one, but enclose the current one to not loose data (preventing auto commit)
 420                  if ($this->transaction)
 421                  {
 422                      $this->transactions++;
 423                      return true;
 424                  }
 425  
 426                  $result = $this->_sql_transaction('begin');
 427  
 428                  if (!$result)
 429                  {
 430                      $this->sql_error();
 431                  }
 432  
 433                  $this->transaction = true;
 434              break;
 435  
 436              case 'commit':
 437                  // If there was a previously opened transaction we do not commit yet...
 438                  // but count back the number of inner transactions
 439                  if ($this->transaction && $this->transactions)
 440                  {
 441                      $this->transactions--;
 442                      return true;
 443                  }
 444  
 445                  // Check if there is a transaction (no transaction can happen if
 446                  // there was an error, with a combined rollback and error returning enabled)
 447                  // This implies we have transaction always set for autocommit db's
 448                  if (!$this->transaction)
 449                  {
 450                      return false;
 451                  }
 452  
 453                  $result = $this->_sql_transaction('commit');
 454  
 455                  if (!$result)
 456                  {
 457                      $this->sql_error();
 458                  }
 459  
 460                  $this->transaction = false;
 461                  $this->transactions = 0;
 462              break;
 463  
 464              case 'rollback':
 465                  $result = $this->_sql_transaction('rollback');
 466                  $this->transaction = false;
 467                  $this->transactions = 0;
 468              break;
 469  
 470              default:
 471                  $result = $this->_sql_transaction($status);
 472              break;
 473          }
 474  
 475          return $result;
 476      }
 477  
 478      /**
 479      * {@inheritDoc}
 480      */
 481  	function sql_build_array($query, $assoc_ary = false)
 482      {
 483          if (!is_array($assoc_ary))
 484          {
 485              return false;
 486          }
 487  
 488          $fields = $values = array();
 489  
 490          if ($query == 'INSERT' || $query == 'INSERT_SELECT')
 491          {
 492              foreach ($assoc_ary as $key => $var)
 493              {
 494                  $fields[] = $key;
 495  
 496                  if (is_array($var) && is_string($var[0]))
 497                  {
 498                      // This is used for INSERT_SELECT(s)
 499                      $values[] = $var[0];
 500                  }
 501                  else
 502                  {
 503                      $values[] = $this->_sql_validate_value($var);
 504                  }
 505              }
 506  
 507              $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' ';
 508          }
 509          else if ($query == 'MULTI_INSERT')
 510          {
 511              trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR);
 512          }
 513          else if ($query == 'UPDATE' || $query == 'SELECT' || $query == 'DELETE')
 514          {
 515              $values = array();
 516              foreach ($assoc_ary as $key => $var)
 517              {
 518                  $values[] = "$key = " . $this->_sql_validate_value($var);
 519              }
 520              $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values);
 521          }
 522  
 523          return $query;
 524      }
 525  
 526      /**
 527      * {@inheritDoc}
 528      */
 529  	function sql_in_set($field, $array, $negate = false, $allow_empty_set = false)
 530      {
 531          if (!sizeof($array))
 532          {
 533              if (!$allow_empty_set)
 534              {
 535                  // Print the backtrace to help identifying the location of the problematic code
 536                  $this->sql_error('No values specified for SQL IN comparison');
 537              }
 538              else
 539              {
 540                  // NOT IN () actually means everything so use a tautology
 541                  if ($negate)
 542                  {
 543                      return '1=1';
 544                  }
 545                  // IN () actually means nothing so use a contradiction
 546                  else
 547                  {
 548                      return '1=0';
 549                  }
 550              }
 551          }
 552  
 553          if (!is_array($array))
 554          {
 555              $array = array($array);
 556          }
 557  
 558          if (sizeof($array) == 1)
 559          {
 560              @reset($array);
 561              $var = current($array);
 562  
 563              return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var);
 564          }
 565          else
 566          {
 567              return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')';
 568          }
 569      }
 570  
 571      /**
 572      * {@inheritDoc}
 573      */
 574  	function sql_bit_and($column_name, $bit, $compare = '')
 575      {
 576          if (method_exists($this, '_sql_bit_and'))
 577          {
 578              return $this->_sql_bit_and($column_name, $bit, $compare);
 579          }
 580  
 581          return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : '');
 582      }
 583  
 584      /**
 585      * {@inheritDoc}
 586      */
 587  	function sql_bit_or($column_name, $bit, $compare = '')
 588      {
 589          if (method_exists($this, '_sql_bit_or'))
 590          {
 591              return $this->_sql_bit_or($column_name, $bit, $compare);
 592          }
 593  
 594          return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : '');
 595      }
 596  
 597      /**
 598      * {@inheritDoc}
 599      */
 600  	function cast_expr_to_bigint($expression)
 601      {
 602          return $expression;
 603      }
 604  
 605      /**
 606      * {@inheritDoc}
 607      */
 608  	function cast_expr_to_string($expression)
 609      {
 610          return $expression;
 611      }
 612  
 613      /**
 614      * {@inheritDoc}
 615      */
 616  	function sql_lower_text($column_name)
 617      {
 618          return "LOWER($column_name)";
 619      }
 620  
 621      /**
 622      * {@inheritDoc}
 623      */
 624  	function sql_multi_insert($table, $sql_ary)
 625      {
 626          if (!sizeof($sql_ary))
 627          {
 628              return false;
 629          }
 630  
 631          if ($this->multi_insert)
 632          {
 633              $ary = array();
 634              foreach ($sql_ary as $id => $_sql_ary)
 635              {
 636                  // If by accident the sql array is only one-dimensional we build a normal insert statement
 637                  if (!is_array($_sql_ary))
 638                  {
 639                      return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary));
 640                  }
 641  
 642                  $values = array();
 643                  foreach ($_sql_ary as $key => $var)
 644                  {
 645                      $values[] = $this->_sql_validate_value($var);
 646                  }
 647                  $ary[] = '(' . implode(', ', $values) . ')';
 648              }
 649  
 650              return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary));
 651          }
 652          else
 653          {
 654              foreach ($sql_ary as $ary)
 655              {
 656                  if (!is_array($ary))
 657                  {
 658                      return false;
 659                  }
 660  
 661                  $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary));
 662  
 663                  if (!$result)
 664                  {
 665                      return false;
 666                  }
 667              }
 668          }
 669  
 670          return true;
 671      }
 672  
 673      /**
 674      * Function for validating values
 675      * @access private
 676      */
 677  	function _sql_validate_value($var)
 678      {
 679          if (is_null($var))
 680          {
 681              return 'NULL';
 682          }
 683          else if (is_string($var))
 684          {
 685              return "'" . $this->sql_escape($var) . "'";
 686          }
 687          else
 688          {
 689              return (is_bool($var)) ? intval($var) : $var;
 690          }
 691      }
 692  
 693      /**
 694      * {@inheritDoc}
 695      */
 696  	function sql_build_query($query, $array)
 697      {
 698          $sql = '';
 699          switch ($query)
 700          {
 701              case 'SELECT':
 702              case 'SELECT_DISTINCT';
 703  
 704                  $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM ';
 705  
 706                  // Build table array. We also build an alias array for later checks.
 707                  $table_array = $aliases = array();
 708                  $used_multi_alias = false;
 709  
 710                  foreach ($array['FROM'] as $table_name => $alias)
 711                  {
 712                      if (is_array($alias))
 713                      {
 714                          $used_multi_alias = true;
 715  
 716                          foreach ($alias as $multi_alias)
 717                          {
 718                              $table_array[] = $table_name . ' ' . $multi_alias;
 719                              $aliases[] = $multi_alias;
 720                          }
 721                      }
 722                      else
 723                      {
 724                          $table_array[] = $table_name . ' ' . $alias;
 725                          $aliases[] = $alias;
 726                      }
 727                  }
 728  
 729                  // We run the following code to determine if we need to re-order the table array. ;)
 730                  // The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison.
 731                  // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is.
 732                  if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false)
 733                  {
 734                      // Take first LEFT JOIN
 735                      $join = current($array['LEFT_JOIN']);
 736  
 737                      // Determine the table used there (even if there are more than one used, we only want to have one
 738                      preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches);
 739  
 740                      // If there is a first join match, we need to make sure the table order is correct
 741                      if (!empty($matches[1]))
 742                      {
 743                          $first_join_match = trim($matches[1]);
 744                          $table_array = $last = array();
 745  
 746                          foreach ($array['FROM'] as $table_name => $alias)
 747                          {
 748                              if (is_array($alias))
 749                              {
 750                                  foreach ($alias as $multi_alias)
 751                                  {
 752                                      ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias;
 753                                  }
 754                              }
 755                              else
 756                              {
 757                                  ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias;
 758                              }
 759                          }
 760  
 761                          $table_array = array_merge($table_array, $last);
 762                      }
 763                  }
 764  
 765                  $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array));
 766  
 767                  if (!empty($array['LEFT_JOIN']))
 768                  {
 769                      foreach ($array['LEFT_JOIN'] as $join)
 770                      {
 771                          $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')';
 772                      }
 773                  }
 774  
 775                  if (!empty($array['WHERE']))
 776                  {
 777                      $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']);
 778                  }
 779  
 780                  if (!empty($array['GROUP_BY']))
 781                  {
 782                      $sql .= ' GROUP BY ' . $array['GROUP_BY'];
 783                  }
 784  
 785                  if (!empty($array['ORDER_BY']))
 786                  {
 787                      $sql .= ' ORDER BY ' . $array['ORDER_BY'];
 788                  }
 789  
 790              break;
 791          }
 792  
 793          return $sql;
 794      }
 795  
 796      /**
 797      * {@inheritDoc}
 798      */
 799  	function sql_error($sql = '')
 800      {
 801          global $auth, $user, $config;
 802  
 803          // Set var to retrieve errored status
 804          $this->sql_error_triggered = true;
 805          $this->sql_error_sql = $sql;
 806  
 807          $this->sql_error_returned = $this->_sql_error();
 808  
 809          if (!$this->return_on_error)
 810          {
 811              $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]<br /><br />' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']';
 812  
 813              // Show complete SQL error and path to administrators only
 814              // Additionally show complete error on installation or if extended debug mode is enabled
 815              // The DEBUG constant is for development only!
 816              if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG'))
 817              {
 818                  $message .= ($sql) ? '<br /><br />SQL<br /><br />' . htmlspecialchars($sql) : '';
 819              }
 820              else
 821              {
 822                  // If error occurs in initiating the session we need to use a pre-defined language string
 823                  // This could happen if the connection could not be established for example (then we are not able to grab the default language)
 824                  if (!isset($user->lang['SQL_ERROR_OCCURRED']))
 825                  {
 826                      $message .= '<br /><br />An sql error occurred while fetching this page. Please contact an administrator if this problem persists.';
 827                  }
 828                  else
 829                  {
 830                      if (!empty($config['board_contact']))
 831                      {
 832                          $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>');
 833                      }
 834                      else
 835                      {
 836                          $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', '');
 837                      }
 838                  }
 839              }
 840  
 841              if ($this->transaction)
 842              {
 843                  $this->sql_transaction('rollback');
 844              }
 845  
 846              if (strlen($message) > 1024)
 847              {
 848                  // We need to define $msg_long_text here to circumvent text stripping.
 849                  global $msg_long_text;
 850                  $msg_long_text = $message;
 851  
 852                  trigger_error(false, E_USER_ERROR);
 853              }
 854  
 855              trigger_error($message, E_USER_ERROR);
 856          }
 857  
 858          if ($this->transaction)
 859          {
 860              $this->sql_transaction('rollback');
 861          }
 862  
 863          return $this->sql_error_returned;
 864      }
 865  
 866      /**
 867      * {@inheritDoc}
 868      */
 869  	function sql_report($mode, $query = '')
 870      {
 871          global $cache, $starttime, $phpbb_root_path, $phpbb_path_helper, $user;
 872          global $request;
 873  
 874          if (is_object($request) && !$request->variable('explain', false))
 875          {
 876              return false;
 877          }
 878  
 879          if (!$query && $this->query_hold != '')
 880          {
 881              $query = $this->query_hold;
 882          }
 883  
 884          switch ($mode)
 885          {
 886              case 'display':
 887                  if (!empty($cache))
 888                  {
 889                      $cache->unload();
 890                  }
 891                  $this->sql_close();
 892  
 893                  $mtime = explode(' ', microtime());
 894                  $totaltime = $mtime[0] + $mtime[1] - $starttime;
 895  
 896                  echo '<!DOCTYPE html>
 897                      <html dir="ltr">
 898                      <head>
 899                          <meta charset="utf-8">
 900                          <meta http-equiv="X-UA-Compatible" content="IE=edge">
 901                          <title>SQL Report</title>
 902                          <link href="' . htmlspecialchars($phpbb_path_helper->update_web_root_path($phpbb_root_path) . $phpbb_path_helper->get_adm_relative_path()) . 'style/admin.css" rel="stylesheet" type="text/css" media="screen" />
 903                      </head>
 904                      <body id="errorpage">
 905                      <div id="wrap">
 906                          <div id="page-header">
 907                              <a href="' . build_url('explain') . '">Return to previous page</a>
 908                          </div>
 909                          <div id="page-body">
 910                              <div id="acp">
 911                              <div class="panel">
 912                                  <span class="corners-top"><span></span></span>
 913                                  <div id="content">
 914                                      <h1>SQL Report</h1>
 915                                      <br />
 916                                      <p><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></p>
 917  
 918                                      <p>Time spent on ' . $this->sql_layer . ' queries: <b>' . round($this->sql_time, 5) . 's</b> | Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></p>
 919  
 920                                      <br /><br />
 921                                      ' . $this->sql_report . '
 922                                  </div>
 923                                  <span class="corners-bottom"><span></span></span>
 924                              </div>
 925                              </div>
 926                          </div>
 927                          <div id="page-footer">
 928                              Powered by <a href="https://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Limited
 929                          </div>
 930                      </div>
 931                      </body>
 932                      </html>';
 933  
 934                  exit_handler();
 935  
 936              break;
 937  
 938              case 'stop':
 939                  $endtime = explode(' ', microtime());
 940                  $endtime = $endtime[0] + $endtime[1];
 941  
 942                  $this->sql_report .= '
 943  
 944                      <table cellspacing="1">
 945                      <thead>
 946                      <tr>
 947                          <th>Query #' . $this->num_queries['total'] . '</th>
 948                      </tr>
 949                      </thead>
 950                      <tbody>
 951                      <tr>
 952                          <td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td>
 953                      </tr>
 954                      </tbody>
 955                      </table>
 956  
 957                      ' . $this->html_hold . '
 958  
 959                      <p style="text-align: center;">
 960                  ';
 961  
 962                  if ($this->query_result)
 963                  {
 964                      if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query))
 965                      {
 966                          $this->sql_report .= 'Affected rows: <b>' . $this->sql_affectedrows() . '</b> | ';
 967                      }
 968                      $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed: <b>' . sprintf('%.5f', $endtime - $this->curtime) . 's</b>';
 969                  }
 970                  else
 971                  {
 972                      $error = $this->sql_error();
 973                      $this->sql_report .= '<b style="color: red">FAILED</b> - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']);
 974                  }
 975  
 976                  $this->sql_report .= '</p><br /><br />';
 977  
 978                  $this->sql_time += $endtime - $this->curtime;
 979              break;
 980  
 981              case 'start':
 982                  $this->query_hold = $query;
 983                  $this->html_hold = '';
 984  
 985                  $this->_sql_report($mode, $query);
 986  
 987                  $this->curtime = explode(' ', microtime());
 988                  $this->curtime = $this->curtime[0] + $this->curtime[1];
 989  
 990              break;
 991  
 992              case 'add_select_row':
 993  
 994                  $html_table = func_get_arg(2);
 995                  $row = func_get_arg(3);
 996  
 997                  if (!$html_table && sizeof($row))
 998                  {
 999                      $html_table = true;
1000                      $this->html_hold .= '<table cellspacing="1"><tr>';
1001  
1002                      foreach (array_keys($row) as $val)
1003                      {
1004                          $this->html_hold .= '<th>' . (($val) ? ucwords(str_replace('_', ' ', $val)) : '&nbsp;') . '</th>';
1005                      }
1006                      $this->html_hold .= '</tr>';
1007                  }
1008                  $this->html_hold .= '<tr>';
1009  
1010                  $class = 'row1';
1011                  foreach (array_values($row) as $val)
1012                  {
1013                      $class = ($class == 'row1') ? 'row2' : 'row1';
1014                      $this->html_hold .= '<td class="' . $class . '">' . (($val) ? $val : '&nbsp;') . '</td>';
1015                  }
1016                  $this->html_hold .= '</tr>';
1017  
1018                  return $html_table;
1019  
1020              break;
1021  
1022              case 'fromcache':
1023  
1024                  $this->_sql_report($mode, $query);
1025  
1026              break;
1027  
1028              case 'record_fromcache':
1029  
1030                  $endtime = func_get_arg(2);
1031                  $splittime = func_get_arg(3);
1032  
1033                  $time_cache = $endtime - $this->curtime;
1034                  $time_db = $splittime - $endtime;
1035                  $color = ($time_db > $time_cache) ? 'green' : 'red';
1036  
1037                  $this->sql_report .= '<table cellspacing="1"><thead><tr><th>Query results obtained from the cache</th></tr></thead><tbody><tr>';
1038                  $this->sql_report .= '<td class="row3"><textarea style="font-family:\'Courier New\',monospace;width:99%" rows="5" cols="10">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></tbody></table>';
1039                  $this->sql_report .= '<p style="text-align: center;">';
1040                  $this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $starttime) . 's | After: ' . sprintf('%.5f', $endtime - $starttime) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p><br /><br />';
1041  
1042                  // Pad the start time to not interfere with page timing
1043                  $starttime += $time_db;
1044  
1045              break;
1046  
1047              default:
1048  
1049                  $this->_sql_report($mode, $query);
1050  
1051              break;
1052          }
1053  
1054          return true;
1055      }
1056  
1057      /**
1058      * {@inheritDoc}
1059      */
1060  	function get_estimated_row_count($table_name)
1061      {
1062          return $this->get_row_count($table_name);
1063      }
1064  
1065      /**
1066      * {@inheritDoc}
1067      */
1068  	function get_row_count($table_name)
1069      {
1070          $sql = 'SELECT COUNT(*) AS rows_total
1071              FROM ' . $this->sql_escape($table_name);
1072          $result = $this->sql_query($sql);
1073          $rows_total = $this->sql_fetchfield('rows_total');
1074          $this->sql_freeresult($result);
1075  
1076          return $rows_total;
1077      }
1078  }


Generated: Thu Jan 11 00:25:41 2018 Cross-referenced by PHPXref 0.7.1