source: Dev/branches/cakephp/cake/libs/controller/components/cookie.php @ 126

Last change on this file since 126 was 126, checked in by fpvanagthoven, 14 years ago

Cakephp branch.

File size: 11.4 KB
Line 
1<?php
2/**
3 * Cookie Component
4 *
5 * PHP versions 4 and 5
6 *
7 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
8 * Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
9 *
10 * Licensed under The MIT License
11 * Redistributions of files must retain the above copyright notice.
12 *
13 * @copyright     Copyright 2005-2011, Cake Software Foundation, Inc. (http://cakefoundation.org)
14 * @link          http://cakephp.org CakePHP(tm) Project
15 * @package       cake
16 * @subpackage    cake.cake.libs.controller.components
17 * @since         CakePHP(tm) v 1.2.0.4213
18 * @license       MIT License (http://www.opensource.org/licenses/mit-license.php)
19 */
20
21/**
22 * Load Security class
23 */
24App::import('Core', 'Security');
25
26/**
27 * Cookie Component.
28 *
29 * Cookie handling for the controller.
30 *
31 * @package       cake
32 * @subpackage    cake.cake.libs.controller.components
33 * @link http://book.cakephp.org/view/1280/Cookies
34 *
35 */
36class CookieComponent extends Object {
37
38/**
39 * The name of the cookie.
40 *
41 * Overridden with the controller beforeFilter();
42 * $this->Cookie->name = 'CookieName';
43 *
44 * @var string
45 * @access public
46 */
47        var $name = 'CakeCookie';
48
49/**
50 * The time a cookie will remain valid.
51 *
52 * Can be either integer Unix timestamp or a date string.
53 *
54 * Overridden with the controller beforeFilter();
55 * $this->Cookie->time = '5 Days';
56 *
57 * @var mixed
58 * @access public
59 */
60        var $time = null;
61
62/**
63 * Cookie path.
64 *
65 * Overridden with the controller beforeFilter();
66 * $this->Cookie->path = '/';
67 *
68 * The path on the server in which the cookie will be available on.
69 * If  var $cookiePath is set to '/foo/', the cookie will only be available
70 * within the /foo/ directory and all sub-directories such as /foo/bar/ of domain.
71 * The default value is the entire domain.
72 *
73 * @var string
74 * @access public
75 */
76        var $path = '/';
77
78/**
79 * Domain path.
80 *
81 * The domain that the cookie is available.
82 *
83 * Overridden with the controller beforeFilter();
84 * $this->Cookie->domain = '.example.com';
85 *
86 * To make the cookie available on all subdomains of example.com.
87 * Set $this->Cookie->domain = '.example.com'; in your controller beforeFilter
88 *
89 * @var string
90 * @access public
91 */
92        var $domain = '';
93
94/**
95 * Secure HTTPS only cookie.
96 *
97 * Overridden with the controller beforeFilter();
98 * $this->Cookie->secure = true;
99 *
100 * Indicates that the cookie should only be transmitted over a secure HTTPS connection.
101 * When set to true, the cookie will only be set if a secure connection exists.
102 *
103 * @var boolean
104 * @access public
105 */
106        var $secure = false;
107
108/**
109 * Encryption key.
110 *
111 * Overridden with the controller beforeFilter();
112 * $this->Cookie->key = 'SomeRandomString';
113 *
114 * @var string
115 * @access protected
116 */
117        var $key = null;
118
119/**
120 * Values stored in the cookie.
121 *
122 * Accessed in the controller using $this->Cookie->read('Name.key');
123 *
124 * @see CookieComponent::read();
125 * @var string
126 * @access private
127 */
128        var $__values = array();
129
130/**
131 * Type of encryption to use.
132 *
133 * Currently only one method is available
134 * Defaults to Security::cipher();
135 *
136 * @var string
137 * @access private
138 * @todo add additional encryption methods
139 */
140        var $__type = 'cipher';
141
142/**
143 * Used to reset cookie time if $expire is passed to CookieComponent::write()
144 *
145 * @var string
146 * @access private
147 */
148        var $__reset = null;
149
150/**
151 * Expire time of the cookie
152 *
153 * This is controlled by CookieComponent::time;
154 *
155 * @var string
156 * @access private
157 */
158        var $__expires = 0;
159
160/**
161 * Main execution method.
162 *
163 * @param object $controller A reference to the instantiating controller object
164 * @access public
165 */
166        function initialize(&$controller, $settings) {
167                $this->key = Configure::read('Security.salt');
168                $this->_set($settings);
169                if (isset($this->time)) {
170                        $this->__expire($this->time);
171                }
172        }
173
174/**
175 * Start CookieComponent for use in the controller
176 *
177 * @access public
178 */
179        function startup() {
180                $this->__expire($this->time);
181
182                if (isset($_COOKIE[$this->name])) {
183                        $this->__values = $this->__decrypt($_COOKIE[$this->name]);
184                }
185        }
186
187/**
188 * Write a value to the $_COOKIE[$key];
189 *
190 * Optional [Name.], required key, optional $value, optional $encrypt, optional $expires
191 * $this->Cookie->write('[Name.]key, $value);
192 *
193 * By default all values are encrypted.
194 * You must pass $encrypt false to store values in clear test
195 *
196 * You must use this method before any output is sent to the browser.
197 * Failure to do so will result in header already sent errors.
198 *
199 * @param mixed $key Key for the value
200 * @param mixed $value Value
201 * @param boolean $encrypt Set to true to encrypt value, false otherwise
202 * @param string $expires Can be either Unix timestamp, or date string
203 * @access public
204 */
205        function write($key, $value = null, $encrypt = true, $expires = null) {
206                if (is_null($encrypt)) {
207                        $encrypt = true;
208                }
209                $this->__encrypted = $encrypt;
210                $this->__expire($expires);
211
212                if (!is_array($key)) {
213                        $key = array($key => $value);
214                }
215
216                foreach ($key as $name => $value) {
217                        if (strpos($name, '.') === false) {
218                                $this->__values[$name] = $value;
219                                $this->__write("[$name]", $value);
220
221                        } else {
222                                $names = explode('.', $name, 2);
223                                if (!isset($this->__values[$names[0]])) {
224                                        $this->__values[$names[0]] = array();
225                                }
226                                $this->__values[$names[0]] = Set::insert($this->__values[$names[0]], $names[1], $value);
227                                $this->__write('[' . implode('][', $names) . ']', $value);
228                        }
229                }
230                $this->__encrypted = true;
231        }
232
233/**
234 * Read the value of the $_COOKIE[$key];
235 *
236 * Optional [Name.], required key
237 * $this->Cookie->read(Name.key);
238 *
239 * @param mixed $key Key of the value to be obtained. If none specified, obtain map key => values
240 * @return string or null, value for specified key
241 * @access public
242 */
243        function read($key = null) {
244                if (empty($this->__values) && isset($_COOKIE[$this->name])) {
245                        $this->__values = $this->__decrypt($_COOKIE[$this->name]);
246                }
247
248                if (is_null($key)) {
249                        return $this->__values;
250                }
251
252                if (strpos($key, '.') !== false) {
253                        $names = explode('.', $key, 2);
254                        $key = $names[0];
255                }
256                if (!isset($this->__values[$key])) {
257                        return null;
258                }
259
260                if (!empty($names[1])) {
261                        return Set::extract($this->__values[$key], $names[1]);
262                }
263                return $this->__values[$key];
264        }
265
266/**
267 * Delete a cookie value
268 *
269 * Optional [Name.], required key
270 * $this->Cookie->read('Name.key);
271 *
272 * You must use this method before any output is sent to the browser.
273 * Failure to do so will result in header already sent errors.
274 *
275 * @param string $key Key of the value to be deleted
276 * @return void
277 * @access public
278 */
279        function delete($key) {
280                if (empty($this->__values)) {
281                        $this->read();
282                }
283                if (strpos($key, '.') === false) {
284                        if (isset($this->__values[$key]) && is_array($this->__values[$key])) {
285                                foreach ($this->__values[$key] as $idx => $val) {
286                                        $this->__delete("[$key][$idx]");
287                                }
288                        }
289                        $this->__delete("[$key]");
290                        unset($this->__values[$key]);
291                        return;
292                }
293                $names = explode('.', $key, 2);
294                if (isset($this->__values[$names[0]])) {
295                        $this->__values[$names[0]] = Set::remove($this->__values[$names[0]], $names[1]);
296                }
297                $this->__delete('[' . implode('][', $names) . ']');
298        }
299
300/**
301 * Destroy current cookie
302 *
303 * You must use this method before any output is sent to the browser.
304 * Failure to do so will result in header already sent errors.
305 *
306 * @return void
307 * @access public
308 */
309        function destroy() {
310                if (isset($_COOKIE[$this->name])) {
311                        $this->__values = $this->__decrypt($_COOKIE[$this->name]);
312                }
313
314                foreach ($this->__values as $name => $value) {
315                        if (is_array($value)) {
316                                foreach ($value as $key => $val) {
317                                        unset($this->__values[$name][$key]);
318                                        $this->__delete("[$name][$key]");
319                                }
320                        }
321                        unset($this->__values[$name]);
322                        $this->__delete("[$name]");
323                }
324        }
325
326/**
327 * Will allow overriding default encryption method.
328 *
329 * @param string $type Encryption method
330 * @access public
331 * @todo NOT IMPLEMENTED
332 */
333        function type($type = 'cipher') {
334                $this->__type = 'cipher';
335        }
336
337/**
338 * Set the expire time for a session variable.
339 *
340 * Creates a new expire time for a session variable.
341 * $expire can be either integer Unix timestamp or a date string.
342 *
343 * Used by write()
344 * CookieComponent::write(string, string, boolean, 8400);
345 * CookieComponent::write(string, string, boolean, '5 Days');
346 *
347 * @param mixed $expires Can be either Unix timestamp, or date string
348 * @return int Unix timestamp
349 * @access private
350 */
351        function __expire($expires = null) {
352                $now = time();
353                if (is_null($expires)) {
354                        return $this->__expires;
355                }
356                $this->__reset = $this->__expires;
357
358                if ($expires == 0) {
359                        return $this->__expires = 0;
360                }
361
362                if (is_integer($expires) || is_numeric($expires)) {
363                        return $this->__expires = $now + intval($expires);
364                }
365                return $this->__expires = strtotime($expires, $now);
366        }
367
368/**
369 * Set cookie
370 *
371 * @param string $name Name for cookie
372 * @param string $value Value for cookie
373 * @access private
374 */
375        function __write($name, $value) {
376                setcookie($this->name . $name, $this->__encrypt($value), $this->__expires, $this->path, $this->domain, $this->secure);
377
378                if (!is_null($this->__reset)) {
379                        $this->__expires = $this->__reset;
380                        $this->__reset = null;
381                }
382        }
383
384/**
385 * Sets a cookie expire time to remove cookie value
386 *
387 * @param string $name Name of cookie
388 * @access private
389 */
390        function __delete($name) {
391                setcookie($this->name . $name, '', time() - 42000, $this->path, $this->domain, $this->secure);
392        }
393
394/**
395 * Encrypts $value using var $type method in Security class
396 *
397 * @param string $value Value to encrypt
398 * @return string encrypted string
399 * @access private
400 */
401        function __encrypt($value) {
402                if (is_array($value)) {
403                        $value = $this->__implode($value);
404                }
405
406                if ($this->__encrypted === true) {
407                        $type = $this->__type;
408                        $value = "Q2FrZQ==." .base64_encode(Security::$type($value, $this->key));
409                }
410                return $value;
411        }
412
413/**
414 * Decrypts $value using var $type method in Security class
415 *
416 * @param array $values Values to decrypt
417 * @return string decrypted string
418 * @access private
419 */
420        function __decrypt($values) {
421                $decrypted = array();
422                $type = $this->__type;
423
424                foreach ((array)$values as $name => $value) {
425                        if (is_array($value)) {
426                                foreach ($value as $key => $val) {
427                                        $pos = strpos($val, 'Q2FrZQ==.');
428                                        $decrypted[$name][$key] = $this->__explode($val);
429
430                                        if ($pos !== false) {
431                                                $val = substr($val, 8);
432                                                $decrypted[$name][$key] = $this->__explode(Security::$type(base64_decode($val), $this->key));
433                                        }
434                                }
435                        } else {
436                                $pos = strpos($value, 'Q2FrZQ==.');
437                                $decrypted[$name] = $this->__explode($value);
438
439                                if ($pos !== false) {
440                                        $value = substr($value, 8);
441                                        $decrypted[$name] = $this->__explode(Security::$type(base64_decode($value), $this->key));
442                                }
443                        }
444                }
445                return $decrypted;
446        }
447
448/**
449 * Implode method to keep keys are multidimensional arrays
450 *
451 * @param array $array Map of key and values
452 * @return string String in the form key1|value1,key2|value2
453 * @access private
454 */
455        function __implode($array) {
456                $string = '';
457                foreach ($array as $key => $value) {
458                        $string .= ',' . $key . '|' . $value;
459                }
460                return substr($string, 1);
461        }
462
463/**
464 * Explode method to return array from string set in CookieComponent::__implode()
465 *
466 * @param string $string String in the form key1|value1,key2|value2
467 * @return array Map of key and values
468 * @access private
469 */
470        function __explode($string) {
471                $array = array();
472                foreach (explode(',', $string) as $pair) {
473                        $key = explode('|', $pair);
474                        if (!isset($key[1])) {
475                                return $key[0];
476                        }
477                        $array[$key[0]] = $key[1];
478                }
479                return $array;
480        }
481}
Note: See TracBrowser for help on using the repository browser.