PageRenderTime 52ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/www/libs/nette-dev/Web/Uri.php

https://github.com/bazo/Mokuji
PHP | 438 lines | 180 code | 96 blank | 162 comment | 17 complexity | 61066eb1cd0f390dfce00d9f3288c111 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT
  1. <?php
  2. /**
  3. * Nette Framework
  4. *
  5. * @copyright Copyright (c) 2004, 2010 David Grudl
  6. * @license http://nettephp.com/license Nette license
  7. * @link http://nettephp.com
  8. * @category Nette
  9. * @package Nette\Web
  10. */
  11. /**
  12. * URI Syntax (RFC 3986).
  13. *
  14. * <pre>
  15. * http://user:password@nettephp.com:8042/en/manual.html?name=param#fragment
  16. * \__/^^^\_____________________________/\_____________/^\________/^\______/
  17. * | | | | |
  18. * scheme authority path query fragment
  19. * </pre>
  20. *
  21. * - authority: [user[:password]@]host[:port]
  22. * - hostUri: http://user:password@nettephp.com:8042
  23. *
  24. * @copyright Copyright (c) 2004, 2010 David Grudl
  25. * @package Nette\Web
  26. *
  27. * @property string $scheme
  28. * @property string $user
  29. * @property string $password
  30. * @property string $host
  31. * @property string $port
  32. * @property string $path
  33. * @property string $query
  34. * @property string $fragment
  35. * @property-read string $absoluteUri
  36. * @property-read string $authority
  37. * @property-read string $hostUri
  38. */
  39. class Uri extends FreezableObject
  40. {
  41. /** @var array */
  42. public static $defaultPorts = array(
  43. 'http' => 80,
  44. 'https' => 443,
  45. 'ftp' => 21,
  46. 'news' => 119,
  47. 'nntp' => 119,
  48. );
  49. /** @var string */
  50. private $scheme = '';
  51. /** @var string */
  52. private $user = '';
  53. /** @var string */
  54. private $pass = '';
  55. /** @var string */
  56. private $host = '';
  57. /** @var int */
  58. private $port = NULL;
  59. /** @var string */
  60. private $path = '';
  61. /** @var string */
  62. private $query = '';
  63. /** @var string */
  64. private $fragment = '';
  65. /**
  66. * @param string URL
  67. * @throws InvalidArgumentException
  68. */
  69. public function __construct($uri = NULL)
  70. {
  71. if (is_string($uri)) {
  72. $parts = @parse_url($uri); // intentionally @
  73. if ($parts === FALSE) {
  74. throw new InvalidArgumentException("Malformed or unsupported URI '$uri'.");
  75. }
  76. foreach ($parts as $key => $val) {
  77. $this->$key = $val;
  78. }
  79. if (!$this->port && isset(self::$defaultPorts[$this->scheme])) {
  80. $this->port = self::$defaultPorts[$this->scheme];
  81. }
  82. } elseif ($uri instanceof self) {
  83. foreach ($this as $key => $val) {
  84. $this->$key = $uri->$key;
  85. }
  86. }
  87. }
  88. /**
  89. * Sets the scheme part of URI.
  90. * @param string
  91. * @return Uri provides a fluent interface
  92. */
  93. public function setScheme($value)
  94. {
  95. $this->updating();
  96. $this->scheme = (string) $value;
  97. return $this;
  98. }
  99. /**
  100. * Returns the scheme part of URI.
  101. * @return string
  102. */
  103. public function getScheme()
  104. {
  105. return $this->scheme;
  106. }
  107. /**
  108. * Sets the user name part of URI.
  109. * @param string
  110. * @return Uri provides a fluent interface
  111. */
  112. public function setUser($value)
  113. {
  114. $this->updating();
  115. $this->user = (string) $value;
  116. return $this;
  117. }
  118. /**
  119. * Returns the user name part of URI.
  120. * @return string
  121. */
  122. public function getUser()
  123. {
  124. return $this->user;
  125. }
  126. /**
  127. * Sets the password part of URI.
  128. * @param string
  129. * @return Uri provides a fluent interface
  130. */
  131. public function setPassword($value)
  132. {
  133. $this->updating();
  134. $this->pass = (string) $value;
  135. return $this;
  136. }
  137. /**
  138. * Returns the password part of URI.
  139. * @return string
  140. */
  141. public function getPassword()
  142. {
  143. return $this->pass;
  144. }
  145. /**
  146. * Sets the host part of URI.
  147. * @param string
  148. * @return Uri provides a fluent interface
  149. */
  150. public function setHost($value)
  151. {
  152. $this->updating();
  153. $this->host = (string) $value;
  154. return $this;
  155. }
  156. /**
  157. * Returns the host part of URI.
  158. * @return string
  159. */
  160. public function getHost()
  161. {
  162. return $this->host;
  163. }
  164. /**
  165. * Sets the port part of URI.
  166. * @param string
  167. * @return Uri provides a fluent interface
  168. */
  169. public function setPort($value)
  170. {
  171. $this->updating();
  172. $this->port = (int) $value;
  173. return $this;
  174. }
  175. /**
  176. * Returns the port part of URI.
  177. * @return string
  178. */
  179. public function getPort()
  180. {
  181. return $this->port;
  182. }
  183. /**
  184. * Sets the path part of URI.
  185. * @param string
  186. * @return Uri provides a fluent interface
  187. */
  188. public function setPath($value)
  189. {
  190. $this->updating();
  191. $this->path = (string) $value;
  192. return $this;
  193. }
  194. /**
  195. * Returns the path part of URI.
  196. * @return string
  197. */
  198. public function getPath()
  199. {
  200. return $this->path;
  201. }
  202. /**
  203. * Sets the query part of URI.
  204. * @param string|array
  205. * @return Uri provides a fluent interface
  206. */
  207. public function setQuery($value)
  208. {
  209. $this->updating();
  210. $this->query = (string) (is_array($value) ? http_build_query($value, '', '&') : $value);
  211. return $this;
  212. }
  213. /**
  214. * Appends the query part of URI.
  215. * @param string|array
  216. * @return void
  217. */
  218. public function appendQuery($value)
  219. {
  220. $this->updating();
  221. $value = (string) (is_array($value) ? http_build_query($value, '', '&') : $value);
  222. $this->query .= ($this->query === '' || $value === '') ? $value : '&' . $value;
  223. }
  224. /**
  225. * Returns the query part of URI.
  226. * @return string
  227. */
  228. public function getQuery()
  229. {
  230. return $this->query;
  231. }
  232. /**
  233. * Sets the fragment part of URI.
  234. * @param string
  235. * @return Uri provides a fluent interface
  236. */
  237. public function setFragment($value)
  238. {
  239. $this->updating();
  240. $this->fragment = (string) $value;
  241. return $this;
  242. }
  243. /**
  244. * Returns the fragment part of URI.
  245. * @return string
  246. */
  247. public function getFragment()
  248. {
  249. return $this->fragment;
  250. }
  251. /**
  252. * Returns the entire URI including query string and fragment.
  253. * @return string
  254. */
  255. public function getAbsoluteUri()
  256. {
  257. return $this->scheme . '://' . $this->getAuthority() . $this->path
  258. . ($this->query === '' ? '' : '?' . $this->query)
  259. . ($this->fragment === '' ? '' : '#' . $this->fragment);
  260. }
  261. /**
  262. * Returns the [user[:pass]@]host[:port] part of URI.
  263. * @return string
  264. */
  265. public function getAuthority()
  266. {
  267. $authority = $this->host;
  268. if ($this->port && isset(self::$defaultPorts[$this->scheme]) && $this->port !== self::$defaultPorts[$this->scheme]) {
  269. $authority .= ':' . $this->port;
  270. }
  271. if ($this->user !== '' && $this->scheme !== 'http' && $this->scheme !== 'https') {
  272. $authority = $this->user . ($this->pass === '' ? '' : ':' . $this->pass) . '@' . $authority;
  273. }
  274. return $authority;
  275. }
  276. /**
  277. * Returns the scheme and authority part of URI.
  278. * @return string
  279. */
  280. public function getHostUri()
  281. {
  282. return $this->scheme . '://' . $this->getAuthority();
  283. }
  284. /**
  285. * URI comparsion (this object must be in canonical form).
  286. * @param string
  287. * @return bool
  288. */
  289. public function isEqual($uri)
  290. {
  291. // compare host + path
  292. $part = self::unescape(strtok($uri, '?#'), '%/');
  293. if (strncmp($part, '//', 2) === 0) { // absolute URI without scheme
  294. if ($part !== '//' . $this->getAuthority() . $this->path) return FALSE;
  295. } elseif (strncmp($part, '/', 1) === 0) { // absolute path
  296. if ($part !== $this->path) return FALSE;
  297. } else {
  298. if ($part !== $this->scheme . '://' . $this->getAuthority() . $this->path) return FALSE;
  299. }
  300. // compare query strings
  301. $part = self::unescape(strtr((string) strtok('?#'), '+', ' '), '%&;=+');
  302. return $part === $this->query;
  303. }
  304. /**
  305. * Transform to canonical form.
  306. * @return void
  307. */
  308. public function canonicalize()
  309. {
  310. $this->updating();
  311. $this->path = $this->path === '' ? '/' : self::unescape($this->path, '%/');
  312. $this->host = strtolower(rawurldecode($this->host));
  313. $this->query = self::unescape(strtr($this->query, '+', ' '), '%&;=+');
  314. }
  315. /**
  316. * @return string
  317. */
  318. public function __toString()
  319. {
  320. return $this->getAbsoluteUri();
  321. }
  322. /**
  323. * Similar to rawurldecode, but preserve reserved chars encoded.
  324. * @param string to decode
  325. * @param string reserved characters
  326. * @return string
  327. */
  328. public static function unescape($s, $reserved = '%;/?:@&=+$,')
  329. {
  330. // reserved (@see RFC 2396) = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
  331. // within a path segment, the characters "/", ";", "=", "?" are reserved
  332. // within a query component, the characters ";", "/", "?", ":", "@", "&", "=", "+", ",", "$" are reserved.
  333. preg_match_all('#(?<=%)[a-f0-9][a-f0-9]#i', $s, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
  334. foreach (array_reverse($matches) as $match) {
  335. $ch = chr(hexdec($match[0][0]));
  336. if (strpos($reserved, $ch) === FALSE) {
  337. $s = substr_replace($s, $ch, $match[0][1] - 1, 3);
  338. }
  339. }
  340. return $s;
  341. }
  342. }