mirror of
https://github.com/processwire/processwire.git
synced 2025-08-16 11:44:42 +02:00
Refactoring and documentation improvements to the WireInputDataCookie class which manages the $input->cookie API var. Contained in these updates is also a fix for processwire/processwire-issues#1053
This commit is contained in:
@@ -286,7 +286,45 @@ class WireInput extends Wire {
|
|||||||
/**
|
/**
|
||||||
* Retrieve a named COOKIE variable value or all COOKIE variables
|
* Retrieve a named COOKIE variable value or all COOKIE variables
|
||||||
*
|
*
|
||||||
* Always sanitize (and validate where appropriate) any values from user input.
|
* Please see the [cookie API reference page](https://processwire.com/api/ref/wire-input-data-cookie/) for
|
||||||
|
* additional documentation on how to get and set cookies and cookie options.
|
||||||
|
*
|
||||||
|
* ~~~~~
|
||||||
|
* // setting cookies
|
||||||
|
* $input->cookie->foo = 'bar'; // set with default options (expires with session)
|
||||||
|
* $input->cookie->set('foo', 'bar'); // same as above
|
||||||
|
* $input->cookie->set('foo', bar', 86400); // expire after 86400 seconds (1 day)
|
||||||
|
* $input->cookie->set('foo', 'bar', [ 'age' => 86400, 'path' => $page->url ]);
|
||||||
|
*
|
||||||
|
* // getting cookies
|
||||||
|
* $val = $input->cookie->foo;
|
||||||
|
* $val = $input->cookie->get('foo'); // same as above
|
||||||
|
* $val = $input->cookie->text('foo'); // get and use text sanitizer
|
||||||
|
*
|
||||||
|
* // removing cookies
|
||||||
|
* $input->cookie->remove('foo');
|
||||||
|
*
|
||||||
|
* // getting cookie options
|
||||||
|
* $array = $input->cookie->options();
|
||||||
|
* print_r($array); // see all options
|
||||||
|
*
|
||||||
|
* // setting cookie options (to use in next $input->cookie->set call)
|
||||||
|
* $input->cookie->options('age', 86400); // set default age to 1 day
|
||||||
|
* $input->cookie->options([ // set multiple options
|
||||||
|
* 'age' => 86400,
|
||||||
|
* 'path' => $page->url,
|
||||||
|
* 'domain' => 'www.domain.com',
|
||||||
|
* ]);
|
||||||
|
*
|
||||||
|
* // setting default options (in /site/config.php):
|
||||||
|
* $config->cookieOptions = [
|
||||||
|
* 'age' => 604800, // 1 week
|
||||||
|
* 'httponly' => true, // make visible to PHP but not JS
|
||||||
|
* // and so on
|
||||||
|
* ];
|
||||||
|
* ~~~~~
|
||||||
|
*
|
||||||
|
* Cookies are a form of user input, so always sanitize (and validate where appropriate) any values.
|
||||||
*
|
*
|
||||||
* The following optional features are available in ProcessWire version 3.0.125 and newer:
|
* The following optional features are available in ProcessWire version 3.0.125 and newer:
|
||||||
*
|
*
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
<?php namespace ProcessWire;
|
<?php namespace ProcessWire;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WireInputDataCookie class represents the $input->cookie API variable
|
* Provides methods for managing cookies via the $input->cookie API variable
|
||||||
*
|
*
|
||||||
* #pw-summary Enables setting and getting cookies from the ProcessWire API using $input->cookie.
|
* #pw-summary Enables getting, setting and removing cookies from the ProcessWire API using `$input->cookie`.
|
||||||
*
|
*
|
||||||
* #pw-body =
|
* #pw-body =
|
||||||
*
|
*
|
||||||
* - Whether getting or setting, cookie values are always strings.
|
* - Whether getting or setting, cookie values are always strings.
|
||||||
* - Values retrieved from `$input->cookie` are user input (like PHP’s $_COOKIE) and should be sanitized and validated.
|
* - Values retrieved from `$input->cookie` are user input (like PHP’s $_COOKIE) and need to be sanitized and validated by you.
|
||||||
* - When removing/unsetting cookies, the path, domain, secure, and httponly options must be the same as when the cookie was set,
|
* - When removing/unsetting cookies, the path, domain, secure, and httponly options must be the same as when the cookie was set,
|
||||||
* as a result, it’s good to have these things predefined in `$config->cookieOptions` rather than setting during runtime.
|
* as a result, it’s good to have these things predefined in `$config->cookieOptions` rather than setting during runtime.
|
||||||
* - Note that this class does not manage PW’s session cookies.
|
* - Note that this class does not manage PW’s session cookies.
|
||||||
@@ -41,21 +41,22 @@
|
|||||||
* $config->cookieOptions = [
|
* $config->cookieOptions = [
|
||||||
*
|
*
|
||||||
* // Max age of cookies in seconds or 0 to expire with session
|
* // Max age of cookies in seconds or 0 to expire with session
|
||||||
* // 3600=1hr, 86400=1day, 604800=1week, 2592000=30days, etc.
|
* // 3600=1 hour, 86400=1 day, 604800=1 week, 2592000=30 days, etc.
|
||||||
* 'age' => 604800,
|
* 'age' => 604800,
|
||||||
*
|
*
|
||||||
* // Cookie path/URL or null for PW installation’s root URL
|
* // Cookie path/URL or null for PW installation’s root URL
|
||||||
* 'path' => null,
|
* 'path' => null,
|
||||||
*
|
*
|
||||||
* // Cookie domain: null for current hostname, true for all subdomains of current domain,
|
* // Cookie domain: null for current hostname, true for all subdomains of current domain,
|
||||||
* // domain.com for domain and all subdomains, www.domain.com for www subdomain.
|
* // domain.com for domain and all subdomains (same as true), www.domain.com for www subdomain
|
||||||
|
* // and additional hosts off www subdomain (i.e. dev.www.domain.com)
|
||||||
* 'domain' => null,
|
* 'domain' => null,
|
||||||
*
|
*
|
||||||
* // Transmit cookies only over secure HTTPS connection?
|
* // Transmit cookies only over secure HTTPS connection?
|
||||||
* // Specify true, false, or null to auto-detect (uses true for cookies set when HTTPS).
|
* // Specify true, false, or null to auto-detect (uses true for cookies set when HTTPS).
|
||||||
* 'secure' => null,
|
* 'secure' => null,
|
||||||
*
|
*
|
||||||
* // Make cookies accessible by HTTP only?
|
* // Make cookies accessible by HTTP (ProcessWire/PHP) only?
|
||||||
* // When true, cookie is http/server-side only and not visible to client-side JS code.
|
* // When true, cookie is http/server-side only and not visible to client-side JS code.
|
||||||
* 'httponly' => false,
|
* 'httponly' => false,
|
||||||
*
|
*
|
||||||
@@ -66,7 +67,7 @@
|
|||||||
* ~~~~~
|
* ~~~~~
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* ProcessWire 3.x, Copyright 2019 by Ryan Cramer
|
* ProcessWire 3.x, Copyright 2020 by Ryan Cramer
|
||||||
* https://processwire.com
|
* https://processwire.com
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -89,6 +90,7 @@ class WireInputDataCookie extends WireInputData {
|
|||||||
*/
|
*/
|
||||||
protected $defaultOptions = array(
|
protected $defaultOptions = array(
|
||||||
'age' => 0,
|
'age' => 0,
|
||||||
|
'expire' => null,
|
||||||
'path' => null,
|
'path' => null,
|
||||||
'domain' => null,
|
'domain' => null,
|
||||||
'secure' => null,
|
'secure' => null,
|
||||||
@@ -98,13 +100,14 @@ class WireInputDataCookie extends WireInputData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Cookie options specifically set at runtime
|
* Cookie options specifically set at runtime
|
||||||
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected $options = array();
|
protected $options = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cookie names not be allowed to be removed
|
* Cookie names not allowed to be set or removed (i.e. session cookies)
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*
|
*
|
||||||
@@ -149,6 +152,22 @@ class WireInputDataCookie extends WireInputData {
|
|||||||
* - Specify string for $key (and omit $value) to get the value of one option.
|
* - Specify string for $key (and omit $value) to get the value of one option.
|
||||||
* - Specify both $key and $value arguments to set one option.
|
* - Specify both $key and $value arguments to set one option.
|
||||||
* - Specify associative array for $key (and omit $value) to set multiple options.
|
* - Specify associative array for $key (and omit $value) to set multiple options.
|
||||||
|
*
|
||||||
|
* Options you can get or set:
|
||||||
|
*
|
||||||
|
* - `age` (int): Max age of cookies in seconds or 0 to expire with session. For example: 3600=1 hour, 86400=1 day,
|
||||||
|
* 604800=1 week, 2592000=30 days, etc. (default=0, expire with session)
|
||||||
|
* - `expire` (int|string): If you prefer to use an expiration date rather than the `age` option, specify a unix timestamp (int),
|
||||||
|
* ISO-8601 date string, or any date string recognized by PHP’s strtotime(), like "2020-11-03" or +1 WEEK", etc. (default=null).
|
||||||
|
* Please note the expire option was added in 3.0.159, previous versions should use the `age` option only.
|
||||||
|
* - `path` (string|null): Cookie path/URL or null for PW installation’s root URL. (default=null)
|
||||||
|
* - `secure` (bool|null): Transmit cookies only over secure HTTPS connection? Specify true or false, or use null to auto-detect,
|
||||||
|
* which uses true for cookies set when HTTPS is detected. (default=null)
|
||||||
|
* - `httponly` (bool): When true, cookie is visible to PHP/ProcessWire only and not visible to client-side JS code. (default=false)
|
||||||
|
* - `fallback` (bool): If set cookie fails (perhaps due to output already sent), attempt to set at beginning of next request? (default=true)
|
||||||
|
* - `domain` (string|bool|null): Cookie domain, specify one of the following: `null` or blank string for current hostname [default],
|
||||||
|
* boolean `true` for all subdomains of current domain, `domain.com` for domain.com and *.domain.com [same as true], `www.domain.com`
|
||||||
|
* for www subdomain and and hostnames off of it, like dev.www.domain.com. (default=null, current hostname)
|
||||||
*
|
*
|
||||||
* @param string|array|null $key
|
* @param string|array|null $key
|
||||||
* @param string|array|int|float|null $value
|
* @param string|array|int|float|null $value
|
||||||
@@ -194,18 +213,59 @@ class WireInputDataCookie extends WireInputData {
|
|||||||
$this->setCookie($key, $value, array());
|
$this->setCookie($key, $value, array());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a cookie value
|
||||||
|
*
|
||||||
|
* Gets a previously set cookie value or null if cookie not present or expired.
|
||||||
|
* Cookies are a type of user input, so always sanitize (and validate where appropriate) any values.
|
||||||
|
*
|
||||||
|
* ~~~~~
|
||||||
|
* $val = $input->cookie->foo;
|
||||||
|
* $val = $input->cookie->get('foo'); // same as above
|
||||||
|
* $val = $input->cookie->text('foo'); // get and use text sanitizer
|
||||||
|
* ~~~~~
|
||||||
|
*
|
||||||
|
* @param string $key Name of cookie to get
|
||||||
|
* @param array|int|string $options Options not currently used, but available for descending classes or future use
|
||||||
|
* @return string|int|float|array|null $value
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function get($key, $options = array()) {
|
||||||
|
return parent::get($key, $options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a cookie (optionally with options)
|
* Set a cookie (optionally with options)
|
||||||
|
*
|
||||||
|
* The defaults or previously set options from an `options()` method call are used for any `$options` not specified.
|
||||||
|
*
|
||||||
|
* ~~~~~
|
||||||
|
* $input->cookie->foo = 'bar'; // set with default options (expires with session)
|
||||||
|
* $input->cookie->set('foo', 'bar'); // same as above
|
||||||
|
* $input->cookie->set('foo', bar', 86400); // expire after 86400 seconds (1 day)
|
||||||
|
* $input->cookie->set('foo', 'bar', [ // set with options
|
||||||
|
* 'age' => 86400,
|
||||||
|
* 'path' => $page->url,
|
||||||
|
* 'httponly' => true,
|
||||||
|
* ]);
|
||||||
|
* ~~~~~
|
||||||
*
|
*
|
||||||
* @param string $key Cookie name
|
* @param string $key Cookie name
|
||||||
* @param string $value Cookie value
|
* @param string $value Cookie value
|
||||||
* @param array|int|string $options Optionally specify max age in seconds (int) or array with any of the following options:
|
* @param array|int|string $options Specify int for `age` option, string for `expire` option, or array for multiple options:
|
||||||
* - `age` (int): Max age of cookies in seconds or 0 to expire with session (3600=1hr, 86400=1day, 604800=1week, 2592000=30days, etc.)
|
* - `age` (int): Max age of cookies in seconds or 0 to expire with session. For example: 3600=1 hour, 86400=1 day,
|
||||||
* - `path` (string|null): Cookie path/URL or null for PW installation’s root URL.
|
* 604800=1 week, 2592000=30 days, etc. (default=0, expire with session)
|
||||||
* - `domain` (string|bool|null): Cookie domain: null for current hostname, true for all subdomains of current domain, domain.com for domain and all subdomains, www.domain.com for www subdomain.
|
* - `expire` (int|string): If you prefer to use an expiration date rather than the `age` option, specify a unix timestamp (int),
|
||||||
* - `secure` (bool|null): Transmit cookies only over secure HTTPS connection? (true, false, or null to auto-detect, substituting true for cookies set when HTTPS is active).
|
* ISO-8601 date string, or any date string recognized by PHP’s strtotime(), like "2020-11-03" or +1 WEEK", etc. (default=null).
|
||||||
* - `httponly` (bool): When true, cookie is http/server-side only and not visible to client-side JS code.
|
* Please note the expire option was added in 3.0.159, previous versions should use the `age` option only.
|
||||||
* - `fallback` (bool): If set cookie fails (perhaps due to output already sent), attempt to set at beginning of next request?
|
* - `path` (string|null): Cookie path/URL or null for PW installation’s root URL. (default=null)
|
||||||
|
* - `secure` (bool|null): Transmit cookies only over secure HTTPS connection? Specify true or false, or use null to auto-detect,
|
||||||
|
* which uses true for cookies set when HTTPS is detected. (default=null)
|
||||||
|
* - `httponly` (bool): When true, cookie is visible to PHP/ProcessWire only and not visible to client-side JS code. (default=false)
|
||||||
|
* - `fallback` (bool): If set cookie fails (perhaps due to output already sent), attempt to set at beginning of next request? (default=true)
|
||||||
|
* - `domain` (string|bool|null): Cookie domain, specify one of the following: `null` or blank string for current hostname [default],
|
||||||
|
* boolean `true` for all subdomains of current domain, `domain.com` for domain.com and *.domain.com [same as true], `www.domain.com`
|
||||||
|
* for www subdomain and and hostnames off of it, like dev.www.domain.com. (default=null, current hostname)
|
||||||
* @return $this
|
* @return $this
|
||||||
* @since 3.0.141
|
* @since 3.0.141
|
||||||
*
|
*
|
||||||
@@ -217,9 +277,16 @@ class WireInputDataCookie extends WireInputData {
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!is_array($options) && ctype_digit("$options")) {
|
if(!is_array($options)) {
|
||||||
$age = (int) $options;
|
if(is_int($options) || ctype_digit("$options")) {
|
||||||
$options = array('age' => $age);
|
$age = (int) $options;
|
||||||
|
$options = array('age' => $age);
|
||||||
|
} else if(!empty($options) && is_string($options)) {
|
||||||
|
$expire = $options;
|
||||||
|
$options = array('expire' => $expire);
|
||||||
|
} else {
|
||||||
|
$options = array();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->setCookie($key, $value, $options);
|
$this->setCookie($key, $value, $options);
|
||||||
@@ -228,39 +295,93 @@ class WireInputDataCookie extends WireInputData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a cookie (internal)
|
* Remove a cookie value by name
|
||||||
*
|
*
|
||||||
* @param string $key
|
* @param string $key Name of cookie variable to remove value for
|
||||||
* @param string|array|int|float $value
|
* @return WireInputDataCookie|WireInputData|$this
|
||||||
* @param array $options Optionally override options from $config->cookieOptions and any previously set from an options() call:
|
|
||||||
* - `age` (int): Max age of cookies in seconds or 0 to expire with session (3600=1hr, 86400=1day, 604800=1week, 2592000=30days, etc.)
|
|
||||||
* - `path` (string|null): Cookie path/URL or null for PW installation’s root URL.
|
|
||||||
* - `domain` (string|bool|null): Cookie domain: null for current hostname, true for all subdomains of current domain, domain.com for domain and all subdomains, www.domain.com for www subdomain.
|
|
||||||
* - `secure` (bool|null): Transmit cookies only over secure HTTPS connection? (true, false, or null to auto-detect, substituting true for cookies set when HTTPS is active).
|
|
||||||
* - `httponly` (bool): When true, cookie is http/server-side only and not visible to client-side JS code.
|
|
||||||
* - `fallback` (bool): If set cookie fails (perhaps due to output already sent), attempt to set at beginning of next request?
|
|
||||||
* @return bool
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
protected function setCookie($key, $value, array $options) {
|
public function remove($key) {
|
||||||
|
return parent::remove($key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all cookies (other than those required for current session)
|
||||||
|
*
|
||||||
|
* @return $this|WireInputData
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function removeAll() {
|
||||||
|
foreach($this as $key => $value) {
|
||||||
|
$this->offsetUnset($key);
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a cookie with options and return success state
|
||||||
|
*
|
||||||
|
* This is the same as the `set()` mehod except for the following:
|
||||||
|
*
|
||||||
|
* - It returns a boolean (success state) rather than reference to $this.
|
||||||
|
* - An $options array argument is required.
|
||||||
|
* - It does not accept a max age in place of $options argument.
|
||||||
|
*
|
||||||
|
* #pw-internal
|
||||||
|
*
|
||||||
|
* @param string $key Name of cookie to set
|
||||||
|
* @param string|array|int|float $value Value to place in cookie
|
||||||
|
* @param array $options Optionally override options from $config->cookieOptions and any previously set from an options() call:
|
||||||
|
* - `age` (int): Max age of cookies in seconds or 0 to expire with session. For example: 3600=1 hour, 86400=1 day,
|
||||||
|
* 604800=1 week, 2592000=30 days, etc. (default=0, expire with session)
|
||||||
|
* - `expire` (int|string): If you prefer to use an expiration date rather than the `age` option, specify a unix timestamp (int),
|
||||||
|
* ISO-8601 date string, or any date string recognized by PHP’s strtotime(), like "2020-11-03" or +1 WEEK", etc. (default=null).
|
||||||
|
* Please note the expire option was added in 3.0.159, previous versions should use the `age` option only.
|
||||||
|
* - `path` (string|null): Cookie path/URL or null for PW installation’s root URL. (default=null)
|
||||||
|
* - `secure` (bool|null): Transmit cookies only over secure HTTPS connection? Specify true or false, or use null to auto-detect,
|
||||||
|
* which uses true for cookies set when HTTPS is detected. (default=null)
|
||||||
|
* - `httponly` (bool): When true, cookie is visible to PHP/ProcessWire only and not visible to client-side JS code. (default=false)
|
||||||
|
* - `fallback` (bool): If set cookie fails (perhaps due to output already sent), attempt to set at beginning of next request? (default=true)
|
||||||
|
* - `domain` (string|bool|null): Cookie domain, specify one of the following: `null` or blank string for current hostname [default],
|
||||||
|
* boolean `true` for all subdomains of current domain, `domain.com` for domain.com and *.domain.com [same as true], `www.domain.com`
|
||||||
|
* for www subdomain and and hostnames off of it, like dev.www.domain.com. (default=null)
|
||||||
|
* @return bool Returns true on success or false if cookie could not be set in this request and has been queued for next request
|
||||||
|
* @since 3.0.159
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function setCookie($key, $value, array $options) {
|
||||||
|
|
||||||
/** @var Config $config */
|
/** @var Config $config */
|
||||||
$config = $this->wire('config');
|
$config = $this->wire('config');
|
||||||
$options = array_merge($this->defaultOptions, $config->cookieOptions, $this->options, $options);
|
$options = array_merge($this->defaultOptions, $config->cookieOptions, $this->options, $options);
|
||||||
|
|
||||||
$expires = $options['age'] ? time() + (int) $options['age'] : 0;
|
|
||||||
$path = $options['path'] === null || $options['path'] === true ? $config->urls->root : $options['path'];
|
$path = $options['path'] === null || $options['path'] === true ? $config->urls->root : $options['path'];
|
||||||
$secure = $options['secure'] === null ? (bool) $config->https : (bool) $options['secure'];
|
$secure = $options['secure'] === null ? (bool) $config->https : (bool) $options['secure'];
|
||||||
$httponly = (bool) $options['httponly'];
|
$httponly = (bool) $options['httponly'];
|
||||||
$domain = $options['domain'];
|
$domain = $options['domain'];
|
||||||
$remove = $value === null;
|
$remove = $value === null;
|
||||||
|
$expires = null;
|
||||||
|
|
||||||
|
if(!empty($options['expire'])) {
|
||||||
|
if(is_string($options['expire']) && !ctype_digit($options['expire'])) {
|
||||||
|
$expires = strtotime($options['expire']);
|
||||||
|
} else {
|
||||||
|
$expires = (int) $options['expire'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($expires)) {
|
||||||
|
$expires = $options['age'] ? time() + (int) $options['age'] : 0;
|
||||||
|
}
|
||||||
|
|
||||||
if(!$this->allowSetCookie($key)) return false;
|
if(!$this->allowSetCookie($key)) return false;
|
||||||
|
|
||||||
// determine what to use for the domain argument
|
// determine what to use for the domain argument
|
||||||
if($domain === null) {
|
if($domain === null) {
|
||||||
// use current http host
|
// use current/origin http host only
|
||||||
$domain = $config->httpHost;
|
// http://www.faqs.org/rfcs/rfc6265.html - 4.1.2.3.
|
||||||
|
// “If the server omits the Domain attribute, the user agent will return the cookie only to the origin server.”
|
||||||
|
$domain = '';
|
||||||
} else if($domain === true) {
|
} else if($domain === true) {
|
||||||
// allow all subdomains off current domain
|
// allow all subdomains off current domain
|
||||||
$parts = explode('.', $config->httpHost);
|
$parts = explode('.', $config->httpHost);
|
||||||
@@ -318,20 +439,6 @@ class WireInputDataCookie extends WireInputData {
|
|||||||
if(empty($this->skipCookies)) $this->skipCookies = $this->wire('session')->getCookieNames();
|
if(empty($this->skipCookies)) $this->skipCookies = $this->wire('session')->getCookieNames();
|
||||||
return in_array($name, $this->skipCookies) ? false : true;
|
return in_array($name, $this->skipCookies) ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove all cookies (other than those required for current session)
|
|
||||||
*
|
|
||||||
* @return $this|WireInputData
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public function removeAll() {
|
|
||||||
foreach($this as $key => $value) {
|
|
||||||
$this->offsetUnset($key);
|
|
||||||
}
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user