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