Skip to content

Commit 2b58ab2

Browse files
pmmagacmb69
authored andcommitted
Support for samesite cookies with array syntax
Allows using an alternative array argument with support for the samesite option on the following functions: setcookie setrawcookie session_set_cookie_params
1 parent 08b9310 commit 2b58ab2

11 files changed

+331
-65
lines changed

Diff for: ext/session/session.c

+97-35
Original file line numberDiff line numberDiff line change
@@ -1664,21 +1664,31 @@ PHPAPI void session_adapt_url(const char *url, size_t urllen, char **new, size_t
16641664
* Userspace exported functions *
16651665
******************************** */
16661666

1667-
/* {{{ proto void session_set_cookie_params(int lifetime [, string path [, string domain [, bool secure[, bool httponly[, string samesite]]]]])
1667+
/* {{{ proto bool session_set_cookie_params(int lifetime [, string path [, string domain [, bool secure[, bool httponly]]]])
1668+
session_set_cookie_params(array options)
16681669
Set session cookie parameters */
16691670
static PHP_FUNCTION(session_set_cookie_params)
16701671
{
1671-
zval *lifetime;
1672-
zend_string *path = NULL, *domain = NULL, *samesite = NULL;
1673-
int argc = ZEND_NUM_ARGS();
1674-
zend_bool secure = 0, httponly = 0;
1672+
zval *lifetime_or_options = NULL;
1673+
zend_string *lifetime = NULL, *path = NULL, *domain = NULL, *samesite = NULL;
1674+
zend_bool secure = 0, secure_null = 1;
1675+
zend_bool httponly = 0, httponly_null = 1;
16751676
zend_string *ini_name;
1677+
int result;
1678+
int found = 0;
16761679

1677-
if (!PS(use_cookies) ||
1678-
zend_parse_parameters(argc, "z|SSbbS", &lifetime, &path, &domain, &secure, &httponly, &samesite) == FAILURE) {
1680+
if (!PS(use_cookies)) {
16791681
return;
16801682
}
16811683

1684+
ZEND_PARSE_PARAMETERS_START(1, 5)
1685+
Z_PARAM_ZVAL(lifetime_or_options)
1686+
Z_PARAM_OPTIONAL
1687+
Z_PARAM_STR(path)
1688+
Z_PARAM_STR(domain)
1689+
Z_PARAM_BOOL_EX(secure, secure_null, 1, 0)
1690+
Z_PARAM_BOOL_EX(httponly, httponly_null, 1, 0)
1691+
ZEND_PARSE_PARAMETERS_END();
16821692

16831693
if (PS(session_status) == php_session_active) {
16841694
php_error_docref(NULL, E_WARNING, "Cannot change session cookie parameters when session is active");
@@ -1690,55 +1700,108 @@ static PHP_FUNCTION(session_set_cookie_params)
16901700
RETURN_FALSE;
16911701
}
16921702

1693-
convert_to_string_ex(lifetime);
1703+
if (Z_TYPE_P(lifetime_or_options) == IS_ARRAY) {
1704+
zend_string *key;
1705+
zval *value;
1706+
1707+
ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(lifetime_or_options), key, value) {
1708+
if (key) {
1709+
ZVAL_DEREF(value);
1710+
if(!strcasecmp("lifetime", ZSTR_VAL(key))) {
1711+
lifetime = zval_get_string(value);
1712+
found++;
1713+
} else if(!strcasecmp("path", ZSTR_VAL(key))) {
1714+
path = zval_get_string(value);
1715+
found++;
1716+
} else if(!strcasecmp("domain", ZSTR_VAL(key))) {
1717+
domain = zval_get_string(value);
1718+
found++;
1719+
} else if(!strcasecmp("secure", ZSTR_VAL(key))) {
1720+
secure = zval_is_true(value);
1721+
secure_null = 0;
1722+
found++;
1723+
} else if(!strcasecmp("httponly", ZSTR_VAL(key))) {
1724+
httponly = zval_is_true(value);
1725+
httponly_null = 0;
1726+
found++;
1727+
} else if(!strcasecmp("samesite", ZSTR_VAL(key))) {
1728+
samesite = zval_get_string(value);
1729+
found++;
1730+
} else {
1731+
php_error_docref(NULL, E_WARNING, "Unrecognized key '%s' found in the options array", ZSTR_VAL(key));
1732+
}
1733+
} else {
1734+
php_error_docref(NULL, E_WARNING, "Numeric key found in the options array");
1735+
}
1736+
} ZEND_HASH_FOREACH_END();
16941737

1695-
ini_name = zend_string_init("session.cookie_lifetime", sizeof("session.cookie_lifetime") - 1, 0);
1696-
if (zend_alter_ini_entry(ini_name, Z_STR_P(lifetime), PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
1697-
zend_string_release_ex(ini_name, 0);
1698-
RETURN_FALSE;
1738+
if (found == 0) {
1739+
php_error_docref(NULL, E_WARNING, "No valid keys were found in the options array");
1740+
RETURN_FALSE;
1741+
}
1742+
} else {
1743+
lifetime = zval_get_string(lifetime_or_options);
16991744
}
1700-
zend_string_release_ex(ini_name, 0);
17011745

1746+
if (lifetime) {
1747+
ini_name = zend_string_init("session.cookie_lifetime", sizeof("session.cookie_lifetime") - 1, 0);
1748+
result = zend_alter_ini_entry(ini_name, lifetime, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1749+
zend_string_release(lifetime);
1750+
zend_string_release_ex(ini_name, 0);
1751+
if (result == FAILURE) {
1752+
RETURN_FALSE;
1753+
}
1754+
}
17021755
if (path) {
17031756
ini_name = zend_string_init("session.cookie_path", sizeof("session.cookie_path") - 1, 0);
1704-
if (zend_alter_ini_entry(ini_name, path, PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
1705-
zend_string_release_ex(ini_name, 0);
1706-
RETURN_FALSE;
1757+
result = zend_alter_ini_entry(ini_name, path, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1758+
if (found > 0) {
1759+
zend_string_release(path);
17071760
}
17081761
zend_string_release_ex(ini_name, 0);
1762+
if (result == FAILURE) {
1763+
RETURN_FALSE;
1764+
}
17091765
}
17101766
if (domain) {
17111767
ini_name = zend_string_init("session.cookie_domain", sizeof("session.cookie_domain") - 1, 0);
1712-
if (zend_alter_ini_entry(ini_name, domain, PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
1713-
zend_string_release_ex(ini_name, 0);
1714-
RETURN_FALSE;
1768+
result = zend_alter_ini_entry(ini_name, domain, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1769+
if (found > 0) {
1770+
zend_string_release(domain);
17151771
}
17161772
zend_string_release_ex(ini_name, 0);
1773+
if (result == FAILURE) {
1774+
RETURN_FALSE;
1775+
}
17171776
}
1718-
1719-
if (argc > 3) {
1777+
if (!secure_null) {
17201778
ini_name = zend_string_init("session.cookie_secure", sizeof("session.cookie_secure") - 1, 0);
1721-
if (zend_alter_ini_entry_chars(ini_name, secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
1722-
zend_string_release_ex(ini_name, 0);
1779+
result = zend_alter_ini_entry_chars(ini_name, secure ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1780+
zend_string_release_ex(ini_name, 0);
1781+
if (result == FAILURE) {
17231782
RETURN_FALSE;
17241783
}
1725-
zend_string_release_ex(ini_name, 0);
17261784
}
1727-
if (argc > 4) {
1785+
if (!httponly_null) {
17281786
ini_name = zend_string_init("session.cookie_httponly", sizeof("session.cookie_httponly") - 1, 0);
1729-
if (zend_alter_ini_entry_chars(ini_name, httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME) == FAILURE) {
1730-
zend_string_release_ex(ini_name, 0);
1787+
result = zend_alter_ini_entry_chars(ini_name, httponly ? "1" : "0", 1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1788+
zend_string_release_ex(ini_name, 0);
1789+
if (result == FAILURE) {
17311790
RETURN_FALSE;
17321791
}
1792+
}
1793+
if (samesite) {
1794+
ini_name = zend_string_init("session.cookie_samesite", sizeof("session.cookie_samesite") - 1, 0);
1795+
result = zend_alter_ini_entry(ini_name, samesite, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1796+
if (found > 0) {
1797+
zend_string_release(samesite);
1798+
}
17331799
zend_string_release_ex(ini_name, 0);
1800+
if (result == FAILURE) {
1801+
RETURN_FALSE;
1802+
}
17341803
}
17351804

1736-
if (argc > 5) {
1737-
ini_name = zend_string_init("session.cookie_samesite", sizeof("session.cookie_samesite") - 1, 0);
1738-
zend_alter_ini_entry(ini_name, samesite, PHP_INI_USER, PHP_INI_STAGE_RUNTIME);
1739-
zend_string_release(ini_name);
1740-
}
1741-
17421805
RETURN_TRUE;
17431806
}
17441807
/* }}} */
@@ -2638,12 +2701,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_session_cache_expire, 0, 0, 0)
26382701
ZEND_END_ARG_INFO()
26392702

26402703
ZEND_BEGIN_ARG_INFO_EX(arginfo_session_set_cookie_params, 0, 0, 1)
2641-
ZEND_ARG_INFO(0, lifetime)
2704+
ZEND_ARG_INFO(0, lifetime_or_options)
26422705
ZEND_ARG_INFO(0, path)
26432706
ZEND_ARG_INFO(0, domain)
26442707
ZEND_ARG_INFO(0, secure)
26452708
ZEND_ARG_INFO(0, httponly)
2646-
ZEND_ARG_INFO(0, samesite)
26472709
ZEND_END_ARG_INFO()
26482710

26492711
ZEND_BEGIN_ARG_INFO(arginfo_session_class_open, 0)

Diff for: ext/session/tests/session_get_cookie_params_basic.phpt

+27-4
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,17 @@ ob_start();
2323
echo "*** Testing session_get_cookie_params() : basic functionality ***\n";
2424

2525
var_dump(session_get_cookie_params());
26-
var_dump(session_set_cookie_params(3600, "/path", "blah", FALSE, FALSE, "foo"));
26+
var_dump(session_set_cookie_params(3600, "/path", "blah", FALSE, FALSE));
2727
var_dump(session_get_cookie_params());
28-
var_dump(session_set_cookie_params(1234567890, "/guff", "foo", TRUE, TRUE, "blah"));
28+
var_dump(session_set_cookie_params(1234567890, "/guff", "foo", TRUE, TRUE));
29+
var_dump(session_get_cookie_params());
30+
var_dump(session_set_cookie_params([
31+
"lifetime" => 123,
32+
"path" => "/bar",
33+
"domain" => "baz",
34+
"secure" => FALSE,
35+
"httponly" => FALSE,
36+
"samesite" => "please"]));
2937
var_dump(session_get_cookie_params());
3038

3139
echo "Done";
@@ -60,7 +68,7 @@ array(6) {
6068
["httponly"]=>
6169
bool(false)
6270
["samesite"]=>
63-
string(3) "foo"
71+
string(0) ""
6472
}
6573
bool(true)
6674
array(6) {
@@ -75,6 +83,21 @@ array(6) {
7583
["httponly"]=>
7684
bool(true)
7785
["samesite"]=>
78-
string(4) "blah"
86+
string(0) ""
87+
}
88+
bool(true)
89+
array(6) {
90+
["lifetime"]=>
91+
int(123)
92+
["path"]=>
93+
string(4) "/bar"
94+
["domain"]=>
95+
string(3) "baz"
96+
["secure"]=>
97+
bool(false)
98+
["httponly"]=>
99+
bool(false)
100+
["samesite"]=>
101+
string(6) "please"
79102
}
80103
Done

Diff for: ext/session/tests/session_set_cookie_params_variation3.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ session.cookie_domain=foo
1010
ob_start();
1111

1212
/*
13-
* Prototype : void session_set_cookie_params(int $lifetime [, string $path [, string $domain [, bool $secure [, bool $httponly[, string $samesite]]]]])
13+
* Prototype : void session_set_cookie_params(int $lifetime [, string $path [, string $domain [, bool $secure [, bool $httponly]]]])
1414
* Description : Set the session cookie parameters
1515
* Source code : ext/session/session.c
1616
*/

Diff for: ext/session/tests/session_set_cookie_params_variation5.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ session.cookie_httponly=TRUE
1010
ob_start();
1111

1212
/*
13-
* Prototype : void session_set_cookie_params(int $lifetime [, string $path [, string $domain [, bool $secure [, bool $httponly[, string $samesite]]]]])
13+
* Prototype : void session_set_cookie_params(int $lifetime [, string $path [, string $domain [, bool $secure [, bool $httponly]]]])
1414
* Description : Set the session cookie parameters
1515
* Source code : ext/session/session.c
1616
*/

Diff for: ext/session/tests/session_set_cookie_params_variation6.phpt

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@ session.cookie_samesite=test
1010
ob_start();
1111

1212
/*
13-
* Prototype : void session_set_cookie_params(int $lifetime [, string $path [, string $domain [, bool $secure [, bool $samesite[, string $samesite]]]]])
13+
* Prototype : void session_set_cookie_params(array $options)
1414
* Description : Set the session cookie parameters
1515
* Source code : ext/session/session.c
1616
*/
1717

1818
echo "*** Testing session_set_cookie_params() : variation ***\n";
1919

2020
var_dump(ini_get("session.cookie_samesite"));
21-
var_dump(session_set_cookie_params(3600, "/path", "blah", FALSE, FALSE, "nothing"));
21+
var_dump(session_set_cookie_params(["samesite" => "nothing"]));
2222
var_dump(ini_get("session.cookie_samesite"));
2323
var_dump(session_start());
2424
var_dump(ini_get("session.cookie_samesite"));
25-
var_dump(session_set_cookie_params(3600, "/path", "blah", FALSE, TRUE, "test"));
25+
var_dump(session_set_cookie_params(["samesite" => "test"]));
2626
var_dump(ini_get("session.cookie_samesite"));
2727
var_dump(session_destroy());
2828
var_dump(ini_get("session.cookie_samesite"));
29-
var_dump(session_set_cookie_params(3600, "/path", "blah", FALSE, FALSE, "other"));
29+
var_dump(session_set_cookie_params(["samesite" => "other"]));
3030
var_dump(ini_get("session.cookie_samesite"));
3131

3232
echo "Done";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
--TEST--
2+
Test session_set_cookie_params() function : array parameter variation
3+
--INI--
4+
session.cookie_lifetime=0
5+
session.cookie_path="/"
6+
session.cookie_domain=""
7+
session.cookie_secure=0
8+
session.cookie_httponly=0
9+
session.cookie_samesite=""
10+
--SKIPIF--
11+
<?php include('skipif.inc'); ?>
12+
--FILE--
13+
<?php
14+
15+
ob_start();
16+
17+
/*
18+
* Prototype : void session_set_cookie_params(array $options)
19+
* Description : Set the session cookie parameters
20+
* Source code : ext/session/session.c
21+
*/
22+
23+
echo "*** Testing session_set_cookie_params() : array parameter variation ***\n";
24+
25+
// Invalid cases
26+
var_dump(session_set_cookie_params([]));
27+
var_dump(session_set_cookie_params(["unknown_key" => true]));
28+
29+
var_dump(ini_get("session.cookie_secure"));
30+
var_dump(ini_get("session.cookie_samesite"));
31+
var_dump(session_set_cookie_params(["secure" => true, "samesite" => "please"]));
32+
var_dump(ini_get("session.cookie_secure"));
33+
var_dump(ini_get("session.cookie_samesite"));
34+
35+
var_dump(ini_get("session.cookie_lifetime"));
36+
var_dump(session_set_cookie_params(["lifetime" => 42]));
37+
var_dump(ini_get("session.cookie_lifetime"));
38+
39+
echo "Done";
40+
ob_end_flush();
41+
?>
42+
--EXPECTF--
43+
*** Testing session_set_cookie_params() : array parameter variation ***
44+
45+
Warning: session_set_cookie_params(): No valid keys were found in the options array in %s
46+
bool(false)
47+
48+
Warning: session_set_cookie_params(): Unrecognized key 'unknown_key' found in the options array in %s
49+
50+
Warning: session_set_cookie_params(): No valid keys were found in the options array in %s
51+
bool(false)
52+
string(1) "0"
53+
string(0) ""
54+
bool(true)
55+
string(1) "1"
56+
string(6) "please"
57+
string(1) "0"
58+
bool(true)
59+
string(2) "42"
60+
Done

Diff for: ext/standard/basic_functions.c

+2-4
Original file line numberDiff line numberDiff line change
@@ -1431,23 +1431,21 @@ ZEND_END_ARG_INFO()
14311431
ZEND_BEGIN_ARG_INFO_EX(arginfo_setcookie, 0, 0, 1)
14321432
ZEND_ARG_INFO(0, name)
14331433
ZEND_ARG_INFO(0, value)
1434-
ZEND_ARG_INFO(0, expires)
1434+
ZEND_ARG_INFO(0, expires_or_options)
14351435
ZEND_ARG_INFO(0, path)
14361436
ZEND_ARG_INFO(0, domain)
14371437
ZEND_ARG_INFO(0, secure)
14381438
ZEND_ARG_INFO(0, httponly)
1439-
ZEND_ARG_INFO(0, samesite)
14401439
ZEND_END_ARG_INFO()
14411440

14421441
ZEND_BEGIN_ARG_INFO_EX(arginfo_setrawcookie, 0, 0, 1)
14431442
ZEND_ARG_INFO(0, name)
14441443
ZEND_ARG_INFO(0, value)
1445-
ZEND_ARG_INFO(0, expires)
1444+
ZEND_ARG_INFO(0, expires_or_options)
14461445
ZEND_ARG_INFO(0, path)
14471446
ZEND_ARG_INFO(0, domain)
14481447
ZEND_ARG_INFO(0, secure)
14491448
ZEND_ARG_INFO(0, httponly)
1450-
ZEND_ARG_INFO(0, samesite)
14511449
ZEND_END_ARG_INFO()
14521450

14531451
ZEND_BEGIN_ARG_INFO_EX(arginfo_headers_sent, 0, 0, 0)

0 commit comments

Comments
 (0)