Make WordPress Core


Ignore:
Timestamp:
10/31/2022 08:43:56 PM (2 years ago)
Author:
SergeyBiryukov
Message:

Database: Revert [53575].

When using '%%%s%%' pattern with $wpdb->prepare(), it works on 6.0.3 but does not on 6.1-RC. Why? The inserted value is wrapped in quotes on 6.1-RC5 whereas it is not on <= 6.0.3.

With 6.1 final release tomorrow, more time is needed to further investigate and test. Reverting this changeset to restore the previous behavior.

This commit also adds a dataset for testing the '%%%s%%' pattern.

Props SergeyBiryukov, hellofromTonya, bernhard-reiter, desrosj, davidbaumwald, jorbin.
Reviewed by hellofromTonya, SergeyBiryukov.
Merges [54733] to the 6.1 branch.
Fixes #56933.
See #52506.

Location:
branches/6.1
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/6.1

  • branches/6.1/tests/phpunit/tests/db.php

    r53670 r54734  
    495495        $this->assertTrue( $wpdb->has_cap( 'group_concat' ) );
    496496        $this->assertTrue( $wpdb->has_cap( 'subqueries' ) );
    497         $this->assertTrue( $wpdb->has_cap( 'identifier_placeholders' ) );
    498497        $this->assertTrue( $wpdb->has_cap( 'COLLATION' ) );
    499498        $this->assertTrue( $wpdb->has_cap( 'GROUP_CONCAT' ) );
    500499        $this->assertTrue( $wpdb->has_cap( 'SUBQUERIES' ) );
    501         $this->assertTrue( $wpdb->has_cap( 'IDENTIFIER_PLACEHOLDERS' ) );
    502500        $this->assertSame(
    503501            version_compare( $wpdb->db_version(), '5.0.7', '>=' ),
     
    17181716                "'{$placeholder_escape}'{$placeholder_escape}s 'hello'",
    17191717            ),
     1718            /*
     1719             * @ticket 56933.
     1720             * When preparing a '%%%s%%', test that the inserted value
     1721             * is not wrapped in single quotes between the 2 hex values.
     1722             */
     1723            array(
     1724                '%%%s%%',
     1725                'hello',
     1726                false,
     1727                "{$placeholder_escape}hello{$placeholder_escape}",
     1728            ),
    17201729            array(
    17211730                "'%-'#5s' '%'#-+-5s'",
     
    17241733                "'hello' 'foo##'",
    17251734            ),
    1726             array(
    1727                 'SELECT * FROM %i WHERE %i = %d;',
    1728                 array( 'my_table', 'my_field', 321 ),
    1729                 false,
    1730                 'SELECT * FROM `my_table` WHERE `my_field` = 321;',
    1731             ),
    1732             array(
    1733                 'WHERE %i = %d;',
    1734                 array( 'evil_`_field', 321 ),
    1735                 false,
    1736                 'WHERE `evil_``_field` = 321;', // To quote the identifier itself, then you need to double the character, e.g. `a``b`.
    1737             ),
    1738             array(
    1739                 'WHERE %i = %d;',
    1740                 array( 'evil_````````_field', 321 ),
    1741                 false,
    1742                 'WHERE `evil_````````````````_field` = 321;',
    1743             ),
    1744             array(
    1745                 'WHERE %i = %d;',
    1746                 array( '``evil_field``', 321 ),
    1747                 false,
    1748                 'WHERE `````evil_field````` = 321;',
    1749             ),
    1750             array(
    1751                 'WHERE %i = %d;',
    1752                 array( 'evil\'field', 321 ),
    1753                 false,
    1754                 'WHERE `evil\'field` = 321;',
    1755             ),
    1756             array(
    1757                 'WHERE %i = %d;',
    1758                 array( 'evil_\``_field', 321 ),
    1759                 false,
    1760                 'WHERE `evil_\````_field` = 321;',
    1761             ),
    1762             array(
    1763                 'WHERE %i = %d;',
    1764                 array( 'evil_%s_field', 321 ),
    1765                 false,
    1766                 "WHERE `evil_{$placeholder_escape}s_field` = 321;",
    1767             ),
    1768             array(
    1769                 'WHERE %i = %d;',
    1770                 array( 'value`', 321 ),
    1771                 false,
    1772                 'WHERE `value``` = 321;',
    1773             ),
    1774             array(
    1775                 'WHERE `%i = %d;',
    1776                 array( ' AND evil_value', 321 ),
    1777                 false,
    1778                 'WHERE `` AND evil_value` = 321;', // Won't run (SQL parse error: "Unclosed quote").
    1779             ),
    1780             array(
    1781                 'WHERE %i` = %d;',
    1782                 array( 'evil_value -- ', 321 ),
    1783                 false,
    1784                 'WHERE `evil_value -- `` = 321;', // Won't run (SQL parse error: "Unclosed quote").
    1785             ),
    1786             array(
    1787                 'WHERE `%i`` = %d;',
    1788                 array( ' AND true -- ', 321 ),
    1789                 false,
    1790                 'WHERE `` AND true -- ``` = 321;', // Won't run (Unknown column '').
    1791             ),
    1792             array(
    1793                 'WHERE ``%i` = %d;',
    1794                 array( ' AND true -- ', 321 ),
    1795                 false,
    1796                 'WHERE ``` AND true -- `` = 321;', // Won't run (SQL parse error: "Unclosed quote").
    1797             ),
    1798             array(
    1799                 'WHERE %2$i = %1$d;',
    1800                 array( '1', 'two' ),
    1801                 false,
    1802                 'WHERE `two` = 1;',
    1803             ),
    1804             array(
    1805                 'WHERE \'%i\' = 1 AND "%i" = 2 AND `%i` = 3 AND ``%i`` = 4 AND %15i = 5',
    1806                 array( 'my_field1', 'my_field2', 'my_field3', 'my_field4', 'my_field5' ),
    1807                 false,
    1808                 'WHERE \'`my_field1`\' = 1 AND "`my_field2`" = 2 AND ``my_field3`` = 3 AND ```my_field4``` = 4 AND `      my_field5` = 5', // Does not remove any existing quotes, always adds it's own (safer).
    1809             ),
    1810             array(
    1811                 'WHERE id = %d AND %i LIKE %2$s LIMIT 1',
    1812                 array( 123, 'field -- ', false ),
    1813                 true, // Incorrect usage.
    1814                 null, // Should be rejected, otherwise the `%1$s` could use Identifier escaping, e.g. 'WHERE `field -- ` LIKE field --  LIMIT 1' (thanks @vortfu).
    1815             ),
    1816             array(
    1817                 'WHERE %i LIKE %s LIMIT 1',
    1818                 array( "field' -- ", "field' -- " ),
    1819                 false,
    1820                 "WHERE `field' -- ` LIKE 'field\' -- ' LIMIT 1", // In contrast to the above, Identifier vs String escaping is used.
    1821             ),
    1822         );
    1823     }
    1824 
    1825     public function test_allow_unsafe_unquoted_parameters() {
    1826         global $wpdb;
    1827 
    1828         $sql    = 'WHERE (%i = %s) OR (%10i = %10s) OR (%5$i = %6$s)';
    1829         $values = array( 'field_a', 'string_a', 'field_b', 'string_b', 'field_c', 'string_c' );
    1830 
    1831         $default = $wpdb->allow_unsafe_unquoted_parameters;
    1832 
    1833         $wpdb->allow_unsafe_unquoted_parameters = true;
    1834 
    1835         // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    1836         $part = $wpdb->prepare( $sql, $values );
    1837         $this->assertSame( 'WHERE (`field_a` = \'string_a\') OR (`   field_b` =   string_b) OR (`field_c` = string_c)', $part ); // Unsafe, unquoted parameters.
    1838 
    1839         $wpdb->allow_unsafe_unquoted_parameters = false;
    1840 
    1841         // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
    1842         $part = $wpdb->prepare( $sql, $values );
    1843         $this->assertSame( 'WHERE (`field_a` = \'string_a\') OR (`   field_b` = \'  string_b\') OR (`field_c` = \'string_c\')', $part );
    1844 
    1845         $wpdb->allow_unsafe_unquoted_parameters = $default;
    1846 
     1735        );
    18471736    }
    18481737
Note: See TracChangeset for help on using the changeset viewer.