home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress2 / wp-includes / wp-db.php < prev    next >
Encoding:
PHP Script  |  2018-01-22  |  97.1 KB  |  3,431 lines

  1. <?php
  2. /**
  3.  * WordPress DB Class
  4.  *
  5.  * Original code from {@link http://php.justinvincent.com Justin Vincent (justin@visunet.ie)}
  6.  *
  7.  * @package WordPress
  8.  * @subpackage Database
  9.  * @since 0.71
  10.  */
  11.  
  12. /**
  13.  * @since 0.71
  14.  */
  15. define( 'EZSQL_VERSION', 'WP1.25' );
  16.  
  17. /**
  18.  * @since 0.71
  19.  */
  20. define( 'OBJECT', 'OBJECT' );
  21. define( 'object', 'OBJECT' ); // Back compat.
  22.  
  23. /**
  24.  * @since 2.5.0
  25.  */
  26. define( 'OBJECT_K', 'OBJECT_K' );
  27.  
  28. /**
  29.  * @since 0.71
  30.  */
  31. define( 'ARRAY_A', 'ARRAY_A' );
  32.  
  33. /**
  34.  * @since 0.71
  35.  */
  36. define( 'ARRAY_N', 'ARRAY_N' );
  37.  
  38. /**
  39.  * WordPress Database Access Abstraction Object
  40.  *
  41.  * It is possible to replace this class with your own
  42.  * by setting the $wpdb global variable in wp-content/db.php
  43.  * file to your class. The wpdb class will still be included,
  44.  * so you can extend it or simply use your own.
  45.  *
  46.  * @link https://codex.wordpress.org/Function_Reference/wpdb_Class
  47.  *
  48.  * @since 0.71
  49.  */
  50. class wpdb {
  51.  
  52.     /**
  53.      * Whether to show SQL/DB errors.
  54.      *
  55.      * Default behavior is to show errors if both WP_DEBUG and WP_DEBUG_DISPLAY
  56.      * evaluated to true.
  57.      *
  58.      * @since 0.71
  59.      * @var bool
  60.      */
  61.     var $show_errors = false;
  62.  
  63.     /**
  64.      * Whether to suppress errors during the DB bootstrapping.
  65.      *
  66.      * @since 2.5.0
  67.      * @var bool
  68.      */
  69.     var $suppress_errors = false;
  70.  
  71.     /**
  72.      * The last error during query.
  73.      *
  74.      * @since 2.5.0
  75.      * @var string
  76.      */
  77.     public $last_error = '';
  78.  
  79.     /**
  80.      * Amount of queries made
  81.      *
  82.      * @since 1.2.0
  83.      * @var int
  84.      */
  85.     public $num_queries = 0;
  86.  
  87.     /**
  88.      * Count of rows returned by previous query
  89.      *
  90.      * @since 0.71
  91.      * @var int
  92.      */
  93.     public $num_rows = 0;
  94.  
  95.     /**
  96.      * Count of affected rows by previous query
  97.      *
  98.      * @since 0.71
  99.      * @var int
  100.      */
  101.     var $rows_affected = 0;
  102.  
  103.     /**
  104.      * The ID generated for an AUTO_INCREMENT column by the previous query (usually INSERT).
  105.      *
  106.      * @since 0.71
  107.      * @var int
  108.      */
  109.     public $insert_id = 0;
  110.  
  111.     /**
  112.      * Last query made
  113.      *
  114.      * @since 0.71
  115.      * @var array
  116.      */
  117.     var $last_query;
  118.  
  119.     /**
  120.      * Results of the last query made
  121.      *
  122.      * @since 0.71
  123.      * @var array|null
  124.      */
  125.     var $last_result;
  126.  
  127.     /**
  128.      * MySQL result, which is either a resource or boolean.
  129.      *
  130.      * @since 0.71
  131.      * @var mixed
  132.      */
  133.     protected $result;
  134.  
  135.     /**
  136.      * Cached column info, for sanity checking data before inserting
  137.      *
  138.      * @since 4.2.0
  139.      * @var array
  140.      */
  141.     protected $col_meta = array();
  142.  
  143.     /**
  144.      * Calculated character sets on tables
  145.      *
  146.      * @since 4.2.0
  147.      * @var array
  148.      */
  149.     protected $table_charset = array();
  150.  
  151.     /**
  152.      * Whether text fields in the current query need to be sanity checked.
  153.      *
  154.      * @since 4.2.0
  155.      * @var bool
  156.      */
  157.     protected $check_current_query = true;
  158.  
  159.     /**
  160.      * Flag to ensure we don't run into recursion problems when checking the collation.
  161.      *
  162.      * @since 4.2.0
  163.      * @see wpdb::check_safe_collation()
  164.      * @var bool
  165.      */
  166.     private $checking_collation = false;
  167.  
  168.     /**
  169.      * Saved info on the table column
  170.      *
  171.      * @since 0.71
  172.      * @var array
  173.      */
  174.     protected $col_info;
  175.  
  176.     /**
  177.      * Saved queries that were executed
  178.      *
  179.      * @since 1.5.0
  180.      * @var array
  181.      */
  182.     var $queries;
  183.  
  184.     /**
  185.      * The number of times to retry reconnecting before dying.
  186.      *
  187.      * @since 3.9.0
  188.      * @see wpdb::check_connection()
  189.      * @var int
  190.      */
  191.     protected $reconnect_retries = 5;
  192.  
  193.     /**
  194.      * WordPress table prefix
  195.      *
  196.      * You can set this to have multiple WordPress installations
  197.      * in a single database. The second reason is for possible
  198.      * security precautions.
  199.      *
  200.      * @since 2.5.0
  201.      * @var string
  202.      */
  203.     public $prefix = '';
  204.  
  205.     /**
  206.      * WordPress base table prefix.
  207.      *
  208.      * @since 3.0.0
  209.      * @var string
  210.      */
  211.      public $base_prefix;
  212.  
  213.     /**
  214.      * Whether the database queries are ready to start executing.
  215.      *
  216.      * @since 2.3.2
  217.      * @var bool
  218.      */
  219.     var $ready = false;
  220.  
  221.     /**
  222.      * Blog ID.
  223.      *
  224.      * @since 3.0.0
  225.      * @var int
  226.      */
  227.     public $blogid = 0;
  228.  
  229.     /**
  230.      * Site ID.
  231.      *
  232.      * @since 3.0.0
  233.      * @var int
  234.      */
  235.     public $siteid = 0;
  236.  
  237.     /**
  238.      * List of WordPress per-blog tables
  239.      *
  240.      * @since 2.5.0
  241.      * @see wpdb::tables()
  242.      * @var array
  243.      */
  244.     var $tables = array( 'posts', 'comments', 'links', 'options', 'postmeta',
  245.         'terms', 'term_taxonomy', 'term_relationships', 'termmeta', 'commentmeta' );
  246.  
  247.     /**
  248.      * List of deprecated WordPress tables
  249.      *
  250.      * categories, post2cat, and link2cat were deprecated in 2.3.0, db version 5539
  251.      *
  252.      * @since 2.9.0
  253.      * @see wpdb::tables()
  254.      * @var array
  255.      */
  256.     var $old_tables = array( 'categories', 'post2cat', 'link2cat' );
  257.  
  258.     /**
  259.      * List of WordPress global tables
  260.      *
  261.      * @since 3.0.0
  262.      * @see wpdb::tables()
  263.      * @var array
  264.      */
  265.     var $global_tables = array( 'users', 'usermeta' );
  266.  
  267.     /**
  268.      * List of Multisite global tables
  269.      *
  270.      * @since 3.0.0
  271.      * @see wpdb::tables()
  272.      * @var array
  273.      */
  274.     var $ms_global_tables = array( 'blogs', 'signups', 'site', 'sitemeta',
  275.         'sitecategories', 'registration_log', 'blog_versions' );
  276.  
  277.     /**
  278.      * WordPress Comments table
  279.      *
  280.      * @since 1.5.0
  281.      * @var string
  282.      */
  283.     public $comments;
  284.  
  285.     /**
  286.      * WordPress Comment Metadata table
  287.      *
  288.      * @since 2.9.0
  289.      * @var string
  290.      */
  291.     public $commentmeta;
  292.  
  293.     /**
  294.      * WordPress Links table
  295.      *
  296.      * @since 1.5.0
  297.      * @var string
  298.      */
  299.     public $links;
  300.  
  301.     /**
  302.      * WordPress Options table
  303.      *
  304.      * @since 1.5.0
  305.      * @var string
  306.      */
  307.     public $options;
  308.  
  309.     /**
  310.      * WordPress Post Metadata table
  311.      *
  312.      * @since 1.5.0
  313.      * @var string
  314.      */
  315.     public $postmeta;
  316.  
  317.     /**
  318.      * WordPress Posts table
  319.      *
  320.      * @since 1.5.0
  321.      * @var string
  322.      */
  323.     public $posts;
  324.  
  325.     /**
  326.      * WordPress Terms table
  327.      *
  328.      * @since 2.3.0
  329.      * @var string
  330.      */
  331.     public $terms;
  332.  
  333.     /**
  334.      * WordPress Term Relationships table
  335.      *
  336.      * @since 2.3.0
  337.      * @var string
  338.      */
  339.     public $term_relationships;
  340.  
  341.     /**
  342.      * WordPress Term Taxonomy table
  343.      *
  344.      * @since 2.3.0
  345.      * @var string
  346.      */
  347.     public $term_taxonomy;
  348.  
  349.     /**
  350.      * WordPress Term Meta table.
  351.      *
  352.      * @since 4.4.0
  353.      * @var string
  354.      */
  355.     public $termmeta;
  356.  
  357.     //
  358.     // Global and Multisite tables
  359.     //
  360.  
  361.     /**
  362.      * WordPress User Metadata table
  363.      *
  364.      * @since 2.3.0
  365.      * @var string
  366.      */
  367.     public $usermeta;
  368.  
  369.     /**
  370.      * WordPress Users table
  371.      *
  372.      * @since 1.5.0
  373.      * @var string
  374.      */
  375.     public $users;
  376.  
  377.     /**
  378.      * Multisite Blogs table
  379.      *
  380.      * @since 3.0.0
  381.      * @var string
  382.      */
  383.     public $blogs;
  384.  
  385.     /**
  386.      * Multisite Blog Versions table
  387.      *
  388.      * @since 3.0.0
  389.      * @var string
  390.      */
  391.     public $blog_versions;
  392.  
  393.     /**
  394.      * Multisite Registration Log table
  395.      *
  396.      * @since 3.0.0
  397.      * @var string
  398.      */
  399.     public $registration_log;
  400.  
  401.     /**
  402.      * Multisite Signups table
  403.      *
  404.      * @since 3.0.0
  405.      * @var string
  406.      */
  407.     public $signups;
  408.  
  409.     /**
  410.      * Multisite Sites table
  411.      *
  412.      * @since 3.0.0
  413.      * @var string
  414.      */
  415.     public $site;
  416.  
  417.     /**
  418.      * Multisite Sitewide Terms table
  419.      *
  420.      * @since 3.0.0
  421.      * @var string
  422.      */
  423.     public $sitecategories;
  424.  
  425.     /**
  426.      * Multisite Site Metadata table
  427.      *
  428.      * @since 3.0.0
  429.      * @var string
  430.      */
  431.     public $sitemeta;
  432.  
  433.     /**
  434.      * Format specifiers for DB columns. Columns not listed here default to %s. Initialized during WP load.
  435.      *
  436.      * Keys are column names, values are format types: 'ID' => '%d'
  437.      *
  438.      * @since 2.8.0
  439.      * @see wpdb::prepare()
  440.      * @see wpdb::insert()
  441.      * @see wpdb::update()
  442.      * @see wpdb::delete()
  443.      * @see wp_set_wpdb_vars()
  444.      * @var array
  445.      */
  446.     public $field_types = array();
  447.  
  448.     /**
  449.      * Database table columns charset
  450.      *
  451.      * @since 2.2.0
  452.      * @var string
  453.      */
  454.     public $charset;
  455.  
  456.     /**
  457.      * Database table columns collate
  458.      *
  459.      * @since 2.2.0
  460.      * @var string
  461.      */
  462.     public $collate;
  463.  
  464.     /**
  465.      * Database Username
  466.      *
  467.      * @since 2.9.0
  468.      * @var string
  469.      */
  470.     protected $dbuser;
  471.  
  472.     /**
  473.      * Database Password
  474.      *
  475.      * @since 3.1.0
  476.      * @var string
  477.      */
  478.     protected $dbpassword;
  479.  
  480.     /**
  481.      * Database Name
  482.      *
  483.      * @since 3.1.0
  484.      * @var string
  485.      */
  486.     protected $dbname;
  487.  
  488.     /**
  489.      * Database Host
  490.      *
  491.      * @since 3.1.0
  492.      * @var string
  493.      */
  494.     protected $dbhost;
  495.  
  496.     /**
  497.      * Database Handle
  498.      *
  499.      * @since 0.71
  500.      * @var string
  501.      */
  502.     protected $dbh;
  503.  
  504.     /**
  505.      * A textual description of the last query/get_row/get_var call
  506.      *
  507.      * @since 3.0.0
  508.      * @var string
  509.      */
  510.     public $func_call;
  511.  
  512.     /**
  513.      * Whether MySQL is used as the database engine.
  514.      *
  515.      * Set in WPDB::db_connect() to true, by default. This is used when checking
  516.      * against the required MySQL version for WordPress. Normally, a replacement
  517.      * database drop-in (db.php) will skip these checks, but setting this to true
  518.      * will force the checks to occur.
  519.      *
  520.      * @since 3.3.0
  521.      * @var bool
  522.      */
  523.     public $is_mysql = null;
  524.  
  525.     /**
  526.      * A list of incompatible SQL modes.
  527.      *
  528.      * @since 3.9.0
  529.      * @var array
  530.      */
  531.     protected $incompatible_modes = array( 'NO_ZERO_DATE', 'ONLY_FULL_GROUP_BY',
  532.         'STRICT_TRANS_TABLES', 'STRICT_ALL_TABLES', 'TRADITIONAL' );
  533.  
  534.     /**
  535.      * Whether to use mysqli over mysql.
  536.      *
  537.      * @since 3.9.0
  538.      * @var bool
  539.      */
  540.     private $use_mysqli = false;
  541.  
  542.     /**
  543.      * Whether we've managed to successfully connect at some point
  544.      *
  545.      * @since 3.9.0
  546.      * @var bool
  547.      */
  548.     private $has_connected = false;
  549.  
  550.     /**
  551.      * Connects to the database server and selects a database
  552.      *
  553.      * PHP5 style constructor for compatibility with PHP5. Does
  554.      * the actual setting up of the class properties and connection
  555.      * to the database.
  556.      *
  557.      * @link https://core.trac.wordpress.org/ticket/3354
  558.      * @since 2.0.8
  559.      *
  560.      * @global string $wp_version
  561.      *
  562.      * @param string $dbuser     MySQL database user
  563.      * @param string $dbpassword MySQL database password
  564.      * @param string $dbname     MySQL database name
  565.      * @param string $dbhost     MySQL database host
  566.      */
  567.     public function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
  568.         register_shutdown_function( array( $this, '__destruct' ) );
  569.  
  570.         if ( WP_DEBUG && WP_DEBUG_DISPLAY )
  571.             $this->show_errors();
  572.  
  573.         // Use ext/mysqli if it exists unless WP_USE_EXT_MYSQL is defined as true
  574.         if ( function_exists( 'mysqli_connect' ) ) {
  575.             $this->use_mysqli = true;
  576.  
  577.             if ( defined( 'WP_USE_EXT_MYSQL' ) ) {
  578.                 $this->use_mysqli = ! WP_USE_EXT_MYSQL;
  579.             }
  580.         }
  581.  
  582.         $this->dbuser = $dbuser;
  583.         $this->dbpassword = $dbpassword;
  584.         $this->dbname = $dbname;
  585.         $this->dbhost = $dbhost;
  586.  
  587.         // wp-config.php creation will manually connect when ready.
  588.         if ( defined( 'WP_SETUP_CONFIG' ) ) {
  589.             return;
  590.         }
  591.  
  592.         $this->db_connect();
  593.     }
  594.  
  595.     /**
  596.      * PHP5 style destructor and will run when database object is destroyed.
  597.      *
  598.      * @see wpdb::__construct()
  599.      * @since 2.0.8
  600.      * @return true
  601.      */
  602.     public function __destruct() {
  603.         return true;
  604.     }
  605.  
  606.     /**
  607.      * Makes private properties readable for backward compatibility.
  608.      *
  609.      * @since 3.5.0
  610.      *
  611.      * @param string $name The private member to get, and optionally process
  612.      * @return mixed The private member
  613.      */
  614.     public function __get( $name ) {
  615.         if ( 'col_info' === $name )
  616.             $this->load_col_info();
  617.  
  618.         return $this->$name;
  619.     }
  620.  
  621.     /**
  622.      * Makes private properties settable for backward compatibility.
  623.      *
  624.      * @since 3.5.0
  625.      *
  626.      * @param string $name  The private member to set
  627.      * @param mixed  $value The value to set
  628.      */
  629.     public function __set( $name, $value ) {
  630.         $protected_members = array(
  631.             'col_meta',
  632.             'table_charset',
  633.             'check_current_query',
  634.         );
  635.         if (  in_array( $name, $protected_members, true ) ) {
  636.             return;
  637.         }
  638.         $this->$name = $value;
  639.     }
  640.  
  641.     /**
  642.      * Makes private properties check-able for backward compatibility.
  643.      *
  644.      * @since 3.5.0
  645.      *
  646.      * @param string $name  The private member to check
  647.      *
  648.      * @return bool If the member is set or not
  649.      */
  650.     public function __isset( $name ) {
  651.         return isset( $this->$name );
  652.     }
  653.  
  654.     /**
  655.      * Makes private properties un-settable for backward compatibility.
  656.      *
  657.      * @since 3.5.0
  658.      *
  659.      * @param string $name  The private member to unset
  660.      */
  661.     public function __unset( $name ) {
  662.         unset( $this->$name );
  663.     }
  664.  
  665.     /**
  666.      * Set $this->charset and $this->collate
  667.      *
  668.      * @since 3.1.0
  669.      */
  670.     public function init_charset() {
  671.         $charset = '';
  672.         $collate = '';
  673.  
  674.         if ( function_exists('is_multisite') && is_multisite() ) {
  675.             $charset = 'utf8';
  676.             if ( defined( 'DB_COLLATE' ) && DB_COLLATE ) {
  677.                 $collate = DB_COLLATE;
  678.             } else {
  679.                 $collate = 'utf8_general_ci';
  680.             }
  681.         } elseif ( defined( 'DB_COLLATE' ) ) {
  682.             $collate = DB_COLLATE;
  683.         }
  684.  
  685.         if ( defined( 'DB_CHARSET' ) ) {
  686.             $charset = DB_CHARSET;
  687.         }
  688.  
  689.         $charset_collate = $this->determine_charset( $charset, $collate );
  690.  
  691.         $this->charset = $charset_collate['charset'];
  692.         $this->collate = $charset_collate['collate'];
  693.     }
  694.  
  695.     /**
  696.      * Determines the best charset and collation to use given a charset and collation.
  697.      *
  698.      * For example, when able, utf8mb4 should be used instead of utf8.
  699.      *
  700.      * @since 4.6.0
  701.      *
  702.      * @param string $charset The character set to check.
  703.      * @param string $collate The collation to check.
  704.      * @return array The most appropriate character set and collation to use.
  705.      */
  706.     public function determine_charset( $charset, $collate ) {
  707.         if ( ( $this->use_mysqli && ! ( $this->dbh instanceof mysqli ) ) || empty( $this->dbh ) ) {
  708.             return compact( 'charset', 'collate' );
  709.         }
  710.  
  711.         if ( 'utf8' === $charset && $this->has_cap( 'utf8mb4' ) ) {
  712.             $charset = 'utf8mb4';
  713.         }
  714.  
  715.         if ( 'utf8mb4' === $charset && ! $this->has_cap( 'utf8mb4' ) ) {
  716.             $charset = 'utf8';
  717.             $collate = str_replace( 'utf8mb4_', 'utf8_', $collate );
  718.         }
  719.  
  720.         if ( 'utf8mb4' === $charset ) {
  721.             // _general_ is outdated, so we can upgrade it to _unicode_, instead.
  722.             if ( ! $collate || 'utf8_general_ci' === $collate ) {
  723.                 $collate = 'utf8mb4_unicode_ci';
  724.             } else {
  725.                 $collate = str_replace( 'utf8_', 'utf8mb4_', $collate );
  726.             }
  727.         }
  728.  
  729.         // _unicode_520_ is a better collation, we should use that when it's available.
  730.         if ( $this->has_cap( 'utf8mb4_520' ) && 'utf8mb4_unicode_ci' === $collate ) {
  731.             $collate = 'utf8mb4_unicode_520_ci';
  732.         }
  733.  
  734.         return compact( 'charset', 'collate' );
  735.     }
  736.  
  737.     /**
  738.      * Sets the connection's character set.
  739.      *
  740.      * @since 3.1.0
  741.      *
  742.      * @param resource $dbh     The resource given by mysql_connect
  743.      * @param string   $charset Optional. The character set. Default null.
  744.      * @param string   $collate Optional. The collation. Default null.
  745.      */
  746.     public function set_charset( $dbh, $charset = null, $collate = null ) {
  747.         if ( ! isset( $charset ) )
  748.             $charset = $this->charset;
  749.         if ( ! isset( $collate ) )
  750.             $collate = $this->collate;
  751.         if ( $this->has_cap( 'collation' ) && ! empty( $charset ) ) {
  752.             $set_charset_succeeded = true;
  753.  
  754.             if ( $this->use_mysqli ) {
  755.                 if ( function_exists( 'mysqli_set_charset' ) && $this->has_cap( 'set_charset' ) ) {
  756.                     $set_charset_succeeded = mysqli_set_charset( $dbh, $charset );
  757.                 }
  758.  
  759.                 if ( $set_charset_succeeded ) {
  760.                     $query = $this->prepare( 'SET NAMES %s', $charset );
  761.                     if ( ! empty( $collate ) )
  762.                         $query .= $this->prepare( ' COLLATE %s', $collate );
  763.                     mysqli_query( $dbh, $query );
  764.                 }
  765.             } else {
  766.                 if ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset' ) ) {
  767.                     $set_charset_succeeded = mysql_set_charset( $charset, $dbh );
  768.                 }
  769.                 if ( $set_charset_succeeded ) {
  770.                     $query = $this->prepare( 'SET NAMES %s', $charset );
  771.                     if ( ! empty( $collate ) )
  772.                         $query .= $this->prepare( ' COLLATE %s', $collate );
  773.                     mysql_query( $query, $dbh );
  774.                 }
  775.             }
  776.         }
  777.     }
  778.  
  779.     /**
  780.      * Change the current SQL mode, and ensure its WordPress compatibility.
  781.      *
  782.      * If no modes are passed, it will ensure the current MySQL server
  783.      * modes are compatible.
  784.      *
  785.      * @since 3.9.0
  786.      *
  787.      * @param array $modes Optional. A list of SQL modes to set.
  788.      */
  789.     public function set_sql_mode( $modes = array() ) {
  790.         if ( empty( $modes ) ) {
  791.             if ( $this->use_mysqli ) {
  792.                 $res = mysqli_query( $this->dbh, 'SELECT @@SESSION.sql_mode' );
  793.             } else {
  794.                 $res = mysql_query( 'SELECT @@SESSION.sql_mode', $this->dbh );
  795.             }
  796.  
  797.             if ( empty( $res ) ) {
  798.                 return;
  799.             }
  800.  
  801.             if ( $this->use_mysqli ) {
  802.                 $modes_array = mysqli_fetch_array( $res );
  803.                 if ( empty( $modes_array[0] ) ) {
  804.                     return;
  805.                 }
  806.                 $modes_str = $modes_array[0];
  807.             } else {
  808.                 $modes_str = mysql_result( $res, 0 );
  809.             }
  810.  
  811.             if ( empty( $modes_str ) ) {
  812.                 return;
  813.             }
  814.  
  815.             $modes = explode( ',', $modes_str );
  816.         }
  817.  
  818.         $modes = array_change_key_case( $modes, CASE_UPPER );
  819.  
  820.         /**
  821.          * Filters the list of incompatible SQL modes to exclude.
  822.          *
  823.          * @since 3.9.0
  824.          *
  825.          * @param array $incompatible_modes An array of incompatible modes.
  826.          */
  827.         $incompatible_modes = (array) apply_filters( 'incompatible_sql_modes', $this->incompatible_modes );
  828.  
  829.         foreach ( $modes as $i => $mode ) {
  830.             if ( in_array( $mode, $incompatible_modes ) ) {
  831.                 unset( $modes[ $i ] );
  832.             }
  833.         }
  834.  
  835.         $modes_str = implode( ',', $modes );
  836.  
  837.         if ( $this->use_mysqli ) {
  838.             mysqli_query( $this->dbh, "SET SESSION sql_mode='$modes_str'" );
  839.         } else {
  840.             mysql_query( "SET SESSION sql_mode='$modes_str'", $this->dbh );
  841.         }
  842.     }
  843.  
  844.     /**
  845.      * Sets the table prefix for the WordPress tables.
  846.      *
  847.      * @since 2.5.0
  848.      *
  849.      * @param string $prefix          Alphanumeric name for the new prefix.
  850.      * @param bool   $set_table_names Optional. Whether the table names, e.g. wpdb::$posts, should be updated or not.
  851.      * @return string|WP_Error Old prefix or WP_Error on error
  852.      */
  853.     public function set_prefix( $prefix, $set_table_names = true ) {
  854.  
  855.         if ( preg_match( '|[^a-z0-9_]|i', $prefix ) )
  856.             return new WP_Error('invalid_db_prefix', 'Invalid database prefix' );
  857.  
  858.         $old_prefix = is_multisite() ? '' : $prefix;
  859.  
  860.         if ( isset( $this->base_prefix ) )
  861.             $old_prefix = $this->base_prefix;
  862.  
  863.         $this->base_prefix = $prefix;
  864.  
  865.         if ( $set_table_names ) {
  866.             foreach ( $this->tables( 'global' ) as $table => $prefixed_table )
  867.                 $this->$table = $prefixed_table;
  868.  
  869.             if ( is_multisite() && empty( $this->blogid ) )
  870.                 return $old_prefix;
  871.  
  872.             $this->prefix = $this->get_blog_prefix();
  873.  
  874.             foreach ( $this->tables( 'blog' ) as $table => $prefixed_table )
  875.                 $this->$table = $prefixed_table;
  876.  
  877.             foreach ( $this->tables( 'old' ) as $table => $prefixed_table )
  878.                 $this->$table = $prefixed_table;
  879.         }
  880.         return $old_prefix;
  881.     }
  882.  
  883.     /**
  884.      * Sets blog id.
  885.      *
  886.      * @since 3.0.0
  887.      *
  888.      * @param int $blog_id
  889.      * @param int $network_id Optional.
  890.      * @return int previous blog id
  891.      */
  892.     public function set_blog_id( $blog_id, $network_id = 0 ) {
  893.         if ( ! empty( $network_id ) ) {
  894.             $this->siteid = $network_id;
  895.         }
  896.  
  897.         $old_blog_id  = $this->blogid;
  898.         $this->blogid = $blog_id;
  899.  
  900.         $this->prefix = $this->get_blog_prefix();
  901.  
  902.         foreach ( $this->tables( 'blog' ) as $table => $prefixed_table )
  903.             $this->$table = $prefixed_table;
  904.  
  905.         foreach ( $this->tables( 'old' ) as $table => $prefixed_table )
  906.             $this->$table = $prefixed_table;
  907.  
  908.         return $old_blog_id;
  909.     }
  910.  
  911.     /**
  912.      * Gets blog prefix.
  913.      *
  914.      * @since 3.0.0
  915.      * @param int $blog_id Optional.
  916.      * @return string Blog prefix.
  917.      */
  918.     public function get_blog_prefix( $blog_id = null ) {
  919.         if ( is_multisite() ) {
  920.             if ( null === $blog_id )
  921.                 $blog_id = $this->blogid;
  922.             $blog_id = (int) $blog_id;
  923.             if ( defined( 'MULTISITE' ) && ( 0 == $blog_id || 1 == $blog_id ) )
  924.                 return $this->base_prefix;
  925.             else
  926.                 return $this->base_prefix . $blog_id . '_';
  927.         } else {
  928.             return $this->base_prefix;
  929.         }
  930.     }
  931.  
  932.     /**
  933.      * Returns an array of WordPress tables.
  934.      *
  935.      * Also allows for the CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE to
  936.      * override the WordPress users and usermeta tables that would otherwise
  937.      * be determined by the prefix.
  938.      *
  939.      * The scope argument can take one of the following:
  940.      *
  941.      * 'all' - returns 'all' and 'global' tables. No old tables are returned.
  942.      * 'blog' - returns the blog-level tables for the queried blog.
  943.      * 'global' - returns the global tables for the installation, returning multisite tables only if running multisite.
  944.      * 'ms_global' - returns the multisite global tables, regardless if current installation is multisite.
  945.      * 'old' - returns tables which are deprecated.
  946.      *
  947.      * @since 3.0.0
  948.      * @uses wpdb::$tables
  949.      * @uses wpdb::$old_tables
  950.      * @uses wpdb::$global_tables
  951.      * @uses wpdb::$ms_global_tables
  952.      *
  953.      * @param string $scope   Optional. Can be all, global, ms_global, blog, or old tables. Defaults to all.
  954.      * @param bool   $prefix  Optional. Whether to include table prefixes. Default true. If blog
  955.      *                        prefix is requested, then the custom users and usermeta tables will be mapped.
  956.      * @param int    $blog_id Optional. The blog_id to prefix. Defaults to wpdb::$blogid. Used only when prefix is requested.
  957.      * @return array Table names. When a prefix is requested, the key is the unprefixed table name.
  958.      */
  959.     public function tables( $scope = 'all', $prefix = true, $blog_id = 0 ) {
  960.         switch ( $scope ) {
  961.             case 'all' :
  962.                 $tables = array_merge( $this->global_tables, $this->tables );
  963.                 if ( is_multisite() )
  964.                     $tables = array_merge( $tables, $this->ms_global_tables );
  965.                 break;
  966.             case 'blog' :
  967.                 $tables = $this->tables;
  968.                 break;
  969.             case 'global' :
  970.                 $tables = $this->global_tables;
  971.                 if ( is_multisite() )
  972.                     $tables = array_merge( $tables, $this->ms_global_tables );
  973.                 break;
  974.             case 'ms_global' :
  975.                 $tables = $this->ms_global_tables;
  976.                 break;
  977.             case 'old' :
  978.                 $tables = $this->old_tables;
  979.                 break;
  980.             default :
  981.                 return array();
  982.         }
  983.  
  984.         if ( $prefix ) {
  985.             if ( ! $blog_id )
  986.                 $blog_id = $this->blogid;
  987.             $blog_prefix = $this->get_blog_prefix( $blog_id );
  988.             $base_prefix = $this->base_prefix;
  989.             $global_tables = array_merge( $this->global_tables, $this->ms_global_tables );
  990.             foreach ( $tables as $k => $table ) {
  991.                 if ( in_array( $table, $global_tables ) )
  992.                     $tables[ $table ] = $base_prefix . $table;
  993.                 else
  994.                     $tables[ $table ] = $blog_prefix . $table;
  995.                 unset( $tables[ $k ] );
  996.             }
  997.  
  998.             if ( isset( $tables['users'] ) && defined( 'CUSTOM_USER_TABLE' ) )
  999.                 $tables['users'] = CUSTOM_USER_TABLE;
  1000.  
  1001.             if ( isset( $tables['usermeta'] ) && defined( 'CUSTOM_USER_META_TABLE' ) )
  1002.                 $tables['usermeta'] = CUSTOM_USER_META_TABLE;
  1003.         }
  1004.  
  1005.         return $tables;
  1006.     }
  1007.  
  1008.     /**
  1009.      * Selects a database using the current database connection.
  1010.      *
  1011.      * The database name will be changed based on the current database
  1012.      * connection. On failure, the execution will bail and display an DB error.
  1013.      *
  1014.      * @since 0.71
  1015.      *
  1016.      * @param string        $db  MySQL database name
  1017.      * @param resource|null $dbh Optional link identifier.
  1018.      */
  1019.     public function select( $db, $dbh = null ) {
  1020.         if ( is_null($dbh) )
  1021.             $dbh = $this->dbh;
  1022.  
  1023.         if ( $this->use_mysqli ) {
  1024.             $success = mysqli_select_db( $dbh, $db );
  1025.         } else {
  1026.             $success = mysql_select_db( $db, $dbh );
  1027.         }
  1028.         if ( ! $success ) {
  1029.             $this->ready = false;
  1030.             if ( ! did_action( 'template_redirect' ) ) {
  1031.                 wp_load_translations_early();
  1032.  
  1033.                 $message = '<h1>' . __( 'Can’t select database' ) . "</h1>\n";
  1034.  
  1035.                 $message .= '<p>' . sprintf(
  1036.                     /* translators: %s: database name */
  1037.                     __( 'We were able to connect to the database server (which means your username and password is okay) but not able to select the %s database.' ),
  1038.                     '<code>' . htmlspecialchars( $db, ENT_QUOTES ) . '</code>'
  1039.                 ) . "</p>\n";
  1040.  
  1041.                 $message .= "<ul>\n";
  1042.                 $message .= '<li>' . __( 'Are you sure it exists?' ) . "</li>\n";
  1043.  
  1044.                 $message .= '<li>' . sprintf(
  1045.                     /* translators: 1: database user, 2: database name */
  1046.                     __( 'Does the user %1$s have permission to use the %2$s database?' ),
  1047.                     '<code>' . htmlspecialchars( $this->dbuser, ENT_QUOTES )  . '</code>',
  1048.                     '<code>' . htmlspecialchars( $db, ENT_QUOTES ) . '</code>'
  1049.                 ) . "</li>\n";
  1050.  
  1051.                 $message .= '<li>' . sprintf(
  1052.                     /* translators: %s: database name */
  1053.                     __( 'On some systems the name of your database is prefixed with your username, so it would be like <code>username_%1$s</code>. Could that be the problem?' ),
  1054.                     htmlspecialchars( $db, ENT_QUOTES )
  1055.                 ). "</li>\n";
  1056.  
  1057.                 $message .= "</ul>\n";
  1058.  
  1059.                 $message .= '<p>' . sprintf(
  1060.                     /* translators: %s: support forums URL */
  1061.                     __( 'If you don’t know how to set up a database you should <strong>contact your host</strong>. If all else fails you may find help at the <a href="%s">WordPress Support Forums</a>.' ),
  1062.                     __( 'https://wordpress.org/support/' )
  1063.                 ) . "</p>\n";
  1064.  
  1065.                 $this->bail( $message, 'db_select_fail' );
  1066.             }
  1067.         }
  1068.     }
  1069.  
  1070.     /**
  1071.      * Do not use, deprecated.
  1072.      *
  1073.      * Use esc_sql() or wpdb::prepare() instead.
  1074.      *
  1075.      * @since 2.8.0
  1076.      * @deprecated 3.6.0 Use wpdb::prepare()
  1077.      * @see wpdb::prepare
  1078.      * @see esc_sql()
  1079.      *
  1080.      * @param string $string
  1081.      * @return string
  1082.      */
  1083.     function _weak_escape( $string ) {
  1084.         if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) )
  1085.             _deprecated_function( __METHOD__, '3.6.0', 'wpdb::prepare() or esc_sql()' );
  1086.         return addslashes( $string );
  1087.     }
  1088.  
  1089.     /**
  1090.      * Real escape, using mysqli_real_escape_string() or mysql_real_escape_string()
  1091.      *
  1092.      * @see mysqli_real_escape_string()
  1093.      * @see mysql_real_escape_string()
  1094.      * @since 2.8.0
  1095.      *
  1096.      * @param  string $string to escape
  1097.      * @return string escaped
  1098.      */
  1099.     function _real_escape( $string ) {
  1100.         if ( $this->dbh ) {
  1101.             if ( $this->use_mysqli ) {
  1102.                 $escaped = mysqli_real_escape_string( $this->dbh, $string );
  1103.             } else {
  1104.                 $escaped = mysql_real_escape_string( $string, $this->dbh );
  1105.             }
  1106.         } else {
  1107.             $class = get_class( $this );
  1108.             if ( function_exists( '__' ) ) {
  1109.                 /* translators: %s: database access abstraction class, usually wpdb or a class extending wpdb */
  1110.                 _doing_it_wrong( $class, sprintf( __( '%s must set a database connection for use with escaping.' ), $class ), '3.6.0' );
  1111.             } else {
  1112.                 _doing_it_wrong( $class, sprintf( '%s must set a database connection for use with escaping.', $class ), '3.6.0' );
  1113.             }
  1114.             $escaped = addslashes( $string );
  1115.         }
  1116.  
  1117.         return $this->add_placeholder_escape( $escaped );
  1118.     }
  1119.  
  1120.     /**
  1121.      * Escape data. Works on arrays.
  1122.      *
  1123.      * @uses wpdb::_real_escape()
  1124.      * @since  2.8.0
  1125.      *
  1126.      * @param  string|array $data
  1127.      * @return string|array escaped
  1128.      */
  1129.     public function _escape( $data ) {
  1130.         if ( is_array( $data ) ) {
  1131.             foreach ( $data as $k => $v ) {
  1132.                 if ( is_array( $v ) ) {
  1133.                     $data[$k] = $this->_escape( $v );
  1134.                 } else {
  1135.                     $data[$k] = $this->_real_escape( $v );
  1136.                 }
  1137.             }
  1138.         } else {
  1139.             $data = $this->_real_escape( $data );
  1140.         }
  1141.  
  1142.         return $data;
  1143.     }
  1144.  
  1145.     /**
  1146.      * Do not use, deprecated.
  1147.      *
  1148.      * Use esc_sql() or wpdb::prepare() instead.
  1149.      *
  1150.      * @since 0.71
  1151.      * @deprecated 3.6.0 Use wpdb::prepare()
  1152.      * @see wpdb::prepare()
  1153.      * @see esc_sql()
  1154.      *
  1155.      * @param mixed $data
  1156.      * @return mixed
  1157.      */
  1158.     public function escape( $data ) {
  1159.         if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) )
  1160.             _deprecated_function( __METHOD__, '3.6.0', 'wpdb::prepare() or esc_sql()' );
  1161.         if ( is_array( $data ) ) {
  1162.             foreach ( $data as $k => $v ) {
  1163.                 if ( is_array( $v ) )
  1164.                     $data[$k] = $this->escape( $v, 'recursive' );
  1165.                 else
  1166.                     $data[$k] = $this->_weak_escape( $v, 'internal' );
  1167.             }
  1168.         } else {
  1169.             $data = $this->_weak_escape( $data, 'internal' );
  1170.         }
  1171.  
  1172.         return $data;
  1173.     }
  1174.  
  1175.     /**
  1176.      * Escapes content by reference for insertion into the database, for security
  1177.      *
  1178.      * @uses wpdb::_real_escape()
  1179.      *
  1180.      * @since 2.3.0
  1181.      *
  1182.      * @param string $string to escape
  1183.      */
  1184.     public function escape_by_ref( &$string ) {
  1185.         if ( ! is_float( $string ) )
  1186.             $string = $this->_real_escape( $string );
  1187.     }
  1188.  
  1189.     /**
  1190.      * Prepares a SQL query for safe execution. Uses sprintf()-like syntax.
  1191.      *
  1192.      * The following placeholders can be used in the query string:
  1193.      *   %d (integer)
  1194.      *   %f (float)
  1195.      *   %s (string)
  1196.      *
  1197.      * All placeholders MUST be left unquoted in the query string. A corresponding argument MUST be passed for each placeholder.
  1198.      *
  1199.      * For compatibility with old behavior, numbered or formatted string placeholders (eg, %1$s, %5s) will not have quotes
  1200.      * added by this function, so should be passed with appropriate quotes around them for your usage.
  1201.      *
  1202.      * Literal percentage signs (%) in the query string must be written as %%. Percentage wildcards (for example,
  1203.      * to use in LIKE syntax) must be passed via a substitution argument containing the complete LIKE string, these
  1204.      * cannot be inserted directly in the query string. Also see {@see esc_like()}.
  1205.      *
  1206.      * Arguments may be passed as individual arguments to the method, or as a single array containing all arguments. A combination
  1207.      * of the two is not supported.
  1208.      *
  1209.      * Examples:
  1210.      *     $wpdb->prepare( "SELECT * FROM `table` WHERE `column` = %s AND `field` = %d OR `other_field` LIKE %s", array( 'foo', 1337, '%bar' ) );
  1211.      *     $wpdb->prepare( "SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s", 'foo' );
  1212.      *
  1213.      * @link https://secure.php.net/sprintf Description of syntax.
  1214.      * @since 2.3.0
  1215.      *
  1216.      * @param string      $query    Query statement with sprintf()-like placeholders
  1217.      * @param array|mixed $args     The array of variables to substitute into the query's placeholders if being called with an array of arguments,
  1218.      *                              or the first variable to substitute into the query's placeholders if being called with individual arguments.
  1219.      * @param mixed       $args,... further variables to substitute into the query's placeholders if being called wih individual arguments.
  1220.      * @return string|void Sanitized query string, if there is a query to prepare.
  1221.      */
  1222.     public function prepare( $query, $args ) {
  1223.         if ( is_null( $query ) ) {
  1224.             return;
  1225.         }
  1226.  
  1227.         // This is not meant to be foolproof -- but it will catch obviously incorrect usage.
  1228.         if ( strpos( $query, '%' ) === false ) {
  1229.             wp_load_translations_early();
  1230.             _doing_it_wrong( 'wpdb::prepare', sprintf( __( 'The query argument of %s must have a placeholder.' ), 'wpdb::prepare()' ), '3.9.0' );
  1231.         }
  1232.  
  1233.         $args = func_get_args();
  1234.         array_shift( $args );
  1235.  
  1236.         // If args were passed as an array (as in vsprintf), move them up.
  1237.         $passed_as_array = false;
  1238.         if ( is_array( $args[0] ) && count( $args ) == 1 ) {
  1239.             $passed_as_array = true;
  1240.             $args = $args[0];
  1241.         }
  1242.  
  1243.         foreach ( $args as $arg ) {
  1244.             if ( ! is_scalar( $arg ) && ! is_null( $arg ) ) {
  1245.                 wp_load_translations_early();
  1246.                 _doing_it_wrong( 'wpdb::prepare', sprintf( __( 'Unsupported value type (%s).' ), gettype( $arg ) ), '4.8.2' );
  1247.             }
  1248.         }
  1249.  
  1250.         /*
  1251.          * Specify the formatting allowed in a placeholder. The following are allowed:
  1252.          *
  1253.          * - Sign specifier. eg, $+d
  1254.          * - Numbered placeholders. eg, %1$s
  1255.          * - Padding specifier, including custom padding characters. eg, %05s, %'#5s
  1256.          * - Alignment specifier. eg, %05-s
  1257.          * - Precision specifier. eg, %.2f
  1258.          */
  1259.         $allowed_format = '(?:[1-9][0-9]*[$])?[-+0-9]*(?: |0|\'.)?[-+0-9]*(?:\.[0-9]+)?';
  1260.  
  1261.         /*
  1262.          * If a %s placeholder already has quotes around it, removing the existing quotes and re-inserting them
  1263.          * ensures the quotes are consistent.
  1264.          *
  1265.          * For backwards compatibility, this is only applied to %s, and not to placeholders like %1$s, which are frequently
  1266.          * used in the middle of longer strings, or as table name placeholders.
  1267.          */
  1268.         $query = str_replace( "'%s'", '%s', $query ); // Strip any existing single quotes.
  1269.         $query = str_replace( '"%s"', '%s', $query ); // Strip any existing double quotes.
  1270.         $query = preg_replace( '/(?<!%)%s/', "'%s'", $query ); // Quote the strings, avoiding escaped strings like %%s.
  1271.  
  1272.         $query = preg_replace( "/(?<!%)(%($allowed_format)?f)/" , '%\\2F', $query ); // Force floats to be locale unaware.
  1273.  
  1274.         $query = preg_replace( "/%(?:%|$|(?!($allowed_format)?[sdF]))/", '%%\\1', $query ); // Escape any unescaped percents.
  1275.  
  1276.         // Count the number of valid placeholders in the query.
  1277.         $placeholders = preg_match_all( "/(^|[^%]|(%%)+)%($allowed_format)?[sdF]/", $query, $matches );
  1278.  
  1279.         if ( count( $args ) !== $placeholders ) {
  1280.             if ( 1 === $placeholders && $passed_as_array ) {
  1281.                 // If the passed query only expected one argument, but the wrong number of arguments were sent as an array, bail.
  1282.                 wp_load_translations_early();
  1283.                 _doing_it_wrong( 'wpdb::prepare', __( 'The query only expected one placeholder, but an array of multiple placeholders was sent.' ), '4.9.0' );
  1284.  
  1285.                 return;
  1286.             } else {
  1287.                 /*
  1288.                  * If we don't have the right number of placeholders, but they were passed as individual arguments,
  1289.                  * or we were expecting multiple arguments in an array, throw a warning.
  1290.                  */
  1291.                 wp_load_translations_early();
  1292.                 _doing_it_wrong( 'wpdb::prepare',
  1293.                     /* translators: 1: number of placeholders, 2: number of arguments passed */
  1294.                     sprintf( __( 'The query does not contain the correct number of placeholders (%1$d) for the number of arguments passed (%2$d).' ),
  1295.                         $placeholders,
  1296.                         count( $args ) ),
  1297.                     '4.8.3'
  1298.                 );
  1299.             }
  1300.         }
  1301.  
  1302.         array_walk( $args, array( $this, 'escape_by_ref' ) );
  1303.         $query = @vsprintf( $query, $args );
  1304.  
  1305.         return $this->add_placeholder_escape( $query );
  1306.     }
  1307.  
  1308.     /**
  1309.      * First half of escaping for LIKE special characters % and _ before preparing for MySQL.
  1310.      *
  1311.      * Use this only before wpdb::prepare() or esc_sql().  Reversing the order is very bad for security.
  1312.      *
  1313.      * Example Prepared Statement:
  1314.      *
  1315.      *     $wild = '%';
  1316.      *     $find = 'only 43% of planets';
  1317.      *     $like = $wild . $wpdb->esc_like( $find ) . $wild;
  1318.      *     $sql  = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_content LIKE %s", $like );
  1319.      *
  1320.      * Example Escape Chain:
  1321.      *
  1322.      *     $sql  = esc_sql( $wpdb->esc_like( $input ) );
  1323.      *
  1324.      * @since 4.0.0
  1325.      *
  1326.      * @param string $text The raw text to be escaped. The input typed by the user should have no
  1327.      *                     extra or deleted slashes.
  1328.      * @return string Text in the form of a LIKE phrase. The output is not SQL safe. Call $wpdb::prepare()
  1329.      *                or real_escape next.
  1330.      */
  1331.     public function esc_like( $text ) {
  1332.         return addcslashes( $text, '_%\\' );
  1333.     }
  1334.  
  1335.     /**
  1336.      * Print SQL/DB error.
  1337.      *
  1338.      * @since 0.71
  1339.      * @global array $EZSQL_ERROR Stores error information of query and error string
  1340.      *
  1341.      * @param string $str The error to display
  1342.      * @return false|void False if the showing of errors is disabled.
  1343.      */
  1344.     public function print_error( $str = '' ) {
  1345.         global $EZSQL_ERROR;
  1346.  
  1347.         if ( !$str ) {
  1348.             if ( $this->use_mysqli ) {
  1349.                 $str = mysqli_error( $this->dbh );
  1350.             } else {
  1351.                 $str = mysql_error( $this->dbh );
  1352.             }
  1353.         }
  1354.         $EZSQL_ERROR[] = array( 'query' => $this->last_query, 'error_str' => $str );
  1355.  
  1356.         if ( $this->suppress_errors )
  1357.             return false;
  1358.  
  1359.         wp_load_translations_early();
  1360.  
  1361.         if ( $caller = $this->get_caller() ) {
  1362.             /* translators: 1: Database error message, 2: SQL query, 3: Name of the calling function */
  1363.             $error_str = sprintf( __( 'WordPress database error %1$s for query %2$s made by %3$s' ), $str, $this->last_query, $caller );
  1364.         } else {
  1365.             /* translators: 1: Database error message, 2: SQL query */
  1366.             $error_str = sprintf( __( 'WordPress database error %1$s for query %2$s' ), $str, $this->last_query );
  1367.         }
  1368.  
  1369.         error_log( $error_str );
  1370.  
  1371.         // Are we showing errors?
  1372.         if ( ! $this->show_errors )
  1373.             return false;
  1374.  
  1375.         // If there is an error then take note of it
  1376.         if ( is_multisite() ) {
  1377.             $msg = sprintf(
  1378.                 "%s [%s]\n%s\n",
  1379.                 __( 'WordPress database error:' ),
  1380.                 $str,
  1381.                 $this->last_query
  1382.             );
  1383.  
  1384.             if ( defined( 'ERRORLOGFILE' ) ) {
  1385.                 error_log( $msg, 3, ERRORLOGFILE );
  1386.             }
  1387.             if ( defined( 'DIEONDBERROR' ) ) {
  1388.                 wp_die( $msg );
  1389.             }
  1390.         } else {
  1391.             $str   = htmlspecialchars( $str, ENT_QUOTES );
  1392.             $query = htmlspecialchars( $this->last_query, ENT_QUOTES );
  1393.  
  1394.             printf(
  1395.                 '<div id="error"><p class="wpdberror"><strong>%s</strong> [%s]<br /><code>%s</code></p></div>',
  1396.                 __( 'WordPress database error:' ),
  1397.                 $str,
  1398.                 $query
  1399.             );
  1400.         }
  1401.     }
  1402.  
  1403.     /**
  1404.      * Enables showing of database errors.
  1405.      *
  1406.      * This function should be used only to enable showing of errors.
  1407.      * wpdb::hide_errors() should be used instead for hiding of errors. However,
  1408.      * this function can be used to enable and disable showing of database
  1409.      * errors.
  1410.      *
  1411.      * @since 0.71
  1412.      * @see wpdb::hide_errors()
  1413.      *
  1414.      * @param bool $show Whether to show or hide errors
  1415.      * @return bool Old value for showing errors.
  1416.      */
  1417.     public function show_errors( $show = true ) {
  1418.         $errors = $this->show_errors;
  1419.         $this->show_errors = $show;
  1420.         return $errors;
  1421.     }
  1422.  
  1423.     /**
  1424.      * Disables showing of database errors.
  1425.      *
  1426.      * By default database errors are not shown.
  1427.      *
  1428.      * @since 0.71
  1429.      * @see wpdb::show_errors()
  1430.      *
  1431.      * @return bool Whether showing of errors was active
  1432.      */
  1433.     public function hide_errors() {
  1434.         $show = $this->show_errors;
  1435.         $this->show_errors = false;
  1436.         return $show;
  1437.     }
  1438.  
  1439.     /**
  1440.      * Whether to suppress database errors.
  1441.      *
  1442.      * By default database errors are suppressed, with a simple
  1443.      * call to this function they can be enabled.
  1444.      *
  1445.      * @since 2.5.0
  1446.      * @see wpdb::hide_errors()
  1447.      * @param bool $suppress Optional. New value. Defaults to true.
  1448.      * @return bool Old value
  1449.      */
  1450.     public function suppress_errors( $suppress = true ) {
  1451.         $errors = $this->suppress_errors;
  1452.         $this->suppress_errors = (bool) $suppress;
  1453.         return $errors;
  1454.     }
  1455.  
  1456.     /**
  1457.      * Kill cached query results.
  1458.      *
  1459.      * @since 0.71
  1460.      */
  1461.     public function flush() {
  1462.         $this->last_result = array();
  1463.         $this->col_info    = null;
  1464.         $this->last_query  = null;
  1465.         $this->rows_affected = $this->num_rows = 0;
  1466.         $this->last_error  = '';
  1467.  
  1468.         if ( $this->use_mysqli && $this->result instanceof mysqli_result ) {
  1469.             mysqli_free_result( $this->result );
  1470.             $this->result = null;
  1471.  
  1472.             // Sanity check before using the handle
  1473.             if ( empty( $this->dbh ) || !( $this->dbh instanceof mysqli ) ) {
  1474.                 return;
  1475.             }
  1476.  
  1477.             // Clear out any results from a multi-query
  1478.             while ( mysqli_more_results( $this->dbh ) ) {
  1479.                 mysqli_next_result( $this->dbh );
  1480.             }
  1481.         } elseif ( is_resource( $this->result ) ) {
  1482.             mysql_free_result( $this->result );
  1483.         }
  1484.     }
  1485.  
  1486.     /**
  1487.      * Connect to and select database.
  1488.      *
  1489.      * If $allow_bail is false, the lack of database connection will need
  1490.      * to be handled manually.
  1491.      *
  1492.      * @since 3.0.0
  1493.      * @since 3.9.0 $allow_bail parameter added.
  1494.      *
  1495.      * @param bool $allow_bail Optional. Allows the function to bail. Default true.
  1496.      * @return bool True with a successful connection, false on failure.
  1497.      */
  1498.     public function db_connect( $allow_bail = true ) {
  1499.         $this->is_mysql = true;
  1500.  
  1501.         /*
  1502.          * Deprecated in 3.9+ when using MySQLi. No equivalent
  1503.          * $new_link parameter exists for mysqli_* functions.
  1504.          */
  1505.         $new_link = defined( 'MYSQL_NEW_LINK' ) ? MYSQL_NEW_LINK : true;
  1506.         $client_flags = defined( 'MYSQL_CLIENT_FLAGS' ) ? MYSQL_CLIENT_FLAGS : 0;
  1507.  
  1508.         if ( $this->use_mysqli ) {
  1509.             $this->dbh = mysqli_init();
  1510.  
  1511.             $host    = $this->dbhost;
  1512.             $port    = null;
  1513.             $socket  = null;
  1514.             $is_ipv6 = false;
  1515.  
  1516.             if ( $host_data = $this->parse_db_host( $this->dbhost ) ) {
  1517.                 list( $host, $port, $socket, $is_ipv6 ) = $host_data;
  1518.             }
  1519.  
  1520.             /*
  1521.              * If using the `mysqlnd` library, the IPv6 address needs to be
  1522.              * enclosed in square brackets, whereas it doesn't while using the
  1523.              * `libmysqlclient` library.
  1524.              * @see https://bugs.php.net/bug.php?id=67563
  1525.              */
  1526.             if ( $is_ipv6 && extension_loaded( 'mysqlnd' ) ) {
  1527.                 $host = "[$host]";
  1528.             }
  1529.  
  1530.             if ( WP_DEBUG ) {
  1531.                 mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags );
  1532.             } else {
  1533.                 @mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags );
  1534.             }
  1535.  
  1536.             if ( $this->dbh->connect_errno ) {
  1537.                 $this->dbh = null;
  1538.  
  1539.                 /*
  1540.                  * It's possible ext/mysqli is misconfigured. Fall back to ext/mysql if:
  1541.                   *  - We haven't previously connected, and
  1542.                   *  - WP_USE_EXT_MYSQL isn't set to false, and
  1543.                   *  - ext/mysql is loaded.
  1544.                   */
  1545.                 $attempt_fallback = true;
  1546.  
  1547.                 if ( $this->has_connected ) {
  1548.                     $attempt_fallback = false;
  1549.                 } elseif ( defined( 'WP_USE_EXT_MYSQL' ) && ! WP_USE_EXT_MYSQL ) {
  1550.                     $attempt_fallback = false;
  1551.                 } elseif ( ! function_exists( 'mysql_connect' ) ) {
  1552.                     $attempt_fallback = false;
  1553.                 }
  1554.  
  1555.                 if ( $attempt_fallback ) {
  1556.                     $this->use_mysqli = false;
  1557.                     return $this->db_connect( $allow_bail );
  1558.                 }
  1559.             }
  1560.         } else {
  1561.             if ( WP_DEBUG ) {
  1562.                 $this->dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
  1563.             } else {
  1564.                 $this->dbh = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
  1565.             }
  1566.         }
  1567.  
  1568.         if ( ! $this->dbh && $allow_bail ) {
  1569.             wp_load_translations_early();
  1570.  
  1571.             // Load custom DB error template, if present.
  1572.             if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
  1573.                 require_once( WP_CONTENT_DIR . '/db-error.php' );
  1574.                 die();
  1575.             }
  1576.  
  1577.             $message = '<h1>' . __( 'Error establishing a database connection' ) . "</h1>\n";
  1578.  
  1579.             $message .= '<p>' . sprintf(
  1580.                 /* translators: 1: wp-config.php. 2: database host */
  1581.                 __( 'This either means that the username and password information in your %1$s file is incorrect or we can’t contact the database server at %2$s. This could mean your host’s database server is down.' ),
  1582.                 '<code>wp-config.php</code>',
  1583.                 '<code>' . htmlspecialchars( $this->dbhost, ENT_QUOTES ) . '</code>'
  1584.             ) . "</p>\n";
  1585.  
  1586.             $message .= "<ul>\n";
  1587.             $message .= '<li>' . __( 'Are you sure you have the correct username and password?' ) . "</li>\n";
  1588.             $message .= '<li>' . __( 'Are you sure that you have typed the correct hostname?' ) . "</li>\n";
  1589.             $message .= '<li>' . __( 'Are you sure that the database server is running?' ) . "</li>\n";
  1590.             $message .= "</ul>\n";
  1591.  
  1592.             $message .= '<p>' . sprintf(
  1593.                 /* translators: %s: support forums URL */
  1594.                 __( 'If you’re unsure what these terms mean you should probably contact your host. If you still need help you can always visit the <a href="%s">WordPress Support Forums</a>.' ),
  1595.                 __( 'https://wordpress.org/support/' )
  1596.             ) . "</p>\n";
  1597.  
  1598.             $this->bail( $message, 'db_connect_fail' );
  1599.  
  1600.             return false;
  1601.         } elseif ( $this->dbh ) {
  1602.             if ( ! $this->has_connected ) {
  1603.                 $this->init_charset();
  1604.             }
  1605.  
  1606.             $this->has_connected = true;
  1607.  
  1608.             $this->set_charset( $this->dbh );
  1609.  
  1610.             $this->ready = true;
  1611.             $this->set_sql_mode();
  1612.             $this->select( $this->dbname, $this->dbh );
  1613.  
  1614.             return true;
  1615.         }
  1616.  
  1617.         return false;
  1618.     }
  1619.  
  1620.     /**
  1621.      * Parse the DB_HOST setting to interpret it for mysqli_real_connect.
  1622.      *
  1623.      * mysqli_real_connect doesn't support the host param including a port or
  1624.      * socket like mysql_connect does. This duplicates how mysql_connect detects
  1625.      * a port and/or socket file.
  1626.      *
  1627.      * @since 4.9.0
  1628.      *
  1629.      * @param string $host The DB_HOST setting to parse.
  1630.      * @return array|bool Array containing the host, the port, the socket and whether
  1631.      *                    it is an IPv6 address, in that order. If $host couldn't be parsed,
  1632.      *                    returns false.
  1633.      */
  1634.     public function parse_db_host( $host ) {
  1635.         $port    = null;
  1636.         $socket  = null;
  1637.         $is_ipv6 = false;
  1638.  
  1639.         // First peel off the socket parameter from the right, if it exists.
  1640.         $socket_pos = strpos( $host, ':/' );
  1641.         if ( $socket_pos !== false ) {
  1642.             $socket = substr( $host, $socket_pos + 1 );
  1643.             $host = substr( $host, 0, $socket_pos );
  1644.         }
  1645.  
  1646.         // We need to check for an IPv6 address first.
  1647.         // An IPv6 address will always contain at least two colons.
  1648.         if ( substr_count( $host, ':' ) > 1 ) {
  1649.             $pattern = '#^(?:\[)?(?P<host>[0-9a-fA-F:]+)(?:\]:(?P<port>[\d]+))?#';
  1650.             $is_ipv6 = true;
  1651.         } else {
  1652.             // We seem to be dealing with an IPv4 address.
  1653.             $pattern = '#^(?P<host>[^:/]*)(?::(?P<port>[\d]+))?#';
  1654.         }
  1655.  
  1656.         $matches = array();
  1657.         $result = preg_match( $pattern, $host, $matches );
  1658.  
  1659.         if ( 1 !== $result ) {
  1660.             // Couldn't parse the address, bail.
  1661.             return false;
  1662.         }
  1663.  
  1664.         $host = '';
  1665.         foreach ( array( 'host', 'port' ) as $component ) {
  1666.             if ( ! empty( $matches[ $component ] ) ) {
  1667.                 $$component = $matches[ $component ];
  1668.             }
  1669.         }
  1670.  
  1671.         return array( $host, $port, $socket, $is_ipv6 );
  1672.     }
  1673.  
  1674.     /**
  1675.      * Checks that the connection to the database is still up. If not, try to reconnect.
  1676.      *
  1677.      * If this function is unable to reconnect, it will forcibly die, or if after the
  1678.      * the {@see 'template_redirect'} hook has been fired, return false instead.
  1679.      *
  1680.      * If $allow_bail is false, the lack of database connection will need
  1681.      * to be handled manually.
  1682.      *
  1683.      * @since 3.9.0
  1684.      *
  1685.      * @param bool $allow_bail Optional. Allows the function to bail. Default true.
  1686.      * @return bool|void True if the connection is up.
  1687.      */
  1688.     public function check_connection( $allow_bail = true ) {
  1689.         if ( $this->use_mysqli ) {
  1690.             if ( ! empty( $this->dbh ) && mysqli_ping( $this->dbh ) ) {
  1691.                 return true;
  1692.             }
  1693.         } else {
  1694.             if ( ! empty( $this->dbh ) && mysql_ping( $this->dbh ) ) {
  1695.                 return true;
  1696.             }
  1697.         }
  1698.  
  1699.         $error_reporting = false;
  1700.  
  1701.         // Disable warnings, as we don't want to see a multitude of "unable to connect" messages
  1702.         if ( WP_DEBUG ) {
  1703.             $error_reporting = error_reporting();
  1704.             error_reporting( $error_reporting & ~E_WARNING );
  1705.         }
  1706.  
  1707.         for ( $tries = 1; $tries <= $this->reconnect_retries; $tries++ ) {
  1708.             // On the last try, re-enable warnings. We want to see a single instance of the
  1709.             // "unable to connect" message on the bail() screen, if it appears.
  1710.             if ( $this->reconnect_retries === $tries && WP_DEBUG ) {
  1711.                 error_reporting( $error_reporting );
  1712.             }
  1713.  
  1714.             if ( $this->db_connect( false ) ) {
  1715.                 if ( $error_reporting ) {
  1716.                     error_reporting( $error_reporting );
  1717.                 }
  1718.  
  1719.                 return true;
  1720.             }
  1721.  
  1722.             sleep( 1 );
  1723.         }
  1724.  
  1725.         // If template_redirect has already happened, it's too late for wp_die()/dead_db().
  1726.         // Let's just return and hope for the best.
  1727.         if ( did_action( 'template_redirect' ) ) {
  1728.             return false;
  1729.         }
  1730.  
  1731.         if ( ! $allow_bail ) {
  1732.             return false;
  1733.         }
  1734.  
  1735.         wp_load_translations_early();
  1736.  
  1737.         $message = '<h1>' . __( 'Error reconnecting to the database' ) . "</h1>\n";
  1738.  
  1739.         $message .= '<p>' . sprintf(
  1740.             /* translators: %s: database host */
  1741.             __( 'This means that we lost contact with the database server at %s. This could mean your host’s database server is down.' ),
  1742.             '<code>' . htmlspecialchars( $this->dbhost, ENT_QUOTES ) . '</code>'
  1743.         ) . "</p>\n";
  1744.  
  1745.         $message .= "<ul>\n";
  1746.         $message .= '<li>' . __( 'Are you sure that the database server is running?' ) . "</li>\n";
  1747.         $message .= '<li>' . __( 'Are you sure that the database server is not under particularly heavy load?' ) . "</li>\n";
  1748.         $message .= "</ul>\n";
  1749.  
  1750.         $message .= '<p>' . sprintf(
  1751.             /* translators: %s: support forums URL */
  1752.             __( 'If you’re unsure what these terms mean you should probably contact your host. If you still need help you can always visit the <a href="%s">WordPress Support Forums</a>.' ),
  1753.             __( 'https://wordpress.org/support/' )
  1754.         ) . "</p>\n";
  1755.  
  1756.         // We weren't able to reconnect, so we better bail.
  1757.         $this->bail( $message, 'db_connect_fail' );
  1758.  
  1759.         // Call dead_db() if bail didn't die, because this database is no more. It has ceased to be (at least temporarily).
  1760.         dead_db();
  1761.     }
  1762.  
  1763.     /**
  1764.      * Perform a MySQL database query, using current database connection.
  1765.      *
  1766.      * More information can be found on the codex page.
  1767.      *
  1768.      * @since 0.71
  1769.      *
  1770.      * @param string $query Database query
  1771.      * @return int|false Number of rows affected/selected or false on error
  1772.      */
  1773.     public function query( $query ) {
  1774.         if ( ! $this->ready ) {
  1775.             $this->check_current_query = true;
  1776.             return false;
  1777.         }
  1778.  
  1779.         /**
  1780.          * Filters the database query.
  1781.          *
  1782.          * Some queries are made before the plugins have been loaded,
  1783.          * and thus cannot be filtered with this method.
  1784.          *
  1785.          * @since 2.1.0
  1786.          *
  1787.          * @param string $query Database query.
  1788.          */
  1789.         $query = apply_filters( 'query', $query );
  1790.  
  1791.         $this->flush();
  1792.  
  1793.         // Log how the function was called
  1794.         $this->func_call = "\$db->query(\"$query\")";
  1795.  
  1796.         // If we're writing to the database, make sure the query will write safely.
  1797.         if ( $this->check_current_query && ! $this->check_ascii( $query ) ) {
  1798.             $stripped_query = $this->strip_invalid_text_from_query( $query );
  1799.             // strip_invalid_text_from_query() can perform queries, so we need
  1800.             // to flush again, just to make sure everything is clear.
  1801.             $this->flush();
  1802.             if ( $stripped_query !== $query ) {
  1803.                 $this->insert_id = 0;
  1804.                 return false;
  1805.             }
  1806.         }
  1807.  
  1808.         $this->check_current_query = true;
  1809.  
  1810.         // Keep track of the last query for debug.
  1811.         $this->last_query = $query;
  1812.  
  1813.         $this->_do_query( $query );
  1814.  
  1815.         // MySQL server has gone away, try to reconnect.
  1816.         $mysql_errno = 0;
  1817.         if ( ! empty( $this->dbh ) ) {
  1818.             if ( $this->use_mysqli ) {
  1819.                 if ( $this->dbh instanceof mysqli ) {
  1820.                     $mysql_errno = mysqli_errno( $this->dbh );
  1821.                 } else {
  1822.                     // $dbh is defined, but isn't a real connection.
  1823.                     // Something has gone horribly wrong, let's try a reconnect.
  1824.                     $mysql_errno = 2006;
  1825.                 }
  1826.             } else {
  1827.                 if ( is_resource( $this->dbh ) ) {
  1828.                     $mysql_errno = mysql_errno( $this->dbh );
  1829.                 } else {
  1830.                     $mysql_errno = 2006;
  1831.                 }
  1832.             }
  1833.         }
  1834.  
  1835.         if ( empty( $this->dbh ) || 2006 == $mysql_errno ) {
  1836.             if ( $this->check_connection() ) {
  1837.                 $this->_do_query( $query );
  1838.             } else {
  1839.                 $this->insert_id = 0;
  1840.                 return false;
  1841.             }
  1842.         }
  1843.  
  1844.         // If there is an error then take note of it.
  1845.         if ( $this->use_mysqli ) {
  1846.             if ( $this->dbh instanceof mysqli ) {
  1847.                 $this->last_error = mysqli_error( $this->dbh );
  1848.             } else {
  1849.                 $this->last_error = __( 'Unable to retrieve the error message from MySQL' );
  1850.             }
  1851.         } else {
  1852.             if ( is_resource( $this->dbh ) ) {
  1853.                 $this->last_error = mysql_error( $this->dbh );
  1854.             } else {
  1855.                 $this->last_error = __( 'Unable to retrieve the error message from MySQL' );
  1856.             }
  1857.         }
  1858.  
  1859.         if ( $this->last_error ) {
  1860.             // Clear insert_id on a subsequent failed insert.
  1861.             if ( $this->insert_id && preg_match( '/^\s*(insert|replace)\s/i', $query ) )
  1862.                 $this->insert_id = 0;
  1863.  
  1864.             $this->print_error();
  1865.             return false;
  1866.         }
  1867.  
  1868.         if ( preg_match( '/^\s*(create|alter|truncate|drop)\s/i', $query ) ) {
  1869.             $return_val = $this->result;
  1870.         } elseif ( preg_match( '/^\s*(insert|delete|update|replace)\s/i', $query ) ) {
  1871.             if ( $this->use_mysqli ) {
  1872.                 $this->rows_affected = mysqli_affected_rows( $this->dbh );
  1873.             } else {
  1874.                 $this->rows_affected = mysql_affected_rows( $this->dbh );
  1875.             }
  1876.             // Take note of the insert_id
  1877.             if ( preg_match( '/^\s*(insert|replace)\s/i', $query ) ) {
  1878.                 if ( $this->use_mysqli ) {
  1879.                     $this->insert_id = mysqli_insert_id( $this->dbh );
  1880.                 } else {
  1881.                     $this->insert_id = mysql_insert_id( $this->dbh );
  1882.                 }
  1883.             }
  1884.             // Return number of rows affected
  1885.             $return_val = $this->rows_affected;
  1886.         } else {
  1887.             $num_rows = 0;
  1888.             if ( $this->use_mysqli && $this->result instanceof mysqli_result ) {
  1889.                 while ( $row = mysqli_fetch_object( $this->result ) ) {
  1890.                     $this->last_result[$num_rows] = $row;
  1891.                     $num_rows++;
  1892.                 }
  1893.             } elseif ( is_resource( $this->result ) ) {
  1894.                 while ( $row = mysql_fetch_object( $this->result ) ) {
  1895.                     $this->last_result[$num_rows] = $row;
  1896.                     $num_rows++;
  1897.                 }
  1898.             }
  1899.  
  1900.             // Log number of rows the query returned
  1901.             // and return number of rows selected
  1902.             $this->num_rows = $num_rows;
  1903.             $return_val     = $num_rows;
  1904.         }
  1905.  
  1906.         return $return_val;
  1907.     }
  1908.  
  1909.     /**
  1910.      * Internal function to perform the mysql_query() call.
  1911.      *
  1912.      * @since 3.9.0
  1913.      *
  1914.      * @see wpdb::query()
  1915.      *
  1916.      * @param string $query The query to run.
  1917.      */
  1918.     private function _do_query( $query ) {
  1919.         if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
  1920.             $this->timer_start();
  1921.         }
  1922.  
  1923.         if ( ! empty( $this->dbh ) && $this->use_mysqli ) {
  1924.             $this->result = mysqli_query( $this->dbh, $query );
  1925.         } elseif ( ! empty( $this->dbh ) ) {
  1926.             $this->result = mysql_query( $query, $this->dbh );
  1927.         }
  1928.         $this->num_queries++;
  1929.  
  1930.         if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
  1931.             $this->queries[] = array( $query, $this->timer_stop(), $this->get_caller() );
  1932.         }
  1933.     }
  1934.  
  1935.     /**
  1936.      * Generates and returns a placeholder escape string for use in queries returned by ::prepare().
  1937.      *
  1938.      * @since 4.8.3
  1939.      *
  1940.      * @return string String to escape placeholders.
  1941.      */
  1942.     public function placeholder_escape() {
  1943.         static $placeholder;
  1944.  
  1945.         if ( ! $placeholder ) {
  1946.             // If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
  1947.             $algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
  1948.             // Old WP installs may not have AUTH_SALT defined.
  1949.             $salt = defined( 'AUTH_SALT' ) && AUTH_SALT ? AUTH_SALT : (string) rand();
  1950.  
  1951.             $placeholder = '{' . hash_hmac( $algo, uniqid( $salt, true ), $salt ) . '}';
  1952.         }
  1953.  
  1954.         /*
  1955.          * Add the filter to remove the placeholder escaper. Uses priority 0, so that anything
  1956.          * else attached to this filter will recieve the query with the placeholder string removed.
  1957.          */
  1958.         if ( ! has_filter( 'query', array( $this, 'remove_placeholder_escape' ) ) ) {
  1959.             add_filter( 'query', array( $this, 'remove_placeholder_escape' ), 0 );
  1960.         }
  1961.  
  1962.         return $placeholder;
  1963.     }
  1964.  
  1965.     /**
  1966.      * Adds a placeholder escape string, to escape anything that resembles a printf() placeholder.
  1967.      *
  1968.      * @since 4.8.3
  1969.      *
  1970.      * @param string $query The query to escape.
  1971.      * @return string The query with the placeholder escape string inserted where necessary.
  1972.      */
  1973.     public function add_placeholder_escape( $query ) {
  1974.         /*
  1975.          * To prevent returning anything that even vaguely resembles a placeholder,
  1976.          * we clobber every % we can find.
  1977.          */
  1978.         return str_replace( '%', $this->placeholder_escape(), $query );
  1979.     }
  1980.  
  1981.     /**
  1982.      * Removes the placeholder escape strings from a query.
  1983.      *
  1984.      * @since 4.8.3
  1985.      *
  1986.      * @param string $query The query from which the placeholder will be removed.
  1987.      * @return string The query with the placeholder removed.
  1988.      */
  1989.     public function remove_placeholder_escape( $query ) {
  1990.         return str_replace( $this->placeholder_escape(), '%', $query );
  1991.     }
  1992.  
  1993.     /**
  1994.      * Insert a row into a table.
  1995.      *
  1996.      *     wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
  1997.      *     wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
  1998.      *
  1999.      * @since 2.5.0
  2000.      * @see wpdb::prepare()
  2001.      * @see wpdb::$field_types
  2002.      * @see wp_set_wpdb_vars()
  2003.      *
  2004.      * @param string       $table  Table name
  2005.      * @param array        $data   Data to insert (in column => value pairs).
  2006.      *                             Both $data columns and $data values should be "raw" (neither should be SQL escaped).
  2007.      *                             Sending a null value will cause the column to be set to NULL - the corresponding format is ignored in this case.
  2008.      * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data.
  2009.      *                             If string, that format will be used for all of the values in $data.
  2010.      *                             A format is one of '%d', '%f', '%s' (integer, float, string).
  2011.      *                             If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
  2012.      * @return int|false The number of rows inserted, or false on error.
  2013.      */
  2014.     public function insert( $table, $data, $format = null ) {
  2015.         return $this->_insert_replace_helper( $table, $data, $format, 'INSERT' );
  2016.     }
  2017.  
  2018.     /**
  2019.      * Replace a row into a table.
  2020.      *
  2021.      *     wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
  2022.      *     wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
  2023.      *
  2024.      * @since 3.0.0
  2025.      * @see wpdb::prepare()
  2026.      * @see wpdb::$field_types
  2027.      * @see wp_set_wpdb_vars()
  2028.      *
  2029.      * @param string       $table  Table name
  2030.      * @param array        $data   Data to insert (in column => value pairs).
  2031.      *                             Both $data columns and $data values should be "raw" (neither should be SQL escaped).
  2032.      *                             Sending a null value will cause the column to be set to NULL - the corresponding format is ignored in this case.
  2033.      * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data.
  2034.      *                             If string, that format will be used for all of the values in $data.
  2035.      *                             A format is one of '%d', '%f', '%s' (integer, float, string).
  2036.      *                             If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
  2037.      * @return int|false The number of rows affected, or false on error.
  2038.      */
  2039.     public function replace( $table, $data, $format = null ) {
  2040.         return $this->_insert_replace_helper( $table, $data, $format, 'REPLACE' );
  2041.     }
  2042.  
  2043.     /**
  2044.      * Helper function for insert and replace.
  2045.      *
  2046.      * Runs an insert or replace query based on $type argument.
  2047.      *
  2048.      * @since 3.0.0
  2049.      * @see wpdb::prepare()
  2050.      * @see wpdb::$field_types
  2051.      * @see wp_set_wpdb_vars()
  2052.      *
  2053.      * @param string       $table  Table name
  2054.      * @param array        $data   Data to insert (in column => value pairs).
  2055.      *                             Both $data columns and $data values should be "raw" (neither should be SQL escaped).
  2056.      *                             Sending a null value will cause the column to be set to NULL - the corresponding format is ignored in this case.
  2057.      * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data.
  2058.      *                             If string, that format will be used for all of the values in $data.
  2059.      *                             A format is one of '%d', '%f', '%s' (integer, float, string).
  2060.      *                             If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
  2061.      * @param string $type         Optional. What type of operation is this? INSERT or REPLACE. Defaults to INSERT.
  2062.      * @return int|false The number of rows affected, or false on error.
  2063.      */
  2064.     function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) {
  2065.         $this->insert_id = 0;
  2066.  
  2067.         if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) ) {
  2068.             return false;
  2069.         }
  2070.  
  2071.         $data = $this->process_fields( $table, $data, $format );
  2072.         if ( false === $data ) {
  2073.             return false;
  2074.         }
  2075.  
  2076.         $formats = $values = array();
  2077.         foreach ( $data as $value ) {
  2078.             if ( is_null( $value['value'] ) ) {
  2079.                 $formats[] = 'NULL';
  2080.                 continue;
  2081.             }
  2082.  
  2083.             $formats[] = $value['format'];
  2084.             $values[]  = $value['value'];
  2085.         }
  2086.  
  2087.         $fields  = '`' . implode( '`, `', array_keys( $data ) ) . '`';
  2088.         $formats = implode( ', ', $formats );
  2089.  
  2090.         $sql = "$type INTO `$table` ($fields) VALUES ($formats)";
  2091.  
  2092.         $this->check_current_query = false;
  2093.         return $this->query( $this->prepare( $sql, $values ) );
  2094.     }
  2095.  
  2096.     /**
  2097.      * Update a row in the table
  2098.      *
  2099.      *     wpdb::update( 'table', array( 'column' => 'foo', 'field' => 'bar' ), array( 'ID' => 1 ) )
  2100.      *     wpdb::update( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( 'ID' => 1 ), array( '%s', '%d' ), array( '%d' ) )
  2101.      *
  2102.      * @since 2.5.0
  2103.      * @see wpdb::prepare()
  2104.      * @see wpdb::$field_types
  2105.      * @see wp_set_wpdb_vars()
  2106.      *
  2107.      * @param string       $table        Table name
  2108.      * @param array        $data         Data to update (in column => value pairs).
  2109.      *                                   Both $data columns and $data values should be "raw" (neither should be SQL escaped).
  2110.      *                                   Sending a null value will cause the column to be set to NULL - the corresponding
  2111.      *                                   format is ignored in this case.
  2112.      * @param array        $where        A named array of WHERE clauses (in column => value pairs).
  2113.      *                                   Multiple clauses will be joined with ANDs.
  2114.      *                                   Both $where columns and $where values should be "raw".
  2115.      *                                   Sending a null value will create an IS NULL comparison - the corresponding format will be ignored in this case.
  2116.      * @param array|string $format       Optional. An array of formats to be mapped to each of the values in $data.
  2117.      *                                   If string, that format will be used for all of the values in $data.
  2118.      *                                   A format is one of '%d', '%f', '%s' (integer, float, string).
  2119.      *                                   If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.
  2120.      * @param array|string $where_format Optional. An array of formats to be mapped to each of the values in $where.
  2121.      *                                   If string, that format will be used for all of the items in $where.
  2122.      *                                   A format is one of '%d', '%f', '%s' (integer, float, string).
  2123.      *                                   If omitted, all values in $where will be treated as strings.
  2124.      * @return int|false The number of rows updated, or false on error.
  2125.      */
  2126.     public function update( $table, $data, $where, $format = null, $where_format = null ) {
  2127.         if ( ! is_array( $data ) || ! is_array( $where ) ) {
  2128.             return false;
  2129.         }
  2130.  
  2131.         $data = $this->process_fields( $table, $data, $format );
  2132.         if ( false === $data ) {
  2133.             return false;
  2134.         }
  2135.         $where = $this->process_fields( $table, $where, $where_format );
  2136.         if ( false === $where ) {
  2137.             return false;
  2138.         }
  2139.  
  2140.         $fields = $conditions = $values = array();
  2141.         foreach ( $data as $field => $value ) {
  2142.             if ( is_null( $value['value'] ) ) {
  2143.                 $fields[] = "`$field` = NULL";
  2144.                 continue;
  2145.             }
  2146.  
  2147.             $fields[] = "`$field` = " . $value['format'];
  2148.             $values[] = $value['value'];
  2149.         }
  2150.         foreach ( $where as $field => $value ) {
  2151.             if ( is_null( $value['value'] ) ) {
  2152.                 $conditions[] = "`$field` IS NULL";
  2153.                 continue;
  2154.             }
  2155.  
  2156.             $conditions[] = "`$field` = " . $value['format'];
  2157.             $values[] = $value['value'];
  2158.         }
  2159.  
  2160.         $fields = implode( ', ', $fields );
  2161.         $conditions = implode( ' AND ', $conditions );
  2162.  
  2163.         $sql = "UPDATE `$table` SET $fields WHERE $conditions";
  2164.  
  2165.         $this->check_current_query = false;
  2166.         return $this->query( $this->prepare( $sql, $values ) );
  2167.     }
  2168.  
  2169.     /**
  2170.      * Delete a row in the table
  2171.      *
  2172.      *     wpdb::delete( 'table', array( 'ID' => 1 ) )
  2173.      *     wpdb::delete( 'table', array( 'ID' => 1 ), array( '%d' ) )
  2174.      *
  2175.      * @since 3.4.0
  2176.      * @see wpdb::prepare()
  2177.      * @see wpdb::$field_types
  2178.      * @see wp_set_wpdb_vars()
  2179.      *
  2180.      * @param string       $table        Table name
  2181.      * @param array        $where        A named array of WHERE clauses (in column => value pairs).
  2182.      *                                   Multiple clauses will be joined with ANDs.
  2183.      *                                   Both $where columns and $where values should be "raw".
  2184.      *                                   Sending a null value will create an IS NULL comparison - the corresponding format will be ignored in this case.
  2185.      * @param array|string $where_format Optional. An array of formats to be mapped to each of the values in $where.
  2186.      *                                   If string, that format will be used for all of the items in $where.
  2187.      *                                   A format is one of '%d', '%f', '%s' (integer, float, string).
  2188.      *                                   If omitted, all values in $where will be treated as strings unless otherwise specified in wpdb::$field_types.
  2189.      * @return int|false The number of rows updated, or false on error.
  2190.      */
  2191.     public function delete( $table, $where, $where_format = null ) {
  2192.         if ( ! is_array( $where ) ) {
  2193.             return false;
  2194.         }
  2195.  
  2196.         $where = $this->process_fields( $table, $where, $where_format );
  2197.         if ( false === $where ) {
  2198.             return false;
  2199.         }
  2200.  
  2201.         $conditions = $values = array();
  2202.         foreach ( $where as $field => $value ) {
  2203.             if ( is_null( $value['value'] ) ) {
  2204.                 $conditions[] = "`$field` IS NULL";
  2205.                 continue;
  2206.             }
  2207.  
  2208.             $conditions[] = "`$field` = " . $value['format'];
  2209.             $values[] = $value['value'];
  2210.         }
  2211.  
  2212.         $conditions = implode( ' AND ', $conditions );
  2213.  
  2214.         $sql = "DELETE FROM `$table` WHERE $conditions";
  2215.  
  2216.         $this->check_current_query = false;
  2217.         return $this->query( $this->prepare( $sql, $values ) );
  2218.     }
  2219.  
  2220.     /**
  2221.      * Processes arrays of field/value pairs and field formats.
  2222.      *
  2223.      * This is a helper method for wpdb's CRUD methods, which take field/value
  2224.      * pairs for inserts, updates, and where clauses. This method first pairs
  2225.      * each value with a format. Then it determines the charset of that field,
  2226.      * using that to determine if any invalid text would be stripped. If text is
  2227.      * stripped, then field processing is rejected and the query fails.
  2228.      *
  2229.      * @since 4.2.0
  2230.      *
  2231.      * @param string $table  Table name.
  2232.      * @param array  $data   Field/value pair.
  2233.      * @param mixed  $format Format for each field.
  2234.      * @return array|false Returns an array of fields that contain paired values
  2235.      *                    and formats. Returns false for invalid values.
  2236.      */
  2237.     protected function process_fields( $table, $data, $format ) {
  2238.         $data = $this->process_field_formats( $data, $format );
  2239.         if ( false === $data ) {
  2240.             return false;
  2241.         }
  2242.  
  2243.         $data = $this->process_field_charsets( $data, $table );
  2244.         if ( false === $data ) {
  2245.             return false;
  2246.         }
  2247.  
  2248.         $data = $this->process_field_lengths( $data, $table );
  2249.         if ( false === $data ) {
  2250.             return false;
  2251.         }
  2252.  
  2253.         $converted_data = $this->strip_invalid_text( $data );
  2254.  
  2255.         if ( $data !== $converted_data ) {
  2256.             return false;
  2257.         }
  2258.  
  2259.         return $data;
  2260.     }
  2261.  
  2262.     /**
  2263.      * Prepares arrays of value/format pairs as passed to wpdb CRUD methods.
  2264.      *
  2265.      * @since 4.2.0
  2266.      *
  2267.      * @param array $data   Array of fields to values.
  2268.      * @param mixed $format Formats to be mapped to the values in $data.
  2269.      * @return array Array, keyed by field names with values being an array
  2270.      *               of 'value' and 'format' keys.
  2271.      */
  2272.     protected function process_field_formats( $data, $format ) {
  2273.         $formats = $original_formats = (array) $format;
  2274.  
  2275.         foreach ( $data as $field => $value ) {
  2276.             $value = array(
  2277.                 'value'  => $value,
  2278.                 'format' => '%s',
  2279.             );
  2280.  
  2281.             if ( ! empty( $format ) ) {
  2282.                 $value['format'] = array_shift( $formats );
  2283.                 if ( ! $value['format'] ) {
  2284.                     $value['format'] = reset( $original_formats );
  2285.                 }
  2286.             } elseif ( isset( $this->field_types[ $field ] ) ) {
  2287.                 $value['format'] = $this->field_types[ $field ];
  2288.             }
  2289.  
  2290.             $data[ $field ] = $value;
  2291.         }
  2292.  
  2293.         return $data;
  2294.     }
  2295.  
  2296.     /**
  2297.      * Adds field charsets to field/value/format arrays generated by
  2298.      * the wpdb::process_field_formats() method.
  2299.      *
  2300.      * @since 4.2.0
  2301.      *
  2302.      * @param array  $data  As it comes from the wpdb::process_field_formats() method.
  2303.      * @param string $table Table name.
  2304.      * @return array|false The same array as $data with additional 'charset' keys.
  2305.      */
  2306.     protected function process_field_charsets( $data, $table ) {
  2307.         foreach ( $data as $field => $value ) {
  2308.             if ( '%d' === $value['format'] || '%f' === $value['format'] ) {
  2309.                 /*
  2310.                  * We can skip this field if we know it isn't a string.
  2311.                  * This checks %d/%f versus ! %s because its sprintf() could take more.
  2312.                  */
  2313.                 $value['charset'] = false;
  2314.             } else {
  2315.                 $value['charset'] = $this->get_col_charset( $table, $field );
  2316.                 if ( is_wp_error( $value['charset'] ) ) {
  2317.                     return false;
  2318.                 }
  2319.             }
  2320.  
  2321.             $data[ $field ] = $value;
  2322.         }
  2323.  
  2324.         return $data;
  2325.     }
  2326.  
  2327.     /**
  2328.      * For string fields, record the maximum string length that field can safely save.
  2329.      *
  2330.      * @since 4.2.1
  2331.      *
  2332.      * @param array  $data  As it comes from the wpdb::process_field_charsets() method.
  2333.      * @param string $table Table name.
  2334.      * @return array|false The same array as $data with additional 'length' keys, or false if
  2335.      *                     any of the values were too long for their corresponding field.
  2336.      */
  2337.     protected function process_field_lengths( $data, $table ) {
  2338.         foreach ( $data as $field => $value ) {
  2339.             if ( '%d' === $value['format'] || '%f' === $value['format'] ) {
  2340.                 /*
  2341.                  * We can skip this field if we know it isn't a string.
  2342.                  * This checks %d/%f versus ! %s because its sprintf() could take more.
  2343.                  */
  2344.                 $value['length'] = false;
  2345.             } else {
  2346.                 $value['length'] = $this->get_col_length( $table, $field );
  2347.                 if ( is_wp_error( $value['length'] ) ) {
  2348.                     return false;
  2349.                 }
  2350.             }
  2351.  
  2352.             $data[ $field ] = $value;
  2353.         }
  2354.  
  2355.         return $data;
  2356.     }
  2357.  
  2358.     /**
  2359.      * Retrieve one variable from the database.
  2360.      *
  2361.      * Executes a SQL query and returns the value from the SQL result.
  2362.      * If the SQL result contains more than one column and/or more than one row, this function returns the value in the column and row specified.
  2363.      * If $query is null, this function returns the value in the specified column and row from the previous SQL result.
  2364.      *
  2365.      * @since 0.71
  2366.      *
  2367.      * @param string|null $query Optional. SQL query. Defaults to null, use the result from the previous query.
  2368.      * @param int         $x     Optional. Column of value to return. Indexed from 0.
  2369.      * @param int         $y     Optional. Row of value to return. Indexed from 0.
  2370.      * @return string|null Database query result (as string), or null on failure
  2371.      */
  2372.     public function get_var( $query = null, $x = 0, $y = 0 ) {
  2373.         $this->func_call = "\$db->get_var(\"$query\", $x, $y)";
  2374.  
  2375.         if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
  2376.             $this->check_current_query = false;
  2377.         }
  2378.  
  2379.         if ( $query ) {
  2380.             $this->query( $query );
  2381.         }
  2382.  
  2383.         // Extract var out of cached results based x,y vals
  2384.         if ( !empty( $this->last_result[$y] ) ) {
  2385.             $values = array_values( get_object_vars( $this->last_result[$y] ) );
  2386.         }
  2387.  
  2388.         // If there is a value return it else return null
  2389.         return ( isset( $values[$x] ) && $values[$x] !== '' ) ? $values[$x] : null;
  2390.     }
  2391.  
  2392.     /**
  2393.      * Retrieve one row from the database.
  2394.      *
  2395.      * Executes a SQL query and returns the row from the SQL result.
  2396.      *
  2397.      * @since 0.71
  2398.      *
  2399.      * @param string|null $query  SQL query.
  2400.      * @param string      $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
  2401.      *                            an stdClass object, an associative array, or a numeric array, respectively. Default OBJECT.
  2402.      * @param int         $y      Optional. Row to return. Indexed from 0.
  2403.      * @return array|object|null|void Database query result in format specified by $output or null on failure
  2404.      */
  2405.     public function get_row( $query = null, $output = OBJECT, $y = 0 ) {
  2406.         $this->func_call = "\$db->get_row(\"$query\",$output,$y)";
  2407.  
  2408.         if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
  2409.             $this->check_current_query = false;
  2410.         }
  2411.  
  2412.         if ( $query ) {
  2413.             $this->query( $query );
  2414.         } else {
  2415.             return null;
  2416.         }
  2417.  
  2418.         if ( !isset( $this->last_result[$y] ) )
  2419.             return null;
  2420.  
  2421.         if ( $output == OBJECT ) {
  2422.             return $this->last_result[$y] ? $this->last_result[$y] : null;
  2423.         } elseif ( $output == ARRAY_A ) {
  2424.             return $this->last_result[$y] ? get_object_vars( $this->last_result[$y] ) : null;
  2425.         } elseif ( $output == ARRAY_N ) {
  2426.             return $this->last_result[$y] ? array_values( get_object_vars( $this->last_result[$y] ) ) : null;
  2427.         } elseif ( strtoupper( $output ) === OBJECT ) {
  2428.             // Back compat for OBJECT being previously case insensitive.
  2429.             return $this->last_result[$y] ? $this->last_result[$y] : null;
  2430.         } else {
  2431.             $this->print_error( " \$db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N" );
  2432.         }
  2433.     }
  2434.  
  2435.     /**
  2436.      * Retrieve one column from the database.
  2437.      *
  2438.      * Executes a SQL query and returns the column from the SQL result.
  2439.      * If the SQL result contains more than one column, this function returns the column specified.
  2440.      * If $query is null, this function returns the specified column from the previous SQL result.
  2441.      *
  2442.      * @since 0.71
  2443.      *
  2444.      * @param string|null $query Optional. SQL query. Defaults to previous query.
  2445.      * @param int         $x     Optional. Column to return. Indexed from 0.
  2446.      * @return array Database query result. Array indexed from 0 by SQL result row number.
  2447.      */
  2448.     public function get_col( $query = null , $x = 0 ) {
  2449.         if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
  2450.             $this->check_current_query = false;
  2451.         }
  2452.  
  2453.         if ( $query ) {
  2454.             $this->query( $query );
  2455.         }
  2456.  
  2457.         $new_array = array();
  2458.         // Extract the column values
  2459.         for ( $i = 0, $j = count( $this->last_result ); $i < $j; $i++ ) {
  2460.             $new_array[$i] = $this->get_var( null, $x, $i );
  2461.         }
  2462.         return $new_array;
  2463.     }
  2464.  
  2465.     /**
  2466.      * Retrieve an entire SQL result set from the database (i.e., many rows)
  2467.      *
  2468.      * Executes a SQL query and returns the entire SQL result.
  2469.      *
  2470.      * @since 0.71
  2471.      *
  2472.      * @param string $query  SQL query.
  2473.      * @param string $output Optional. Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants.
  2474.      *                       With one of the first three, return an array of rows indexed from 0 by SQL result row number.
  2475.      *                       Each row is an associative array (column => value, ...), a numerically indexed array (0 => value, ...), or an object. ( ->column = value ), respectively.
  2476.      *                       With OBJECT_K, return an associative array of row objects keyed by the value of each row's first column's value.
  2477.      *                       Duplicate keys are discarded.
  2478.      * @return array|object|null Database query results
  2479.      */
  2480.     public function get_results( $query = null, $output = OBJECT ) {
  2481.         $this->func_call = "\$db->get_results(\"$query\", $output)";
  2482.  
  2483.         if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
  2484.             $this->check_current_query = false;
  2485.         }
  2486.  
  2487.         if ( $query ) {
  2488.             $this->query( $query );
  2489.         } else {
  2490.             return null;
  2491.         }
  2492.  
  2493.         $new_array = array();
  2494.         if ( $output == OBJECT ) {
  2495.             // Return an integer-keyed array of row objects
  2496.             return $this->last_result;
  2497.         } elseif ( $output == OBJECT_K ) {
  2498.             // Return an array of row objects with keys from column 1
  2499.             // (Duplicates are discarded)
  2500.             foreach ( $this->last_result as $row ) {
  2501.                 $var_by_ref = get_object_vars( $row );
  2502.                 $key = array_shift( $var_by_ref );
  2503.                 if ( ! isset( $new_array[ $key ] ) )
  2504.                     $new_array[ $key ] = $row;
  2505.             }
  2506.             return $new_array;
  2507.         } elseif ( $output == ARRAY_A || $output == ARRAY_N ) {
  2508.             // Return an integer-keyed array of...
  2509.             if ( $this->last_result ) {
  2510.                 foreach ( (array) $this->last_result as $row ) {
  2511.                     if ( $output == ARRAY_N ) {
  2512.                         // ...integer-keyed row arrays
  2513.                         $new_array[] = array_values( get_object_vars( $row ) );
  2514.                     } else {
  2515.                         // ...column name-keyed row arrays
  2516.                         $new_array[] = get_object_vars( $row );
  2517.                     }
  2518.                 }
  2519.             }
  2520.             return $new_array;
  2521.         } elseif ( strtoupper( $output ) === OBJECT ) {
  2522.             // Back compat for OBJECT being previously case insensitive.
  2523.             return $this->last_result;
  2524.         }
  2525.         return null;
  2526.     }
  2527.  
  2528.     /**
  2529.      * Retrieves the character set for the given table.
  2530.      *
  2531.      * @since 4.2.0
  2532.      *
  2533.      * @param string $table Table name.
  2534.      * @return string|WP_Error Table character set, WP_Error object if it couldn't be found.
  2535.      */
  2536.     protected function get_table_charset( $table ) {
  2537.         $tablekey = strtolower( $table );
  2538.  
  2539.         /**
  2540.          * Filters the table charset value before the DB is checked.
  2541.          *
  2542.          * Passing a non-null value to the filter will effectively short-circuit
  2543.          * checking the DB for the charset, returning that value instead.
  2544.          *
  2545.          * @since 4.2.0
  2546.          *
  2547.          * @param string $charset The character set to use. Default null.
  2548.          * @param string $table   The name of the table being checked.
  2549.          */
  2550.         $charset = apply_filters( 'pre_get_table_charset', null, $table );
  2551.         if ( null !== $charset ) {
  2552.             return $charset;
  2553.         }
  2554.  
  2555.         if ( isset( $this->table_charset[ $tablekey ] ) ) {
  2556.             return $this->table_charset[ $tablekey ];
  2557.         }
  2558.  
  2559.         $charsets = $columns = array();
  2560.  
  2561.         $table_parts = explode( '.', $table );
  2562.         $table = '`' . implode( '`.`', $table_parts ) . '`';
  2563.         $results = $this->get_results( "SHOW FULL COLUMNS FROM $table" );
  2564.         if ( ! $results ) {
  2565.             return new WP_Error( 'wpdb_get_table_charset_failure' );
  2566.         }
  2567.  
  2568.         foreach ( $results as $column ) {
  2569.             $columns[ strtolower( $column->Field ) ] = $column;
  2570.         }
  2571.  
  2572.         $this->col_meta[ $tablekey ] = $columns;
  2573.  
  2574.         foreach ( $columns as $column ) {
  2575.             if ( ! empty( $column->Collation ) ) {
  2576.                 list( $charset ) = explode( '_', $column->Collation );
  2577.  
  2578.                 // If the current connection can't support utf8mb4 characters, let's only send 3-byte utf8 characters.
  2579.                 if ( 'utf8mb4' === $charset && ! $this->has_cap( 'utf8mb4' ) ) {
  2580.                     $charset = 'utf8';
  2581.                 }
  2582.  
  2583.                 $charsets[ strtolower( $charset ) ] = true;
  2584.             }
  2585.  
  2586.             list( $type ) = explode( '(', $column->Type );
  2587.  
  2588.             // A binary/blob means the whole query gets treated like this.
  2589.             if ( in_array( strtoupper( $type ), array( 'BINARY', 'VARBINARY', 'TINYBLOB', 'MEDIUMBLOB', 'BLOB', 'LONGBLOB' ) ) ) {
  2590.                 $this->table_charset[ $tablekey ] = 'binary';
  2591.                 return 'binary';
  2592.             }
  2593.         }
  2594.  
  2595.         // utf8mb3 is an alias for utf8.
  2596.         if ( isset( $charsets['utf8mb3'] ) ) {
  2597.             $charsets['utf8'] = true;
  2598.             unset( $charsets['utf8mb3'] );
  2599.         }
  2600.  
  2601.         // Check if we have more than one charset in play.
  2602.         $count = count( $charsets );
  2603.         if ( 1 === $count ) {
  2604.             $charset = key( $charsets );
  2605.         } elseif ( 0 === $count ) {
  2606.             // No charsets, assume this table can store whatever.
  2607.             $charset = false;
  2608.         } else {
  2609.             // More than one charset. Remove latin1 if present and recalculate.
  2610.             unset( $charsets['latin1'] );
  2611.             $count = count( $charsets );
  2612.             if ( 1 === $count ) {
  2613.                 // Only one charset (besides latin1).
  2614.                 $charset = key( $charsets );
  2615.             } elseif ( 2 === $count && isset( $charsets['utf8'], $charsets['utf8mb4'] ) ) {
  2616.                 // Two charsets, but they're utf8 and utf8mb4, use utf8.
  2617.                 $charset = 'utf8';
  2618.             } else {
  2619.                 // Two mixed character sets. ascii.
  2620.                 $charset = 'ascii';
  2621.             }
  2622.         }
  2623.  
  2624.         $this->table_charset[ $tablekey ] = $charset;
  2625.         return $charset;
  2626.     }
  2627.  
  2628.     /**
  2629.      * Retrieves the character set for the given column.
  2630.      *
  2631.      * @since 4.2.0
  2632.      *
  2633.      * @param string $table  Table name.
  2634.      * @param string $column Column name.
  2635.      * @return string|false|WP_Error Column character set as a string. False if the column has no
  2636.      *                               character set. WP_Error object if there was an error.
  2637.      */
  2638.     public function get_col_charset( $table, $column ) {
  2639.         $tablekey = strtolower( $table );
  2640.         $columnkey = strtolower( $column );
  2641.  
  2642.         /**
  2643.          * Filters the column charset value before the DB is checked.
  2644.          *
  2645.          * Passing a non-null value to the filter will short-circuit
  2646.          * checking the DB for the charset, returning that value instead.
  2647.          *
  2648.          * @since 4.2.0
  2649.          *
  2650.          * @param string $charset The character set to use. Default null.
  2651.          * @param string $table   The name of the table being checked.
  2652.          * @param string $column  The name of the column being checked.
  2653.          */
  2654.         $charset = apply_filters( 'pre_get_col_charset', null, $table, $column );
  2655.         if ( null !== $charset ) {
  2656.             return $charset;
  2657.         }
  2658.  
  2659.         // Skip this entirely if this isn't a MySQL database.
  2660.         if ( empty( $this->is_mysql ) ) {
  2661.             return false;
  2662.         }
  2663.  
  2664.         if ( empty( $this->table_charset[ $tablekey ] ) ) {
  2665.             // This primes column information for us.
  2666.             $table_charset = $this->get_table_charset( $table );
  2667.             if ( is_wp_error( $table_charset ) ) {
  2668.                 return $table_charset;
  2669.             }
  2670.         }
  2671.  
  2672.         // If still no column information, return the table charset.
  2673.         if ( empty( $this->col_meta[ $tablekey ] ) ) {
  2674.             return $this->table_charset[ $tablekey ];
  2675.         }
  2676.  
  2677.         // If this column doesn't exist, return the table charset.
  2678.         if ( empty( $this->col_meta[ $tablekey ][ $columnkey ] ) ) {
  2679.             return $this->table_charset[ $tablekey ];
  2680.         }
  2681.  
  2682.         // Return false when it's not a string column.
  2683.         if ( empty( $this->col_meta[ $tablekey ][ $columnkey ]->Collation ) ) {
  2684.             return false;
  2685.         }
  2686.  
  2687.         list( $charset ) = explode( '_', $this->col_meta[ $tablekey ][ $columnkey ]->Collation );
  2688.         return $charset;
  2689.     }
  2690.  
  2691.     /**
  2692.      * Retrieve the maximum string length allowed in a given column.
  2693.      * The length may either be specified as a byte length or a character length.
  2694.      *
  2695.      * @since 4.2.1
  2696.      *
  2697.      * @param string $table  Table name.
  2698.      * @param string $column Column name.
  2699.      * @return array|false|WP_Error array( 'length' => (int), 'type' => 'byte' | 'char' )
  2700.      *                              false if the column has no length (for example, numeric column)
  2701.      *                              WP_Error object if there was an error.
  2702.      */
  2703.     public function get_col_length( $table, $column ) {
  2704.         $tablekey = strtolower( $table );
  2705.         $columnkey = strtolower( $column );
  2706.  
  2707.         // Skip this entirely if this isn't a MySQL database.
  2708.         if ( empty( $this->is_mysql ) ) {
  2709.             return false;
  2710.         }
  2711.  
  2712.         if ( empty( $this->col_meta[ $tablekey ] ) ) {
  2713.             // This primes column information for us.
  2714.             $table_charset = $this->get_table_charset( $table );
  2715.             if ( is_wp_error( $table_charset ) ) {
  2716.                 return $table_charset;
  2717.             }
  2718.         }
  2719.  
  2720.         if ( empty( $this->col_meta[ $tablekey ][ $columnkey ] ) ) {
  2721.             return false;
  2722.         }
  2723.  
  2724.         $typeinfo = explode( '(', $this->col_meta[ $tablekey ][ $columnkey ]->Type );
  2725.  
  2726.         $type = strtolower( $typeinfo[0] );
  2727.         if ( ! empty( $typeinfo[1] ) ) {
  2728.             $length = trim( $typeinfo[1], ')' );
  2729.         } else {
  2730.             $length = false;
  2731.         }
  2732.  
  2733.         switch( $type ) {
  2734.             case 'char':
  2735.             case 'varchar':
  2736.                 return array(
  2737.                     'type'   => 'char',
  2738.                     'length' => (int) $length,
  2739.                 );
  2740.  
  2741.             case 'binary':
  2742.             case 'varbinary':
  2743.                 return array(
  2744.                     'type'   => 'byte',
  2745.                     'length' => (int) $length,
  2746.                 );
  2747.  
  2748.             case 'tinyblob':
  2749.             case 'tinytext':
  2750.                 return array(
  2751.                     'type'   => 'byte',
  2752.                     'length' => 255,        // 2^8 - 1
  2753.                 );
  2754.  
  2755.             case 'blob':
  2756.             case 'text':
  2757.                 return array(
  2758.                     'type'   => 'byte',
  2759.                     'length' => 65535,      // 2^16 - 1
  2760.                 );
  2761.  
  2762.             case 'mediumblob':
  2763.             case 'mediumtext':
  2764.                 return array(
  2765.                     'type'   => 'byte',
  2766.                     'length' => 16777215,   // 2^24 - 1
  2767.                 );
  2768.  
  2769.             case 'longblob':
  2770.             case 'longtext':
  2771.                 return array(
  2772.                     'type'   => 'byte',
  2773.                     'length' => 4294967295, // 2^32 - 1
  2774.                 );
  2775.  
  2776.             default:
  2777.                 return false;
  2778.         }
  2779.     }
  2780.  
  2781.     /**
  2782.      * Check if a string is ASCII.
  2783.      *
  2784.      * The negative regex is faster for non-ASCII strings, as it allows
  2785.      * the search to finish as soon as it encounters a non-ASCII character.
  2786.      *
  2787.      * @since 4.2.0
  2788.      *
  2789.      * @param string $string String to check.
  2790.      * @return bool True if ASCII, false if not.
  2791.      */
  2792.     protected function check_ascii( $string ) {
  2793.         if ( function_exists( 'mb_check_encoding' ) ) {
  2794.             if ( mb_check_encoding( $string, 'ASCII' ) ) {
  2795.                 return true;
  2796.             }
  2797.         } elseif ( ! preg_match( '/[^\x00-\x7F]/', $string ) ) {
  2798.             return true;
  2799.         }
  2800.  
  2801.         return false;
  2802.     }
  2803.  
  2804.     /**
  2805.      * Check if the query is accessing a collation considered safe on the current version of MySQL.
  2806.      *
  2807.      * @since 4.2.0
  2808.      *
  2809.      * @param string $query The query to check.
  2810.      * @return bool True if the collation is safe, false if it isn't.
  2811.      */
  2812.     protected function check_safe_collation( $query ) {
  2813.         if ( $this->checking_collation ) {
  2814.             return true;
  2815.         }
  2816.  
  2817.         // We don't need to check the collation for queries that don't read data.
  2818.         $query = ltrim( $query, "\r\n\t (" );
  2819.         if ( preg_match( '/^(?:SHOW|DESCRIBE|DESC|EXPLAIN|CREATE)\s/i', $query ) ) {
  2820.             return true;
  2821.         }
  2822.  
  2823.         // All-ASCII queries don't need extra checking.
  2824.         if ( $this->check_ascii( $query ) ) {
  2825.             return true;
  2826.         }
  2827.  
  2828.         $table = $this->get_table_from_query( $query );
  2829.         if ( ! $table ) {
  2830.             return false;
  2831.         }
  2832.  
  2833.         $this->checking_collation = true;
  2834.         $collation = $this->get_table_charset( $table );
  2835.         $this->checking_collation = false;
  2836.  
  2837.         // Tables with no collation, or latin1 only, don't need extra checking.
  2838.         if ( false === $collation || 'latin1' === $collation ) {
  2839.             return true;
  2840.         }
  2841.  
  2842.         $table = strtolower( $table );
  2843.         if ( empty( $this->col_meta[ $table ] ) ) {
  2844.             return false;
  2845.         }
  2846.  
  2847.         // If any of the columns don't have one of these collations, it needs more sanity checking.
  2848.         foreach ( $this->col_meta[ $table ] as $col ) {
  2849.             if ( empty( $col->Collation ) ) {
  2850.                 continue;
  2851.             }
  2852.  
  2853.             if ( ! in_array( $col->Collation, array( 'utf8_general_ci', 'utf8_bin', 'utf8mb4_general_ci', 'utf8mb4_bin' ), true ) ) {
  2854.                 return false;
  2855.             }
  2856.         }
  2857.  
  2858.         return true;
  2859.     }
  2860.  
  2861.     /**
  2862.      * Strips any invalid characters based on value/charset pairs.
  2863.      *
  2864.      * @since 4.2.0
  2865.      *
  2866.      * @param array $data Array of value arrays. Each value array has the keys
  2867.      *                    'value' and 'charset'. An optional 'ascii' key can be
  2868.      *                    set to false to avoid redundant ASCII checks.
  2869.      * @return array|WP_Error The $data parameter, with invalid characters removed from
  2870.      *                        each value. This works as a passthrough: any additional keys
  2871.      *                        such as 'field' are retained in each value array. If we cannot
  2872.      *                        remove invalid characters, a WP_Error object is returned.
  2873.      */
  2874.     protected function strip_invalid_text( $data ) {
  2875.         $db_check_string = false;
  2876.  
  2877.         foreach ( $data as &$value ) {
  2878.             $charset = $value['charset'];
  2879.  
  2880.             if ( is_array( $value['length'] ) ) {
  2881.                 $length = $value['length']['length'];
  2882.                 $truncate_by_byte_length = 'byte' === $value['length']['type'];
  2883.             } else {
  2884.                 $length = false;
  2885.                 // Since we have no length, we'll never truncate.
  2886.                 // Initialize the variable to false. true would take us
  2887.                 // through an unnecessary (for this case) codepath below.
  2888.                 $truncate_by_byte_length = false;
  2889.             }
  2890.  
  2891.             // There's no charset to work with.
  2892.             if ( false === $charset ) {
  2893.                 continue;
  2894.             }
  2895.  
  2896.             // Column isn't a string.
  2897.             if ( ! is_string( $value['value'] ) ) {
  2898.                 continue;
  2899.             }
  2900.  
  2901.             $needs_validation = true;
  2902.             if (
  2903.                 // latin1 can store any byte sequence
  2904.                 'latin1' === $charset
  2905.             ||
  2906.                 // ASCII is always OK.
  2907.                 ( ! isset( $value['ascii'] ) && $this->check_ascii( $value['value'] ) )
  2908.             ) {
  2909.                 $truncate_by_byte_length = true;
  2910.                 $needs_validation = false;
  2911.             }
  2912.  
  2913.             if ( $truncate_by_byte_length ) {
  2914.                 mbstring_binary_safe_encoding();
  2915.                 if ( false !== $length && strlen( $value['value'] ) > $length ) {
  2916.                     $value['value'] = substr( $value['value'], 0, $length );
  2917.                 }
  2918.                 reset_mbstring_encoding();
  2919.  
  2920.                 if ( ! $needs_validation ) {
  2921.                     continue;
  2922.                 }
  2923.             }
  2924.  
  2925.             // utf8 can be handled by regex, which is a bunch faster than a DB lookup.
  2926.             if ( ( 'utf8' === $charset || 'utf8mb3' === $charset || 'utf8mb4' === $charset ) && function_exists( 'mb_strlen' ) ) {
  2927.                 $regex = '/
  2928.                     (
  2929.                         (?: [\x00-\x7F]                  # single-byte sequences   0xxxxxxx
  2930.                         |   [\xC2-\xDF][\x80-\xBF]       # double-byte sequences   110xxxxx 10xxxxxx
  2931.                         |   \xE0[\xA0-\xBF][\x80-\xBF]   # triple-byte sequences   1110xxxx 10xxxxxx * 2
  2932.                         |   [\xE1-\xEC][\x80-\xBF]{2}
  2933.                         |   \xED[\x80-\x9F][\x80-\xBF]
  2934.                         |   [\xEE-\xEF][\x80-\xBF]{2}';
  2935.  
  2936.                 if ( 'utf8mb4' === $charset ) {
  2937.                     $regex .= '
  2938.                         |    \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences   11110xxx 10xxxxxx * 3
  2939.                         |    [\xF1-\xF3][\x80-\xBF]{3}
  2940.                         |    \xF4[\x80-\x8F][\x80-\xBF]{2}
  2941.                     ';
  2942.                 }
  2943.  
  2944.                 $regex .= '){1,40}                          # ...one or more times
  2945.                     )
  2946.                     | .                                  # anything else
  2947.                     /x';
  2948.                 $value['value'] = preg_replace( $regex, '$1', $value['value'] );
  2949.  
  2950.  
  2951.                 if ( false !== $length && mb_strlen( $value['value'], 'UTF-8' ) > $length ) {
  2952.                     $value['value'] = mb_substr( $value['value'], 0, $length, 'UTF-8' );
  2953.                 }
  2954.                 continue;
  2955.             }
  2956.  
  2957.             // We couldn't use any local conversions, send it to the DB.
  2958.             $value['db'] = $db_check_string = true;
  2959.         }
  2960.         unset( $value ); // Remove by reference.
  2961.  
  2962.         if ( $db_check_string ) {
  2963.             $queries = array();
  2964.             foreach ( $data as $col => $value ) {
  2965.                 if ( ! empty( $value['db'] ) ) {
  2966.                     // We're going to need to truncate by characters or bytes, depending on the length value we have.
  2967.                     if ( 'byte' === $value['length']['type'] ) {
  2968.                         // Using binary causes LEFT() to truncate by bytes.
  2969.                         $charset = 'binary';
  2970.                     } else {
  2971.                         $charset = $value['charset'];
  2972.                     }
  2973.  
  2974.                     if ( $this->charset ) {
  2975.                         $connection_charset = $this->charset;
  2976.                     } else {
  2977.                         if ( $this->use_mysqli ) {
  2978.                             $connection_charset = mysqli_character_set_name( $this->dbh );
  2979.                         } else {
  2980.                             $connection_charset = mysql_client_encoding();
  2981.                         }
  2982.                     }
  2983.  
  2984.                     if ( is_array( $value['length'] ) ) {
  2985.                         $length = sprintf( '%.0f', $value['length']['length'] );
  2986.                         $queries[ $col ] = $this->prepare( "CONVERT( LEFT( CONVERT( %s USING $charset ), $length ) USING $connection_charset )", $value['value'] );
  2987.                     } else if ( 'binary' !== $charset ) {
  2988.                         // If we don't have a length, there's no need to convert binary - it will always return the same result.
  2989.                         $queries[ $col ] = $this->prepare( "CONVERT( CONVERT( %s USING $charset ) USING $connection_charset )", $value['value'] );
  2990.                     }
  2991.  
  2992.                     unset( $data[ $col ]['db'] );
  2993.                 }
  2994.             }
  2995.  
  2996.             $sql = array();
  2997.             foreach ( $queries as $column => $query ) {
  2998.                 if ( ! $query ) {
  2999.                     continue;
  3000.                 }
  3001.  
  3002.                 $sql[] = $query . " AS x_$column";
  3003.             }
  3004.  
  3005.             $this->check_current_query = false;
  3006.             $row = $this->get_row( "SELECT " . implode( ', ', $sql ), ARRAY_A );
  3007.             if ( ! $row ) {
  3008.                 return new WP_Error( 'wpdb_strip_invalid_text_failure' );
  3009.             }
  3010.  
  3011.             foreach ( array_keys( $data ) as $column ) {
  3012.                 if ( isset( $row["x_$column"] ) ) {
  3013.                     $data[ $column ]['value'] = $row["x_$column"];
  3014.                 }
  3015.             }
  3016.         }
  3017.  
  3018.         return $data;
  3019.     }
  3020.  
  3021.     /**
  3022.      * Strips any invalid characters from the query.
  3023.      *
  3024.      * @since 4.2.0
  3025.      *
  3026.      * @param string $query Query to convert.
  3027.      * @return string|WP_Error The converted query, or a WP_Error object if the conversion fails.
  3028.      */
  3029.     protected function strip_invalid_text_from_query( $query ) {
  3030.         // We don't need to check the collation for queries that don't read data.
  3031.         $trimmed_query = ltrim( $query, "\r\n\t (" );
  3032.         if ( preg_match( '/^(?:SHOW|DESCRIBE|DESC|EXPLAIN|CREATE)\s/i', $trimmed_query ) ) {
  3033.             return $query;
  3034.         }
  3035.  
  3036.         $table = $this->get_table_from_query( $query );
  3037.         if ( $table ) {
  3038.             $charset = $this->get_table_charset( $table );
  3039.             if ( is_wp_error( $charset ) ) {
  3040.                 return $charset;
  3041.             }
  3042.  
  3043.             // We can't reliably strip text from tables containing binary/blob columns
  3044.             if ( 'binary' === $charset ) {
  3045.                 return $query;
  3046.             }
  3047.         } else {
  3048.             $charset = $this->charset;
  3049.         }
  3050.  
  3051.         $data = array(
  3052.             'value'   => $query,
  3053.             'charset' => $charset,
  3054.             'ascii'   => false,
  3055.             'length'  => false,
  3056.         );
  3057.  
  3058.         $data = $this->strip_invalid_text( array( $data ) );
  3059.         if ( is_wp_error( $data ) ) {
  3060.             return $data;
  3061.         }
  3062.  
  3063.         return $data[0]['value'];
  3064.     }
  3065.  
  3066.     /**
  3067.      * Strips any invalid characters from the string for a given table and column.
  3068.      *
  3069.      * @since 4.2.0
  3070.      *
  3071.      * @param string $table  Table name.
  3072.      * @param string $column Column name.
  3073.      * @param string $value  The text to check.
  3074.      * @return string|WP_Error The converted string, or a WP_Error object if the conversion fails.
  3075.      */
  3076.     public function strip_invalid_text_for_column( $table, $column, $value ) {
  3077.         if ( ! is_string( $value ) ) {
  3078.             return $value;
  3079.         }
  3080.  
  3081.         $charset = $this->get_col_charset( $table, $column );
  3082.         if ( ! $charset ) {
  3083.             // Not a string column.
  3084.             return $value;
  3085.         } elseif ( is_wp_error( $charset ) ) {
  3086.             // Bail on real errors.
  3087.             return $charset;
  3088.         }
  3089.  
  3090.         $data = array(
  3091.             $column => array(
  3092.                 'value'   => $value,
  3093.                 'charset' => $charset,
  3094.                 'length'  => $this->get_col_length( $table, $column ),
  3095.             )
  3096.         );
  3097.  
  3098.         $data = $this->strip_invalid_text( $data );
  3099.         if ( is_wp_error( $data ) ) {
  3100.             return $data;
  3101.         }
  3102.  
  3103.         return $data[ $column ]['value'];
  3104.     }
  3105.  
  3106.     /**
  3107.      * Find the first table name referenced in a query.
  3108.      *
  3109.      * @since 4.2.0
  3110.      *
  3111.      * @param string $query The query to search.
  3112.      * @return string|false $table The table name found, or false if a table couldn't be found.
  3113.      */
  3114.     protected function get_table_from_query( $query ) {
  3115.         // Remove characters that can legally trail the table name.
  3116.         $query = rtrim( $query, ';/-#' );
  3117.  
  3118.         // Allow (select...) union [...] style queries. Use the first query's table name.
  3119.         $query = ltrim( $query, "\r\n\t (" );
  3120.  
  3121.         // Strip everything between parentheses except nested selects.
  3122.         $query = preg_replace( '/\((?!\s*select)[^(]*?\)/is', '()', $query );
  3123.  
  3124.         // Quickly match most common queries.
  3125.         if ( preg_match( '/^\s*(?:'
  3126.                 . 'SELECT.*?\s+FROM'
  3127.                 . '|INSERT(?:\s+LOW_PRIORITY|\s+DELAYED|\s+HIGH_PRIORITY)?(?:\s+IGNORE)?(?:\s+INTO)?'
  3128.                 . '|REPLACE(?:\s+LOW_PRIORITY|\s+DELAYED)?(?:\s+INTO)?'
  3129.                 . '|UPDATE(?:\s+LOW_PRIORITY)?(?:\s+IGNORE)?'
  3130.                 . '|DELETE(?:\s+LOW_PRIORITY|\s+QUICK|\s+IGNORE)*(?:.+?FROM)?'
  3131.                 . ')\s+((?:[0-9a-zA-Z$_.`-]|[\xC2-\xDF][\x80-\xBF])+)/is', $query, $maybe ) ) {
  3132.             return str_replace( '`', '', $maybe[1] );
  3133.         }
  3134.  
  3135.         // SHOW TABLE STATUS and SHOW TABLES WHERE Name = 'wp_posts'
  3136.         if ( preg_match( '/^\s*SHOW\s+(?:TABLE\s+STATUS|(?:FULL\s+)?TABLES).+WHERE\s+Name\s*=\s*("|\')((?:[0-9a-zA-Z$_.-]|[\xC2-\xDF][\x80-\xBF])+)\\1/is', $query, $maybe ) ) {
  3137.             return $maybe[2];
  3138.         }
  3139.  
  3140.         // SHOW TABLE STATUS LIKE and SHOW TABLES LIKE 'wp\_123\_%'
  3141.         // This quoted LIKE operand seldom holds a full table name.
  3142.         // It is usually a pattern for matching a prefix so we just
  3143.         // strip the trailing % and unescape the _ to get 'wp_123_'
  3144.         // which drop-ins can use for routing these SQL statements.
  3145.         if ( preg_match( '/^\s*SHOW\s+(?:TABLE\s+STATUS|(?:FULL\s+)?TABLES)\s+(?:WHERE\s+Name\s+)?LIKE\s*("|\')((?:[\\\\0-9a-zA-Z$_.-]|[\xC2-\xDF][\x80-\xBF])+)%?\\1/is', $query, $maybe ) ) {
  3146.             return str_replace( '\\_', '_', $maybe[2] );
  3147.         }
  3148.  
  3149.         // Big pattern for the rest of the table-related queries.
  3150.         if ( preg_match( '/^\s*(?:'
  3151.                 . '(?:EXPLAIN\s+(?:EXTENDED\s+)?)?SELECT.*?\s+FROM'
  3152.                 . '|DESCRIBE|DESC|EXPLAIN|HANDLER'
  3153.                 . '|(?:LOCK|UNLOCK)\s+TABLE(?:S)?'
  3154.                 . '|(?:RENAME|OPTIMIZE|BACKUP|RESTORE|CHECK|CHECKSUM|ANALYZE|REPAIR).*\s+TABLE'
  3155.                 . '|TRUNCATE(?:\s+TABLE)?'
  3156.                 . '|CREATE(?:\s+TEMPORARY)?\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?'
  3157.                 . '|ALTER(?:\s+IGNORE)?\s+TABLE'
  3158.                 . '|DROP\s+TABLE(?:\s+IF\s+EXISTS)?'
  3159.                 . '|CREATE(?:\s+\w+)?\s+INDEX.*\s+ON'
  3160.                 . '|DROP\s+INDEX.*\s+ON'
  3161.                 . '|LOAD\s+DATA.*INFILE.*INTO\s+TABLE'
  3162.                 . '|(?:GRANT|REVOKE).*ON\s+TABLE'
  3163.                 . '|SHOW\s+(?:.*FROM|.*TABLE)'
  3164.                 . ')\s+\(*\s*((?:[0-9a-zA-Z$_.`-]|[\xC2-\xDF][\x80-\xBF])+)\s*\)*/is', $query, $maybe ) ) {
  3165.             return str_replace( '`', '', $maybe[1] );
  3166.         }
  3167.  
  3168.         return false;
  3169.     }
  3170.  
  3171.     /**
  3172.      * Load the column metadata from the last query.
  3173.      *
  3174.      * @since 3.5.0
  3175.      *
  3176.      */
  3177.     protected function load_col_info() {
  3178.         if ( $this->col_info )
  3179.             return;
  3180.  
  3181.         if ( $this->use_mysqli ) {
  3182.             $num_fields = mysqli_num_fields( $this->result );
  3183.             for ( $i = 0; $i < $num_fields; $i++ ) {
  3184.                 $this->col_info[ $i ] = mysqli_fetch_field( $this->result );
  3185.             }
  3186.         } else {
  3187.             $num_fields = mysql_num_fields( $this->result );
  3188.             for ( $i = 0; $i < $num_fields; $i++ ) {
  3189.                 $this->col_info[ $i ] = mysql_fetch_field( $this->result, $i );
  3190.             }
  3191.         }
  3192.     }
  3193.  
  3194.     /**
  3195.      * Retrieve column metadata from the last query.
  3196.      *
  3197.      * @since 0.71
  3198.      *
  3199.      * @param string $info_type  Optional. Type one of name, table, def, max_length, not_null, primary_key, multiple_key, unique_key, numeric, blob, type, unsigned, zerofill
  3200.      * @param int    $col_offset Optional. 0: col name. 1: which table the col's in. 2: col's max length. 3: if the col is numeric. 4: col's type
  3201.      * @return mixed Column Results
  3202.      */
  3203.     public function get_col_info( $info_type = 'name', $col_offset = -1 ) {
  3204.         $this->load_col_info();
  3205.  
  3206.         if ( $this->col_info ) {
  3207.             if ( $col_offset == -1 ) {
  3208.                 $i = 0;
  3209.                 $new_array = array();
  3210.                 foreach ( (array) $this->col_info as $col ) {
  3211.                     $new_array[$i] = $col->{$info_type};
  3212.                     $i++;
  3213.                 }
  3214.                 return $new_array;
  3215.             } else {
  3216.                 return $this->col_info[$col_offset]->{$info_type};
  3217.             }
  3218.         }
  3219.     }
  3220.  
  3221.     /**
  3222.      * Starts the timer, for debugging purposes.
  3223.      *
  3224.      * @since 1.5.0
  3225.      *
  3226.      * @return true
  3227.      */
  3228.     public function timer_start() {
  3229.         $this->time_start = microtime( true );
  3230.         return true;
  3231.     }
  3232.  
  3233.     /**
  3234.      * Stops the debugging timer.
  3235.      *
  3236.      * @since 1.5.0
  3237.      *
  3238.      * @return float Total time spent on the query, in seconds
  3239.      */
  3240.     public function timer_stop() {
  3241.         return ( microtime( true ) - $this->time_start );
  3242.     }
  3243.  
  3244.     /**
  3245.      * Wraps errors in a nice header and footer and dies.
  3246.      *
  3247.      * Will not die if wpdb::$show_errors is false.
  3248.      *
  3249.      * @since 1.5.0
  3250.      *
  3251.      * @param string $message    The Error message
  3252.      * @param string $error_code Optional. A Computer readable string to identify the error.
  3253.      * @return false|void
  3254.      */
  3255.     public function bail( $message, $error_code = '500' ) {
  3256.         if ( !$this->show_errors ) {
  3257.             if ( class_exists( 'WP_Error', false ) ) {
  3258.                 $this->error = new WP_Error($error_code, $message);
  3259.             } else {
  3260.                 $this->error = $message;
  3261.             }
  3262.             return false;
  3263.         }
  3264.         wp_die($message);
  3265.     }
  3266.  
  3267.  
  3268.     /**
  3269.      * Closes the current database connection.
  3270.      *
  3271.      * @since 4.5.0
  3272.      *
  3273.      * @return bool True if the connection was successfully closed, false if it wasn't,
  3274.      *              or the connection doesn't exist.
  3275.      */
  3276.     public function close() {
  3277.         if ( ! $this->dbh ) {
  3278.             return false;
  3279.         }
  3280.  
  3281.         if ( $this->use_mysqli ) {
  3282.             $closed = mysqli_close( $this->dbh );
  3283.         } else {
  3284.             $closed = mysql_close( $this->dbh );
  3285.         }
  3286.  
  3287.         if ( $closed ) {
  3288.             $this->dbh = null;
  3289.             $this->ready = false;
  3290.             $this->has_connected = false;
  3291.         }
  3292.  
  3293.         return $closed;
  3294.     }
  3295.  
  3296.     /**
  3297.      * Whether MySQL database is at least the required minimum version.
  3298.      *
  3299.      * @since 2.5.0
  3300.      *
  3301.      * @global string $wp_version
  3302.      * @global string $required_mysql_version
  3303.      *
  3304.      * @return WP_Error|void
  3305.      */
  3306.     public function check_database_version() {
  3307.         global $wp_version, $required_mysql_version;
  3308.         // Make sure the server has the required MySQL version
  3309.         if ( version_compare($this->db_version(), $required_mysql_version, '<') ) {
  3310.             /* translators: 1: WordPress version number, 2: Minimum required MySQL version number */
  3311.             return new WP_Error('database_version', sprintf( __( '<strong>ERROR</strong>: WordPress %1$s requires MySQL %2$s or higher' ), $wp_version, $required_mysql_version ));
  3312.         }
  3313.     }
  3314.  
  3315.     /**
  3316.      * Whether the database supports collation.
  3317.      *
  3318.      * Called when WordPress is generating the table scheme.
  3319.      *
  3320.      * Use `wpdb::has_cap( 'collation' )`.
  3321.      *
  3322.      * @since 2.5.0
  3323.      * @deprecated 3.5.0 Use wpdb::has_cap()
  3324.      *
  3325.      * @return bool True if collation is supported, false if version does not
  3326.      */
  3327.     public function supports_collation() {
  3328.         _deprecated_function( __FUNCTION__, '3.5.0', 'wpdb::has_cap( \'collation\' )' );
  3329.         return $this->has_cap( 'collation' );
  3330.     }
  3331.  
  3332.     /**
  3333.      * The database character collate.
  3334.      *
  3335.      * @since 3.5.0
  3336.      *
  3337.      * @return string The database character collate.
  3338.      */
  3339.     public function get_charset_collate() {
  3340.         $charset_collate = '';
  3341.  
  3342.         if ( ! empty( $this->charset ) )
  3343.             $charset_collate = "DEFAULT CHARACTER SET $this->charset";
  3344.         if ( ! empty( $this->collate ) )
  3345.             $charset_collate .= " COLLATE $this->collate";
  3346.  
  3347.         return $charset_collate;
  3348.     }
  3349.  
  3350.     /**
  3351.      * Determine if a database supports a particular feature.
  3352.      *
  3353.      * @since 2.7.0
  3354.      * @since 4.1.0 Added support for the 'utf8mb4' feature.
  3355.      * @since 4.6.0 Added support for the 'utf8mb4_520' feature.
  3356.      *
  3357.      * @see wpdb::db_version()
  3358.      *
  3359.      * @param string $db_cap The feature to check for. Accepts 'collation',
  3360.      *                       'group_concat', 'subqueries', 'set_charset',
  3361.      *                       'utf8mb4', or 'utf8mb4_520'.
  3362.      * @return int|false Whether the database feature is supported, false otherwise.
  3363.      */
  3364.     public function has_cap( $db_cap ) {
  3365.         $version = $this->db_version();
  3366.  
  3367.         switch ( strtolower( $db_cap ) ) {
  3368.             case 'collation' :    // @since 2.5.0
  3369.             case 'group_concat' : // @since 2.7.0
  3370.             case 'subqueries' :   // @since 2.7.0
  3371.                 return version_compare( $version, '4.1', '>=' );
  3372.             case 'set_charset' :
  3373.                 return version_compare( $version, '5.0.7', '>=' );
  3374.             case 'utf8mb4' :      // @since 4.1.0
  3375.                 if ( version_compare( $version, '5.5.3', '<' ) ) {
  3376.                     return false;
  3377.                 }
  3378.                 if ( $this->use_mysqli ) {
  3379.                     $client_version = mysqli_get_client_info();
  3380.                 } else {
  3381.                     $client_version = mysql_get_client_info();
  3382.                 }
  3383.  
  3384.                 /*
  3385.                  * libmysql has supported utf8mb4 since 5.5.3, same as the MySQL server.
  3386.                  * mysqlnd has supported utf8mb4 since 5.0.9.
  3387.                  */
  3388.                 if ( false !== strpos( $client_version, 'mysqlnd' ) ) {
  3389.                     $client_version = preg_replace( '/^\D+([\d.]+).*/', '$1', $client_version );
  3390.                     return version_compare( $client_version, '5.0.9', '>=' );
  3391.                 } else {
  3392.                     return version_compare( $client_version, '5.5.3', '>=' );
  3393.                 }
  3394.             case 'utf8mb4_520' : // @since 4.6.0
  3395.                 return version_compare( $version, '5.6', '>=' );
  3396.         }
  3397.  
  3398.         return false;
  3399.     }
  3400.  
  3401.     /**
  3402.      * Retrieve the name of the function that called wpdb.
  3403.      *
  3404.      * Searches up the list of functions until it reaches
  3405.      * the one that would most logically had called this method.
  3406.      *
  3407.      * @since 2.5.0
  3408.      *
  3409.      * @return string|array The name of the calling function
  3410.      */
  3411.     public function get_caller() {
  3412.         return wp_debug_backtrace_summary( __CLASS__ );
  3413.     }
  3414.  
  3415.     /**
  3416.      * Retrieves the MySQL server version.
  3417.      *
  3418.      * @since 2.7.0
  3419.      *
  3420.      * @return null|string Null on failure, version number on success.
  3421.      */
  3422.     public function db_version() {
  3423.         if ( $this->use_mysqli ) {
  3424.             $server_info = mysqli_get_server_info( $this->dbh );
  3425.         } else {
  3426.             $server_info = mysql_get_server_info( $this->dbh );
  3427.         }
  3428.         return preg_replace( '/[^0-9.].*/', '', $server_info );
  3429.     }
  3430. }
  3431.