1
0
mirror of https://github.com/php/php-src.git synced 2026-04-20 22:41:20 +02:00

Merge remote-tracking branch 'derickr/bug75035-big-year-serialisation'

This commit is contained in:
Derick Rethans
2022-07-22 15:36:04 +01:00
15 changed files with 191 additions and 46 deletions

4
NEWS
View File

@@ -7,6 +7,10 @@ PHP NEWS
different type). (Derick)
. Fixed bug GH-8964 (DateTime object comparison after applying delta less
than 1 second). (Derick)
. Fixed bug #75035 (Datetime fails to unserialize "extreme" dates).
(Derick)
. Fixed bug #80483 (DateTime Object with 5-digit year can't unserialized).
(Derick)
. Fixed bug #81263 (Wrong result from DateTimeImmutable::diff). (Derick)
- DBA:

View File

@@ -1,4 +1,4 @@
/* Generated by re2c 0.15.3 on Sun Jun 26 17:34:01 2022 */
/* Generated by re2c 0.15.3 on Fri Jul 22 15:29:55 2022 */
#line 1 "ext/date/lib/parse_date.re"
/*
* The MIT License (MIT)
@@ -26004,7 +26004,7 @@ timelib_time *timelib_strtotime(const char *s, size_t len, timelib_error_contain
add_pbf_error(s, TIMELIB_ERR_UNEXPECTED_DATA, "Unexpected data found.", string, begin); \
}
#define TIMELIB_CHECK_SIGNED_NUMBER \
if (strchr("-0123456789", *ptr) == NULL) \
if (strchr("+-0123456789", *ptr) == NULL) \
{ \
add_pbf_error(s, TIMELIB_ERR_UNEXPECTED_DATA, "Unexpected data found.", string, begin); \
}
@@ -26079,6 +26079,8 @@ static const timelib_format_specifier default_format_map[] = {
{' ', TIMELIB_FORMAT_WHITESPACE},
{'y', TIMELIB_FORMAT_YEAR_TWO_DIGIT},
{'Y', TIMELIB_FORMAT_YEAR_FOUR_DIGIT},
{'x', TIMELIB_FORMAT_YEAR_EXPANDED},
{'X', TIMELIB_FORMAT_YEAR_EXPANDED},
{'\0', TIMELIB_FORMAT_END}
};
@@ -26265,6 +26267,15 @@ timelib_time *timelib_parse_from_format_with_map(const char *format, const char
break;
}
s->time->have_date = 1;
break;
case TIMELIB_FORMAT_YEAR_EXPANDED: /* optional symbol, followed by up to 19 digits */
TIMELIB_CHECK_SIGNED_NUMBER;
if ((s->time->y = timelib_get_signed_nr(s, &ptr, 19)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_FOUR_DIGIT_YEAR, "An expanded digit year could not be found", string, begin);
break;
}
s->time->have_date = 1;
break;
case TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX: /* two digit hour, without leading zero */

View File

@@ -2006,7 +2006,7 @@ timelib_time *timelib_strtotime(const char *s, size_t len, timelib_error_contain
add_pbf_error(s, TIMELIB_ERR_UNEXPECTED_DATA, "Unexpected data found.", string, begin); \
}
#define TIMELIB_CHECK_SIGNED_NUMBER \
if (strchr("-0123456789", *ptr) == NULL) \
if (strchr("+-0123456789", *ptr) == NULL) \
{ \
add_pbf_error(s, TIMELIB_ERR_UNEXPECTED_DATA, "Unexpected data found.", string, begin); \
}
@@ -2081,6 +2081,8 @@ static const timelib_format_specifier default_format_map[] = {
{' ', TIMELIB_FORMAT_WHITESPACE},
{'y', TIMELIB_FORMAT_YEAR_TWO_DIGIT},
{'Y', TIMELIB_FORMAT_YEAR_FOUR_DIGIT},
{'x', TIMELIB_FORMAT_YEAR_EXPANDED},
{'X', TIMELIB_FORMAT_YEAR_EXPANDED},
{'\0', TIMELIB_FORMAT_END}
};
@@ -2267,6 +2269,15 @@ timelib_time *timelib_parse_from_format_with_map(const char *format, const char
break;
}
s->time->have_date = 1;
break;
case TIMELIB_FORMAT_YEAR_EXPANDED: /* optional symbol, followed by up to 19 digits */
TIMELIB_CHECK_SIGNED_NUMBER;
if ((s->time->y = timelib_get_signed_nr(s, &ptr, 19)) == TIMELIB_UNSET) {
add_pbf_error(s, TIMELIB_ERR_NO_FOUR_DIGIT_YEAR, "An expanded digit year could not be found", string, begin);
break;
}
s->time->have_date = 1;
break;
case TIMELIB_FORMAT_HOUR_TWO_DIGIT_12_MAX: /* two digit hour, without leading zero */

