Cookie.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. /**
  3. * Cookie helper.
  4. *
  5. * @package Kohana
  6. * @category Helpers
  7. * @author Kohana Team
  8. * @copyright (c) Kohana Team
  9. * @license https://koseven.ga/LICENSE.md
  10. */
  11. class Kohana_Cookie {
  12. /**
  13. * @var string Magic salt to add to the cookie
  14. */
  15. public static $salt = NULL;
  16. /**
  17. * @var integer Number of seconds before the cookie expires
  18. */
  19. public static $expiration = 0;
  20. /**
  21. * @var string Restrict the path that the cookie is available to
  22. */
  23. public static $path = '/';
  24. /**
  25. * @var string Restrict the domain that the cookie is available to
  26. */
  27. public static $domain = '';
  28. /**
  29. * @var boolean Only transmit cookies over secure connections
  30. */
  31. public static $secure = FALSE;
  32. /**
  33. * @var boolean Only transmit cookies over HTTP, disabling Javascript access
  34. */
  35. public static $httponly = FALSE;
  36. /**
  37. * Gets the value of a signed cookie. Cookies without signatures will not
  38. * be returned. If the cookie signature is present, but invalid, the cookie
  39. * will be deleted.
  40. *
  41. * // Get the "theme" cookie, or use "blue" if the cookie does not exist
  42. * $theme = Cookie::get('theme', 'blue');
  43. *
  44. * @param string $key cookie name
  45. * @param mixed $default default value to return
  46. * @return string
  47. */
  48. public static function get($key, $default = NULL)
  49. {
  50. if ( ! isset($_COOKIE[$key]))
  51. {
  52. // The cookie does not exist
  53. return $default;
  54. }
  55. // Get the cookie value
  56. $cookie = $_COOKIE[$key];
  57. // Find the position of the split between salt and contents
  58. $split = strlen(Cookie::salt($key, NULL));
  59. if (isset($cookie[$split]) AND $cookie[$split] === '~')
  60. {
  61. // Separate the salt and the value
  62. list ($hash, $value) = explode('~', $cookie, 2);
  63. if (Security::slow_equals(Cookie::salt($key, $value), $hash))
  64. {
  65. // Cookie signature is valid
  66. return $value;
  67. }
  68. // The cookie signature is invalid, delete it
  69. static::delete($key);
  70. }
  71. return $default;
  72. }
  73. /**
  74. * Sets a signed cookie. Note that all cookie values must be strings and no
  75. * automatic serialization will be performed!
  76. *
  77. * [!!] By default, Cookie::$expiration is 0 - if you skip/pass NULL for the optional
  78. * lifetime argument your cookies will expire immediately unless you have separately
  79. * configured Cookie::$expiration.
  80. *
  81. *
  82. * // Set the "theme" cookie
  83. * Cookie::set('theme', 'red');
  84. *
  85. * @param string $name name of cookie
  86. * @param string $value value of cookie
  87. * @param integer $lifetime lifetime in seconds
  88. * @return boolean
  89. * @uses Cookie::salt
  90. */
  91. public static function set($name, $value, $lifetime = NULL)
  92. {
  93. if ($lifetime === NULL)
  94. {
  95. // Use the default expiration
  96. $lifetime = Cookie::$expiration;
  97. }
  98. if ($lifetime !== 0)
  99. {
  100. // The expiration is expected to be a UNIX timestamp
  101. $lifetime += static::_time();
  102. }
  103. // Add the salt to the cookie value
  104. $value = Cookie::salt($name, $value).'~'.$value;
  105. return static::_setcookie($name, $value, $lifetime, Cookie::$path, Cookie::$domain, Cookie::$secure, Cookie::$httponly);
  106. }
  107. /**
  108. * Deletes a cookie by making the value an empty string and expiring it.
  109. *
  110. * Cookie::delete('theme');
  111. *
  112. * @param string $name cookie name
  113. * @return boolean
  114. */
  115. public static function delete($name)
  116. {
  117. // Remove the cookie
  118. unset($_COOKIE[$name]);
  119. // Empty the cookie and make it expire
  120. return static::_setcookie($name, '', -86400, Cookie::$path, Cookie::$domain, Cookie::$secure, Cookie::$httponly);
  121. }
  122. /**
  123. * Generates a salt string for a cookie based on the name and value.
  124. *
  125. * $salt = Cookie::salt('theme', 'red');
  126. *
  127. * @param string $name name of cookie
  128. * @param string $value value of cookie
  129. *
  130. * @throws Kohana_Exception if Cookie::$salt is not configured
  131. * @return string
  132. */
  133. public static function salt($name, $value)
  134. {
  135. // Require a valid salt
  136. if ( ! Cookie::$salt)
  137. {
  138. throw new Kohana_Exception('A valid cookie salt is required. Please set Cookie::$salt in your bootstrap.php. For more information check the documentation');
  139. }
  140. // Determine the user agent
  141. $agent = isset($_SERVER['HTTP_USER_AGENT']) ? strtolower($_SERVER['HTTP_USER_AGENT']) : 'unknown';
  142. return hash_hmac('sha1', $agent.$name.$value.Cookie::$salt, Cookie::$salt);
  143. }
  144. /**
  145. * Proxy for the native setcookie function - to allow mocking in unit tests so that they do not fail when headers
  146. * have been sent.
  147. *
  148. * @param string $name
  149. * @param string $value
  150. * @param integer $expire
  151. * @param string $path
  152. * @param string $domain
  153. * @param boolean $secure
  154. * @param boolean $httponly
  155. *
  156. * @return bool
  157. * @see setcookie
  158. */
  159. protected static function _setcookie($name, $value, $expire, $path, $domain, $secure, $httponly)
  160. {
  161. return setcookie($name, $value, $expire, $path, $domain, $secure, $httponly);
  162. }
  163. /**
  164. * Proxy for the native time function - to allow mocking of time-related logic in unit tests
  165. *
  166. * @return int
  167. * @see time
  168. */
  169. protected static function _time()
  170. {
  171. return time();
  172. }
  173. }