PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/nooku/libraries/koowa/request/request.php

https://github.com/bhar1red/anahita
PHP | 720 lines | 407 code | 101 blank | 212 comment | 81 complexity | d20a9d691609d91dca39399908ba4cfb MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * @version $Id: request.php 4628 2012-05-06 19:56:43Z johanjanssens $
  4. * @package Koowa_Request
  5. * @copyright Copyright (C) 2007 - 2012 Johan Janssens. All rights reserved.
  6. * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
  7. * @link http://www.nooku.org
  8. */
  9. //Instantiate the request singleton
  10. KRequest::getInstance();
  11. /**
  12. * Request class
  13. *
  14. * @author Johan Janssens <johan@nooku.org>
  15. * @package Koowa_Request
  16. * @uses KFilter
  17. * @uses KInflector
  18. * @uses KService
  19. * @static
  20. */
  21. class KRequest
  22. {
  23. /**
  24. * URL of the request regardless of the server
  25. *
  26. * @var KHttpUrl
  27. */
  28. protected static $_url = null;
  29. /**
  30. * Base path of the request.
  31. *
  32. * @var KHttpUrl
  33. */
  34. protected static $_base = null;
  35. /**
  36. * Root path of the request.
  37. *
  38. * @var KHttpUrl
  39. */
  40. protected static $_root = null;
  41. /**
  42. * Referrer of the request
  43. *
  44. * @var KHttpUrl
  45. */
  46. protected static $_referrer = null;
  47. /**
  48. * The raw post or put content information
  49. *
  50. * @var array
  51. */
  52. protected static $_content = null;
  53. /**
  54. * The request accepts information
  55. *
  56. * @var array
  57. */
  58. protected static $_accept = null;
  59. /**
  60. * Constructor
  61. *
  62. * Prevent creating instances of this class by making the contructor private
  63. */
  64. final private function __construct(KConfig $config)
  65. {
  66. $content = self::content();
  67. if(self::type() == 'HTTP')
  68. {
  69. if(strpos(PHP_SAPI, 'cgi') !== false) {
  70. $authorization = KRequest::get('server.REDIRECT_HTTP_AUTHORIZATION', 'string');
  71. } else {
  72. $authorization = KRequest::get('server.HTTP_AUTHORIZATION', 'url');
  73. }
  74. if (strstr($authorization,"Basic"))
  75. {
  76. $parts = explode(':',base64_decode(substr($authorization, 6)));
  77. if (count($parts) == 2)
  78. {
  79. KRequest::set('server.PHP_AUTH_USER', $parts[0]);
  80. KRequest::set('server.PHP_AUTH_PW' , $parts[1]);
  81. }
  82. }
  83. }
  84. if(!empty($content['data']))
  85. {
  86. if($content['type'] == 'application/x-www-form-urlencoded')
  87. {
  88. if (in_array(self::method(), array('PUT', 'DELETE')))
  89. {
  90. parse_str($content['data'], $GLOBALS['_'.self::method()]);
  91. $GLOBALS['_REQUEST'] = array_merge($GLOBALS['_REQUEST'], $GLOBALS['_'.self::method()]);
  92. }
  93. }
  94. if($content['type'] == 'application/json')
  95. {
  96. if(in_array(self::method(), array('POST', 'PUT', 'DELETE')))
  97. {
  98. $GLOBALS['_'.self::method()] = json_decode($content['data'], true);
  99. $GLOBALS['_REQUEST'] = array_merge($GLOBALS['_REQUEST'], $GLOBALS['_'.self::method()]);
  100. }
  101. }
  102. }
  103. }
  104. /**
  105. * Clone
  106. *
  107. * Prevent creating clones of this class
  108. */
  109. final private function __clone() { }
  110. /**
  111. * Force creation of a singleton
  112. *
  113. * @return void
  114. */
  115. public static function getInstance($config = array())
  116. {
  117. static $instance;
  118. if ($instance === NULL)
  119. {
  120. if(!$config instanceof KConfig) {
  121. $config = new KConfig($config);
  122. }
  123. $instance = new self($config);
  124. }
  125. return $instance;
  126. }
  127. /**
  128. * Get sanitized data from the request.
  129. *
  130. * @param string Variable identifier, prefixed by hash name eg post.foo.bar
  131. * @param mixed Filter(s), can be a KFilter object, a filter name, an array of filter names or a filter identifier
  132. * @param mixed Default value when the variable doesn't exist
  133. * @throws KRequestException When an invalid filter was passed
  134. * @return mixed The sanitized data
  135. */
  136. public static function get($identifier, $filter, $default = null)
  137. {
  138. list($hash, $keys) = self::_parseIdentifier($identifier);
  139. $result = null;
  140. if(isset($GLOBALS['_'.$hash]))
  141. {
  142. $result = $GLOBALS['_'.$hash];
  143. foreach($keys as $key)
  144. {
  145. if(array_key_exists($key, $result)) {
  146. $result = $result[$key];
  147. } else {
  148. $result = null;
  149. break;
  150. }
  151. }
  152. }
  153. // If the value is null return the default
  154. if(is_null($result)) {
  155. return $default;
  156. }
  157. // Handle magic quotes compatability
  158. if (get_magic_quotes_gpc() && !in_array($hash, array('FILES', 'SESSION'))) {
  159. $result = self::_stripSlashes( $result );
  160. }
  161. if(!($filter instanceof KFilterInterface)) {
  162. $filter = KService::get('koowa:filter.factory')->instantiate($filter);
  163. }
  164. return $filter->sanitize($result);
  165. }
  166. /**
  167. * Set a variable in the request. Cookies and session data are stored persistently.
  168. *
  169. * @param mixed Variable identifier, prefixed by hash name eg post.foo.bar
  170. * @param mixed Variable value
  171. */
  172. public static function set($identifier, $value)
  173. {
  174. list($hash, $keys) = self::_parseIdentifier($identifier);
  175. // Add to _REQUEST hash if original hash is get, post, or cookies
  176. if(in_array($hash, array('GET', 'POST', 'COOKIE'))) {
  177. self::set('request.'.implode('.', $keys), $value);
  178. }
  179. // Store cookies persistently
  180. if($hash == 'COOKIE' && strpos(KRequest::scheme(), 'http') !== false)
  181. {
  182. // rewrite the $keys as foo[bar][bar]
  183. $ckeys = $keys; // get a copy
  184. $name = array_shift($ckeys);
  185. foreach($ckeys as $ckey) {
  186. $name .= '['.$ckey.']';
  187. }
  188. if(!setcookie($name, $value)) {
  189. throw new KRequestException("Couldn't set cookie, headers already sent.");
  190. }
  191. }
  192. // Store in $GLOBALS
  193. foreach(array_reverse($keys, true) as $key) {
  194. $value = array($key => $value);
  195. }
  196. // Add the global if it's doesn't exist
  197. if(!isset($GLOBALS['_'.$hash])) {
  198. $GLOBALS['_'.$hash] = array();
  199. }
  200. $GLOBALS['_'.$hash] = KHelperArray::merge($GLOBALS['_'.$hash], $value);
  201. }
  202. /**
  203. * Check if a variable exists based on an identifier
  204. *
  205. * @param string Variable identifier, prefixed by hash name eg post.foo.bar
  206. * @return boolean
  207. */
  208. public static function has($identifier)
  209. {
  210. list($hash, $keys) = self::_parseIdentifier($identifier);
  211. foreach($keys as $key)
  212. {
  213. if(isset($GLOBALS['_'.$hash]) && array_key_exists($key, $GLOBALS['_'.$hash])) {
  214. return true;
  215. }
  216. }
  217. return false;
  218. }
  219. /**
  220. * Get the POST or PUT raw content information
  221. *
  222. * The raw post data is not available with enctype="multipart/form-data".
  223. *
  224. * @param string The content data to return. Can be 'type' or 'data'.
  225. * If not set, all the data will be returned.
  226. * @return array An associative array with the content data. Valid keys are
  227. * 'type' and 'data'
  228. */
  229. public static function content($key = null)
  230. {
  231. $result = '';
  232. if (!isset(self::$_content) && isset($_SERVER['CONTENT_TYPE']))
  233. {
  234. $type = $_SERVER['CONTENT_TYPE'];
  235. // strip parameters from content-type like "; charset=UTF-8"
  236. if (is_string($type))
  237. {
  238. if (preg_match('/^([^,\;]*)/', $type, $matches)) {
  239. $type = $matches[1];
  240. }
  241. }
  242. self::$_content['type'] = $type;
  243. $data = '';
  244. if (isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > 0)
  245. {
  246. $input = fopen('php://input', 'r');
  247. while ($chunk = fread($input, 1024)) {
  248. $data .= $chunk;
  249. }
  250. fclose($input);
  251. }
  252. self::$_content['data'] = $data;
  253. }
  254. return isset($key) ? self::$_content[$key] : self::$_content;
  255. }
  256. /**
  257. * Get the accept request information
  258. *
  259. * @param string The accept data to return. Can be 'format', 'encoding' or 'language'.
  260. * If not set, all the accept data will be returned.
  261. * @return array An associative array with the content data. Valid keys are
  262. * 'format', 'encoding' and 'language'
  263. */
  264. public static function accept($type = null)
  265. {
  266. if (!isset(self::$_accept) && isset($_SERVER['HTTP_ACCEPT']))
  267. {
  268. $accept = KRequest::get('server.HTTP_ACCEPT', 'string');
  269. self::$_accept['format'] = self::_parseAccept($accept);
  270. if (isset($_SERVER['HTTP_ACCEPT_ENCODING']))
  271. {
  272. $accept = KRequest::get('server.HTTP_ACCEPT_ENCODING', 'string');
  273. self::$_accept['encoding'] = self::_parseAccept($accept);
  274. }
  275. if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))
  276. {
  277. $accept = KRequest::get('server.HTTP_ACCEPT_LANGUAGE', 'string');
  278. self::$_accept['language'] = self::_parseAccept($accept);
  279. }
  280. }
  281. return $type ? self::$_accept[$type] : self::$_accept;
  282. }
  283. /**
  284. * Returns the client information doing the request
  285. *
  286. * @return string $_SERVER['HTTP_USER_AGENT'] or an empty string if it's not supplied in the request
  287. */
  288. public static function client()
  289. {
  290. return isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
  291. }
  292. /**
  293. * Returns the HTTP referrer.
  294. *
  295. * 'referer' a commonly used misspelling word for 'referrer'
  296. * @see http://en.wikipedia.org/wiki/HTTP_referrer
  297. *
  298. * @param boolean Only allow internal url's
  299. * @return KHttpUrl A KHttpUrl object
  300. */
  301. public static function referrer($isInternal = true)
  302. {
  303. if(!isset(self::$_referrer))
  304. {
  305. if($referrer = KRequest::get('server.HTTP_REFERER', 'url'))
  306. {
  307. self::$_referrer = KService::get('koowa:http.url', array('url' => $referrer));
  308. if($isInternal)
  309. {
  310. if(!KService::get('koowa:filter.internalurl')->validate((string)self::$_referrer)) {
  311. return null;
  312. }
  313. }
  314. }
  315. }
  316. return self::$_referrer;
  317. }
  318. /**
  319. * Return the URI of the request regardless of the server
  320. *
  321. * @return KHttpUrl A KHttpUri object
  322. */
  323. public static function url()
  324. {
  325. if(!isset(self::$_url))
  326. {
  327. $url = self::scheme().'://';
  328. if (PHP_SAPI !== 'cli')
  329. {
  330. /*
  331. * Since we are assigning the URI from the server variables, we first need
  332. * to determine if we are running on apache or IIS. If PHP_SELF and REQUEST_URI
  333. * are present, we will assume we are running on apache.
  334. */
  335. if (!empty ($_SERVER['PHP_SELF']) && !empty ($_SERVER['REQUEST_URI']))
  336. {
  337. /*
  338. * To build the entire URI we need to prepend the protocol, and the http host
  339. * to the URI string.
  340. */
  341. $url .= $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
  342. /*
  343. * Since we do not have REQUEST_URI to work with, we will assume we are
  344. * running on IIS and will therefore need to work some magic with the SCRIPT_NAME and
  345. * QUERY_STRING environment variables.
  346. */
  347. }
  348. else
  349. {
  350. // IIS uses the SCRIPT_NAME variable instead of a REQUEST_URI variable
  351. $url .= $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'];
  352. // If the query string exists append it to the URI string
  353. if (isset($_SERVER['QUERY_STRING']) && !empty($_SERVER['QUERY_STRING'])) {
  354. $url .= '?' . $_SERVER['QUERY_STRING'];
  355. }
  356. }
  357. }
  358. else $url .= 'koowa';
  359. // Sanitize the url since we can't trust the server var
  360. $url = KService::get('koowa:filter.url')->sanitize($url);
  361. // Create the URI object
  362. self::$_url = KService::get('koowa:http.url', array('url' => $url));
  363. }
  364. return self::$_url;
  365. }
  366. /**
  367. * Returns the base path of the request.
  368. *
  369. * @return object A KHttpUrl object
  370. */
  371. public static function base()
  372. {
  373. if(!isset(self::$_base))
  374. {
  375. // Get the base request path
  376. if (strpos(PHP_SAPI, 'cgi') !== false && !ini_get('cgi.fix_pathinfo') && !empty($_SERVER['REQUEST_URI']))
  377. {
  378. // PHP-CGI on Apache with "cgi.fix_pathinfo = 0"
  379. // We don't have user-supplied PATH_INFO in PHP_SELF
  380. $path = $_SERVER['PHP_SELF'];
  381. }
  382. else $path = $_SERVER['SCRIPT_NAME'];
  383. $path = rtrim(dirname($path), '/\\');
  384. // Sanitize the url since we can't trust the server var
  385. $path = KService::get('koowa:filter.url')->sanitize($path);
  386. self::$_base = KService::get('koowa:http.url', array('url' => $path));
  387. }
  388. return self::$_base;
  389. }
  390. /**
  391. * Returns the root path of the request.
  392. *
  393. * In most case this value will be the same as KRequest::base however it can be
  394. * changed by pushing in a different value
  395. *
  396. * @return object A KHttpUrl object
  397. */
  398. public static function root($path = null)
  399. {
  400. if(!is_null($path))
  401. {
  402. if(!$path instanceof KhttpUrl) {
  403. $path = KService::get('koowa:http.url', array('url' => $path));
  404. }
  405. self::$_root = $path;
  406. }
  407. if(is_null(self::$_root)) {
  408. self::$_root = self::$_base;
  409. }
  410. return self::$_root;
  411. }
  412. /**
  413. * Returns the current request scheme, based on $_SERVER['https']. In CLI
  414. * mode, 'cli' will be returned.
  415. *
  416. * @return string
  417. */
  418. public static function scheme()
  419. {
  420. $scheme = 'cli';
  421. if (PHP_SAPI !== 'cli')
  422. {
  423. $scheme = 'http';
  424. if (isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off')) {
  425. $scheme = 'https';
  426. }
  427. }
  428. return $scheme;
  429. }
  430. /**
  431. * Return the protocal based on $_SERVER['SERVER_PROTOCOL']
  432. *
  433. * @return string
  434. */
  435. public static function protocol()
  436. {
  437. return $_SERVER['SERVER_PROTOCOL'];
  438. }
  439. /**
  440. * Returns current request method.
  441. *
  442. * @return string
  443. */
  444. public static function method()
  445. {
  446. $method = '';
  447. if(PHP_SAPI != 'cli')
  448. {
  449. $method = strtoupper($_SERVER['REQUEST_METHOD']);
  450. if($method == 'POST')
  451. {
  452. if(isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
  453. $method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
  454. }
  455. if(self::has('post._method')) {
  456. $method = strtoupper(self::get('post._method', 'cmd'));
  457. }
  458. }
  459. }
  460. return $method;
  461. }
  462. /**
  463. * Return the current request transport type.
  464. *
  465. * @return string
  466. */
  467. public static function type()
  468. {
  469. $type = 'HTTP';
  470. if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
  471. $type = 'AJAX';
  472. }
  473. if( isset($_SERVER['HTTP_X_FLASH_VERSION'])) {
  474. $type = 'FLASH';
  475. }
  476. if(preg_match('/^(Shockwave|Adobe) Flash/', KRequest::client()) == 1) {
  477. $type = 'FLASH';
  478. }
  479. return $type;
  480. }
  481. /**
  482. * Return the request token
  483. *
  484. * @return string The request token or NULL if no token could be found
  485. */
  486. public static function token()
  487. {
  488. $token = null;
  489. if(self::has('server.HTTP_X_TOKEN')) {
  490. $token = self::get('server.HTTP_X_TOKEN', 'md5');
  491. }
  492. if(self::has('request._token')) {
  493. $token = self::get('request._token', 'md5');
  494. }
  495. return $token;
  496. }
  497. /**
  498. * Return the request format
  499. *
  500. * This function tries to find the format by inspecting the accept header,
  501. * only if one accept type is specified the format will be parsed from it,
  502. * otherwise the path extension or the 'format' request variable is used.
  503. *
  504. * @return string The request format or NULL if no format could be found
  505. */
  506. public static function format()
  507. {
  508. $format = null;
  509. if(count(self::accept('format')) == 1)
  510. {
  511. $mime = explode('/', key(self::accept('format')));
  512. $format = $mime[1];
  513. if($pos = strpos($format, '+')) {
  514. $format = substr($format, 0, $pos);
  515. }
  516. //Format cannot be *
  517. if($format == '*') {
  518. $format = null;
  519. }
  520. }
  521. if(self::has('request.format')) {
  522. $format = self::get('request.format', 'word');
  523. }
  524. return $format;
  525. }
  526. /**
  527. * Parse the variable identifier
  528. *
  529. * @param string Variable identifier
  530. * @return array 0 => hash, 1 => parts
  531. */
  532. protected static function _parseIdentifier($identifier)
  533. {
  534. $parts = array();
  535. $hash = $identifier;
  536. // Validate the variable format
  537. if(strpos($identifier, '.') !== false)
  538. {
  539. // Split the variable name into it's parts
  540. $parts = explode('.', $identifier);
  541. // Validate the hash name
  542. $hash = array_shift($parts);
  543. }
  544. $hash = strtoupper($hash);
  545. return array($hash, $parts);
  546. }
  547. /**
  548. * Parses an accept header and returns an array (type => quality) of the
  549. * accepted types, ordered by quality.
  550. *
  551. * @param string header to parse
  552. * @param array default values
  553. * @return array
  554. */
  555. protected static function _parseAccept( $accept, array $defaults = NULL)
  556. {
  557. if (!empty($accept))
  558. {
  559. // Get all of the types
  560. $types = explode(',', $accept);
  561. foreach ($types as $type)
  562. {
  563. // Split the type into parts
  564. $parts = explode(';', $type);
  565. // Make the type only the MIME
  566. $type = trim(array_shift($parts));
  567. // Default quality is 1.0
  568. $options = array('quality' => 1.0);
  569. foreach ($parts as $part)
  570. {
  571. // Prevent undefined $value notice below
  572. if (strpos($part, '=') === FALSE) {
  573. continue;
  574. }
  575. // Separate the key and value
  576. list ($key, $value) = explode('=', trim($part));
  577. switch ($key)
  578. {
  579. case 'q' : $options['quality'] = (float) trim($value); break;
  580. case 'version' : $options['version'] = (float) trim($value); break;
  581. }
  582. }
  583. // Add the accept type and quality
  584. $defaults[$type] = $options;
  585. }
  586. }
  587. // Make sure that accepts is an array
  588. $accepts = (array) $defaults;
  589. // Order by quality
  590. arsort($accepts);
  591. return $accepts;
  592. }
  593. /**
  594. * Strips slashes recursively on an array
  595. *
  596. * @param array Array of (nested arrays of) strings
  597. * @return array The input array with stripshlashes applied to it
  598. */
  599. protected static function _stripSlashes( $value )
  600. {
  601. if(!is_object($value)) {
  602. $value = is_array( $value ) ? array_map( array( 'KRequest', '_stripSlashes' ), $value ) : stripslashes( $value );
  603. }
  604. return $value;
  605. }
  606. }