View File

@@ -1,4 +1,4 @@
/* Generated by re2c 0.15.3 on Sun Jun 26 17:34:21 2022 */
/* Generated by re2c 0.15.3 on Fri Jul 22 15:30:08 2022 */
#line 1 "ext/date/lib/parse_iso_intervals.re"
/*
* The MIT License (MIT)

View File

@@ -30,9 +30,9 @@
# include "timelib_config.h"
#endif
#define TIMELIB_VERSION 202115
#define TIMELIB_EXTENDED_VERSION 20211501
#define TIMELIB_ASCII_VERSION "2021.15"
#define TIMELIB_VERSION 202201
#define TIMELIB_EXTENDED_VERSION 20220101
#define TIMELIB_ASCII_VERSION "2022.01"
#include <stdlib.h>
#include <stdbool.h>
@@ -438,6 +438,7 @@ typedef enum _timelib_format_specifier_code {
TIMELIB_FORMAT_WHITESPACE,
TIMELIB_FORMAT_YEAR_TWO_DIGIT,
TIMELIB_FORMAT_YEAR_FOUR_DIGIT,
TIMELIB_FORMAT_YEAR_EXPANDED,
TIMELIB_FORMAT_YEAR_ISO
} timelib_format_specifier_code;

View File

@@ -134,6 +134,7 @@ PHPAPI time_t php_time(void)
* zone = (( "+" / "-" ) 4DIGIT)
*/
#define DATE_FORMAT_RFC2822 "D, d M Y H:i:s O"
/*
* RFC3339, Section 5.6: http://www.ietf.org/rfc/rfc3339.txt
* date-fullyear = 4DIGIT
@@ -156,8 +157,42 @@ PHPAPI time_t php_time(void)
*/
#define DATE_FORMAT_RFC3339 "Y-m-d\\TH:i:sP"
/*
* This format does not technically match the ISO 8601 standard, as it does not
* use : in the UTC offset format specifier. This is kept for BC reasons. The
* DATE_FORMAT_ISO8601_EXPANDED format does correct this, as well as adding
* support for years out side of the traditional 0000-9999 range.
*/
#define DATE_FORMAT_ISO8601 "Y-m-d\\TH:i:sO"
/* ISO 8601:2004(E)
*
* Section 3.5 Expansion:
* By mutual agreement of the partners in information interchange, it is
* permitted to expand the component identifying the calendar year, which is
* otherwise limited to four digits. This enables reference to dates and times
* in calendar years outside the range supported by complete representations,
* i.e. before the start of the year [0000] or after the end of the year
* [9999]."
*
* Section 4.1.2.4 Expanded representations:
* If, by agreement, expanded representations are used, the formats shall be as
* specified below. The interchange parties shall agree the additional number of
* digits in the time element year. In the examples below it has been agreed to
* expand the time element year with two digits.
* Extended format: ±YYYYY-MM-DD
* Example: +001985-04-12
*
* PHP's year expansion digits are variable.
*/
#define DATE_FORMAT_ISO8601_EXPANDED "X-m-d\\TH:i:sP"
/* Internal Only
* This format only extends the year when needed, keeping the 'P' format with
* colon for UTC offsets
*/
#define DATE_FORMAT_ISO8601_LARGE_YEAR "x-m-d\\TH:i:sP"
/*
* RFC3339, Appendix A: http://www.ietf.org/rfc/rfc3339.txt
* ISO 8601 also requires (in section 5.3.1.3) that a decimal fraction
@@ -659,6 +694,8 @@ static zend_string *date_format(const char *format, size_t format_len, timelib_t
case 'L': length = slprintf(buffer, sizeof(buffer), "%d", timelib_is_leap((int) t->y)); break;
case 'y': length = slprintf(buffer, sizeof(buffer), "%02d", (int) (t->y % 100)); break;
case 'Y': length = slprintf(buffer, sizeof(buffer), "%s%04lld", t->y < 0 ? "-" : "", php_date_llabs((timelib_sll) t->y)); break;
case 'x': length = slprintf(buffer, sizeof(buffer), "%s%04lld", t->y < 0 ? "-" : (t->y >= 10000 ? "+" : ""), php_date_llabs((timelib_sll) t->y)); break;
case 'X': length = slprintf(buffer, sizeof(buffer), "%s%04lld", t->y < 0 ? "-" : "+", php_date_llabs((timelib_sll) t->y)); break;
/* time */
case 'a': length = slprintf(buffer, sizeof(buffer), "%s", t->h >= 12 ? "pm" : "am"); break;
@@ -1810,7 +1847,7 @@ static void date_object_to_hash(php_date_obj *dateobj, HashTable *props)
zval zv;
/* first we add the date and time in ISO format */
ZVAL_STR(&zv, date_format("Y-m-d H:i:s.u", sizeof("Y-m-d H:i:s.u")-1, dateobj->time, 1));
ZVAL_STR(&zv, date_format("x-m-d H:i:s.u", sizeof("x-m-d H:i:s.u")-1, dateobj->time, 1));
zend_hash_str_update(props, "date", sizeof("date")-1, &zv);
/* then we add the timezone name (or similar) */
@@ -3800,7 +3837,7 @@ PHP_FUNCTION(timezone_transitions_get)
#define add_nominal() \
array_init(&element); \
add_assoc_long(&element, "ts", timestamp_begin); \
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, timestamp_begin, 0)); \
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, timestamp_begin, 0)); \
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[0].offset); \
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[0].isdst); \
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[0].abbr_idx]); \
@@ -3809,7 +3846,7 @@ PHP_FUNCTION(timezone_transitions_get)
#define add(i,ts) \
array_init(&element); \
add_assoc_long(&element, "ts", ts); \
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, ts, 0)); \
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].offset); \
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].isdst); \
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[tzobj->tzi.tz->trans_idx[i]].abbr_idx]); \
@@ -3818,7 +3855,7 @@ PHP_FUNCTION(timezone_transitions_get)
#define add_by_index(i,ts) \
array_init(&element); \
add_assoc_long(&element, "ts", ts); \
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, ts, 0)); \
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
add_assoc_long(&element, "offset", tzobj->tzi.tz->type[i].offset); \
add_assoc_bool(&element, "isdst", tzobj->tzi.tz->type[i].isdst); \
add_assoc_string(&element, "abbr", &tzobj->tzi.tz->timezone_abbr[tzobj->tzi.tz->type[i].abbr_idx]); \
@@ -3827,7 +3864,7 @@ PHP_FUNCTION(timezone_transitions_get)
#define add_from_tto(to,ts) \
array_init(&element); \
add_assoc_long(&element, "ts", ts); \
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601, 13, ts, 0)); \
add_assoc_str(&element, "time", php_format_date(DATE_FORMAT_ISO8601_LARGE_YEAR, 13, ts, 0)); \
add_assoc_long(&element, "offset", (to)->offset); \
add_assoc_bool(&element, "isdst", (to)->is_dst); \
add_assoc_string(&element, "abbr", (to)->abbr); \

