← All changes
|
wp-includes/database/mysql/class-wp-mysql-lexer.php
+23
-17
3.0.1
→
3.1.0
View file →
| @@ -41,9 +41,9 @@ | ||
| 41 | 41 | * |
| 42 | 42 | * These are intended to be used with "strspn()" and "strcspn()" functions |
| 43 | 43 | * for fast character class matching in the SQL payload. |
| 44 | 44 | */ |
| 45 | - const WHITESPACE_MASK = " \t\n\r\f"; | |
| 45 | + const WHITESPACE_MASK = " \t\n\r\f\v"; | |
| 46 | 46 | const DIGIT_MASK = '0123456789'; |
| 47 | 47 | const HEX_DIGIT_MASK = '0123456789abcdefABCDEF'; |
| 48 | 48 | |
| 49 | 49 | /** |
| @@ -2992,24 +2992,29 @@ | ||
| 2992 | 2992 | |
| 2993 | 2993 | private function read_mysql_comment(): int { |
| 2994 | 2994 | // @TODO: Consider supporting optimizer hints (/*+ ... */) or document |
| 2995 | 2995 | // that they are not supported. |
| 2996 | - // @TODO: Implement six-digit version number support (from MySQL 8.4). | |
| 2997 | 2996 | |
| 2998 | - // MySQL-specific comment in one of the following forms: | |
| 2999 | - // 1. /*! ... */ - The content is treated as SQL. | |
| 3000 | - // 2. /*!12345 ... */ - The content is treated as SQL when "MySQL version >= 12345". | |
| 2997 | + // MySQL-specific comments in the following forms: | |
| 2998 | + // 1. /*! ... */ - The content is treated as SQL. | |
| 2999 | + // 2. /*!80400 ... */ - SQL when the server version is at least 8.4.0. | |
| 3000 | + // 3. /*!080400 ... */ - The same version in six-digit form (MySQL 8.1+). | |
| 3001 | + // | |
| 3002 | + // See: https://dev.mysql.com/doc/refman/8.4/en/comments.html | |
| 3001 | 3003 | $this->bytes_already_read += 3; // Consume the '/*!'. |
| 3002 | 3004 | |
| 3003 | - // Check if the next 5 characters are digits. | |
| 3004 | - $digit_count = strspn( $this->sql, self::DIGIT_MASK, $this->bytes_already_read, 5 ); | |
| 3005 | - $is_version_comment = 5 === $digit_count; | |
| 3005 | + // Version has 5 digits (Mmmrr) or 6 digits (MMmmrr + whitespace, MySQL 8.1+). | |
| 3006 | + $digit_count = strspn( $this->sql, self::DIGIT_MASK, $this->bytes_already_read, 6 ); | |
| 3007 | + $version_length = $digit_count < 5 ? 0 : 5; | |
| 3008 | + if ( | |
| 3009 | + 6 === $digit_count | |
| 3010 | + && $this->mysql_version >= 80100 | |
| 3011 | + && 1 === strspn( $this->sql, self::WHITESPACE_MASK, $this->bytes_already_read + 6, 1 ) | |
| 3012 | + ) { | |
| 3013 | + $version_length = 6; | |
| 3014 | + } | |
| 3015 | + $version = (int) substr( $this->sql, $this->bytes_already_read, $version_length ); | |
| 3006 | 3016 | |
| 3007 | - // For version comments, extract the version number. | |
| 3008 | - $version = $is_version_comment | |
| 3009 | - ? (int) substr( $this->sql, $this->bytes_already_read, $digit_count ) | |
| 3010 | - : 0; | |
| 3011 | - | |
| 3012 | 3017 | if ( $this->mysql_version < $version ) { |
| 3013 | 3018 | // Version not satisfied. Treat the content as a regular comment. |
| 3014 | 3019 | $this->read_comment_content(); |
| 3015 | 3020 | return self::COMMENT; |
| @@ -3014,9 +3019,9 @@ | ||
| 3014 | 3019 | $this->read_comment_content(); |
| 3015 | 3020 | return self::COMMENT; |
| 3016 | 3021 | } else { |
| 3017 | 3022 | // Version satisfied or not specified. Treat the content as SQL code. |
| 3018 | - $this->bytes_already_read += $digit_count; // Skip the version number. | |
| 3023 | + $this->bytes_already_read += $version_length; // Skip the version number. | |
| 3019 | 3024 | $this->in_mysql_comment = true; |
| 3020 | 3025 | return self::MYSQL_COMMENT_START; |
| 3021 | 3026 | } |
| 3022 | 3027 | } |
| @@ -3077,13 +3082,14 @@ | ||
| 3077 | 3082 | } |
| 3078 | 3083 | |
| 3079 | 3084 | // Determine function calls. |
| 3080 | 3085 | if ( isset( self::FUNCTIONS[ $type ] ) ) { |
| 3081 | - // Skip any whitespace character if the SQL mode says they should be ignored. | |
| 3086 | + // Keep ignored whitespace outside the current token range. | |
| 3087 | + $peek = $this->bytes_already_read; | |
| 3082 | 3088 | if ( $this->is_sql_mode_active( self::SQL_MODE_IGNORE_SPACE ) ) { |
| 3083 | - $this->bytes_already_read += strspn( $this->sql, self::WHITESPACE_MASK, $this->bytes_already_read ); | |
| 3089 | + $peek += strspn( $this->sql, self::WHITESPACE_MASK, $peek ); | |
| 3084 | 3090 | } |
| 3085 | - if ( '(' !== ( $this->sql[ $this->bytes_already_read ] ?? null ) ) { | |
| 3091 | + if ( '(' !== ( $this->sql[ $peek ] ?? null ) ) { | |
| 3086 | 3092 | return self::IDENTIFIER; |
| 3087 | 3093 | } |
| 3088 | 3094 | } |
| 3089 | 3095 | |