PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Http/Request.php

https://github.com/telkins/zf2
PHP | 549 lines | 274 code | 61 blank | 214 comment | 31 complexity | ce952ee543fc8322f61112962a043314 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Http;
  10. use Zend\Stdlib\Parameters;
  11. use Zend\Stdlib\ParametersInterface;
  12. use Zend\Stdlib\RequestInterface;
  13. use Zend\Uri\Exception as UriException;
  14. use Zend\Uri\Http as HttpUri;
  15. /**
  16. * HTTP Request
  17. *
  18. * @link http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5
  19. */
  20. class Request extends AbstractMessage implements RequestInterface
  21. {
  22. /**#@+
  23. * @const string METHOD constant names
  24. */
  25. const METHOD_OPTIONS = 'OPTIONS';
  26. const METHOD_GET = 'GET';
  27. const METHOD_HEAD = 'HEAD';
  28. const METHOD_POST = 'POST';
  29. const METHOD_PUT = 'PUT';
  30. const METHOD_DELETE = 'DELETE';
  31. const METHOD_TRACE = 'TRACE';
  32. const METHOD_CONNECT = 'CONNECT';
  33. const METHOD_PATCH = 'PATCH';
  34. const METHOD_PROPFIND = 'PROPFIND';
  35. /**#@-*/
  36. /**
  37. * @var string
  38. */
  39. protected $method = self::METHOD_GET;
  40. /**
  41. * @var bool
  42. */
  43. protected $allowCustomMethods = true;
  44. /**
  45. * @var string|HttpUri
  46. */
  47. protected $uri = null;
  48. /**
  49. * @var ParametersInterface
  50. */
  51. protected $queryParams = null;
  52. /**
  53. * @var ParametersInterface
  54. */
  55. protected $postParams = null;
  56. /**
  57. * @var ParametersInterface
  58. */
  59. protected $fileParams = null;
  60. /**
  61. * A factory that produces a Request object from a well-formed Http Request string
  62. *
  63. * @param string $string
  64. * @param bool $allowCustomMethods
  65. * @throws Exception\InvalidArgumentException
  66. * @return Request
  67. */
  68. public static function fromString($string, $allowCustomMethods = true)
  69. {
  70. /** @var Request $request */
  71. $request = new static();
  72. $request->setAllowCustomMethods($allowCustomMethods);
  73. $lines = explode("\r\n", $string);
  74. // first line must be Method/Uri/Version string
  75. $matches = null;
  76. $methods = $allowCustomMethods
  77. ? '[\w-]+'
  78. : implode(
  79. '|',
  80. array(
  81. self::METHOD_OPTIONS,
  82. self::METHOD_GET,
  83. self::METHOD_HEAD,
  84. self::METHOD_POST,
  85. self::METHOD_PUT,
  86. self::METHOD_DELETE,
  87. self::METHOD_TRACE,
  88. self::METHOD_CONNECT,
  89. self::METHOD_PATCH
  90. )
  91. );
  92. $regex = '#^(?P<method>' . $methods . ')\s(?P<uri>[^ ]*)(?:\sHTTP\/(?P<version>\d+\.\d+)){0,1}#';
  93. $firstLine = array_shift($lines);
  94. if (!preg_match($regex, $firstLine, $matches)) {
  95. throw new Exception\InvalidArgumentException(
  96. 'A valid request line was not found in the provided string'
  97. );
  98. }
  99. $request->setMethod($matches['method']);
  100. $request->setUri($matches['uri']);
  101. $parsedUri = parse_url($matches['uri']);
  102. if (array_key_exists('query', $parsedUri)) {
  103. $parsedQuery = array();
  104. parse_str($parsedUri['query'], $parsedQuery);
  105. $request->setQuery(new Parameters($parsedQuery));
  106. }
  107. if (isset($matches['version'])) {
  108. $request->setVersion($matches['version']);
  109. }
  110. if (count($lines) == 0) {
  111. return $request;
  112. }
  113. $isHeader = true;
  114. $headers = $rawBody = array();
  115. while ($lines) {
  116. $nextLine = array_shift($lines);
  117. if ($nextLine == '') {
  118. $isHeader = false;
  119. continue;
  120. }
  121. if ($isHeader) {
  122. $headers[] = $nextLine;
  123. } else {
  124. $rawBody[] = $nextLine;
  125. }
  126. }
  127. if ($headers) {
  128. $request->headers = implode("\r\n", $headers);
  129. }
  130. if ($rawBody) {
  131. $request->setContent(implode("\r\n", $rawBody));
  132. }
  133. return $request;
  134. }
  135. /**
  136. * Set the method for this request
  137. *
  138. * @param string $method
  139. * @return Request
  140. * @throws Exception\InvalidArgumentException
  141. */
  142. public function setMethod($method)
  143. {
  144. $method = strtoupper($method);
  145. if (!defined('static::METHOD_' . $method) && ! $this->getAllowCustomMethods()) {
  146. throw new Exception\InvalidArgumentException('Invalid HTTP method passed');
  147. }
  148. $this->method = $method;
  149. return $this;
  150. }
  151. /**
  152. * Return the method for this request
  153. *
  154. * @return string
  155. */
  156. public function getMethod()
  157. {
  158. return $this->method;
  159. }
  160. /**
  161. * Set the URI/URL for this request, this can be a string or an instance of Zend\Uri\Http
  162. *
  163. * @throws Exception\InvalidArgumentException
  164. * @param string|HttpUri $uri
  165. * @return Request
  166. */
  167. public function setUri($uri)
  168. {
  169. if (is_string($uri)) {
  170. try {
  171. $uri = new HttpUri($uri);
  172. } catch (UriException\InvalidUriPartException $e) {
  173. throw new Exception\InvalidArgumentException(
  174. sprintf('Invalid URI passed as string (%s)', (string) $uri),
  175. $e->getCode(),
  176. $e
  177. );
  178. }
  179. } elseif (!($uri instanceof HttpUri)) {
  180. throw new Exception\InvalidArgumentException(
  181. 'URI must be an instance of Zend\Uri\Http or a string'
  182. );
  183. }
  184. $this->uri = $uri;
  185. return $this;
  186. }
  187. /**
  188. * Return the URI for this request object
  189. *
  190. * @return HttpUri
  191. */
  192. public function getUri()
  193. {
  194. if ($this->uri === null || is_string($this->uri)) {
  195. $this->uri = new HttpUri($this->uri);
  196. }
  197. return $this->uri;
  198. }
  199. /**
  200. * Return the URI for this request object as a string
  201. *
  202. * @return string
  203. */
  204. public function getUriString()
  205. {
  206. if ($this->uri instanceof HttpUri) {
  207. return $this->uri->toString();
  208. }
  209. return $this->uri;
  210. }
  211. /**
  212. * Provide an alternate Parameter Container implementation for query parameters in this object,
  213. * (this is NOT the primary API for value setting, for that see getQuery())
  214. *
  215. * @param \Zend\Stdlib\ParametersInterface $query
  216. * @return Request
  217. */
  218. public function setQuery(ParametersInterface $query)
  219. {
  220. $this->queryParams = $query;
  221. return $this;
  222. }
  223. /**
  224. * Return the parameter container responsible for query parameters or a single query parameter
  225. *
  226. * @param string|null $name Parameter name to retrieve, or null to get the whole container.
  227. * @param mixed|null $default Default value to use when the parameter is missing.
  228. * @return \Zend\Stdlib\ParametersInterface|mixed
  229. */
  230. public function getQuery($name = null, $default = null)
  231. {
  232. if ($this->queryParams === null) {
  233. $this->queryParams = new Parameters();
  234. }
  235. if ($name === null) {
  236. return $this->queryParams;
  237. }
  238. return $this->queryParams->get($name, $default);
  239. }
  240. /**
  241. * Provide an alternate Parameter Container implementation for post parameters in this object,
  242. * (this is NOT the primary API for value setting, for that see getPost())
  243. *
  244. * @param \Zend\Stdlib\ParametersInterface $post
  245. * @return Request
  246. */
  247. public function setPost(ParametersInterface $post)
  248. {
  249. $this->postParams = $post;
  250. return $this;
  251. }
  252. /**
  253. * Return the parameter container responsible for post parameters or a single post parameter.
  254. *
  255. * @param string|null $name Parameter name to retrieve, or null to get the whole container.
  256. * @param mixed|null $default Default value to use when the parameter is missing.
  257. * @return \Zend\Stdlib\ParametersInterface|mixed
  258. */
  259. public function getPost($name = null, $default = null)
  260. {
  261. if ($this->postParams === null) {
  262. $this->postParams = new Parameters();
  263. }
  264. if ($name === null) {
  265. return $this->postParams;
  266. }
  267. return $this->postParams->get($name, $default);
  268. }
  269. /**
  270. * Return the Cookie header, this is the same as calling $request->getHeaders()->get('Cookie');
  271. *
  272. * @convenience $request->getHeaders()->get('Cookie');
  273. * @return Header\Cookie|bool
  274. */
  275. public function getCookie()
  276. {
  277. return $this->getHeaders()->get('Cookie');
  278. }
  279. /**
  280. * Provide an alternate Parameter Container implementation for file parameters in this object,
  281. * (this is NOT the primary API for value setting, for that see getFiles())
  282. *
  283. * @param ParametersInterface $files
  284. * @return Request
  285. */
  286. public function setFiles(ParametersInterface $files)
  287. {
  288. $this->fileParams = $files;
  289. return $this;
  290. }
  291. /**
  292. * Return the parameter container responsible for file parameters or a single file.
  293. *
  294. * @param string|null $name Parameter name to retrieve, or null to get the whole container.
  295. * @param mixed|null $default Default value to use when the parameter is missing.
  296. * @return ParametersInterface|mixed
  297. */
  298. public function getFiles($name = null, $default = null)
  299. {
  300. if ($this->fileParams === null) {
  301. $this->fileParams = new Parameters();
  302. }
  303. if ($name === null) {
  304. return $this->fileParams;
  305. }
  306. return $this->fileParams->get($name, $default);
  307. }
  308. /**
  309. * Return the header container responsible for headers or all headers of a certain name/type
  310. *
  311. * @see \Zend\Http\Headers::get()
  312. * @param string|null $name Header name to retrieve, or null to get the whole container.
  313. * @param mixed|null $default Default value to use when the requested header is missing.
  314. * @return \Zend\Http\Headers|bool|\Zend\Http\Header\HeaderInterface|\ArrayIterator
  315. */
  316. public function getHeaders($name = null, $default = false)
  317. {
  318. if ($this->headers === null || is_string($this->headers)) {
  319. // this is only here for fromString lazy loading
  320. $this->headers = (is_string($this->headers)) ? Headers::fromString($this->headers) : new Headers();
  321. }
  322. if ($name === null) {
  323. return $this->headers;
  324. }
  325. if ($this->headers->has($name)) {
  326. return $this->headers->get($name);
  327. }
  328. return $default;
  329. }
  330. /**
  331. * Get all headers of a certain name/type.
  332. *
  333. * @see Request::getHeaders()
  334. * @param string|null $name Header name to retrieve, or null to get the whole container.
  335. * @param mixed|null $default Default value to use when the requested header is missing.
  336. * @return \Zend\Http\Headers|bool|\Zend\Http\Header\HeaderInterface|\ArrayIterator
  337. */
  338. public function getHeader($name, $default = false)
  339. {
  340. return $this->getHeaders($name, $default);
  341. }
  342. /**
  343. * Is this an OPTIONS method request?
  344. *
  345. * @return bool
  346. */
  347. public function isOptions()
  348. {
  349. return ($this->method === self::METHOD_OPTIONS);
  350. }
  351. /**
  352. * Is this a PROPFIND method request?
  353. *
  354. * @return bool
  355. */
  356. public function isPropFind()
  357. {
  358. return ($this->method === self::METHOD_PROPFIND);
  359. }
  360. /**
  361. * Is this a GET method request?
  362. *
  363. * @return bool
  364. */
  365. public function isGet()
  366. {
  367. return ($this->method === self::METHOD_GET);
  368. }
  369. /**
  370. * Is this a HEAD method request?
  371. *
  372. * @return bool
  373. */
  374. public function isHead()
  375. {
  376. return ($this->method === self::METHOD_HEAD);
  377. }
  378. /**
  379. * Is this a POST method request?
  380. *
  381. * @return bool
  382. */
  383. public function isPost()
  384. {
  385. return ($this->method === self::METHOD_POST);
  386. }
  387. /**
  388. * Is this a PUT method request?
  389. *
  390. * @return bool
  391. */
  392. public function isPut()
  393. {
  394. return ($this->method === self::METHOD_PUT);
  395. }
  396. /**
  397. * Is this a DELETE method request?
  398. *
  399. * @return bool
  400. */
  401. public function isDelete()
  402. {
  403. return ($this->method === self::METHOD_DELETE);
  404. }
  405. /**
  406. * Is this a TRACE method request?
  407. *
  408. * @return bool
  409. */
  410. public function isTrace()
  411. {
  412. return ($this->method === self::METHOD_TRACE);
  413. }
  414. /**
  415. * Is this a CONNECT method request?
  416. *
  417. * @return bool
  418. */
  419. public function isConnect()
  420. {
  421. return ($this->method === self::METHOD_CONNECT);
  422. }
  423. /**
  424. * Is this a PATCH method request?
  425. *
  426. * @return bool
  427. */
  428. public function isPatch()
  429. {
  430. return ($this->method === self::METHOD_PATCH);
  431. }
  432. /**
  433. * Is the request a Javascript XMLHttpRequest?
  434. *
  435. * Should work with Prototype/Script.aculo.us, possibly others.
  436. *
  437. * @return bool
  438. */
  439. public function isXmlHttpRequest()
  440. {
  441. $header = $this->getHeaders()->get('X_REQUESTED_WITH');
  442. return false !== $header && $header->getFieldValue() == 'XMLHttpRequest';
  443. }
  444. /**
  445. * Is this a Flash request?
  446. *
  447. * @return bool
  448. */
  449. public function isFlashRequest()
  450. {
  451. $header = $this->getHeaders()->get('USER_AGENT');
  452. return false !== $header && stristr($header->getFieldValue(), ' flash');
  453. }
  454. /**
  455. * Return the formatted request line (first line) for this http request
  456. *
  457. * @return string
  458. */
  459. public function renderRequestLine()
  460. {
  461. return $this->method . ' ' . (string) $this->uri . ' HTTP/' . $this->version;
  462. }
  463. /**
  464. * @return string
  465. */
  466. public function toString()
  467. {
  468. $str = $this->renderRequestLine() . "\r\n";
  469. $str .= $this->getHeaders()->toString();
  470. $str .= "\r\n";
  471. $str .= $this->getContent();
  472. return $str;
  473. }
  474. /**
  475. * @return boolean
  476. */
  477. public function getAllowCustomMethods()
  478. {
  479. return $this->allowCustomMethods;
  480. }
  481. /**
  482. * @param boolean $strictMethods
  483. */
  484. public function setAllowCustomMethods($strictMethods)
  485. {
  486. $this->allowCustomMethods = (bool) $strictMethods;
  487. }
  488. }