Changeset 32182
- Timestamp:
- 04/20/2015 11:08:17 AM (10 years ago)
- Location:
- branches/3.9
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/3.9/src/wp-admin/includes/post.php
r28113 r32182 178 178 */ 179 179 function edit_post( $post_data = null ) { 180 global $wpdb; 180 181 181 182 if ( empty($post_data) ) … … 318 319 update_post_meta( $post_ID, '_edit_last', get_current_user_id() ); 319 320 320 wp_update_post( $post_data ); 321 $success = wp_update_post( $post_data ); 322 // If the save failed, see if we can sanity check the main fields and try again 323 if ( ! $success && is_callable( array( $wpdb, 'strip_invalid_text_for_column' ) ) ) { 324 $fields = array( 'post_title', 'post_content', 'post_excerpt' ); 325 326 foreach( $fields as $field ) { 327 if ( isset( $post_data[ $field ] ) ) { 328 $post_data[ $field ] = $wpdb->strip_invalid_text_for_column( $wpdb->posts, $field, $post_data[ $field ] ); 329 } 330 } 331 332 wp_update_post( $post_data ); 333 } 321 334 322 335 // Now that we have an ID we can fix any attachment anchor hrefs -
branches/3.9/src/wp-includes/wp-db.php
r28022 r32182 142 142 143 143 /** 144 * Cached column info, for sanity checking data before inserting 145 * 146 * @since 4.2.0 147 * @access protected 148 * @var array 149 */ 150 protected $col_meta = array(); 151 152 /** 153 * Calculated character sets on tables 154 * 155 * @since 4.2.0 156 * @access protected 157 * @var array 158 */ 159 protected $table_charset = array(); 160 161 /** 162 * Whether text fields in the current query need to be sanity checked. 163 * 164 * @since 4.2.0 165 * @access protected 166 * @var bool 167 */ 168 protected $check_current_query = true; 169 170 /** 171 * Flag to ensure we don't run into recursion problems when checking the collation. 172 * 173 * @since 4.2.0 174 * @access protected 175 * @see wpdb::check_safe_collation() 176 * @var boolean 177 */ 178 protected $checking_collation = false; 179 180 /** 144 181 * Saved info on the table column 145 182 * … … 640 677 */ 641 678 function __set( $name, $value ) { 679 $protected_members = array( 680 'col_meta', 681 'table_charset', 682 'check_current_query', 683 ); 684 if ( in_array( $name, $protected_members, true ) ) { 685 return; 686 } 642 687 $this->$name = $value; 643 688 } … … 709 754 if ( ! empty( $collate ) ) 710 755 $query .= $this->prepare( ' COLLATE %s', $collate ); 711 mysqli_query( $ query, $dbh);756 mysqli_query( $dbh, $query ); 712 757 } 713 758 } else { … … 1497 1542 */ 1498 1543 function query( $query ) { 1499 if ( ! $this->ready ) 1544 if ( ! $this->ready ) { 1545 $this->check_current_query = true; 1500 1546 return false; 1547 } 1501 1548 1502 1549 /** … … 1517 1564 // Log how the function was called 1518 1565 $this->func_call = "\$db->query(\"$query\")"; 1566 1567 // If we're writing to the database, make sure the query will write safely. 1568 if ( $this->check_current_query && ! $this->check_ascii( $query ) ) { 1569 $stripped_query = $this->strip_invalid_text_from_query( $query ); 1570 // strip_invalid_text_from_query() can perform queries, so we need 1571 // to flush again, just to make sure everything is clear. 1572 $this->flush(); 1573 if ( $stripped_query !== $query ) { 1574 $this->insert_id = 0; 1575 return false; 1576 } 1577 } 1578 1579 $this->check_current_query = true; 1519 1580 1520 1581 // Keep track of the last query for debug.. … … 1691 1752 */ 1692 1753 function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) { 1693 if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) ) 1754 if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) ) { 1694 1755 return false; 1756 } 1757 1758 $data = $this->process_fields( $table, $data, $format ); 1759 if ( false === $data ) { 1760 return false; 1761 } 1762 1763 $formats = $values = array(); 1764 foreach ( $data as $value ) { 1765 $formats[] = $value['format']; 1766 $values[] = $value['value']; 1767 } 1768 1769 $fields = '`' . implode( '`, `', array_keys( $data ) ) . '`'; 1770 $formats = implode( ', ', $formats ); 1771 1772 $sql = "$type INTO `$table` ($fields) VALUES ($formats)"; 1773 1695 1774 $this->insert_id = 0; 1696 $formats = $format = (array) $format; 1697 $fields = array_keys( $data ); 1698 $formatted_fields = array(); 1699 foreach ( $fields as $field ) { 1700 if ( !empty( $format ) ) 1701 $form = ( $form = array_shift( $formats ) ) ? $form : $format[0]; 1702 elseif ( isset( $this->field_types[$field] ) ) 1703 $form = $this->field_types[$field]; 1704 else 1705 $form = '%s'; 1706 $formatted_fields[] = $form; 1707 } 1708 $sql = "{$type} INTO `$table` (`" . implode( '`,`', $fields ) . "`) VALUES (" . implode( ",", $formatted_fields ) . ")"; 1709 return $this->query( $this->prepare( $sql, $data ) ); 1775 $this->check_current_query = false; 1776 return $this->query( $this->prepare( $sql, $values ) ); 1710 1777 } 1711 1778 … … 1732 1799 */ 1733 1800 function update( $table, $data, $where, $format = null, $where_format = null ) { 1734 if ( ! is_array( $data ) || ! is_array( $where ) ) 1801 if ( ! is_array( $data ) || ! is_array( $where ) ) { 1735 1802 return false; 1736 1737 $formats = $format = (array) $format; 1738 $bits = $wheres = array(); 1739 foreach ( (array) array_keys( $data ) as $field ) { 1740 if ( !empty( $format ) ) 1741 $form = ( $form = array_shift( $formats ) ) ? $form : $format[0]; 1742 elseif ( isset($this->field_types[$field]) ) 1743 $form = $this->field_types[$field]; 1744 else 1745 $form = '%s'; 1746 $bits[] = "`$field` = {$form}"; 1747 } 1748 1749 $where_formats = $where_format = (array) $where_format; 1750 foreach ( (array) array_keys( $where ) as $field ) { 1751 if ( !empty( $where_format ) ) 1752 $form = ( $form = array_shift( $where_formats ) ) ? $form : $where_format[0]; 1753 elseif ( isset( $this->field_types[$field] ) ) 1754 $form = $this->field_types[$field]; 1755 else 1756 $form = '%s'; 1757 $wheres[] = "`$field` = {$form}"; 1758 } 1759 1760 $sql = "UPDATE `$table` SET " . implode( ', ', $bits ) . ' WHERE ' . implode( ' AND ', $wheres ); 1761 return $this->query( $this->prepare( $sql, array_merge( array_values( $data ), array_values( $where ) ) ) ); 1803 } 1804 1805 $data = $this->process_fields( $table, $data, $format ); 1806 if ( false === $data ) { 1807 return false; 1808 } 1809 $where = $this->process_fields( $table, $where, $where_format ); 1810 if ( false === $where ) { 1811 return false; 1812 } 1813 1814 $fields = $conditions = $values = array(); 1815 foreach ( $data as $field => $value ) { 1816 $fields[] = "`$field` = " . $value['format']; 1817 $values[] = $value['value']; 1818 } 1819 foreach ( $where as $field => $value ) { 1820 $conditions[] = "`$field` = " . $value['format']; 1821 $values[] = $value['value']; 1822 } 1823 1824 $fields = implode( ', ', $fields ); 1825 $conditions = implode( ' AND ', $conditions ); 1826 1827 $sql = "UPDATE `$table` SET $fields WHERE $conditions"; 1828 1829 $this->check_current_query = false; 1830 return $this->query( $this->prepare( $sql, $values ) ); 1762 1831 } 1763 1832 … … 1781 1850 */ 1782 1851 function delete( $table, $where, $where_format = null ) { 1783 if ( ! is_array( $where ) ) 1852 if ( ! is_array( $where ) ) { 1784 1853 return false; 1785 1786 $bits = $wheres = array(); 1787 1788 $where_formats = $where_format = (array) $where_format; 1789 1790 foreach ( array_keys( $where ) as $field ) { 1791 if ( !empty( $where_format ) ) { 1792 $form = ( $form = array_shift( $where_formats ) ) ? $form : $where_format[0]; 1854 } 1855 1856 $where = $this->process_fields( $table, $where, $where_format ); 1857 if ( false === $where ) { 1858 return false; 1859 } 1860 1861 $conditions = $values = array(); 1862 foreach ( $where as $field => $value ) { 1863 $conditions[] = "`$field` = " . $value['format']; 1864 $values[] = $value['value']; 1865 } 1866 1867 $conditions = implode( ' AND ', $conditions ); 1868 1869 $sql = "DELETE FROM `$table` WHERE $conditions"; 1870 1871 $this->check_current_query = false; 1872 return $this->query( $this->prepare( $sql, $values ) ); 1873 } 1874 1875 1876 /** 1877 * Processes arrays of field/value pairs and field formats. 1878 * 1879 * This is a helper method for wpdb's CRUD methods, which take field/value 1880 * pairs for inserts, updates, and where clauses. This method first pairs 1881 * each value with a format. Then it determines the charset of that field, 1882 * using that to determine if any invalid text would be stripped. If text is 1883 * stripped, then field processing is rejected and the query fails. 1884 * 1885 * @since 4.2.0 1886 * @access protected 1887 * 1888 * @param string $table Table name. 1889 * @param array $data Field/value pair. 1890 * @param mixed $format Format for each field. 1891 * @return array|bool Returns an array of fields that contain paired values 1892 * and formats. Returns false for invalid values. 1893 */ 1894 protected function process_fields( $table, $data, $format ) { 1895 $data = $this->process_field_formats( $data, $format ); 1896 $data = $this->process_field_charsets( $data, $table ); 1897 if ( false === $data ) { 1898 return false; 1899 } 1900 1901 $converted_data = $this->strip_invalid_text( $data ); 1902 1903 if ( $data !== $converted_data ) { 1904 return false; 1905 } 1906 1907 return $data; 1908 } 1909 1910 /** 1911 * Prepares arrays of value/format pairs as passed to wpdb CRUD methods. 1912 * 1913 * @since 4.2.0 1914 * @access protected 1915 * 1916 * @param array $data Array of fields to values. 1917 * @param mixed $format Formats to be mapped to the values in $data. 1918 * @return array Array, keyed by field names with values being an array 1919 * of 'value' and 'format' keys. 1920 */ 1921 protected function process_field_formats( $data, $format ) { 1922 $formats = $original_formats = (array) $format; 1923 1924 foreach ( $data as $field => $value ) { 1925 $value = array( 1926 'value' => $value, 1927 'format' => '%s', 1928 ); 1929 1930 if ( ! empty( $format ) ) { 1931 $value['format'] = array_shift( $formats ); 1932 if ( ! $value['format'] ) { 1933 $value['format'] = reset( $original_formats ); 1934 } 1793 1935 } elseif ( isset( $this->field_types[ $field ] ) ) { 1794 $form = $this->field_types[ $field ]; 1936 $value['format'] = $this->field_types[ $field ]; 1937 } 1938 1939 $data[ $field ] = $value; 1940 } 1941 1942 return $data; 1943 } 1944 1945 /** 1946 * Adds field charsets to field/value/format arrays generated by 1947 * the {@see wpdb::process_field_formats()} method. 1948 * 1949 * @since 4.2.0 1950 * @access protected 1951 * 1952 * @param array $data As it comes from the {@see wpdb::process_field_formats()} method. 1953 * @param string $table Table name. 1954 * @return The same array as $data with additional 'charset' keys. 1955 */ 1956 protected function process_field_charsets( $data, $table ) { 1957 foreach ( $data as $field => $value ) { 1958 if ( '%d' === $value['format'] || '%f' === $value['format'] ) { 1959 // We can skip this field if we know it isn't a string. 1960 // This checks %d/%f versus ! %s because it's sprintf() could take more. 1961 $value['charset'] = false; 1962 } elseif ( $this->check_ascii( $value['value'] ) ) { 1963 // If it's ASCII, then we don't need the charset. We can skip this field. 1964 $value['charset'] = false; 1795 1965 } else { 1796 $form = '%s'; 1797 } 1798 1799 $wheres[] = "$field = $form"; 1800 } 1801 1802 $sql = "DELETE FROM $table WHERE " . implode( ' AND ', $wheres ); 1803 return $this->query( $this->prepare( $sql, $where ) ); 1804 } 1805 1966 $value['charset'] = $this->get_col_charset( $table, $field ); 1967 if ( is_wp_error( $value['charset'] ) ) { 1968 return false; 1969 } 1970 1971 // This isn't ASCII. Don't have strip_invalid_text() re-check. 1972 $value['ascii'] = false; 1973 } 1974 1975 $data[ $field ] = $value; 1976 } 1977 1978 return $data; 1979 } 1806 1980 1807 1981 /** … … 1951 2125 } 1952 2126 2127 2128 /** 2129 * Retrieves the character set for the given table. 2130 * 2131 * @since 4.2.0 2132 * @access protected 2133 * 2134 * @param string $table Table name. 2135 * @return string|WP_Error Table character set, {@see WP_Error} object if it couldn't be found. 2136 */ 2137 protected function get_table_charset( $table ) { 2138 $tablekey = strtolower( $table ); 2139 2140 /** 2141 * Filter the table charset value before the DB is checked. 2142 * 2143 * Passing a non-null value to the filter will effectively short-circuit 2144 * checking the DB for the charset, returning that value instead. 2145 * 2146 * @since 4.2.0 2147 * 2148 * @param string $charset The character set to use. Default null. 2149 * @param string $table The name of the table being checked. 2150 */ 2151 $charset = apply_filters( 'pre_get_table_charset', null, $table ); 2152 if ( null !== $charset ) { 2153 return $charset; 2154 } 2155 2156 if ( isset( $this->table_charset[ $tablekey ] ) ) { 2157 return $this->table_charset[ $tablekey ]; 2158 } 2159 2160 $charsets = $columns = array(); 2161 $results = $this->get_results( "SHOW FULL COLUMNS FROM `$table`" ); 2162 if ( ! $results ) { 2163 return new WP_Error( 'wpdb_get_table_charset_failure' ); 2164 } 2165 2166 foreach ( $results as $column ) { 2167 $columns[ strtolower( $column->Field ) ] = $column; 2168 } 2169 2170 $this->col_meta[ $tablekey ] = $columns; 2171 2172 foreach ( $columns as $column ) { 2173 if ( ! empty( $column->Collation ) ) { 2174 list( $charset ) = explode( '_', $column->Collation ); 2175 $charsets[ strtolower( $charset ) ] = true; 2176 } 2177 2178 list( $type ) = explode( '(', $column->Type ); 2179 2180 // A binary/blob means the whole query gets treated like this. 2181 if ( in_array( strtoupper( $type ), array( 'BINARY', 'VARBINARY', 'TINYBLOB', 'MEDIUMBLOB', 'BLOB', 'LONGBLOB' ) ) ) { 2182 $this->table_charset[ $tablekey ] = 'binary'; 2183 return 'binary'; 2184 } 2185 } 2186 2187 // utf8mb3 is an alias for utf8. 2188 if ( isset( $charsets['utf8mb3'] ) ) { 2189 $charsets['utf8'] = true; 2190 unset( $charsets['utf8mb3'] ); 2191 } 2192 2193 // Check if we have more than one charset in play. 2194 $count = count( $charsets ); 2195 if ( 1 === $count ) { 2196 $charset = key( $charsets ); 2197 } elseif ( 0 === $count ) { 2198 // No charsets, assume this table can store whatever. 2199 $charset = false; 2200 } else { 2201 // More than one charset. Remove latin1 if present and recalculate. 2202 unset( $charsets['latin1'] ); 2203 $count = count( $charsets ); 2204 if ( 1 === $count ) { 2205 // Only one charset (besides latin1). 2206 $charset = key( $charsets ); 2207 } elseif ( 2 === $count && isset( $charsets['utf8'], $charsets['utf8mb4'] ) ) { 2208 // Two charsets, but they're utf8 and utf8mb4, use utf8. 2209 $charset = 'utf8'; 2210 } else { 2211 // Two mixed character sets. ascii. 2212 $charset = 'ascii'; 2213 } 2214 } 2215 2216 $this->table_charset[ $tablekey ] = $charset; 2217 return $charset; 2218 } 2219 2220 /** 2221 * Retrieves the character set for the given column. 2222 * 2223 * @since 4.2.0 2224 * @access public 2225 * 2226 * @param string $table Table name. 2227 * @param string $column Column name. 2228 * @return mixed Column character set as a string. False if the column has no 2229 * character set. {@see WP_Error} object if there was an error. 2230 */ 2231 public function get_col_charset( $table, $column ) { 2232 $tablekey = strtolower( $table ); 2233 $columnkey = strtolower( $column ); 2234 2235 /** 2236 * Filter the column charset value before the DB is checked. 2237 * 2238 * Passing a non-null value to the filter will short-circuit 2239 * checking the DB for the charset, returning that value instead. 2240 * 2241 * @since 4.2.0 2242 * 2243 * @param string $charset The character set to use. Default null. 2244 * @param string $table The name of the table being checked. 2245 * @param string $column The name of the column being checked. 2246 */ 2247 $charset = apply_filters( 'pre_get_col_charset', null, $table, $column ); 2248 if ( null !== $charset ) { 2249 return $charset; 2250 } 2251 2252 // Skip this entirely if this isn't a MySQL database. 2253 if ( false === $this->is_mysql ) { 2254 return false; 2255 } 2256 2257 if ( empty( $this->table_charset[ $tablekey ] ) ) { 2258 // This primes column information for us. 2259 $table_charset = $this->get_table_charset( $table ); 2260 if ( is_wp_error( $table_charset ) ) { 2261 return $table_charset; 2262 } 2263 } 2264 2265 // If still no column information, return the table charset. 2266 if ( empty( $this->col_meta[ $tablekey ] ) ) { 2267 return $this->table_charset[ $tablekey ]; 2268 } 2269 2270 // If this column doesn't exist, return the table charset. 2271 if ( empty( $this->col_meta[ $tablekey ][ $columnkey ] ) ) { 2272 return $this->table_charset[ $tablekey ]; 2273 } 2274 2275 // Return false when it's not a string column. 2276 if ( empty( $this->col_meta[ $tablekey ][ $columnkey ]->Collation ) ) { 2277 return false; 2278 } 2279 2280 list( $charset ) = explode( '_', $this->col_meta[ $tablekey ][ $columnkey ]->Collation ); 2281 return $charset; 2282 } 2283 2284 /** 2285 * Check if a string is ASCII. 2286 * 2287 * The negative regex is faster for non-ASCII strings, as it allows 2288 * the search to finish as soon as it encounters a non-ASCII character. 2289 * 2290 * @since 4.2.0 2291 * @access protected 2292 * 2293 * @param string $string String to check. 2294 * @return bool True if ASCII, false if not. 2295 */ 2296 protected function check_ascii( $string ) { 2297 if ( function_exists( 'mb_check_encoding' ) ) { 2298 if ( mb_check_encoding( $string, 'ASCII' ) ) { 2299 return true; 2300 } 2301 } elseif ( ! preg_match( '/[^\x00-\x7F]/', $string ) ) { 2302 return true; 2303 } 2304 2305 return false; 2306 } 2307 2308 /** 2309 * Check if the query is accessing a collation considered safe on the current version of MySQL. 2310 * 2311 * @since 4.2.0 2312 * @access protected 2313 * 2314 * @param string $query The query to check. 2315 * @return bool True if the collation is safe, false if it isn't. 2316 */ 2317 protected function check_safe_collation( $query ) { 2318 if ( $this->checking_collation ) { 2319 return true; 2320 } 2321 $table = $this->get_table_from_query( $query ); 2322 if ( ! $table ) { 2323 return false; 2324 } 2325 2326 $this->checking_collation = true; 2327 $this->get_table_charset( $table ); 2328 $this->checking_collation = false; 2329 2330 $table = strtolower( $table ); 2331 if ( empty( $this->col_meta[ $table ] ) ) { 2332 return false; 2333 } 2334 2335 foreach( $this->col_meta[ $table ] as $col ) { 2336 if ( empty( $col->Collation ) ) { 2337 continue; 2338 } 2339 2340 if ( ! in_array( $col->Collation, array( 'utf8_general_ci', 'utf8_bin', 'utf8mb4_general_ci', 'utf8mb4_bin' ), true ) ) { 2341 return false; 2342 } 2343 } 2344 2345 return true; 2346 } 2347 2348 /** 2349 * Strips any invalid characters based on value/charset pairs. 2350 * 2351 * @since 4.2.0 2352 * @access protected 2353 * 2354 * @param array $data Array of value arrays. Each value array has the keys 2355 * 'value' and 'charset'. An optional 'ascii' key can be 2356 * set to false to avoid redundant ASCII checks. 2357 * @return array|WP_Error The $data parameter, with invalid characters removed from 2358 * each value. This works as a passthrough: any additional keys 2359 * such as 'field' are retained in each value array. If we cannot 2360 * remove invalid characters, a {@see WP_Error} object is returned. 2361 */ 2362 protected function strip_invalid_text( $data ) { 2363 // Some multibyte character sets that we can check in PHP. 2364 $mb_charsets = array( 2365 'ascii' => 'ASCII', 2366 'big5' => 'BIG-5', 2367 'eucjpms' => 'eucJP-win', 2368 'gb2312' => 'EUC-CN', 2369 'ujis' => 'EUC-JP', 2370 'utf32' => 'UTF-32', 2371 ); 2372 2373 $supported_charsets = array(); 2374 if ( function_exists( 'mb_list_encodings' ) ) { 2375 $supported_charsets = mb_list_encodings(); 2376 } 2377 2378 $db_check_string = false; 2379 2380 foreach ( $data as &$value ) { 2381 $charset = $value['charset']; 2382 2383 // Column isn't a string, or is latin1, which will will happily store anything. 2384 if ( false === $charset || 'latin1' === $charset ) { 2385 continue; 2386 } 2387 2388 if ( ! is_string( $value['value'] ) ) { 2389 continue; 2390 } 2391 2392 // ASCII is always OK. 2393 if ( ! isset( $value['ascii'] ) && $this->check_ascii( $value['value'] ) ) { 2394 continue; 2395 } 2396 2397 // Convert the text locally. 2398 if ( $supported_charsets ) { 2399 if ( isset( $mb_charsets[ $charset ] ) && in_array( $mb_charsets[ $charset ], $supported_charsets ) ) { 2400 $value['value'] = mb_convert_encoding( $value['value'], $mb_charsets[ $charset ], $mb_charsets[ $charset ] ); 2401 continue; 2402 } 2403 } 2404 2405 // utf8 can be handled by regex, which is a bunch faster than a DB lookup. 2406 if ( 'utf8' === $charset || 'utf8mb3' === $charset || 'utf8mb4' === $charset ) { 2407 $regex = '/ 2408 ( 2409 (?: [\x00-\x7F] # single-byte sequences 0xxxxxxx 2410 | [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx 2411 | \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2 2412 | [\xE1-\xEC][\x80-\xBF]{2} 2413 | \xED[\x80-\x9F][\x80-\xBF] 2414 | [\xEE-\xEF][\x80-\xBF]{2}'; 2415 2416 if ( 'utf8mb4' === $charset) { 2417 $regex .= ' 2418 | \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3 2419 | [\xF1-\xF3][\x80-\xBF]{3} 2420 | \xF4[\x80-\x8F][\x80-\xBF]{2} 2421 '; 2422 } 2423 2424 $regex .= '){1,50} # ...one or more times 2425 ) 2426 | . # anything else 2427 /x'; 2428 $value['value'] = preg_replace( $regex, '$1', $value['value'] ); 2429 continue; 2430 } 2431 2432 // We couldn't use any local conversions, send it to the DB. 2433 $value['db'] = $db_check_string = true; 2434 } 2435 unset( $value ); // Remove by reference. 2436 2437 if ( $db_check_string ) { 2438 $queries = array(); 2439 foreach ( $data as $col => $value ) { 2440 if ( ! empty( $value['db'] ) ) { 2441 if ( ! isset( $queries[ $value['charset'] ] ) ) { 2442 $queries[ $value['charset'] ] = array(); 2443 } 2444 2445 // Split the CONVERT() calls by charset, so we can make sure the connection is right 2446 $queries[ $value['charset'] ][ $col ] = $this->prepare( "CONVERT( %s USING {$value['charset']} )", $value['value'] ); 2447 } 2448 } 2449 2450 $connection_charset = $this->charset; 2451 foreach ( $queries as $charset => $query ) { 2452 if ( ! $query ) { 2453 continue; 2454 } 2455 2456 // Change the charset to match the string(s) we're converting 2457 if ( $charset !== $connection_charset ) { 2458 $connection_charset = $charset; 2459 $this->set_charset( $this->dbh, $charset ); 2460 } 2461 2462 $this->check_current_query = false; 2463 2464 $row = $this->get_row( "SELECT " . implode( ', ', $query ), ARRAY_N ); 2465 if ( ! $row ) { 2466 $this->set_charset( $this->dbh, $connection_charset ); 2467 return new WP_Error( 'wpdb_strip_invalid_text_failure' ); 2468 } 2469 2470 $cols = array_keys( $query ); 2471 $col_count = count( $cols ); 2472 for ( $ii = 0; $ii < $col_count; $ii++ ) { 2473 $data[ $cols[ $ii ] ]['value'] = $row[ $ii ]; 2474 } 2475 } 2476 2477 // Don't forget to change the charset back! 2478 if ( $connection_charset !== $this->charset ) { 2479 $this->set_charset( $this->dbh ); 2480 } 2481 } 2482 2483 return $data; 2484 } 2485 2486 /** 2487 * Strips any invalid characters from the query. 2488 * 2489 * @since 4.2.0 2490 * @access protected 2491 * 2492 * @param string $query Query to convert. 2493 * @return string|WP_Error The converted query, or a {@see WP_Error} object if the conversion fails. 2494 */ 2495 protected function strip_invalid_text_from_query( $query ) { 2496 $table = $this->get_table_from_query( $query ); 2497 if ( $table ) { 2498 $charset = $this->get_table_charset( $table ); 2499 if ( is_wp_error( $charset ) ) { 2500 return $charset; 2501 } 2502 2503 // We can't reliably strip text from tables containing binary/blob columns 2504 if ( 'binary' === $charset ) { 2505 return $query; 2506 } 2507 } else { 2508 $charset = $this->charset; 2509 } 2510 2511 $data = array( 2512 'value' => $query, 2513 'charset' => $charset, 2514 'ascii' => false, 2515 ); 2516 2517 $data = $this->strip_invalid_text( array( $data ) ); 2518 if ( is_wp_error( $data ) ) { 2519 return $data; 2520 } 2521 2522 return $data[0]['value']; 2523 } 2524 2525 /** 2526 * Strips any invalid characters from the string for a given table and column. 2527 * 2528 * @since 4.2.0 2529 * @access public 2530 * 2531 * @param string $table Table name. 2532 * @param string $column Column name. 2533 * @param string $value The text to check. 2534 * @return string|WP_Error The converted string, or a `WP_Error` object if the conversion fails. 2535 */ 2536 public function strip_invalid_text_for_column( $table, $column, $value ) { 2537 if ( ! is_string( $value ) || $this->check_ascii( $value ) ) { 2538 return $value; 2539 } 2540 2541 $charset = $this->get_col_charset( $table, $column ); 2542 if ( ! $charset ) { 2543 // Not a string column. 2544 return $value; 2545 } elseif ( is_wp_error( $charset ) ) { 2546 // Bail on real errors. 2547 return $charset; 2548 } 2549 2550 $data = array( 2551 $column => array( 2552 'value' => $value, 2553 'charset' => $charset, 2554 'ascii' => false, 2555 ) 2556 ); 2557 2558 $data = $this->strip_invalid_text( $data ); 2559 if ( is_wp_error( $data ) ) { 2560 return $data; 2561 } 2562 2563 return $data[ $column ]['value']; 2564 } 2565 2566 /** 2567 * Find the first table name referenced in a query. 2568 * 2569 * @since 4.2.0 2570 * @access protected 2571 * 2572 * @param string $query The query to search. 2573 * @return string|false $table The table name found, or false if a table couldn't be found. 2574 */ 2575 protected function get_table_from_query( $query ) { 2576 // Remove characters that can legally trail the table name. 2577 $query = rtrim( $query, ';/-#' ); 2578 2579 // Allow (select...) union [...] style queries. Use the first query's table name. 2580 $query = ltrim( $query, "\r\n\t (" ); 2581 2582 /* 2583 * Strip everything between parentheses except nested selects and use only 1,000 2584 * chars of the query. 2585 */ 2586 $query = preg_replace( '/\((?!\s*select)[^(]*?\)/is', '()', substr( $query, 0, 1000 ) ); 2587 2588 // Quickly match most common queries. 2589 if ( preg_match( '/^\s*(?:' 2590 . 'SELECT.*?\s+FROM' 2591 . '|INSERT(?:\s+LOW_PRIORITY|\s+DELAYED|\s+HIGH_PRIORITY)?(?:\s+IGNORE)?(?:\s+INTO)?' 2592 . '|REPLACE(?:\s+LOW_PRIORITY|\s+DELAYED)?(?:\s+INTO)?' 2593 . '|UPDATE(?:\s+LOW_PRIORITY)?(?:\s+IGNORE)?' 2594 . '|DELETE(?:\s+LOW_PRIORITY|\s+QUICK|\s+IGNORE)*(?:\s+FROM)?' 2595 . ')\s+`?([\w-]+)`?/is', $query, $maybe ) ) { 2596 return $maybe[1]; 2597 } 2598 2599 // SHOW TABLE STATUS and SHOW TABLES 2600 if ( preg_match( '/^\s*(?:' 2601 . 'SHOW\s+TABLE\s+STATUS.+(?:LIKE\s+|WHERE\s+Name\s*=\s*)' 2602 . '|SHOW\s+(?:FULL\s+)?TABLES.+(?:LIKE\s+|WHERE\s+Name\s*=\s*)' 2603 . ')\W([\w-]+)\W/is', $query, $maybe ) ) { 2604 return $maybe[1]; 2605 } 2606 2607 // Big pattern for the rest of the table-related queries. 2608 if ( preg_match( '/^\s*(?:' 2609 . '(?:EXPLAIN\s+(?:EXTENDED\s+)?)?SELECT.*?\s+FROM' 2610 . '|DESCRIBE|DESC|EXPLAIN|HANDLER' 2611 . '|(?:LOCK|UNLOCK)\s+TABLE(?:S)?' 2612 . '|(?:RENAME|OPTIMIZE|BACKUP|RESTORE|CHECK|CHECKSUM|ANALYZE|REPAIR).*\s+TABLE' 2613 . '|TRUNCATE(?:\s+TABLE)?' 2614 . '|CREATE(?:\s+TEMPORARY)?\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?' 2615 . '|ALTER(?:\s+IGNORE)?\s+TABLE' 2616 . '|DROP\s+TABLE(?:\s+IF\s+EXISTS)?' 2617 . '|CREATE(?:\s+\w+)?\s+INDEX.*\s+ON' 2618 . '|DROP\s+INDEX.*\s+ON' 2619 . '|LOAD\s+DATA.*INFILE.*INTO\s+TABLE' 2620 . '|(?:GRANT|REVOKE).*ON\s+TABLE' 2621 . '|SHOW\s+(?:.*FROM|.*TABLE)' 2622 . ')\s+\(*\s*`?([\w-]+)`?\s*\)*/is', $query, $maybe ) ) { 2623 return $maybe[1]; 2624 } 2625 2626 return false; 2627 } 2628 1953 2629 /** 1954 2630 * Load the column metadata from the last query. -
branches/3.9/tests/phpunit/includes/utils.php
r26187 r32182 388 388 remove_filter( 'get_the_terms', array( 'Featured_Content', 'hide_the_featured_term' ), 10, 3 ); 389 389 } 390 391 /** 392 * Special class for exposing protected wpdb methods we need to access 393 */ 394 class wpdb_exposed_methods_for_testing extends wpdb { 395 public function __construct() { 396 global $wpdb; 397 $this->dbh = $wpdb->dbh; 398 $this->use_mysqli = $wpdb->use_mysqli; 399 $this->ready = true; 400 $this->field_types = $wpdb->field_types; 401 $this->charset = $wpdb->charset; 402 } 403 404 public function __call( $name, $arguments ) { 405 return call_user_func_array( array( $this, $name ), $arguments ); 406 } 407 } -
branches/3.9/tests/phpunit/tests/db.php
r27250 r32182 15 15 16 16 /** 17 * Our special WPDB 18 * @var resource 19 */ 20 protected static $_wpdb; 21 22 public static function setUpBeforeClass() { 23 self::$_wpdb = new wpdb_exposed_methods_for_testing(); 24 } 25 26 /** 17 27 * Set up the test fixture 18 28 */ … … 27 37 */ 28 38 public function tearDown() { 39 remove_filter( 'query', array( $this, 'query_filter' ) ); 29 40 parent::tearDown(); 30 remove_filter( 'query', array( $this, 'query_filter' ) );31 41 } 32 42 … … 126 136 127 137 /** 138 * @ticket 21212 139 */ 140 function test_wpdb_actually_protected_properties() { 141 global $wpdb; 142 143 $new_meta = "HAHA I HOPE THIS DOESN'T WORK"; 144 145 $col_meta = $wpdb->col_meta; 146 $wpdb->col_meta = $new_meta; 147 148 $this->assertNotEquals( $col_meta, $new_meta ); 149 $this->assertEquals( $col_meta, $wpdb->col_meta ); 150 } 151 152 /** 128 153 * @ticket 18510 129 154 */ … … 153 178 * @ticket 26847 154 179 */ 155 publicfunction test_set_sql_mode() {180 function test_set_sql_mode() { 156 181 global $wpdb; 157 182 … … 159 184 160 185 $new_modes = array( 'IGNORE_SPACE', 'NO_AUTO_CREATE_USER' ); 186 161 187 $wpdb->set_sql_mode( $new_modes ); 188 162 189 $check_new_modes = $wpdb->get_var( 'SELECT @@SESSION.sql_mode;' ); 163 $this->assertEqual s( implode( ',', $new_modes ), $check_new_modes);190 $this->assertEqualSets( $new_modes, explode( ',', $check_new_modes ) ); 164 191 165 192 $wpdb->set_sql_mode( explode( ',', $current_modes ) ); … … 170 197 * @ticket 26847 171 198 */ 172 publicfunction test_set_incompatible_sql_mode() {199 function test_set_incompatible_sql_mode() { 173 200 global $wpdb; 174 201 … … 178 205 $wpdb->set_sql_mode( $new_modes ); 179 206 $check_new_modes = $wpdb->get_var( 'SELECT @@SESSION.sql_mode;' ); 180 $this->assert False( in_array( 'NO_ZERO_DATE', explode( ',', $check_new_modes )) );207 $this->assertNotContains( 'NO_ZERO_DATE', explode( ',', $check_new_modes ) ); 181 208 182 209 $wpdb->set_sql_mode( explode( ',', $current_modes ) ); … … 187 214 * @ticket 26847 188 215 */ 189 publicfunction test_set_allowed_incompatible_sql_mode() {216 function test_set_allowed_incompatible_sql_mode() { 190 217 global $wpdb; 191 218 192 219 $current_modes = $wpdb->get_var( 'SELECT @@SESSION.sql_mode;' ); 193 220 194 $new_modes = array( 'IGNORE_SPACE', ' NO_ZERO_DATE', 'NO_AUTO_CREATE_USER' );221 $new_modes = array( 'IGNORE_SPACE', 'ONLY_FULL_GROUP_BY', 'NO_AUTO_CREATE_USER' ); 195 222 196 223 add_filter( 'incompatible_sql_modes', array( $this, 'filter_allowed_incompatible_sql_mode' ), 1, 1 ); … … 199 226 200 227 $check_new_modes = $wpdb->get_var( 'SELECT @@SESSION.sql_mode;' ); 201 $this->assert True( in_array( 'NO_ZERO_DATE', explode( ',', $check_new_modes )) );228 $this->assertContains( 'ONLY_FULL_GROUP_BY', explode( ',', $check_new_modes ) ); 202 229 203 230 $wpdb->set_sql_mode( explode( ',', $current_modes ) ); … … 205 232 206 233 public function filter_allowed_incompatible_sql_mode( $modes ) { 207 $pos = array_search( ' NO_ZERO_DATE', $modes );234 $pos = array_search( 'ONLY_FULL_GROUP_BY', $modes ); 208 235 $this->assertGreaterThanOrEqual( 0, $pos ); 209 236 … … 227 254 $this->assertEquals( "SELECT * FROM $wpdb->users WHERE id = 0", $prepared ); 228 255 } 256 257 function test_db_version() { 258 global $wpdb; 259 260 $this->assertTrue( version_compare( $wpdb->db_version(), '5.0', '>=' ) ); 261 } 262 263 function test_get_caller() { 264 global $wpdb; 265 $str = $wpdb->get_caller(); 266 $calls = explode( ', ', $str ); 267 $called = join( '->', array( __CLASS__, __FUNCTION__ ) ); 268 $this->assertEquals( $called, end( $calls ) ); 269 } 270 271 function test_has_cap() { 272 global $wpdb; 273 $this->assertTrue( $wpdb->has_cap( 'collation' ) ); 274 $this->assertTrue( $wpdb->has_cap( 'group_concat' ) ); 275 $this->assertTrue( $wpdb->has_cap( 'subqueries' ) ); 276 $this->assertTrue( $wpdb->has_cap( 'COLLATION' ) ); 277 $this->assertTrue( $wpdb->has_cap( 'GROUP_CONCAT' ) ); 278 $this->assertTrue( $wpdb->has_cap( 'SUBQUERIES' ) ); 279 $this->assertEquals( 280 version_compare( $wpdb->db_version(), '5.0.7', '>=' ), 281 $wpdb->has_cap( 'set_charset' ) 282 ); 283 $this->assertEquals( 284 version_compare( $wpdb->db_version(), '5.0.7', '>=' ), 285 $wpdb->has_cap( 'SET_CHARSET' ) 286 ); 287 } 288 289 /** 290 * @expectedDeprecated supports_collation 291 */ 292 function test_supports_collation() { 293 global $wpdb; 294 $this->assertTrue( $wpdb->supports_collation() ); 295 } 296 297 function test_check_database_version() { 298 global $wpdb; 299 $this->assertEmpty( $wpdb->check_database_version() ); 300 } 301 302 /** 303 * @expectedException WPDieException 304 */ 305 function test_bail() { 306 global $wpdb; 307 $wpdb->bail( 'Database is dead.' ); 308 } 309 310 function test_timers() { 311 global $wpdb; 312 313 $wpdb->timer_start(); 314 usleep( 5 ); 315 $stop = $wpdb->timer_stop(); 316 317 $this->assertNotEquals( $wpdb->time_start, $stop ); 318 $this->assertGreaterThan( $stop, $wpdb->time_start ); 319 } 320 321 function test_get_col_info() { 322 global $wpdb; 323 324 $wpdb->get_results( "SELECT ID FROM $wpdb->users" ); 325 326 $this->assertEquals( array( 'ID' ), $wpdb->get_col_info() ); 327 $this->assertEquals( array( $wpdb->users ), $wpdb->get_col_info( 'table' ) ); 328 $this->assertEquals( $wpdb->users, $wpdb->get_col_info( 'table', 0 ) ); 329 } 330 331 function test_query_and_delete() { 332 global $wpdb; 333 $rows = $wpdb->query( "INSERT INTO $wpdb->users (display_name) VALUES ('Walter Sobchak')" ); 334 $this->assertEquals( 1, $rows ); 335 $this->assertNotEmpty( $wpdb->insert_id ); 336 $d_rows = $wpdb->delete( $wpdb->users, array( 'ID' => $wpdb->insert_id ) ); 337 $this->assertEquals( 1, $d_rows ); 338 } 339 340 function test_get_row() { 341 global $wpdb; 342 $rows = $wpdb->query( "INSERT INTO $wpdb->users (display_name) VALUES ('Walter Sobchak')" ); 343 $this->assertEquals( 1, $rows ); 344 $this->assertNotEmpty( $wpdb->insert_id ); 345 346 $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE ID = %d", $wpdb->insert_id ) ); 347 $this->assertInternalType( 'object', $row ); 348 $this->assertEquals( 'Walter Sobchak', $row->display_name ); 349 } 350 351 function test_replace() { 352 global $wpdb; 353 $rows1 = $wpdb->insert( $wpdb->users, array( 'display_name' => 'Walter Sobchak' ) ); 354 $this->assertEquals( 1, $rows1 ); 355 $this->assertNotEmpty( $wpdb->insert_id ); 356 $last = $wpdb->insert_id; 357 358 $rows2 = $wpdb->replace( $wpdb->users, array( 'ID' => $last, 'display_name' => 'Walter Replace Sobchak' ) ); 359 $this->assertEquals( 2, $rows2 ); 360 $this->assertNotEmpty( $wpdb->insert_id ); 361 362 $this->assertEquals( $last, $wpdb->insert_id ); 363 364 $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->users WHERE ID = %d", $last ) ); 365 $this->assertEquals( 'Walter Replace Sobchak', $row->display_name ); 366 } 367 368 /** 369 * wpdb::update() requires a WHERE condition. 370 * 371 * @ticket 26106 372 */ 373 function test_empty_where_on_update() { 374 global $wpdb; 375 $suppress = $wpdb->suppress_errors( true ); 376 $wpdb->update( $wpdb->posts, array( 'post_name' => 'burrito' ), array() ); 377 378 $expected1 = "UPDATE `{$wpdb->posts}` SET `post_name` = 'burrito' WHERE "; 379 $this->assertNotEmpty( $wpdb->last_error ); 380 $this->assertEquals( $expected1, $wpdb->last_query ); 381 382 $wpdb->update( $wpdb->posts, array( 'post_name' => 'burrito' ), array( 'post_status' => 'taco' ) ); 383 384 $expected2 = "UPDATE `{$wpdb->posts}` SET `post_name` = 'burrito' WHERE `post_status` = 'taco'"; 385 $this->assertEmpty( $wpdb->last_error ); 386 $this->assertEquals( $expected2, $wpdb->last_query ); 387 $wpdb->suppress_errors( $suppress ); 388 } 389 390 /** 391 * @ticket 21212 392 */ 393 function data_get_table_from_query() { 394 $table = 'a_test_table_name'; 395 396 $queries = array( 397 // Basic 398 "SELECT * FROM $table", 399 "SELECT * FROM `$table`", 400 401 "INSERT $table", 402 "INSERT IGNORE $table", 403 "INSERT IGNORE INTO $table", 404 "INSERT INTO $table", 405 "INSERT LOW_PRIORITY $table", 406 "INSERT DELAYED $table", 407 "INSERT HIGH_PRIORITY $table", 408 "INSERT LOW_PRIORITY IGNORE $table", 409 "INSERT LOW_PRIORITY INTO $table", 410 "INSERT LOW_PRIORITY IGNORE INTO $table", 411 412 "REPLACE $table", 413 "REPLACE INTO $table", 414 "REPLACE LOW_PRIORITY $table", 415 "REPLACE DELAYED $table", 416 "REPLACE LOW_PRIORITY INTO $table", 417 418 "UPDATE LOW_PRIORITY $table", 419 "UPDATE LOW_PRIORITY IGNORE $table", 420 421 "DELETE $table", 422 "DELETE IGNORE $table", 423 "DELETE IGNORE FROM $table", 424 "DELETE FROM $table", 425 "DELETE LOW_PRIORITY $table", 426 "DELETE QUICK $table", 427 "DELETE IGNORE $table", 428 "DELETE LOW_PRIORITY FROM $table", 429 430 // STATUS 431 "SHOW TABLE STATUS LIKE '$table'", 432 "SHOW TABLE STATUS WHERE NAME='$table'", 433 434 "SHOW TABLES LIKE '$table'", 435 "SHOW FULL TABLES LIKE '$table'", 436 "SHOW TABLES WHERE NAME='$table'", 437 438 // Extended 439 "EXPLAIN SELECT * FROM $table", 440 "EXPLAIN EXTENDED SELECT * FROM $table", 441 "EXPLAIN EXTENDED SELECT * FROM `$table`", 442 443 "DESCRIBE $table", 444 "DESC $table", 445 "EXPLAIN $table", 446 "HANDLER $table", 447 448 "LOCK TABLE $table", 449 "LOCK TABLES $table", 450 "UNLOCK TABLE $table", 451 452 "RENAME TABLE $table", 453 "OPTIMIZE TABLE $table", 454 "BACKUP TABLE $table", 455 "RESTORE TABLE $table", 456 "CHECK TABLE $table", 457 "CHECKSUM TABLE $table", 458 "ANALYZE TABLE $table", 459 "REPAIR TABLE $table", 460 461 "TRUNCATE $table", 462 "TRUNCATE TABLE $table", 463 464 "CREATE TABLE $table", 465 "CREATE TEMPORARY TABLE $table", 466 "CREATE TABLE IF NOT EXISTS $table", 467 468 "ALTER TABLE $table", 469 "ALTER IGNORE TABLE $table", 470 471 "DROP TABLE $table", 472 "DROP TABLE IF EXISTS $table", 473 474 "CREATE INDEX foo(bar(20)) ON $table", 475 "CREATE UNIQUE INDEX foo(bar(20)) ON $table", 476 "CREATE FULLTEXT INDEX foo(bar(20)) ON $table", 477 "CREATE SPATIAL INDEX foo(bar(20)) ON $table", 478 479 "DROP INDEX foo ON $table", 480 481 "LOAD DATA INFILE 'wp.txt' INTO TABLE $table", 482 "LOAD DATA LOW_PRIORITY INFILE 'wp.txt' INTO TABLE $table", 483 "LOAD DATA CONCURRENT INFILE 'wp.txt' INTO TABLE $table", 484 "LOAD DATA LOW_PRIORITY LOCAL INFILE 'wp.txt' INTO TABLE $table", 485 "LOAD DATA INFILE 'wp.txt' REPLACE INTO TABLE $table", 486 "LOAD DATA INFILE 'wp.txt' IGNORE INTO TABLE $table", 487 488 "GRANT ALL ON TABLE $table", 489 "REVOKE ALL ON TABLE $table", 490 491 "SHOW COLUMNS FROM $table", 492 "SHOW FULL COLUMNS FROM $table", 493 "SHOW CREATE TABLE $table", 494 "SHOW INDEX FROM $table", 495 ); 496 497 foreach ( $queries as &$query ) { 498 $query = array( $query, $table ); 499 } 500 return $queries; 501 } 502 503 /** 504 * @dataProvider data_get_table_from_query 505 * @ticket 21212 506 */ 507 function test_get_table_from_query( $query, $table ) { 508 $this->assertEquals( $table, self::$_wpdb->get_table_from_query( $query ) ); 509 } 510 511 function data_get_table_from_query_false() { 512 $table = 'a_test_table_name'; 513 return array( 514 array( "LOL THIS ISN'T EVEN A QUERY $table" ), 515 ); 516 } 517 518 /** 519 * @dataProvider data_get_table_from_query_false 520 * @ticket 21212 521 */ 522 function test_get_table_from_query_false( $query ) { 523 $this->assertFalse( self::$_wpdb->get_table_from_query( $query ) ); 524 } 525 526 /** 527 * @ticket 21212 528 */ 529 function data_process_field_formats() { 530 $core_db_fields_no_format_specified = array( 531 array( 'post_content' => 'foo', 'post_parent' => 0 ), 532 null, 533 array( 534 'post_content' => array( 'value' => 'foo', 'format' => '%s' ), 535 'post_parent' => array( 'value' => 0, 'format' => '%d' ), 536 ) 537 ); 538 539 $core_db_fields_formats_specified = array( 540 array( 'post_content' => 'foo', 'post_parent' => 0 ), 541 array( '%d', '%s' ), // These override core field_types 542 array( 543 'post_content' => array( 'value' => 'foo', 'format' => '%d' ), 544 'post_parent' => array( 'value' => 0, 'format' => '%s' ), 545 ) 546 ); 547 548 $misc_fields_no_format_specified = array( 549 array( 'this_is_not_a_core_field' => 'foo', 'this_is_not_either' => 0 ), 550 null, 551 array( 552 'this_is_not_a_core_field' => array( 'value' => 'foo', 'format' => '%s' ), 553 'this_is_not_either' => array( 'value' => 0, 'format' => '%s' ), 554 ) 555 ); 556 557 $misc_fields_formats_specified = array( 558 array( 'this_is_not_a_core_field' => 0, 'this_is_not_either' => 1.2 ), 559 array( '%d', '%f' ), 560 array( 561 'this_is_not_a_core_field' => array( 'value' => 0, 'format' => '%d' ), 562 'this_is_not_either' => array( 'value' => 1.2, 'format' => '%f' ), 563 ) 564 ); 565 566 $misc_fields_insufficient_formats_specified = array( 567 array( 'this_is_not_a_core_field' => 0, 'this_is_not_either' => 's', 'nor_this' => 1 ), 568 array( '%d', '%s' ), // The first format is used for the third 569 array( 570 'this_is_not_a_core_field' => array( 'value' => 0, 'format' => '%d' ), 571 'this_is_not_either' => array( 'value' => 's', 'format' => '%s' ), 572 'nor_this' => array( 'value' => 1, 'format' => '%d' ), 573 ) 574 ); 575 576 $vars = get_defined_vars(); 577 // Push the variable name onto the end for assertSame $message 578 foreach ( $vars as $var_name => $var ) { 579 $vars[ $var_name ][] = $var_name; 580 } 581 return array_values( $vars ); 582 } 583 584 /** 585 * @dataProvider data_process_field_formats 586 * @ticket 21212 587 */ 588 function test_process_field_formats( $data, $format, $expected, $message ) { 589 $actual = self::$_wpdb->process_field_formats( $data, $format ); 590 $this->assertSame( $expected, $actual, $message ); 591 } 592 593 /** 594 * @ticket 21212 595 */ 596 function test_process_fields() { 597 global $wpdb; 598 599 if ( $wpdb->charset ) { 600 $expected_charset = $wpdb->charset; 601 } else { 602 $expected_charset = $wpdb->get_col_charset( $wpdb->posts, 'post_content' ); 603 } 604 605 if ( ! in_array( $expected_charset, array( 'utf8', 'utf8mb4', 'latin1' ) ) ) { 606 $this->markTestSkipped( "This test only works with utf8, utf8mb4 or latin1 character sets" ); 607 } 608 609 $data = array( 'post_content' => '¡foo foo foo!' ); 610 $expected = array( 611 'post_content' => array( 612 'value' => '¡foo foo foo!', 613 'format' => '%s', 614 'charset' => $expected_charset, 615 'ascii' => false, 616 ) 617 ); 618 619 $this->assertSame( $expected, self::$_wpdb->process_fields( $wpdb->posts, $data, null ) ); 620 } 621 622 /** 623 * @ticket 21212 624 * @depends test_process_fields 625 */ 626 function test_process_fields_on_nonexistent_table( $data ) { 627 self::$_wpdb->suppress_errors( true ); 628 $data = array( 'post_content' => '¡foo foo foo!' ); 629 $this->assertFalse( self::$_wpdb->process_fields( 'nonexistent_table', $data, null ) ); 630 self::$_wpdb->suppress_errors( false ); 631 } 632 633 /** 634 * @ticket 21212 635 */ 636 function test_pre_get_table_charset_filter() { 637 add_filter( 'pre_get_table_charset', array( $this, 'filter_pre_get_table_charset' ), 10, 2 ); 638 $charset = self::$_wpdb->get_table_charset( 'some_table' ); 639 remove_filter( 'pre_get_table_charset', array( $this, 'filter_pre_get_table_charset' ), 10 ); 640 641 $this->assertEquals( $charset, 'fake_charset' ); 642 } 643 function filter_pre_get_table_charset( $charset, $table ) { 644 return 'fake_charset'; 645 } 646 647 /** 648 * @ticket 21212 649 */ 650 function test_pre_get_col_charset_filter() { 651 add_filter( 'pre_get_col_charset', array( $this, 'filter_pre_get_col_charset' ), 10, 3 ); 652 $charset = self::$_wpdb->get_col_charset( 'some_table', 'some_col' ); 653 remove_filter( 'pre_get_col_charset', array( $this, 'filter_pre_get_col_charset' ), 10 ); 654 655 $this->assertEquals( $charset, 'fake_col_charset' ); 656 } 657 function filter_pre_get_col_charset( $charset, $table, $column ) { 658 return 'fake_col_charset'; 659 } 229 660 } 661 -
branches/3.9/tests/phpunit/tests/post.php
r27720 r32182 914 914 915 915 } 916 917 /** 918 * @ticket 21212 919 */ 920 function test_utf8mb3_post_saves_with_emoji() { 921 global $wpdb; 922 $_wpdb = new wpdb_exposed_methods_for_testing(); 923 924 if ( 'utf8' !== $_wpdb->get_col_charset( $wpdb->posts, 'post_title' ) ) { 925 $this->markTestSkipped( 'This test is only useful with the utf8 character set' ); 926 } 927 928 require_once( ABSPATH . '/wp-admin/includes/post.php' ); 929 930 $post_id = $this->factory->post->create(); 931 932 $data = array( 933 'post_ID' => $post_id, 934 'post_title' => "foo\xf0\x9f\x98\x88bar", 935 'post_content' => "foo\xf0\x9f\x98\x8ebaz", 936 'post_excerpt' => "foo\xf0\x9f\x98\x90bat" 937 ); 938 939 $expected = array( 940 'post_title' => "foobar", 941 'post_content' => "foobaz", 942 'post_excerpt' => "foobat" 943 ); 944 945 edit_post( $data ); 946 947 $post = get_post( $post_id ); 948 949 foreach( $expected as $field => $value ) { 950 $this->assertEquals( $post->$field, $value ); 951 } 952 }
Note: See TracChangeset
for help on using the changeset viewer.