From d83851dae86dbfbf4370ec42750b606e79de7ac3 Mon Sep 17 00:00:00 2001 From: Derick Rethans Date: Thu, 9 Jul 2026 15:29:05 +0100 Subject: [PATCH 1/2] Update timelib to 2022.17, which has fixes for PHP bugs --- NEWS | 7 +++++++ ext/date/lib/parse_date.re | 4 ++-- ext/date/lib/timelib.h | 6 +++--- ext/date/lib/timelib_private.h | 2 ++ ext/date/lib/tm2unixtime.c | 31 +++---------------------------- ext/date/lib/unixtime2tm.c | 27 ++++++++++++++++++--------- 6 files changed, 35 insertions(+), 42 deletions(-) diff --git a/NEWS b/NEWS index cdd6a48a4874..d64ce32ab995 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,13 @@ PHP NEWS . Fixed bug GH-22602 (gregoriantojd() and juliantojd() integer overflow with INT_MAX year). (arshidkv12) +- Date: + . Update timelib to 2022.17. (Derick) + . Fixed bug GH-19803 (Parsing a string with a single white space does create + an error). (Derick) + . Fixed Unix timestamps in February of the year 0 are misparsed with + @-notation. (LukasGelbmann) + - DBA: . Fixed OOB read on malformed length field in dba flatfile handler. (alhudz) diff --git a/ext/date/lib/parse_date.re b/ext/date/lib/parse_date.re index f4a392753249..07d9c0e73488 100644 --- a/ext/date/lib/parse_date.re +++ b/ext/date/lib/parse_date.re @@ -555,7 +555,6 @@ static timelib_ull timelib_get_signed_nr(Scanner *s, const char **ptr, int max_l int len = 0; /* Skip over non-numeric chars */ - while (((**ptr < '0') || (**ptr > '9')) && (**ptr != '+') && (**ptr != '-')) { if (**ptr == '\0') { add_error(s, TIMELIB_ERR_UNEXPECTED_DATA, "Found unexpected data"); @@ -569,6 +568,7 @@ static timelib_ull timelib_get_signed_nr(Scanner *s, const char **ptr, int max_l str[0] = '+'; /* First position is the sign */ str_ptr = str + 1; + while ((**ptr == '+') || (**ptr == '-')) { if (**ptr == '-') { str[0] = str[0] == '+' ? '-' : '+'; @@ -2020,7 +2020,7 @@ timelib_time *timelib_strtotime(const char *s, size_t len, timelib_error_contain in.errors->error_messages = NULL; if (len > 0) { - while (isspace((unsigned char)*s) && s < e) { + while (isspace((unsigned char)*s) && s <= e) { s++; } while (isspace((unsigned char)*e) && e > s) { diff --git a/ext/date/lib/timelib.h b/ext/date/lib/timelib.h index acae8e32533d..d08aa77ea5e5 100644 --- a/ext/date/lib/timelib.h +++ b/ext/date/lib/timelib.h @@ -30,9 +30,9 @@ # include "timelib_config.h" #endif -#define TIMELIB_VERSION 202215 -#define TIMELIB_EXTENDED_VERSION 20221501 -#define TIMELIB_ASCII_VERSION "2022.15" +#define TIMELIB_VERSION 202217 +#define TIMELIB_EXTENDED_VERSION 20221701 +#define TIMELIB_ASCII_VERSION "2022.17" #include #include diff --git a/ext/date/lib/timelib_private.h b/ext/date/lib/timelib_private.h index 3c5f9b22147c..42cbaa68dbbf 100644 --- a/ext/date/lib/timelib_private.h +++ b/ext/date/lib/timelib_private.h @@ -135,6 +135,7 @@ #ifndef TIMELIB_HAVE_BUILTIN_SADDLL_OVERFLOW # define TIMELIB_HAVE_BUILTIN_SADDLL_OVERFLOW 0 #endif + struct _ttinfo { int32_t offset; @@ -165,6 +166,7 @@ extern "C" { #endif /* From unixtime2tm.c */ +void timelib_date_from_epoch_days(timelib_sll epoch_days, timelib_sll *y, timelib_sll *m, timelib_sll *d); int timelib_apply_localtime(timelib_time *t, unsigned int localtime); /* From parse_posix.c */ diff --git a/ext/date/lib/tm2unixtime.c b/ext/date/lib/tm2unixtime.c index f13a9412406f..4c0252e244dd 100644 --- a/ext/date/lib/tm2unixtime.c +++ b/ext/date/lib/tm2unixtime.c @@ -197,32 +197,6 @@ void timelib_do_rel_normalize(timelib_time *base, timelib_rel_time *rt) do_range_limit(0, 12, 12, &rt->m, &rt->y); } -static void magic_date_calc(timelib_time *time) -{ - timelib_sll y, ddd, mi, mm, dd, g; - - /* The algorithm doesn't work before the year 1 */ - if (time->d < -719498) { - return; - } - - g = time->d + HINNANT_EPOCH_SHIFT - 1; - - y = (10000 * g + 14780) / 3652425; - ddd = g - ((365*y) + (y/4) - (y/100) + (y/400)); - if (ddd < 0) { - y--; - ddd = g - ((365*y) + (y/4) - (y/100) + (y/400)); - } - mi = (100 * ddd + 52) / 3060; - mm = ((mi + 2) % 12) + 1; - y = y + (mi + 2) / 12; - dd = ddd - ((mi * 306 + 5) / 10) + 1; - time->y = y; - time->m = mm; - time->d = dd; -} - void timelib_do_normalize(timelib_time* time) { if (time->us != TIMELIB_UNSET) do_range_limit(0, 1000000, 1000000, &time->us, &time->s); @@ -232,8 +206,9 @@ void timelib_do_normalize(timelib_time* time) do_range_limit(1, 13, 12, &time->m, &time->y); /* Short cut if we're doing things against the Epoch */ - if (time->y == 1970 && time->m == 1 && time->d != 1) { - magic_date_calc(time); + if (time->y == 1970 && time->m == 1) { + timelib_date_from_epoch_days(time->d - 1, &time->y, &time->m, &time->d); + return; } do {} while (do_range_limit_days(&time->y, &time->m, &time->d)); diff --git a/ext/date/lib/unixtime2tm.c b/ext/date/lib/unixtime2tm.c index 30b3d00c7f44..9c4ba901a93d 100644 --- a/ext/date/lib/unixtime2tm.c +++ b/ext/date/lib/unixtime2tm.c @@ -26,20 +26,16 @@ #include "timelib.h" #include "timelib_private.h" -void timelib_unixtime2date(timelib_sll ts, timelib_sll *y, timelib_sll *m, timelib_sll *d) +/* Converts Unix epoch days (days since 1970-01-01) to a date. Algorithm from: + * http://howardhinnant.github.io/date_algorithms.html#civil_from_days */ +void timelib_date_from_epoch_days(timelib_sll epoch_days, timelib_sll *y, timelib_sll *m, timelib_sll *d) { - timelib_sll days, era, t; + timelib_sll days, era; timelib_ull day_of_era, year_of_era, day_of_year, month_portion; /* Calculate days since algorithm's epoch (0000-03-01) */ - days = ts / SECS_PER_DAY + HINNANT_EPOCH_SHIFT; - - /* Adjustment for a negative time portion */ - t = ts % SECS_PER_DAY; - days += (t < 0) ? -1 : 0; + days = epoch_days + HINNANT_EPOCH_SHIFT; - /* Calculate year, month, and day. Algorithm from: - * http://howardhinnant.github.io/date_algorithms.html#civil_from_days */ era = (days >= 0 ? days : days - DAYS_PER_ERA + 1) / DAYS_PER_ERA; day_of_era = days - era * DAYS_PER_ERA; year_of_era = (day_of_era - day_of_era / 1460 + day_of_era / 36524 - day_of_era / 146096) / DAYS_PER_YEAR; @@ -49,6 +45,19 @@ void timelib_unixtime2date(timelib_sll ts, timelib_sll *y, timelib_sll *m, timel *d = day_of_year - (153 * month_portion + 2) / 5 + 1; *m = month_portion + (month_portion < 10 ? 3 : -9); *y += (*m <= 2); +} + +void timelib_unixtime2date(timelib_sll ts, timelib_sll *y, timelib_sll *m, timelib_sll *d) +{ + timelib_sll epoch_days, t; + + epoch_days = ts / SECS_PER_DAY; + + /* Adjustment for a negative time portion */ + t = ts % SECS_PER_DAY; + epoch_days += (t < 0) ? -1 : 0; + + timelib_date_from_epoch_days(epoch_days, y, m, d); TIMELIB_DEBUG(printf("A: ts=%lld, year=%lld, month=%lld, day=%lld,", ts, *y, *m, *d);); } From c3f1015e5655ac5d3ddb06f6a7c222886890bc83 Mon Sep 17 00:00:00 2001 From: James Titcumb Date: Thu, 9 Jul 2026 18:44:23 +0100 Subject: [PATCH 2/2] Add information about PIE extensions (#22613) Adds information about PIE to the PHP extensions section of the readme, also indicating that PECL is now deprecated. --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3f4e0534ede2..d83203d74c0b 100644 --- a/README.md +++ b/README.md @@ -130,8 +130,10 @@ permissions. ## PHP extensions Extensions provide additional functionality on top of PHP. PHP consists of many -essential bundled extensions. Additional extensions can be found in the PHP -Extension Community Library - [PECL](https://pecl.php.net). +essential bundled extensions. Additional extensions can be found on the +[PIE Extensions](https://packagist.org/extensions) list, and installed with +[🥧 PIE, the PHP Installer for Extensions](https://github.com/php/pie) or the +deprecated PHP Extension Community Library - [PECL](https://pecl.php.net). ## Contributing