PluginProbe ʕ •ᴥ•ʔ
FAPI Member / 2.2.31
FAPI Member v2.2.31
2.2.33 2.2.32 trunk 1.9.47 2.1.18 2.2.24 2.2.25 2.2.26 2.2.28 2.2.29 2.2.30 2.2.31
fapi-member / libs / nette / http / src / Http / Url.php
fapi-member / libs / nette / http / src / Http Last commit date
Context.php 1 month ago FileUpload.php 1 month ago Helpers.php 1 month ago IRequest.php 1 month ago IResponse.php 1 month ago Request.php 1 month ago RequestFactory.php 1 month ago Response.php 1 month ago Session.php 1 month ago SessionSection.php 1 month ago Url.php 1 month ago UrlImmutable.php 1 month ago UrlScript.php 1 month ago UserStorage.php 1 month ago
Url.php
334 lines
1 <?php
2
3 /**
4 * This file is part of the Nette Framework (https://nette.org)
5 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6 */
7 declare (strict_types=1);
8 namespace FapiMember\Library\Nette\Http;
9
10 use FapiMember\Library\Nette;
11 /**
12 * Mutable representation of a URL.
13 *
14 * <pre>
15 * scheme user password host port path query fragment
16 * | | | | | | | |
17 * /--\ /--\ /------\ /-------\ /--\/------------\ /--------\ /------\
18 * http://john:x0y17575@nette.org:8042/en/manual.php?name=param#fragment <-- absoluteUrl
19 * \______\__________________________/
20 * | |
21 * hostUrl authority
22 * </pre>
23 *
24 * @property string $scheme
25 * @property string $user
26 * @property string $password
27 * @property string $host
28 * @property int $port
29 * @property string $path
30 * @property string $query
31 * @property string $fragment
32 * @property-read string $absoluteUrl
33 * @property-read string $authority
34 * @property-read string $hostUrl
35 * @property-read string $basePath
36 * @property-read string $baseUrl
37 * @property-read string $relativeUrl
38 * @property-read array $queryParameters
39 */
40 class Url implements \JsonSerializable
41 {
42 use Nette\SmartObject;
43 /** @var array */
44 public static $defaultPorts = ['http' => 80, 'https' => 443, 'ftp' => 21];
45 /** @var string */
46 private $scheme = '';
47 /** @var string */
48 private $user = '';
49 /** @var string */
50 private $password = '';
51 /** @var string */
52 private $host = '';
53 /** @var int|null */
54 private $port;
55 /** @var string */
56 private $path = '';
57 /** @var array */
58 private $query = [];
59 /** @var string */
60 private $fragment = '';
61 /**
62 * @param string|self|UrlImmutable $url
63 * @throws Nette\InvalidArgumentException if URL is malformed
64 */
65 public function __construct($url = null)
66 {
67 if (is_string($url)) {
68 $p = @parse_url($url);
69 // @ - is escalated to exception
70 if ($p === \false) {
71 throw new Nette\InvalidArgumentException("Malformed or unsupported URI '{$url}'.");
72 }
73 $this->scheme = $p['scheme'] ?? '';
74 $this->port = $p['port'] ?? null;
75 $this->host = rawurldecode($p['host'] ?? '');
76 $this->user = rawurldecode($p['user'] ?? '');
77 $this->password = rawurldecode($p['pass'] ?? '');
78 $this->setPath($p['path'] ?? '');
79 $this->setQuery($p['query'] ?? []);
80 $this->fragment = rawurldecode($p['fragment'] ?? '');
81 } elseif ($url instanceof UrlImmutable || $url instanceof self) {
82 [$this->scheme, $this->user, $this->password, $this->host, $this->port, $this->path, $this->query, $this->fragment] = $url->export();
83 } elseif ($url !== null) {
84 throw new Nette\InvalidArgumentException();
85 }
86 }
87 /** @return static */
88 public function setScheme(string $scheme)
89 {
90 $this->scheme = $scheme;
91 return $this;
92 }
93 public function getScheme(): string
94 {
95 return $this->scheme;
96 }
97 /** @return static */
98 public function setUser(string $user)
99 {
100 $this->user = $user;
101 return $this;
102 }
103 public function getUser(): string
104 {
105 return $this->user;
106 }
107 /** @return static */
108 public function setPassword(string $password)
109 {
110 $this->password = $password;
111 return $this;
112 }
113 public function getPassword(): string
114 {
115 return $this->password;
116 }
117 /** @return static */
118 public function setHost(string $host)
119 {
120 $this->host = $host;
121 $this->setPath($this->path);
122 return $this;
123 }
124 public function getHost(): string
125 {
126 return $this->host;
127 }
128 /**
129 * Returns the part of domain.
130 */
131 public function getDomain(int $level = 2): string
132 {
133 $parts = ip2long($this->host) ? [$this->host] : explode('.', $this->host);
134 $parts = ($level >= 0) ? array_slice($parts, -$level) : array_slice($parts, 0, $level);
135 return implode('.', $parts);
136 }
137 /** @return static */
138 public function setPort(int $port)
139 {
140 $this->port = $port;
141 return $this;
142 }
143 public function getPort(): ?int
144 {
145 return $this->port ?: $this->getDefaultPort();
146 }
147 public function getDefaultPort(): ?int
148 {
149 return self::$defaultPorts[$this->scheme] ?? null;
150 }
151 /** @return static */
152 public function setPath(string $path)
153 {
154 $this->path = $path;
155 if ($this->host && substr($this->path, 0, 1) !== '/') {
156 $this->path = '/' . $this->path;
157 }
158 return $this;
159 }
160 public function getPath(): string
161 {
162 return $this->path;
163 }
164 /**
165 * @param string|array $value
166 * @return static
167 */
168 public function setQuery($query)
169 {
170 $this->query = is_array($query) ? $query : self::parseQuery($query);
171 return $this;
172 }
173 /**
174 * @param string|array $value
175 * @return static
176 */
177 public function appendQuery($query)
178 {
179 $this->query = is_array($query) ? $query + $this->query : self::parseQuery($this->getQuery() . '&' . $query);
180 return $this;
181 }
182 public function getQuery(): string
183 {
184 return http_build_query($this->query, '', '&', \PHP_QUERY_RFC3986);
185 }
186 public function getQueryParameters(): array
187 {
188 return $this->query;
189 }
190 /** @return mixed */
191 public function getQueryParameter(string $name)
192 {
193 if (func_num_args() > 1) {
194 trigger_error(__METHOD__ . '() parameter $default is deprecated, use operator ??', \E_USER_DEPRECATED);
195 }
196 return $this->query[$name] ?? null;
197 }
198 /**
199 * @param mixed $value null unsets the parameter
200 * @return static
201 */
202 public function setQueryParameter(string $name, $value)
203 {
204 $this->query[$name] = $value;
205 return $this;
206 }
207 /** @return static */
208 public function setFragment(string $fragment)
209 {
210 $this->fragment = $fragment;
211 return $this;
212 }
213 public function getFragment(): string
214 {
215 return $this->fragment;
216 }
217 public function getAbsoluteUrl(): string
218 {
219 return $this->getHostUrl() . $this->path . (($tmp = $this->getQuery()) ? '?' . $tmp : '') . (($this->fragment === '') ? '' : ('#' . $this->fragment));
220 }
221 /**
222 * Returns the [user[:pass]@]host[:port] part of URI.
223 */
224 public function getAuthority(): string
225 {
226 return ($this->host === '') ? '' : ((($this->user !== '') ? rawurlencode($this->user) . (($this->password === '') ? '' : (':' . rawurlencode($this->password))) . '@' : '') . $this->host . (($this->port && $this->port !== $this->getDefaultPort()) ? ':' . $this->port : ''));
227 }
228 /**
229 * Returns the scheme and authority part of URI.
230 */
231 public function getHostUrl(): string
232 {
233 return ($this->scheme ? $this->scheme . ':' : '') . ((($authority = $this->getAuthority()) !== '') ? '//' . $authority : '');
234 }
235 /** @deprecated use UrlScript::getBasePath() instead */
236 public function getBasePath(): string
237 {
238 $pos = strrpos($this->path, '/');
239 return ($pos === \false) ? '' : substr($this->path, 0, $pos + 1);
240 }
241 /** @deprecated use UrlScript::getBaseUrl() instead */
242 public function getBaseUrl(): string
243 {
244 return $this->getHostUrl() . $this->getBasePath();
245 }
246 /** @deprecated use UrlScript::getRelativeUrl() instead */
247 public function getRelativeUrl(): string
248 {
249 return substr($this->getAbsoluteUrl(), strlen($this->getBaseUrl()));
250 }
251 /**
252 * URL comparison.
253 * @param string|self $url
254 */
255 public function isEqual($url): bool
256 {
257 $url = new self($url);
258 $query = $url->query;
259 ksort($query);
260 $query2 = $this->query;
261 ksort($query2);
262 $host = rtrim($url->host, '.');
263 $host2 = rtrim($this->host, '.');
264 return $url->scheme === $this->scheme && (!strcasecmp($host, $host2) || self::idnHostToUnicode($host) === self::idnHostToUnicode($host2)) && $url->getPort() === $this->getPort() && $url->user === $this->user && $url->password === $this->password && self::unescape($url->path, '%/') === self::unescape($this->path, '%/') && $query === $query2 && $url->fragment === $this->fragment;
265 }
266 /**
267 * Transforms URL to canonical form.
268 * @return static
269 * @deprecated
270 */
271 public function canonicalize()
272 {
273 $this->path = preg_replace_callback('#[^!$&\'()*+,/:;=@%]+#', function (array $m): string {
274 return rawurlencode($m[0]);
275 }, self::unescape($this->path, '%/'));
276 $this->host = rtrim($this->host, '.');
277 $this->host = self::idnHostToUnicode(strtolower($this->host));
278 return $this;
279 }
280 public function __toString(): string
281 {
282 return $this->getAbsoluteUrl();
283 }
284 public function jsonSerialize(): string
285 {
286 return $this->getAbsoluteUrl();
287 }
288 /** @internal */
289 final public function export(): array
290 {
291 return [$this->scheme, $this->user, $this->password, $this->host, $this->port, $this->path, $this->query, $this->fragment];
292 }
293 /**
294 * Converts IDN ASCII host to UTF-8.
295 */
296 private static function idnHostToUnicode(string $host): string
297 {
298 if (strpos($host, '--') === \false) {
299 // host does not contain IDN
300 return $host;
301 }
302 if (function_exists('idn_to_utf8') && defined('INTL_IDNA_VARIANT_UTS46')) {
303 return idn_to_utf8($host, \IDNA_DEFAULT, \INTL_IDNA_VARIANT_UTS46) ?: $host;
304 }
305 trigger_error('PHP extension intl is not loaded or is too old', \E_USER_WARNING);
306 }
307 /**
308 * Similar to rawurldecode, but preserves reserved chars encoded.
309 */
310 public static function unescape(string $s, string $reserved = '%;/?:@&=+$,'): string
311 {
312 // reserved (@see RFC 2396) = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
313 // within a path segment, the characters "/", ";", "=", "?" are reserved
314 // within a query component, the characters ";", "/", "?", ":", "@", "&", "=", "+", ",", "$" are reserved.
315 if ($reserved !== '') {
316 $s = preg_replace_callback('#%(' . substr(chunk_split(bin2hex($reserved), 2, '|'), 0, -1) . ')#i', function (array $m): string {
317 return '%25' . strtoupper($m[1]);
318 }, $s);
319 }
320 return rawurldecode($s);
321 }
322 /**
323 * Parses query string. Is affected by directive arg_separator.input.
324 */
325 public static function parseQuery(string $s): array
326 {
327 $s = str_replace(['%5B', '%5b'], '[', $s);
328 $sep = preg_quote(ini_get('arg_separator.input'));
329 $s = preg_replace("#([{$sep}])([^[{$sep}=]+)([^{$sep}]*)#", '&0[$2]$3', '&' . $s);
330 parse_str($s, $res);
331 return $res[0] ?? [];
332 }
333 }
334