Database: Throw a notice if `wpdb::prepare()` is called with an incorrect number of arguments

`wpdb::prepare()` currently gives no information if the number of arguments passed doesn't match the number of placeholders in the query. This change gives an explicit notice that the call was incorrect.

Also fixes an enrelated term meta test that was triggering this new notice.

Props thekt12 for the initial patch.
Fixes #42040.



git-svn-id: https://develop.svn.wordpress.org/trunk@41662 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Gary Pendergast 2017-10-02 02:10:14 +00:00
parent e02c481487
commit b4a6de9997
3 changed files with 86 additions and 6 deletions

View File

@ -1251,7 +1251,20 @@ class wpdb {
$query = str_replace( '"%s"', '%s', $query ); // doublequote unquoting
$query = preg_replace( '|(?<!%)%f|' , '%F', $query ); // Force floats to be locale unaware
$query = preg_replace( '|(?<!%)%s|', "'%s'", $query ); // quote the strings, avoiding escaped strings like %%s
$query = preg_replace( '/%(?:%|$|([^dsF]))/', '%%\\1', $query ); // escape any unescaped percents
$query = preg_replace( '/%(?:%|$|([^dsF]))/', '%%\\1', $query ); // escape any unescaped percents
// Count the number of valid placeholders in the query
$placeholders = preg_match_all( '/(^|[^%]|(%%)+)%[sdF]/', $query );
if ( count ( $args ) !== $placeholders ) {
_doing_it_wrong( 'wpdb::prepare',
sprintf( __( 'The query does not contain the correct number of placeholders (%d) for the number of arguments passed (%d).' ),
$placeholders,
count( $args ) ),
'4.9.0'
);
}
array_walk( $args, array( $this, 'escape_by_ref' ) );
return @vsprintf( $query, $args );
}
@ -2046,7 +2059,7 @@ class wpdb {
$conditions = implode( ' AND ', $conditions );
$sql = "UPDATE `$table` SET $fields WHERE $conditions";
$this->check_current_query = false;
return $this->query( $this->prepare( $sql, $values ) );
}

View File

@ -375,8 +375,8 @@ class Tests_DB extends WP_UnitTestCase {
$this->assertEquals( "SELECT * FROM $wpdb->users WHERE id = 0 AND user_login = 'admin'", $prepared );
}
function test_prepare_vsprintf() {
global $wpdb;
function test_prepare_vsprintf() {
global $wpdb;
$prepared = $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s", array( 1, "admin" ) );
$this->assertEquals( "SELECT * FROM $wpdb->users WHERE id = 1 AND user_login = 'admin'", $prepared );
@ -393,7 +393,74 @@ class Tests_DB extends WP_UnitTestCase {
$prepared = @$wpdb->prepare( "SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s", array( array( 1 ), "admin" ) );
$this->assertEquals( "SELECT * FROM $wpdb->users WHERE id = 0 AND user_login = 'admin'", $prepared );
}
}
/**
* @ticket 42040
* @dataProvider data_prepare_incorrect_arg_count
* @expectedIncorrectUsage wpdb::prepare
*/
public function test_prepare_incorrect_arg_count( $query, $args, $expected ) {
global $wpdb;
// $query is the first argument to be passed to wpdb::prepare()
array_unshift( $args, $query );
$prepared = @call_user_func_array( array( $wpdb, 'prepare' ), $args );
$this->assertEquals( $expected, $prepared );
}
public function data_prepare_incorrect_arg_count() {
global $wpdb;
return array(
array(
"SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s", // Query
array( 1, "admin", "extra-arg" ), // ::prepare() args, to be passed via call_user_func_array
"SELECT * FROM $wpdb->users WHERE id = 1 AND user_login = 'admin'", // Expected output
),
array(
"SELECT * FROM $wpdb->users WHERE id = %%%d AND user_login = %s",
array( 1 ),
false,
),
array(
"SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s",
array( array( 1, "admin", "extra-arg" ) ),
"SELECT * FROM $wpdb->users WHERE id = 1 AND user_login = 'admin'",
),
array(
"SELECT * FROM $wpdb->users WHERE id = %d AND %% AND user_login = %s",
array( 1, "admin", "extra-arg" ),
"SELECT * FROM $wpdb->users WHERE id = 1 AND % AND user_login = 'admin'",
),
array(
"SELECT * FROM $wpdb->users WHERE id = %%%d AND %F AND %f AND user_login = %s",
array( 1, 2.3, "4.5", "admin", "extra-arg" ),
"SELECT * FROM $wpdb->users WHERE id = %1 AND 2.300000 AND 4.500000 AND user_login = 'admin'",
),
array(
"SELECT * FROM $wpdb->users WHERE id = %d AND user_login = %s",
array( array( 1 ), "admin", "extra-arg" ),
"SELECT * FROM $wpdb->users WHERE id = 0 AND user_login = 'admin'",
),
array(
"SELECT * FROM $wpdb->users WHERE id = %d and user_nicename = %s and user_status = %d and user_login = %s",
array( 1, "admin", 0 ),
'',
),
array(
"SELECT * FROM $wpdb->users WHERE id = %d and user_nicename = %s and user_status = %d and user_login = %s",
array( array( 1, "admin", 0 ) ),
'',
),
array(
"SELECT * FROM $wpdb->users WHERE id = %d and %% and user_login = %s and user_status = %d and user_login = %s",
array( 1, "admin", "extra-arg" ),
'',
),
);
}
function test_db_version() {
global $wpdb;

View File

@ -358,7 +358,7 @@ class Tests_Term_Meta extends WP_UnitTestCase {
register_taxonomy( 'wptests_tax', 'post' );
$t1 = wp_insert_term( 'Foo', 'wptests_tax' );
add_term_meta( $t1, 'foo', 'bar' );
add_term_meta( $t1['term_id'], 'foo', 'bar' );
register_taxonomy( 'wptests_tax_2', 'post' );
register_taxonomy( 'wptests_tax_3', 'post' );