bug #34904 [Validator][ConstraintValidator] Safe fail on invalid timezones (fancyweb)
This PR was merged into the 3.4 branch.
Discussion
----------
[Validator][ConstraintValidator] Safe fail on invalid timezones
Co-authored-by: Scott Dawson <scott@loyaltycorp.com.au>
| Q | A
| ------------- | ---
| Branch? | 3.4
| Bug fix? | yes
| New feature? | no
| Deprecations? | no
| Tickets | https://github.com/symfony/symfony/issues/33901
| License | MIT
| Doc PR |
Alternative to https://github.com/symfony/symfony/pull/33902.
I will explain why I think it is better this way:
1. We set the timezone with the setter because it's 100% safe, it never fails. It fall backs to the default timezone if the provided timezone is not supported (as if we passed null, so the same behavior that always existed). We are therefore compatible with all edge cases.
2. We don't validate the timezone with `\DateTimeZone::listIdentifiers()`. It only returns full identifiers like "Europe/Paris" but it doesn't take into account "numeric" identifiers such as "+08:00" which are perfectly valid. I added a test case to ensure we stay valid with this case. + some invalid identifiers for the native `\IntlDateFormatter` are valid with the polyfill that uses `\DateTimeZone` (eg : `X`). I don't think we can validate anything safely that will work reliably on both implementations.
Commits
-------
3b1b994cb3
[Validator][ConstraintValidator] Safe fail on invalid timezones
This commit is contained in:
commit
e04331657f
@ -87,16 +87,12 @@ abstract class ConstraintValidator implements ConstraintValidatorInterface
|
||||
{
|
||||
if (($format & self::PRETTY_DATE) && $value instanceof \DateTimeInterface) {
|
||||
if (class_exists('IntlDateFormatter')) {
|
||||
$locale = \Locale::getDefault();
|
||||
$formatter = new \IntlDateFormatter($locale, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, $value->getTimezone());
|
||||
$formatter = new \IntlDateFormatter(\Locale::getDefault(), \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, 'UTC');
|
||||
|
||||
// neither the native nor the stub IntlDateFormatter support
|
||||
// DateTimeImmutable as of yet
|
||||
if (!$value instanceof \DateTime) {
|
||||
$value = new \DateTime($value->format('Y-m-d H:i:s.u e'));
|
||||
}
|
||||
|
||||
return $formatter->format($value);
|
||||
return $formatter->format(new \DateTime(
|
||||
$value->format('Y-m-d H:i:s.u'),
|
||||
new \DateTimeZone('UTC')
|
||||
));
|
||||
}
|
||||
|
||||
return $value->format('Y-m-d H:i:s');
|
||||
|
@ -27,6 +27,9 @@ final class ConstraintValidatorTest extends TestCase
|
||||
|
||||
public function formatValueProvider()
|
||||
{
|
||||
$defaultTimezone = date_default_timezone_get();
|
||||
date_default_timezone_set('Europe/Moscow'); // GMT+3
|
||||
|
||||
$data = [
|
||||
['true', true],
|
||||
['false', false],
|
||||
@ -36,10 +39,15 @@ final class ConstraintValidatorTest extends TestCase
|
||||
['array', []],
|
||||
['object', $toString = new TestToStringObject()],
|
||||
['ccc', $toString, ConstraintValidator::OBJECT_TO_STRING],
|
||||
['object', $dateTime = (new \DateTimeImmutable('@0'))->setTimezone(new \DateTimeZone('UTC'))],
|
||||
[class_exists(\IntlDateFormatter::class) ? 'Jan 1, 1970, 12:00 AM' : '1970-01-01 00:00:00', $dateTime, ConstraintValidator::PRETTY_DATE],
|
||||
['object', $dateTime = new \DateTimeImmutable('1971-02-02T08:00:00UTC')],
|
||||
[class_exists(\IntlDateFormatter::class) ? 'Oct 4, 2019, 11:02 AM' : '2019-10-04 11:02:03', new \DateTimeImmutable('2019-10-04T11:02:03+09:00'), ConstraintValidator::PRETTY_DATE],
|
||||
[class_exists(\IntlDateFormatter::class) ? 'Feb 2, 1971, 8:00 AM' : '1971-02-02 08:00:00', $dateTime, ConstraintValidator::PRETTY_DATE],
|
||||
[class_exists(\IntlDateFormatter::class) ? 'Jan 1, 1970, 6:00 AM' : '1970-01-01 06:00:00', new \DateTimeImmutable('1970-01-01T06:00:00Z'), ConstraintValidator::PRETTY_DATE],
|
||||
[class_exists(\IntlDateFormatter::class) ? 'Jan 1, 1970, 3:00 PM' : '1970-01-01 15:00:00', (new \DateTimeImmutable('1970-01-01T23:00:00'))->setTimezone(new \DateTimeZone('America/New_York')), ConstraintValidator::PRETTY_DATE],
|
||||
];
|
||||
|
||||
date_default_timezone_set($defaultTimezone);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user