From 7217a4f6e5c07c04385157580dbd4efd0a6f2329 Mon Sep 17 00:00:00 2001 From: Gary Pendergast Date: Fri, 17 Jul 2015 07:06:33 +0000 Subject: [PATCH] WPDB: `::strip_text_from_query()` doesn't pass a length to `::strip_invalid_text()`, which was causing queries to fail when they contained characters that needed to be sanity checked by MySQL. Props dd32, mdawaffe, pento. Fixes #32279. git-svn-id: https://develop.svn.wordpress.org/trunk@33310 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/wp-db.php | 14 ++++++++++--- tests/phpunit/tests/db/charset.php | 32 ++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/wp-db.php b/src/wp-includes/wp-db.php index d6f5a6679b..c480e46d68 100644 --- a/src/wp-includes/wp-db.php +++ b/src/wp-includes/wp-db.php @@ -2629,8 +2629,13 @@ class wpdb { if ( is_array( $value['length'] ) ) { $length = $value['length']['length']; + $truncate_by_byte_length = 'byte' === $value['length']['type']; } else { $length = false; + // Since we have no length, we'll never truncate. + // Initialize the variable to false. true would take us + // through an unnecessary (for this case) codepath below. + $truncate_by_byte_length = false; } // There's no charset to work with. @@ -2643,8 +2648,6 @@ class wpdb { continue; } - $truncate_by_byte_length = 'byte' === $value['length']['type']; - $needs_validation = true; if ( // latin1 can store any byte sequence @@ -2718,7 +2721,12 @@ class wpdb { $charset = $value['charset']; } - $queries[ $col ] = $this->prepare( "CONVERT( LEFT( CONVERT( %s USING $charset ), %.0f ) USING {$this->charset} )", $value['value'], $value['length']['length'] ); + if ( is_array( $value['length'] ) ) { + $queries[ $col ] = $this->prepare( "CONVERT( LEFT( CONVERT( %s USING $charset ), %.0f ) USING {$this->charset} )", $value['value'], $value['length']['length'] ); + } else if ( 'binary' !== $charset ) { + // If we don't have a length, there's no need to convert binary - it will always return the same result. + $queries[ $col ] = $this->prepare( "CONVERT( CONVERT( %s USING $charset ) USING {$this->charset} )", $value['value'] ); + } unset( $data[ $col ]['db'] ); } diff --git a/tests/phpunit/tests/db/charset.php b/tests/phpunit/tests/db/charset.php index 25d4d3adf4..45c7978419 100755 --- a/tests/phpunit/tests/db/charset.php +++ b/tests/phpunit/tests/db/charset.php @@ -214,6 +214,21 @@ class Tests_DB_Charset extends WP_UnitTestCase { 'expected' => "\xd8ord\xd0ress", 'length' => array( 'type' => 'char', 'length' => 100 ), ), + 'cp1251_no_length' => array( + 'charset' => 'cp1251', + 'value' => "\xd8ord\xd0ress", + 'expected' => "\xd8ord\xd0ress", + 'length' => false, + ), + 'cp1251_no_length_ascii' => array( + 'charset' => 'cp1251', + 'value' => "WordPress", + 'expected' => "WordPress", + 'length' => false, + // Don't set 'ascii' => true/false. + // That's a different codepath than it being unset even if + // three's only only ASCII in the value. + ), 'cp1251_char_length' => array( 'charset' => 'cp1251', 'value' => str_repeat( "\xd8\xd0", 10 ), @@ -807,4 +822,21 @@ class Tests_DB_Charset extends WP_UnitTestCase { $stripped = $wpdb->strip_invalid_text_for_column( $wpdb->comments, 'comment_agent', str_repeat( 'A', 256 ) ); $this->assertEquals( 255, strlen( $stripped ) ); } + + /** + * @ticket 32279 + */ + function test_strip_invalid_text_from_query_cp1251_is_safe() { + $tablename = 'test_cp1251_query_' . rand_str( 5 ); + if ( ! self::$_wpdb->query( "CREATE TABLE $tablename ( a VARCHAR(50) ) DEFAULT CHARSET 'cp1251'" ) ) { + $this->markTestSkipped( "Test requires the 'cp1251' charset" ); + } + + $safe_query = "INSERT INTO $tablename( `a` ) VALUES( 'safe data' )"; + $stripped_query = self::$_wpdb->strip_invalid_text_from_query( $safe_query ); + + self::$_wpdb->query( "DROP TABLE $tablename" ); + + $this->assertEquals( $safe_query, $stripped_query ); + } }