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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ phpcs-standard/

# OS generated files
.DS_Store
.phpunit.result.cache
21 changes: 14 additions & 7 deletions HM-Minimum/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,17 @@
<element value="get_post_gallery" /> <!-- with param 2 set to true, the default -->
</property>
</properties>

<!--
Exception messages are internal program state, not an output boundary.
Escaping belongs at the point of output (catch/render), not at throw.
The OutputNotEscaped rule still covers actual HTML output points.
See: https://github.com/WordPress/WordPress-Coding-Standards/issues/2374

To opt back in to this check, add to your ruleset:
<rule ref="HM.Security.EscapeOutput.ExceptionNotEscaped" />
-->
<exclude name="HM.Security.EscapeOutput.ExceptionNotEscaped" />
</rule>

<!-- Disallow use of __FILE__ in menu slugs, which exposes the filesystem's data. -->
Expand Down Expand Up @@ -154,13 +165,12 @@
<rule ref="Generic.Files.ByteOrderMark" />

<!-- Disallow empty statements. -->
<rule ref="WordPress.CodeAnalysis.EmptyStatement" />
<rule ref="Generic.CodeAnalysis.EmptyPHPStatement" />

<!-- Require correct usage of WP's i18n functions. -->
<rule ref="WordPress.WP.I18n">
<properties>
<property name="check_translator_comments" value="false" />
</properties>
<!-- Ignore missing translator comments -->
<exclude name="WordPress.WP.I18n.MissingTranslatorsComment" />

<!-- Allow empty strings to be translated (e.g. space character) -->
<exclude name="WordPress.WP.I18n.NoEmptyStrings" />
Expand All @@ -176,9 +186,6 @@
<!--
Rules based on WordPress-Extra
-->
<!-- Disallow parts of PHP which may cause compatibility issues. -->
<rule ref="Generic.Functions.CallTimePassByReference" />

<!-- Disallow "development" functions like var_dump/print_r/phpinfo -->
<rule ref="WordPress.PHP.DevelopmentFunctions">
<!-- Allow triggering errors for reporting purposes. -->
Expand Down
8 changes: 5 additions & 3 deletions HM/Sniffs/ExtraSniffCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace HM\Sniffs;

use PHP_CodeSniffer\Files\File as PhpcsFile;
use PHP_CodeSniffer\Util;

