diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc b/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc index 1f1a49076c..947f152711 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.1.inc @@ -33,7 +33,7 @@ $wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . esc_sql( $f $wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . ABSINT( $foo ) . ";" ); // Ok. // Test multi-line strings. -$all_post_meta = $wpdb->get_results( $wpdb->prepare( sprintf( +$all_post_meta = $wpdb->get_results( $wpdb->prepare( \SPRINTF( 'SELECT `post_id`, `meta_value` FROM `%s` WHERE `meta_key` = "sort_order" @@ -45,7 +45,7 @@ $all_post_meta = $wpdb->get_results( $wpdb->prepare( sprintf( $wpdb->query( " SELECT * FROM $wpdb->posts - WHERE post_title LIKE '" . esc_sql( $foo ) . "';" + WHERE post_title LIKE '" . \esc_SQL( $foo ) . "';" ); // Ok. $wpdb->query( $wpdb->prepare( " @@ -143,5 +143,60 @@ echo $wpdb::CONSTANT_NAME; // Not an identifiable method call. $wpdb->{$methodName}('query'); -// Don't throw an error during live coding. -wpdb::prepare( "SELECT * FROM $wpdb->posts +/* + * Safeguard correct handling of all types of namespaced calls to the WPDB::prepare() method. + * + * Note that calling wpdb::prepare() statically will result in an error. Still, the tests are included here since the + * sniff handles those calls. + * + * Except for the fully qualified global call, the calls below are currently false positives. The sniff + * incorrectly identifies calls to a non-global class named `wpdb` preceded by a namespace separator as calls to the + * global `$wpdb` object. Related to: https://github.com/WordPress/WordPress-Coding-Standards/issues/2710. + */ +\WPDB::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); +MyNamespace\WPDB::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); +\MyNamespace\wpdb::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); +namespace\wpdb::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); // False positive (see comment above). This should be flagged in the future once the sniff is able to resolve relative namespaces. +namespace\Sub\wpdb::prepare( "SELECT * FROM $wpdb->posts WHERE post_title LIKE '" . foo() . "';" ); + +/* + * Safeguard correct handling of all types of namespaced calls to PreparedSQLSniff::$SQLEscapingFunctions. + * + * Note: The sniff currently has a limitation in how it identifies and counts errors for namespaced function calls that + * match function names in $SQLEscapingFunctions, $SQLAutoEscapedFunctions, or + * FormattingFunctionsHelper::$formattingFunctions. When it encounters such a call, it treats the function name as if it + * were a global function call and skips checking the contents. For example, `MyNamespace\absint( $foo )` should trigger + * two errors (one for MyNamespace\absint, one for $foo), but currently only triggers one error for "MyNamespace" + * because the sniff incorrectly treats "absint" as a valid global escaping function and skips its contents. + * Additionally, multi-level namespace calls like `namespace\Sub\count( $foo )` generate multiple errors (one for + * "namespace", one for "Sub") instead of recognizing it as a single namespaced function call. This will be easier to + * fix once only PHPCS 4 is supported. Reported in https://github.com/WordPress/WordPress-Coding-Standards/issues/2648. + */ +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . \absint( $foo ) ); +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . MyNamespace\esc_sql( $foo ) ); +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . \MyNamespace\intval( $foo ) ); +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . namespace\floatval( $foo ) ); // This should NOT be flagged in the future once the sniff is able to resolve relative namespaces. +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . namespace\Sub\like_escape( $foo ) ); + +/* + * Safeguard correct handling of all types of namespaced calls to PreparedSQLSniff::$SQLAutoEscapedFunctions. + * + * Note: See the comment above the $SQLEscapingFunctions tests for details about the sniff's current limitations. + */ +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . \count( $foo ) ); +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . \Count( $foo ) ); +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . MyNamespace\count( $foo ) ); +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . \MyNamespace\count( $foo ) ); +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . namespace\count( $foo ) ); // This should NOT be flagged in the future once the sniff is able to resolve relative namespaces. +$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . namespace\Sub\count( $foo ) ); + +/* + * Safeguard correct handling of all types of namespaced calls to FormattingFunctionsHelper::$formattingFunctions. + * + * Note: See the comment above the $SQLEscapingFunctions tests for details about the sniff's current limitations. + */ +$wpdb->get_results( \sprintf( "SELECT * FROM $wpdb->posts WHERE ID = %s", intval( $id ) ) ); +$wpdb->get_results( MyNamespace\wp_sprintf( "SELECT * FROM $wpdb->posts WHERE ID = %s", intval( $id ) ) ); +$wpdb->get_results( \MyNamespace\sprintf( "SELECT * FROM $wpdb->posts WHERE ID = %s", intval( $id ) ) ); +$wpdb->get_results( namespace\wp_sprintf( "SELECT * FROM $wpdb->posts WHERE ID = %s", intval( $id ) ) ); // This should NOT be flagged in the future once the sniff is able to resolve relative namespaces. +$wpdb->get_results( namespace\Sub\sprintf( "SELECT * FROM $wpdb->posts WHERE ID = %s", intval( $id ) ) ); diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.3.inc b/WordPress/Tests/DB/PreparedSQLUnitTest.3.inc new file mode 100644 index 0000000000..4047216b82 --- /dev/null +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.3.inc @@ -0,0 +1,8 @@ +posts diff --git a/WordPress/Tests/DB/PreparedSQLUnitTest.php b/WordPress/Tests/DB/PreparedSQLUnitTest.php index 0a296ff984..54c503427e 100644 --- a/WordPress/Tests/DB/PreparedSQLUnitTest.php +++ b/WordPress/Tests/DB/PreparedSQLUnitTest.php @@ -66,6 +66,29 @@ public function getErrorList( $testFile = '' ) { 124 => 1, 128 => 1, 132 => 2, + 156 => 1, + + /** + * False positives. See https://github.com/WordPress/WordPress-Coding-Standards/issues/2710 and + * comment in the test case file. + */ + 157 => 1, + 158 => 1, + 159 => 1, + 160 => 1, + + 176 => 1, + 177 => 1, + 178 => 1, + 179 => 2, + 188 => 1, + 189 => 1, + 190 => 1, + 191 => 2, + 199 => 1, + 200 => 1, + 201 => 1, + 202 => 2, ); case 'PreparedSQLUnitTest.2.inc':