diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index a3d965ad9966..93a2572e1382 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -753,6 +753,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_setrawcookie, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, domain, IS_STRING, 0, "\"\"") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, secure, _IS_BOOL, 0, "false") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, httponly, _IS_BOOL, 0, "false") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, partitioned, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() #define arginfo_setcookie arginfo_setrawcookie diff --git a/ext/standard/head.c b/ext/standard/head.c index ccef4be16bdf..7aaabdc429c7 100644 --- a/ext/standard/head.c +++ b/ext/standard/head.c @@ -79,7 +79,7 @@ PHPAPI bool php_header(void) #define ILLEGAL_COOKIE_CHARACTER "\",\", \";\", \" \", \"\\t\", \"\\r\", \"\\n\", \"\\013\", or \"\\014\"" PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t expires, zend_string *path, zend_string *domain, bool secure, bool httponly, - zend_string *samesite, bool url_encode) + zend_string *samesite, bool partitioned, bool url_encode) { zend_string *dt; sapi_header_line ctr = {0}; @@ -182,6 +182,9 @@ PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t e smart_str_appends(&buf, COOKIE_SAMESITE); smart_str_append(&buf, samesite); } + if (partitioned) { + smart_str_appends(&buf, COOKIE_PARTITIONED); + } ctr.line = ZSTR_VAL(buf.s); ctr.line_len = (uint32_t) ZSTR_LEN(buf.s); @@ -192,7 +195,7 @@ PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t e } static zend_result php_head_parse_cookie_options_array(HashTable *options, zend_long *expires, zend_string **path, - zend_string **domain, bool *secure, bool *httponly, zend_string **samesite) + zend_string **domain, bool *secure, bool *httponly, zend_string **samesite, bool *partitioned) { zend_string *key; zval *value; @@ -212,6 +215,8 @@ static zend_result php_head_parse_cookie_options_array(HashTable *options, zend_ *secure = zval_is_true(value); } else if (zend_string_equals_literal_ci(key, "httponly")) { *httponly = zval_is_true(value); + } else if (zend_string_equals_literal_ci(key, "partitioned")) { + *partitioned = zval_is_true(value); } else if (zend_string_equals_literal_ci(key, "samesite")) { *samesite = zval_get_string(value); } else { @@ -227,9 +232,9 @@ static void php_setcookie_common(INTERNAL_FUNCTION_PARAMETERS, bool is_raw) HashTable *options = NULL; zend_long expires = 0; zend_string *name, *value = NULL, *path = NULL, *domain = NULL, *samesite = NULL; - bool secure = 0, httponly = 0; + bool secure = 0, httponly = 0, partitioned = 0; - ZEND_PARSE_PARAMETERS_START(1, 7) + ZEND_PARSE_PARAMETERS_START(1, 8) Z_PARAM_STR(name) Z_PARAM_OPTIONAL Z_PARAM_STR(value) @@ -238,6 +243,7 @@ static void php_setcookie_common(INTERNAL_FUNCTION_PARAMETERS, bool is_raw) Z_PARAM_STR(domain) Z_PARAM_BOOL(secure) Z_PARAM_BOOL(httponly) + Z_PARAM_BOOL(partitioned) ZEND_PARSE_PARAMETERS_END(); if (options) { @@ -248,13 +254,13 @@ static void php_setcookie_common(INTERNAL_FUNCTION_PARAMETERS, bool is_raw) } if (FAILURE == php_head_parse_cookie_options_array(options, &expires, &path, - &domain, &secure, &httponly, &samesite) + &domain, &secure, &httponly, &samesite, &partitioned) ) { goto cleanup; } } - if (php_setcookie(name, value, expires, path, domain, secure, httponly, samesite, !is_raw) == SUCCESS) { + if (php_setcookie(name, value, expires, path, domain, secure, httponly, samesite, partitioned, !is_raw) == SUCCESS) { RETVAL_TRUE; } else { RETVAL_FALSE; diff --git a/ext/standard/head.h b/ext/standard/head.h index 32c2570a5325..0eef6ffe0d1e 100644 --- a/ext/standard/head.h +++ b/ext/standard/head.h @@ -24,12 +24,13 @@ #define COOKIE_SECURE "; secure" #define COOKIE_HTTPONLY "; HttpOnly" #define COOKIE_SAMESITE "; SameSite=" +#define COOKIE_PARTITIONED "; Partitioned" extern PHP_RINIT_FUNCTION(head); PHPAPI bool php_header(void); PHPAPI zend_result php_setcookie(zend_string *name, zend_string *value, time_t expires, zend_string *path, zend_string *domain, bool secure, bool httponly, - zend_string *samesite, bool url_encode); + zend_string *samesite, bool url_encode, bool partitioned); #endif diff --git a/ext/standard/tests/network/setcookie.phpt b/ext/standard/tests/network/setcookie.phpt index f43680a5bcea..8d7a44be4e79 100644 --- a/ext/standard/tests/network/setcookie.phpt +++ b/ext/standard/tests/network/setcookie.phpt @@ -16,10 +16,13 @@ setcookie('name', 'value', 0, '/path/'); setcookie('name', 'value', 0, '', 'domain.tld'); setcookie('name', 'value', 0, '', '', TRUE); setcookie('name', 'value', 0, '', '', FALSE, TRUE); +setcookie('name', 'value', 0, '', '', FALSE, FALSE, TRUE); setcookie('name', 'value', ['expires' => $tsp]); setcookie('name', 'value', ['expires' => $tsn, 'path' => '/path/', 'domain' => 'domain.tld', 'secure' => true, 'httponly' => true, 'samesite' => 'Strict']); +setcookie('name', 'value', ['partitioned' => 1]); + $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', @@ -33,8 +36,10 @@ $expected = array( 'Set-Cookie: name=value; domain=domain.tld', 'Set-Cookie: name=value; secure', 'Set-Cookie: name=value; HttpOnly', + 'Set-Cookie: name=value; Partitioned', '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', $tsn).' GMT; Max-Age=0; path=/path/; domain=domain.tld; secure; HttpOnly; SameSite=Strict', + 'Set-Cookie: name=value; Partitioned', ); $headers = headers_list();