cookie.php

Go to the documentation of this file.
00001 <?php
00002 /* SVN FILE: $Id: cookie_8php-source.html 580 2008-07-01 14:45:49Z gwoo $ */
00003 /**
00004  * Short description for file.
00005  *
00006  * Long description for file
00007  *
00008  * PHP versions 4 and 5
00009  *
00010  * CakePHP(tm) :  Rapid Development Framework <http://www.cakephp.org/>
00011  * Copyright 2005-2008, Cake Software Foundation, Inc.
00012  *                              1785 E. Sahara Avenue, Suite 490-204
00013  *                              Las Vegas, Nevada 89104
00014  *
00015  * Licensed under The MIT License
00016  * Redistributions of files must retain the above copyright notice.
00017  *
00018  * @filesource
00019  * @copyright       Copyright 2005-2008, Cake Software Foundation, Inc.
00020  * @link                http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
00021  * @package         cake
00022  * @subpackage      cake.cake.libs.controller.components
00023  * @since           CakePHP(tm) v 1.2.0.4213
00024  * @version         $Revision: 580 $
00025  * @modifiedby      $LastChangedBy: gwoo $
00026  * @lastmodified    $Date: 2008-07-01 09:45:49 -0500 (Tue, 01 Jul 2008) $
00027  * @license         http://www.opensource.org/licenses/mit-license.php The MIT License
00028  */
00029 /**
00030  * Load Security class
00031  */
00032 App::import('Core', 'Security');
00033 /**
00034  * Cookie Component.
00035  *
00036  * Cookie handling for the controller.
00037  *
00038  * @package     cake
00039  * @subpackage  cake.cake.libs.controller.components
00040  *
00041  */
00042 class CookieComponent extends Object {
00043 /**
00044  * The name of the cookie.
00045  *
00046  * Overridden with the controller beforeFilter();
00047  * $this->Cookie->name = 'CookieName';
00048  *
00049  * @var string
00050  * @access public
00051  */
00052     var $name = 'CakeCookie';
00053 /**
00054  * The time a cookie will remain valid.
00055  *
00056  * Can be either integer Unix timestamp or a date string.
00057  *
00058  * Overridden with the controller beforeFilter();
00059  * $this->Cookie->time = '5 Days';
00060  *
00061  * @var mixed
00062  * @access public
00063  */
00064     var $time = null;
00065 /**
00066  * Cookie path.
00067  *
00068  * Overridden with the controller beforeFilter();
00069  * $this->Cookie->path = '/';
00070  *
00071  * The path on the server in which the cookie will be available on.
00072  * If  var $cookiePath is set to '/foo/', the cookie will only be available
00073  * within the /foo/ directory and all sub-directories such as /foo/bar/ of domain.
00074  * The default value is the entire domain.
00075  *
00076  * @var string
00077  * @access public
00078  */
00079     var $path = '/';
00080 /**
00081  * Domain path.
00082  *
00083  * The domain that the cookie is available.
00084  *
00085  * Overridden with the controller beforeFilter();
00086  * $this->Cookie->domain = '.example.com';
00087  *
00088  * To make the cookie available on all subdomains of example.com.
00089  * Set $this->Cookie->domain = '.example.com'; in your controller beforeFilter
00090  *
00091  * @var string
00092  * @access public
00093  */
00094     var $domain = '';
00095 /**
00096  * Secure HTTPS only cookie.
00097  *
00098  * Overridden with the controller beforeFilter();
00099  * $this->Cookie->secure = true;
00100  *
00101  * Indicates that the cookie should only be transmitted over a secure HTTPS connection.
00102  * When set to true, the cookie will only be set if a secure connection exists.
00103  *
00104  * @var boolean
00105  * @access public
00106  */
00107     var $secure = false;
00108 /**
00109  * Encryption key.
00110  *
00111  * Overridden with the controller beforeFilter();
00112  * $this->Cookie->key = 'SomeRandomString';
00113  *
00114  * @var string
00115  * @access protected
00116  */
00117     var $key = null;
00118 /**
00119  * Values stored in the cookie.
00120  *
00121  * Accessed in the controller using $this->Cookie->read('Name.key');
00122  *
00123  * @see CookieComponent::read();
00124  * @var string
00125  * @access private
00126  */
00127     var $__values = array();
00128 /**
00129  * Type of encryption to use.
00130  *
00131  * Currently only one method is available
00132  * Defaults to Security::cipher();
00133  *
00134  * @var string
00135  * @access private
00136  * @todo add additional encryption methods
00137  */
00138     var $__type = 'cipher';
00139 /**
00140  * Used to reset cookie time if $expire is passed to CookieComponent::write()
00141  *
00142  * @var string
00143  * @access private
00144  */
00145     var $__reset = null;
00146 /**
00147  * Expire time of the cookie
00148  *
00149  * This is controlled by CookieComponent::time;
00150  *
00151  * @var string
00152  * @access private
00153  */
00154     var $__expires = 0;
00155 /**
00156  * Main execution method.
00157  *
00158  * @param object $controller A reference to the instantiating controller object
00159  * @access public
00160  */
00161     function initialize(&$controller, $settings) {
00162         $this->key = Configure::read('Security.salt');
00163         $this->_set($settings);
00164     }
00165 /**
00166  * Start CookieComponent for use in the controller
00167  *
00168  * @access public
00169  */
00170     function startup() {
00171         $this->__expire($this->time);
00172 
00173         if (isset($_COOKIE[$this->name])) {
00174             $this->__values = $this->__decrypt($_COOKIE[$this->name]);
00175         }
00176     }
00177 /**
00178  * Write a value to the $_COOKIE[$key];
00179  *
00180  * Optional [Name.], reguired key, optional $value, optional $encrypt, optional $expires
00181  * $this->Cookie->write('[Name.]key, $value);
00182  *
00183  * By default all values are encrypted.
00184  * You must pass $encrypt false to store values in clear test
00185  *
00186  * You must use this method before any output is sent to the browser.
00187  * Failure to do so will result in header already sent errors.
00188  *
00189  * @param mixed $key Key for the value
00190  * @param mixed $value Value
00191  * @param boolean $encrypt Set to true to encrypt value, false otherwise
00192  * @param string $expires Can be either Unix timestamp, or date string
00193  * @access public
00194  */
00195     function write($key, $value = null, $encrypt = true, $expires = null) {
00196         if (is_null($encrypt)) {
00197             $encrypt = true;
00198         }
00199 
00200         $this->__encrypted = $encrypt;
00201         $this->__expire($expires);
00202 
00203         if (!is_array($key) && $value !== null) {
00204             $name = $this->__cookieVarNames($key);
00205 
00206             if (count($name) > 1) {
00207                 $this->__values[$name[0]][$name[1]] = $value;
00208                 $this->__write("[".$name[0]."][".$name[1]."]", $value);
00209             } else {
00210                 $this->__values[$name[0]] = $value;
00211                 $this->__write("[".$name[0]."]", $value);
00212             }
00213         } else {
00214             foreach ($key as $names => $value) {
00215                 $name = $this->__cookieVarNames($names);
00216 
00217                 if (count($name) > 1) {
00218                     $this->__values[$name[0]][$name[1]] = $value;
00219                     $this->__write("[".$name[0]."][".$name[1]."]", $value);
00220                 } else {
00221                     $this->__values[$name[0]] = $value;
00222                     $this->__write("[".$name[0]."]", $value);
00223                 }
00224             }
00225         }
00226         $this->__encrypted = true;
00227     }
00228 /**
00229  * Read the value of the $_COOKIE[$key];
00230  *
00231  * Optional [Name.], reguired key
00232  * $this->Cookie->read(Name.key);
00233  *
00234  * @param mixed $key Key of the value to be obtained. If none specified, obtain map key => values
00235  * @return string or null, value for specified key
00236  * @access public
00237  */
00238     function read($key = null) {
00239         if (empty($this->__values) && isset($_COOKIE[$this->name])) {
00240             $this->__values = $this->__decrypt($_COOKIE[$this->name]);
00241         }
00242 
00243         if (is_null($key)) {
00244             return $this->__values;
00245         }
00246         $name = $this->__cookieVarNames($key);
00247 
00248         if (count($name) > 1) {
00249             if (isset($this->__values[$name[0]])) {
00250                 if(isset($this->__values[$name[0]][$name[1]])) {
00251                     return $this->__values[$name[0]][$name[1]];
00252                 }
00253             }
00254             return null;
00255         } else {
00256             if (isset($this->__values[$name[0]])) {
00257                 $value = $this->__values[$name[0]];
00258                 return $value;
00259             }
00260             return null;
00261         }
00262     }
00263 /**
00264  * Delete a cookie value
00265  *
00266  * Optional [Name.], reguired key
00267  * $this->Cookie->read('Name.key);
00268  *
00269  * You must use this method before any output is sent to the browser.
00270  * Failure to do so will result in header already sent errors.
00271  *
00272  * @param string $key Key of the value to be deleted
00273  * @access public
00274  */
00275     function del($key) {
00276         $name = $this->__cookieVarNames($key);
00277 
00278         if (count($name) > 1) {
00279             if (isset($this->__values[$name[0]])) {
00280                 unset($this->__values[$name[0]][$name[1]]);
00281                 $this->__delete("[".$name[0]."][".$name[1]."]");
00282             }
00283         } else {
00284             if (isset($this->__values[$name[0]])) {
00285                 if (is_array($this->__values[$name[0]])) {
00286                     foreach ($this->__values[$name[0]] as $key => $value) {
00287                         $this->__delete("[".$name[0]."][".$key."]");
00288                     }
00289                 }
00290                 $this->__delete("[".$name[0]."]");
00291                 unset($this->__values[$name[0]]);
00292             }
00293         }
00294     }
00295 /**
00296  * Destroy current cookie
00297  *
00298  * You must use this method before any output is sent to the browser.
00299  * Failure to do so will result in header already sent errors.
00300  *
00301  * @access public
00302  */
00303     function destroy() {
00304         if (isset($_COOKIE[$this->name])) {
00305             $this->__values = $this->__decrypt($_COOKIE[$this->name]);
00306         }
00307 
00308         foreach ($this->__values as $name => $value) {
00309             if (is_array($value)) {
00310                 foreach ($value as $key => $val) {
00311                     unset($this->__values[$name][$key]);
00312                     $this->__delete("[$name][$key]");
00313                 }
00314             }
00315             unset($this->__values[$name]);
00316             $this->__delete("[$name]");
00317         }
00318     }
00319 /**
00320  * Will allow overriding default encryption method.
00321  *
00322  * @param string $type Encryption method
00323  * @access public
00324  * @todo NOT IMPLEMENTED
00325  */
00326     function type($type = 'cipher') {
00327         $this->__type = 'cipher';
00328     }
00329 /**
00330  * Set the expire time for a session variable.
00331  *
00332  * Creates a new expire time for a session variable.
00333  * $expire can be either integer Unix timestamp or a date string.
00334  *
00335  * Used by write()
00336  * CookieComponent::write(string, string, boolean, 8400);
00337  * CookieComponent::write(string, string, boolean, '5 Days');
00338  *
00339  * @param mixed $expires Can be either Unix timestamp, or date string
00340  * @return int Unix timestamp
00341  * @access private
00342  */
00343     function __expire($expires = null) {
00344         $now = time();
00345         if (is_null($expires)) {
00346             return $this->__expires;
00347         }
00348         $this->__reset = $this->__expires;
00349         if (is_integer($expires) || is_numeric($expires)) {
00350             return $this->__expires = $now + intval($expires);
00351         } else {
00352             return $this->__expires = strtotime($expires, $now);
00353         }
00354     }
00355 /**
00356  * Set cookie
00357  *
00358  * @param string $name Name for cookie
00359  * @param string $value Value for cookie
00360  * @access private
00361  */
00362     function __write($name, $value) {
00363         setcookie($this->name . "$name", $this->__encrypt($value), $this->__expires, $this->path, $this->domain, $this->secure);
00364 
00365         if (!is_null($this->__reset)) {
00366             $this->__expires = $this->__reset;
00367             $this->__reset = null;
00368         }
00369     }
00370 /**
00371  * Sets a cookie expire time to remove cookie value
00372  *
00373  * @param string $name Name of cookie
00374  * @access private
00375  */
00376     function __delete($name) {
00377         setcookie($this->name . $name, '', time() - 42000, $this->path, $this->domain, $this->secure);
00378     }
00379 /**
00380  * Encrypts $value using var $type method in Security class
00381  *
00382  * @param string $value Value to encrypt
00383  * @return string encrypted string
00384  * @access private
00385  */
00386     function __encrypt($value) {
00387         if (is_array($value)) {
00388             $value = $this->__implode($value);
00389         }
00390 
00391         if ($this->__encrypted === true) {
00392             $type = $this->__type;
00393             $value = "Q2FrZQ==." .base64_encode(Security::$type($value, $this->key));
00394         }
00395         return($value);
00396     }
00397 /**
00398  * Decrypts $value using var $type method in Security class
00399  *
00400  * @param array $values Values to decrypt
00401  * @return string decrypted string
00402  * @access private
00403  */
00404     function __decrypt($values) {
00405         $decrypted = array();
00406         $type = $this->__type;
00407 
00408         foreach ($values as $name => $value) {
00409             if (is_array($value)) {
00410                 foreach ($value as $key => $val) {
00411                     $pos = strpos($val, 'Q2FrZQ==.');
00412                     $decrypted[$name][$key] = $this->__explode($val);
00413 
00414                     if ($pos !== false) {
00415                         $val = substr($val, 8);
00416                         $decrypted[$name][$key] = $this->__explode(Security::$type(base64_decode($val), $this->key));
00417                     }
00418                 }
00419             } else {
00420                     $pos = strpos($value, 'Q2FrZQ==.');
00421                     $decrypted[$name] = $this->__explode($value);
00422 
00423                     if ($pos !== false) {
00424                         $value = substr($value, 8);
00425                         $decrypted[$name] = $this->__explode(Security::$type(base64_decode($value), $this->key));
00426                     }
00427             }
00428         }
00429 
00430         return($decrypted);
00431     }
00432 
00433 /**
00434  * Creates an array from the $name parameter which allows the dot notation
00435  * similar to one used by Session and Configure classes
00436  *
00437  * @param string $name Name with or without dot notation
00438  * @return array Extracted names
00439  * @access private
00440  */
00441     function __cookieVarNames($name) {
00442         if (is_string($name)) {
00443             if (strpos($name, ".")) {
00444                 $name = explode(".", $name);
00445             } else {
00446                 $name = array($name);
00447             }
00448         }
00449         return $name;
00450     }
00451 /**
00452  * Implode method to keep keys are multidimensional arrays
00453  *
00454  * @param array $array Map of key and values
00455  * @return string String in the form key1|value1,key2|value2
00456  * @access private
00457  */
00458     function __implode($array) {
00459         $string = '';
00460         foreach ($array as $key => $value) {
00461             $string .= ',' . $key . '|' . $value;
00462         }
00463         return substr($string, 1);
00464     }
00465 /**
00466  * Explode method to return array from string set in CookieComponent::__implode()
00467  *
00468  * @param string $string String in the form key1|value1,key2|value2
00469  * @return array Map of key and values
00470  * @access private
00471  */
00472     function __explode($string) {
00473         $array = array();
00474         foreach (explode(',', $string) as $pair) {
00475             $key = explode('|', $pair);
00476             if (!isset($key[1])) {
00477                 return $key[0];
00478             }
00479             $array[$key[0]] = $key[1];
00480         }
00481         return $array;
00482     }
00483 }
00484 ?>