[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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.1 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/normaliser 47 * 48 * @package SimplePie 49 * @subpackage HTTP 50 * @author Geoffrey Sneddon 51 * @author Steve Minutillo 52 * @author Ryan McCue 53 * @copyright 2007-2012 Geoffrey Sneddon, Steve Minutillo, Ryan McCue 54 * @license http://www.opensource.org/licenses/bsd-license.php 55 */ 56 class SimplePie_IRI 57 { 58 /** 59 * Scheme 60 * 61 * @var string 62 */ 63 protected $scheme = null; 64 65 /** 66 * User Information 67 * 68 * @var string 69 */ 70 protected $iuserinfo = null; 71 72 /** 73 * ihost 74 * 75 * @var string 76 */ 77 protected $ihost = null; 78 79 /** 80 * Port 81 * 82 * @var string 83 */ 84 protected $port = null; 85 86 /** 87 * ipath 88 * 89 * @var string 90 */ 91 protected $ipath = ''; 92 93 /** 94 * iquery 95 * 96 * @var string 97 */ 98 protected $iquery = null; 99 100 /** 101 * ifragment 102 * 103 * @var string 104 */ 105 protected $ifragment = null; 106 107 /** 108 * Normalization database 109 * 110 * Each key is the scheme, each value is an array with each key as the IRI 111 * part and value as the default value for that part. 112 */ 113 protected $normalization = array( 114 'acap' => array( 115 'port' => 674 116 ), 117 'dict' => array( 118 'port' => 2628 119 ), 120 'file' => array( 121 'ihost' => 'localhost' 122 ), 123 'http' => array( 124 'port' => 80, 125 'ipath' => '/' 126 ), 127 'https' => array( 128 'port' => 443, 129 'ipath' => '/' 130 ), 131 ); 132 133 /** 134 * Return the entire IRI when you try and read the object as a string 135 * 136 * @return string 137 */ 138 public function __toString() 139 { 140 return $this->get_iri(); 141 } 142 143 /** 144 * Overload __set() to provide access via properties 145 * 146 * @param string $name Property name 147 * @param mixed $value Property value 148 */ 149 public function __set($name, $value) 150 { 151 if (method_exists($this, 'set_' . $name)) 152 { 153 call_user_func(array($this, 'set_' . $name), $value); 154 } 155 elseif ( 156 $name === 'iauthority' 157 || $name === 'iuserinfo' 158 || $name === 'ihost' 159 || $name === 'ipath' 160 || $name === 'iquery' 161 || $name === 'ifragment' 162 ) 163 { 164 call_user_func(array($this, 'set_' . substr($name, 1)), $value); 165 } 166 } 167 168 /** 169 * Overload __get() to provide access via properties 170 * 171 * @param string $name Property name 172 * @return mixed 173 */ 174 public function __get($name) 175 { 176 // isset() returns false for null, we don't want to do that 177 // Also why we use array_key_exists below instead of isset() 178 $props = get_object_vars($this); 179 180 if ( 181 $name === 'iri' || 182 $name === 'uri' || 183 $name === 'iauthority' || 184 $name === 'authority' 185 ) 186 { 187 $return = $this->{"get_$name"}(); 188 } 189 elseif (array_key_exists($name, $props)) 190 { 191 $return = $this->$name; 192 } 193 // host -> ihost 194 elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) 195 { 196 $name = $prop; 197 $return = $this->$prop; 198 } 199 // ischeme -> scheme 200 elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) 201 { 202 $name = $prop; 203 $return = $this->$prop; 204 } 205 else 206 { 207 trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE); 208 $return = null; 209 } 210 211 if ($return === null && isset($this->normalization[$this->scheme][$name])) 212 { 213 return $this->normalization[$this->scheme][$name]; 214 } 215 else 216 { 217 return $return; 218 } 219 } 220 221 /** 222 * Overload __isset() to provide access via properties 223 * 224 * @param string $name Property name 225 * @return bool 226 */ 227 public function __isset($name) 228 { 229 if (method_exists($this, 'get_' . $name) || isset($this->$name)) 230 { 231 return true; 232 } 233 else 234 { 235 return false; 236 } 237 } 238 239 /** 240 * Overload __unset() to provide access via properties 241 * 242 * @param string $name Property name 243 */ 244 public function __unset($name) 245 { 246 if (method_exists($this, 'set_' . $name)) 247 { 248 call_user_func(array($this, 'set_' . $name), ''); 249 } 250 } 251 252 /** 253 * Create a new IRI object, from a specified string 254 * 255 * @param string $iri 256 */ 257 public function __construct($iri = null) 258 { 259 $this->set_iri($iri); 260 } 261 262 /** 263 * Create a new IRI object by resolving a relative IRI 264 * 265 * Returns false if $base is not absolute, otherwise an IRI. 266 * 267 * @param IRI|string $base (Absolute) Base IRI 268 * @param IRI|string $relative Relative IRI 269 * @return IRI|false 270 */ 271 public static function absolutize($base, $relative) 272 { 273 if (!($relative instanceof SimplePie_IRI)) 274 { 275 $relative = new SimplePie_IRI($relative); 276 } 277 if (!$relative->is_valid()) 278 { 279 return false; 280 } 281 elseif ($relative->scheme !== null) 282 { 283 return clone $relative; 284 } 285 else 286 { 287 if (!($base instanceof SimplePie_IRI)) 288 { 289 $base = new SimplePie_IRI($base); 290 } 291 if ($base->scheme !== null && $base->is_valid()) 292 { 293 if ($relative->get_iri() !== '') 294 { 295 if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) 296 { 297 $target = clone $relative; 298 $target->scheme = $base->scheme; 299 } 300 else 301 { 302 $target = new SimplePie_IRI; 303 $target->scheme = $base->scheme; 304 $target->iuserinfo = $base->iuserinfo; 305 $target->ihost = $base->ihost; 306 $target->port = $base->port; 307 if ($relative->ipath !== '') 308 { 309 if ($relative->ipath[0] === '/') 310 { 311 $target->ipath = $relative->ipath; 312 } 313 elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') 314 { 315 $target->ipath = '/' . $relative->ipath; 316 } 317 elseif (($last_segment = strrpos($base->ipath, '/')) !== false) 318 { 319 $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath; 320 } 321 else 322 { 323 $target->ipath = $relative->ipath; 324 } 325 $target->ipath = $target->remove_dot_segments($target->ipath); 326 $target->iquery = $relative->iquery; 327 } 328 else 329 { 330 $target->ipath = $base->ipath; 331 if ($relative->iquery !== null) 332 { 333 $target->iquery = $relative->iquery; 334 } 335 elseif ($base->iquery !== null) 336 { 337 $target->iquery = $base->iquery; 338 } 339 } 340 $target->ifragment = $relative->ifragment; 341 } 342 } 343 else 344 { 345 $target = clone $base; 346 $target->ifragment = null; 347 } 348 $target->scheme_normalization(); 349 return $target; 350 } 351 else 352 { 353 return false; 354 } 355 } 356 } 357 358 /** 359 * Parse an IRI into scheme/authority/path/query/fragment segments 360 * 361 * @param string $iri 362 * @return array 363 */ 364 protected function parse_iri($iri) 365 { 366 $iri = trim($iri, "\x20\x09\x0A\x0C\x0D"); 367 if (preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match)) 368 { 369 if ($match[1] === '') 370 { 371 $match['scheme'] = null; 372 } 373 if (!isset($match[3]) || $match[3] === '') 374 { 375 $match['authority'] = null; 376 } 377 if (!isset($match[5])) 378 { 379 $match['path'] = ''; 380 } 381 if (!isset($match[6]) || $match[6] === '') 382 { 383 $match['query'] = null; 384 } 385 if (!isset($match[8]) || $match[8] === '') 386 { 387 $match['fragment'] = null; 388 } 389 return $match; 390 } 391 else 392 { 393 // This can occur when a paragraph is accidentally parsed as a URI 394 return false; 395 } 396 } 397 398 /** 399 * Remove dot segments from a path 400 * 401 * @param string $input 402 * @return string 403 */ 404 protected function remove_dot_segments($input) 405 { 406 $output = ''; 407 while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') 408 { 409 // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, 410 if (strpos($input, '../') === 0) 411 { 412 $input = substr($input, 3); 413 } 414 elseif (strpos($input, './') === 0) 415 { 416 $input = substr($input, 2); 417 } 418 // 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, 419 elseif (strpos($input, '/./') === 0) 420 { 421 $input = substr($input, 2); 422 } 423 elseif ($input === '/.') 424 { 425 $input = '/'; 426 } 427 // 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, 428 elseif (strpos($input, '/../') === 0) 429 { 430 $input = substr($input, 3); 431 $output = substr_replace($output, '', strrpos($output, '/')); 432 } 433 elseif ($input === '/..') 434 { 435 $input = '/'; 436 $output = substr_replace($output, '', strrpos($output, '/')); 437 } 438 // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, 439 elseif ($input === '.' || $input === '..') 440 { 441 $input = ''; 442 } 443 // 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 444 elseif (($pos = strpos($input, '/', 1)) !== false) 445 { 446 $output .= substr($input, 0, $pos); 447 $input = substr_replace($input, '', 0, $pos); 448 } 449 else 450 { 451 $output .= $input; 452 $input = ''; 453 } 454 } 455 return $output . $input; 456 } 457 458 /** 459 * Replace invalid character with percent encoding 460 * 461 * @param string $string Input string 462 * @param string $extra_chars Valid characters not in iunreserved or 463 * iprivate (this is ASCII-only) 464 * @param bool $iprivate Allow iprivate 465 * @return string 466 */ 467 protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) 468 { 469 // Normalize as many pct-encoded sections as possible 470 $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array($this, 'remove_iunreserved_percent_encoded'), $string); 471 472 // Replace invalid percent characters 473 $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string); 474 475 // Add unreserved and % to $extra_chars (the latter is safe because all 476 // pct-encoded sections are now valid). 477 $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%'; 478 479 // Now replace any bytes that aren't allowed with their pct-encoded versions 480 $position = 0; 481 $strlen = strlen($string); 482 while (($position += strspn($string, $extra_chars, $position)) < $strlen) 483 { 484 $value = ord($string[$position]); 485 486 // Start position 487 $start = $position; 488 489 // By default we are valid 490 $valid = true; 491 492 // No one byte sequences are valid due to the while. 493 // Two byte sequence: 494 if (($value & 0xE0) === 0xC0) 495 { 496 $character = ($value & 0x1F) << 6; 497 $length = 2; 498 $remaining = 1; 499 } 500 // Three byte sequence: 501 elseif (($value & 0xF0) === 0xE0) 502 { 503 $character = ($value & 0x0F) << 12; 504 $length = 3; 505 $remaining = 2; 506 } 507 // Four byte sequence: 508 elseif (($value & 0xF8) === 0xF0) 509 { 510 $character = ($value & 0x07) << 18; 511 $length = 4; 512 $remaining = 3; 513 } 514 // Invalid byte: 515 else 516 { 517 $valid = false; 518 $length = 1; 519 $remaining = 0; 520 } 521 522 if ($remaining) 523 { 524 if ($position + $length <= $strlen) 525 { 526 for ($position++; $remaining; $position++) 527 { 528 $value = ord($string[$position]); 529 530 // Check that the byte is valid, then add it to the character: 531 if (($value & 0xC0) === 0x80) 532 { 533 $character |= ($value & 0x3F) << (--$remaining * 6); 534 } 535 // If it is invalid, count the sequence as invalid and reprocess the current byte: 536 else 537 { 538 $valid = false; 539 $position--; 540 break; 541 } 542 } 543 } 544 else 545 { 546 $position = $strlen - 1; 547 $valid = false; 548 } 549 } 550 551 // Percent encode anything invalid or not in ucschar 552 if ( 553 // Invalid sequences 554 !$valid 555 // Non-shortest form sequences are invalid 556 || $length > 1 && $character <= 0x7F 557 || $length > 2 && $character <= 0x7FF 558 || $length > 3 && $character <= 0xFFFF 559 // Outside of range of ucschar codepoints 560 // Noncharacters 561 || ($character & 0xFFFE) === 0xFFFE 562 || $character >= 0xFDD0 && $character <= 0xFDEF 563 || ( 564 // Everything else not in ucschar 565 $character > 0xD7FF && $character < 0xF900 566 || $character < 0xA0 567 || $character > 0xEFFFD 568 ) 569 && ( 570 // Everything not in iprivate, if it applies 571 !$iprivate 572 || $character < 0xE000 573 || $character > 0x10FFFD 574 ) 575 ) 576 { 577 // If we were a character, pretend we weren't, but rather an error. 578 if ($valid) 579 $position--; 580 581 for ($j = $start; $j <= $position; $j++) 582 { 583 $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1); 584 $j += 2; 585 $position += 2; 586 $strlen += 2; 587 } 588 } 589 } 590 591 return $string; 592 } 593 594 /** 595 * Callback function for preg_replace_callback. 596 * 597 * Removes sequences of percent encoded bytes that represent UTF-8 598 * encoded characters in iunreserved 599 * 600 * @param array $match PCRE match 601 * @return string Replacement 602 */ 603 protected function remove_iunreserved_percent_encoded($match) 604 { 605 // As we just have valid percent encoded sequences we can just explode 606 // and ignore the first member of the returned array (an empty string). 607 $bytes = explode('%', $match[0]); 608 609 // Initialize the new string (this is what will be returned) and that 610 // there are no bytes remaining in the current sequence (unsurprising 611 // at the first byte!). 612 $string = ''; 613 $remaining = 0; 614 615 // Loop over each and every byte, and set $value to its value 616 for ($i = 1, $len = count($bytes); $i < $len; $i++) 617 { 618 $value = hexdec($bytes[$i]); 619 620 // If we're the first byte of sequence: 621 if (!$remaining) 622 { 623 // Start position 624 $start = $i; 625 626 // By default we are valid 627 $valid = true; 628 629 // One byte sequence: 630 if ($value <= 0x7F) 631 { 632 $character = $value; 633 $length = 1; 634 } 635 // Two byte sequence: 636 elseif (($value & 0xE0) === 0xC0) 637 { 638 $character = ($value & 0x1F) << 6; 639 $length = 2; 640 $remaining = 1; 641 } 642 // Three byte sequence: 643 elseif (($value & 0xF0) === 0xE0) 644 { 645 $character = ($value & 0x0F) << 12; 646 $length = 3; 647 $remaining = 2; 648 } 649 // Four byte sequence: 650 elseif (($value & 0xF8) === 0xF0) 651 { 652 $character = ($value & 0x07) << 18; 653 $length = 4; 654 $remaining = 3; 655 } 656 // Invalid byte: 657 else 658 { 659 $valid = false; 660 $remaining = 0; 661 } 662 } 663 // Continuation byte: 664 else 665 { 666 // Check that the byte is valid, then add it to the character: 667 if (($value & 0xC0) === 0x80) 668 { 669 $remaining--; 670 $character |= ($value & 0x3F) << ($remaining * 6); 671 } 672 // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence: 673 else 674 { 675 $valid = false; 676 $remaining = 0; 677 $i--; 678 } 679 } 680 681 // If we've reached the end of the current byte sequence, append it to Unicode::$data 682 if (!$remaining) 683 { 684 // Percent encode anything invalid or not in iunreserved 685 if ( 686 // Invalid sequences 687 !$valid 688 // Non-shortest form sequences are invalid 689 || $length > 1 && $character <= 0x7F 690 || $length > 2 && $character <= 0x7FF 691 || $length > 3 && $character <= 0xFFFF 692 // Outside of range of iunreserved codepoints 693 || $character < 0x2D 694 || $character > 0xEFFFD 695 // Noncharacters 696 || ($character & 0xFFFE) === 0xFFFE 697 || $character >= 0xFDD0 && $character <= 0xFDEF 698 // Everything else not in iunreserved (this is all BMP) 699 || $character === 0x2F 700 || $character > 0x39 && $character < 0x41 701 || $character > 0x5A && $character < 0x61 702 || $character > 0x7A && $character < 0x7E 703 || $character > 0x7E && $character < 0xA0 704 || $character > 0xD7FF && $character < 0xF900 705 ) 706 { 707 for ($j = $start; $j <= $i; $j++) 708 { 709 $string .= '%' . strtoupper($bytes[$j]); 710 } 711 } 712 else 713 { 714 for ($j = $start; $j <= $i; $j++) 715 { 716 $string .= chr(hexdec($bytes[$j])); 717 } 718 } 719 } 720 } 721 722 // If we have any bytes left over they are invalid (i.e., we are 723 // mid-way through a multi-byte sequence) 724 if ($remaining) 725 { 726 for ($j = $start; $j < $len; $j++) 727 { 728 $string .= '%' . strtoupper($bytes[$j]); 729 } 730 } 731 732 return $string; 733 } 734 735 protected function scheme_normalization() 736 { 737 if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) 738 { 739 $this->iuserinfo = null; 740 } 741 if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) 742 { 743 $this->ihost = null; 744 } 745 if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) 746 { 747 $this->port = null; 748 } 749 if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) 750 { 751 $this->ipath = ''; 752 } 753 if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) 754 { 755 $this->iquery = null; 756 } 757 if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) 758 { 759 $this->ifragment = null; 760 } 761 } 762 763 /** 764 * Check if the object represents a valid IRI. This needs to be done on each 765 * call as some things change depending on another part of the IRI. 766 * 767 * @return bool 768 */ 769 public function is_valid() 770 { 771 $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null; 772 if ($this->ipath !== '' && 773 ( 774 $isauthority && ( 775 $this->ipath[0] !== '/' || 776 substr($this->ipath, 0, 2) === '//' 777 ) || 778 ( 779 $this->scheme === null && 780 !$isauthority && 781 strpos($this->ipath, ':') !== false && 782 (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/')) 783 ) 784 ) 785 ) 786 { 787 return false; 788 } 789 790 return true; 791 } 792 793 /** 794 * Set the entire IRI. Returns true on success, false on failure (if there 795 * are any invalid characters). 796 * 797 * @param string $iri 798 * @return bool 799 */ 800 public function set_iri($iri) 801 { 802 static $cache; 803 if (!$cache) 804 { 805 $cache = array(); 806 } 807 808 if ($iri === null) 809 { 810 return true; 811 } 812 elseif (isset($cache[$iri])) 813 { 814 list($this->scheme, 815 $this->iuserinfo, 816 $this->ihost, 817 $this->port, 818 $this->ipath, 819 $this->iquery, 820 $this->ifragment, 821 $return) = $cache[$iri]; 822 return $return; 823 } 824 else 825 { 826 $parsed = $this->parse_iri((string) $iri); 827 if (!$parsed) 828 { 829 return false; 830 } 831 832 $return = $this->set_scheme($parsed['scheme']) 833 && $this->set_authority($parsed['authority']) 834 && $this->set_path($parsed['path']) 835 && $this->set_query($parsed['query']) 836 && $this->set_fragment($parsed['fragment']); 837 838 $cache[$iri] = array($this->scheme, 839 $this->iuserinfo, 840 $this->ihost, 841 $this->port, 842 $this->ipath, 843 $this->iquery, 844 $this->ifragment, 845 $return); 846 return $return; 847 } 848 } 849 850 /** 851 * Set the scheme. Returns true on success, false on failure (if there are 852 * any invalid characters). 853 * 854 * @param string $scheme 855 * @return bool 856 */ 857 public function set_scheme($scheme) 858 { 859 if ($scheme === null) 860 { 861 $this->scheme = null; 862 } 863 elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) 864 { 865 $this->scheme = null; 866 return false; 867 } 868 else 869 { 870 $this->scheme = strtolower($scheme); 871 } 872 return true; 873 } 874 875 /** 876 * Set the authority. Returns true on success, false on failure (if there are 877 * any invalid characters). 878 * 879 * @param string $authority 880 * @return bool 881 */ 882 public function set_authority($authority) 883 { 884 static $cache; 885 if (!$cache) 886 $cache = array(); 887 888 if ($authority === null) 889 { 890 $this->iuserinfo = null; 891 $this->ihost = null; 892 $this->port = null; 893 return true; 894 } 895 elseif (isset($cache[$authority])) 896 { 897 list($this->iuserinfo, 898 $this->ihost, 899 $this->port, 900 $return) = $cache[$authority]; 901 902 return $return; 903 } 904 else 905 { 906 $remaining = $authority; 907 if (($iuserinfo_end = strrpos($remaining, '@')) !== false) 908 { 909 $iuserinfo = substr($remaining, 0, $iuserinfo_end); 910 $remaining = substr($remaining, $iuserinfo_end + 1); 911 } 912 else 913 { 914 $iuserinfo = null; 915 } 916 if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false) 917 { 918 if (($port = substr($remaining, $port_start + 1)) === false) 919 { 920 $port = null; 921 } 922 $remaining = substr($remaining, 0, $port_start); 923 } 924 else 925 { 926 $port = null; 927 } 928 929 $return = $this->set_userinfo($iuserinfo) && 930 $this->set_host($remaining) && 931 $this->set_port($port); 932 933 $cache[$authority] = array($this->iuserinfo, 934 $this->ihost, 935 $this->port, 936 $return); 937 938 return $return; 939 } 940 } 941 942 /** 943 * Set the iuserinfo. 944 * 945 * @param string $iuserinfo 946 * @return bool 947 */ 948 public function set_userinfo($iuserinfo) 949 { 950 if ($iuserinfo === null) 951 { 952 $this->iuserinfo = null; 953 } 954 else 955 { 956 $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+,;=:'); 957 $this->scheme_normalization(); 958 } 959 960 return true; 961 } 962 963 /** 964 * Set the ihost. Returns true on success, false on failure (if there are 965 * any invalid characters). 966 * 967 * @param string $ihost 968 * @return bool 969 */ 970 public function set_host($ihost) 971 { 972 if ($ihost === null) 973 { 974 $this->ihost = null; 975 return true; 976 } 977 elseif (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') 978 { 979 if (SimplePie_Net_IPv6::check_ipv6(substr($ihost, 1, -1))) 980 { 981 $this->ihost = '[' . SimplePie_Net_IPv6::compress(substr($ihost, 1, -1)) . ']'; 982 } 983 else 984 { 985 $this->ihost = null; 986 return false; 987 } 988 } 989 else 990 { 991 $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+,;='); 992 993 // Lowercase, but ignore pct-encoded sections (as they should 994 // remain uppercase). This must be done after the previous step 995 // as that can add unescaped characters. 996 $position = 0; 997 $strlen = strlen($ihost); 998 while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) 999 { 1000 if ($ihost[$position] === '%') 1001 { 1002 $position += 3; 1003 } 1004 else 1005 { 1006 $ihost[$position] = strtolower($ihost[$position]); 1007 $position++; 1008 } 1009 } 1010 1011 $this->ihost = $ihost; 1012 } 1013 1014 $this->scheme_normalization(); 1015 1016 return true; 1017 } 1018 1019 /** 1020 * Set the port. Returns true on success, false on failure (if there are 1021 * any invalid characters). 1022 * 1023 * @param string $port 1024 * @return bool 1025 */ 1026 public function set_port($port) 1027 { 1028 if ($port === null) 1029 { 1030 $this->port = null; 1031 return true; 1032 } 1033 elseif (strspn($port, '0123456789') === strlen($port)) 1034 { 1035 $this->port = (int) $port; 1036 $this->scheme_normalization(); 1037 return true; 1038 } 1039 else 1040 { 1041 $this->port = null; 1042 return false; 1043 } 1044 } 1045 1046 /** 1047 * Set the ipath. 1048 * 1049 * @param string $ipath 1050 * @return bool 1051 */ 1052 public function set_path($ipath) 1053 { 1054 static $cache; 1055 if (!$cache) 1056 { 1057 $cache = array(); 1058 } 1059 1060 $ipath = (string) $ipath; 1061 1062 if (isset($cache[$ipath])) 1063 { 1064 $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)]; 1065 } 1066 else 1067 { 1068 $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+,;=@:/'); 1069 $removed = $this->remove_dot_segments($valid); 1070 1071 $cache[$ipath] = array($valid, $removed); 1072 $this->ipath = ($this->scheme !== null) ? $removed : $valid; 1073 } 1074 1075 $this->scheme_normalization(); 1076 return true; 1077 } 1078 1079 /** 1080 * Set the iquery. 1081 * 1082 * @param string $iquery 1083 * @return bool 1084 */ 1085 public function set_query($iquery) 1086 { 1087 if ($iquery === null) 1088 { 1089 $this->iquery = null; 1090 } 1091 else 1092 { 1093 $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+,;=:@/?', true); 1094 $this->scheme_normalization(); 1095 } 1096 return true; 1097 } 1098 1099 /** 1100 * Set the ifragment. 1101 * 1102 * @param string $ifragment 1103 * @return bool 1104 */ 1105 public function set_fragment($ifragment) 1106 { 1107 if ($ifragment === null) 1108 { 1109 $this->ifragment = null; 1110 } 1111 else 1112 { 1113 $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+,;=:@/?'); 1114 $this->scheme_normalization(); 1115 } 1116 return true; 1117 } 1118 1119 /** 1120 * Convert an IRI to a URI (or parts thereof) 1121 * 1122 * @return string 1123 */ 1124 public function to_uri($string) 1125 { 1126 static $non_ascii; 1127 if (!$non_ascii) 1128 { 1129 $non_ascii = implode('', range("\x80", "\xFF")); 1130 } 1131 1132 $position = 0; 1133 $strlen = strlen($string); 1134 while (($position += strcspn($string, $non_ascii, $position)) < $strlen) 1135 { 1136 $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1); 1137 $position += 3; 1138 $strlen += 2; 1139 } 1140 1141 return $string; 1142 } 1143 1144 /** 1145 * Get the complete IRI 1146 * 1147 * @return string 1148 */ 1149 public function get_iri() 1150 { 1151 if (!$this->is_valid()) 1152 { 1153 return false; 1154 } 1155 1156 $iri = ''; 1157 if ($this->scheme !== null) 1158 { 1159 $iri .= $this->scheme . ':'; 1160 } 1161 if (($iauthority = $this->get_iauthority()) !== null) 1162 { 1163 $iri .= '//' . $iauthority; 1164 } 1165 if ($this->ipath !== '') 1166 { 1167 $iri .= $this->ipath; 1168 } 1169 elseif (!empty($this->normalization[$this->scheme]['ipath']) && $iauthority !== null && $iauthority !== '') 1170 { 1171 $iri .= $this->normalization[$this->scheme]['ipath']; 1172 } 1173 if ($this->iquery !== null) 1174 { 1175 $iri .= '?' . $this->iquery; 1176 } 1177 if ($this->ifragment !== null) 1178 { 1179 $iri .= '#' . $this->ifragment; 1180 } 1181 1182 return $iri; 1183 } 1184 1185 /** 1186 * Get the complete URI 1187 * 1188 * @return string 1189 */ 1190 public function get_uri() 1191 { 1192 return $this->to_uri($this->get_iri()); 1193 } 1194 1195 /** 1196 * Get the complete iauthority 1197 * 1198 * @return string 1199 */ 1200 protected function get_iauthority() 1201 { 1202 if ($this->iuserinfo !== null || $this->ihost !== null || $this->port !== null) 1203 { 1204 $iauthority = ''; 1205 if ($this->iuserinfo !== null) 1206 { 1207 $iauthority .= $this->iuserinfo . '@'; 1208 } 1209 if ($this->ihost !== null) 1210 { 1211 $iauthority .= $this->ihost; 1212 } 1213 if ($this->port !== null) 1214 { 1215 $iauthority .= ':' . $this->port; 1216 } 1217 return $iauthority; 1218 } 1219 else 1220 { 1221 return null; 1222 } 1223 } 1224 1225 /** 1226 * Get the complete authority 1227 * 1228 * @return string 1229 */ 1230 protected function get_authority() 1231 { 1232 $iauthority = $this->get_iauthority(); 1233 if (is_string($iauthority)) 1234 return $this->to_uri($iauthority); 1235 else 1236 return $iauthority; 1237 } 1238 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |