~canonical-sysadmins/wordpress/4.9.7

« back to all changes in this revision

Viewing changes to wp-includes/wp-db.php

  • Committer: Barry Price
  • Date: 2017-11-02 04:15:21 UTC
  • mto: This revision was merged to the branch mainline in revision 33.
  • Revision ID: barry.price@canonical.com-20171102041521-ndw2qbwzffjd42hv
new upstream release 4.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1168
1168
        function _real_escape( $string ) {
1169
1169
                if ( $this->dbh ) {
1170
1170
                        if ( $this->use_mysqli ) {
1171
 
                                return mysqli_real_escape_string( $this->dbh, $string );
 
1171
                                $escaped = mysqli_real_escape_string( $this->dbh, $string );
1172
1172
                        } else {
1173
 
                                return mysql_real_escape_string( $string, $this->dbh );
 
1173
                                $escaped = mysql_real_escape_string( $string, $this->dbh );
1174
1174
                        }
1175
 
                }
1176
 
 
1177
 
                $class = get_class( $this );
1178
 
                if ( function_exists( '__' ) ) {
1179
 
                        /* translators: %s: database access abstraction class, usually wpdb or a class extending wpdb */
1180
 
                        _doing_it_wrong( $class, sprintf( __( '%s must set a database connection for use with escaping.' ), $class ), '3.6.0' );
1181
1175
                } else {
1182
 
                        _doing_it_wrong( $class, sprintf( '%s must set a database connection for use with escaping.', $class ), '3.6.0' );
 
1176
                        $class = get_class( $this );
 
1177
                        if ( function_exists( '__' ) ) {
 
1178
                                /* translators: %s: database access abstraction class, usually wpdb or a class extending wpdb */
 
1179
                                _doing_it_wrong( $class, sprintf( __( '%s must set a database connection for use with escaping.' ), $class ), '3.6.0' );
 
1180
                        } else {
 
1181
                                _doing_it_wrong( $class, sprintf( '%s must set a database connection for use with escaping.', $class ), '3.6.0' );
 
1182
                        }
 
1183
                        $escaped = addslashes( $string );
1183
1184
                }
1184
 
                return addslashes( $string );
 
1185
 
 
1186
                return $this->add_placeholder_escape( $escaped );
1185
1187
        }
1186
1188
 
1187
1189
        /**
1257
1259
        /**
1258
1260
         * Prepares a SQL query for safe execution. Uses sprintf()-like syntax.
1259
1261
         *
1260
 
         * The following directives can be used in the query format string:
 
1262
         * The following placeholders can be used in the query string:
1261
1263
         *   %d (integer)
1262
1264
         *   %f (float)
1263
1265
         *   %s (string)
1264
 
         *   %% (literal percentage sign - no argument needed)
1265
 
         *
1266
 
         * All of %d, %f, and %s are to be left unquoted in the query string and they need an argument passed for them.
1267
 
         * Literals (%) as parts of the query must be properly written as %%.
1268
 
         *
1269
 
         * This function only supports a small subset of the sprintf syntax; it only supports %d (integer), %f (float), and %s (string).
1270
 
         * Does not support sign, padding, alignment, width or precision specifiers.
1271
 
         * Does not support argument numbering/swapping.
1272
 
         *
1273
 
         * May be called like {@link https://secure.php.net/sprintf sprintf()} or like {@link https://secure.php.net/vsprintf vsprintf()}.
1274
 
         *
1275
 
         * Both %d and %s should be left unquoted in the query string.
1276
 
         *
1277
 
         *     $wpdb->prepare( "SELECT * FROM `table` WHERE `column` = %s AND `field` = %d", 'foo', 1337 );
 
1266
         *
 
1267
         * All placeholders MUST be left unquoted in the query string. A corresponding argument MUST be passed for each placeholder.
 
1268
         *
 
1269
         * For compatibility with old behavior, numbered or formatted string placeholders (eg, %1$s, %5s) will not have quotes
 
1270
         * added by this function, so should be passed with appropriate quotes around them for your usage.
 
1271
         *
 
1272
         * Literal percentage signs (%) in the query string must be written as %%. Percentage wildcards (for example,
 
1273
         * to use in LIKE syntax) must be passed via a substitution argument containing the complete LIKE string, these
 
1274
         * cannot be inserted directly in the query string. Also see {@see esc_like()}.
 
1275
         *
 
1276
         * Arguments may be passed as individual arguments to the method, or as a single array containing all arguments. A combination
 
1277
         * of the two is not supported.
 
1278
         *
 
1279
         * Examples:
 
1280
         *     $wpdb->prepare( "SELECT * FROM `table` WHERE `column` = %s AND `field` = %d OR `other_field` LIKE %s", array( 'foo', 1337, '%bar' ) );
1278
1281
         *     $wpdb->prepare( "SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s", 'foo' );
1279
1282
         *
1280
1283
         * @link https://secure.php.net/sprintf Description of syntax.
1281
1284
         * @since 2.3.0
1282
1285
         *
1283
1286
         * @param string      $query    Query statement with sprintf()-like placeholders
1284
 
         * @param array|mixed $args     The array of variables to substitute into the query's placeholders if being called like
1285
 
         *                              {@link https://secure.php.net/vsprintf vsprintf()}, or the first variable to substitute into the query's placeholders if
1286
 
         *                              being called like {@link https://secure.php.net/sprintf sprintf()}.
1287
 
         * @param mixed       $args,... further variables to substitute into the query's placeholders if being called like
1288
 
         *                              {@link https://secure.php.net/sprintf sprintf()}.
 
1287
         * @param array|mixed $args     The array of variables to substitute into the query's placeholders if being called with an array of arguments,
 
1288
         *                              or the first variable to substitute into the query's placeholders if being called with individual arguments.
 
1289
         * @param mixed       $args,... further variables to substitute into the query's placeholders if being called wih individual arguments.
1289
1290
         * @return string|void Sanitized query string, if there is a query to prepare.
1290
1291
         */
