Make WordPress Core

Changeset 52370


Ignore:
Timestamp:
12/14/2021 02:59:33 PM (3 years ago)
Author:
hellofromTonya
Message:

Formatting: Use is_scalar() in sanitize_key().

This is a follow-up to [52292] which introduced is_string() to check the given key is a string to be sanitized, else the key is set to an empty string.

sanitize_key() is clearly identified (in the documentation) to only work with string keys. However, it had a bug in it that allowed non-strings to pass through it:

  • A non-scalar "key" would throw a PHP Warning (which was resolved in [52292].
  • A non-string scalar "key" was handled by the PHP native strtolower() which converted it into a string.

While is_string() is valid, non-string scalar types passed as the key to be sanitized were being set to an empty string. Given that strtolower() handles these without error or deprecation as of PHP 8.1, is_scalar() protects the website from issues while retaining the past behavior of converting integer keys (for example) into a string.

Changes include:

  • Using is_scalar() instead of is_string()
  • Refactor for readability and less code
  • More tests

Please note, this does not change the behavior of the function, nor redefine it to now accept non-string scalars.

References:

Follow-up [52292].

Props wppunk, hellofromTonya, costdev, jrf.
Fixes #54160.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/formatting.php

    r52332 r52370  
    21332133 * @since 3.0.0
    21342134 *
    2135  * @param string $key String key
    2136  * @return string Sanitized key
     2135 * @param string $key String key.
     2136 * @return string Sanitized key.
    21372137 */
    21382138function sanitize_key( $key ) {
    2139     $raw_key = $key;
    2140 
    2141     if ( ! is_string( $key ) ) {
    2142         $key = '';
    2143     }
    2144 
    2145     if ( '' !== $key ) {
    2146         $key = strtolower( $key );
    2147         $key = preg_replace( '/[^a-z0-9_\-]/', '', $key );
     2139    $sanitized_key = '';
     2140
     2141    if ( is_scalar( $key ) ) {
     2142        $sanitized_key = strtolower( $key );
     2143        $sanitized_key = preg_replace( '/[^a-z0-9_\-]/', '', $sanitized_key );
    21482144    }
    21492145
     
    21532149     * @since 3.0.0
    21542150     *
    2155      * @param string $key    Sanitized key.
    2156      * @param string $raw_key The key prior to sanitization.
     2151     * @param string $sanitized_key Sanitized key.
     2152     * @param string $key          The key prior to sanitization.
    21572153     */
    2158     return apply_filters( 'sanitize_key', $key, $raw_key );
     2154    return apply_filters( 'sanitize_key', $sanitized_key, $key );
    21592155}
    21602156
  • trunk/tests/phpunit/tests/formatting/sanitizeKey.php

    r52292 r52370  
    88
    99    /**
    10      * @ticket 54160
     10     * @ticket       54160
    1111     * @dataProvider data_sanitize_key
    1212     *
    13      * @param mixed $key       The key to sanitize.
    14      * @param mixed $expected The expected value.
     13     * @param string $key      The key to sanitize.
     14     * @param string $expected The expected value.
    1515     */
    1616    public function test_sanitize_key( $key, $expected ) {
     
    1818    }
    1919
     20    /**
     21     * Data provider.
     22     *
     23     * @return array
     24     */
    2025    public function data_sanitize_key() {
    2126        return array(
    2227            'an empty string key'            => array(
    2328                'key'      => '',
    24                 'expected' => '',
    25             ),
    26             'a null key'                     => array(
    27                 'key'      => null,
    28                 'expected' => '',
    29             ),
    30             'an int 0 key'                   => array(
    31                 'key'      => 0,
    32                 'expected' => '',
    33             ),
    34             'a true key'                     => array(
    35                 'key'      => true,
    36                 'expected' => '',
    37             ),
    38             'an array key'                   => array(
    39                 'key'      => array( 'Howdy, admin!' ),
    4029                'expected' => '',
    4130            ),
     
    7261
    7362    /**
    74      * @ticket 54160
     63     * @ticket       54160
     64     * @dataProvider data_sanitize_key_nonstring_scalar
    7565     *
    76      * @covers WP_Hook::sanitize_key
     66     * @param mixed  $key      The key to sanitize.
     67     * @param string $expected The expected value.
    7768     */
    78     public function test_filter_sanitize_key() {
    79         $key = 'Howdy, admin!';
     69    public function test_sanitize_key_nonstring_scalar( $key, $expected ) {
     70        $this->assertSame( $expected, sanitize_key( $key ) );
     71    }
    8072
     73    /**
     74     * Data provider.
     75     *
     76     * @return array
     77     */
     78    public function data_sanitize_key_nonstring_scalar() {
     79        return array(
     80            'integer type'  => array(
     81                'key'      => 0,
     82                'expected' => '0',
     83            ),
     84            'boolean true'  => array(
     85                'key'      => true,
     86                'expected' => '1',
     87            ),
     88            'boolean false' => array(
     89                'key'      => false,
     90                'expected' => '',
     91            ),
     92            'float type'    => array(
     93                'key'      => 0.123,
     94                'expected' => '0123',
     95            ),
     96        );
     97    }
     98
     99    /**
     100     * @ticket       54160
     101     * @dataProvider data_sanitize_key_with_non_scalars
     102     *
     103     * @param mixed $nonscalar_key A non-scalar data type given as a key.
     104     */
     105    public function test_sanitize_key_with_non_scalars( $nonscalar_key ) {
    81106        add_filter(
    82107            'sanitize_key',
    83             static function( $key ) {
    84                 return 'Howdy, admin!';
    85             }
     108            function ( $sanitized_key, $key ) use ( $nonscalar_key ) {
     109                $this->assertEmpty( $sanitized_key, 'Empty string not passed as first filtered argument' );
     110                $this->assertSame( $nonscalar_key, $key, 'Given unsanitized key not passed as second filtered argument' );
     111                return $sanitized_key;
     112            },
     113            10,
     114            2
    86115        );
     116        $this->assertEmpty( sanitize_key( $nonscalar_key ), 'Non-scalar key did not return empty string' );
     117    }
    87118
    88         $this->assertSame( $key, sanitize_key( $key ) );
     119    /**
     120     * Data provider.
     121     *
     122     * @return array
     123     */
     124    public function data_sanitize_key_with_non_scalars() {
     125        return array(
     126            'array type' => array(
     127                'key'      => array( 'key' ),
     128                'expected' => '',
     129            ),
     130            'null'       => array(
     131                'key'      => null,
     132                'expected' => '',
     133            ),
     134            'object'     => array(
     135                'key'      => new stdClass(),
     136                'expected' => '',
     137            ),
     138        );
    89139    }
    90140}
Note: See TracChangeset for help on using the changeset viewer.