]> git.immae.eu Git - github/wallabag/wallabag.git/blob - inc/3rdparty/simplepie/SimplePie/IRI.php
Merge pull request #181 from inthepoche/dev
[github/wallabag/wallabag.git] / inc / 3rdparty / simplepie / SimplePie / IRI.php
1 <?php
2 /**
3 * SimplePie
4 *
5 * A PHP-Based RSS and Atom Feed Framework.
6 * Takes the hard work out of managing a complete RSS/Atom solution.
7 *
8 * Copyright (c) 2004-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without modification, are
12 * permitted provided that the following conditions are met:
13 *
14 * * Redistributions of source code must retain the above copyright notice, this list of
15 * conditions and the following disclaimer.
16 *
17 * * Redistributions in binary form must reproduce the above copyright notice, this list
18 * of conditions and the following disclaimer in the documentation and/or other materials
19 * provided with the distribution.
20 *
21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used
22 * to endorse or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 * @package SimplePie
36 * @version 1.3-dev
37 * @copyright 2004-2010 Ryan Parman, Geoffrey Sneddon, Ryan McCue
38 * @author Ryan Parman
39 * @author Geoffrey Sneddon
40 * @author Ryan McCue
41 * @link http://simplepie.org/ SimplePie
42 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
43 * @todo phpDoc comments
44 */
45
46 /**
47 * IRI parser/serialiser
48 *
49 * @package SimplePie
50 */
51 class SimplePie_IRI
52 {
53 /**
54 * Scheme
55 *
56 * @access private
57 * @var string
58 */
59 var $scheme;
60
61 /**
62 * User Information
63 *
64 * @access private
65 * @var string
66 */
67 var $userinfo;
68
69 /**
70 * Host
71 *
72 * @access private
73 * @var string
74 */
75 var $host;
76
77 /**
78 * Port
79 *
80 * @access private
81 * @var string
82 */
83 var $port;
84
85 /**
86 * Path
87 *
88 * @access private
89 * @var string
90 */
91 var $path;
92
93 /**
94 * Query
95 *
96 * @access private
97 * @var string
98 */
99 var $query;
100
101 /**
102 * Fragment
103 *
104 * @access private
105 * @var string
106 */
107 var $fragment;
108
109 /**
110 * Whether the object represents a valid IRI
111 *
112 * @access private
113 * @var array
114 */
115 var $valid = array();
116
117 /**
118 * Return the entire IRI when you try and read the object as a string
119 *
120 * @access public
121 * @return string
122 */
123 public function __toString()
124 {
125 return $this->get_iri();
126 }
127
128 /**
129 * Create a new IRI object, from a specified string
130 *
131 * @access public
132 * @param string $iri
133 * @return SimplePie_IRI
134 */
135 public function __construct($iri)
136 {
137 $iri = (string) $iri;
138 if ($iri !== '')
139 {
140 $parsed = $this->parse_iri($iri);
141 $this->set_scheme($parsed['scheme']);
142 $this->set_authority($parsed['authority']);
143 $this->set_path($parsed['path']);
144 $this->set_query($parsed['query']);
145 $this->set_fragment($parsed['fragment']);
146 }
147 }
148
149 /**
150 * Create a new IRI object by resolving a relative IRI
151 *
152 * @static
153 * @access public
154 * @param SimplePie_IRI $base Base IRI
155 * @param string $relative Relative IRI
156 * @return SimplePie_IRI
157 */
158 public static function absolutize($base, $relative)
159 {
160 $relative = (string) $relative;
161 if ($relative !== '')
162 {
163 $relative = new SimplePie_IRI($relative);
164 if ($relative->get_scheme() !== null)
165 {
166 $target = $relative;
167 }
168 elseif ($base->get_iri() !== null)
169 {
170 if ($relative->get_authority() !== null)
171 {
172 $target = $relative;
173 $target->set_scheme($base->get_scheme());
174 }
175 else
176 {
177 $target = new SimplePie_IRI('');
178 $target->set_scheme($base->get_scheme());
179 $target->set_userinfo($base->get_userinfo());
180 $target->set_host($base->get_host());
181 $target->set_port($base->get_port());
182 if ($relative->get_path() !== null)
183 {
184 if (strpos($relative->get_path(), '/') === 0)
185 {
186 $target->set_path($relative->get_path());
187 }
188 elseif (($base->get_userinfo() !== null || $base->get_host() !== null || $base->get_port() !== null) && $base->get_path() === null)
189 {
190 $target->set_path('/' . $relative->get_path());
191 }
192 elseif (($last_segment = strrpos($base->get_path(), '/')) !== false)
193 {
194 $target->set_path(substr($base->get_path(), 0, $last_segment + 1) . $relative->get_path());
195 }
196 else
197 {
198 $target->set_path($relative->get_path());
199 }
200 $target->set_query($relative->get_query());
201 }
202 else
203 {
204 $target->set_path($base->get_path());
205 if ($relative->get_query() !== null)
206 {
207 $target->set_query($relative->get_query());
208 }
209 elseif ($base->get_query() !== null)
210 {
211 $target->set_query($base->get_query());
212 }
213 }
214 }
215 $target->set_fragment($relative->get_fragment());
216 }
217 else
218 {
219 // No base URL, just return the relative URL
220 $target = $relative;
221 }
222 }
223 else
224 {
225 $target = $base;
226 }
227 return $target;
228 }
229
230 /**
231 * Parse an IRI into scheme/authority/path/query/fragment segments
232 *
233 * @access private
234 * @param string $iri
235 * @return array
236 */
237 public function parse_iri($iri)
238 {
239 preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $iri, $match);
240 for ($i = count($match); $i <= 9; $i++)
241 {
242 $match[$i] = '';
243 }
244 return array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]);
245 }
246
247 /**
248 * Remove dot segments from a path
249 *
250 * @access private
251 * @param string $input
252 * @return string
253 */
254 public function remove_dot_segments($input)
255 {
256 $output = '';
257 while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..')
258 {
259 // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
260 if (strpos($input, '../') === 0)
261 {
262 $input = substr($input, 3);
263 }
264 elseif (strpos($input, './') === 0)
265 {
266 $input = substr($input, 2);
267 }
268 // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
269 elseif (strpos($input, '/./') === 0)
270 {
271 $input = substr_replace($input, '/', 0, 3);
272 }
273 elseif ($input === '/.')
274 {
275 $input = '/';
276 }
277 // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
278 elseif (strpos($input, '/../') === 0)
279 {
280 $input = substr_replace($input, '/', 0, 4);
281 $output = substr_replace($output, '', strrpos($output, '/'));
282 }
283 elseif ($input === '/..')
284 {
285 $input = '/';
286 $output = substr_replace($output, '', strrpos($output, '/'));
287 }
288 // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
289 elseif ($input === '.' || $input === '..')
290 {
291 $input = '';
292 }
293 // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
294 elseif (($pos = strpos($input, '/', 1)) !== false)
295 {
296 $output .= substr($input, 0, $pos);
297 $input = substr_replace($input, '', 0, $pos);
298 }
299 else
300 {
301 $output .= $input;
302 $input = '';
303 }
304 }
305 return $output . $input;
306 }
307
308 /**
309 * Replace invalid character with percent encoding
310 *
311 * @param string $string Input string
312 * @param string $valid_chars Valid characters not in iunreserved or iprivate (this is ASCII-only)
313 * @param int $case Normalise case
314 * @param bool $iprivate Allow iprivate
315 * @return string
316 */
317 protected function replace_invalid_with_pct_encoding($string, $valid_chars, $case = SIMPLEPIE_SAME_CASE, $iprivate = false)
318 {
319 // Normalize as many pct-encoded sections as possible
320 $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string);
321
322 // Replace invalid percent characters
323 $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string);
324
325 // Add unreserved and % to $valid_chars (the latter is safe because all
326 // pct-encoded sections are now valid).
327 $valid_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%';
328
329 // Now replace any bytes that aren't allowed with their pct-encoded versions
330 $position = 0;
331 $strlen = strlen($string);
332 while (($position += strspn($string, $valid_chars, $position)) < $strlen)
333 {
334 $value = ord($string[$position]);
335
336 // Start position
337 $start = $position;
338
339 // By default we are valid
340 $valid = true;
341
342 // No one byte sequences are valid due to the while.
343 // Two byte sequence:
344 if (($value & 0xE0) === 0xC0)
345 {
346 $character = ($value & 0x1F) << 6;
347 $length = 2;
348 $remaining = 1;
349 }
350 // Three byte sequence:
351 elseif (($value & 0xF0) === 0xE0)
352 {
353 $character = ($value & 0x0F) << 12;
354 $length = 3;
355 $remaining = 2;
356 }
357 // Four byte sequence:
358 elseif (($value & 0xF8) === 0xF0)
359 {
360 $character = ($value & 0x07) << 18;
361 $length = 4;
362 $remaining = 3;
363 }
364 // Invalid byte:
365 else
366 {
367 $valid = false;
368 $length = 1;
369 $remaining = 0;
370 }
371
372 if ($remaining)
373 {
374 if ($position + $length <= $strlen)
375 {
376 for ($position++; $remaining; $position++)
377 {
378 $value = ord($string[$position]);
379
380 // Check that the byte is valid, then add it to the character:
381 if (($value & 0xC0) === 0x80)
382 {
383 $character |= ($value & 0x3F) << (--$remaining * 6);
384 }
385 // If it is invalid, count the sequence as invalid and reprocess the current byte:
386 else
387 {
388 $valid = false;
389 $position--;
390 break;
391 }
392 }
393 }
394 else
395 {
396 $position = $strlen - 1;
397 $valid = false;
398 }
399 }
400
401 // Percent encode anything invalid or not in ucschar
402 if (
403 // Invalid sequences
404 !$valid
405 // Non-shortest form sequences are invalid
406 || $length > 1 && $character <= 0x7F
407 || $length > 2 && $character <= 0x7FF
408 || $length > 3 && $character <= 0xFFFF
409 // Outside of range of ucschar codepoints
410 // Noncharacters
411 || ($character & 0xFFFE) === 0xFFFE
412 || $character >= 0xFDD0 && $character <= 0xFDEF
413 || (
414 // Everything else not in ucschar
415 $character > 0xD7FF && $character < 0xF900
416 || $character < 0xA0
417 || $character > 0xEFFFD
418 )
419 && (
420 // Everything not in iprivate, if it applies
421 !$iprivate
422 || $character < 0xE000
423 || $character > 0x10FFFD
424 )
425 )
426 {
427 // If we were a character, pretend we weren't, but rather an error.
428 if ($valid)
429 $position--;
430
431 for ($j = $start; $j <= $position; $j++)
432 {
433 $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1);
434 $j += 2;
435 $position += 2;
436 $strlen += 2;
437 }
438 }
439 }
440
441 // Normalise case
442 if ($case & SIMPLEPIE_LOWERCASE)
443 {
444 $string = strtolower($string);
445 }
446 elseif ($case & SIMPLEPIE_UPPERCASE)
447 {
448 $string = strtoupper($string);
449 }
450
451 return $string;
452 }
453
454 /**
455 * Callback function for preg_replace_callback.
456 *
457 * Removes sequences of percent encoded bytes that represent UTF-8
458 * encoded characters in iunreserved
459 *
460 * @param array $match PCRE match
461 * @return string Replacement
462 */
463 protected function remove_iunreserved_percent_encoded($match)
464 {
465 // As we just have valid percent encoded sequences we can just explode
466 // and ignore the first member of the returned array (an empty string).
467 $bytes = explode('%', $match[0]);
468
469 // Initialize the new string (this is what will be returned) and that
470 // there are no bytes remaining in the current sequence (unsurprising
471 // at the first byte!).
472 $string = '';
473 $remaining = 0;
474
475 // Loop over each and every byte, and set $value to its value
476 for ($i = 1, $len = count($bytes); $i < $len; $i++)
477 {
478 $value = hexdec($bytes[$i]);
479
480 // If we're the first byte of sequence:
481 if (!$remaining)
482 {
483 // Start position
484 $start = $i;
485
486 // By default we are valid
487 $valid = true;
488
489 // One byte sequence:
490 if ($value <= 0x7F)
491 {
492 $character = $value;
493 $length = 1;
494 }
495 // Two byte sequence:
496 elseif (($value & 0xE0) === 0xC0)
497 {
498 $character = ($value & 0x1F) << 6;
499 $length = 2;
500 $remaining = 1;
501 }
502 // Three byte sequence:
503 elseif (($value & 0xF0) === 0xE0)
504 {
505 $character = ($value & 0x0F) << 12;
506 $length = 3;
507 $remaining = 2;
508 }
509 // Four byte sequence:
510 elseif (($value & 0xF8) === 0xF0)
511 {
512 $character = ($value & 0x07) << 18;
513 $length = 4;
514 $remaining = 3;
515 }
516 // Invalid byte:
517 else
518 {
519 $valid = false;
520 $remaining = 0;
521 }
522 }
523 // Continuation byte:
524 else
525 {
526 // Check that the byte is valid, then add it to the character:
527 if (($value & 0xC0) === 0x80)
528 {
529 $remaining--;
530 $character |= ($value & 0x3F) << ($remaining * 6);
531 }
532 // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence:
533 else
534 {
535 $valid = false;
536 $remaining = 0;
537 $i--;
538 }
539 }
540
541 // If we've reached the end of the current byte sequence, append it to Unicode::$data
542 if (!$remaining)
543 {
544 // Percent encode anything invalid or not in iunreserved
545 if (
546 // Invalid sequences
547 !$valid
548 // Non-shortest form sequences are invalid
549 || $length > 1 && $character <= 0x7F
550 || $length > 2 && $character <= 0x7FF
551 || $length > 3 && $character <= 0xFFFF
552 // Outside of range of iunreserved codepoints
553 || $character < 0x2D
554 || $character > 0xEFFFD
555 // Noncharacters
556 || ($character & 0xFFFE) === 0xFFFE
557 || $character >= 0xFDD0 && $character <= 0xFDEF
558 // Everything else not in iunreserved (this is all BMP)
559 || $character === 0x2F
560 || $character > 0x39 && $character < 0x41
561 || $character > 0x5A && $character < 0x61
562 || $character > 0x7A && $character < 0x7E
563 || $character > 0x7E && $character < 0xA0
564 || $character > 0xD7FF && $character < 0xF900
565 )
566 {
567 for ($j = $start; $j <= $i; $j++)
568 {
569 $string .= '%' . strtoupper($bytes[$j]);
570 }
571 }
572 else
573 {
574 for ($j = $start; $j <= $i; $j++)
575 {
576 $string .= chr(hexdec($bytes[$j]));
577 }
578 }
579 }
580 }
581
582 // If we have any bytes left over they are invalid (i.e., we are
583 // mid-way through a multi-byte sequence)
584 if ($remaining)
585 {
586 for ($j = $start; $j < $len; $j++)
587 {
588 $string .= '%' . strtoupper($bytes[$j]);
589 }
590 }
591
592 return $string;
593 }
594
595 /**
596 * Check if the object represents a valid IRI
597 *
598 * @access public
599 * @return bool
600 */
601 public function is_valid()
602 {
603 return array_sum($this->valid) === count($this->valid);
604 }
605
606 /**
607 * Set the scheme. Returns true on success, false on failure (if there are
608 * any invalid characters).
609 *
610 * @access public
611 * @param string $scheme
612 * @return bool
613 */
614 public function set_scheme($scheme)
615 {
616 if ($scheme === null || $scheme === '')
617 {
618 $this->scheme = null;
619 }
620 else
621 {
622 $len = strlen($scheme);
623 switch (true)
624 {
625 case $len > 1:
626 if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-.', 1))
627 {
628 $this->scheme = null;
629 $this->valid[__FUNCTION__] = false;
630 return false;
631 }
632
633 case $len > 0:
634 if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 0, 1))
635 {
636 $this->scheme = null;
637 $this->valid[__FUNCTION__] = false;
638 return false;
639 }
640 }
641 $this->scheme = strtolower($scheme);
642 }
643 $this->valid[__FUNCTION__] = true;
644 return true;
645 }
646
647 /**
648 * Set the authority. Returns true on success, false on failure (if there are
649 * any invalid characters).
650 *
651 * @access public
652 * @param string $authority
653 * @return bool
654 */
655 public function set_authority($authority)
656 {
657 if (($userinfo_end = strrpos($authority, '@')) !== false)
658 {
659 $userinfo = substr($authority, 0, $userinfo_end);
660 $authority = substr($authority, $userinfo_end + 1);
661 }
662 else
663 {
664 $userinfo = null;
665 }
666
667 if (($port_start = strpos($authority, ':')) !== false)
668 {
669 $port = substr($authority, $port_start + 1);
670 if ($port === false)
671 {
672 $port = null;
673 }
674 $authority = substr($authority, 0, $port_start);
675 }
676 else
677 {
678 $port = null;
679 }
680
681 return $this->set_userinfo($userinfo) && $this->set_host($authority) && $this->set_port($port);
682 }
683
684 /**
685 * Set the userinfo.
686 *
687 * @access public
688 * @param string $userinfo
689 * @return bool
690 */
691 public function set_userinfo($userinfo)
692 {
693 if ($userinfo === null || $userinfo === '')
694 {
695 $this->userinfo = null;
696 }
697 else
698 {
699 $this->userinfo = $this->replace_invalid_with_pct_encoding($userinfo, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:');
700 }
701 $this->valid[__FUNCTION__] = true;
702 return true;
703 }
704
705 /**
706 * Set the host. Returns true on success, false on failure (if there are
707 * any invalid characters).
708 *
709 * @access public
710 * @param string $host
711 * @return bool
712 */
713 public function set_host($host)
714 {
715 if ($host === null || $host === '')
716 {
717 $this->host = null;
718 $this->valid[__FUNCTION__] = true;
719 return true;
720 }
721 elseif ($host[0] === '[' && substr($host, -1) === ']')
722 {
723 if (SimplePie_Net_IPv6::checkIPv6(substr($host, 1, -1)))
724 {
725 $this->host = $host;
726 $this->valid[__FUNCTION__] = true;
727 return true;
728 }
729 else
730 {
731 $this->host = null;
732 $this->valid[__FUNCTION__] = false;
733 return false;
734 }
735 }
736 else
737 {
738 $this->host = $this->replace_invalid_with_pct_encoding($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=', SIMPLEPIE_LOWERCASE);
739 $this->valid[__FUNCTION__] = true;
740 return true;
741 }
742 }
743
744 /**
745 * Set the port. Returns true on success, false on failure (if there are
746 * any invalid characters).
747 *
748 * @access public
749 * @param string $port
750 * @return bool
751 */
752 public function set_port($port)
753 {
754 if ($port === null || $port === '')
755 {
756 $this->port = null;
757 $this->valid[__FUNCTION__] = true;
758 return true;
759 }
760 elseif (strspn($port, '0123456789') === strlen($port))
761 {
762 $this->port = (int) $port;
763 $this->valid[__FUNCTION__] = true;
764 return true;
765 }
766 else
767 {
768 $this->port = null;
769 $this->valid[__FUNCTION__] = false;
770 return false;
771 }
772 }
773
774 /**
775 * Set the path.
776 *
777 * @access public
778 * @param string $path
779 * @return bool
780 */
781 public function set_path($path)
782 {
783 if ($path === null || $path === '')
784 {
785 $this->path = null;
786 $this->valid[__FUNCTION__] = true;
787 return true;
788 }
789 elseif (substr($path, 0, 2) === '//' && $this->userinfo === null && $this->host === null && $this->port === null)
790 {
791 $this->path = null;
792 $this->valid[__FUNCTION__] = false;
793 return false;
794 }
795 else
796 {
797 $this->path = $this->replace_invalid_with_pct_encoding($path, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=@/');
798 if ($this->scheme !== null)
799 {
800 $this->path = $this->remove_dot_segments($this->path);
801 }
802 $this->valid[__FUNCTION__] = true;
803 return true;
804 }
805 }
806
807 /**
808 * Set the query.
809 *
810 * @access public
811 * @param string $query
812 * @return bool
813 */
814 public function set_query($query)
815 {
816 if ($query === null || $query === '')
817 {
818 $this->query = null;
819 }
820 else
821 {
822 $this->query = $this->replace_invalid_with_pct_encoding($query, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$\'()*+,;:@/?&=');
823 }
824 $this->valid[__FUNCTION__] = true;
825 return true;
826 }
827
828 /**
829 * Set the fragment.
830 *
831 * @access public
832 * @param string $fragment
833 * @return bool
834 */
835 public function set_fragment($fragment)
836 {
837 if ($fragment === null || $fragment === '')
838 {
839 $this->fragment = null;
840 }
841 else
842 {
843 $this->fragment = $this->replace_invalid_with_pct_encoding($fragment, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:@/?');
844 }
845 $this->valid[__FUNCTION__] = true;
846 return true;
847 }
848
849 /**
850 * Get the complete IRI
851 *
852 * @access public
853 * @return string
854 */
855 public function get_iri()
856 {
857 $iri = '';
858 if ($this->scheme !== null)
859 {
860 $iri .= $this->scheme . ':';
861 }
862 if (($authority = $this->get_authority()) !== null)
863 {
864 $iri .= '//' . $authority;
865 }
866 if ($this->path !== null)
867 {
868 $iri .= $this->path;
869 }
870 if ($this->query !== null)
871 {
872 $iri .= '?' . $this->query;
873 }
874 if ($this->fragment !== null)
875 {
876 $iri .= '#' . $this->fragment;
877 }
878
879 if ($iri !== '')
880 {
881 return $iri;
882 }
883 else
884 {
885 return null;
886 }
887 }
888
889 /**
890 * Get the scheme
891 *
892 * @access public
893 * @return string
894 */
895 public function get_scheme()
896 {
897 return $this->scheme;
898 }
899
900 /**
901 * Get the complete authority
902 *
903 * @access public
904 * @return string
905 */
906 public function get_authority()
907 {
908 $authority = '';
909 if ($this->userinfo !== null)
910 {
911 $authority .= $this->userinfo . '@';
912 }
913 if ($this->host !== null)
914 {
915 $authority .= $this->host;
916 }
917 if ($this->port !== null)
918 {
919 $authority .= ':' . $this->port;
920 }
921
922 if ($authority !== '')
923 {
924 return $authority;
925 }
926 else
927 {
928 return null;
929 }
930 }
931
932 /**
933 * Get the user information
934 *
935 * @access public
936 * @return string
937 */
938 public function get_userinfo()
939 {
940 return $this->userinfo;
941 }
942
943 /**
944 * Get the host
945 *
946 * @access public
947 * @return string
948 */
949 public function get_host()
950 {
951 return $this->host;
952 }
953
954 /**
955 * Get the port
956 *
957 * @access public
958 * @return string
959 */
960 public function get_port()
961 {
962 return $this->port;
963 }
964
965 /**
966 * Get the path
967 *
968 * @access public
969 * @return string
970 */
971 public function get_path()
972 {
973 return $this->path;
974 }
975
976 /**
977 * Get the query
978 *
979 * @access public
980 * @return string
981 */
982 public function get_query()
983 {
984 return $this->query;
985 }
986
987 /**
988 * Get the fragment
989 *
990 * @access public
991 * @return string
992 */
993 public function get_fragment()
994 {
995 return $this->fragment;
996 }
997 }