Cookie.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2013, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\storage\session\adapter;
  9. use RuntimeException;
  10. use lithium\util\Set;
  11. /**
  12. * A minimal adapter to interface with HTTP cookies.
  13. *
  14. * This adapter provides basic support for `write`, `read` and `delete`
  15. * cookie handling, as well as allowing these three methods to be filtered as
  16. * per the Lithium filtering system.
  17. *
  18. */
  19. class Cookie extends \lithium\core\Object {
  20. /**
  21. * Default settings for this session adapter.
  22. *
  23. * @var array Keys are in direct correspondence with the parameters in the PHP-native
  24. * `setcookie()` method. The only difference is that the `expire` value is a
  25. * strtotime-compatible string instead of an epochal timestamp.
  26. */
  27. protected $_defaults = array(
  28. 'expire' => '+2 days', 'path' => '/',
  29. 'domain' => '', 'secure' => false, 'httponly' => false
  30. );
  31. /**
  32. * Class constructor.
  33. *
  34. * Takes care of setting appropriate configurations for this object.
  35. *
  36. * @param array $config Optional configuration parameters.
  37. */
  38. public function __construct(array $config = array()) {
  39. if (empty($config['name'])) {
  40. $config['name'] = basename(LITHIUM_APP_PATH) . 'cookie';
  41. }
  42. parent::__construct($config + $this->_defaults);
  43. }
  44. /**
  45. * Obtain the top-level cookie key.
  46. *
  47. * @return string The configured cookie 'name' parameter
  48. */
  49. public function key() {
  50. return $this->_config['name'];
  51. }
  52. /**
  53. * Determines if cookies are enabled.
  54. *
  55. * @return boolean True
  56. * @todo Implement
  57. */
  58. public function isEnabled() {
  59. return true;
  60. }
  61. /**
  62. * Obtain the status of the cookie storage.
  63. *
  64. * @return boolean True if $_COOKIE has been initialized, false otherwise.
  65. */
  66. public function isStarted() {
  67. return (isset($_COOKIE));
  68. }
  69. /**
  70. * Checks if a value has been set in the cookie.
  71. *
  72. * @param string $key Key of the entry to be checked.
  73. * @return closure Function returning boolean `true` if the key exists, `false` otherwise.
  74. */
  75. public function check($key) {
  76. $config = $this->_config;
  77. return function($self, $params) use (&$config) {
  78. return (isset($_COOKIE[$config['name']][$params['key']]));
  79. };
  80. }
  81. /**
  82. * Read a value from the cookie.
  83. *
  84. * @param null|string $key Key of the entry to be read. If $key is null, returns
  85. * all cookie key/value pairs that have been set.
  86. * @param array $options Options array. Not used in this adapter.
  87. * @return closure Function returning data in the session if successful, `null` otherwise.
  88. */
  89. public function read($key = null, array $options = array()) {
  90. $config = $this->_config;
  91. return function($self, $params) use (&$config) {
  92. $key = $params['key'];
  93. if (!$key) {
  94. if (isset($_COOKIE[$config['name']])) {
  95. return $_COOKIE[$config['name']];
  96. }
  97. return array();
  98. }
  99. if (strpos($key, '.') !== false) {
  100. $key = explode('.', $key);
  101. $result = (isset($_COOKIE[$config['name']])) ? $_COOKIE[$config['name']] : array();
  102. foreach ($key as $k) {
  103. if (!isset($result[$k])) {
  104. return null;
  105. }
  106. $result = $result[$k];
  107. }
  108. return $result;
  109. }
  110. if (isset($_COOKIE[$config['name']][$key])) {
  111. return $_COOKIE[$config['name']][$key];
  112. }
  113. };
  114. }
  115. /**
  116. * Write a value to the cookie store.
  117. *
  118. * @param string $key Key of the item to be stored.
  119. * @param mixed $value The value to be stored.
  120. * @param array $options Options array.
  121. * @return closure Function returning boolean `true` on successful write, `false` otherwise.
  122. */
  123. public function write($key, $value = null, array $options = array()) {
  124. $expire = (!isset($options['expire']) && empty($this->_config['expire']));
  125. $config = $this->_config;
  126. $cookieClass = __CLASS__;
  127. if ($expire && $key !== $config['name']) {
  128. return null;
  129. }
  130. $expires = (isset($options['expire'])) ? $options['expire'] : $config['expire'];
  131. return function($self, $params) use (&$config, &$expires, $cookieClass) {
  132. $key = $params['key'];
  133. $value = $params['value'];
  134. $key = array($key => $value);
  135. if (is_array($value)) {
  136. $key = Set::flatten($key);
  137. }
  138. foreach ($key as $name => $val) {
  139. $name = $cookieClass::keyFormat($name, $config);
  140. $result = setcookie($name, $val, strtotime($expires), $config['path'],
  141. $config['domain'], $config['secure'], $config['httponly']
  142. );
  143. if (!$result) {
  144. throw new RuntimeException("There was an error setting {$name} cookie.");
  145. }
  146. }
  147. return true;
  148. };
  149. }
  150. /**
  151. * Delete a value from the cookie store.
  152. *
  153. * @param string $key The key to be deleted from the cookie store.
  154. * @param array $options Options array.
  155. * @return closure Function returning boolean `true` on successful delete, `false` otherwise.
  156. */
  157. public function delete($key, array $options = array()) {
  158. $config = $this->_config;
  159. $cookieClass = get_called_class();
  160. return function($self, $params) use (&$config, $cookieClass) {
  161. $key = $params['key'];
  162. $path = '/' . str_replace('.', '/', $config['name'] . '.' . $key) . '/.';
  163. $cookies = current(Set::extract($_COOKIE, $path));
  164. if (is_array($cookies)) {
  165. $cookies = array_keys(Set::flatten($cookies));
  166. foreach ($cookies as &$name) {
  167. $name = $key . '.' . $name;
  168. }
  169. } else {
  170. $cookies = array($key);
  171. }
  172. foreach ($cookies as &$name) {
  173. $name = $cookieClass::keyFormat($name, $config);
  174. $result = setcookie($name, "", 1, $config['path'],
  175. $config['domain'], $config['secure'], $config['httponly']
  176. );
  177. if (!$result) {
  178. throw new RuntimeException("There was an error deleting {$name} cookie.");
  179. }
  180. }
  181. return true;
  182. };
  183. }
  184. /**
  185. * Clears all cookies.
  186. *
  187. * @param array $options Options array. Not used fro this adapter method.
  188. * @return boolean True on successful clear, false otherwise.
  189. */
  190. public function clear(array $options = array()) {
  191. $options += array('destroySession' => true);
  192. $config = $this->_config;
  193. $cookieClass = get_called_class();
  194. return function($self, $params) use (&$config, $options, $cookieClass) {
  195. if ($options['destroySession'] && session_id()) {
  196. session_destroy();
  197. }
  198. if (!isset($_COOKIE[$config['name']])) {
  199. return true;
  200. }
  201. $cookies = array_keys(Set::flatten($_COOKIE[$config['name']]));
  202. foreach ($cookies as $name) {
  203. $name = $cookieClass::keyFormat($name, $config);
  204. $result = setcookie($name, "", 1, $config['path'],
  205. $config['domain'], $config['secure'], $config['httponly']
  206. );
  207. if (!$result) {
  208. throw new RuntimeException("There was an error clearing {$cookie} cookie.");
  209. }
  210. }
  211. unset($_COOKIE[$config['name']]);
  212. return true;
  213. };
  214. }
  215. /**
  216. * Formats the given `$name` argument for use in the cookie adapter.
  217. *
  218. * @param string $name The key to be formatted, e.g. `foo.bar.baz`.
  219. * @param array $config
  220. * @return string The formatted key.
  221. */
  222. public static function keyFormat($name, $config) {
  223. return $config['name'] . '[' . str_replace('.', '][', $name) . ']';
  224. }
  225. }
  226. ?>