Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.1.inc
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,10 @@ $GLOBALS[ $something ] = 'value'; // Warning.
$GLOBALS[ "{$something}_something" ] = 'value'; // Warning.
$GLOBALS[ ${$something} ] = 'value'; // Warning.

define( ${$something}, 'value' ); // Warning.
DEFINE( ${$something}, 'value' ); // Warning.
define( $something, 'value' ); // Warning.
define( $something . '_CONSTANT', 'value' ); // Warning.
define( "{$something}_CONSTANT", 'value' ); // Warning.
\Define( "{$something}_CONSTANT", 'value' ); // Warning.
define( $something . '_CONSTANT', 'value' ); // Warning.

do_action( "{$acronym_filter_var}_hook_name" ); // Warning.
Expand Down Expand Up @@ -683,4 +683,16 @@ class Acronym_AsymmetricVisibilityProperties {
public function __construct(public protected(set) int $foo = 0) {} // Ok.
}

/*
* Safeguard correct handling of all types of namespaced function calls.
*/
\define('SOME_GLOBAL', [ 1, 2, 3 ]); // Bad.
MyNamespace\define('SOME_GLOBAL', [ 1, 2, 3 ]); // Ok.
\MyNamespace\define('SOME_GLOBAL', [ 1, 2, 3 ]); // Ok.
namespace\define('SOME_GLOBAL', [ 1, 2, 3 ]); // Ok. The sniff should start flagging this once it can resolve relative namespaces.
\do_action( 'plugin_action' ); // Bad.
MyNamespace\do_action( 'plugin_action' ); // Ok.
\MyNamespace\apply_filters( 'plugin_filter', $variable ); // Ok.
namespace\do_action_ref_array( 'plugin_action', array( $variable ) ); // Ok. The sniff should start flagging this once it can resolve relative namespaces.

// phpcs:set WordPress.NamingConventions.PrefixAllGlobals prefixes[]
34 changes: 33 additions & 1 deletion WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.3.inc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Some_Test extends \PHPUnit_Framework_TestCase {
}
}