View File

@@ -20,6 +20,12 @@ const DATE_COOKIE = "l, d-M-Y H:i:s T";
*/
const DATE_ISO8601 = "Y-m-d\\TH:i:sO";
/**
* @var string
* @cvalue DATE_FORMAT_ISO8601_EXPANDED
*/
const DATE_ISO8601_EXPANDED = "X-m-d\\TH:i:sP";
/**
* @var string
* @cvalue DATE_FORMAT_RFC822
@@ -285,6 +291,8 @@ interface DateTimeInterface
/** @var string */
public const ISO8601 = DATE_ISO8601;
/** @var string */
public const ISO8601_EXPANDED = DATE_ISO8601_EXPANDED;
/** @var string */
public const RFC822 = DATE_RFC822;
/** @var string */
public const RFC850 = DATE_RFC850;

View File

@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 5ccde6eb3c96eda925633f50091c7019050846be */
* Stub hash: 6949e2c795288f9615222b1fd496768ab20eb7c5 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strtotime, 0, 1, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, datetime, IS_STRING, 0)
@@ -756,6 +756,8 @@ static void register_php_date_symbols(int module_number)
ZEND_ASSERT(strcmp(DATE_FORMAT_COOKIE, "l, d-M-Y H:i:s T") == 0);
REGISTER_STRING_CONSTANT("DATE_ISO8601", DATE_FORMAT_ISO8601, CONST_CS | CONST_PERSISTENT);
ZEND_ASSERT(strcmp(DATE_FORMAT_ISO8601, "Y-m-d\\TH:i:sO") == 0);
REGISTER_STRING_CONSTANT("DATE_ISO8601_EXPANDED", DATE_FORMAT_ISO8601_EXPANDED, CONST_CS | CONST_PERSISTENT);
ZEND_ASSERT(strcmp(DATE_FORMAT_ISO8601_EXPANDED, "X-m-d\\TH:i:sP") == 0);
REGISTER_STRING_CONSTANT("DATE_RFC822", DATE_FORMAT_RFC822, CONST_CS | CONST_PERSISTENT);
ZEND_ASSERT(strcmp(DATE_FORMAT_RFC822, "D, d M y H:i:s O") == 0);
REGISTER_STRING_CONSTANT("DATE_RFC850", DATE_FORMAT_RFC850, CONST_CS | CONST_PERSISTENT);
@@ -807,6 +809,13 @@ static zend_class_entry *register_class_DateTimeInterface(void)
zend_declare_class_constant_ex(class_entry, const_ISO8601_name, &const_ISO8601_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_ISO8601_name);
zval const_ISO8601_EXPANDED_value;
zend_string *const_ISO8601_EXPANDED_value_str = zend_string_init(DATE_FORMAT_ISO8601_EXPANDED, sizeof(DATE_FORMAT_ISO8601_EXPANDED) - 1, 1);
ZVAL_STR(&const_ISO8601_EXPANDED_value, const_ISO8601_EXPANDED_value_str);
zend_string *const_ISO8601_EXPANDED_name = zend_string_init_interned("ISO8601_EXPANDED", sizeof("ISO8601_EXPANDED") - 1, 1);
zend_declare_class_constant_ex(class_entry, const_ISO8601_EXPANDED_name, &const_ISO8601_EXPANDED_value, ZEND_ACC_PUBLIC, NULL);
zend_string_release(const_ISO8601_EXPANDED_name);
zval const_RFC822_value;
zend_string *const_RFC822_value_str = zend_string_init(DATE_FORMAT_RFC822, sizeof(DATE_FORMAT_RFC822) - 1, 1);
ZVAL_STR(&const_RFC822_value, const_RFC822_value_str);

