From 7947bce347122daa530b0b11864d34fb35e6e465 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 5 Oct 2019 03:29:33 +0200 Subject: [PATCH] New "DateTime.RestrictedFunctions" sniff This introduces a new `WordPress.DateTime.RestrictedFunctions` sniff which initially includes two groups: * `timezone_change` - moved from the `WordPress.WP.TimezoneChange` sniff * `date` - moved from the `WordPress.PHP.RestrictedPHPFunctions` sniff (group not yet in a released WPCS version yet) The `WordPress.WP.TimezoneChange` sniff is now deprecated. * The sniff is no longer included in the WPCS rulesets. * If the sniff is explicitly included via a custom ruleset, deprecation notices will be thrown. * If the `exclude` property is set from with a custom ruleset, a deprecation notice will be thrown. The new sniff is now included in the `Core` ruleset. Note: once WP Core upgrades, the one instance of using `date_default_timezone_set()` in WP Core (in `wp-settings.php`) will need to be whitelisted inline. There are a few more occurrences in the unit tests, but those can be ignored via file based excludes. Fixes 1805 --- WordPress-Core/ruleset.xml | 4 ++ WordPress-Extra/ruleset.xml | 1 - .../DateTime/RestrictedFunctionsSniff.php | 62 ++++++++++++++++ .../PHP/RestrictedPHPFunctionsSniff.php | 8 --- WordPress/Sniffs/WP/TimezoneChangeSniff.php | 72 ++++++++++++++----- .../DateTime/RestrictedFunctionsUnitTest.inc | 9 +++ .../DateTime/RestrictedFunctionsUnitTest.php | 44 ++++++++++++ .../PHP/RestrictedPHPFunctionsUnitTest.inc | 3 - .../PHP/RestrictedPHPFunctionsUnitTest.php | 1 - WordPress/Tests/WP/TimezoneChangeUnitTest.inc | 6 +- WordPress/Tests/WP/TimezoneChangeUnitTest.php | 7 +- WordPress/ruleset.xml | 6 +- 12 files changed, 187 insertions(+), 36 deletions(-) create mode 100644 WordPress/Sniffs/DateTime/RestrictedFunctionsSniff.php create mode 100644 WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc create mode 100644 WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php diff --git a/WordPress-Core/ruleset.xml b/WordPress-Core/ruleset.xml index 5d4c5deb66..949d16efe2 100644 --- a/WordPress-Core/ruleset.xml +++ b/WordPress-Core/ruleset.xml @@ -519,4 +519,8 @@ + + + diff --git a/WordPress-Extra/ruleset.xml b/WordPress-Extra/ruleset.xml index f44b0db786..a795891878 100644 --- a/WordPress-Extra/ruleset.xml +++ b/WordPress-Extra/ruleset.xml @@ -145,7 +145,6 @@ - diff --git a/WordPress/Sniffs/DateTime/RestrictedFunctionsSniff.php b/WordPress/Sniffs/DateTime/RestrictedFunctionsSniff.php new file mode 100644 index 0000000000..0da070190c --- /dev/null +++ b/WordPress/Sniffs/DateTime/RestrictedFunctionsSniff.php @@ -0,0 +1,62 @@ + array( + 'type' => 'error', + 'message' => 'Using %s() and similar isn\'t allowed, instead use WP internal timezone support.', + 'functions' => array( + 'date_default_timezone_set', + ), + ), + + /* + * Use gmdate(), not date(). + * Don't rely on the current PHP time zone as it might have been changed by third party code. + * + * @link https://make.wordpress.org/core/2019/09/23/date-time-improvements-wp-5-3/ + * @link https://core.trac.wordpress.org/ticket/46438 + * @link https://github.com/WordPress/WordPress-Coding-Standards/issues/1713 + */ + 'date' => array( + 'type' => 'error', + 'message' => '%s() is affected by runtime timezone changes which can cause date/time to be incorrectly displayed. Use gmdate() instead.', + 'functions' => array( + 'date', + ), + ), + ); + } + +} diff --git a/WordPress/Sniffs/PHP/RestrictedPHPFunctionsSniff.php b/WordPress/Sniffs/PHP/RestrictedPHPFunctionsSniff.php index b7f3bb14a1..280c94d919 100644 --- a/WordPress/Sniffs/PHP/RestrictedPHPFunctionsSniff.php +++ b/WordPress/Sniffs/PHP/RestrictedPHPFunctionsSniff.php @@ -17,7 +17,6 @@ * @package WPCS\WordPressCodingStandards * * @since 0.14.0 - * @since 2.2.0 New group `date` added. */ class RestrictedPHPFunctionsSniff extends AbstractFunctionRestrictionsSniff { @@ -43,13 +42,6 @@ public function getGroups() { 'create_function', ), ), - 'date' => array( - 'type' => 'error', - 'message' => '%s() is affected by runtime timezone changes which can cause date/time to be incorrectly displayed. Use gmdate() instead.', - 'functions' => array( - 'date', - ), - ), ); } diff --git a/WordPress/Sniffs/WP/TimezoneChangeSniff.php b/WordPress/Sniffs/WP/TimezoneChangeSniff.php index 5712df975c..f376c5e3a3 100644 --- a/WordPress/Sniffs/WP/TimezoneChangeSniff.php +++ b/WordPress/Sniffs/WP/TimezoneChangeSniff.php @@ -9,7 +9,7 @@ namespace WordPressCS\WordPress\Sniffs\WP; -use WordPressCS\WordPress\AbstractFunctionRestrictionsSniff; +use WordPressCS\WordPress\Sniffs\DateTime\RestrictedFunctionsSniff; /** * Disallow the changing of timezone. @@ -23,32 +23,66 @@ * class instead of the upstream `Generic.PHP.ForbiddenFunctions` sniff. * @since 0.13.0 Class name changed: this class is now namespaced. * @since 1.0.0 This sniff has been moved from the `VIP` category to the `WP` category. + * + * @deprecated 2.2.0 Use the `WordPress.DateTime.RestrictedFunctions` sniff instead. + * This `WordPress.WP.TimezoneChange` sniff will be removed in WPCS 3.0.0. */ -class TimezoneChangeSniff extends AbstractFunctionRestrictionsSniff { +class TimezoneChangeSniff extends RestrictedFunctionsSniff { /** - * Groups of functions to restrict. + * Keep track of whether the warnings have been thrown to prevent + * the messages being thrown for every token triggering the sniff. * - * Example: groups => array( - * 'lambda' => array( - * 'type' => 'error' | 'warning', - * 'message' => 'Use anonymous functions instead please!', - * 'functions' => array( 'file_get_contents', 'create_function' ), - * ) - * ) + * @since 2.2.0 + * + * @var array + */ + private $thrown = array( + 'DeprecatedSniff' => false, + 'FoundPropertyForDeprecatedSniff' => false, + ); + + /** + * Don't use. + * + * @deprecated 2.2.0 * * @return array */ public function getGroups() { - return array( - 'timezone_change' => array( - 'type' => 'error', - 'message' => 'Using %s() and similar isn\'t allowed, instead use WP internal timezone support.', - 'functions' => array( - 'date_default_timezone_set', - ), - ), - ); + $groups = parent::getGroups(); + return array( 'timezone_change' => $groups['timezone_change'] ); } + /** + * Don't use. + * + * @since 2.2.0 Added to allow for throwing the deprecation notices. + * @deprecated 2.2.0 + * + * @param int $stackPtr The position of the current token in the stack. + * + * @return void|int + */ + public function process_token( $stackPtr ) { + if ( false === $this->thrown['DeprecatedSniff'] ) { + $this->thrown['DeprecatedSniff'] = $this->phpcsFile->addWarning( + 'The "WordPress.WP.TimezoneChange" sniff has been deprecated. Use the "WordPress.DateTime.RestrictedFunctions" sniff instead. Please update your custom ruleset.', + 0, + 'DeprecatedSniff' + ); + } + + if ( ! empty( $this->exclude ) + && false === $this->thrown['FoundPropertyForDeprecatedSniff'] + ) { + $this->thrown['FoundPropertyForDeprecatedSniff'] = $this->phpcsFile->addWarning( + 'The "WordPress.WP.TimezoneChange" sniff has been deprecated. Use the "WordPress.DateTime.RestrictedFunctions" sniff instead. "exclude" property setting found. Please update your custom ruleset.', + 0, + 'FoundPropertyForDeprecatedSniff' + ); + } + + return parent::process_token( $stackPtr ); + } } diff --git a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc new file mode 100644 index 0000000000..25227b5178 --- /dev/null +++ b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.inc @@ -0,0 +1,9 @@ +setTimezone( new DateTimeZone( 'America/Toronto' ) ); // Yay! + +$post_data['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( __( 'F j, Y' ), $now ), date( __( 'g:i a' ), $now ) ); // Error. +$post_data['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), gmdate( __( 'F j, Y' ), $now ), gmdate( __( 'g:i a' ), $now ) ); // OK. diff --git a/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php new file mode 100644 index 0000000000..ecfc78867f --- /dev/null +++ b/WordPress/Tests/DateTime/RestrictedFunctionsUnitTest.php @@ -0,0 +1,44 @@ + => + */ + public function getErrorList() { + return array( + 3 => 1, + 8 => 2, + ); + } + + /** + * Returns the lines where warnings should occur. + * + * @return array => + */ + public function getWarningList() { + return array(); + } + +} diff --git a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc index 2a4e8754b5..84dbd1d7b3 100644 --- a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc +++ b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.inc @@ -3,6 +3,3 @@ add_action( 'widgets_init', create_function( '', // Error. 'return register_widget( "time_more_on_time_widget" );' ) ); - -$post_data['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), date( __( 'F j, Y' ), $now ), date( __( 'g:i a' ), $now ) ); // Error. -$post_data['post_title'] = sprintf( __( 'Draft created on %1$s at %2$s' ), gmdate( __( 'F j, Y' ), $now ), gmdate( __( 'g:i a' ), $now ) ); // OK. diff --git a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php index 3d21aa7195..af8707d3cd 100644 --- a/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php +++ b/WordPress/Tests/PHP/RestrictedPHPFunctionsUnitTest.php @@ -28,7 +28,6 @@ class RestrictedPHPFunctionsUnitTest extends AbstractSniffUnitTest { public function getErrorList() { return array( 3 => 1, - 7 => 2, ); } diff --git a/WordPress/Tests/WP/TimezoneChangeUnitTest.inc b/WordPress/Tests/WP/TimezoneChangeUnitTest.inc index 4e38791f9b..c1a374c306 100644 --- a/WordPress/Tests/WP/TimezoneChangeUnitTest.inc +++ b/WordPress/Tests/WP/TimezoneChangeUnitTest.inc @@ -2,5 +2,7 @@ date_default_timezone_set( 'Foo/Bar' ); // Bad. -$date = new DateTime(); -$date->setTimezone( new DateTimeZone( 'America/Toronto' ) ); // Yay! +// phpcs:set WordPress.WP.TimezoneChange exclude[] timezone_change +date_default_timezone_set( 'Foo/Bar' ); // OK. + +// phpcs:set WordPress.WP.TimezoneChange exclude[] diff --git a/WordPress/Tests/WP/TimezoneChangeUnitTest.php b/WordPress/Tests/WP/TimezoneChangeUnitTest.php index 81e86d1e6e..906883077b 100644 --- a/WordPress/Tests/WP/TimezoneChangeUnitTest.php +++ b/WordPress/Tests/WP/TimezoneChangeUnitTest.php @@ -19,6 +19,9 @@ * @since 0.3.0 * @since 0.13.0 Class name changed: this class is now namespaced. * @since 1.0.0 This sniff has been moved from the `VIP` category to the `WP` category. + * @since 2.2.0 The sniff has been deprecated. This unit test file now + * only tests that the deprecation warnings are correctly thrown + * and that the sniff falls through to the parent correctly. */ class TimezoneChangeUnitTest extends AbstractSniffUnitTest { @@ -39,7 +42,9 @@ public function getErrorList() { * @return array => */ public function getWarningList() { - return array(); + return array( + 1 => 2, + ); } } diff --git a/WordPress/ruleset.xml b/WordPress/ruleset.xml index fd24ae6318..20ff9a38cc 100644 --- a/WordPress/ruleset.xml +++ b/WordPress/ruleset.xml @@ -8,6 +8,10 @@ --> - + + + + +