Make WordPress Core

Ticket #53623: 53623.diff

File 53623.diff, 9.4 KB (added by SergeyBiryukov, 23 months ago)
  • src/wp-includes/class-wpdb.php

     
    33763376                }
    33773377
    33783378                // If any of the columns don't have one of these collations, it needs more sanity checking.
     3379                $safe_collations = array(
     3380                        'utf8_bin',
     3381                        'utf8_general_ci',
     3382                        'utf8mb3_bin',
     3383                        'utf8mb3_general_ci',
     3384                        'utf8mb4_bin',
     3385                        'utf8mb4_general_ci',
     3386                );
     3387
    33793388                foreach ( $this->col_meta[ $table ] as $col ) {
    33803389                        if ( empty( $col->Collation ) ) {
    33813390                                continue;
    33823391                        }
    33833392
    3384                         if ( ! in_array( $col->Collation, array( 'utf8_general_ci', 'utf8_bin', 'utf8mb4_general_ci', 'utf8mb4_bin' ), true ) ) {
     3393                        if ( ! in_array( $col->Collation, $safe_collations, true ) ) {
    33853394                                return false;
    33863395                        }
    33873396                }
  • tests/phpunit/tests/db/charset.php

     
    99class Tests_DB_Charset extends WP_UnitTestCase {
    1010
    1111        /**
    12          * Our special WPDB
     12         * Our special WPDB.
    1313         *
    1414         * @var resource
    1515         */
     
    1616        protected static $_wpdb;
    1717
    1818        /**
    19          * The version of the MySQL server.
     19         * Whether to expect utf8mb3 instead of utf8 in various commands output.
    2020         *
     21         * @var bool
     22         */
     23        private static $utf8_is_utf8mb3 = false;
     24
     25        /**
     26         * The database server version.
     27         *
    2128         * @var string
    2229         */
    23         private static $server_info;
     30        private static $db_version;
    2431
     32        /**
     33         * Full database server information.
     34         *
     35         * @var string
     36         */
     37        private static $db_server_info;
     38
    2539        public static function set_up_before_class() {
    2640                parent::set_up_before_class();
    2741
     
    2943
    3044                self::$_wpdb = new WpdbExposedMethodsForTesting();
    3145
    32                 self::$server_info = self::$_wpdb->db_server_info();
     46                self::$db_version     = self::$_wpdb->db_version();
     47                self::$db_server_info = self::$_wpdb->db_server_info();
     48
     49                /*
     50                 * MariaDB 10.6.1 or later and MySQL 8.0.30 or later
     51                 * use utf8mb3 instead of utf8 in various commands output.
     52                 */
     53                if ( str_contains( self::$db_server_info, 'MariaDB' ) && version_compare( self::$db_version, '10.6.1', '>=' )
     54                        || ! str_contains( self::$db_server_info, 'MariaDB' ) && version_compare( self::$db_version, '8.0.30', '>=' )
     55                ) {
     56                        self::$utf8_is_utf8mb3 = true;
     57                }
    3358        }
    3459
    3560        /**
     
    492517                        $this->markTestSkipped( "The current MySQL server doesn't support the utf8mb4 character set." );
    493518                }
    494519
    495                 if ( 'big5' === $new_charset && 'byte' === $data[0]['length']['type'] && false !== strpos( self::$server_info, 'MariaDB' ) ) {
     520                if ( 'big5' === $new_charset && 'byte' === $data[0]['length']['type']
     521                        && str_contains( self::$db_server_info, 'MariaDB' )
     522                ) {
    496523                        $this->markTestSkipped( "MariaDB doesn't support this data set. See https://core.trac.wordpress.org/ticket/33171." );
    497524                }
    498525
     
    808835                self::$_wpdb->query( $create );
    809836
    810837                foreach ( $expected_charset as $column => $charset ) {
     838                        if ( self::$utf8_is_utf8mb3 && 'utf8' === $charset ) {
     839                                $charset = 'utf8mb3';
     840                        }
     841
    811842                        $this->assertSame( $charset, self::$_wpdb->get_col_charset( $table, $column ) );
    812843                        $this->assertSame( $charset, self::$_wpdb->get_col_charset( strtoupper( $table ), strtoupper( $column ) ) );
    813844                }
     
    875906        public function data_strip_invalid_text_from_query() {
    876907                $table_name = 'strip_invalid_text_from_query_table';
    877908                $data       = array(
    878                         array(
     909                        'utf8 + binary'  => array(
    879910                                // Binary tables don't get stripped.
    880                                 '( a VARCHAR(50) CHARACTER SET utf8, b BINARY )', // Create.
    881                                 "('foo\xf0\x9f\x98\x88bar', 'foo')",              // Query.
    882                                 "('foo\xf0\x9f\x98\x88bar', 'foo')",              // Expected result.
     911                                'create'   => '( a VARCHAR(50) CHARACTER SET utf8, b BINARY )',
     912                                'query'    => "('foo\xf0\x9f\x98\x88bar', 'foo')",
     913                                'expected' => "('foo\xf0\x9f\x98\x88bar', 'foo')",
    883914                        ),
    884                         array(
     915                        'utf8 + utf8mb4' => array(
    885916                                // utf8/utf8mb4 tables default to utf8.
    886                                 '( a VARCHAR(50) CHARACTER SET utf8, b VARCHAR(50) CHARACTER SET utf8mb4 )',
    887                                 "('foo\xf0\x9f\x98\x88bar', 'foo')",
    888                                 "('foobar', 'foo')",
     917                                'create'   => '( a VARCHAR(50) CHARACTER SET utf8, b VARCHAR(50) CHARACTER SET utf8mb4 )',
     918                                'query'    => "('foo\xf0\x9f\x98\x88bar', 'foo')",
     919                                'expected' => "('foobar', 'foo')",
    889920                        ),
    890921                );
    891922
    892                 foreach ( $data as $i => &$value ) {
    893                         $this_table_name = $table_name . '_' . $i;
     923                $i = 0;
    894924
    895                         $value[0] = "CREATE TABLE $this_table_name {$value[0]}";
    896                         $value[1] = "INSERT INTO $this_table_name VALUES {$value[1]}";
    897                         $value[2] = "INSERT INTO $this_table_name VALUES {$value[2]}";
    898                         $value[3] = "DROP TABLE IF EXISTS $this_table_name";
     925                foreach ( $data as &$value ) {
     926                        $this_table_name = $table_name . '_' . $i++;
     927
     928                        $value['create']   = "CREATE TABLE $this_table_name {$value['create']}";
     929                        $value['query']    = "INSERT INTO $this_table_name VALUES {$value['query']}";
     930                        $value['expected'] = "INSERT INTO $this_table_name VALUES {$value['expected']}";
     931                        $value['drop']     = "DROP TABLE IF EXISTS $this_table_name";
    899932                }
    900933                unset( $value );
    901934
     
    9791012        public function data_table_collation_check() {
    9801013                $table_name = 'table_collation_check';
    9811014                $data       = array(
    982                         array(
     1015                        'utf8_bin'                   => array(
    9831016                                // utf8_bin tables don't need extra sanity checking.
    984                                 '( a VARCHAR(50) COLLATE utf8_bin )', // Create.
    985                                 true,                                 // Expected result.
     1017                                'create'   => '( a VARCHAR(50) COLLATE utf8_bin )',
     1018                                'expected' => true,
    9861019                        ),
    987                         array(
     1020                        'utf8_general_ci'            => array(
    9881021                                // Neither do utf8_general_ci tables.
    989                                 '( a VARCHAR(50) COLLATE utf8_general_ci )',
    990                                 true,
     1022                                'create'   => '( a VARCHAR(50) COLLATE utf8_general_ci )',
     1023                                'expected' => true,
    9911024                        ),
    992                         array(
     1025                        'utf8_unicode_ci'            => array(
    9931026                                // utf8_unicode_ci tables do.
    994                                 '( a VARCHAR(50) COLLATE utf8_unicode_ci )',
    995                                 false,
     1027                                'create'   => '( a VARCHAR(50) COLLATE utf8_unicode_ci )',
     1028                                'expected' => false,
    9961029                        ),
    997                         array(
     1030                        'utf8_bin + big5_chinese_ci' => array(
    9981031                                // utf8_bin tables don't need extra sanity checking,
    9991032                                // except for when they're not just utf8_bin.
    1000                                 '( a VARCHAR(50) COLLATE utf8_bin, b VARCHAR(50) COLLATE big5_chinese_ci )',
    1001                                 false,
     1033                                'create'   => '( a VARCHAR(50) COLLATE utf8_bin, b VARCHAR(50) COLLATE big5_chinese_ci )',
     1034                                'expected' => false,
    10021035                        ),
    1003                         array(
     1036                        'utf8_bin + int'             => array(
    10041037                                // utf8_bin tables don't need extra sanity checking
    10051038                                // when the other columns aren't strings.
    1006                                 '( a VARCHAR(50) COLLATE utf8_bin, b INT )',
    1007                                 true,
     1039                                'create'   => '( a VARCHAR(50) COLLATE utf8_bin, b INT )',
     1040                                'expected' => true,
    10081041                        ),
    10091042                );
    10101043
    1011                 foreach ( $data as $i => &$value ) {
    1012                         $this_table_name = $table_name . '_' . $i;
     1044                $i = 0;
    10131045
    1014                         $value[0] = "CREATE TABLE $this_table_name {$value[0]}";
    1015                         $value[2] = "SELECT * FROM $this_table_name WHERE a='\xf0\x9f\x98\x88'";
    1016                         $value[3] = "DROP TABLE IF EXISTS $this_table_name";
    1017                         $value[4] = array(
     1046                foreach ( $data as &$value ) {
     1047                        $this_table_name = $table_name . '_' . $i++;
     1048
     1049                        $value['create']      = "CREATE TABLE $this_table_name {$value['create']}";
     1050                        $value['query']       = "SELECT * FROM $this_table_name WHERE a='\xf0\x9f\x98\x88'";
     1051                        $value['drop']        = "DROP TABLE IF EXISTS $this_table_name";
     1052                        $value['always_true'] = array(
    10181053                                "SELECT * FROM $this_table_name WHERE a='foo'",
    10191054                                "SHOW FULL TABLES LIKE $this_table_name",
    10201055                                "DESCRIBE $this_table_name",
     
    10401075                self::$_wpdb->query( $create );
    10411076
    10421077                $return = self::$_wpdb->check_safe_collation( $query );
    1043                 $this->assertSame( $expected, $return );
     1078                $this->assertSame(
     1079                        $expected,
     1080                        $return,
     1081                        sprintf(
     1082                                "wpdb::check_safe_collation() should return %s for this query.\n" .
     1083                                "Table: %s\n" .
     1084                                'Query: %s',
     1085                                $expected ? 'true' : 'false',
     1086                                $create,
     1087                                $query
     1088                        )
     1089                );
    10441090
    10451091                foreach ( $always_true as $true_query ) {
    10461092                        $return = self::$_wpdb->check_safe_collation( $true_query );
    1047                         $this->assertTrue( $return );
     1093                        $this->assertTrue(
     1094                                $return,
     1095                                sprintf(
     1096                                        "wpdb::check_safe_collation() should return true for this query.\n" .
     1097                                        "Table: %s\n" .
     1098                                        'Query: %s',
     1099                                        $create,
     1100                                        $true_query
     1101                                )
     1102                        );
    10481103                }
    10491104
    10501105                self::$_wpdb->query( $drop );
     
    11151170         */
    11161171        public function test_set_charset_changes_the_connection_collation() {
    11171172                self::$_wpdb->set_charset( self::$_wpdb->dbh, 'utf8', 'utf8_general_ci' );
    1118                 $results = self::$_wpdb->get_results( "SHOW VARIABLES WHERE Variable_name='collation_connection'" );
    1119                 $this->assertSame( 'utf8_general_ci', $results[0]->Value );
     1173                $results  = self::$_wpdb->get_results( "SHOW VARIABLES WHERE Variable_name='collation_connection'" );
     1174                $expected = self::$utf8_is_utf8mb3 ? 'utf8mb3_general_ci' : 'utf8_general_ci';
     1175                $this->assertSame( $expected, $results[0]->Value, "Collation should be set to $expected." );
    11201176
    11211177                self::$_wpdb->set_charset( self::$_wpdb->dbh, 'utf8mb4', 'utf8mb4_unicode_ci' );
    11221178                $results = self::$_wpdb->get_results( "SHOW VARIABLES WHERE Variable_name='collation_connection'" );
    1123                 $this->assertSame( 'utf8mb4_unicode_ci', $results[0]->Value );
     1179                $this->assertSame( 'utf8mb4_unicode_ci', $results[0]->Value, 'Collation should be set to utf8mb4_unicode_ci.' );
    11241180
    11251181                self::$_wpdb->set_charset( self::$_wpdb->dbh );
    11261182        }