PageRenderTime 29ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/web/vendor/nette/http/src/Http/Url.php

https://gitlab.com/adam.kvita/MI-VMM-SIFT
PHP | 505 lines | 228 code | 83 blank | 194 comment | 19 complexity | 1440e728086d762f64202ef4dba83ad2 MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the Nette Framework (https://nette.org)
  4. * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  5. */
  6. namespace Nette\Http;
  7. use Nette;
  8. /**
  9. * URI Syntax (RFC 3986).
  10. *
  11. * <pre>
  12. * scheme user password host port basePath relativeUrl
  13. * | | | | | | |
  14. * /--\ /--\ /------\ /-------\ /--\/--\/----------------------------\
  15. * http://john:x0y17575@nette.org:8042/en/manual.php?name=param#fragment <-- absoluteUrl
  16. * \__________________________/\____________/^\________/^\______/
  17. * | | | |
  18. * authority path query fragment
  19. * </pre>
  20. *
  21. * - authority: [user[:password]@]host[:port]
  22. * - hostUrl: http://user:password@nette.org:8042
  23. * - basePath: /en/ (everything before relative URI not including the script name)
  24. * - baseUrl: http://user:password@nette.org:8042/en/
  25. * - relativeUrl: manual.php
  26. *
  27. * @property string $scheme
  28. * @property string $user
  29. * @property string $password
  30. * @property string $host
  31. * @property int $port
  32. * @property string $path
  33. * @property string $query
  34. * @property string $fragment
  35. * @property-read string $absoluteUrl
  36. * @property-read string $authority
  37. * @property-read string $hostUrl
  38. * @property-read string $basePath
  39. * @property-read string $baseUrl
  40. * @property-read string $relativeUrl
  41. * @property-read array $queryParameters
  42. */
  43. class Url implements \JsonSerializable
  44. {
  45. use Nette\SmartObject;
  46. /** @var array */
  47. public static $defaultPorts = [
  48. 'http' => 80,
  49. 'https' => 443,
  50. 'ftp' => 21,
  51. 'news' => 119,
  52. 'nntp' => 119,
  53. ];
  54. /** @var string */
  55. private $scheme = '';
  56. /** @var string */
  57. private $user = '';
  58. /** @var string */
  59. private $password = '';
  60. /** @var string */
  61. private $host = '';
  62. /** @var int|NULL */
  63. private $port;
  64. /** @var string */
  65. private $path = '';
  66. /** @var array */
  67. private $query = [];
  68. /** @var string */
  69. private $fragment = '';
  70. /**
  71. * @param string|self
  72. * @throws Nette\InvalidArgumentException if URL is malformed
  73. */
  74. public function __construct($url = NULL)
  75. {
  76. if (is_string($url)) {
  77. $p = @parse_url($url); // @ - is escalated to exception
  78. if ($p === FALSE) {
  79. throw new Nette\InvalidArgumentException("Malformed or unsupported URI '$url'.");
  80. }
  81. $this->scheme = isset($p['scheme']) ? $p['scheme'] : '';
  82. $this->port = isset($p['port']) ? $p['port'] : NULL;
  83. $this->host = isset($p['host']) ? rawurldecode($p['host']) : '';
  84. $this->user = isset($p['user']) ? rawurldecode($p['user']) : '';
  85. $this->password = isset($p['pass']) ? rawurldecode($p['pass']) : '';
  86. $this->setPath(isset($p['path']) ? $p['path'] : '');
  87. $this->setQuery(isset($p['query']) ? $p['query'] : []);
  88. $this->fragment = isset($p['fragment']) ? rawurldecode($p['fragment']) : '';
  89. } elseif ($url instanceof self) {
  90. foreach ($this as $key => $val) {
  91. $this->$key = $url->$key;
  92. }
  93. }
  94. }
  95. /**
  96. * Sets the scheme part of URI.
  97. * @param string
  98. * @return self
  99. */
  100. public function setScheme($value)
  101. {
  102. $this->scheme = (string) $value;
  103. return $this;
  104. }
  105. /**
  106. * Returns the scheme part of URI.
  107. * @return string
  108. */
  109. public function getScheme()
  110. {
  111. return $this->scheme;
  112. }
  113. /**
  114. * Sets the user name part of URI.
  115. * @param string
  116. * @return self
  117. */
  118. public function setUser($value)
  119. {
  120. $this->user = (string) $value;
  121. return $this;
  122. }
  123. /**
  124. * Returns the user name part of URI.
  125. * @return string
  126. */
  127. public function getUser()
  128. {
  129. return $this->user;
  130. }
  131. /**
  132. * Sets the password part of URI.
  133. * @param string
  134. * @return self
  135. */
  136. public function setPassword($value)
  137. {
  138. $this->password = (string) $value;
  139. return $this;
  140. }
  141. /**
  142. * Returns the password part of URI.
  143. * @return string
  144. */
  145. public function getPassword()
  146. {
  147. return $this->password;
  148. }
  149. /**
  150. * Sets the host part of URI.
  151. * @param string
  152. * @return self
  153. */
  154. public function setHost($value)
  155. {
  156. $this->host = (string) $value;
  157. $this->setPath($this->path);
  158. return $this;
  159. }
  160. /**
  161. * Returns the host part of URI.
  162. * @return string
  163. */
  164. public function getHost()
  165. {
  166. return $this->host;
  167. }
  168. /**
  169. * Sets the port part of URI.
  170. * @param int
  171. * @return self
  172. */
  173. public function setPort($value)
  174. {
  175. $this->port = (int) $value;
  176. return $this;
  177. }
  178. /**
  179. * Returns the port part of URI.
  180. * @return int|NULL
  181. */
  182. public function getPort()
  183. {
  184. return $this->port
  185. ? $this->port
  186. : (isset(self::$defaultPorts[$this->scheme]) ? self::$defaultPorts[$this->scheme] : NULL);
  187. }
  188. /**
  189. * Sets the path part of URI.
  190. * @param string
  191. * @return self
  192. */
  193. public function setPath($value)
  194. {
  195. $this->path = (string) $value;
  196. if ($this->host && substr($this->path, 0, 1) !== '/') {
  197. $this->path = '/' . $this->path;
  198. }
  199. return $this;
  200. }
  201. /**
  202. * Returns the path part of URI.
  203. * @return string
  204. */
  205. public function getPath()
  206. {
  207. return $this->path;
  208. }
  209. /**
  210. * Sets the query part of URI.
  211. * @param string|array
  212. * @return self
  213. */
  214. public function setQuery($value)
  215. {
  216. $this->query = is_array($value) ? $value : self::parseQuery($value);
  217. return $this;
  218. }
  219. /**
  220. * Appends the query part of URI.
  221. * @param string|array
  222. * @return self
  223. */
  224. public function appendQuery($value)
  225. {
  226. $this->query = is_array($value)
  227. ? $value + $this->query
  228. : self::parseQuery($this->getQuery() . '&' . $value);
  229. return $this;
  230. }
  231. /**
  232. * Returns the query part of URI.
  233. * @return string
  234. */
  235. public function getQuery()
  236. {
  237. return http_build_query($this->query, '', '&', PHP_QUERY_RFC3986);
  238. }
  239. /**
  240. * @return array
  241. */
  242. public function getQueryParameters()
  243. {
  244. return $this->query;
  245. }
  246. /**
  247. * @param string
  248. * @param mixed
  249. * @return mixed
  250. */
  251. public function getQueryParameter($name, $default = NULL)
  252. {
  253. return isset($this->query[$name]) ? $this->query[$name] : $default;
  254. }
  255. /**
  256. * @param string
  257. * @param mixed NULL unsets the parameter
  258. * @return self
  259. */
  260. public function setQueryParameter($name, $value)
  261. {
  262. $this->query[$name] = $value;
  263. return $this;
  264. }
  265. /**
  266. * Sets the fragment part of URI.
  267. * @param string
  268. * @return self
  269. */
  270. public function setFragment($value)
  271. {
  272. $this->fragment = (string) $value;
  273. return $this;
  274. }
  275. /**
  276. * Returns the fragment part of URI.
  277. * @return string
  278. */
  279. public function getFragment()
  280. {
  281. return $this->fragment;
  282. }
  283. /**
  284. * Returns the entire URI including query string and fragment.
  285. * @return string
  286. */
  287. public function getAbsoluteUrl()
  288. {
  289. return $this->getHostUrl() . $this->path
  290. . (($tmp = $this->getQuery()) ? '?' . $tmp : '')
  291. . ($this->fragment === '' ? '' : '#' . $this->fragment);
  292. }
  293. /**
  294. * Returns the [user[:pass]@]host[:port] part of URI.
  295. * @return string
  296. */
  297. public function getAuthority()
  298. {
  299. return $this->host === ''
  300. ? ''
  301. : ($this->user !== '' && $this->scheme !== 'http' && $this->scheme !== 'https'
  302. ? rawurlencode($this->user) . ($this->password === '' ? '' : ':' . rawurlencode($this->password)) . '@'
  303. : '')
  304. . $this->host
  305. . ($this->port && (!isset(self::$defaultPorts[$this->scheme]) || $this->port !== self::$defaultPorts[$this->scheme])
  306. ? ':' . $this->port
  307. : '');
  308. }
  309. /**
  310. * Returns the scheme and authority part of URI.
  311. * @return string
  312. */
  313. public function getHostUrl()
  314. {
  315. return ($this->scheme ? $this->scheme . ':' : '')
  316. . (($authority = $this->getAuthority()) || $this->scheme ? '//' . $authority : '');
  317. }
  318. /**
  319. * Returns the base-path.
  320. * @return string
  321. */
  322. public function getBasePath()
  323. {
  324. $pos = strrpos($this->path, '/');
  325. return $pos === FALSE ? '' : substr($this->path, 0, $pos + 1);
  326. }
  327. /**
  328. * Returns the base-URI.
  329. * @return string
  330. */
  331. public function getBaseUrl()
  332. {
  333. return $this->getHostUrl() . $this->getBasePath();
  334. }
  335. /**
  336. * Returns the relative-URI.
  337. * @return string
  338. */
  339. public function getRelativeUrl()
  340. {
  341. return (string) substr($this->getAbsoluteUrl(), strlen($this->getBaseUrl()));
  342. }
  343. /**
  344. * URL comparison.
  345. * @param string|self
  346. * @return bool
  347. */
  348. public function isEqual($url)
  349. {
  350. $url = new self($url);
  351. $query = $url->query;
  352. ksort($query);
  353. $query2 = $this->query;
  354. ksort($query2);
  355. $http = in_array($this->scheme, ['http', 'https'], TRUE);
  356. return $url->scheme === $this->scheme
  357. && !strcasecmp($url->host, $this->host)
  358. && $url->getPort() === $this->getPort()
  359. && ($http || $url->user === $this->user)
  360. && ($http || $url->password === $this->password)
  361. && self::unescape($url->path, '%/') === self::unescape($this->path, '%/')
  362. && $query === $query2
  363. && $url->fragment === $this->fragment;
  364. }
  365. /**
  366. * Transforms URL to canonical form.
  367. * @return self
  368. */
  369. public function canonicalize()
  370. {
  371. $this->path = preg_replace_callback(
  372. '#[^!$&\'()*+,/:;=@%]+#',
  373. function ($m) { return rawurlencode($m[0]); },
  374. self::unescape($this->path, '%/')
  375. );
  376. $this->host = strtolower($this->host);
  377. return $this;
  378. }
  379. /**
  380. * @return string
  381. */
  382. public function __toString()
  383. {
  384. return $this->getAbsoluteUrl();
  385. }
  386. /**
  387. * @return string
  388. */
  389. public function jsonSerialize()
  390. {
  391. return $this->getAbsoluteUrl();
  392. }
  393. /**
  394. * Similar to rawurldecode, but preserves reserved chars encoded.
  395. * @param string to decode
  396. * @param string reserved characters
  397. * @return string
  398. */
  399. public static function unescape($s, $reserved = '%;/?:@&=+$,')
  400. {
  401. // reserved (@see RFC 2396) = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
  402. // within a path segment, the characters "/", ";", "=", "?" are reserved
  403. // within a query component, the characters ";", "/", "?", ":", "@", "&", "=", "+", ",", "$" are reserved.
  404. if ($reserved !== '') {
  405. $s = preg_replace_callback(
  406. '#%(' . substr(chunk_split(bin2hex($reserved), 2, '|'), 0, -1) . ')#i',
  407. function ($m) { return '%25' . strtoupper($m[1]); },
  408. $s
  409. );
  410. }
  411. return rawurldecode($s);
  412. }
  413. /**
  414. * Parses query string.
  415. * @return array
  416. */
  417. public static function parseQuery($s)
  418. {
  419. parse_str($s, $res);
  420. return $res;
  421. }
  422. }