diff --git a/src/wp-includes/wp-db.php b/src/wp-includes/wp-db.php index 53ba207203..57c3bd76f6 100644 --- a/src/wp-includes/wp-db.php +++ b/src/wp-includes/wp-db.php @@ -2015,7 +2015,15 @@ class wpdb { // to flush again, just to make sure everything is clear. $this->flush(); if ( $stripped_query !== $query ) { - $this->insert_id = 0; + $this->insert_id = 0; + $this->last_query = $query; + + if ( function_exists( '__' ) ) { + $this->last_error = __( 'WordPress database error: Could not perform query because it contains invalid data.' ); + } else { + $this->last_error = 'WordPress database error: Could not perform query because it contains invalid data.'; + } + return false; } } @@ -2535,6 +2543,32 @@ class wpdb { $converted_data = $this->strip_invalid_text( $data ); if ( $data !== $converted_data ) { + + $problem_fields = array(); + foreach ( $data as $field => $value ) { + if ( $value !== $converted_data[ $field ] ) { + $problem_fields[] = $field; + } + } + + if ( 1 === count( $problem_fields ) ) { + if ( function_exists( '__' ) ) { + /* translators: %s Database field where the error occurred. */ + $message = __( 'WordPress database error: Processing the value for the following field failed: %s. The supplied value may be too long or contains invalid data.' ); + } else { + $message = 'WordPress database error: Processing the value for the following field failed: %s. The supplied value may be too long or contains invalid data.'; + } + } else { + if ( function_exists( '__' ) ) { + /* translators: %s Database fields where the error occurred. */ + $message = __( 'WordPress database error: Processing the value for the following fields failed: %s. The supplied value may be too long or contains invalid data.' ); + } else { + $message = 'WordPress database error: Processing the value for the following fields failed: %s. The supplied value may be too long or contains invalid data.'; + } + } + + $this->last_error = sprintf( $message, implode( ', ', $problem_fields ) ); + return false; } diff --git a/tests/phpunit/tests/db.php b/tests/phpunit/tests/db.php index e10de7126e..4ad6a2ad0a 100644 --- a/tests/phpunit/tests/db.php +++ b/tests/phpunit/tests/db.php @@ -33,6 +33,8 @@ class Tests_DB extends WP_UnitTestCase { parent::set_up(); $this->_queries = array(); add_filter( 'query', array( $this, 'query_filter' ) ); + self::$_wpdb->last_error = null; + $GLOBALS['wpdb']->last_error = null; } /** @@ -1095,6 +1097,164 @@ class Tests_DB extends WP_UnitTestCase { return 'fake_col_charset'; } + /** + * @dataProvider data_process_single_field_invalid_data + * @dataProvider data_process_multiple_fields_invalid_data + * + * @ticket 32315 + * + * @covers wpdb::process_fields + * + * @param array $data Data to process. + * @param string $errored_fields Expected fields in the error message. + */ + public function test_process_fields_value_too_long_for_field( array $data, $errored_fields ) { + global $wpdb; + + $this->assertFalse( self::$_wpdb->process_fields( $wpdb->posts, $data, null ) ); + $this->assertSame( $this->get_db_error_value_too_long( $errored_fields ), self::$_wpdb->last_error ); + } + + /** + * @dataProvider data_process_single_field_invalid_data + * + * @ticket 32315 + * + * @covers wpdb::insert + * + * @param array $data Data to process. + * @param string $errored_fields Expected fields in the error message. + */ + public function test_insert_value_too_long_for_field( array $data, $errored_fields ) { + global $wpdb; + + $this->assertFalse( $wpdb->insert( $wpdb->posts, $data ) ); + $this->assertSame( $this->get_db_error_value_too_long( $errored_fields ), $wpdb->last_error ); + } + + /** + * @dataProvider data_process_single_field_invalid_data + * + * @ticket 32315 + * + * @covers wpdb::replace + * + * @param array $data Data to process. + * @param string $errored_fields Expected fields in the error message. + */ + public function test_replace_value_too_long_for_field( array $data, $errored_fields ) { + global $wpdb; + + $this->assertFalse( $wpdb->replace( $wpdb->posts, $data ) ); + $this->assertSame( $this->get_db_error_value_too_long( $errored_fields ), $wpdb->last_error ); + } + + /** + * @dataProvider data_process_single_field_invalid_data + * + * @ticket 32315 + * + * @covers wpdb::update + * + * @param array $data Data to process. + * @param string $errored_fields Expected fields in the error message. + */ + public function test_update_value_too_long_for_field( array $data, $errored_fields ) { + global $wpdb; + + $this->assertFalse( $wpdb->update( $wpdb->posts, $data, array() ) ); + $this->assertSame( $this->get_db_error_value_too_long( $errored_fields ), $wpdb->last_error ); + } + + /** + * @dataProvider data_process_single_field_invalid_data + * + * @ticket 32315 + * + * @covers wpdb::delete + * + * @param array $data Data to process. + * @param string $errored_fields Expected fields in the error message. + */ + public function test_delete_value_too_long_for_field( array $data, $errored_fields ) { + global $wpdb; + + $this->assertFalse( $wpdb->delete( $wpdb->posts, $data, array() ) ); + $this->assertSame( $this->get_db_error_value_too_long( $errored_fields ), $wpdb->last_error ); + } + + /** + * Assert the error message matches the fields. + * + * @param string $errored_fields Expected fields in the error message. + */ + private function get_db_error_value_too_long( $errored_fields ) { + return sprintf( + 'WordPress database error: Processing the value for the following field%s failed: %s. ' . + 'The supplied value may be too long or contains invalid data.', + str_contains( $errored_fields, ', ' ) ? 's' : '', + $errored_fields + ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_process_single_field_invalid_data() { + return array( + 'too long' => array( + 'data' => array( 'post_status' => str_repeat( 'a', 21 ) ), + 'errored_fields' => 'post_status', + ), + 'invalid chars' => array( + 'data' => array( 'post_status' => "\xF5" ), + 'errored_fields' => 'post_status', + ), + ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_process_multiple_fields_invalid_data() { + return array( + 'too long' => array( + 'data' => array( + 'post_status' => str_repeat( 'a', 21 ), + 'post_content' => "\xF5", + ), + 'errored_fields' => 'post_status, post_content', + ), + 'invalid chars' => array( + 'data' => array( + 'post_status' => "\xF5", + 'post_name' => str_repeat( "\xF5", 21 ), + ), + 'errored_fields' => 'post_status, post_name', + ), + ); + } + + /** + * @ticket 32315 + */ + public function test_query_value_contains_invalid_chars() { + global $wpdb; + + $this->assertFalse( + $wpdb->query( "INSERT INTO {$wpdb->posts} (post_status) VALUES ('\xF5')" ) + ); + + $this->assertSame( + 'WordPress database error: Could not perform query because it contains invalid data.', + $wpdb->last_error + ); + } + /** * @ticket 15158 */