1291
1292
        public function prepare( $query, $args ) {
1292
 
                if ( is_null( $query ) )
 
1293
                if ( is_null( $query ) ) {
1293
1294
                        return;
 
1295
                }
1294
1296
 
1295
1297
                // This is not meant to be foolproof -- but it will catch obviously incorrect usage.
1296
1298
                if ( strpos( $query, '%' ) === false ) {
 
1299
                        wp_load_translations_early();
1297
1300
                        _doing_it_wrong( 'wpdb::prepare', sprintf( __( 'The query argument of %s must have a placeholder.' ), 'wpdb::prepare()' ), '3.9.0' );
1298
1301
                }
1299
1302
 
1300
1303
                $args = func_get_args();
1301
1304
                array_shift( $args );
1302
1305
 
1303
 
                // If args were passed as an array (as in vsprintf), move them up
 
1306
                // If args were passed as an array (as in vsprintf), move them up.
 
1307
                $passed_as_array = false;
1304
1308
                if ( is_array( $args[0] ) && count( $args ) == 1 ) {
 
1309
                        $passed_as_array = true;
1305
1310
                        $args = $args[0];
1306
1311
                }
1307
1312
 
1308
1313
                foreach ( $args as $arg ) {
1309
1314
                        if ( ! is_scalar( $arg ) && ! is_null( $arg ) ) {
1310
 
                                _doing_it_wrong( 'wpdb::prepare', sprintf( 'Unsupported value type (%s).', gettype( $arg ) ), '4.8.2' );
1311
 
                        }
1312
 
                }
1313
 
 
1314
 
                $query = str_replace( "'%s'", '%s', $query ); // in case someone mistakenly already singlequoted it
1315
 
                $query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting
1316
 
                $query = preg_replace( '|(?<!%)%f|' , '%F', $query ); // Force floats to be locale unaware
1317
 
                $query = preg_replace( '|(?<!%)%s|', "'%s'", $query ); // quote the strings, avoiding escaped strings like %%s
1318
 
                $query = preg_replace( '/%(?:%|$|([^dsF]))/', '%%\\1', $query ); // escape any unescaped percents 
 
1315
                                wp_load_translations_early();
 
1316
                                _doing_it_wrong( 'wpdb::prepare', sprintf( __( 'Unsupported value type (%s).' ), gettype( $arg ) ), '4.8.2' );
 
1317
                        }
 
1318
                }
 
1319
 
 
1320
                /*
 
1321
                 * Specify the formatting allowed in a placeholder. The following are allowed:
 
1322
                 *
 
1323
                 * - Sign specifier. eg, $+d
 
1324
                 * - Numbered placeholders. eg, %1$s
 
1325
                 * - Padding specifier, including custom padding characters. eg, %05s, %'#5s
 
1326
                 * - Alignment specifier. eg, %05-s
 
1327
                 * - Precision specifier. eg, %.2f
 
1328
                 */
 
1329
                $allowed_format = '(?:[1-9][0-9]*[$])?[-+0-9]*(?: |0|\'.)?[-+0-9]*(?:\.[0-9]+)?';
 
1330
 
 
1331
                /*
 
1332
                 * If a %s placeholder already has quotes around it, removing the existing quotes and re-inserting them
 
1333
                 * ensures the quotes are consistent.
 
1334
                 *
 
1335
                 * For backwards compatibility, this is only applied to %s, and not to placeholders like %1$s, which are frequently
 
1336
                 * used in the middle of longer strings, or as table name placeholders.
 
1337
                 */
 
1338
                $query = str_replace( "'%s'", '%s', $query ); // Strip any existing single quotes.
 
1339
                $query = str_replace( '"%s"', '%s', $query ); // Strip any existing double quotes.
 
1340
                $query = preg_replace( '/(?<!%)%s/', "'%s'", $query ); // Quote the strings, avoiding escaped strings like %%s.
 
