5e1eaf6310a597ac23165e5ca7019c4c3513c1b1
[Packages/TYPO3.CMS.git] / typo3 / contrib / pear / Net / URL2.php
1 <?php
2 /**
3 * Net_URL2, a class representing a URL as per RFC 3986.
4 *
5 * PHP version 5
6 *
7 * LICENSE:
8 *
9 * Copyright (c) 2007-2009, Peytz & Co. A/S
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * * Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in
20 * the documentation and/or other materials provided with the distribution.
21 * * Neither the name of the Net_URL2 nor the names of its contributors may
22 * be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
26 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
27 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
33 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * @category Networking
38 * @package Net_URL2
39 * @author Christian Schmidt <schmidt@php.net>
40 * @copyright 2007-2009 Peytz & Co. A/S
41 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
42 * @version CVS: $Id: URL2.php 290036 2009-10-28 19:52:49Z schmidt $
43 * @link http://www.rfc-editor.org/rfc/rfc3986.txt
44 */
45
46 /**
47 * Represents a URL as per RFC 3986.
48 *
49 * @category Networking
50 * @package Net_URL2
51 * @author Christian Schmidt <schmidt@php.net>
52 * @copyright 2007-2009 Peytz & Co. A/S
53 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
54 * @version Release: @package_version@
55 * @link http://pear.php.net/package/Net_URL2
56 */
57 class Net_URL2
58 {
59 /**
60 * Do strict parsing in resolve() (see RFC 3986, section 5.2.2). Default
61 * is true.
62 */
63 const OPTION_STRICT = 'strict';
64
65 /**
66 * Represent arrays in query using PHP's [] notation. Default is true.
67 */
68 const OPTION_USE_BRACKETS = 'use_brackets';
69
70 /**
71 * URL-encode query variable keys. Default is true.
72 */
73 const OPTION_ENCODE_KEYS = 'encode_keys';
74
75 /**
76 * Query variable separators when parsing the query string. Every character
77 * is considered a separator. Default is "&".
78 */
79 const OPTION_SEPARATOR_INPUT = 'input_separator';
80
81 /**
82 * Query variable separator used when generating the query string. Default
83 * is "&".
84 */
85 const OPTION_SEPARATOR_OUTPUT = 'output_separator';
86
87 /**
88 * Default options corresponds to how PHP handles $_GET.
89 */
90 private $_options = array(
91 self::OPTION_STRICT => true,
92 self::OPTION_USE_BRACKETS => true,
93 self::OPTION_ENCODE_KEYS => true,
94 self::OPTION_SEPARATOR_INPUT => '&',
95 self::OPTION_SEPARATOR_OUTPUT => '&',
96 );
97
98 /**
99 * @var string|bool
100 */
101 private $_scheme = false;
102
103 /**
104 * @var string|bool
105 */
106 private $_userinfo = false;
107
108 /**
109 * @var string|bool
110 */
111 private $_host = false;
112
113 /**
114 * @var string|bool
115 */
116 private $_port = false;
117
118 /**
119 * @var string
120 */
121 private $_path = '';
122
123 /**
124 * @var string|bool
125 */
126 private $_query = false;
127
128 /**
129 * @var string|bool
130 */
131 private $_fragment = false;
132
133 /**
134 * Constructor.
135 *
136 * @param string $url an absolute or relative URL
137 * @param array $options an array of OPTION_xxx constants
138 */
139 public function __construct($url, array $options = array())
140 {
141 foreach ($options as $optionName => $value) {
142 if (array_key_exists($optionName, $this->_options)) {
143 $this->_options[$optionName] = $value;
144 }
145 }
146
147 // The regular expression is copied verbatim from RFC 3986, appendix B.
148 // The expression does not validate the URL but matches any string.
149 preg_match('!^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?!',
150 $url,
151 $matches);
152
153 // "path" is always present (possibly as an empty string); the rest
154 // are optional.
155 $this->_scheme = !empty($matches[1]) ? $matches[2] : false;
156 $this->setAuthority(!empty($matches[3]) ? $matches[4] : false);
157 $this->_path = $matches[5];
158 $this->_query = !empty($matches[6]) ? $matches[7] : false;
159 $this->_fragment = !empty($matches[8]) ? $matches[9] : false;
160 }
161
162 /**
163 * Magic Setter.
164 *
165 * This method will magically set the value of a private variable ($var)
166 * with the value passed as the args
167 *
168 * @param string $var The private variable to set.
169 * @param mixed $arg An argument of any type.
170 * @return void
171 */
172 public function __set($var, $arg)
173 {
174 $method = 'set' . $var;
175 if (method_exists($this, $method)) {
176 $this->$method($arg);
177 }
178 }
179
180 /**
181 * Magic Getter.
182 *
183 * This is the magic get method to retrieve the private variable
184 * that was set by either __set() or it's setter...
185 *
186 * @param string $var The property name to retrieve.
187 * @return mixed $this->$var Either a boolean false if the
188 * property is not set or the value
189 * of the private property.
190 */
191 public function __get($var)
192 {
193 $method = 'get' . $var;
194 if (method_exists($this, $method)) {
195 return $this->$method();
196 }
197
198 return false;
199 }
200
201 /**
202 * Returns the scheme, e.g. "http" or "urn", or false if there is no
203 * scheme specified, i.e. if this is a relative URL.
204 *
205 * @return string|bool
206 */
207 public function getScheme()
208 {
209 return $this->_scheme;
210 }
211
212 /**
213 * Sets the scheme, e.g. "http" or "urn". Specify false if there is no
214 * scheme specified, i.e. if this is a relative URL.
215 *
216 * @param string|bool $scheme e.g. "http" or "urn", or false if there is no
217 * scheme specified, i.e. if this is a relative
218 * URL
219 *
220 * @return void
221 * @see getScheme()
222 */
223 public function setScheme($scheme)
224 {
225 $this->_scheme = $scheme;
226 }
227
228 /**
229 * Returns the user part of the userinfo part (the part preceding the first
230 * ":"), or false if there is no userinfo part.
231 *
232 * @return string|bool
233 */
234 public function getUser()
235 {
236 return $this->_userinfo !== false
237 ? preg_replace('@:.*$@', '', $this->_userinfo)
238 : false;
239 }
240
241 /**
242 * Returns the password part of the userinfo part (the part after the first
243 * ":"), or false if there is no userinfo part (i.e. the URL does not
244 * contain "@" in front of the hostname) or the userinfo part does not
245 * contain ":".
246 *
247 * @return string|bool
248 */
249 public function getPassword()
250 {
251 return $this->_userinfo !== false
252 ? substr(strstr($this->_userinfo, ':'), 1)
253 : false;
254 }
255
256 /**
257 * Returns the userinfo part, or false if there is none, i.e. if the
258 * authority part does not contain "@".
259 *
260 * @return string|bool
261 */
262 public function getUserinfo()
263 {
264 return $this->_userinfo;
265 }
266
267 /**
268 * Sets the userinfo part. If two arguments are passed, they are combined
269 * in the userinfo part as username ":" password.
270 *
271 * @param string|bool $userinfo userinfo or username
272 * @param string|bool $password optional password, or false
273 *
274 * @return void
275 */
276 public function setUserinfo($userinfo, $password = false)
277 {
278 $this->_userinfo = $userinfo;
279 if ($password !== false) {
280 $this->_userinfo .= ':' . $password;
281 }
282 }
283
284 /**
285 * Returns the host part, or false if there is no authority part, e.g.
286 * relative URLs.
287 *
288 * @return string|bool a hostname, an IP address, or false
289 */
290 public function getHost()
291 {
292 return $this->_host;
293 }
294
295 /**
296 * Sets the host part. Specify false if there is no authority part, e.g.
297 * relative URLs.
298 *
299 * @param string|bool $host a hostname, an IP address, or false
300 *
301 * @return void
302 */
303 public function setHost($host)
304 {
305 $this->_host = $host;
306 }
307
308 /**
309 * Returns the port number, or false if there is no port number specified,
310 * i.e. if the default port is to be used.
311 *
312 * @return string|bool
313 */
314 public function getPort()
315 {
316 return $this->_port;
317 }
318
319 /**
320 * Sets the port number. Specify false if there is no port number specified,
321 * i.e. if the default port is to be used.
322 *
323 * @param string|bool $port a port number, or false
324 *
325 * @return void
326 */
327 public function setPort($port)
328 {
329 $this->_port = $port;
330 }
331
332 /**
333 * Returns the authority part, i.e. [ userinfo "@" ] host [ ":" port ], or
334 * false if there is no authority.
335 *
336 * @return string|bool
337 */
338 public function getAuthority()
339 {
340 if (!$this->_host) {
341 return false;
342 }
343
344 $authority = '';
345
346 if ($this->_userinfo !== false) {
347 $authority .= $this->_userinfo . '@';
348 }
349
350 $authority .= $this->_host;
351
352 if ($this->_port !== false) {
353 $authority .= ':' . $this->_port;
354 }
355
356 return $authority;
357 }
358
359 /**
360 * Sets the authority part, i.e. [ userinfo "@" ] host [ ":" port ]. Specify
361 * false if there is no authority.
362 *
363 * @param string|false $authority a hostname or an IP addresse, possibly
364 * with userinfo prefixed and port number
365 * appended, e.g. "foo:bar@example.org:81".
366 *
367 * @return void
368 */
369 public function setAuthority($authority)
370 {
371 $this->_userinfo = false;
372 $this->_host = false;
373 $this->_port = false;
374 if (preg_match('@^(([^\@]*)\@)?([^:]+)(:(\d*))?$@', $authority, $reg)) {
375 if ($reg[1]) {
376 $this->_userinfo = $reg[2];
377 }
378
379 $this->_host = $reg[3];
380 if (isset($reg[5])) {
381 $this->_port = $reg[5];
382 }
383 }
384 }
385
386 /**
387 * Returns the path part (possibly an empty string).
388 *
389 * @return string
390 */
391 public function getPath()
392 {
393 return $this->_path;
394 }
395
396 /**
397 * Sets the path part (possibly an empty string).
398 *
399 * @param string $path a path
400 *
401 * @return void
402 */
403 public function setPath($path)
404 {
405 $this->_path = $path;
406 }
407
408 /**
409 * Returns the query string (excluding the leading "?"), or false if "?"
410 * is not present in the URL.
411 *
412 * @return string|bool
413 * @see self::getQueryVariables()
414 */
415 public function getQuery()
416 {
417 return $this->_query;
418 }
419
420 /**
421 * Sets the query string (excluding the leading "?"). Specify false if "?"
422 * is not present in the URL.
423 *
424 * @param string|bool $query a query string, e.g. "foo=1&bar=2"
425 *
426 * @return void
427 * @see self::setQueryVariables()
428 */
429 public function setQuery($query)
430 {
431 $this->_query = $query;
432 }
433
434 /**
435 * Returns the fragment name, or false if "#" is not present in the URL.
436 *
437 * @return string|bool
438 */
439 public function getFragment()
440 {
441 return $this->_fragment;
442 }
443
444 /**
445 * Sets the fragment name. Specify false if "#" is not present in the URL.
446 *
447 * @param string|bool $fragment a fragment excluding the leading "#", or
448 * false
449 *
450 * @return void
451 */
452 public function setFragment($fragment)
453 {
454 $this->_fragment = $fragment;
455 }
456
457 /**
458 * Returns the query string like an array as the variables would appear in
459 * $_GET in a PHP script. If the URL does not contain a "?", an empty array
460 * is returned.
461 *
462 * @return array
463 */
464 public function getQueryVariables()
465 {
466 $pattern = '/[' .
467 preg_quote($this->getOption(self::OPTION_SEPARATOR_INPUT), '/') .
468 ']/';
469 $parts = preg_split($pattern, $this->_query, -1, PREG_SPLIT_NO_EMPTY);
470 $return = array();
471
472 foreach ($parts as $part) {
473 if (strpos($part, '=') !== false) {
474 list($key, $value) = explode('=', $part, 2);
475 } else {
476 $key = $part;
477 $value = null;
478 }
479
480 if ($this->getOption(self::OPTION_ENCODE_KEYS)) {
481 $key = rawurldecode($key);
482 }
483 $value = rawurldecode($value);
484
485 if ($this->getOption(self::OPTION_USE_BRACKETS) &&
486 preg_match('#^(.*)\[([0-9a-z_-]*)\]#i', $key, $matches)) {
487
488 $key = $matches[1];
489 $idx = $matches[2];
490
491 // Ensure is an array
492 if (empty($return[$key]) || !is_array($return[$key])) {
493 $return[$key] = array();
494 }
495
496 // Add data
497 if ($idx === '') {
498 $return[$key][] = $value;
499 } else {
500 $return[$key][$idx] = $value;
501 }
502 } elseif (!$this->getOption(self::OPTION_USE_BRACKETS)
503 && !empty($return[$key])
504 ) {
505 $return[$key] = (array) $return[$key];
506 $return[$key][] = $value;
507 } else {
508 $return[$key] = $value;
509 }
510 }
511
512 return $return;
513 }
514
515 /**
516 * Sets the query string to the specified variable in the query string.
517 *
518 * @param array $array (name => value) array
519 *
520 * @return void
521 */
522 public function setQueryVariables(array $array)
523 {
524 if (!$array) {
525 $this->_query = false;
526 } else {
527 foreach ($array as $name => $value) {
528 if ($this->getOption(self::OPTION_ENCODE_KEYS)) {
529 $name = self::urlencode($name);
530 }
531
532 if (is_array($value)) {
533 foreach ($value as $k => $v) {
534 $parts[] = $this->getOption(self::OPTION_USE_BRACKETS)
535 ? sprintf('%s[%s]=%s', $name, $k, $v)
536 : ($name . '=' . $v);
537 }
538 } elseif (!is_null($value)) {
539 $parts[] = $name . '=' . self::urlencode($value);
540 } else {
541 $parts[] = $name;
542 }
543 }
544 $this->_query = implode($this->getOption(self::OPTION_SEPARATOR_OUTPUT),
545 $parts);
546 }
547 }
548
549 /**
550 * Sets the specified variable in the query string.
551 *
552 * @param string $name variable name
553 * @param mixed $value variable value
554 *
555 * @return array
556 */
557 public function setQueryVariable($name, $value)
558 {
559 $array = $this->getQueryVariables();
560 $array[$name] = $value;
561 $this->setQueryVariables($array);
562 }
563
564 /**
565 * Removes the specifed variable from the query string.
566 *
567 * @param string $name a query string variable, e.g. "foo" in "?foo=1"
568 *
569 * @return void
570 */
571 public function unsetQueryVariable($name)
572 {
573 $array = $this->getQueryVariables();
574 unset($array[$name]);
575 $this->setQueryVariables($array);
576 }
577
578 /**
579 * Returns a string representation of this URL.
580 *
581 * @return string
582 */
583 public function getURL()
584 {
585 // See RFC 3986, section 5.3
586 $url = "";
587
588 if ($this->_scheme !== false) {
589 $url .= $this->_scheme . ':';
590 }
591
592 $authority = $this->getAuthority();
593 if ($authority !== false) {
594 $url .= '//' . $authority;
595 }
596 $url .= $this->_path;
597
598 if ($this->_query !== false) {
599 $url .= '?' . $this->_query;
600 }
601
602 if ($this->_fragment !== false) {
603 $url .= '#' . $this->_fragment;
604 }
605
606 return $url;
607 }
608
609 /**
610 * Returns a string representation of this URL.
611 *
612 * @return string
613 * @see toString()
614 */
615 public function __toString()
616 {
617 return $this->getURL();
618 }
619
620 /**
621 * Returns a normalized string representation of this URL. This is useful
622 * for comparison of URLs.
623 *
624 * @return string
625 */
626 public function getNormalizedURL()
627 {
628 $url = clone $this;
629 $url->normalize();
630 return $url->getUrl();
631 }
632
633 /**
634 * Returns a normalized Net_URL2 instance.
635 *
636 * @return Net_URL2
637 */
638 public function normalize()
639 {
640 // See RFC 3886, section 6
641
642 // Schemes are case-insensitive
643 if ($this->_scheme) {
644 $this->_scheme = strtolower($this->_scheme);
645 }
646
647 // Hostnames are case-insensitive
648 if ($this->_host) {
649 $this->_host = strtolower($this->_host);
650 }
651
652 // Remove default port number for known schemes (RFC 3986, section 6.2.3)
653 if ($this->_port &&
654 $this->_scheme &&
655 $this->_port == getservbyname($this->_scheme, 'tcp')) {
656
657 $this->_port = false;
658 }
659
660 // Normalize case of %XX percentage-encodings (RFC 3986, section 6.2.2.1)
661 foreach (array('_userinfo', '_host', '_path') as $part) {
662 if ($this->$part) {
663 $this->$part = preg_replace('/%[0-9a-f]{2}/ie',
664 'strtoupper("\0")',
665 $this->$part);
666 }
667 }
668
669 // Path segment normalization (RFC 3986, section 6.2.2.3)
670 $this->_path = self::removeDotSegments($this->_path);
671
672 // Scheme based normalization (RFC 3986, section 6.2.3)
673 if ($this->_host && !$this->_path) {
674 $this->_path = '/';
675 }
676 }
677
678 /**
679 * Returns whether this instance represents an absolute URL.
680 *
681 * @return bool
682 */
683 public function isAbsolute()
684 {
685 return (bool) $this->_scheme;
686 }
687
688 /**
689 * Returns an Net_URL2 instance representing an absolute URL relative to
690 * this URL.
691 *
692 * @param Net_URL2|string $reference relative URL
693 *
694 * @return Net_URL2
695 */
696 public function resolve($reference)
697 {
698 if (!$reference instanceof Net_URL2) {
699 $reference = new self($reference);
700 }
701 if (!$this->isAbsolute()) {
702 throw new Exception('Base-URL must be absolute');
703 }
704
705 // A non-strict parser may ignore a scheme in the reference if it is
706 // identical to the base URI's scheme.
707 if (!$this->getOption(self::OPTION_STRICT) && $reference->_scheme == $this->_scheme) {
708 $reference->_scheme = false;
709 }
710
711 $target = new self('');
712 if ($reference->_scheme !== false) {
713 $target->_scheme = $reference->_scheme;
714 $target->setAuthority($reference->getAuthority());
715 $target->_path = self::removeDotSegments($reference->_path);
716 $target->_query = $reference->_query;
717 } else {
718 $authority = $reference->getAuthority();
719 if ($authority !== false) {
720 $target->setAuthority($authority);
721 $target->_path = self::removeDotSegments($reference->_path);
722 $target->_query = $reference->_query;
723 } else {
724 if ($reference->_path == '') {
725 $target->_path = $this->_path;
726 if ($reference->_query !== false) {
727 $target->_query = $reference->_query;
728 } else {
729 $target->_query = $this->_query;
730 }
731 } else {
732 if (substr($reference->_path, 0, 1) == '/') {
733 $target->_path = self::removeDotSegments($reference->_path);
734 } else {
735 // Merge paths (RFC 3986, section 5.2.3)
736 if ($this->_host !== false && $this->_path == '') {
737 $target->_path = '/' . $this->_path;
738 } else {
739 $i = strrpos($this->_path, '/');
740 if ($i !== false) {
741 $target->_path = substr($this->_path, 0, $i + 1);
742 }
743 $target->_path .= $reference->_path;
744 }
745 $target->_path = self::removeDotSegments($target->_path);
746 }
747 $target->_query = $reference->_query;
748 }
749 $target->setAuthority($this->getAuthority());
750 }
751 $target->_scheme = $this->_scheme;
752 }
753
754 $target->_fragment = $reference->_fragment;
755
756 return $target;
757 }
758
759 /**
760 * Removes dots as described in RFC 3986, section 5.2.4, e.g.
761 * "/foo/../bar/baz" => "/bar/baz"
762 *
763 * @param string $path a path
764 *
765 * @return string a path
766 */
767 public static function removeDotSegments($path)
768 {
769 $output = '';
770
771 // Make sure not to be trapped in an infinite loop due to a bug in this
772 // method
773 $j = 0;
774 while ($path && $j++ < 100) {
775 if (substr($path, 0, 2) == './') {
776 // Step 2.A
777 $path = substr($path, 2);
778 } elseif (substr($path, 0, 3) == '../') {
779 // Step 2.A
780 $path = substr($path, 3);
781 } elseif (substr($path, 0, 3) == '/./' || $path == '/.') {
782 // Step 2.B
783 $path = '/' . substr($path, 3);
784 } elseif (substr($path, 0, 4) == '/../' || $path == '/..') {
785 // Step 2.C
786 $path = '/' . substr($path, 4);
787 $i = strrpos($output, '/');
788 $output = $i === false ? '' : substr($output, 0, $i);
789 } elseif ($path == '.' || $path == '..') {
790 // Step 2.D
791 $path = '';
792 } else {
793 // Step 2.E
794 $i = strpos($path, '/');
795 if ($i === 0) {
796 $i = strpos($path, '/', 1);
797 }
798 if ($i === false) {
799 $i = strlen($path);
800 }
801 $output .= substr($path, 0, $i);
802 $path = substr($path, $i);
803 }
804 }
805
806 return $output;
807 }
808
809 /**
810 * Percent-encodes all non-alphanumeric characters except these: _ . - ~
811 * Similar to PHP's rawurlencode(), except that it also encodes ~ in PHP
812 * 5.2.x and earlier.
813 *
814 * @param $raw the string to encode
815 * @return string
816 */
817 public static function urlencode($string)
818 {
819 $encoded = rawurlencode($string);
820 // This is only necessary in PHP < 5.3.
821 $encoded = str_replace('%7E', '~', $encoded);
822 return $encoded;
823 }
824
825 /**
826 * Returns a Net_URL2 instance representing the canonical URL of the
827 * currently executing PHP script.
828 *
829 * @return string
830 */
831 public static function getCanonical()
832 {
833 if (!isset($_SERVER['REQUEST_METHOD'])) {
834 // ALERT - no current URL
835 throw new Exception('Script was not called through a webserver');
836 }
837
838 // Begin with a relative URL
839 $url = new self($_SERVER['PHP_SELF']);
840 $url->_scheme = isset($_SERVER['HTTPS']) ? 'https' : 'http';
841 $url->_host = $_SERVER['SERVER_NAME'];
842 $port = $_SERVER['SERVER_PORT'];
843 if ($url->_scheme == 'http' && $port != 80 ||
844 $url->_scheme == 'https' && $port != 443) {
845
846 $url->_port = $port;
847 }
848 return $url;
849 }
850
851 /**
852 * Returns the URL used to retrieve the current request.
853 *
854 * @return string
855 */
856 public static function getRequestedURL()
857 {
858 return self::getRequested()->getUrl();
859 }
860
861 /**
862 * Returns a Net_URL2 instance representing the URL used to retrieve the
863 * current request.
864 *
865 * @return Net_URL2
866 */
867 public static function getRequested()
868 {
869 if (!isset($_SERVER['REQUEST_METHOD'])) {
870 // ALERT - no current URL
871 throw new Exception('Script was not called through a webserver');
872 }
873
874 // Begin with a relative URL
875 $url = new self($_SERVER['REQUEST_URI']);
876 $url->_scheme = isset($_SERVER['HTTPS']) ? 'https' : 'http';
877 // Set host and possibly port
878 $url->setAuthority($_SERVER['HTTP_HOST']);
879 return $url;
880 }
881
882 /**
883 * Returns the value of the specified option.
884 *
885 * @param string $optionName The name of the option to retrieve
886 *
887 * @return mixed
888 */
889 function getOption($optionName)
890 {
891 return isset($this->_options[$optionName])
892 ? $this->_options[$optionName] : false;
893 }
894 }
895 ?>