From 15e3fcb468d7ef6faddc8f99f8f708fe8c2d8492 Mon Sep 17 00:00:00 2001 From: Derick Rethans Date: Thu, 11 Aug 2022 14:41:22 +0100 Subject: [PATCH 1/2] Fixed GH-9200: setcookie has an obsolete expires date format --- NEWS | 1 + ext/standard/head.c | 8 +++----- ext/standard/tests/network/bug72071.phpt | 2 +- ext/standard/tests/network/setcookie.phpt | 14 +++++++------- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index 77954599d3b..cf376832ae4 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,7 @@ PHP NEWS - Standard: . Fixed bug #65489 (glob() basedir check is inconsistent). (Jakub Zelenka) + . Fixed GH-9200 (setcookie has an obsolete expires date format). (Derick) . Fixed GH-9244 (Segfault with array_multisort + array_shift). (cmb) 04 Aug 2022, PHP 8.2.0beta2 diff --git a/ext/standard/head.c b/ext/standard/head.c index ab64fecf381..608959adeb9 100644 --- a/ext/standard/head.c +++ b/ext/standard/head.c @@ -118,7 +118,7 @@ PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t e * so in order to force cookies to be deleted, even on MSIE, we * pick an expiry date in the past */ - dt = php_format_date("D, d-M-Y H:i:s T", sizeof("D, d-M-Y H:i:s T")-1, 1, 0); + dt = php_format_date("D, d M Y H:i:s \\G\\M\\T", sizeof("D, d M Y H:i:s \\G\\M\\T")-1, 1, 0); smart_str_appends(&buf, "Set-Cookie: "); smart_str_append(&buf, name); smart_str_appends(&buf, "=deleted; expires="); @@ -137,14 +137,12 @@ PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t e smart_str_append(&buf, value); } if (expires > 0) { - const char *p; double diff; smart_str_appends(&buf, COOKIE_EXPIRES); - dt = php_format_date("D, d-M-Y H:i:s T", sizeof("D, d-M-Y H:i:s T")-1, expires, 0); + dt = php_format_date("D, d M Y H:i:s \\G\\M\\T", sizeof("D, d M Y H:i:s \\G\\M\\T")-1, expires, 0); /* check to make sure that the year does not exceed 4 digits in length */ - p = zend_memrchr(ZSTR_VAL(dt), '-', ZSTR_LEN(dt)); - if (!p || *(p + 5) != ' ') { + if (php_idate('Y', expires, 0) > 9999) { zend_string_free(dt); smart_str_free(&buf); zend_value_error("%s(): \"expires\" option cannot have a year greater than 9999", diff --git a/ext/standard/tests/network/bug72071.phpt b/ext/standard/tests/network/bug72071.phpt index 6d19ab46e37..3940083f06a 100644 --- a/ext/standard/tests/network/bug72071.phpt +++ b/ext/standard/tests/network/bug72071.phpt @@ -11,4 +11,4 @@ setcookie("name", "value", $date); ?> --EXPECT-- --EXPECTHEADERS-- -Set-Cookie: name=value; expires=Sat, 01-Apr-2017 12:25:39 GMT; Max-Age=0 +Set-Cookie: name=value; expires=Sat, 01 Apr 2017 12:25:39 GMT; Max-Age=0 diff --git a/ext/standard/tests/network/setcookie.phpt b/ext/standard/tests/network/setcookie.phpt index aad67298f14..f43680a5bce 100644 --- a/ext/standard/tests/network/setcookie.phpt +++ b/ext/standard/tests/network/setcookie.phpt @@ -21,20 +21,20 @@ setcookie('name', 'value', ['expires' => $tsp]); setcookie('name', 'value', ['expires' => $tsn, 'path' => '/path/', 'domain' => 'domain.tld', 'secure' => true, 'httponly' => true, 'samesite' => 'Strict']); $expected = array( - 'Set-Cookie: name=deleted; expires='.date('D, d-M-Y H:i:s', 1).' GMT; Max-Age=0', - 'Set-Cookie: name=deleted; expires='.date('D, d-M-Y H:i:s', 1).' GMT; Max-Age=0', + 'Set-Cookie: name=deleted; expires='.date('D, d M Y H:i:s', 1).' GMT; Max-Age=0', + 'Set-Cookie: name=deleted; expires='.date('D, d M Y H:i:s', 1).' GMT; Max-Age=0', 'Set-Cookie: name=value', 'Set-Cookie: name=space%20value', 'Set-Cookie: name=value', - 'Set-Cookie: name=value; expires='.date('D, d-M-Y H:i:s', $tsp).' GMT; Max-Age=5', - 'Set-Cookie: name=value; expires='.date('D, d-M-Y H:i:s', $tsn).' GMT; Max-Age=0', - 'Set-Cookie: name=value; expires='.date('D, d-M-Y H:i:s', $tsc).' GMT; Max-Age=0', + 'Set-Cookie: name=value; expires='.date('D, d M Y H:i:s', $tsp).' GMT; Max-Age=5', + 'Set-Cookie: name=value; expires='.date('D, d M Y H:i:s', $tsn).' GMT; Max-Age=0', + 'Set-Cookie: name=value; expires='.date('D, d M Y H:i:s', $tsc).' GMT; Max-Age=0', 'Set-Cookie: name=value; path=/path/', 'Set-Cookie: name=value; domain=domain.tld', 'Set-Cookie: name=value; secure', 'Set-Cookie: name=value; HttpOnly', - 'Set-Cookie: name=value; expires='.date('D, d-M-Y H:i:s', $tsp).' GMT; Max-Age=5', - 'Set-Cookie: name=value; expires='.date('D, d-M-Y H:i:s', $tsn).' GMT; Max-Age=0; path=/path/; domain=domain.tld; secure; HttpOnly; SameSite=Strict' + 'Set-Cookie: name=value; expires='.date('D, d M Y H:i:s', $tsp).' GMT; Max-Age=5', + 'Set-Cookie: name=value; expires='.date('D, d M Y H:i:s', $tsn).' GMT; Max-Age=0; path=/path/; domain=domain.tld; secure; HttpOnly; SameSite=Strict' ); $headers = headers_list(); From a6a5d46704becde675c7430388077a49abc84ddf Mon Sep 17 00:00:00 2001 From: Derick Rethans Date: Thu, 11 Aug 2022 16:19:56 +0100 Subject: [PATCH 2/2] Simplify and move check for too high expiry time, which you can't reach on 32bit systems --- ext/standard/head.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ext/standard/head.c b/ext/standard/head.c index 608959adeb9..5bdae98dfce 100644 --- a/ext/standard/head.c +++ b/ext/standard/head.c @@ -110,6 +110,14 @@ PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t e get_active_function_name()); return FAILURE; } +#ifdef ZEND_ENABLE_ZVAL_LONG64 + if (expires >= 253402300800) { + zend_value_error("%s(): \"expires\" option cannot have a year greater than 9999", + get_active_function_name()); + return FAILURE; + } +#endif + /* Should check value of SameSite? */ if (value == NULL || ZSTR_LEN(value) == 0) { @@ -136,19 +144,12 @@ PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t e } else { smart_str_append(&buf, value); } + if (expires > 0) { double diff; smart_str_appends(&buf, COOKIE_EXPIRES); dt = php_format_date("D, d M Y H:i:s \\G\\M\\T", sizeof("D, d M Y H:i:s \\G\\M\\T")-1, expires, 0); - /* check to make sure that the year does not exceed 4 digits in length */ - if (php_idate('Y', expires, 0) > 9999) { - zend_string_free(dt); - smart_str_free(&buf); - zend_value_error("%s(): \"expires\" option cannot have a year greater than 9999", - get_active_function_name()); - return FAILURE; - } smart_str_append(&buf, dt); zend_string_free(dt);