Changeset 55151 for trunk/tests/phpunit/tests/db.php
- Timestamp:
- 01/27/2023 06:47:53 PM (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/tests/phpunit/tests/db.php
r54733 r55151 495 495 $this->assertTrue( $wpdb->has_cap( 'group_concat' ) ); 496 496 $this->assertTrue( $wpdb->has_cap( 'subqueries' ) ); 497 $this->assertTrue( $wpdb->has_cap( 'identifier_placeholders' ) ); 497 498 $this->assertTrue( $wpdb->has_cap( 'COLLATION' ) ); 498 499 $this->assertTrue( $wpdb->has_cap( 'GROUP_CONCAT' ) ); 499 500 $this->assertTrue( $wpdb->has_cap( 'SUBQUERIES' ) ); 501 $this->assertTrue( $wpdb->has_cap( 'IDENTIFIER_PLACEHOLDERS' ) ); 500 502 $this->assertSame( 501 503 version_compare( $wpdb->db_version(), '5.0.7', '>=' ), … … 1516 1518 global $wpdb; 1517 1519 1518 if ( $incorrect_usage ) {1520 if ( is_string( $incorrect_usage ) || true === $incorrect_usage ) { 1519 1521 $this->setExpectedIncorrectUsage( 'wpdb::prepare' ); 1520 1522 } … … 1526 1528 // phpcs:ignore WordPress.DB.PreparedSQL 1527 1529 $sql = $wpdb->prepare( $sql, ...$values ); 1528 $this->assertSame( $expected, $sql ); 1530 $this->assertSame( $expected, $sql, 'The expected SQL does not match' ); 1531 1532 if ( is_string( $incorrect_usage ) && array_key_exists( 'wpdb::prepare', $this->caught_doing_it_wrong ) ) { 1533 $this->assertStringContainsString( $incorrect_usage, $this->caught_doing_it_wrong['wpdb::prepare'], 'The "_doing_it_wrong" message does not match' ); 1534 } 1529 1535 } 1530 1536 … … 1535 1541 global $wpdb; 1536 1542 1537 if ( $incorrect_usage ) {1543 if ( is_string( $incorrect_usage ) || true === $incorrect_usage ) { 1538 1544 $this->setExpectedIncorrectUsage( 'wpdb::prepare' ); 1539 1545 } … … 1545 1551 // phpcs:ignore WordPress.DB.PreparedSQL 1546 1552 $sql = $wpdb->prepare( $sql, $values ); 1547 $this->assertSame( $expected, $sql ); 1553 $this->assertSame( $expected, $sql, 'The expected SQL does not match' ); 1554 1555 if ( is_string( $incorrect_usage ) && array_key_exists( 'wpdb::prepare', $this->caught_doing_it_wrong ) ) { 1556 $this->assertStringContainsString( $incorrect_usage, $this->caught_doing_it_wrong['wpdb::prepare'], 'The "_doing_it_wrong" message does not match' ); 1557 } 1548 1558 } 1549 1559 … … 1704 1714 "'{$placeholder_escape}'{$placeholder_escape}s", 1705 1715 ), 1706 array( 1707 "'%'%%s%s", 1708 'hello', 1709 false, 1710 "'{$placeholder_escape}'{$placeholder_escape}s'hello'", 1711 ), 1712 array( 1713 "'%'%%s %s", 1714 'hello', 1715 false, 1716 "'{$placeholder_escape}'{$placeholder_escape}s 'hello'", 1717 ), 1716 1718 1717 /* 1719 1718 * @ticket 56933. 1720 1719 * When preparing a '%%%s%%', test that the inserted value 1721 * is not wrapped in single quotes between the 2 hex values.1720 * is not wrapped in single quotes between the 2 "%". 1722 1721 */ 1722 array( 1723 '%%s %d', 1724 1, 1725 false, 1726 "{$placeholder_escape}s 1", 1727 ), 1728 array( 1729 '%%%s', 1730 'hello', 1731 false, 1732 "{$placeholder_escape}hello", 1733 ), 1734 array( 1735 '%%%%s', 1736 'hello', 1737 false, 1738 "{$placeholder_escape}{$placeholder_escape}s", 1739 ), 1740 array( 1741 '%%%%%s', 1742 'hello', 1743 false, 1744 "{$placeholder_escape}{$placeholder_escape}hello", 1745 ), 1723 1746 array( 1724 1747 '%%%s%%', … … 1728 1751 ), 1729 1752 array( 1753 "'%'%%s%s", 1754 'hello', 1755 false, 1756 "'{$placeholder_escape}'{$placeholder_escape}s'hello'", 1757 ), 1758 array( 1759 "'%'%%s %s", 1760 'hello', 1761 false, 1762 "'{$placeholder_escape}'{$placeholder_escape}s 'hello'", 1763 ), 1764 array( 1730 1765 "'%-'#5s' '%'#-+-5s'", 1731 1766 array( 'hello', 'foo' ), … … 1733 1768 "'hello' 'foo##'", 1734 1769 ), 1770 1771 /* 1772 * Before WP 6.2 the "force floats to be locale-unaware" RegEx didn't 1773 * convert "%%%f" to "%%%F" (note the uppercase F). 1774 * This was because it didn't check to see if the leading "%" was escaped. 1775 * And because the "Escape any unescaped percents" RegEx used "[sdF]" in its 1776 * negative lookahead assertion, when there was an odd number of "%", it added 1777 * an extra "%", to give the fully escaped "%%%%f" (not a placeholder). 1778 */ 1779 array( 1780 '%f OR id = %d', 1781 array( 3, 5 ), 1782 false, 1783 '3.000000 OR id = 5', 1784 ), 1785 array( 1786 '%%f OR id = %d', 1787 array( 5 ), 1788 false, 1789 "{$placeholder_escape}f OR id = 5", 1790 ), 1791 array( 1792 '%%%f OR id = %d', 1793 array( 5 ), 1794 false, 1795 "{$placeholder_escape}{$placeholder_escape}f OR id = 5", 1796 ), 1797 array( 1798 '%%%%f OR id = %d', 1799 array( 5 ), 1800 false, 1801 "{$placeholder_escape}{$placeholder_escape}f OR id = 5", 1802 ), 1803 array( 1804 "WHERE id = %d AND content LIKE '%.4f'", 1805 array( 1, 2 ), 1806 false, 1807 "WHERE id = 1 AND content LIKE '2.0000'", 1808 ), 1809 array( 1810 "WHERE id = %d AND content LIKE '%%.4f'", 1811 array( 1 ), 1812 false, 1813 "WHERE id = 1 AND content LIKE '{$placeholder_escape}.4f'", 1814 ), 1815 array( 1816 "WHERE id = %d AND content LIKE '%%%.4f'", 1817 array( 1 ), 1818 false, 1819 "WHERE id = 1 AND content LIKE '{$placeholder_escape}{$placeholder_escape}.4f'", 1820 ), 1821 array( 1822 "WHERE id = %d AND content LIKE '%%%%.4f'", 1823 array( 1 ), 1824 false, 1825 "WHERE id = 1 AND content LIKE '{$placeholder_escape}{$placeholder_escape}.4f'", 1826 ), 1827 array( 1828 "WHERE id = %d AND content LIKE '%%%%%.4f'", 1829 array( 1 ), 1830 false, 1831 "WHERE id = 1 AND content LIKE '{$placeholder_escape}{$placeholder_escape}{$placeholder_escape}.4f'", 1832 ), 1833 array( 1834 '%.4f', 1835 array( 1 ), 1836 false, 1837 '1.0000', 1838 ), 1839 array( 1840 '%.4f OR id = %d', 1841 array( 1, 5 ), 1842 false, 1843 '1.0000 OR id = 5', 1844 ), 1845 array( 1846 '%%.4f OR id = %d', 1847 array( 5 ), 1848 false, 1849 "{$placeholder_escape}.4f OR id = 5", 1850 ), 1851 array( 1852 '%%%.4f OR id = %d', 1853 array( 5 ), 1854 false, 1855 "{$placeholder_escape}{$placeholder_escape}.4f OR id = 5", 1856 ), 1857 array( 1858 '%%%%.4f OR id = %d', 1859 array( 5 ), 1860 false, 1861 "{$placeholder_escape}{$placeholder_escape}.4f OR id = 5", 1862 ), 1863 array( 1864 '%%%%%.4f OR id = %d', 1865 array( 5 ), 1866 false, 1867 "{$placeholder_escape}{$placeholder_escape}{$placeholder_escape}.4f OR id = 5", 1868 ), 1869 1870 /* 1871 * @ticket 52506. 1872 * Adding an escape method for Identifiers (e.g. table/field names). 1873 */ 1874 array( 1875 'SELECT * FROM %i WHERE %i = %d;', 1876 array( 'my_table', 'my_field', 321 ), 1877 false, 1878 'SELECT * FROM `my_table` WHERE `my_field` = 321;', 1879 ), 1880 array( 1881 'WHERE %i = %d;', 1882 array( 'evil_`_field', 321 ), 1883 false, 1884 'WHERE `evil_``_field` = 321;', // To quote the identifier itself, then you need to double the character, e.g. `a``b`. 1885 ), 1886 array( 1887 'WHERE %i = %d;', 1888 array( 'evil_````````_field', 321 ), 1889 false, 1890 'WHERE `evil_````````````````_field` = 321;', 1891 ), 1892 array( 1893 'WHERE %i = %d;', 1894 array( '``evil_field``', 321 ), 1895 false, 1896 'WHERE `````evil_field````` = 321;', 1897 ), 1898 array( 1899 'WHERE %i = %d;', 1900 array( 'evil\'field', 321 ), 1901 false, 1902 'WHERE `evil\'field` = 321;', 1903 ), 1904 array( 1905 'WHERE %i = %d;', 1906 array( 'evil_\``_field', 321 ), 1907 false, 1908 'WHERE `evil_\````_field` = 321;', 1909 ), 1910 array( 1911 'WHERE %i = %d;', 1912 array( 'evil_%s_field', 321 ), 1913 false, 1914 "WHERE `evil_{$placeholder_escape}s_field` = 321;", 1915 ), 1916 array( 1917 'WHERE %i = %d;', 1918 array( 'value`', 321 ), 1919 false, 1920 'WHERE `value``` = 321;', 1921 ), 1922 array( 1923 'WHERE `%i = %d;', 1924 array( ' AND evil_value', 321 ), 1925 false, 1926 'WHERE `` AND evil_value` = 321;', // Won't run (SQL parse error: "Unclosed quote"). 1927 ), 1928 array( 1929 'WHERE %i` = %d;', 1930 array( 'evil_value -- ', 321 ), 1931 false, 1932 'WHERE `evil_value -- `` = 321;', // Won't run (SQL parse error: "Unclosed quote"). 1933 ), 1934 array( 1935 'WHERE `%i`` = %d;', 1936 array( ' AND true -- ', 321 ), 1937 false, 1938 'WHERE `` AND true -- ``` = 321;', // Won't run (Unknown column ''). 1939 ), 1940 array( 1941 'WHERE ``%i` = %d;', 1942 array( ' AND true -- ', 321 ), 1943 false, 1944 'WHERE ``` AND true -- `` = 321;', // Won't run (SQL parse error: "Unclosed quote"). 1945 ), 1946 array( 1947 'WHERE %2$i = %1$d;', 1948 array( '1', 'two' ), 1949 false, 1950 'WHERE `two` = 1;', 1951 ), 1952 array( 1953 'WHERE \'%i\' = 1 AND "%i" = 2 AND `%i` = 3 AND ``%i`` = 4 AND %15i = 5', 1954 array( 'my_field1', 'my_field2', 'my_field3', 'my_field4', 'my_field5' ), 1955 false, 1956 '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). 1957 ), 1958 array( 1959 'WHERE id = %d AND %i LIKE %2$s LIMIT 1', 1960 array( 123, 'field -- ', false ), 1961 'Arguments cannot be prepared as both an Identifier and Value. Found the following conflicts: %i and %2$s', 1962 null, // Should be rejected, otherwise the `%1$s` could use Identifier escaping, e.g. 'WHERE `field -- ` LIKE field -- LIMIT 1' (thanks @vortfu). 1963 ), 1964 array( 1965 'WHERE %i LIKE %s LIMIT 1', 1966 array( "field' -- ", "field' -- " ), 1967 false, 1968 "WHERE `field' -- ` LIKE 'field\' -- ' LIMIT 1", // In contrast to the above, Identifier vs String escaping is used. 1969 ), 1970 array( 1971 'WHERE %2$i IN ( %s , %s ) LIMIT 1', 1972 array( 'a', 'b' ), 1973 'Arguments cannot be prepared as both an Identifier and Value. Found the following conflicts: %2$i and %s', 1974 null, 1975 ), 1976 array( 1977 'WHERE %1$i = %1$s', 1978 array( 'a', 'b' ), 1979 'Arguments cannot be prepared as both an Identifier and Value. Found the following conflicts: %1$i and %1$s', 1980 null, 1981 ), 1982 array( 1983 'WHERE %1$i = %1$s OR %2$i = %2$s', 1984 array( 'a', 'b' ), 1985 'Arguments cannot be prepared as both an Identifier and Value. Found the following conflicts: %1$i and %1$s, %2$i and %2$s', 1986 null, 1987 ), 1988 array( 1989 'WHERE %1$i = %1$s OR %2$i = %1$s', 1990 array( 'a', 'b' ), 1991 'Arguments cannot be prepared as both an Identifier and Value. Found the following conflicts: %1$i and %1$s and %1$s', 1992 null, 1993 ), 1994 ); 1995 } 1996 1997 /** 1998 * The wpdb->allow_unsafe_unquoted_parameters is true (for now), purely for backwards compatibility reasons. 1999 * 2000 * @ticket 52506 2001 * 2002 * @dataProvider data_prepare_should_respect_the_allow_unsafe_unquoted_parameters_property 2003 * 2004 * @covers wpdb::prepare 2005 * 2006 * @param bool $allow Whether to allow unsafe unquoted parameters. 2007 * @param string $sql The SQL to prepare. 2008 * @param array $values The values for prepare. 2009 * @param string $expected The expected prepared parameters. 2010 */ 2011 public function test_prepare_should_respect_the_allow_unsafe_unquoted_parameters_property( $allow, $sql, $values, $expected ) { 2012 global $wpdb; 2013 2014 $default = $wpdb->allow_unsafe_unquoted_parameters; 2015 2016 $property = new ReflectionProperty( $wpdb, 'allow_unsafe_unquoted_parameters' ); 2017 $property->setAccessible( true ); 2018 $property->setValue( $wpdb, $allow ); 2019 2020 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared 2021 $actual = $wpdb->prepare( $sql, $values ); 2022 2023 // Reset. 2024 $property->setValue( $wpdb, $default ); 2025 $property->setAccessible( false ); 2026 2027 $this->assertSame( $expected, $actual ); 2028 } 2029 2030 /** 2031 * Data provider for test_prepare_should_respect_the_allow_unsafe_unquoted_parameters_property(). 2032 * 2033 * @return array[] 2034 */ 2035 public function data_prepare_should_respect_the_allow_unsafe_unquoted_parameters_property() { 2036 global $wpdb; 2037 2038 $placeholder_escape = $wpdb->placeholder_escape(); 2039 2040 return array( 2041 2042 'numbered-true-1' => array( 2043 'allow' => true, 2044 'sql' => 'WHERE (%i = %s) OR (%3$i = %4$s)', 2045 'values' => array( 'field_a', 'string_a', 'field_b', 'string_b' ), 2046 'expected' => 'WHERE (`field_a` = \'string_a\') OR (`field_b` = string_b)', 2047 ), 2048 'numbered-false-1' => array( 2049 'allow' => false, 2050 'sql' => 'WHERE (%i = %s) OR (%3$i = %4$s)', 2051 'values' => array( 'field_a', 'string_a', 'field_b', 'string_b' ), 2052 'expected' => 'WHERE (`field_a` = \'string_a\') OR (`field_b` = \'string_b\')', 2053 ), 2054 'numbered-true-2' => array( 2055 'allow' => true, 2056 'sql' => 'WHERE (%i = %s) OR (%3$i = %4$s)', 2057 'values' => array( 'field_a', 'string_a', 'field_b', '0 OR EvilSQL' ), 2058 'expected' => 'WHERE (`field_a` = \'string_a\') OR (`field_b` = 0 OR EvilSQL)', 2059 ), 2060 'numbered-false-2' => array( 2061 'allow' => false, 2062 'sql' => 'WHERE (%i = %s) OR (%3$i = %4$s)', 2063 'values' => array( 'field_a', 'string_a', 'field_b', '0 OR EvilSQL' ), 2064 'expected' => 'WHERE (`field_a` = \'string_a\') OR (`field_b` = \'0 OR EvilSQL\')', 2065 ), 2066 2067 'format-true-1' => array( 2068 'allow' => true, 2069 'sql' => 'WHERE (%10i = %10s)', 2070 'values' => array( 'field_a', 'string_a' ), 2071 'expected' => 'WHERE (` field_a` = string_a)', 2072 ), 2073 'format-false-1' => array( 2074 'allow' => false, 2075 'sql' => 'WHERE (%10i = %10s)', 2076 'values' => array( 'field_a', 'string_a' ), 2077 'expected' => 'WHERE (` field_a` = \' string_a\')', 2078 ), 2079 'format-true-2' => array( 2080 'allow' => true, 2081 'sql' => 'WHERE (%10i = %10s)', 2082 'values' => array( 'field_a', '0 OR EvilSQL' ), 2083 'expected' => 'WHERE (` field_a` = 0 OR EvilSQL)', 2084 ), 2085 'format-false-2' => array( 2086 'allow' => false, 2087 'sql' => 'WHERE (%10i = %10s)', 2088 'values' => array( 'field_a', '0 OR EvilSQL' ), 2089 'expected' => 'WHERE (` field_a` = \'0 OR EvilSQL\')', 2090 ), 2091 2092 'escaped-true-1' => array( 2093 'allow' => true, 2094 'sql' => 'SELECT 9%%%s', 2095 'values' => array( '7' ), 2096 'expected' => "SELECT 9{$placeholder_escape}7", // SELECT 9%7. 2097 ), 2098 'escaped-false-1' => array( 2099 'allow' => false, 2100 'sql' => 'SELECT 9%%%s', 2101 'values' => array( '7' ), 2102 'expected' => "SELECT 9{$placeholder_escape}'7'", // SELECT 9%'7'. 2103 ), 2104 'escaped-true-2' => array( 2105 'allow' => true, 2106 'sql' => 'SELECT 9%%%s', 2107 'values' => array( '7 OR EvilSQL' ), 2108 'expected' => "SELECT 9{$placeholder_escape}7 OR EvilSQL", // SELECT 9%7 OR EvilSQL. 2109 ), 2110 'escaped-false-2' => array( 2111 'allow' => false, 2112 'sql' => 'SELECT 9%%%s', 2113 'values' => array( '7 OR EvilSQL' ), 2114 'expected' => "SELECT 9{$placeholder_escape}'7 OR EvilSQL'", // SELECT 9%'7 OR EvilSQL'. 2115 ), 2116 1735 2117 ); 1736 2118 }
Note: See TracChangeset
for help on using the changeset viewer.