~ubuntu-branches/debian/experimental/php-nette/experimental

« back to all changes in this revision

Viewing changes to Nette-2.0.13/Nette/Http/Url.php

  • Committer: Package Import Robot
  • Author(s): David Prévot
  • Date: 2013-11-30 08:47:54 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20131130084754-4udf1xsu9085tnfc
Tags: 2.1.0~rc-1
* New upstream branch
* Update copyright

Show diffs side-by-side

added added

removed removed

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