PageRenderTime 60ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/server/lib/Slim/Slim/Http/Util.php

https://bitbucket.org/sonnylazuardi/konsol
PHP | 389 lines | 182 code | 29 blank | 178 comment | 41 complexity | d8f41593cb8449fd35c14f2580d36436 MD5 | raw file
  1. <?php
  2. /**
  3. * Slim - a micro PHP 5 framework
  4. *
  5. * @author Josh Lockhart <info@slimframework.com>
  6. * @copyright 2011 Josh Lockhart
  7. * @link http://www.slimframework.com
  8. * @license http://www.slimframework.com/license
  9. * @version 2.0.0
  10. * @package Slim
  11. *
  12. * MIT LICENSE
  13. *
  14. * Permission is hereby granted, free of charge, to any person obtaining
  15. * a copy of this software and associated documentation files (the
  16. * "Software"), to deal in the Software without restriction, including
  17. * without limitation the rights to use, copy, modify, merge, publish,
  18. * distribute, sublicense, and/or sell copies of the Software, and to
  19. * permit persons to whom the Software is furnished to do so, subject to
  20. * the following conditions:
  21. *
  22. * The above copyright notice and this permission notice shall be
  23. * included in all copies or substantial portions of the Software.
  24. *
  25. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  28. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  29. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  30. * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  31. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  32. */
  33. namespace Slim\Http;
  34. /**
  35. * Slim HTTP Utilities
  36. *
  37. * This class provides useful methods for handling HTTP requests.
  38. *
  39. * @package Slim
  40. * @author Josh Lockhart
  41. * @since 1.0.0
  42. */
  43. class Util
  44. {
  45. /**
  46. * Strip slashes from string or array
  47. *
  48. * This method strips slashes from its input. By default, this method will only
  49. * strip slashes from its input if magic quotes are enabled. Otherwise, you may
  50. * override the magic quotes setting with either TRUE or FALSE as the send argument
  51. * to force this method to strip or not strip slashes from its input.
  52. *
  53. * @var array|string $rawData
  54. * @return array|string
  55. */
  56. public static function stripSlashesIfMagicQuotes($rawData, $overrideStripSlashes = null)
  57. {
  58. $strip = is_null($overrideStripSlashes) ? get_magic_quotes_gpc() : $overrideStripSlashes;
  59. if ($strip) {
  60. return self::_stripSlashes($rawData);
  61. } else {
  62. return $rawData;
  63. }
  64. }
  65. /**
  66. * Strip slashes from string or array
  67. * @param array|string $rawData
  68. * @return array|string
  69. */
  70. protected static function _stripSlashes($rawData)
  71. {
  72. return is_array($rawData) ? array_map(array('self', '_stripSlashes'), $rawData) : stripslashes($rawData);
  73. }
  74. /**
  75. * Encrypt data
  76. *
  77. * This method will encrypt data using a given key, vector, and cipher.
  78. * By default, this will encrypt data using the RIJNDAEL/AES 256 bit cipher. You
  79. * may override the default cipher and cipher mode by passing your own desired
  80. * cipher and cipher mode as the final key-value array argument.
  81. *
  82. * @param string $data The unencrypted data
  83. * @param string $key The encryption key
  84. * @param string $iv The encryption initialization vector
  85. * @param array $settings Optional key-value array with custom algorithm and mode
  86. * @return string
  87. */
  88. public static function encrypt($data, $key, $iv, $settings = array())
  89. {
  90. if ($data === '' || !extension_loaded('mcrypt')) {
  91. return $data;
  92. }
  93. //Merge settings with defaults
  94. $settings = array_merge(array(
  95. 'algorithm' => MCRYPT_RIJNDAEL_256,
  96. 'mode' => MCRYPT_MODE_CBC
  97. ), $settings);
  98. //Get module
  99. $module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], '');
  100. //Validate IV
  101. $ivSize = mcrypt_enc_get_iv_size($module);
  102. if (strlen($iv) > $ivSize) {
  103. $iv = substr($iv, 0, $ivSize);
  104. }
  105. //Validate key
  106. $keySize = mcrypt_enc_get_key_size($module);
  107. if (strlen($key) > $keySize) {
  108. $key = substr($key, 0, $keySize);
  109. }
  110. //Encrypt value
  111. mcrypt_generic_init($module, $key, $iv);
  112. $res = @mcrypt_generic($module, $data);
  113. mcrypt_generic_deinit($module);
  114. return $res;
  115. }
  116. /**
  117. * Decrypt data
  118. *
  119. * This method will decrypt data using a given key, vector, and cipher.
  120. * By default, this will decrypt data using the RIJNDAEL/AES 256 bit cipher. You
  121. * may override the default cipher and cipher mode by passing your own desired
  122. * cipher and cipher mode as the final key-value array argument.
  123. *
  124. * @param string $data The encrypted data
  125. * @param string $key The encryption key
  126. * @param string $iv The encryption initialization vector
  127. * @param array $settings Optional key-value array with custom algorithm and mode
  128. * @return string
  129. */
  130. public static function decrypt($data, $key, $iv, $settings = array())
  131. {
  132. if ($data === '' || !extension_loaded('mcrypt')) {
  133. return $data;
  134. }
  135. //Merge settings with defaults
  136. $settings = array_merge(array(
  137. 'algorithm' => MCRYPT_RIJNDAEL_256,
  138. 'mode' => MCRYPT_MODE_CBC
  139. ), $settings);
  140. //Get module
  141. $module = mcrypt_module_open($settings['algorithm'], '', $settings['mode'], '');
  142. //Validate IV
  143. $ivSize = mcrypt_enc_get_iv_size($module);
  144. if (strlen($iv) > $ivSize) {
  145. $iv = substr($iv, 0, $ivSize);
  146. }
  147. //Validate key
  148. $keySize = mcrypt_enc_get_key_size($module);
  149. if (strlen($key) > $keySize) {
  150. $key = substr($key, 0, $keySize);
  151. }
  152. //Decrypt value
  153. mcrypt_generic_init($module, $key, $iv);
  154. $decryptedData = @mdecrypt_generic($module, $data);
  155. $res = str_replace("\x0", '', $decryptedData);
  156. mcrypt_generic_deinit($module);
  157. return $res;
  158. }
  159. /**
  160. * Encode secure cookie value
  161. *
  162. * This method will create the secure value of an HTTP cookie. The
  163. * cookie value is encrypted and hashed so that its value is
  164. * secure and checked for integrity when read in subsequent requests.
  165. *
  166. * @param string $value The unsecure HTTP cookie value
  167. * @param int $expires The UNIX timestamp at which this cookie will expire
  168. * @param string $secret The secret key used to hash the cookie value
  169. * @param int $algorithm The algorithm to use for encryption
  170. * @param int $mode The algorithm mode to use for encryption
  171. * @param string
  172. */
  173. public static function encodeSecureCookie($value, $expires, $secret, $algorithm, $mode)
  174. {
  175. $key = hash_hmac('sha1', $expires, $secret);
  176. $iv = self::get_iv($expires, $secret);
  177. $secureString = base64_encode(self::encrypt($value, $key, $iv, array(
  178. 'algorithm' => $algorithm,
  179. 'mode' => $mode
  180. )));
  181. $verificationString = hash_hmac('sha1', $expires . $value, $key);
  182. return implode('|', array($expires, $secureString, $verificationString));
  183. }
  184. /**
  185. * Decode secure cookie value
  186. *
  187. * This method will decode the secure value of an HTTP cookie. The
  188. * cookie value is encrypted and hashed so that its value is
  189. * secure and checked for integrity when read in subsequent requests.
  190. *
  191. * @param string $value The secure HTTP cookie value
  192. * @param int $expires The UNIX timestamp at which this cookie will expire
  193. * @param string $secret The secret key used to hash the cookie value
  194. * @param int $algorithm The algorithm to use for encryption
  195. * @param int $mode The algorithm mode to use for encryption
  196. * @param string
  197. */
  198. public static function decodeSecureCookie($value, $secret, $algorithm, $mode)
  199. {
  200. if ($value) {
  201. $value = explode('|', $value);
  202. if (count($value) === 3 && ((int) $value[0] === 0 || (int) $value[0] > time())) {
  203. $key = hash_hmac('sha1', $value[0], $secret);
  204. $iv = self::get_iv($value[0], $secret);
  205. $data = self::decrypt(base64_decode($value[1]), $key, $iv, array(
  206. 'algorithm' => $algorithm,
  207. 'mode' => $mode
  208. ));
  209. $verificationString = hash_hmac('sha1', $value[0] . $data, $key);
  210. if ($verificationString === $value[2]) {
  211. return $data;
  212. }
  213. }
  214. }
  215. return false;
  216. }
  217. /**
  218. * Set HTTP cookie header
  219. *
  220. * This method will construct and set the HTTP `Set-Cookie` header. Slim
  221. * uses this method instead of PHP's native `setcookie` method. This allows
  222. * more control of the HTTP header irrespective of the native implementation's
  223. * dependency on PHP versions.
  224. *
  225. * This method accepts the Slim_Http_Headers object by reference as its
  226. * first argument; this method directly modifies this object instead of
  227. * returning a value.
  228. *
  229. * @param array $header
  230. * @param string $name
  231. * @param string $value
  232. */
  233. public static function setCookieHeader(&$header, $name, $value)
  234. {
  235. //Build cookie header
  236. if (is_array($value)) {
  237. $domain = '';
  238. $path = '';
  239. $expires = '';
  240. $secure = '';
  241. $httponly = '';
  242. if (isset($value['domain']) && $value['domain']) {
  243. $domain = '; domain=' . $value['domain'];
  244. }
  245. if (isset($value['path']) && $value['path']) {
  246. $path = '; path=' . $value['path'];
  247. }
  248. if (isset($value['expires'])) {
  249. if (is_string($value['expires'])) {
  250. $timestamp = strtotime($value['expires']);
  251. } else {
  252. $timestamp = (int) $value['expires'];
  253. }
  254. if ($timestamp !== 0) {
  255. $expires = '; expires=' . gmdate('D, d-M-Y H:i:s e', $timestamp);
  256. }
  257. }
  258. if (isset($value['secure']) && $value['secure']) {
  259. $secure = '; secure';
  260. }
  261. if (isset($value['httponly']) && $value['httponly']) {
  262. $httponly = '; HttpOnly';
  263. }
  264. $cookie = sprintf('%s=%s%s', urlencode($name), urlencode((string) $value['value']), $domain . $path . $expires . $secure . $httponly);
  265. } else {
  266. $cookie = sprintf('%s=%s', urlencode($name), urlencode((string) $value));
  267. }
  268. //Set cookie header
  269. if (!isset($header['Set-Cookie']) || $header['Set-Cookie'] === '') {
  270. $header['Set-Cookie'] = $cookie;
  271. } else {
  272. $header['Set-Cookie'] = implode("\n", array($header['Set-Cookie'], $cookie));
  273. }
  274. }
  275. /**
  276. * Delete HTTP cookie header
  277. *
  278. * This method will construct and set the HTTP `Set-Cookie` header to invalidate
  279. * a client-side HTTP cookie. If a cookie with the same name (and, optionally, domain)
  280. * is already set in the HTTP response, it will also be removed. Slim uses this method
  281. * instead of PHP's native `setcookie` method. This allows more control of the HTTP header
  282. * irrespective of PHP's native implementation's dependency on PHP versions.
  283. *
  284. * This method accepts the Slim_Http_Headers object by reference as its
  285. * first argument; this method directly modifies this object instead of
  286. * returning a value.
  287. *
  288. * @param array $header
  289. * @param string $name
  290. * @param string $value
  291. */
  292. public static function deleteCookieHeader(&$header, $name, $value = array())
  293. {
  294. //Remove affected cookies from current response header
  295. $cookiesOld = array();
  296. $cookiesNew = array();
  297. if (isset($header['Set-Cookie'])) {
  298. $cookiesOld = explode("\n", $header['Set-Cookie']);
  299. }
  300. foreach ($cookiesOld as $c) {
  301. if (isset($value['domain']) && $value['domain']) {
  302. $regex = sprintf('@%s=.*domain=%s@', urlencode($name), preg_quote($value['domain']));
  303. } else {
  304. $regex = sprintf('@%s=@', urlencode($name));
  305. }
  306. if (preg_match($regex, $c) === 0) {
  307. $cookiesNew[] = $c;
  308. }
  309. }
  310. if ($cookiesNew) {
  311. $header['Set-Cookie'] = implode("\n", $cookiesNew);
  312. } else {
  313. unset($header['Set-Cookie']);
  314. }
  315. //Set invalidating cookie to clear client-side cookie
  316. self::setCookieHeader($header, $name, array_merge(array('value' => '', 'path' => null, 'domain' => null, 'expires' => time() - 100), $value));
  317. }
  318. /**
  319. * Parse cookie header
  320. *
  321. * This method will parse the HTTP requst's `Cookie` header
  322. * and extract cookies into an associative array.
  323. *
  324. * @param string
  325. * @return array
  326. */
  327. public static function parseCookieHeader($header)
  328. {
  329. $cookies = array();
  330. $header = rtrim($header, "\r\n");
  331. $headerPieces = preg_split('@\s*[;,]\s*@', $header);
  332. foreach ($headerPieces as $c) {
  333. $cParts = explode('=', $c);
  334. if (count($cParts) === 2) {
  335. $key = urldecode($cParts[0]);
  336. $value = urldecode($cParts[1]);
  337. if (!isset($cookies[$key])) {
  338. $cookies[$key] = $value;
  339. }
  340. }
  341. }
  342. return $cookies;
  343. }
  344. /**
  345. * Generate a random IV
  346. *
  347. * This method will generate a non-predictable IV for use with
  348. * the cookie encryption
  349. *
  350. * @param int $expires The UNIX timestamp at which this cookie will expire
  351. * @param string $secret The secret key used to hash the cookie value
  352. * @return binary string with length 40
  353. */
  354. private static function get_iv($expires, $secret)
  355. {
  356. $data1 = hash_hmac('sha1', 'a'.$expires.'b', $secret);
  357. $data2 = hash_hmac('sha1', 'z'.$expires.'y', $secret);
  358. return pack("h*", $data1.$data2);
  359. }
  360. }