[ Index ]

PHP Cross Reference of MyBB 1.8.37

title

Body

[close]

/inc/ -> db_mysql.php (source)

   1  <?php
   2  /**
   3   * MyBB 1.8
   4   * Copyright 2014 MyBB Group, All Rights Reserved
   5   *
   6   * Website: http://www.mybb.com
   7   * License: http://www.mybb.com/about/license
   8   *
   9   */
  10  
  11  class DB_MySQL implements DB_Base
  12  {
  13      /**
  14       * The title of this layer.
  15       *
  16       * @var string
  17       */
  18      public $title = "MySQL";
  19  
  20      /**
  21       * The short title of this layer.
  22       *
  23       * @var string
  24       */
  25      public $short_title = "MySQL";
  26  
  27      /**
  28       * The type of db software being used.
  29       *
  30       * @var string
  31       */
  32      public $type;
  33  
  34      /**
  35       * A count of the number of queries.
  36       *
  37       * @var int
  38       */
  39      public $query_count = 0;
  40  
  41      /**
  42       * A list of the performed queries.
  43       *
  44       * @var array
  45       */
  46      public $querylist = array();
  47  
  48      /**
  49       * 1 if error reporting enabled, 0 if disabled.
  50       *
  51       * @var boolean
  52       */
  53      public $error_reporting = 1;
  54  
  55      /**
  56       * The read database connection resource.
  57       *
  58       * @var resource
  59       */
  60      public $read_link;
  61  
  62      /**
  63       * The write database connection resource
  64       *
  65       * @var resource
  66       */
  67      public $write_link;
  68  
  69      /**
  70       * Reference to the last database connection resource used.
  71       *
  72       * @var resource
  73       */
  74      public $current_link;
  75  
  76      /**
  77       * @var array
  78       */
  79      public $connections = array();
  80  
  81      /**
  82       * The database name.
  83       *
  84       * @var string
  85       */
  86      public $database;
  87  
  88      /**
  89       * Explanation of a query.
  90       *
  91       * @var string
  92       */
  93      public $explain;
  94  
  95      /**
  96       * The current version of MySQL.
  97       *
  98       * @var string
  99       */
 100      public $version;
 101  
 102      /**
 103       * The current table type in use (myisam/innodb)
 104       *
 105       * @var string
 106       */
 107      public $table_type = "myisam";
 108  
 109      /**
 110       * The table prefix used for simple select, update, insert and delete queries
 111       *
 112       * @var string
 113       */
 114      public $table_prefix;
 115  
 116      /**
 117       * The extension used to run the SQL database
 118       *
 119       * @var string
 120       */
 121      public $engine = "mysql";
 122  
 123      /**
 124       * Weather or not this engine can use the search functionality
 125       *
 126       * @var boolean
 127       */
 128      public $can_search = true;
 129  
 130      /**
 131       * The database encoding currently in use (if supported)
 132       *
 133       * @var string
 134       */
 135      public $db_encoding = "utf8";
 136  
 137      /**
 138       * The time spent performing queries
 139       *
 140       * @var float
 141       */
 142      public $query_time = 0;
 143  
 144      /**
 145       * Stores previous run query type: 1 => write; 0 => read
 146       *
 147       * @var int
 148       */
 149  
 150      protected $last_query_type = 0;
 151  
 152      /**
 153       * Connect to the database server.
 154       *
 155       * @param array $config Array of DBMS connection details.
 156       * @return resource The DB connection resource. Returns false on fail or -1 on a db connect failure.
 157       */
 158  	function connect($config)
 159      {
 160          // Simple connection to one server
 161          if(array_key_exists('hostname', $config))
 162          {
 163              $connections['read'][] = $config;
 164          }
 165          // Connecting to more than one server
 166          else
 167          {
 168              // Specified multiple servers, but no specific read/write servers
 169              if(!array_key_exists('read', $config))
 170              {
 171                  foreach($config as $key => $settings)
 172                  {
 173                      if(is_int($key))
 174                      {
 175                          $connections['read'][] = $settings;
 176                      }
 177                  }
 178              }
 179              // Specified both read & write servers
 180              else
 181              {
 182                  $connections = $config;
 183              }
 184          }
 185  
 186          if(isset($config['encoding']))
 187          {
 188              $this->db_encoding = $config['encoding'];
 189          }
 190  
 191          // Actually connect to the specified servers
 192          foreach(array('read', 'write') as $type)
 193          {
 194              if(!isset($connections[$type]) || !is_array($connections[$type]))
 195              {
 196                  break;
 197              }
 198  
 199              if(array_key_exists('hostname', $connections[$type]))
 200              {
 201                  $details = $connections[$type];
 202                  unset($connections[$type]);
 203                  $connections[$type][] = $details;
 204              }
 205  
 206              // Shuffle the connections
 207              shuffle($connections[$type]);
 208  
 209              // Loop-de-loop
 210              foreach($connections[$type] as $single_connection)
 211              {
 212                  $connect_function = "mysql_connect";
 213                  if(isset($single_connection['pconnect']))
 214                  {
 215                      $connect_function = "mysql_pconnect";
 216                  }
 217  
 218                  $link = "{$type}_link";
 219  
 220                  get_execution_time();
 221  
 222                  $this->$link = @$connect_function($single_connection['hostname'], $single_connection['username'], $single_connection['password'], 1);
 223  
 224                  $time_spent = get_execution_time();
 225                  $this->query_time += $time_spent;
 226  
 227                  // Successful connection? break down brother!
 228                  if($this->$link)
 229                  {
 230                      $this->connections[] = "[".strtoupper($type)."] {$single_connection['username']}@{$single_connection['hostname']} (Connected in ".format_time_duration($time_spent).")";
 231                      break;
 232                  }
 233                  else
 234                  {
 235                      $this->connections[] = "<span style=\"color: red\">[FAILED] [".strtoupper($type)."] {$single_connection['username']}@{$single_connection['hostname']}</span>";
 236                  }
 237              }
 238          }
 239  
 240          // No write server was specified (simple connection or just multiple servers) - mirror write link
 241          if(!array_key_exists('write', $connections))
 242          {
 243              $this->write_link = &$this->read_link;
 244          }
 245  
 246          // Have no read connection?
 247          if(!$this->read_link)
 248          {
 249              $this->error("[READ] Unable to connect to MySQL server");
 250              return false;
 251          }
 252          // No write?
 253          else if(!$this->write_link)
 254          {
 255              $this->error("[WRITE] Unable to connect to MySQL server");
 256              return false;
 257          }
 258  
 259          // Select databases
 260          if(!$this->select_db($config['database']))
 261          {
 262              return -1;
 263          }
 264  
 265          $this->current_link = &$this->read_link;
 266          return $this->read_link;
 267      }
 268  
 269      /**
 270       * Selects the database to use.
 271       *
 272       * @param string $database The database name.
 273       * @return boolean True when successfully connected, false if not.
 274       */
 275  	function select_db($database)
 276      {
 277          $this->database = $database;
 278  
 279          $this->current_link = &$this->read_link;
 280          $read_success = @mysql_select_db($database, $this->read_link) or $this->error("[READ] Unable to select database", $this->read_link);
 281          if($this->write_link)
 282          {
 283              $this->current_link = &$this->write_link;
 284              $write_success = @mysql_select_db($database, $this->write_link) or $this->error("[WRITE] Unable to select database", $this->write_link);
 285              $success = ($read_success && $write_success ? true : false);
 286          }
 287          else
 288          {
 289              $success = $read_success;
 290          }
 291  
 292          if($success && $this->db_encoding)
 293          {
 294              // A little magic to support PHP 5.2.0, 5.2.1 and 5.2.2
 295              if(version_compare(PHP_VERSION, '5.2.3', '>=')) {
 296                  @mysql_set_charset($this->db_encoding, $this->read_link);
 297              }
 298              else
 299              {
 300                  $this->query("SET NAMES '{$this->db_encoding}'");
 301              }
 302  
 303              if($write_success && count($this->connections) > 1)
 304              {
 305                  if(version_compare(PHP_VERSION, '5.2.3', '>=')) {
 306                      @mysql_set_charset($this->db_encoding, $this->write_link);
 307                  }
 308                  else
 309                  {
 310                      $this->write_query("SET NAMES '{$this->db_encoding}'");
 311                  }
 312              }
 313          }
 314          return $success;
 315      }
 316  
 317      /**
 318       * Query the database.
 319       *
 320       * @param string $string The query SQL.
 321       * @param integer $hide_errors 1 if hide errors, 0 if not.
 322       * @param integer $write_query 1 if executes on master database, 0 if not.
 323       * @return resource The query data.
 324       */
 325  	function query($string, $hide_errors=0, $write_query=0)
 326      {
 327          global $mybb;
 328  
 329          get_execution_time();
 330  
 331          // Only execute write queries on master database
 332          if(($write_query || $this->last_query_type) && $this->write_link)
 333          {
 334              $this->current_link = &$this->write_link;
 335              $query = @mysql_query($string, $this->write_link);
 336          }
 337          else
 338          {
 339              $this->current_link = &$this->read_link;
 340              $query = @mysql_query($string, $this->read_link);
 341          }
 342  
 343          if($this->error_number() && !$hide_errors)
 344          {
 345               $this->error($string);
 346               exit;
 347          }
 348  
 349          if($write_query)
 350          {
 351              $this->last_query_type = 1;
 352          }
 353          else
 354          {
 355              $this->last_query_type = 0;
 356          }
 357  
 358          $query_time = get_execution_time();
 359          $this->query_time += $query_time;
 360          $this->query_count++;
 361  
 362          if($mybb->debug_mode)
 363          {
 364              $this->explain_query($string, $query_time);
 365          }
 366  
 367          return $query;
 368      }
 369  
 370      /**
 371       * Execute a write query on the master database
 372       *
 373       * @param string $query The query SQL.
 374       * @param boolean|int $hide_errors 1 if hide errors, 0 if not.
 375       * @return resource The query data.
 376       */
 377  	function write_query($query, $hide_errors=0)
 378      {
 379          return $this->query($query, $hide_errors, 1);
 380      }
 381  
 382      /**
 383       * Explain a query on the database.
 384       *
 385       * @param string $string The query SQL.
 386       * @param string $qtime The time it took to perform the query.
 387       */
 388  	function explain_query($string, $qtime)
 389      {
 390          global $plugins;
 391  
 392          $debug_extra = '';
 393          if($plugins->current_hook)
 394          {
 395              $debug_extra = "<div style=\"float_right\">(Plugin Hook: {$plugins->current_hook})</div>";
 396          }
 397          if(preg_match("#^\s*select#i", $string))
 398          {
 399              $query = mysql_query("EXPLAIN $string", $this->current_link);
 400              $this->explain .= "<table style=\"background-color: #666;\" width=\"95%\" cellpadding=\"4\" cellspacing=\"1\" align=\"center\">\n".
 401                  "<tr>\n".
 402                  "<td colspan=\"8\" style=\"background-color: #ccc;\">{$debug_extra}<div><strong>#".$this->query_count." - Select Query</strong></div></td>\n".
 403                  "</tr>\n".
 404                  "<tr>\n".
 405                  "<td colspan=\"8\" style=\"background-color: #fefefe;\"><span style=\"font-family: Courier; font-size: 14px;\">".htmlspecialchars_uni($string)."</span></td>\n".
 406                  "</tr>\n".
 407                  "<tr style=\"background-color: #efefef;\">\n".
 408                  "<td><strong>Table</strong></td>\n".
 409                  "<td><strong>Type</strong></td>\n".
 410                  "<td><strong>Possible Keys</strong></td>\n".
 411                  "<td><strong>Key</strong></td>\n".
 412                  "<td><strong>Key Length</strong></td>\n".
 413                  "<td><strong>Ref</strong></td>\n".
 414                  "<td><strong>Rows</strong></td>\n".
 415                  "<td><strong>Extra</strong></td>\n".
 416                  "</tr>\n";
 417  
 418              while($table = mysql_fetch_array($query))
 419              {
 420                  $this->explain .=
 421                      "<tr bgcolor=\"#ffffff\">\n".
 422                      "<td>".$table['table']."</td>\n".
 423                      "<td>".$table['type']."</td>\n".
 424                      "<td>".$table['possible_keys']."</td>\n".
 425                      "<td>".$table['key']."</td>\n".
 426                      "<td>".$table['key_len']."</td>\n".
 427                      "<td>".$table['ref']."</td>\n".
 428                      "<td>".$table['rows']."</td>\n".
 429                      "<td>".$table['Extra']."</td>\n".
 430                      "</tr>\n";
 431              }
 432              $this->explain .=
 433                  "<tr>\n".
 434                  "<td colspan=\"8\" style=\"background-color: #fff;\">Query Time: ".format_time_duration($qtime)."</td>\n".
 435                  "</tr>\n".
 436                  "</table>\n".
 437                  "<br />\n";
 438          }
 439          else
 440          {
 441              $this->explain .= "<table style=\"background-color: #666;\" width=\"95%\" cellpadding=\"4\" cellspacing=\"1\" align=\"center\">\n".
 442                  "<tr>\n".
 443                  "<td style=\"background-color: #ccc;\">{$debug_extra}<div><strong>#".$this->query_count." - Write Query</strong></div></td>\n".
 444                  "</tr>\n".
 445                  "<tr style=\"background-color: #fefefe;\">\n".
 446                  "<td><span style=\"font-family: Courier; font-size: 14px;\">".htmlspecialchars_uni($string)."</span></td>\n".
 447                  "</tr>\n".
 448                  "<tr>\n".
 449                  "<td bgcolor=\"#ffffff\">Query Time: ".format_time_duration($qtime)."</td>\n".
 450                  "</tr>\n".
 451                  "</table>\n".
 452                  "<br />\n";
 453          }
 454  
 455          $this->querylist[$this->query_count]['query'] = $string;
 456          $this->querylist[$this->query_count]['time'] = $qtime;
 457      }
 458  
 459      /**
 460       * Return a result array for a query.
 461       *
 462       * @param resource $query The query ID.
 463       * @param int $resulttype The type of array to return. Either MYSQL_NUM, MYSQL_BOTH or MYSQL_ASSOC
 464       * @return array The array of results.
 465       */
 466  	function fetch_array($query, $resulttype=MYSQL_ASSOC)
 467      {
 468          switch($resulttype)
 469          {
 470              case MYSQL_NUM:
 471              case MYSQL_BOTH:
 472                  break;
 473              default:
 474                  $resulttype = MYSQL_ASSOC;
 475                  break;
 476          }
 477  
 478          $array = mysql_fetch_array($query, $resulttype);
 479  
 480          return $array;
 481      }
 482  
 483      /**
 484       * Return a specific field from a query.
 485       *
 486       * @param resource $query The query ID.
 487       * @param string $field The name of the field to return.
 488       * @param int|bool $row The number of the row to fetch it from.
 489       * @return mixed
 490       */
 491  	function fetch_field($query, $field, $row=false)
 492      {
 493          if($row === false)
 494          {
 495              $array = $this->fetch_array($query);
 496              if($array !== null)
 497              {
 498                  return $array[$field];
 499              }
 500              return null;
 501          }
 502          else
 503          {
 504              return mysql_result($query, $row, $field);
 505          }
 506      }
 507  
 508      /**
 509       * Moves internal row pointer to the next row
 510       *
 511       * @param resource $query The query ID.
 512       * @param int $row The pointer to move the row to.
 513       * @return bool
 514       */
 515  	function data_seek($query, $row)
 516      {
 517          return mysql_data_seek($query, $row);
 518      }
 519  
 520      /**
 521       * Return the number of rows resulting from a query.
 522       *
 523       * @param resource $query The query ID.
 524       * @return int The number of rows in the result.
 525       */
 526  	function num_rows($query)
 527      {
 528          return mysql_num_rows($query);
 529      }
 530  
 531      /**
 532       * Return the last id number of inserted data.
 533       *
 534       * @return int The id number.
 535       */
 536  	function insert_id()
 537      {
 538          return mysql_insert_id($this->current_link);
 539      }
 540  
 541      /**
 542       * Close the connection with the DBMS.
 543       *
 544       */
 545  	function close()
 546      {
 547          @mysql_close($this->read_link);
 548          if($this->write_link)
 549          {
 550              @mysql_close($this->write_link);
 551          }
 552      }
 553  
 554      /**
 555       * Return an error number.
 556       *
 557       * @return int The error number of the current error.
 558       */
 559  	function error_number()
 560      {
 561          if($this->current_link)
 562          {
 563              return @mysql_errno($this->current_link);
 564          }
 565          else
 566          {
 567              return @mysql_errno();
 568          }
 569      }
 570  
 571      /**
 572       * Return an error string.
 573       *
 574       * @return string The explanation for the current error.
 575       */
 576  	function error_string()
 577      {
 578          if($this->current_link)
 579          {
 580              return @mysql_error($this->current_link);
 581          }
 582          else
 583          {
 584              return @mysql_error();
 585          }
 586      }
 587  
 588      /**
 589       * Output a database error.
 590       *
 591       * @param string $string The string to present as an error.
 592       * @return bool Returns false if error reporting is disabled, otherwise true
 593       */
 594  	function error($string="")
 595      {
 596          if($this->error_reporting)
 597          {
 598              if(class_exists("errorHandler"))
 599              {
 600                  global $error_handler;
 601  
 602                  if(!is_object($error_handler))
 603                  {
 604                      require_once  MYBB_ROOT."inc/class_error.php";
 605                      $error_handler = new errorHandler();
 606                  }
 607  
 608                  $error = array(
 609                      "error_no" => $this->error_number(),
 610                      "error" => $this->error_string(),
 611                      "query" => $string
 612                  );
 613                  $error_handler->error(MYBB_SQL, $error);
 614              }
 615              else
 616              {
 617                  trigger_error("<strong>[SQL] [".$this->error_number()."] ".$this->error_string()."</strong><br />{$string}", E_USER_ERROR);
 618              }
 619  
 620              return true;
 621          }
 622          else
 623          {
 624              return false;
 625          }
 626      }
 627  
 628      /**
 629       * Returns the number of affected rows in a query.
 630       *
 631       * @return int The number of affected rows.
 632       */
 633  	function affected_rows()
 634      {
 635          return mysql_affected_rows($this->current_link);
 636      }
 637  
 638      /**
 639       * Return the number of fields.
 640       *
 641       * @param resource $query The query ID.
 642       * @return int The number of fields.
 643       */
 644  	function num_fields($query)
 645      {
 646          return mysql_num_fields($query);
 647      }
 648  
 649      /**
 650       * Lists all tables in the database.
 651       *
 652       * @param string $database The database name.
 653       * @param string $prefix Prefix of the table (optional)
 654       * @return array The table list.
 655       */
 656  	function list_tables($database, $prefix='')
 657      {
 658          if($prefix)
 659          {
 660              if(version_compare($this->get_version(), '5.0.2', '>='))
 661              {
 662                  $query = $this->query("SHOW FULL TABLES FROM `$database` WHERE table_type = 'BASE TABLE' AND `Tables_in_$database` LIKE '".$this->escape_string($prefix)."%'");
 663              }
 664              else
 665              {
 666                  $query = $this->query("SHOW TABLES FROM `$database` LIKE '".$this->escape_string($prefix)."%'");
 667              }
 668          }
 669          else
 670          {
 671              if(version_compare($this->get_version(), '5.0.2', '>='))
 672              {
 673                  $query = $this->query("SHOW FULL TABLES FROM `$database` WHERE table_type = 'BASE TABLE'");
 674              }
 675              else
 676              {
 677                  $query = $this->query("SHOW TABLES FROM `$database`");
 678              }
 679          }
 680  
 681          $tables = array();
 682          while(list($table) = mysql_fetch_array($query))
 683          {
 684              $tables[] = $table;
 685          }
 686  
 687          return $tables;
 688      }
 689  
 690      /**
 691       * Check if a table exists in a database.
 692       *
 693       * @param string $table The table name.
 694       * @return boolean True when exists, false if not.
 695       */
 696  	function table_exists($table)
 697      {
 698          // Execute on master server to ensure if we've just created a table that we get the correct result
 699          if(version_compare($this->get_version(), '5.0.2', '>='))
 700          {
 701              $query = $this->query("SHOW FULL TABLES FROM `".$this->database."` WHERE table_type = 'BASE TABLE' AND `Tables_in_".$this->database."` = '{$this->table_prefix}$table'");
 702          }
 703          else
 704          {
 705              $query = $this->query("SHOW TABLES LIKE '{$this->table_prefix}$table'");
 706          }
 707  
 708          $exists = $this->num_rows($query);
 709          if($exists > 0)
 710          {
 711              return true;
 712          }
 713          else
 714          {
 715              return false;
 716          }
 717      }
 718  
 719      /**
 720       * Check if a field exists in a database.
 721       *
 722       * @param string $field The field name.
 723       * @param string $table The table name.
 724       * @return boolean True when exists, false if not.
 725       */
 726  	function field_exists($field, $table)
 727      {
 728          $query = $this->write_query("
 729              SHOW COLUMNS
 730              FROM {$this->table_prefix}$table
 731              LIKE '$field'
 732          ");
 733          $exists = $this->num_rows($query);
 734          if($exists > 0)
 735          {
 736              return true;
 737          }
 738          else
 739          {
 740              return false;
 741          }
 742      }
 743  
 744      /**
 745       * Add a shutdown query.
 746       *
 747       * @param resource $query The query data.
 748       * @param string $name An optional name for the query.
 749       */
 750  	function shutdown_query($query, $name="")
 751      {
 752          global $shutdown_queries;
 753          if($name)
 754          {
 755              $shutdown_queries[$name] = $query;
 756          }
 757          else
 758          {
 759              $shutdown_queries[] = $query;
 760          }
 761      }
 762      /**
 763       * Performs a simple select query.
 764       *
 765       * @param string $table The table name to be queried.
 766       * @param string $fields Comma delimetered list of fields to be selected.
 767       * @param string $conditions SQL formatted list of conditions to be matched.
 768       * @param array $options List of options: group by, order by, order direction, limit, limit start.
 769       * @return resource The query data.
 770       */
 771  	function simple_select($table, $fields="*", $conditions="", $options=array())
 772      {
 773          $query = "SELECT ".$fields." FROM {$this->table_prefix}{$table}";
 774          if($conditions != "")
 775          {
 776              $query .= " WHERE ".$conditions;
 777          }
 778  
 779          if(isset($options['group_by']))
 780          {
 781              $query .= " GROUP BY ".$options['group_by'];
 782          }
 783  
 784          if(isset($options['order_by']))
 785          {
 786              $query .= " ORDER BY ".$options['order_by'];
 787              if(isset($options['order_dir']))
 788              {
 789                  $query .= " ".my_strtoupper($options['order_dir']);
 790              }
 791          }
 792  
 793          if(isset($options['limit_start']) && isset($options['limit']))
 794          {
 795              $query .= " LIMIT ".$options['limit_start'].", ".$options['limit'];
 796          }
 797          elseif(isset($options['limit']))
 798          {
 799              $query .= " LIMIT ".$options['limit'];
 800          }
 801  
 802          return $this->query($query);
 803      }
 804  
 805      /**
 806       * Build an insert query from an array.
 807       *
 808       * @param string $table The table name to perform the query on.
 809       * @param array $array An array of fields and their values.
 810       * @return int The insert ID if available
 811       */
 812  	function insert_query($table, $array)
 813      {
 814          global $mybb;
 815  
 816          if(!is_array($array))
 817          {
 818              return false;
 819          }
 820  
 821          foreach($array as $field => $value)
 822          {
 823              if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field])
 824              {
 825                  if($value[0] != 'X') // Not escaped?
 826                  {
 827                      $value = $this->escape_binary($value);
 828                  }
 829                  
 830                  $array[$field] = $value;
 831              }
 832              else
 833              {
 834                  $array[$field] = $this->quote_val($value);
 835              }
 836          }
 837  
 838          $fields = "`".implode("`,`", array_keys($array))."`";
 839          $values = implode(",", $array);
 840          $this->write_query("
 841              INSERT
 842              INTO {$this->table_prefix}{$table} (".$fields.")
 843              VALUES (".$values.")
 844          ");
 845          return $this->insert_id();
 846      }
 847  
 848      /**
 849       * Build one query for multiple inserts from a multidimensional array.
 850       *
 851       * @param string $table The table name to perform the query on.
 852       * @param array $array An array of inserts.
 853       * @return void
 854       */
 855  	function insert_query_multiple($table, $array)
 856      {
 857          global $mybb;
 858  
 859          if(!is_array($array))
 860          {
 861              return;
 862          }
 863  
 864          // Field names
 865          $fields = array_keys($array[0]);
 866          $fields = "`".implode("`,`", $fields)."`";
 867  
 868          $insert_rows = array();
 869          foreach($array as $values)
 870          {
 871              foreach($values as $field => $value)
 872              {
 873                  if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field])
 874                  {
 875                      if($value[0] != 'X') // Not escaped?
 876                      {
 877                          $value = $this->escape_binary($value);
 878                      }
 879                  
 880                      $values[$field] = $value;
 881                  }
 882                  else
 883                  {
 884                      $values[$field] = $this->quote_val($value);
 885                  }
 886              }
 887              $insert_rows[] = "(".implode(",", $values).")";
 888          }
 889          $insert_rows = implode(", ", $insert_rows);
 890  
 891          $this->write_query("
 892              INSERT
 893              INTO {$this->table_prefix}{$table} ({$fields})
 894              VALUES {$insert_rows}
 895          ");
 896      }
 897  
 898      /**
 899       * Build an update query from an array.
 900       *
 901       * @param string $table The table name to perform the query on.
 902       * @param array $array An array of fields and their values.
 903       * @param string $where An optional where clause for the query.
 904       * @param string $limit An optional limit clause for the query.
 905       * @param boolean $no_quote An option to quote incoming values of the array.
 906       * @return resource The query data.
 907       */
 908  	function update_query($table, $array, $where="", $limit="", $no_quote=false)
 909      {
 910          global $mybb;
 911  
 912          if(!is_array($array))
 913          {
 914              return false;
 915          }
 916  
 917          $comma = "";
 918          $query = "";
 919          $quote = "'";
 920  
 921          if($no_quote == true)
 922          {
 923              $quote = "";
 924          }
 925  
 926          foreach($array as $field => $value)
 927          {
 928              if(isset($mybb->binary_fields[$table][$field]) && $mybb->binary_fields[$table][$field])
 929              {
 930                  if($value[0] != 'X') // Not escaped?
 931                  {
 932                      $value = $this->escape_binary($value);
 933                  }
 934                  
 935                  $query .= $comma."`".$field."`={$value}";
 936              }
 937              else
 938              {
 939                  $quoted_val = $this->quote_val($value, $quote);
 940  
 941                  $query .= $comma."`".$field."`={$quoted_val}";
 942              }
 943              $comma = ', ';
 944          }
 945  
 946          if(!empty($where))
 947          {
 948              $query .= " WHERE $where";
 949          }
 950  
 951          if(!empty($limit))
 952          {
 953              $query .= " LIMIT $limit";
 954          }
 955  
 956          return $this->write_query("
 957              UPDATE {$this->table_prefix}$table
 958              SET $query
 959          ");
 960      }
 961  
 962      /**
 963       * @param int|string $value
 964       * @param string $quote
 965       *
 966       * @return int|string
 967       */
 968  	private function quote_val($value, $quote="'")
 969      {
 970          if(is_int($value))
 971          {
 972              $quoted = $value;
 973          }
 974          else
 975          {
 976              $quoted = $quote . $value . $quote;
 977          }
 978  
 979          return $quoted;
 980      }
 981  
 982      /**
 983       * Build a delete query.
 984       *
 985       * @param string $table The table name to perform the query on.
 986       * @param string $where An optional where clause for the query.
 987       * @param string $limit An optional limit clause for the query.
 988       * @return resource The query data.
 989       */
 990  	function delete_query($table, $where="", $limit="")
 991      {
 992          $query = "";
 993          if(!empty($where))
 994          {
 995              $query .= " WHERE $where";
 996          }
 997  
 998          if(!empty($limit))
 999          {
1000              $query .= " LIMIT $limit";
1001          }
1002  
1003          return $this->write_query("
1004              DELETE
1005              FROM {$this->table_prefix}$table
1006              $query
1007          ");
1008      }
1009  
1010      /**
1011       * Escape a string according to the MySQL escape format.
1012       *
1013       * @param string $string The string to be escaped.
1014       * @return string The escaped string.
1015       */
1016  	function escape_string($string)
1017      {
1018          if($this->db_encoding == 'utf8')
1019          {
1020              $string = validate_utf8_string($string, false);
1021          }
1022          elseif($this->db_encoding == 'utf8mb4')
1023          {
1024              $string = validate_utf8_string($string);
1025          }
1026  
1027          if(function_exists("mysql_real_escape_string") && $this->read_link)
1028          {
1029              $string = mysql_real_escape_string($string, $this->read_link);
1030          }
1031          else
1032          {
1033              $string = addslashes($string);
1034          }
1035          return $string;
1036      }
1037  
1038      /**
1039       * Frees the resources of a MySQLi query.
1040       *
1041       * @param resource $query The query to destroy.
1042       * @return boolean Returns true on success, false on faliure
1043       */
1044  	function free_result($query)
1045      {
1046          return mysql_free_result($query);
1047      }
1048  
1049      /**
1050       * Escape a string used within a like command.
1051       *
1052       * @param string $string The string to be escaped.
1053       * @return string The escaped string.
1054       */
1055  	function escape_string_like($string)
1056      {
1057          return $this->escape_string(str_replace(array('\\', '%', '_') , array('\\\\', '\\%' , '\\_') , $string));
1058      }
1059  
1060      /**
1061       * Gets the current version of MySQL.
1062       *
1063       * @return string Version of MySQL.
1064       */
1065  	function get_version()
1066      {
1067          if($this->version)
1068          {
1069              return $this->version;
1070          }
1071  
1072          $query = $this->query("SELECT VERSION() as version");
1073          $ver = $this->fetch_array($query);
1074          $version = $ver['version'];
1075  
1076          if($version)
1077          {
1078              $version = explode(".", $version, 3);
1079              $this->version = (int)$version[0].".".(int)$version[1].".".(int)$version[2];
1080          }
1081          return $this->version;
1082      }
1083  
1084      /**
1085       * Optimizes a specific table.
1086       *
1087       * @param string $table The name of the table to be optimized.
1088       */
1089  	function optimize_table($table)
1090      {
1091          $this->write_query("OPTIMIZE TABLE {$this->table_prefix}{$table}");
1092      }
1093  
1094      /**
1095       * Analyzes a specific table.
1096       *
1097       * @param string $table The name of the table to be analyzed.
1098       */
1099  	function analyze_table($table)
1100      {
1101          $this->write_query("ANALYZE TABLE {$this->table_prefix}{$table}");
1102      }
1103  
1104      /**
1105       * Show the "create table" command for a specific table.
1106       *
1107       * @param string $table The name of the table.
1108       * @return string The MySQL command to create the specified table.
1109       */
1110  	function show_create_table($table)
1111      {
1112          $query = $this->write_query("SHOW CREATE TABLE {$this->table_prefix}{$table}");
1113          $structure = $this->fetch_array($query);
1114          return $structure['Create Table'];
1115      }
1116  
1117      /**
1118       * Show the "show fields from" command for a specific table.
1119       *
1120       * @param string $table The name of the table.
1121       * @return array Field info for that table
1122       */
1123  	function show_fields_from($table)
1124      {
1125          $query = $this->write_query("SHOW FIELDS FROM {$this->table_prefix}{$table}");
1126          $field_info = array();
1127          while($field = $this->fetch_array($query))
1128          {
1129              $field_info[] = $field;
1130          }
1131          return $field_info;
1132      }
1133  
1134      /**
1135       * Returns whether or not the table contains a fulltext index.
1136       *
1137       * @param string $table The name of the table.
1138       * @param string $index Optionally specify the name of the index.
1139       * @return boolean True or false if the table has a fulltext index or not.
1140       */
1141  	function is_fulltext($table, $index="")
1142      {
1143          $structure = $this->show_create_table($table);
1144          if($index != "")
1145          {
1146              if(preg_match("#FULLTEXT KEY (`?)$index(`?)#i", $structure))
1147              {
1148                  return true;
1149              }
1150              else
1151              {
1152                  return false;
1153              }
1154          }
1155          if(preg_match('#FULLTEXT KEY#i', $structure))
1156          {
1157              return true;
1158          }
1159          return false;
1160      }
1161  
1162      /**
1163       * Returns whether or not this database engine supports fulltext indexing.
1164       *
1165       * @param string $table The table to be checked.
1166       * @return boolean True or false if supported or not.
1167       */
1168  
1169  	function supports_fulltext($table)
1170      {
1171          $version = $this->get_version();
1172          $query = $this->write_query("SHOW TABLE STATUS LIKE '{$this->table_prefix}$table'");
1173          $status = $this->fetch_array($query);
1174          if($status['Engine'])
1175          {
1176              $table_type = my_strtoupper($status['Engine']);
1177          }
1178          else
1179          {
1180              $table_type = my_strtoupper($status['Type']);
1181          }
1182          if(version_compare($version, '3.23.23', '>=') && ($table_type == 'MYISAM' || $table_type == 'ARIA'))
1183          {
1184              return true;
1185          }
1186          elseif(version_compare($version, '5.6', '>=') && $table_type == 'INNODB')
1187          {
1188              return true;
1189          }
1190          return false;
1191      }
1192  
1193      /**
1194       * Checks to see if an index exists on a specified table
1195       *
1196       * @param string $table The name of the table.
1197       * @param string $index The name of the index.
1198       * @return bool Whether or not the index exists in that table
1199       */
1200  	function index_exists($table, $index)
1201      {
1202          $index_exists = false;
1203          $query = $this->write_query("SHOW INDEX FROM {$this->table_prefix}{$table}");
1204          while($ukey = $this->fetch_array($query))
1205          {
1206              if($ukey['Key_name'] == $index)
1207              {
1208                  $index_exists = true;
1209                  break;
1210              }
1211          }
1212  
1213          if($index_exists)
1214          {
1215              return true;
1216          }
1217  
1218          return false;
1219      }
1220  
1221      /**
1222       * Returns whether or not this database engine supports boolean fulltext matching.
1223       *
1224       * @param string $table The table to be checked.
1225       * @return boolean True or false if supported or not.
1226       */
1227  	function supports_fulltext_boolean($table)
1228      {
1229          $version = $this->get_version();
1230          $supports_fulltext = $this->supports_fulltext($table);
1231          if(version_compare($version, '4.0.1', '>=') && $supports_fulltext == true)
1232          {
1233              return true;
1234          }
1235          return false;
1236      }
1237  
1238      /**
1239       * Creates a fulltext index on the specified column in the specified table with optional index name.
1240       *
1241       * @param string $table The name of the table.
1242       * @param string $column Name of the column to be indexed.
1243       * @param string $name The index name, optional.
1244       */
1245  	function create_fulltext_index($table, $column, $name="")
1246      {
1247          $this->write_query("
1248              ALTER TABLE {$this->table_prefix}$table
1249              ADD FULLTEXT $name ($column)
1250          ");
1251      }
1252  
1253      /**
1254       * Drop an index with the specified name from the specified table
1255       *
1256       * @param string $table The name of the table.
1257       * @param string $name The name of the index.
1258       */
1259  	function drop_index($table, $name)
1260      {
1261          $this->write_query("
1262              ALTER TABLE {$this->table_prefix}$table
1263              DROP INDEX $name
1264          ");
1265      }
1266  
1267      /**
1268       * Drop an table with the specified table
1269       *
1270       * @param string $table The table to drop
1271       * @param boolean $hard hard drop - no checking
1272       * @param boolean $table_prefix use table prefix
1273       */
1274  	function drop_table($table, $hard=false, $table_prefix=true)
1275      {
1276          if($table_prefix == false)
1277          {
1278              $table_prefix = "";
1279          }
1280          else
1281          {
1282              $table_prefix = $this->table_prefix;
1283          }
1284  
1285          if($hard == false)
1286          {
1287              $this->write_query('DROP TABLE IF EXISTS '.$table_prefix.$table);
1288          }
1289          else
1290          {
1291              $this->write_query('DROP TABLE '.$table_prefix.$table);
1292          }
1293      }
1294  
1295      /**
1296       * Renames a table
1297       *
1298       * @param string $old_table The old table name
1299       * @param string $new_table the new table name
1300       * @param boolean $table_prefix use table prefix
1301       * @return resource
1302       */
1303  	function rename_table($old_table, $new_table, $table_prefix=true)
1304      {
1305          if($table_prefix == false)
1306          {
1307              $table_prefix = "";
1308          }
1309          else
1310          {
1311              $table_prefix = $this->table_prefix;
1312          }
1313  
1314          return $this->write_query("RENAME TABLE {$table_prefix}{$old_table} TO {$table_prefix}{$new_table}");
1315      }
1316  
1317      /**
1318       * Replace contents of table with values
1319       *
1320       * @param string $table The table
1321       * @param array $replacements The replacements
1322       * @param string|array $default_field The default field(s)
1323       * @param boolean $insert_id Whether or not to return an insert id. True by default
1324       * @return resource|bool
1325       */
1326  	function replace_query($table, $replacements=array(), $default_field="", $insert_id=true)
1327      {
1328          global $mybb;
1329  
1330          $values = '';
1331          $comma = '';
1332          foreach($replacements as $column => $value)
1333          {
1334              if(isset($mybb->binary_fields[$table][$column]) && $mybb->binary_fields[$table][$column])
1335              {
1336                  if($value[0] != 'X') // Not escaped?
1337                  {
1338                      $value = $this->escape_binary($value);
1339                  }
1340                  
1341                  $values .= $comma."`".$column."`=".$value;
1342              }
1343              else
1344              {
1345                  $values .= $comma."`".$column."`=".$this->quote_val($value);
1346              }
1347  
1348              $comma = ',';
1349          }
1350  
1351          if(empty($replacements))
1352          {
1353               return false;
1354          }
1355  
1356          return $this->write_query("REPLACE INTO {$this->table_prefix}{$table} SET {$values}");
1357      }
1358  
1359      /**
1360       * Drops a column
1361       *
1362       * @param string $table The table
1363       * @param string $column The column name
1364       * @return resource
1365       */
1366  	function drop_column($table, $column)
1367      {
1368          $column = trim($column, '`');
1369  
1370          return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} DROP `{$column}`");
1371      }
1372  
1373      /**
1374       * Adds a column
1375       *
1376       * @param string $table The table
1377       * @param string $column The column name
1378       * @param string $definition the new column definition
1379       * @return resource
1380       */
1381  	function add_column($table, $column, $definition)
1382      {
1383          $column = trim($column, '`');
1384  
1385          return $this->write_query("ALTER TABLE {$this->table_prefix}{$table} ADD `{$column}` {$definition}");
1386      }
1387  
1388      /**
1389       * Modifies a column
1390       *
1391       * @param string $table The table
1392       * @param string $column The column name
1393       * @param string $new_definition the new column definition
1394       * @param boolean|string $new_not_null Whether to "drop" or "set" the NOT NULL attribute (no change if false)
1395       * @param boolean|string $new_default_value The new default value, or false to drop the attribute
1396       * @return bool Returns true if all queries are executed successfully or false if one of them failed
1397       */
1398  	function modify_column($table, $column, $new_definition, $new_not_null=false, $new_default_value=false)
1399      {
1400          $column = trim($column, '`');
1401  
1402          if($new_not_null !== false)
1403          {
1404              if(strtolower($new_not_null) == "set")
1405              {
1406                  $not_null = "NOT NULL";
1407              }
1408              else
1409              {
1410                  $not_null = "NULL";
1411              }
1412          }
1413          else
1414          {
1415              $not_null = '';
1416          }
1417  
1418          if($new_default_value !== false)
1419          {
1420              $default = "DEFAULT ".$new_default_value;
1421          }
1422          else
1423          {
1424              $default = '';
1425          }
1426  
1427          return (bool)$this->write_query("ALTER TABLE {$this->table_prefix}{$table} MODIFY `{$column}` {$new_definition} {$not_null} {$default}");
1428      }
1429  
1430      /**
1431       * Renames a column
1432       *
1433       * @param string $table The table
1434       * @param string $old_column The old column name
1435       * @param string $new_column the new column name
1436       * @param string $new_definition the new column definition
1437       * @param boolean|string $new_not_null Whether to "drop" or "set" the NOT NULL attribute (no change if false)
1438       * @param boolean|string $new_default_value The new default value, or false to drop the attribute
1439       * @return bool Returns true if all queries are executed successfully
1440       */
1441  	function rename_column($table, $old_column, $new_column, $new_definition, $new_not_null=false, $new_default_value=false)
1442      {
1443          $old_column = trim($old_column, '`');
1444          $new_column = trim($new_column, '`');
1445  
1446          if($new_not_null !== false)
1447          {
1448              if(strtolower($new_not_null) == "set")
1449              {
1450                  $not_null = "NOT NULL";
1451              }
1452              else
1453              {
1454                  $not_null = "NULL";
1455              }
1456          }
1457          else
1458          {
1459              $not_null = '';
1460          }
1461  
1462          if($new_default_value !== false)
1463          {
1464              $default = "DEFAULT ".$new_default_value;
1465          }
1466          else
1467          {
1468              $default = '';
1469          }
1470  
1471          return (bool)$this->write_query("ALTER TABLE {$this->table_prefix}{$table} CHANGE `{$old_column}` `{$new_column}` {$new_definition} {$not_null} {$default}");
1472      }
1473  
1474      /**
1475       * Sets the table prefix used by the simple select, insert, update and delete functions
1476       *
1477       * @param string $prefix The new table prefix
1478       */
1479  	function set_table_prefix($prefix)
1480      {
1481          $this->table_prefix = $prefix;
1482      }
1483  
1484      /**
1485       * Fetched the total size of all mysql tables or a specific table
1486       *
1487       * @param string $table The table (optional)
1488       * @return integer the total size of all mysql tables or a specific table
1489       */
1490  	function fetch_size($table='')
1491      {
1492          if($table != '')
1493          {
1494              $query = $this->query("SHOW TABLE STATUS LIKE '".$this->table_prefix.$table."'");
1495          }
1496          else
1497          {
1498              $query = $this->query("SHOW TABLE STATUS");
1499          }
1500          $total = 0;
1501          while($table = $this->fetch_array($query))
1502          {
1503              $total += $table['Data_length']+$table['Index_length'];
1504          }
1505          return $total;
1506      }
1507  
1508      /**
1509       * Fetch a list of database character sets this DBMS supports
1510       *
1511       * @return array|bool Array of supported character sets with array key being the name, array value being display name. False if unsupported
1512       */
1513  	function fetch_db_charsets()
1514      {
1515          if($this->write_link && version_compare($this->get_version(), "4.1", "<"))
1516          {
1517              return false;
1518          }
1519          return array(
1520              'big5' => 'Big5 Traditional Chinese',
1521              'dec8' => 'DEC West European',
1522              'cp850' => 'DOS West European',
1523              'hp8' => 'HP West European',
1524              'koi8r' => 'KOI8-R Relcom Russian',
1525              'latin1' => 'ISO 8859-1 Latin 1',
1526              'latin2' => 'ISO 8859-2 Central European',
1527              'swe7' => '7bit Swedish',
1528              'ascii' => 'US ASCII',
1529              'ujis' => 'EUC-JP Japanese',
1530              'sjis' => 'Shift-JIS Japanese',
1531              'hebrew' => 'ISO 8859-8 Hebrew',
1532              'tis620' => 'TIS620 Thai',
1533              'euckr' => 'EUC-KR Korean',
1534              'koi8u' => 'KOI8-U Ukrainian',
1535              'gb2312' => 'GB2312 Simplified Chinese',
1536              'greek' => 'ISO 8859-7 Greek',
1537              'cp1250' => 'Windows Central European',
1538              'gbk' => 'GBK Simplified Chinese',
1539              'latin5' => 'ISO 8859-9 Turkish',
1540              'armscii8' => 'ARMSCII-8 Armenian',
1541              'utf8' => 'UTF-8 Unicode',
1542              'utf8mb4' => '4-Byte UTF-8 Unicode (requires MySQL 5.5.3 or above)',
1543              'ucs2' => 'UCS-2 Unicode',
1544              'cp866' => 'DOS Russian',
1545              'keybcs2' => 'DOS Kamenicky Czech-Slovak',
1546              'macce' => 'Mac Central European',
1547              'macroman' => 'Mac West European',
1548              'cp852' => 'DOS Central European',
1549              'latin7' => 'ISO 8859-13 Baltic',
1550              'cp1251' => 'Windows Cyrillic',
1551              'cp1256' => 'Windows Arabic',
1552              'cp1257' => 'Windows Baltic',
1553              'geostd8' => 'GEOSTD8 Georgian',
1554              'cp932' => 'SJIS for Windows Japanese',
1555              'eucjpms' => 'UJIS for Windows Japanese',
1556          );
1557      }
1558  
1559      /**
1560       * Fetch a database collation for a particular database character set
1561       *
1562       * @param string  $charset The database character set
1563       * @return string|bool The matching database collation, false if unsupported
1564       */
1565  	function fetch_charset_collation($charset)
1566      {
1567          $collations = array(
1568              'big5' => 'big5_chinese_ci',
1569              'dec8' => 'dec8_swedish_ci',
1570              'cp850' => 'cp850_general_ci',
1571              'hp8' => 'hp8_english_ci',
1572              'koi8r' => 'koi8r_general_ci',
1573              'latin1' => 'latin1_swedish_ci',
1574              'latin2' => 'latin2_general_ci',
1575              'swe7' => 'swe7_swedish_ci',
1576              'ascii' => 'ascii_general_ci',
1577              'ujis' => 'ujis_japanese_ci',
1578              'sjis' => 'sjis_japanese_ci',
1579              'hebrew' => 'hebrew_general_ci',
1580              'tis620' => 'tis620_thai_ci',
1581              'euckr' => 'euckr_korean_ci',
1582              'koi8u' => 'koi8u_general_ci',
1583              'gb2312' => 'gb2312_chinese_ci',
1584              'greek' => 'greek_general_ci',
1585              'cp1250' => 'cp1250_general_ci',
1586              'gbk' => 'gbk_chinese_ci',
1587              'latin5' => 'latin5_turkish_ci',
1588              'armscii8' => 'armscii8_general_ci',
1589              'utf8' => 'utf8_general_ci',
1590              'utf8mb4' => 'utf8mb4_general_ci',
1591              'ucs2' => 'ucs2_general_ci',
1592              'cp866' => 'cp866_general_ci',
1593              'keybcs2' => 'keybcs2_general_ci',
1594              'macce' => 'macce_general_ci',
1595              'macroman' => 'macroman_general_ci',
1596              'cp852' => 'cp852_general_ci',
1597              'latin7' => 'latin7_general_ci',
1598              'cp1251' => 'cp1251_general_ci',
1599              'cp1256' => 'cp1256_general_ci',
1600              'cp1257' => 'cp1257_general_ci',
1601              'geostd8' => 'geostd8_general_ci',
1602              'cp932' => 'cp932_japanese_ci',
1603              'eucjpms' => 'eucjpms_japanese_ci',
1604          );
1605          if($collations[$charset])
1606          {
1607              return $collations[$charset];
1608          }
1609          return false;
1610      }
1611  
1612      /**
1613       * Fetch a character set/collation string for use with CREATE TABLE statements. Uses current DB encoding
1614       *
1615       * @return string The built string, empty if unsupported
1616       */
1617  	function build_create_table_collation()
1618      {
1619          if(!$this->db_encoding)
1620          {
1621              return '';
1622          }
1623  
1624          $collation = $this->fetch_charset_collation($this->db_encoding);
1625          if(!$collation)
1626          {
1627              return '';
1628          }
1629          return " CHARACTER SET {$this->db_encoding} COLLATE {$collation}";
1630      }
1631  
1632      /**
1633       * Time how long it takes for a particular piece of code to run. Place calls above & below the block of code.
1634       *
1635       * @deprecated
1636       */
1637  	function get_execution_time()
1638      {
1639          return get_execution_time();
1640      }
1641  
1642      /**
1643       * Binary database fields require special attention.
1644       *
1645       * @param string $string Binary value
1646       * @return string Encoded binary value
1647       */
1648  	function escape_binary($string)
1649      {
1650          return "X'".$this->escape_string(bin2hex($string))."'";
1651      }
1652  
1653      /**
1654       * Unescape binary data.
1655       *
1656       * @param string $string Binary value
1657       * @return string Encoded binary value
1658       */
1659  	function unescape_binary($string)
1660      {
1661          // Nothing to do
1662          return $string;
1663      }
1664  }
1665  


2005 - 2021 © MyBB.de | Alle Rechte vorbehalten! | Sponsor: netcup Cross-referenced by PHPXref