trait ExtraSniffCode {
Expand All @@ -11,13 +12,14 @@ trait ExtraSniffCode {
* This allows overriding an existing sniff and retaining the existing
* ignore statements.
*
* @param PhpcsFile $file File being checked.
* @param string $legacy Legacy sniff code
*/
protected function duplicate_ignores( $legacy ) {
protected function duplicate_ignores( PhpcsFile $file, $legacy ) {
$expression = sprintf( '/^%s(\..+)?$/', preg_quote( $legacy ) );
$base_code = Util\Common::getSniffCode( get_class( $this ) );

foreach ( $this->phpcsFile->tokenizer->ignoredLines as $line => $ignored ) {
foreach ( $file->tokenizer->ignoredLines as $line => $ignored ) {
$additional = [];

if ( empty( $ignored ) ) {
Expand All @@ -38,7 +40,7 @@ protected function duplicate_ignores( $legacy ) {
}

if ( ! empty( $additional ) ) {
$this->phpcsFile->tokenizer->ignoredLines[ $line ] = array_merge( $ignored, $additional );
$file->tokenizer->ignoredLines[ $line ] = array_merge( $ignored, $additional );
}
}

Expand Down
20 changes: 13 additions & 7 deletions HM/Sniffs/Performance/SlowMetaQuerySniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Util\Tokens;
use PHPCSUtils\Utils\Arrays;
use PHPCSUtils\Utils\MessageHelper;
use PHPCSUtils\Utils\TextStrings;
use WordPressCS\WordPress\AbstractArrayAssignmentRestrictionsSniff;

/**
Expand Down Expand Up @@ -104,7 +107,8 @@ protected function check_meta_query_item( int $array_open ) {
$array_open_token = $this->tokens[ $array_open ];
if ( $array_open_token['code'] !== T_ARRAY && $array_open_token['code'] !== T_OPEN_SHORT_ARRAY ) {
// Dynamic value, we can't check.
$this->addMessage(
MessageHelper::addMessage(
$this->phpcsFile,
'meta_query is dynamic, cannot be checked.',
$array_open,
'warning',
Expand All @@ -114,7 +118,7 @@ protected function check_meta_query_item( int $array_open ) {
return;
}

$array_bounds = $this->find_array_open_close( $array_open );
$array_bounds = Arrays::getOpenClose( $this->phpcsFile, $array_open );
$elements = $this->get_array_indices( $array_bounds['opener'], $array_bounds['closer'] );

// Is this a "first-order" query?
Expand All @@ -138,7 +142,7 @@ protected function check_meta_query_item( int $array_open ) {

foreach ( $elements as $element ) {
if ( isset( $element['index_start'] ) ) {
$index = $this->strip_quotes( $this->tokens[ $element['index_start'] ]['content'] );
$index = TextStrings::stripQuotes( $this->tokens[ $element['index_start'] ]['content'] );
if ( strtolower( $index ) === 'relation' ) {
// Skip 'relation' element.
continue;
Expand Down Expand Up @@ -176,7 +180,7 @@ protected function get_static_value_for_element( array $element ) : ?string {
return static::DYNAMIC_VALUE;
}

return $this->strip_quotes( $this->tokens[ $value_start ]['content'] );
return TextStrings::stripQuotes( $this->tokens[ $value_start ]['content'] );
}

/**
Expand Down Expand Up @@ -208,7 +212,7 @@ protected function find_key_in_array( array $elements, string $array_key ) : ?ar
continue;
}

$index = $this->strip_quotes( $this->tokens[ $start ]['content'] );
$index = TextStrings::stripQuotes( $this->tokens[ $start ]['content'] );
if ( $index !== $array_key ) {
// Not the item we want, skip.
continue;
Expand Down Expand Up @@ -270,15 +274,17 @@ protected function check_compare_value( string $compare, int $stackPtr = null )
}

if ( $compare === static::DYNAMIC_VALUE ) {
$this->addMessage(
MessageHelper::addMessage(
$this->phpcsFile,
'meta_query is using a dynamic comparison; this cannot be checked automatically, and may be non-performant.',
$stackPtr,
'warning',
'dynamic_compare'
);
} elseif ( $compare !== 'EXISTS' && $compare !== 'NOT EXISTS' ) {
// Add a message ourselves.
$this->addMessage(
MessageHelper::addMessage(
$this->phpcsFile,
'meta_query is using %s comparison, which is non-performant.',
$stackPtr,
'warning',
Expand Down
6 changes: 5 additions & 1 deletion HM/Sniffs/Performance/SlowOrderBySniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace HM\Sniffs\Performance;

use PHPCSUtils\Utils\MessageHelper;
use PHPCSUtils\Utils\TextStrings;
use WordPressCS\WordPress\AbstractArrayAssignmentRestrictionsSniff;

/**
Expand Down Expand Up @@ -57,11 +59,13 @@ public function process_token( $stackPtr ) {
* with custom error message passed to ->process().
*/
public function callback( $key, $val, $line, $group ) {
$val = TextStrings::stripQuotes( $val );
switch ( $val ) {
case 'rand':
case 'meta_value':
case 'meta_value_num':
$this->addMessage(
MessageHelper::addMessage(
$this->phpcsFile,
'Ordering query results by %s is not performant.',
$this->stackPtr,
'warning',
Expand Down
13 changes: 7 additions & 6 deletions HM/Sniffs/Security/EscapeOutputSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*
* @see https://github.com/WordPress/WordPress-Coding-Standards/issues/1864
*/
#[\AllowDynamicProperties]
class EscapeOutputSniff extends WPCSEscapeOutputSniff {
use ExtraSniffCode;

Expand Down Expand Up @@ -56,13 +57,13 @@ public function __construct() {
}

/**
* Override init to duplicate any ignores.
* Override process to duplicate any ignores.
*
* @param PhpcsFile $phpcsFile
* @param PhpcsFile $file
* @param int $stackPtr
*/
protected function init( PhpcsFile $phpcsFile ) {
parent::init( $phpcsFile );

$this->duplicate_ignores( 'WordPress.Security.EscapeOutput' );
public function process( PhpcsFile $file, $stackPtr ) {
$this->duplicate_ignores( $file, 'WordPress.Security.EscapeOutput' );
return parent::process( $file, $stackPtr );
}
}
10 changes: 5 additions & 5 deletions HM/Sniffs/Security/NonceVerificationSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,17 @@ class NonceVerificationSniff extends WPCSNonceVerificationSniff {
public $allowQueryVariables = false;

/**
* Override init to override config and duplicate any ignores.
* Override process to override config and duplicate any ignores.
*
* @param PhpcsFile $phpcsFile
* @param int $stackPtr
*/
public function init( PhpcsFile $file ) {
parent::init( $file );

public function process( PhpcsFile $file, $stackPtr ) {
if ( $this->allowQueryVariables ) {
unset( $this->superglobals[ '$_GET' ] );
}

$this->duplicate_ignores( 'WordPress.Security.NonceVerification' );
$this->duplicate_ignores( $file, 'WordPress.Security.NonceVerification' );
return parent::process( $file, $stackPtr );
}
}
16 changes: 9 additions & 7 deletions HM/Sniffs/Security/ValidatedSanitizedInputSniff.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use HM\Sniffs\ExtraSniffCode;
use PHP_CodeSniffer\Files\File as PhpcsFile;
use PHPCSUtils\Utils\TextStrings;
use WordPressCS\WordPress\Helpers\VariableHelper;
use WordPressCS\WordPress\Sniffs\Security\ValidatedSanitizedInputSniff as WPCSValidatedSanitizedInputSniff;

class ValidatedSanitizedInputSniff extends WPCSValidatedSanitizedInputSniff {
Expand Down Expand Up @@ -34,14 +36,14 @@ class ValidatedSanitizedInputSniff extends WPCSValidatedSanitizedInputSniff {
];

/**
* Override init to duplicate any ignores.
* Override process to duplicate any ignores.
*
* @param PhpcsFile $phpcsFile
* @param int $stackPtr
*/
protected function init( PhpcsFile $phpcsFile ) {
parent::init( $phpcsFile );

$this->duplicate_ignores( 'WordPress.Security.ValidatedSanitizedInput' );
public function process( PhpcsFile $file, $stackPtr ) {
$this->duplicate_ignores( $file, 'WordPress.Security.ValidatedSanitizedInput' );
return parent::process( $file, $stackPtr );
}

/**
Expand Down Expand Up @@ -71,7 +73,7 @@ public function process_token( $stackPtr ) {
* @return bool True if this is a $_SERVER variable and is safe, false to run regular checks.
*/
protected function check_server_variable( $stackPtr ) {
$key = $this->get_array_access_key( $stackPtr );
$key = VariableHelper::get_array_access_key( $this->phpcsFile, $stackPtr );

// Find the next non-whitespace token.
$open_bracket = $this->phpcsFile->findNext( T_WHITESPACE, ( $stackPtr + 1 ), null, true );
Expand All @@ -94,7 +96,7 @@ protected function check_server_variable( $stackPtr ) {
}

// Constant string, check if it's allowed.
$key = $this->strip_quotes( $this->tokens[ $index_token ]['content'] );
$key = TextStrings::stripQuotes( $this->tokens[ $index_token ]['content'] );
if ( ! in_array( $key, $this->allowedServerKeys, true ) ) {
// Unsafe key, requires sanitising.
return false;
Expand Down
23 changes: 23 additions & 0 deletions HM/Tests/Whitespace/MultipleEmptyLinesUnitTest.fail.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace HM\Coding\Standards\Tests;

use \HM\Other;
use \WP_Post;

function some_function( $some_argument ) {
$variable = 'some string';

return $variable;
}

class MyTest Class {

__construct() {
do_something();
}

public function another_function() {
return null;
}
}
14 changes: 7 additions & 7 deletions HM/ruleset.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
<exclude name="WordPress.PHP.DevelopmentFunctions.error_log_trigger_error" />
<exclude name="Generic.Formatting.MultipleStatementAlignment.NotSameWarning" />

<!-- We like short arrays and ternaries around here -->
<exclude name="Generic.Arrays.DisallowShortArraySyntax" />
<exclude name="WordPress.PHP.DisallowShortTernary" />
<!-- We like short arrays and short ternaries around here -->
<exclude name="Universal.Arrays.DisallowShortArraySyntax" />
<exclude name="Universal.Operators.DisallowShortTernary" />

<!--
OK, real talk right now. Yoda conditions are ridiculous.
Expand Down Expand Up @@ -71,18 +71,18 @@
<property name="additionalWordDelimiters" value="." />
</properties>
</rule>

<!-- Ease up on the PHP DOM* objects. -->
<rule ref="WordPress.NamingConventions.ValidVariableName">
<properties>
<property name="customPropertiesWhitelist" type="array">
<property name="allowed_custom_properties" type="array">
<!-- DOMDocument::$documentElement -->
<element value="documentElement" />
<!-- DOMElement::$childElementCount -->
<!-- DOMElement::$childElementCount -->
<element value="childElementCount" />
<!-- DOMElement::$parentNode -->
<element value="parentNode" />
<!-- DOMNode::$childNodes -->
<!-- DOMNode::$childNodes -->
<element value="childNodes" />
</property>
</properties>
Expand Down
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
"type": "phpcodesniffer-standard",
"license": "GPL-2.0-or-later",
"require": {
"php": ">=7.1",
"wp-coding-standards/wpcs": "2.3.0",
"automattic/vipwpcs": "2.0.0",
"php": ">=8.2",
"wp-coding-standards/wpcs": "~3.0.0",
"automattic/vipwpcs": "~3.0.0",
"fig-r/psr2r-sniffer": "^0.5.0",
"phpcompatibility/phpcompatibility-wp": "^2.0.0",
"squizlabs/php_codesniffer": "~3.5",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.0"
},
"require-dev": {
"phpunit/phpunit": "^7"
"phpunit/phpunit": "^8.2"
},
"scripts": {
"test": "phpunit"
Expand Down
12 changes: 11 additions & 1 deletion tests/FixtureTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,13 @@ public static function passing_files() {
/**
* Setup our ruleset.
*/
public function setUp() {
public function setUp(): void {
// AllSniffs uses ConfigDouble which sets Config::$configData = [] to prevent
// reading CodeSniffer.conf. Reset it so Ruleset can resolve installed standards.
$configDataProp = new \ReflectionProperty( Config::class, 'configData' );
$configDataProp->setAccessible( true );
$configDataProp->setValue( null, null );

$this->config = new Config();
$this->config->cache = false;
$this->config->standards = [ 'HM' ];
Expand Down Expand Up @@ -115,6 +121,10 @@ public function setUp() {

$this->ruleset = new Ruleset( $this->config );

// ExceptionNotEscaped is excluded in HM-Minimum ruleset.xml, but IN_TESTS mode
// with sniff restrictions skips processRuleset(), so apply the exclusion manually.
$this->ruleset->ruleset['HM.Security.EscapeOutput.ExceptionNotEscaped'] = [ 'severity' => 0 ];

// Set configuration as needed too.
$this->ruleset->setSniffProperty( 'HM\\Sniffs\\Security\\EscapeOutputSniff', 'customAutoEscapedFunctions', [
'scope' => 'sniff',
Expand Down
Loading