[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

/wp-includes/SimplePie/ -> IRI.php (source)

   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  }


Generated: Sat Nov 23 20:47:33 2019 Cross-referenced by PHPXref 0.7