View File

@@ -32,7 +32,7 @@ array(5) {
["ts"]=>
int(-213228000)
["time"]=>
string(24) "1963-03-31T02:00:00+0000"
string(25) "1963-03-31T02:00:00+00:00"
["offset"]=>
int(3600)
["isdst"]=>

View File

@@ -24,35 +24,35 @@ showTransitions('Europe/Paris', 1645095600); // GH Issue 8108
--EXPECT--
Europe/London from @1648342200-@1727398200:
1648342200 2022-03-27T00:50:00+0000 0 x GMT
1648342800 2022-03-27T01:00:00+0000 3600 DST BST
1667091600 2022-10-30T01:00:00+0000 0 x GMT
1679792400 2023-03-26T01:00:00+0000 3600 DST BST
1698541200 2023-10-29T01:00:00+0000 0 x GMT
1711846800 2024-03-31T01:00:00+0000 3600 DST BST
1648342200 2022-03-27T00:50:00+00:00 0 x GMT
1648342800 2022-03-27T01:00:00+00:00 3600 DST BST
1667091600 2022-10-30T01:00:00+00:00 0 x GMT
1679792400 2023-03-26T01:00:00+00:00 3600 DST BST
1698541200 2023-10-29T01:00:00+00:00 0 x GMT
1711846800 2024-03-31T01:00:00+00:00 3600 DST BST
America/Los_Angeles from @1648557596-@1727613596:
1648557596 2022-03-29T12:39:56+0000 -25200 DST PDT
1667725200 2022-11-06T09:00:00+0000 -28800 x PST
1678615200 2023-03-12T10:00:00+0000 -25200 DST PDT
1699174800 2023-11-05T09:00:00+0000 -28800 x PST
1710064800 2024-03-10T10:00:00+0000 -25200 DST PDT
1648557596 2022-03-29T12:39:56+00:00 -25200 DST PDT
1667725200 2022-11-06T09:00:00+00:00 -28800 x PST
1678615200 2023-03-12T10:00:00+00:00 -25200 DST PDT
1699174800 2023-11-05T09:00:00+00:00 -28800 x PST
1710064800 2024-03-10T10:00:00+00:00 -25200 DST PDT
America/Chicago from @1293861600-@1372917600:
1293861600 2011-01-01T06:00:00+0000 -21600 x CST
1300003200 2011-03-13T08:00:00+0000 -18000 DST CDT
1320562800 2011-11-06T07:00:00+0000 -21600 x CST
1331452800 2012-03-11T08:00:00+0000 -18000 DST CDT
1352012400 2012-11-04T07:00:00+0000 -21600 x CST
1362902400 2013-03-10T08:00:00+0000 -18000 DST CDT
1293861600 2011-01-01T06:00:00+00:00 -21600 x CST
1300003200 2011-03-13T08:00:00+00:00 -18000 DST CDT
1320562800 2011-11-06T07:00:00+00:00 -21600 x CST
1331452800 2012-03-11T08:00:00+00:00 -18000 DST CDT
1352012400 2012-11-04T07:00:00+00:00 -21600 x CST
1362902400 2013-03-10T08:00:00+00:00 -18000 DST CDT
Europe/Paris from @1645095600-@1724151600:
1645095600 2022-02-17T11:00:00+0000 3600 x CET
1648342800 2022-03-27T01:00:00+0000 7200 DST CEST
1667091600 2022-10-30T01:00:00+0000 3600 x CET
1679792400 2023-03-26T01:00:00+0000 7200 DST CEST
1698541200 2023-10-29T01:00:00+0000 3600 x CET
1711846800 2024-03-31T01:00:00+0000 7200 DST CEST
1645095600 2022-02-17T11:00:00+00:00 3600 x CET
1648342800 2022-03-27T01:00:00+00:00 7200 DST CEST
1667091600 2022-10-30T01:00:00+00:00 3600 x CET
1679792400 2023-03-26T01:00:00+00:00 7200 DST CEST
1698541200 2023-10-29T01:00:00+00:00 3600 x CET
1711846800 2024-03-31T01:00:00+00:00 7200 DST CEST

View File

@@ -0,0 +1,29 @@
--TEST--
Bug #75035 (Datetime fails to unserialize "extreme" dates)
--INI--
date.timezone=UTC
--FILE--
<?php
var_dump('PHP version', PHP_VERSION);
foreach ([PHP_INT_MIN, PHP_INT_MAX] as $extreme) {
$i = 64;
while ($i --> 0) {
$d = new DateTime('@' . ($extreme >> $i));
$s = serialize($d);
try {
$u = unserialize($s);
} catch (Error $e) {
$u = "failed unserialization: " . $e->getMessage() . ' : ' . $s;
}
$original = $d->format('Y-m-d H:i:s');
$serializedUnserialized = is_string($u) ? $u : $u->format('Y-m-d H:i:s');
if ($original !== $serializedUnserialized) {
var_dump('[' . ($extreme >> $i) . '] ' . $original . ' => ' . $serializedUnserialized);
}
}
}
?>
--EXPECTF--
string(11) "PHP version"
string(%d) "%s"

View File

@@ -0,0 +1,35 @@
--TEST--
Bug #80483 (DateTime Object with 5-digit year can't unserialized)
--INI--
date.timezone=UTC
--FILE--
<?php
$the_date = new DateTime();
$the_date->SetTime(0, 0, 0);
$the_date->SetDate(20201, 01, 01);
var_dump($the_date);
$serialized = serialize($the_date);
var_dump($serialized);
var_dump(unserialize($serialized));
?>
--EXPECTF--
object(DateTime)#%d (%d) {
["date"]=>
string(28) "+20201-01-01 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}
string(116) "O:8:"DateTime":3:{s:4:"date";s:28:"+20201-01-01 00:00:00.000000";s:13:"timezone_type";i:3;s:8:"timezone";s:3:"UTC";}"
object(DateTime)#%d (%d) {
["date"]=>
string(28) "+20201-01-01 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(3) "UTC"
}

