* Userspace exported functions *
******************************** */
-/* {{{ proto void session_set_cookie_params(int lifetime [, string path [, string domain [, bool secure[, bool httponly[, string samesite]]]]])
+/* {{{ proto bool session_set_cookie_params(int lifetime [, string path [, string domain [, bool secure[, bool httponly]]]])
+ session_set_cookie_params(array options)
Set session cookie parameters */
static PHP_FUNCTION(session_set_cookie_params)
{
- zval *lifetime;
- zend_string *path = NULL, *domain = NULL, *samesite = NULL;
- int argc = ZEND_NUM_ARGS();
- zend_bool secure = 0, httponly = 0;
+ zval *lifetime_or_options = NULL;
+ zend_string *lifetime = NULL, *path = NULL, *domain = NULL, *samesite = NULL;
+ zend_bool secure = 0, secure_null = 1;
+ zend_bool httponly = 0, httponly_null = 1;
zend_string *ini_name;
+ int result;
+ int found = 0;
- if (!PS(use_cookies) ||
- zend_parse_parameters(argc, "z|SSbbS", &lifetime, &path, &domain, &secure, &httponly, &samesite) == FAILURE) {
+ if (!PS(use_cookies)) {
return;
}
+ ZEND_PARSE_PARAMETERS_START(1, 5)
+ Z_PARAM_ZVAL(lifetime_or_options)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_STR(path)
+ Z_PARAM_STR(domain)
+ Z_PARAM_BOOL_EX(secure, secure_null, 1, 0)
+ Z_PARAM_BOOL_EX(httponly, httponly_null, 1, 0)
+ ZEND_PARSE_PARAMETERS_END();
if (PS(session_status) == php_session_active) {
php_error_docref(NULL, E_WARNING, "Cannot change session cookie parameters when session is active");
RETURN_FALSE;
}
- convert_to_string_ex(lifetime);
+ if (Z_TYPE_P(lifetime_or_options) == IS_ARRAY) {
+ zend_string *key;
+ zval *value;
+
+ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(lifetime_or_options), key, value) {
+ if (key) {
+ ZVAL_DEREF(value);
+ if(!strcasecmp("lifetime", ZSTR_VAL(key))) {
+ lifetime = zval_get_string(value);
+ found++;
+ } else if(!strcasecmp("path", ZSTR_VAL(key))) {
+ path = zval_get_string(value);
+ found++;
+ } else if(!strcasecmp("domain", ZSTR_VAL(key))) {
+ domain = zval_get_string(value);
+ found++;
+ } else if(!strcasecmp("secure", ZSTR_VAL(key))) {
+ secure = zval_is_true(value);
+ secure_null = 0;
+ found++;
+ } else if(!strcasecmp("httponly", ZSTR_VAL(key))) {
+ httponly = zval_is_true(value);
+ httponly_null = 0;
+ found++;
+ } else if(!strcasecmp("samesite", ZSTR_VAL(key))) {
+ samesite = zval_get_string(value);
+ found++;
+ } else {
+ php_error_docref(NULL, E_WARNING, "Unrecognized key '%s' found in the options array", ZSTR_VAL(key));
+ }
+ } else {
+ php_error_docref(NULL, E_WARNING, "Numeric key found in the options array");
+ }
+ } ZEND_HASH_FOREACH_END();
- ini_name = zend_string_init("session.cookie_lifetime", sizeof("session.cookie_lifetime") - 1, 0);
- if (zend_alter_ini_entry(ini_name, Z_STR_P(lifetime), PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
- zend_string_release_ex(ini_name, 0);
- RETURN_FALSE;
+ if (found == 0) {
+ php_error_docref(NULL, E_WARNING, "No valid keys were found in the options array");
+ RETURN_FALSE;
+ }
+ } else {
+ lifetime = zval_get_string(lifetime_or_options);
}
- zend_string_release_ex(ini_name, 0);
+ if (lifetime) {
+ ini_name = zend_string_init("session.cookie_lifetime", sizeof("session.cookie_lifetime") - 1, 0);
+ result = zend_alter_ini_entry(ini_name, lifetime, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ zend_string_release(lifetime);
+ zend_string_release_ex(ini_name, 0);
+ if (result == FAILURE) {
+ RETURN_FALSE;
+ }
+ }
if (path) {
ini_name = zend_string_init("session.cookie_path", sizeof("session.cookie_path") - 1, 0);
- if (zend_alter_ini_entry(ini_name, path, PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
- zend_string_release_ex(ini_name, 0);
- RETURN_FALSE;
+ result = zend_alter_ini_entry(ini_name, path, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ if (found > 0) {
+ zend_string_release(path);
}
zend_string_release_ex(ini_name, 0);
+ if (result == FAILURE) {
+ RETURN_FALSE;
+ }
}
if (domain) {
ini_name = zend_string_init("session.cookie_domain", sizeof("session.cookie_domain") - 1, 0);
- if (zend_alter_ini_entry(ini_name, domain, PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
- zend_string_release_ex(ini_name, 0);
- RETURN_FALSE;
+ result = zend_alter_ini_entry(ini_name, domain, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ if (found > 0) {
+ zend_string_release(domain);
}
zend_string_release_ex(ini_name, 0);
+ if (result == FAILURE) {
+ RETURN_FALSE;
+ }
}
-
- if (argc > 3) {
+ if (!secure_null) {
ini_name = zend_string_init("session.cookie_secure", sizeof("session.cookie_secure") - 1, 0);
- if (zend_alter_ini_entry_chars(ini_name, secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
- zend_string_release_ex(ini_name, 0);
+ result = zend_alter_ini_entry_chars(ini_name, secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ zend_string_release_ex(ini_name, 0);
+ if (result == FAILURE) {
RETURN_FALSE;
}
- zend_string_release_ex(ini_name, 0);
}
- if (argc > 4) {
+ if (!httponly_null) {
ini_name = zend_string_init("session.cookie_httponly", sizeof("session.cookie_httponly") - 1, 0);
- if (zend_alter_ini_entry_chars(ini_name, httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
- zend_string_release_ex(ini_name, 0);
+ result = zend_alter_ini_entry_chars(ini_name, httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ zend_string_release_ex(ini_name, 0);
+ if (result == FAILURE) {
RETURN_FALSE;
}
+ }
+ if (samesite) {
+ ini_name = zend_string_init("session.cookie_samesite", sizeof("session.cookie_samesite") - 1, 0);
+ result = zend_alter_ini_entry(ini_name, samesite, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
+ if (found > 0) {
+ zend_string_release(samesite);
+ }
zend_string_release_ex(ini_name, 0);
+ if (result == FAILURE) {
+ RETURN_FALSE;
+ }
}
- if (argc > 5) {
- ini_name = zend_string_init("session.cookie_samesite", sizeof("session.cookie_samesite") - 1, 0);
- zend_alter_ini_entry(ini_name, samesite, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
- zend_string_release(ini_name);
- }
-
RETURN_TRUE;
}
/* }}} */
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_session_set_cookie_params, 0, 0, 1)
- ZEND_ARG_INFO(0, lifetime)
+ ZEND_ARG_INFO(0, lifetime_or_options)
ZEND_ARG_INFO(0, path)
ZEND_ARG_INFO(0, domain)
ZEND_ARG_INFO(0, secure)
ZEND_ARG_INFO(0, httponly)
- ZEND_ARG_INFO(0, samesite)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_session_class_open, 0)
echo "*** Testing session_get_cookie_params() : basic functionality ***\n";
var_dump(session_get_cookie_params());
-var_dump(session_set_cookie_params(3600, "/path", "blah", FALSE, FALSE, "foo"));
+var_dump(session_set_cookie_params(3600, "/path", "blah", FALSE, FALSE));
var_dump(session_get_cookie_params());
-var_dump(session_set_cookie_params(1234567890, "/guff", "foo", TRUE, TRUE, "blah"));
+var_dump(session_set_cookie_params(1234567890, "/guff", "foo", TRUE, TRUE));
+var_dump(session_get_cookie_params());
+var_dump(session_set_cookie_params([
+ "lifetime" => 123,
+ "path" => "/bar",
+ "domain" => "baz",
+ "secure" => FALSE,
+ "httponly" => FALSE,
+ "samesite" => "please"]));
var_dump(session_get_cookie_params());
echo "Done";
["httponly"]=>
bool(false)
["samesite"]=>
- string(3) "foo"
+ string(0) ""
}
bool(true)
array(6) {
["httponly"]=>
bool(true)
["samesite"]=>
- string(4) "blah"
+ string(0) ""
+}
+bool(true)
+array(6) {
+ ["lifetime"]=>
+ int(123)
+ ["path"]=>
+ string(4) "/bar"
+ ["domain"]=>
+ string(3) "baz"
+ ["secure"]=>
+ bool(false)
+ ["httponly"]=>
+ bool(false)
+ ["samesite"]=>
+ string(6) "please"
}
Done
ob_start();
/*
- * Prototype : void session_set_cookie_params(int $lifetime [, string $path [, string $domain [, bool $secure [, bool $httponly[, string $samesite]]]]])
+ * Prototype : void session_set_cookie_params(int $lifetime [, string $path [, string $domain [, bool $secure [, bool $httponly]]]])
* Description : Set the session cookie parameters
* Source code : ext/session/session.c
*/
ob_start();
/*
- * Prototype : void session_set_cookie_params(int $lifetime [, string $path [, string $domain [, bool $secure [, bool $httponly[, string $samesite]]]]])
+ * Prototype : void session_set_cookie_params(int $lifetime [, string $path [, string $domain [, bool $secure [, bool $httponly]]]])
* Description : Set the session cookie parameters
* Source code : ext/session/session.c
*/
ob_start();
/*
- * Prototype : void session_set_cookie_params(int $lifetime [, string $path [, string $domain [, bool $secure [, bool $samesite[, string $samesite]]]]])
+ * Prototype : void session_set_cookie_params(array $options)
* Description : Set the session cookie parameters
* Source code : ext/session/session.c
*/
echo "*** Testing session_set_cookie_params() : variation ***\n";
var_dump(ini_get("session.cookie_samesite"));
-var_dump(session_set_cookie_params(3600, "/path", "blah", FALSE, FALSE, "nothing"));
+var_dump(session_set_cookie_params(["samesite" => "nothing"]));
var_dump(ini_get("session.cookie_samesite"));
var_dump(session_start());
var_dump(ini_get("session.cookie_samesite"));
-var_dump(session_set_cookie_params(3600, "/path", "blah", FALSE, TRUE, "test"));
+var_dump(session_set_cookie_params(["samesite" => "test"]));
var_dump(ini_get("session.cookie_samesite"));
var_dump(session_destroy());
var_dump(ini_get("session.cookie_samesite"));
-var_dump(session_set_cookie_params(3600, "/path", "blah", FALSE, FALSE, "other"));
+var_dump(session_set_cookie_params(["samesite" => "other"]));
var_dump(ini_get("session.cookie_samesite"));
echo "Done";
--- /dev/null
+--TEST--
+Test session_set_cookie_params() function : array parameter variation
+--INI--
+session.cookie_lifetime=0
+session.cookie_path="/"
+session.cookie_domain=""
+session.cookie_secure=0
+session.cookie_httponly=0
+session.cookie_samesite=""
+--SKIPIF--
+<?php include('skipif.inc'); ?>
+--FILE--
+<?php
+
+ob_start();
+
+/*
+ * Prototype : void session_set_cookie_params(array $options)
+ * Description : Set the session cookie parameters
+ * Source code : ext/session/session.c
+ */
+
+echo "*** Testing session_set_cookie_params() : array parameter variation ***\n";
+
+// Invalid cases
+var_dump(session_set_cookie_params([]));
+var_dump(session_set_cookie_params(["unknown_key" => true]));
+
+var_dump(ini_get("session.cookie_secure"));
+var_dump(ini_get("session.cookie_samesite"));
+var_dump(session_set_cookie_params(["secure" => true, "samesite" => "please"]));
+var_dump(ini_get("session.cookie_secure"));
+var_dump(ini_get("session.cookie_samesite"));
+
+var_dump(ini_get("session.cookie_lifetime"));
+var_dump(session_set_cookie_params(["lifetime" => 42]));
+var_dump(ini_get("session.cookie_lifetime"));
+
+echo "Done";
+ob_end_flush();
+?>
+--EXPECTF--
+*** Testing session_set_cookie_params() : array parameter variation ***
+
+Warning: session_set_cookie_params(): No valid keys were found in the options array in %s
+bool(false)
+
+Warning: session_set_cookie_params(): Unrecognized key 'unknown_key' found in the options array in %s
+
+Warning: session_set_cookie_params(): No valid keys were found in the options array in %s
+bool(false)
+string(1) "0"
+string(0) ""
+bool(true)
+string(1) "1"
+string(6) "please"
+string(1) "0"
+bool(true)
+string(2) "42"
+Done
ZEND_BEGIN_ARG_INFO_EX(arginfo_setcookie, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, value)
- ZEND_ARG_INFO(0, expires)
+ ZEND_ARG_INFO(0, expires_or_options)
ZEND_ARG_INFO(0, path)
ZEND_ARG_INFO(0, domain)
ZEND_ARG_INFO(0, secure)
ZEND_ARG_INFO(0, httponly)
- ZEND_ARG_INFO(0, samesite)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_setrawcookie, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, value)
- ZEND_ARG_INFO(0, expires)
+ ZEND_ARG_INFO(0, expires_or_options)
ZEND_ARG_INFO(0, path)
ZEND_ARG_INFO(0, domain)
ZEND_ARG_INFO(0, secure)
ZEND_ARG_INFO(0, httponly)
- ZEND_ARG_INFO(0, samesite)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_headers_sent, 0, 0, 0)
}
}
-PHPAPI int php_setcookie(zend_string *name, zend_string *value, time_t expires, zend_string *path, zend_string *domain, int secure, int url_encode, int httponly, zend_string *samesite)
+PHPAPI int php_setcookie(zend_string *name, zend_string *value, time_t expires, zend_string *path, zend_string *domain, int secure, int httponly, zend_string *samesite, int url_encode)
{
char *cookie;
size_t len = sizeof("Set-Cookie: ");
return result;
}
+static int php_head_parse_cookie_options_array(zval *options, zend_long *expires, zend_string **path, zend_string **domain, zend_bool *secure, zend_bool *httponly, zend_string **samesite) {
+ int found = 0;
+ zend_string *key;
+ zval *value;
+
+ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(options), key, value) {
+ if (key) {
+ ZVAL_DEREF(value);
+ if(!strcasecmp("expires", ZSTR_VAL(key))) {
+ *expires = zval_get_long(value);
+ found++;
+ } else if(!strcasecmp("path", ZSTR_VAL(key))) {
+ *path = zval_get_string(value);
+ found++;
+ } else if(!strcasecmp("domain", ZSTR_VAL(key))) {
+ *domain = zval_get_string(value);
+ found++;
+ } else if(!strcasecmp("secure", ZSTR_VAL(key))) {
+ *secure = zval_is_true(value);
+ found++;
+ } else if(!strcasecmp("httponly", ZSTR_VAL(key))) {
+ *httponly = zval_is_true(value);
+ found++;
+ } else if(!strcasecmp("samesite", ZSTR_VAL(key))) {
+ *samesite = zval_get_string(value);
+ found++;
+ } else {
+ php_error_docref(NULL, E_WARNING, "Unrecognized key '%s' found in the options array", ZSTR_VAL(key));
+ }
+ } else {
+ php_error_docref(NULL, E_WARNING, "Numeric key found in the options array");
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ /* Array is not empty but no valid keys were found */
+ if (found == 0 && zend_hash_num_elements(Z_ARRVAL_P(options)) > 0) {
+ php_error_docref(NULL, E_WARNING, "No valid options were found in the given array");
+ return 0;
+ }
+
+ return 1;
+}
-/* php_set_cookie(name, value, expires, path, domain, secure) */
-/* {{{ proto bool setcookie(string name [, string value [, int expires [, string path [, string domain [, bool secure[, bool httponly[, string samesite]]]]]]])
+/* {{{ proto bool setcookie(string name [, string value [, int expires [, string path [, string domain [, bool secure[, bool httponly]]]]]])
+ setcookie(string name [, string value [, array options]])
Send a cookie */
PHP_FUNCTION(setcookie)
{
+ zval *expires_or_options = NULL;
zend_string *name, *value = NULL, *path = NULL, *domain = NULL, *samesite = NULL;
zend_long expires = 0;
- zend_bool secure = 0, httponly = 0;
+ zend_bool secure = 0, httponly = 0, options_array = 0;
- ZEND_PARSE_PARAMETERS_START(1, 8)
+ ZEND_PARSE_PARAMETERS_START(1, 7)
Z_PARAM_STR(name)
Z_PARAM_OPTIONAL
Z_PARAM_STR(value)
- Z_PARAM_LONG(expires)
+ Z_PARAM_ZVAL(expires_or_options)
Z_PARAM_STR(path)
Z_PARAM_STR(domain)
Z_PARAM_BOOL(secure)
Z_PARAM_BOOL(httponly)
- Z_PARAM_STR(samesite)
ZEND_PARSE_PARAMETERS_END();
- if (php_setcookie(name, value, expires, path, domain, secure, 1, httponly, samesite) == SUCCESS) {
+ if (expires_or_options) {
+ if (Z_TYPE_P(expires_or_options) == IS_ARRAY) {
+ options_array = 1;
+ if (!php_head_parse_cookie_options_array(expires_or_options, &expires, &path, &domain, &secure, &httponly, &samesite)) {
+ RETVAL_FALSE;
+ goto cleanup;
+ }
+ } else {
+ expires = Z_LVAL_P(expires_or_options);
+ }
+ }
+
+ if (php_setcookie(name, value, expires, path, domain, secure, httponly, samesite, 1) == SUCCESS) {
RETVAL_TRUE;
} else {
RETVAL_FALSE;
}
+
+cleanup:
+ if (options_array) {
+ if (path) {
+ zend_string_release(path);
+ }
+ if (domain) {
+ zend_string_release(domain);
+ }
+ if (samesite) {
+ zend_string_release(samesite);
+ }
+ }
}
/* }}} */
-/* {{{ proto bool setrawcookie(string name [, string value [, int expires [, string path [, string domain [, bool secure[, bool httponly[, string samesite]]]]]]])
+/* {{{ proto bool setrawcookie(string name [, string value [, int expires [, string path [, string domain [, bool secure[, bool httponly]]]]]])
+ setrawcookie(string name [, string value [, array options]])
Send a cookie with no url encoding of the value */
PHP_FUNCTION(setrawcookie)
{
+ zval *expires_or_options = NULL;
zend_string *name, *value = NULL, *path = NULL, *domain = NULL, *samesite = NULL;
zend_long expires = 0;
- zend_bool secure = 0, httponly = 0;
+ zend_bool secure = 0, httponly = 0, options_array = 0;
- ZEND_PARSE_PARAMETERS_START(1, 8)
+ ZEND_PARSE_PARAMETERS_START(1, 7)
Z_PARAM_STR(name)
Z_PARAM_OPTIONAL
Z_PARAM_STR(value)
- Z_PARAM_LONG(expires)
+ Z_PARAM_ZVAL(expires_or_options)
Z_PARAM_STR(path)
Z_PARAM_STR(domain)
Z_PARAM_BOOL(secure)
Z_PARAM_BOOL(httponly)
- Z_PARAM_STR(samesite)
ZEND_PARSE_PARAMETERS_END();
- if (php_setcookie(name, value, expires, path, domain, secure, 0, httponly, samesite) == SUCCESS) {
+ if (expires_or_options) {
+ if (Z_TYPE_P(expires_or_options) == IS_ARRAY) {
+ options_array = 1;
+ if (!php_head_parse_cookie_options_array(expires_or_options, &expires, &path, &domain, &secure, &httponly, &samesite)) {
+ RETVAL_FALSE;
+ goto cleanup;
+ }
+ } else {
+ expires = Z_LVAL_P(expires_or_options);
+ }
+ }
+
+ if (php_setcookie(name, value, expires, path, domain, secure, httponly, samesite, 0) == SUCCESS) {
RETVAL_TRUE;
} else {
RETVAL_FALSE;
}
+
+cleanup:
+ if (options_array) {
+ if (path) {
+ zend_string_release(path);
+ }
+ if (domain) {
+ zend_string_release(domain);
+ }
+ if (samesite) {
+ zend_string_release(samesite);
+ }
+ }
}
/* }}} */
PHP_FUNCTION(http_response_code);
PHPAPI int php_header(void);
-PHPAPI int php_setcookie(zend_string *name, zend_string *value, time_t expires, zend_string *path, zend_string *domain, int secure, int url_encode, int httponly, zend_string *samesite);
+PHPAPI int php_setcookie(zend_string *name, zend_string *value, time_t expires, zend_string *path, zend_string *domain, int secure, int httponly, zend_string *samesite, int url_encode);
#endif
setcookie('name', 'value', 0, '', '', TRUE);
setcookie('name', 'value', 0, '', '', FALSE, TRUE);
+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=value; path=/path/',
'Set-Cookie: name=value; domain=domain.tld',
'Set-Cookie: name=value; secure',
- 'Set-Cookie: name=value; HttpOnly'
+ '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'
);
$headers = headers_list();
--- /dev/null
+--TEST--
+setcookie() array variant error tests
+--INI--
+date.timezone=UTC
+--FILE--
+<?php
+
+ob_start();
+
+// Unrecognized key and no valid keys
+setcookie('name', 'value', ['unknown_key' => 'only']);
+// Numeric key and no valid keys
+setcookie('name', 'value', [0 => 'numeric_key']);
+// Unrecognized key
+setcookie('name', 'value', ['path' => '/path/', 'foo' => 'bar']);
+
+--EXPECTF--
+Warning: setcookie(): Unrecognized key 'unknown_key' found in the options array in %s
+
+Warning: setcookie(): No valid options were found in the given array in %s
+
+Warning: setcookie(): Numeric key found in the options array in %s
+
+Warning: setcookie(): No valid options were found in the given array in %s
+
+Warning: setcookie(): Unrecognized key 'foo' found in the options array in %s