From 80d8605e64650be830df550e65fa9e6c312a895f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 30 Jul 2026 13:35:53 +1000 Subject: [PATCH] Add sniff for usage of DB_NAME or wpdb->dbname, as they are null on the VIP platform --- .../Constants/RestrictedConstantsSniff.php | 53 +++++++++++++++++++ .../Variables/RestrictedVariablesSniff.php | 7 +++ .../Constants/RestrictedConstantsUnitTest.inc | 26 +++++++++ .../Constants/RestrictedConstantsUnitTest.php | 3 ++ .../Variables/RestrictedVariablesUnitTest.inc | 6 +-- .../Variables/RestrictedVariablesUnitTest.php | 2 + 6 files changed, 94 insertions(+), 3 deletions(-) diff --git a/WordPressVIPMinimum/Sniffs/Constants/RestrictedConstantsSniff.php b/WordPressVIPMinimum/Sniffs/Constants/RestrictedConstantsSniff.php index 416c947f..01424cb7 100644 --- a/WordPressVIPMinimum/Sniffs/Constants/RestrictedConstantsSniff.php +++ b/WordPressVIPMinimum/Sniffs/Constants/RestrictedConstantsSniff.php @@ -11,6 +11,8 @@ use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Utils\TextStrings; +use WordPressCS\WordPress\Helpers\ConstantsHelper; +use WordPressCS\WordPress\Helpers\ContextHelper; use WordPressVIPMinimum\Sniffs\Sniff; /** @@ -37,6 +39,24 @@ class RestrictedConstantsSniff extends Sniff { 'WP_CRON_CONTROL_SECRET', ]; + /** + * List of constants which do not hold a reliable value on the VIP Platform. + * + * @var array Key is the constant name, value is the error message to use. + */ + private $unreliableConstants = [ + 'DB_NAME' => 'The `%s` constant is set to null on the VIP Platform and does not hold the actual database name.', + ]; + + /** + * Functions which resolve a constant based on a constant name passed as a text string. + * + * @var array Key is the function name in lowercase, value is irrelevant. + */ + private $constantNameFunctions = [ + 'constant' => true, + ]; + /** * List of (global) constant names, which should not be referenced in userland code, nor (re-)declared. * @@ -91,6 +111,11 @@ public function process_token( $stackPtr ) { $constantName = TextStrings::stripQuotes( $this->tokens[ $stackPtr ]['content'] ); } + if ( isset( $this->unreliableConstants[ $constantName ] ) === true ) { + $this->process_unreliable_constant( $stackPtr, $constantName ); + return; + } + if ( isset( $this->restrictedConstants[ $constantName ] ) === false && isset( $this->restrictedRedeclaration[ $constantName ] ) === false ) { @@ -138,4 +163,32 @@ public function process_token( $stackPtr ) { } } } + + /** + * Process a token containing the name of a constant which does not hold a reliable value + * on the VIP Platform. + * + * @param int $stackPtr The position of the current token in the stack passed in $tokens. + * @param string $constantName The name of the constant. + * + * @return void + */ + private function process_unreliable_constant( $stackPtr, $constantName ) { + if ( $this->tokens[ $stackPtr ]['code'] === T_STRING ) { + if ( ConstantsHelper::is_use_of_global_constant( $this->phpcsFile, $stackPtr ) === false ) { + // Class constant, property, function name or something else which just shares the name. + return; + } + } elseif ( ContextHelper::is_in_function_call( $this->phpcsFile, $stackPtr, $this->constantNameFunctions ) === false ) { + // A text string only refers to the constant when passed to constant(). + return; + } + + $this->phpcsFile->addError( + $this->unreliableConstants[ $constantName ], + $stackPtr, + 'UnreliableConstant', + [ $constantName ] + ); + } } diff --git a/WordPressVIPMinimum/Sniffs/Variables/RestrictedVariablesSniff.php b/WordPressVIPMinimum/Sniffs/Variables/RestrictedVariablesSniff.php index 033bc585..6a5a644f 100644 --- a/WordPressVIPMinimum/Sniffs/Variables/RestrictedVariablesSniff.php +++ b/WordPressVIPMinimum/Sniffs/Variables/RestrictedVariablesSniff.php @@ -41,6 +41,13 @@ public function getGroups() { '$wpdb->users', ], ], + 'db_name' => [ + 'type' => 'error', + 'message' => 'The `$wpdb->dbname` property is set to null on the VIP Platform and does not hold the actual database name.', + 'object_vars' => [ + '$wpdb->dbname', + ], + ], 'session' => [ 'type' => 'error', 'message' => 'Usage of $_SESSION variable is prohibited.', diff --git a/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.inc b/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.inc index ff0c678f..30f98c27 100644 --- a/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.inc @@ -23,3 +23,29 @@ if ( constant( 'WP_CRON_CONTROL_SECRET' ) ) { // Okay. Can touch. } define( '"A8C_PROXIED_REQUEST"', false ); // Okay, well not really as the name is not a valid PHP constant name, but that's not our concern. + +$name = DB_NAME; // Bad. The constant is null on the platform. + +$name = constant( 'DB_NAME' ); // Bad. The constant is null on the platform. + +if ( defined( 'DB_NAME' ) ) { // Okay. Checking whether a constant exists is not the same as using it. + +} + +$name = My_Class::DB_NAME; // Okay. Class constant. + +$name = $wpdb->DB_NAME; // Okay. Object property. + +$name = DB_NAME(); // Okay. Function call. + +$name = my_function( 'DB_NAME' ); // Okay. Just a text string. + +$name = [ 'DB_NAME' => 'my_database' ]; // Okay. Just a text string. + +class My_Class { + const DB_NAME = 'my_database'; // Okay. Class constant declaration. +} + +$name = \DB_NAME; // Bad. Fully qualified reference to the global constant. + +$name = My_Namespace\DB_NAME; // Okay. Namespaced constant which just shares the name. diff --git a/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.php b/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.php index 4429b324..22996c83 100644 --- a/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.php +++ b/WordPressVIPMinimum/Tests/Constants/RestrictedConstantsUnitTest.php @@ -26,6 +26,9 @@ public function getErrorList() { 11 => 1, 13 => 1, 15 => 1, + 27 => 1, + 29 => 1, + 49 => 1, ]; } diff --git a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc index 39abb1bb..3ec1502f 100644 --- a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc +++ b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.inc @@ -4,9 +4,9 @@ $query = "SELECT * FROM $wpdb->users"; // Error. $wp_db->update( $wpdb->users, array( 'displayname' => 'Kanobe!' ), array( 'ID' => 1 ) ); // Error. - - - +$db_name = $wpdb->dbname; // Error. +$query = "SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA = '$wpdb->dbname'"; // Error. +$db_name = $other_db->dbname; // Ok, not $wpdb. $query = "SELECT * FROM $wpdb->posts"; // Ok. diff --git a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php index e5b7ecf2..e54ca94d 100644 --- a/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php +++ b/WordPressVIPMinimum/Tests/Variables/RestrictedVariablesUnitTest.php @@ -25,6 +25,8 @@ public function getErrorList() { return [ 3 => 1, 5 => 1, + 7 => 1, + 8 => 1, 23 => 1, 36 => 1, 37 => 1,