From 09e619c64833715e5653247d55a193671fc3876a Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Tue, 20 Sep 2022 00:41:58 +0000 Subject: [PATCH] Date/Time: Correct sanitization of localized default `timezone_string` in `populate_options()`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a bug where if the default `timezone_string` is set to a deprecated timezone name due to a localization providing an outdated timezone name string, this localized timezone string would be discarded and an empty string would be set as the timezone value instead. By passing the `DateTimeZone::ALL_WITH_BC` constant as the `$timezoneGroup` parameter to the PHP native `timezone_identifiers_list()` function, a timezone name list is retrieved containing both current and deprecated timezone names, preventing the invalidation of the option value. See the extensive write-up about this in ticket #56468. Also see: [https://www.php.net/manual/en/datetimezone.listidentifiers.php PHP Manual: timezone_identifiers_list()]. Includes: * Expanding the translators comment to encourage translators to use “old” names over “new” names. * Adding a dedicated test to the `Tests_Admin_IncludesSchema` test class. Follow-up to [54207], [54217], [54227], [54229], [54230]. Props jrf, costdev. See #56468. git-svn-id: https://develop.svn.wordpress.org/trunk@54232 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/schema.php | 16 ++++++-- tests/phpunit/tests/admin/includesSchema.php | 41 ++++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/wp-admin/includes/schema.php b/src/wp-admin/includes/schema.php index 5a04ce4750..504acbf949 100644 --- a/src/wp-admin/includes/schema.php +++ b/src/wp-admin/includes/schema.php @@ -388,13 +388,23 @@ function populate_options( array $options = array() ) { /* * translators: default GMT offset or timezone string. Must be either a valid offset (-12 to 14) * or a valid timezone string (America/New_York). See https://www.php.net/manual/en/timezones.php - * for all timezone strings supported by PHP. + * for all timezone strings currently supported by PHP. + * + * Important: When a previous timezone string, like `Europe/Kiev`, has been superseded by an + * updated one, like `Europe/Kyiv`, as a rule of thumb, the **old** timezone name should be used + * in the "translation" to allow for the default timezone setting to be PHP cross-version compatible, + * as old timezone names will be recognized in new PHP versions, while new timezone names cannot + * be recognized in old PHP versions. + * + * To verify which timezone strings are available in the _oldest_ PHP version supported, you can + * use https://3v4l.org/6YQAt#v5.6.20 and replace the "BR" (Brazil) in the code line with the + * country code for which you want to look up the supported timezone names. */ $offset_or_tz = _x( '0', 'default GMT offset or timezone string' ); if ( is_numeric( $offset_or_tz ) ) { $gmt_offset = $offset_or_tz; - } elseif ( $offset_or_tz && in_array( $offset_or_tz, timezone_identifiers_list(), true ) ) { - $timezone_string = $offset_or_tz; + } elseif ( $offset_or_tz && in_array( $offset_or_tz, timezone_identifiers_list( DateTimeZone::ALL_WITH_BC ), true ) ) { + $timezone_string = $offset_or_tz; } $defaults = array( diff --git a/tests/phpunit/tests/admin/includesSchema.php b/tests/phpunit/tests/admin/includesSchema.php index ea392e41c3..f33dff148b 100644 --- a/tests/phpunit/tests/admin/includesSchema.php +++ b/tests/phpunit/tests/admin/includesSchema.php @@ -177,6 +177,47 @@ class Tests_Admin_IncludesSchema extends WP_UnitTestCase { ); } + /** + * Ensures that deprecated timezone strings set as a default in a translation are handled correctly. + * + * @ticket 56468 + */ + public function test_populate_options_when_locale_uses_deprecated_timezone_string() { + global $wpdb; + + // Back up. + $orig_options = $wpdb->options; + $wpdb->options = self::$options; + + // Set the "default" value for the timezone to a deprecated timezone. + add_filter( + 'gettext_with_context', + static function( $translation, $text, $context ) { + if ( '0' === $text && 'default GMT offset or timezone string' === $context ) { + return 'America/Buenos_Aires'; + } + + return $translation; + }, + 10, + 3 + ); + + // Test. + populate_options(); + + wp_cache_delete( 'alloptions', 'options' ); + + $result = get_option( 'timezone_string' ); + + // Reset. + $wpdb->query( "TRUNCATE TABLE {$wpdb->options}" ); + $wpdb->options = $orig_options; + + // Assert. + $this->assertSame( 'America/Buenos_Aires', $result ); + } + /** * @ticket 44896 * @group multisite