View File

@@ -19,7 +19,7 @@ array(5) {
["ts"]=>
int(2140045200)
["time"]=>
string(24) "2037-10-25T01:00:00+0000"
string(25) "2037-10-25T01:00:00+00:00"
["offset"]=>
int(0)
["isdst"]=>
@@ -32,7 +32,7 @@ array(5) {
["ts"]=>
int(2140668000)
["time"]=>
string(24) "2037-11-01T06:00:00+0000"
string(25) "2037-11-01T06:00:00+00:00"
["offset"]=>
int(-18000)
["isdst"]=>
@@ -45,7 +45,7 @@ array(5) {
["ts"]=>
int(2140045200)
["time"]=>
string(24) "2037-10-25T01:00:00+0000"
string(25) "2037-10-25T01:00:00+00:00"
["offset"]=>
int(3600)
["isdst"]=>

View File

@@ -11,8 +11,8 @@ foreach ($tz->getTransitions(strtotime("1996-01-01"), strtotime("1997-12-31")) a
}
?>
--EXPECT--
1996-01-01T00:00:00+0000 3600 CET
1996-03-31T01:00:00+0000 7200 CEST
1996-10-27T01:00:00+0000 3600 CET
1997-03-30T01:00:00+0000 7200 CEST
1997-10-26T01:00:00+0000 3600 CET
1996-01-01T00:00:00+00:00 3600 CET
1996-03-31T01:00:00+00:00 7200 CEST
1996-10-27T01:00:00+00:00 3600 CET
1997-03-30T01:00:00+00:00 7200 CEST
1997-10-26T01:00:00+00:00 3600 CET

View File

@@ -35,7 +35,7 @@ array(5) {
["ts"]=>
int(-213228000)
["time"]=>
string(24) "1963-03-31T02:00:00+0000"
string(25) "1963-03-31T02:00:00+00:00"
["offset"]=>
int(3600)
["isdst"]=>