-
-
Notifications
You must be signed in to change notification settings - Fork 523
Description
Bug Description
The WordPress.DB.PreparedSQL sniff has a limitation in how it identifies and counts errors for namespaced function calls. It doesn't recognize namespaced names as a single unit, leading to incorrect error counting and identification.
Problem 1: Incorrect error counting for all namespaced calls
Multi-level namespace calls generate multiple errors (one for each namespace part) instead of recognizing it as a single namespaced function call. For example, namespace\Sub\custom_function( $foo ) should trigger two errors (one for the namespaced call namespace\Sub\custom_function and one for the unescaped variable $foo), but currently triggers four errors: "namespace", "Sub", "custom_function", and "$foo".
Problem 2: Missing errors when function name matches escaping/auto-escaped/formatting functions
When a namespaced function call matches a function name in $SQLEscapingFunctions, $SQLAutoEscapedFunctions, or FormattingFunctionsHelper::$formattingFunctions, the sniff 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 and 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 checking its contents.
Minimal Code Snippet
The issue happens when running this command:
vendor/bin/phpcs --standard=WordPress --sniffs=WordPress.DB.PreparedSQL test.php... over a file containing this code:
<?php
// Problem 1:
$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . namespace\Sub\custom_function( $foo ) );
// Problem 2:
$wpdb->query( "SELECT * FROM $wpdb->posts WHERE ID = " . MyNamespace\absint( $foo ) );Expected behavior:
FILE: test.php
--------------------------------------------------------------------
FOUND 4 ERRORS AFFECTING 2 LINES
--------------------------------------------------------------------
4 | ERROR | Use placeholders and $wpdb->prepare(); found namespace\Sub\custom_function
4 | ERROR | Use placeholders and $wpdb->prepare(); found $foo
7 | ERROR | Use placeholders and $wpdb->prepare(); found MyNamespace\absint
7 | ERROR | Use placeholders and $wpdb->prepare(); found $foo
--------------------------------------------------------------------
Actual behavior:
FILE: test.php
--------------------------------------------------------------------------
FOUND 5 ERRORS AFFECTING 2 LINES
--------------------------------------------------------------------------
4 | ERROR | Use placeholders and $wpdb->prepare(); found namespace
4 | ERROR | Use placeholders and $wpdb->prepare(); found Sub
4 | ERROR | Use placeholders and $wpdb->prepare(); found custom_function
4 | ERROR | Use placeholders and $wpdb->prepare(); found $foo
7 | ERROR | Use placeholders and $wpdb->prepare(); found MyNamespace
--------------------------------------------------------------------------
Error Code
WordPress.DB.PreparedSQL.NotPrepared
Environment
| Question | Answer |
|---|---|
| PHP version | 8.4 |
| PHP_CodeSniffer version | 3.13.4 |
| WordPressCS version | develop |
| PHPCSUtils version | 1.2.1 |
| PHPCSExtra version | 1.5.0 |
| WordPressCS install type | git clone |
| IDE (if relevant) | N/A |
Additional Context (optional)
The root cause is that the sniff processes tokens one by one without recognizing that a namespaced name should be treated as a single unit. With PHPCS 3.x tokenization, namespaced names are tokenized as separate T_STRING and T_NS_SEPARATOR tokens (e.g., namespace, \, Sub, \, custom_function), and the sniff processes each T_STRING individually.
Additionally, when processing T_STRING tokens, the sniff checks if the string matches any function in the escaping/auto-escaped/formatting function lists without first verifying whether the function is namespaced. If it finds a match, it skips to the end of the function call's parentheses, missing any variables inside.
It will be easier to fix this issue once support for PHPCS 3.x is dropped.
Tested Against develop Branch?
- I have verified the issue still exists in the
developbranch of WordPressCS.