$acronym_test = new class extends \PHPUnit_Framework_TestCase {
$acronym_test = new class extends \phpunit_framework_testcase {

public function testPass() {
define( 'SOME_GLOBAL', '4.0.0' );
Expand All @@ -21,4 +21,36 @@ $acronym_test = new class extends \PHPUnit_Framework_TestCase {
}
};

// Test namespace resolution when the sniff checks the extending class.
class Extends_Namespaced_Class_Not_WP_Test extends WP_Font_Face_UnitTestCase {

public function testPass() {
do_action( 'some-action', $something );
}
}

/*
* Safeguard correct handling of namespaced extending classes.
*/
class Extends_Partially_Qualified_Not_WP_Test extends MyNamespace\WP_UnitTestCase_Base {

public function testPass() {
do_action( 'some-action', $something );
}
}

class Extends_Fully_Qualified_Not_WP_Test extends \MyNamespace\WP_Ajax_UnitTestCase {

public function testPass() {
do_action( 'some-action', $something );
}
}

class Extends_Relative_Namespace_Not_WP_Test extends namespace\WP_Canonical_UnitTestCase {

public function testPass() {
do_action( 'some-action', $something );
}
}

// phpcs:set WordPress.NamingConventions.PrefixAllGlobals prefixes[]
12 changes: 10 additions & 2 deletions WordPress/Tests/NamingConventions/PrefixAllGlobalsUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ public function getErrorList( $testFile = 'PrefixAllGlobalsUnitTest.1.inc' ) {
616 => 1,
617 => 1,
633 => 1,
689 => 1,
693 => 1,
);

case 'PrefixAllGlobalsUnitTest.3.inc':
return array(
28 => 1,
38 => 1,
45 => 1,
52 => 1,
);

case 'PrefixAllGlobalsUnitTest.4.inc':
Expand All @@ -106,8 +116,6 @@ public function getErrorList( $testFile = 'PrefixAllGlobalsUnitTest.1.inc' ) {

case 'PrefixAllGlobalsUnitTest.2.inc':
// Namespaced - all OK, fall through to the default case.
case 'PrefixAllGlobalsUnitTest.3.inc':
// Test class - non-prefixed constant is fine, fall through to the default case.
default:
return array();
}
Expand Down
15 changes: 13 additions & 2 deletions WordPress/Tests/NamingConventions/ValidHookNameUnitTest.1.inc
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ prefix_do_action( 'someAction' ); // Ok - not WP do_action.

// Check for incorrect word separators.
do_action( "admin_head-$hook_suffix" ); // Warning - use underscore.
do_action( 'admin_head.media.upload_popup' ); // Warning - use underscore.
DO_ACTION( 'admin_head.media.upload_popup' ); // Warning - use underscore.
apply_filters( "bulk_actions {$this->screen->id}", $this->_actions ); // Warning - use underscore.
apply_filters( "current_theme/supports-{$feature}", true, $args, $_wp_theme_features[$feature] ); // Warning - use underscore.
\Apply_Filters( "current_theme/supports-{$feature}", true, $args, $_wp_theme_features[$feature] ); // Warning - use underscore.

// Simple strings.
do_action( "adminHead" ); // Error - use lowercase.
Expand Down Expand Up @@ -121,3 +121,14 @@ do_action( 'admin_head_' . $fn( 'UPPERCASE', 'wrong-delimiter' ) . '_action' );
do_action_ref_array( hook: 'My-Hook', args: $args ); // OK. Well, not really, but using the wrong parameter name, so not our concern.
do_action_ref_array( args: $args, hook_name: 'my_hook', ); // OK.
do_action_ref_array( args: $args, hook_name: 'My-Hook', ); // Error - use lowercase + warning about dash.

/*
* Safeguard correct handling of all types of namespaced function calls.
*/
\apply_filters( 'adminHead', $variable ); // Error.
MyNamespace\do_action( 'adminHead' ); // Ok.
\MyNamespace\do_action_ref_array( 'adminHead', array( $variable ) ); // Ok.
namespace\apply_filters_ref_array( 'adminHead', array( $variable ) ); // Ok. The sniff should start flagging this once it can resolve relative namespaces.
apply_filters( 'admin_head_' . MyNamespace\my_function('UPPERCASE') . '_action', $variable ); // Ok.
do_action( 'admin_head_' . \MyNamespace\my_function('UPPERCASE') . '_action' ); // Ok.
do_action_ref_array( 'admin_head_' . namespace\my_function('UPPERCASE') . '_action', array( $variable ) ); // Ok.
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public function getErrorList( $testFile = 'ValidHookNameUnitTest.1.inc' ) {
114 => 1,
115 => 1,
123 => 1,
128 => 1,
);

case 'ValidHookNameUnitTest.2.inc':
Expand Down
12 changes: 10 additions & 2 deletions WordPress/Tests/PHP/NoSilencedErrorsUnitTest.inc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ if (@in_array($array, $needle)) { // Bad.
}

// File extension.
if ( @&file_exists( $filename ) && @ /*comment*/ is_readable( $filename ) ) {
if ( @&file_exists( $filename ) && @ /*comment*/ IS_READABLE( $filename ) ) {
$file = @ \file( $filename );
}

Expand All @@ -22,7 +22,7 @@ $fp = @fopen('https://www.example.com', 'r', false);

// Directory extension.
if (@is_dir($dir)) {
if ($dh = @\opendir($dir)) {
if ($dh = @\OPENDIR($dir)) {
while (($file = @readdir($dh)) !== false) { // Bad.
echo "filename: $file : filetype: " . @\filetype($dir . $file) . "\n";
}
Expand Down Expand Up @@ -84,3 +84,11 @@ $decoded = @hex2bin( $data );
// phpcs:set WordPress.PHP.NoSilencedErrors context_length 0
echo @some_userland_function( $param ); // Bad.
// phpcs:set WordPress.PHP.NoSilencedErrors context_length 6

/*
* Safeguard correct handling of namespaced function calls (fully qualified is already tested above).
*/
$file = @MyNS\MyClass::file_get_contents( $file ); // Bad.
Comment thread
rodrigoprimo marked this conversation as resolved.
$file = @MyNS\MyClass\file_exists( $file ); // Bad.
$file = @namespace\MyNS\MyClass::file( $file ); // Bad.
$file = @namespace\is_dir( $dir ); // The sniff should stop flagging this once it can resolve relative namespaces.
4 changes: 4 additions & 0 deletions WordPress/Tests/PHP/NoSilencedErrorsUnitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ public function getWarningList() {
71 => 1,
78 => 1,
85 => 1,
91 => 1,
92 => 1,
93 => 1,
94 => 1,
);
}
}
171 changes: 168 additions & 3 deletions WordPress/Tests/Security/NonceVerificationUnitTest.1.inc
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ function allow_for_unslash_before_noncecheck() {
}

function allow_for_unslash_in_sanitization() {
$var = sanitize_text_field( wp_unslash( $_POST['foo'] ) ); // OK.
$var = sanitize_text_field( WP_UNSLASH( $_POST['foo'] ) ); // OK.
wp_verify_nonce( $var );
echo $var;
}
Expand Down Expand Up @@ -314,7 +314,7 @@ function allow_in_array_key_exists_before_noncecheck() {
}

function allow_in_key_exists_before_noncecheck() {
if (key_exists('foo', $_POST['subset']) === false) { // OK.
if (Key_Exists('foo', $_POST['subset']) === false) { // OK.
return;
}

Expand Down Expand Up @@ -369,7 +369,7 @@ function disallow_for_non_array_comparison_in_condition() {
}

function allow_for_array_comparison_in_condition_with_named_params() {
if ( array_keys( filter_value: 'my_action', array: $_GET['actions'], strict: true, ) ) { // OK.
if ( \array_KEYS( filter_value: 'my_action', array: $_GET['actions'], strict: true, ) ) { // OK.
check_admin_referer( 'foo' );
foo();
}
Expand Down Expand Up @@ -524,3 +524,168 @@ function different_function_name() {
update_post_meta( (int) $_POST['id'], 'a_key', $_POST['a_value'] );
}
// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[]

function test_fully_qualified_call_to_global_nonce_verification_function() {
if ( ! IS_NUMERIC( $_POST['foo'] ) ) { // OK.
return;
}

\wp_verify_nonce( 'some_action' );
}

function test_namespace_relative_call_to_global_nonce_verification_function() {
if ( ! IS_NUMERIC( $_POST['foo'] ) ) { // Bad, but should become ok once the sniff is able to resolve relative namespaces.
return;
}

namespace\wp_verify_nonce( 'some_action' );
}

function test_namespaced_calls_to_incorrect_nonce_verification_functions() {
if ( ! is_numeric( $_POST['foo'] ) ) { // Bad - none of the below are the WP global functions, so no nonce verification.
return;
}

MyNamespace\wp_verify_nonce( 'some_action' );
\MyNamespace\check_admin_referer( 'some_action' );
namespace\Sub\check_ajax_referer( 'some_action' );
}

// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[] my_nonce_check

function test_namespace_relative_call_to_custom_nonce_verification_function() {
if ( ! is_int( $_POST['foo'] ) ) { // Bad, but should become ok once the sniff is able to resolve relative namespaces.
return;
}

namespace\my_nonce_check( 'some_action' );
}

function test_namespaced_calls_to_incorrect_custom_nonce_verification_functions() {
if ( ! is_string( $_POST['foo'] ) ) { // Bad - none of the below are a custom nonce verification function.
return;
}

MyNamespace\my_nonce_check( 'some_action' );
\MyNamespace\my_nonce_check( 'some_action' );
namespace\Sub\my_nonce_check( 'some_action' );
}

// phpcs:set WordPress.Security.NonceVerification customNonceVerificationFunctions[]

function allow_fully_qualified_key_exists_functions() {
if ( \array_key_exists('foo', $_POST) === false ) { // OK.
return;
}

\WP_VERIFY_NONCE( 'some_action' );
}

function allow_fully_qualified_key_exists_functions_with_mixed_case() {
if ( \Key_Exists('foo', $_POST) === false ) { // OK.
return;
}

wp_verify_nonce( 'some_action' );
}

function allow_namespace_relative_call_to_global_key_exists_functions() {
if ( namespace\array_key_exists('foo', $_POST) === false ) { // Bad, but should become ok once the sniff is able to resolve relative namespaces.
return;
}

wp_verify_nonce( 'some_action' );
}

function disallow_namespaced_key_exists_functions() {
if ( MyNamespace\array_key_exists( 'foo', $_POST ) === false // Bad.
|| \MyNamespace\key_exists( 'foo', $_POST ) === false // Bad.
|| namespace\Sub\key_exists( 'foo', $_POST ) === false // Bad.
) {
return;
}

wp_verify_nonce( 'some_action' );
}

function allow_fully_qualified_type_test_functions() {
if ( ! \is_numeric( $_POST['foo'] ) ) { // OK.
return;
}

\wp_verify_nonce( 'some_action' );
}

function allow_fully_qualified_type_test_functions_uppercase() {
if ( ! \IS_int( $_POST['foo'] ) ) { // OK.
return;
}

\wp_verify_nonce( 'some_action' );
}

function allow_namespace_relative_call_to_global_type_test_functions() {
if ( ! namespace\is_numeric( $_POST['foo'] ) ) { // Bad, but should become ok once the sniff is able to resolve relative namespaces.
return;
}

\wp_verify_nonce( 'some_action' );
}

function disallow_namespaced_type_test_functions() {
if ( ! MyNamespace\is_bool( $_POST['foo'] ) // Bad.
|| ! \MyNamespace\is_object( $_POST['foo'] ) // Bad.
|| ! namespace\Sub\is_string( $_POST['foo'] ) ) // Bad.
{
return;
}

\wp_verify_nonce( 'some_action' );
}

function allow_fully_qualified_array_comparison_functions() {
if ( \in_array( $_GET['action'], $valid_actions, true ) ) { // OK.
check_admin_referer( 'foo' );
}
}

function allow_namespace_relative_call_to_global_array_comparison_functions() {
if ( namespace\in_array( $_GET['action'], $valid_actions, true ) ) { // Bad, but should become ok once the sniff is able to resolve relative namespaces.
check_admin_referer( 'foo' );
}
}

function disallow_namespaced_array_comparison_functions() {
if ( MyNamespace\in_array( $_GET['action'], $valid_actions, true ) // Bad.
|| \MyNamespace\array_search( array( 'subscribe', 'unsubscribe' ), $_GET['action'], true ) // Bad.
|| namespace\Sub\array_keys( $_GET['actions'], 'my_action', true ) // Bad.
) {
check_admin_referer( 'foo' );
}
}

function allow_fully_qualified_unslashing_functions() {
$var = \stripslashes_from_strings_only( $_POST['foo'] ); // OK.
wp_verify_nonce( $var );
echo $var;
}

function allow_fully_qualified_unslashing_functions_mixed_case() {
$var = \stripslashes_FROM_strings_ONLY( $_POST['foo'] ); // OK.
wp_verify_nonce( $var );
echo $var;
}

function allow_namespace_relative_call_to_global_unslashing_functions() {
$var = namespace\stripslashes_from_strings_only( $_POST['foo'] ); // Bad, but should become ok once the sniff is able to resolve relative namespaces.
wp_verify_nonce( $var );
echo $var;
}

function disallow_namespaced_unslashing_functions() {
$var = MyNamespace\stripslashes_from_strings_only( $_POST['foo'] ); // Bad.
$var = \MyNamespace\stripslashes_deep( $_POST['foo'] ); // Bad.
$var = namespace\Sub\wp_unslash( $_POST['foo'] ); // Bad.
wp_verify_nonce( $var );
echo $var;
}
Loading
Loading