Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

driver.php

Zuletzt modifiziert: 09.10.2024, 12:54 - Dateigröße: 23.91 KiB


 0001  <?php
 0002  /**
 0003  *
 0004  * This file is part of the phpBB Forum Software package.
 0005  *
 0006  * @copyright (c) phpBB Limited <https://www.phpbb.com>
 0007  * @license GNU General Public License, version 2 (GPL-2.0)
 0008  *
 0009  * For full copyright and license information, please see
 0010  * the docs/CREDITS.txt file.
 0011  *
 0012  */
 0013   
 0014  namespace phpbb\db\driver;
 0015   
 0016  /**
 0017  * Database Abstraction Layer
 0018  */
 0019  abstract class driver implements driver_interface
 0020  {
 0021      var $db_connect_id;
 0022      var $query_result;
 0023      var $return_on_error = false;
 0024      var $transaction = false;
 0025      var $sql_time = 0;
 0026      var $num_queries = array();
 0027      var $open_queries = array();
 0028   
 0029      var $curtime = 0;
 0030      var $query_hold = '';
 0031      var $html_hold = '';
 0032      var $sql_report = '';
 0033   
 0034      var $persistency = false;
 0035      var $user = '';
 0036      var $server = '';
 0037      var $dbname = '';
 0038   
 0039      // Set to true if error triggered
 0040      var $sql_error_triggered = false;
 0041   
 0042      // Holding the last sql query on sql error
 0043      var $sql_error_sql = '';
 0044      // Holding the error information - only populated if sql_error_triggered is set
 0045      var $sql_error_returned = array();
 0046   
 0047      // Holding transaction count
 0048      var $transactions = 0;
 0049   
 0050      // Supports multi inserts?
 0051      var $multi_insert = false;
 0052   
 0053      /**
 0054      * Current sql layer
 0055      */
 0056      var $sql_layer = '';
 0057   
 0058      /**
 0059      * Wildcards for matching any (%) or exactly one (_) character within LIKE expressions
 0060      */
 0061      var $any_char;
 0062      var $one_char;
 0063   
 0064      /**
 0065      * Exact version of the DBAL, directly queried
 0066      */
 0067      var $sql_server_version = false;
 0068   
 0069      /**
 0070      * Constructor
 0071      */
 0072      function __construct()
 0073      {
 0074          $this->num_queries = array(
 0075              'cached'    => 0,
 0076              'normal'    => 0,
 0077              'total'        => 0,
 0078          );
 0079   
 0080          // Fill default sql layer based on the class being called.
 0081          // This can be changed by the specified layer itself later if needed.
 0082          $this->sql_layer = substr(get_class($this), strlen('phpbb\db\driver\\'));
 0083   
 0084          // Do not change this please! This variable is used to easy the use of it - and is hardcoded.
 0085          $this->any_char = chr(0) . '%';
 0086          $this->one_char = chr(0) . '_';
 0087      }
 0088   
 0089      /**
 0090      * {@inheritdoc}
 0091      */
 0092      public function get_sql_layer()
 0093      {
 0094          return $this->sql_layer;
 0095      }
 0096   
 0097      /**
 0098      * {@inheritdoc}
 0099      */
 0100      public function get_db_name()
 0101      {
 0102          return $this->dbname;
 0103      }
 0104   
 0105      /**
 0106      * {@inheritdoc}
 0107      */
 0108      public function get_any_char()
 0109      {
 0110          return $this->any_char;
 0111      }
 0112   
 0113      /**
 0114      * {@inheritdoc}
 0115      */
 0116      public function get_one_char()
 0117      {
 0118          return $this->one_char;
 0119      }
 0120   
 0121      /**
 0122      * {@inheritdoc}
 0123      */
 0124      public function get_db_connect_id()
 0125      {
 0126          return $this->db_connect_id;
 0127      }
 0128   
 0129      /**
 0130      * {@inheritdoc}
 0131      */
 0132      public function get_sql_error_triggered()
 0133      {
 0134          return $this->sql_error_triggered;
 0135      }
 0136   
 0137      /**
 0138      * {@inheritdoc}
 0139      */
 0140      public function get_sql_error_sql()
 0141      {
 0142          return $this->sql_error_sql;
 0143      }
 0144   
 0145      /**
 0146      * {@inheritdoc}
 0147      */
 0148      public function get_transaction()
 0149      {
 0150          return $this->transaction;
 0151      }
 0152   
 0153      /**
 0154      * {@inheritdoc}
 0155      */
 0156      public function get_sql_time()
 0157      {
 0158          return $this->sql_time;
 0159      }
 0160   
 0161      /**
 0162      * {@inheritdoc}
 0163      */
 0164      public function get_sql_error_returned()
 0165      {
 0166          return $this->sql_error_returned;
 0167      }
 0168   
 0169      /**
 0170      * {@inheritdoc}
 0171      */
 0172      public function get_multi_insert()
 0173      {
 0174          return $this->multi_insert;
 0175      }
 0176   
 0177      /**
 0178      * {@inheritdoc}
 0179      */
 0180      public function set_multi_insert($multi_insert)
 0181      {
 0182          $this->multi_insert = $multi_insert;
 0183      }
 0184   
 0185      /**
 0186      * {@inheritDoc}
 0187      */
 0188      function sql_return_on_error($fail = false)
 0189      {
 0190          $this->sql_error_triggered = false;
 0191          $this->sql_error_sql = '';
 0192   
 0193          $this->return_on_error = $fail;
 0194      }
 0195   
 0196      /**
 0197      * {@inheritDoc}
 0198      */
 0199      function sql_num_queries($cached = false)
 0200      {
 0201          return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal'];
 0202      }
 0203   
 0204      /**
 0205      * {@inheritDoc}
 0206      */
 0207      function sql_add_num_queries($cached = false)
 0208      {
 0209          $this->num_queries['cached'] += ($cached !== false) ? 1 : 0;
 0210          $this->num_queries['normal'] += ($cached !== false) ? 0 : 1;
 0211          $this->num_queries['total'] += 1;
 0212      }
 0213   
 0214      /**
 0215      * {@inheritDoc}
 0216      */
 0217      function sql_close()
 0218      {
 0219          if (!$this->db_connect_id)
 0220          {
 0221              return false;
 0222          }
 0223   
 0224          if ($this->transaction)
 0225          {
 0226              do
 0227              {
 0228                  $this->sql_transaction('commit');
 0229              }
 0230              while ($this->transaction);
 0231          }
 0232   
 0233          foreach ($this->open_queries as $query_id)
 0234          {
 0235              $this->sql_freeresult($query_id);
 0236          }
 0237   
 0238          // Connection closed correctly. Set db_connect_id to false to prevent errors
 0239          if ($result = $this->_sql_close())
 0240          {
 0241              $this->db_connect_id = false;
 0242          }
 0243   
 0244          return $result;
 0245      }
 0246   
 0247      /**
 0248      * {@inheritDoc}
 0249      */
 0250      function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
 0251      {
 0252          if (empty($query))
 0253          {
 0254              return false;
 0255          }
 0256   
 0257          // Never use a negative total or offset
 0258          $total = ($total < 0) ? 0 : $total;
 0259          $offset = ($offset < 0) ? 0 : $offset;
 0260   
 0261          return $this->_sql_query_limit($query, $total, $offset, $cache_ttl);
 0262      }
 0263   
 0264      /**
 0265      * {@inheritDoc}
 0266      */
 0267      function sql_fetchrowset($query_id = false)
 0268      {
 0269          if ($query_id === false)
 0270          {
 0271              $query_id = $this->query_result;
 0272          }
 0273   
 0274          if ($query_id !== false)
 0275          {
 0276              $result = array();
 0277              while ($row = $this->sql_fetchrow($query_id))
 0278              {
 0279                  $result[] = $row;
 0280              }
 0281   
 0282              return $result;
 0283          }
 0284   
 0285          return false;
 0286      }
 0287   
 0288      /**
 0289      * {@inheritDoc}
 0290      */
 0291      function sql_rowseek($rownum, &$query_id)
 0292      {
 0293          global $cache;
 0294   
 0295          if ($query_id === false)
 0296          {
 0297              $query_id = $this->query_result;
 0298          }
 0299   
 0300          if ($cache && $cache->sql_exists($query_id))
 0301          {
 0302              return $cache->sql_rowseek($rownum, $query_id);
 0303          }
 0304   
 0305          if ($query_id === false)
 0306          {
 0307              return false;
 0308          }
 0309   
 0310          $this->sql_freeresult($query_id);
 0311          $query_id = $this->sql_query($this->last_query_text);
 0312   
 0313          if ($query_id === false)
 0314          {
 0315              return false;
 0316          }
 0317   
 0318          // We do not fetch the row for rownum == 0 because then the next resultset would be the second row
 0319          for ($i = 0; $i < $rownum; $i++)
 0320          {
 0321              if (!$this->sql_fetchrow($query_id))
 0322              {
 0323                  return false;
 0324              }
 0325          }
 0326   
 0327          return true;
 0328      }
 0329   
 0330      /**
 0331      * {@inheritDoc}
 0332      */
 0333      function sql_fetchfield($field, $rownum = false, $query_id = false)
 0334      {
 0335          global $cache;
 0336   
 0337          if ($query_id === false)
 0338          {
 0339              $query_id = $this->query_result;
 0340          }
 0341   
 0342          if ($query_id !== false)
 0343          {
 0344              if ($rownum !== false)
 0345              {
 0346                  $this->sql_rowseek($rownum, $query_id);
 0347              }
 0348   
 0349              if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
 0350              {
 0351                  return $cache->sql_fetchfield($query_id, $field);
 0352              }
 0353   
 0354              $row = $this->sql_fetchrow($query_id);
 0355              return (isset($row[$field])) ? $row[$field] : false;
 0356          }
 0357   
 0358          return false;
 0359      }
 0360   
 0361      /**
 0362      * {@inheritDoc}
 0363      */
 0364      function sql_like_expression($expression)
 0365      {
 0366          $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression);
 0367          $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);
 0368   
 0369          return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\'');
 0370      }
 0371   
 0372      /**
 0373      * {@inheritDoc}
 0374      */
 0375      function sql_not_like_expression($expression)
 0376      {
 0377          $expression = utf8_str_replace(array('_', '%'), array("\_", "\%"), $expression);
 0378          $expression = utf8_str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);
 0379   
 0380          return $this->_sql_not_like_expression('NOT LIKE \'' . $this->sql_escape($expression) . '\'');
 0381      }
 0382   
 0383      /**
 0384      * {@inheritDoc}
 0385      */
 0386      public function sql_case($condition, $action_true, $action_false = false)
 0387      {
 0388          $sql_case = 'CASE WHEN ' . $condition;
 0389          $sql_case .= ' THEN ' . $action_true;
 0390          $sql_case .= ($action_false !== false) ? ' ELSE ' . $action_false : '';
 0391          $sql_case .= ' END';
 0392          return $sql_case;
 0393      }
 0394   
 0395      /**
 0396      * {@inheritDoc}
 0397      */
 0398      public function sql_concatenate($expr1, $expr2)
 0399      {
 0400          return $expr1 . ' || ' . $expr2;
 0401      }
 0402   
 0403      /**
 0404      * {@inheritDoc}
 0405      */
 0406      function sql_buffer_nested_transactions()
 0407      {
 0408          return false;
 0409      }
 0410   
 0411      /**
 0412      * {@inheritDoc}
 0413      */
 0414      function sql_transaction($status = 'begin')
 0415      {
 0416          switch ($status)
 0417          {
 0418              case 'begin':
 0419                  // If we are within a transaction we will not open another one, but enclose the current one to not loose data (preventing auto commit)
 0420                  if ($this->transaction)
 0421                  {
 0422                      $this->transactions++;
 0423                      return true;
 0424                  }
 0425   
 0426                  $result = $this->_sql_transaction('begin');
 0427   
 0428                  if (!$result)
 0429                  {
 0430                      $this->sql_error();
 0431                  }
 0432   
 0433                  $this->transaction = true;
 0434              break;
 0435   
 0436              case 'commit':
 0437                  // If there was a previously opened transaction we do not commit yet...
 0438                  // but count back the number of inner transactions
 0439                  if ($this->transaction && $this->transactions)
 0440                  {
 0441                      $this->transactions--;
 0442                      return true;
 0443                  }
 0444   
 0445                  // Check if there is a transaction (no transaction can happen if
 0446                  // there was an error, with a combined rollback and error returning enabled)
 0447                  // This implies we have transaction always set for autocommit db's
 0448                  if (!$this->transaction)
 0449                  {
 0450                      return false;
 0451                  }
 0452   
 0453                  $result = $this->_sql_transaction('commit');
 0454   
 0455                  if (!$result)
 0456                  {
 0457                      $this->sql_error();
 0458                  }
 0459   
 0460                  $this->transaction = false;
 0461                  $this->transactions = 0;
 0462              break;
 0463   
 0464              case 'rollback':
 0465                  $result = $this->_sql_transaction('rollback');
 0466                  $this->transaction = false;
 0467                  $this->transactions = 0;
 0468              break;
 0469   
 0470              default:
 0471                  $result = $this->_sql_transaction($status);
 0472              break;
 0473          }
 0474   
 0475          return $result;
 0476      }
 0477   
 0478      /**
 0479      * {@inheritDoc}
 0480      */
 0481      function sql_build_array($query, $assoc_ary = false)
 0482      {
 0483          if (!is_array($assoc_ary))
 0484          {
 0485              return false;
 0486          }
 0487   
 0488          $fields = $values = array();
 0489   
 0490          if ($query == 'INSERT' || $query == 'INSERT_SELECT')
 0491          {
 0492              foreach ($assoc_ary as $key => $var)
 0493              {
 0494                  $fields[] = $key;
 0495   
 0496                  if (is_array($var) && is_string($var[0]))
 0497                  {
 0498                      // This is used for INSERT_SELECT(s)
 0499                      $values[] = $var[0];
 0500                  }
 0501                  else
 0502                  {
 0503                      $values[] = $this->_sql_validate_value($var);
 0504                  }
 0505              }
 0506   
 0507              $query = ($query == 'INSERT') ? ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')' : ' (' . implode(', ', $fields) . ') SELECT ' . implode(', ', $values) . ' ';
 0508          }
 0509          else if ($query == 'MULTI_INSERT')
 0510          {
 0511              trigger_error('The MULTI_INSERT query value is no longer supported. Please use sql_multi_insert() instead.', E_USER_ERROR);
 0512          }
 0513          else if ($query == 'UPDATE' || $query == 'SELECT' || $query == 'DELETE')
 0514          {
 0515              $values = array();
 0516              foreach ($assoc_ary as $key => $var)
 0517              {
 0518                  $values[] = "$key = " . $this->_sql_validate_value($var);
 0519              }
 0520              $query = implode(($query == 'UPDATE') ? ', ' : ' AND ', $values);
 0521          }
 0522   
 0523          return $query;
 0524      }
 0525   
 0526      /**
 0527      * {@inheritDoc}
 0528      */
 0529      function sql_in_set($field, $array, $negate = false, $allow_empty_set = false)
 0530      {
 0531          if (!sizeof($array))
 0532          {
 0533              if (!$allow_empty_set)
 0534              {
 0535                  // Print the backtrace to help identifying the location of the problematic code
 0536                  $this->sql_error('No values specified for SQL IN comparison');
 0537              }
 0538              else
 0539              {
 0540                  // NOT IN () actually means everything so use a tautology
 0541                  if ($negate)
 0542                  {
 0543                      return '1=1';
 0544                  }
 0545                  // IN () actually means nothing so use a contradiction
 0546                  else
 0547                  {
 0548                      return '1=0';
 0549                  }
 0550              }
 0551          }
 0552   
 0553          if (!is_array($array))
 0554          {
 0555              $array = array($array);
 0556          }
 0557   
 0558          if (sizeof($array) == 1)
 0559          {
 0560              @reset($array);
 0561              $var = current($array);
 0562   
 0563              return $field . ($negate ? ' <> ' : ' = ') . $this->_sql_validate_value($var);
 0564          }
 0565          else
 0566          {
 0567              return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, '_sql_validate_value'), $array)) . ')';
 0568          }
 0569      }
 0570   
 0571      /**
 0572      * {@inheritDoc}
 0573      */
 0574      function sql_bit_and($column_name, $bit, $compare = '')
 0575      {
 0576          if (method_exists($this, '_sql_bit_and'))
 0577          {
 0578              return $this->_sql_bit_and($column_name, $bit, $compare);
 0579          }
 0580   
 0581          return $column_name . ' & ' . (1 << $bit) . (($compare) ? ' ' . $compare : '');
 0582      }
 0583   
 0584      /**
 0585      * {@inheritDoc}
 0586      */
 0587      function sql_bit_or($column_name, $bit, $compare = '')
 0588      {
 0589          if (method_exists($this, '_sql_bit_or'))
 0590          {
 0591              return $this->_sql_bit_or($column_name, $bit, $compare);
 0592          }
 0593   
 0594          return $column_name . ' | ' . (1 << $bit) . (($compare) ? ' ' . $compare : '');
 0595      }
 0596   
 0597      /**
 0598      * {@inheritDoc}
 0599      */
 0600      function cast_expr_to_bigint($expression)
 0601      {
 0602          return $expression;
 0603      }
 0604   
 0605      /**
 0606      * {@inheritDoc}
 0607      */
 0608      function cast_expr_to_string($expression)
 0609      {
 0610          return $expression;
 0611      }
 0612   
 0613      /**
 0614      * {@inheritDoc}
 0615      */
 0616      function sql_lower_text($column_name)
 0617      {
 0618          return "LOWER($column_name)";
 0619      }
 0620   
 0621      /**
 0622      * {@inheritDoc}
 0623      */
 0624      function sql_multi_insert($table, $sql_ary)
 0625      {
 0626          if (!sizeof($sql_ary))
 0627          {
 0628              return false;
 0629          }
 0630   
 0631          if ($this->multi_insert)
 0632          {
 0633              $ary = array();
 0634              foreach ($sql_ary as $id => $_sql_ary)
 0635              {
 0636                  // If by accident the sql array is only one-dimensional we build a normal insert statement
 0637                  if (!is_array($_sql_ary))
 0638                  {
 0639                      return $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary));
 0640                  }
 0641   
 0642                  $values = array();
 0643                  foreach ($_sql_ary as $key => $var)
 0644                  {
 0645                      $values[] = $this->_sql_validate_value($var);
 0646                  }
 0647                  $ary[] = '(' . implode(', ', $values) . ')';
 0648              }
 0649   
 0650              return $this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary));
 0651          }
 0652          else
 0653          {
 0654              foreach ($sql_ary as $ary)
 0655              {
 0656                  if (!is_array($ary))
 0657                  {
 0658                      return false;
 0659                  }
 0660   
 0661                  $result = $this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary));
 0662   
 0663                  if (!$result)
 0664                  {
 0665                      return false;
 0666                  }
 0667              }
 0668          }
 0669   
 0670          return true;
 0671      }
 0672   
 0673      /**
 0674      * Function for validating values
 0675      * @access private
 0676      */
 0677      function _sql_validate_value($var)
 0678      {
 0679          if (is_null($var))
 0680          {
 0681              return 'NULL';
 0682          }
 0683          else if (is_string($var))
 0684          {
 0685              return "'" . $this->sql_escape($var) . "'";
 0686          }
 0687          else
 0688          {
 0689              return (is_bool($var)) ? intval($var) : $var;
 0690          }
 0691      }
 0692   
 0693      /**
 0694      * {@inheritDoc}
 0695      */
 0696      function sql_build_query($query, $array)
 0697      {
 0698          $sql = '';
 0699          switch ($query)
 0700          {
 0701              case 'SELECT':
 0702              case 'SELECT_DISTINCT';
 0703   
 0704                  $sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM ';
 0705   
 0706                  // Build table array. We also build an alias array for later checks.
 0707                  $table_array = $aliases = array();
 0708                  $used_multi_alias = false;
 0709   
 0710                  foreach ($array['FROM'] as $table_name => $alias)
 0711                  {
 0712                      if (is_array($alias))
 0713                      {
 0714                          $used_multi_alias = true;
 0715   
 0716                          foreach ($alias as $multi_alias)
 0717                          {
 0718                              $table_array[] = $table_name . ' ' . $multi_alias;
 0719                              $aliases[] = $multi_alias;
 0720                          }
 0721                      }
 0722                      else
 0723                      {
 0724                          $table_array[] = $table_name . ' ' . $alias;
 0725                          $aliases[] = $alias;
 0726                      }
 0727                  }
 0728   
 0729                  // We run the following code to determine if we need to re-order the table array. ;)
 0730                  // 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.
 0731                  // DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is.
 0732                  if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false)
 0733                  {
 0734                      // Take first LEFT JOIN
 0735                      $join = current($array['LEFT_JOIN']);
 0736   
 0737                      // Determine the table used there (even if there are more than one used, we only want to have one
 0738                      preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches);
 0739   
 0740                      // If there is a first join match, we need to make sure the table order is correct
 0741                      if (!empty($matches[1]))
 0742                      {
 0743                          $first_join_match = trim($matches[1]);
 0744                          $table_array = $last = array();
 0745   
 0746                          foreach ($array['FROM'] as $table_name => $alias)
 0747                          {
 0748                              if (is_array($alias))
 0749                              {
 0750                                  foreach ($alias as $multi_alias)
 0751                                  {
 0752                                      ($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias;
 0753                                  }
 0754                              }
 0755                              else
 0756                              {
 0757                                  ($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias;
 0758                              }
 0759                          }
 0760   
 0761                          $table_array = array_merge($table_array, $last);
 0762                      }
 0763                  }
 0764   
 0765                  $sql .= $this->_sql_custom_build('FROM', implode(' CROSS JOIN ', $table_array));
 0766   
 0767                  if (!empty($array['LEFT_JOIN']))
 0768                  {
 0769                      foreach ($array['LEFT_JOIN'] as $join)
 0770                      {
 0771                          $sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')';
 0772                      }
 0773                  }
 0774   
 0775                  if (!empty($array['WHERE']))
 0776                  {
 0777                      $sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']);
 0778                  }
 0779   
 0780                  if (!empty($array['GROUP_BY']))
 0781                  {
 0782                      $sql .= ' GROUP BY ' . $array['GROUP_BY'];
 0783                  }
 0784   
 0785                  if (!empty($array['ORDER_BY']))
 0786                  {
 0787                      $sql .= ' ORDER BY ' . $array['ORDER_BY'];
 0788                  }
 0789   
 0790              break;
 0791          }
 0792   
 0793          return $sql;
 0794      }
 0795   
 0796      /**
 0797      * {@inheritDoc}
 0798      */
 0799      function sql_error($sql = '')
 0800      {
 0801          global $auth, $user, $config;
 0802   
 0803          // Set var to retrieve errored status
 0804          $this->sql_error_triggered = true;
 0805          $this->sql_error_sql = $sql;
 0806   
 0807          $this->sql_error_returned = $this->_sql_error();
 0808   
 0809          if (!$this->return_on_error)
 0810          {
 0811              $message = 'SQL ERROR [ ' . $this->sql_layer . ' ]<br /><br />' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']';
 0812   
 0813              // Show complete SQL error and path to administrators only
 0814              // Additionally show complete error on installation or if extended debug mode is enabled
 0815              // The DEBUG constant is for development only!
 0816              if ((isset($auth) && $auth->acl_get('a_')) || defined('IN_INSTALL') || defined('DEBUG'))
 0817              {
 0818                  $message .= ($sql) ? '<br /><br />SQL<br /><br />' . htmlspecialchars($sql) : '';
 0819              }
 0820              else
 0821              {
 0822                  // If error occurs in initiating the session we need to use a pre-defined language string
 0823                  // This could happen if the connection could not be established for example (then we are not able to grab the default language)
 0824                  if (!isset($user->lang['SQL_ERROR_OCCURRED']))
 0825                  {
 0826                      $message .= '<br /><br />An sql error occurred while fetching this page. Please contact an administrator if this problem persists.';
 0827                  }
 0828                  else
 0829                  {
 0830                      if (!empty($config['board_contact']))
 0831                      {
 0832                          $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>');
 0833                      }
 0834                      else
 0835                      {
 0836                          $message .= '<br /><br />' . sprintf($user->lang['SQL_ERROR_OCCURRED'], '', '');
 0837                      }
 0838                  }
 0839              }
 0840   
 0841              if ($this->transaction)
 0842              {
 0843                  $this->sql_transaction('rollback');
 0844              }
 0845   
 0846              if (strlen($message) > 1024)
 0847              {
 0848                  // We need to define $msg_long_text here to circumvent text stripping.
 0849                  global $msg_long_text;
 0850                  $msg_long_text = $message;
 0851   
 0852                  trigger_error(false, E_USER_ERROR);
 0853              }
 0854   
 0855              trigger_error($message, E_USER_ERROR);
 0856          }
 0857   
 0858          if ($this->transaction)
 0859          {
 0860              $this->sql_transaction('rollback');
 0861          }
 0862   
 0863          return $this->sql_error_returned;
 0864      }
 0865   
 0866      /**
 0867      * {@inheritDoc}
 0868      */
 0869      function sql_report($mode, $query = '')
 0870      {
 0871          global $cache, $starttime, $phpbb_root_path, $phpbb_path_helper, $user;
 0872          global $request;
 0873   
 0874          if (is_object($request) && !$request->variable('explain', false))
 0875          {
 0876              return false;
 0877          }
 0878   
 0879          if (!$query && $this->query_hold != '')
 0880          {
 0881              $query = $this->query_hold;
 0882          }
 0883   
 0884          switch ($mode)
 0885          {
 0886              case 'display':
 0887                  if (!empty($cache))
 0888                  {
 0889                      $cache->unload();
 0890                  }
 0891                  $this->sql_close();
 0892   
 0893                  $mtime = explode(' ', microtime());
 0894                  $totaltime = $mtime[0] + $mtime[1] - $starttime;
 0895   
 0896                  echo '<!DOCTYPE html>
 0897                      <html dir="ltr">
 0898                      <head>
 0899                          <meta charset="utf-8">
 0900                          <title>SQL Report</title>
 0901                          <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" />
 0902                      </head>
 0903                      <body id="errorpage">
 0904                      <div id="wrap">
 0905                          <div id="page-header">
 0906                              <a href="' . build_url('explain') . '">Return to previous page</a>
 0907                          </div>
 0908                          <div id="page-body">
 0909                              <div id="acp">
 0910                              <div class="panel">
 0911                                  <span class="corners-top"><span></span></span>
 0912                                  <div id="content">
 0913                                      <h1>SQL Report</h1>
 0914                                      <br />
 0915                                      <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>
 0916   
 0917                                      <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>
 0918   
 0919                                      <br /><br />
 0920                                      ' . $this->sql_report . '
 0921                                  </div>
 0922                                  <span class="corners-bottom"><span></span></span>
 0923                              </div>
 0924                              </div>
 0925                          </div>
 0926                          <div id="page-footer">
 0927                              Powered by <a href="https://www.phpbb.com/">phpBB</a>&reg; Forum Software &copy; phpBB Limited
 0928                          </div>
 0929                      </div>
 0930                      </body>
 0931                      </html>';
 0932   
 0933                  exit_handler();
 0934   
 0935              break;
 0936   
 0937              case 'stop':
 0938                  $endtime = explode(' ', microtime());
 0939                  $endtime = $endtime[0] + $endtime[1];
 0940   
 0941                  $this->sql_report .= '
 0942   
 0943                      <table cellspacing="1">
 0944                      <thead>
 0945                      <tr>
 0946                          <th>Query #' . $this->num_queries['total'] . '</th>
 0947                      </tr>
 0948                      </thead>
 0949                      <tbody>
 0950                      <tr>
 0951                          <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>
 0952                      </tr>
 0953                      </tbody>
 0954                      </table>
 0955   
 0956                      ' . $this->html_hold . '
 0957   
 0958                      <p style="text-align: center;">
 0959                  ';
 0960   
 0961                  if ($this->query_result)
 0962                  {
 0963                      if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query))
 0964                      {
 0965                          $this->sql_report .= 'Affected rows: <b>' . $this->sql_affectedrows($this->query_result) . '</b> | ';
 0966                      }
 0967                      $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>';
 0968                  }
 0969                  else
 0970                  {
 0971                      $error = $this->sql_error();
 0972                      $this->sql_report .= '<b style="color: red">FAILED</b> - ' . $this->sql_layer . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']);
 0973                  }
 0974   
 0975                  $this->sql_report .= '</p><br /><br />';
 0976   
 0977                  $this->sql_time += $endtime - $this->curtime;
 0978              break;
 0979   
 0980              case 'start':
 0981                  $this->query_hold = $query;
 0982                  $this->html_hold = '';
 0983   
 0984                  $this->_sql_report($mode, $query);
 0985   
 0986                  $this->curtime = explode(' ', microtime());
 0987                  $this->curtime = $this->curtime[0] + $this->curtime[1];
 0988   
 0989              break;
 0990   
 0991              case 'add_select_row':
 0992   
 0993                  $html_table = func_get_arg(2);
 0994                  $row = func_get_arg(3);
 0995   
 0996                  if (!$html_table && sizeof($row))
 0997                  {
 0998                      $html_table = true;
 0999                      $this->html_hold .= '<table cellspacing="1"><tr>';
 1000   
 1001                      foreach (array_keys($row) as $val)
 1002                      {
 1003                          $this->html_hold .= '<th>' . (($val) ? ucwords(str_replace('_', ' ', $val)) : '&nbsp;') . '</th>';
 1004                      }
 1005                      $this->html_hold .= '</tr>';
 1006                  }
 1007                  $this->html_hold .= '<tr>';
 1008   
 1009                  $class = 'row1';
 1010                  foreach (array_values($row) as $val)
 1011                  {
 1012                      $class = ($class == 'row1') ? 'row2' : 'row1';
 1013                      $this->html_hold .= '<td class="' . $class . '">' . (($val) ? $val : '&nbsp;') . '</td>';
 1014                  }
 1015                  $this->html_hold .= '</tr>';
 1016   
 1017                  return $html_table;
 1018   
 1019              break;
 1020   
 1021              case 'fromcache':
 1022   
 1023                  $this->_sql_report($mode, $query);
 1024   
 1025              break;
 1026   
 1027              case 'record_fromcache':
 1028   
 1029                  $endtime = func_get_arg(2);
 1030                  $splittime = func_get_arg(3);
 1031   
 1032                  $time_cache = $endtime - $this->curtime;
 1033                  $time_db = $splittime - $endtime;
 1034                  $color = ($time_db > $time_cache) ? 'green' : 'red';
 1035   
 1036                  $this->sql_report .= '<table cellspacing="1"><thead><tr><th>Query results obtained from the cache</th></tr></thead><tbody><tr>';
 1037                  $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>';
 1038                  $this->sql_report .= '<p style="text-align: center;">';
 1039                  $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 />';
 1040   
 1041                  // Pad the start time to not interfere with page timing
 1042                  $starttime += $time_db;
 1043   
 1044              break;
 1045   
 1046              default:
 1047   
 1048                  $this->_sql_report($mode, $query);
 1049   
 1050              break;
 1051          }
 1052   
 1053          return true;
 1054      }
 1055   
 1056      /**
 1057      * {@inheritDoc}
 1058      */
 1059      function get_estimated_row_count($table_name)
 1060      {
 1061          return $this->get_row_count($table_name);
 1062      }
 1063   
 1064      /**
 1065      * {@inheritDoc}
 1066      */
 1067      function get_row_count($table_name)
 1068      {
 1069          $sql = 'SELECT COUNT(*) AS rows_total
 1070              FROM ' . $this->sql_escape($table_name);
 1071          $result = $this->sql_query($sql);
 1072          $rows_total = $this->sql_fetchfield('rows_total');
 1073          $this->sql_freeresult($result);
 1074   
 1075          return $rows_total;
 1076      }
 1077  }
 1078