Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
      • Traits
    • Reflection
    • Security
    • Tokenizer
    • Utils
  • Tracy
    • Bridges
      • Nette
  • none

Classes

  • Context
  • FileUpload
  • Helpers
  • Request
  • RequestFactory
  • Response
  • Session
  • SessionSection
  • Url
  • UrlScript
  • UserStorage

Interfaces

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