diff options
-rw-r--r-- | application/config/config.php | 2 | ||||
-rw-r--r-- | system/core/Input.php | 42 | ||||
-rw-r--r-- | user_guide_src/source/libraries/input.rst | 21 |
3 files changed, 53 insertions, 12 deletions
diff --git a/application/config/config.php b/application/config/config.php index f92d11f5d..596f8fefe 100644 --- a/application/config/config.php +++ b/application/config/config.php @@ -385,6 +385,7 @@ $config['sess_regenerate_destroy'] = FALSE; | 'cookie_path' = Typically will be a forward slash | 'cookie_secure' = Cookie will only be set if a secure HTTPS connection exists. | 'cookie_httponly' = Cookie will only be accessible via HTTP(S) (no javascript) +| 'cookie_samesite' = Cookie's samesite attribute (Lax, Strict or None) | | Note: These settings (with the exception of 'cookie_prefix' and | 'cookie_httponly') will also affect sessions. @@ -395,6 +396,7 @@ $config['cookie_domain'] = ''; $config['cookie_path'] = '/'; $config['cookie_secure'] = FALSE; $config['cookie_httponly'] = FALSE; +$config['cookie_samesite'] = 'Lax'; /* |-------------------------------------------------------------------------- diff --git a/system/core/Input.php b/system/core/Input.php index 87e6cfed9..71f28221f 100644 --- a/system/core/Input.php +++ b/system/core/Input.php @@ -300,14 +300,15 @@ class CI_Input { * @param string $prefix Cookie name prefix * @param bool $secure Whether to only transfer cookies via SSL * @param bool $httponly Whether to only makes the cookie accessible via HTTP (no javascript) + * @param string $samesite SameSite attribute * @return void */ - public function set_cookie($name, $value = '', $expire = 0, $domain = '', $path = '/', $prefix = '', $secure = NULL, $httponly = NULL) + public function set_cookie($name, $value = '', $expire = 0, $domain = '', $path = '/', $prefix = '', $secure = NULL, $httponly = NULL, $samesite = NULL) { if (is_array($name)) { // always leave 'name' in last place, as the loop will break otherwise, due to $$item - foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name') as $item) + foreach (array('value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name', 'samesite') as $item) { if (isset($name[$item])) { @@ -348,7 +349,42 @@ class CI_Input { $expire = ($expire > 0) ? time() + $expire : 0; } - setcookie($prefix.$name, $value, $expire, $path, $domain, $secure, $httponly); + isset($samesite) OR $samesite = config_item('cookie_samesite'); + if (isset($samesite)) + { + $samesite = ucfirst(strtolower($samesite)); + in_array($samesite, array('Lax', 'Strict', 'None'), TRUE) OR $samesite = 'Lax'; + } + else + { + $samesite = 'Lax'; + } + + if ($samesite === 'None' && ! $secure) + { + log_message('error', $name.' cookie sent with SameSite=None, but without Secure attribute.'); + } + + if (is_php('7.3')) + { + $setcookie_options = array( + 'expires' => $expire, + 'path' => $path, + 'domain' => $domain, + 'secure' => $secure, + 'httponly' => $httponly, + 'samesite' => $samesite, + ); + setcookie($prefix.$name, $value, $setcookie_options); + } + else + { + $cookie_header = 'Set-Cookie: '.$prefix.$name.'='.rawurlencode($value); + $cookie_header .= ($expire === 0 ? '' : '; expires='.gmdate('D, d-M-Y H:i:s T', $expire)); + $cookie_header .= '; path='.$path.($domain !== '' ? '; domain='.$domain : ''); + $cookie_header .= ($secure ? '; secure' : '').($httponly ? '; HttpOnly' : '').'; SameSite='.$samesite; + header($cookie_header); + } } // -------------------------------------------------------------------- diff --git a/user_guide_src/source/libraries/input.rst b/user_guide_src/source/libraries/input.rst index 730b3a9b0..e0f3d8417 100644 --- a/user_guide_src/source/libraries/input.rst +++ b/user_guide_src/source/libraries/input.rst @@ -242,7 +242,7 @@ Class Reference This method is identical to ``get()``, ``post()`` and ``cookie()``, only it fetches the *php://input* stream data. - .. php:method:: set_cookie($name = ''[, $value = ''[, $expire = 0[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = NULL[, $httponly = NULL]]]]]]]) + .. php:method:: set_cookie($name = ''[, $value = ''[, $expire = 0[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = NULL[, $httponly = NULL[, $samesite = NULL]]]]]]]]) :param mixed $name: Cookie name or an array of parameters :param string $value: Cookie value @@ -252,6 +252,7 @@ Class Reference :param string $prefix: Cookie name prefix :param bool $secure: Whether to only transfer the cookie through HTTPS :param bool $httponly: Whether to only make the cookie accessible for HTTP requests (no JavaScript) + :param string $samesite: SameSite attribute ('Lax', 'Strict', 'None') :rtype: void @@ -265,13 +266,14 @@ Class Reference parameter:: $cookie = array( - 'name' => 'The Cookie Name', - 'value' => 'The Value', - 'expire' => 86500, - 'domain' => '.some-domain.com', - 'path' => '/', - 'prefix' => 'myprefix_', - 'secure' => TRUE + 'name' => 'The Cookie Name', + 'value' => 'The Value', + 'expire' => 86500, + 'domain' => '.some-domain.com', + 'path' => '/', + 'prefix' => 'myprefix_', + 'secure' => TRUE, + 'samesite' => 'Strict' ); $this->input->set_cookie($cookie); @@ -297,13 +299,14 @@ Class Reference The *httponly* and *secure* flags, when omitted, will default to your ``$config['cookie_httponly']`` and ``$config['cookie_secure']`` settings. + The *samesite* parameter can be ``'Lax'``, ``'Strict'`` or ``'None'``. If not set, the same-site cookie attribute will default to ``'Lax'``. **Discrete Parameters** If you prefer, you can set the cookie by passing data using individual parameters:: - $this->input->set_cookie($name, $value, $expire, $domain, $path, $prefix, $secure); + $this->input->set_cookie($name, $value, $expire, $domain, $path, $prefix, $secure, $samesite); .. php:method:: ip_address() |