1341
 
 
1342
                $query = preg_replace( "/(?<!%)(%($allowed_format)?f)/" , '%\\2F', $query ); // Force floats to be locale unaware.
 
1343
 
 
1344
                $query = preg_replace( "/%(?:%|$|(?!($allowed_format)?[sdF]))/", '%%\\1', $query ); // Escape any unescaped percents.
 
1345
 
 
1346
                // Count the number of valid placeholders in the query.
 
1347
                $placeholders = preg_match_all( "/(^|[^%]|(%%)+)%($allowed_format)?[sdF]/", $query, $matches );
 
1348
 
 
1349
                if ( count( $args ) !== $placeholders ) {
 
1350
                        if ( 1 === $placeholders && $passed_as_array ) {
 
1351
                                // If the passed query only expected one argument, but the wrong number of arguments were sent as an array, bail.
 
1352
                                wp_load_translations_early();
 
1353
                                _doing_it_wrong( 'wpdb::prepare', __( 'The query only expected one placeholder, but an array of multiple placeholders was sent.' ), '4.9.0' );
 
1354
 
 
1355
                                return;
 
1356
                        } else {
 
1357
                                /*
 
1358
                                 * If we don't have the right number of placeholders, but they were passed as individual arguments,
 
1359
                                 * or we were expecting multiple arguments in an array, throw a warning.
 
1360
                                 */
 
1361
                                wp_load_translations_early();
 
1362
                                _doing_it_wrong( 'wpdb::prepare',
 
1363
                                        /* translators: 1: number of placeholders, 2: number of arguments passed */
 
1364
                                        sprintf( __( 'The query does not contain the correct number of placeholders (%1$d) for the number of arguments passed (%2$d).' ),
 
1365
                                                $placeholders,
 
1366
                                                count( $args ) ),
 
1367
                                        '4.8.3'
 
1368
                                );
 
1369
                        }
 
1370
                }
 
1371
 
1319
1372
                array_walk( $args, array( $this, 'escape_by_ref' ) );
1320
 
                return @vsprintf( $query, $args );
 
1373
                $query = @vsprintf( $query, $args );
 
1374
 
 
1375
                return $this->add_placeholder_escape( $query );
1321
1376
        }
1322
1377
 
1323
1378
        /**
1896
1951
        }
1897
1952
 
1898
1953
        /**
 
1954
         * Generates and returns a placeholder escape string for use in queries returned by ::prepare().
 
1955
         *
 
1956
         * @since 4.8.3
 
1957
         *
 
1958
         * @return string String to escape placeholders.
 
1959
         */
 
1960
        public function placeholder_escape() {
 
1961
                static $placeholder;
 
1962
 
 
1963
                if ( ! $placeholder ) {
 
1964
                        // If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
 
1965
                        $algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
 
1966
                        // Old WP installs may not have AUTH_SALT defined.
 
1967
                        $salt = defined( 'AUTH_SALT' ) ? AUTH_SALT : rand();
 
1968
 
 
1969
                        $placeholder = '{' . hash_hmac( $algo, uniqid( $salt, true ), $salt ) . '}';
 
1970
                }
 
1971
 
 
1972
                /*
 
1973
                 * Add the filter to remove the placeholder escaper. Uses priority 0, so that anything
 
1974
                 * else attached to this filter will recieve the query with the placeholder string removed.
 
1975
                 */
 
1976
                if ( ! has_filter( 'query', array( $this, 'remove_placeholder_escape' ) ) ) {
 
1977
                        add_filter( 'query', array( $this, 'remove_placeholder_escape' ), 0 );
 
1978
                }
 
1979
 
 
1980
                return $placeholder;
 
1981
        }
 
1982
 
 
1983
        /**
 
1984
         * Adds a placeholder escape string, to escape anything that resembles a printf() placeholder.
 
1985
         *
 
1986
         * @since 4.8.3
 
1987
         *
 
1988
         * @param string $query The query to escape.
 
1989
         * @return string The query with the placeholder escape string inserted where necessary.
 
1990
         */
 
1991
        public function add_placeholder_escape( $query ) {
 
1992
                /*
 
1993
                 * To prevent returning anything that even vaguely resembles a placeholder,
 
1994
                 * we clobber every % we can find.
 
1995
                 */
 
1996
                return str_replace( '%', $this->placeholder_escape(), $query );
 
1997
        }
 
1998
 
 
1999
        /**
 
2000
         * Removes the placeholder escape strings from a query.
 
2001
         *
 
2002
         * @since 4.8.3
 
2003
         *
 
2004
         * @param string $query The query from which the placeholder will be removed.
 
2005
         * @return string The query with the placeholder removed.
 
2006
         */
 
2007
        public function remove_placeholder_escape( $query ) {
 
2008
                return str_replace( $this->placeholder_escape(), '%', $query );
 
2009
        }
 
2010
 
 
2011
        /**
1899
2012
         * Insert a row into a table.
1900
2013
         *
1901
2014
         *     wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )