[ Index ]

PHP Cross Reference of phpBB-3.3.14-deutsch

title

Body

[close]

/vendor/guzzlehttp/psr7/src/ -> UriResolver.php (source)

   1  <?php
   2  
   3  namespace GuzzleHttp\Psr7;
   4  
   5  use Psr\Http\Message\UriInterface;
   6  
   7  /**
   8   * Resolves a URI reference in the context of a base URI and the opposite way.
   9   *
  10   * @author Tobias Schultze
  11   *
  12   * @link https://tools.ietf.org/html/rfc3986#section-5
  13   */
  14  final class UriResolver
  15  {
  16      /**
  17       * Removes dot segments from a path and returns the new path.
  18       *
  19       * @param string $path
  20       *
  21       * @return string
  22       *
  23       * @link http://tools.ietf.org/html/rfc3986#section-5.2.4
  24       */
  25      public static function removeDotSegments($path)
  26      {
  27          if ($path === '' || $path === '/') {
  28              return $path;
  29          }
  30  
  31          $results = [];
  32          $segments = explode('/', $path);
  33          foreach ($segments as $segment) {
  34              if ($segment === '..') {
  35                  array_pop($results);
  36              } elseif ($segment !== '.') {
  37                  $results[] = $segment;
  38              }
  39          }
  40  
  41          $newPath = implode('/', $results);
  42  
  43          if ($path[0] === '/' && (!isset($newPath[0]) || $newPath[0] !== '/')) {
  44              // Re-add the leading slash if necessary for cases like "/.."
  45              $newPath = '/' . $newPath;
  46          } elseif ($newPath !== '' && ($segment === '.' || $segment === '..')) {
  47              // Add the trailing slash if necessary
  48              // If newPath is not empty, then $segment must be set and is the last segment from the foreach
  49              $newPath .= '/';
  50          }
  51  
  52          return $newPath;
  53      }
  54  
  55      /**
  56       * Converts the relative URI into a new URI that is resolved against the base URI.
  57       *
  58       * @param UriInterface $base Base URI
  59       * @param UriInterface $rel  Relative URI
  60       *
  61       * @return UriInterface
  62       *
  63       * @link http://tools.ietf.org/html/rfc3986#section-5.2
  64       */
  65      public static function resolve(UriInterface $base, UriInterface $rel)
  66      {
  67          if ((string) $rel === '') {
  68              // we can simply return the same base URI instance for this same-document reference
  69              return $base;
  70          }
  71  
  72          if ($rel->getScheme() != '') {
  73              return $rel->withPath(self::removeDotSegments($rel->getPath()));
  74          }
  75  
  76          if ($rel->getAuthority() != '') {
  77              $targetAuthority = $rel->getAuthority();
  78              $targetPath = self::removeDotSegments($rel->getPath());
  79              $targetQuery = $rel->getQuery();
  80          } else {
  81              $targetAuthority = $base->getAuthority();
  82              if ($rel->getPath() === '') {
  83                  $targetPath = $base->getPath();
  84                  $targetQuery = $rel->getQuery() != '' ? $rel->getQuery() : $base->getQuery();
  85              } else {
  86                  if ($rel->getPath()[0] === '/') {
  87                      $targetPath = $rel->getPath();
  88                  } else {
  89                      if ($targetAuthority != '' && $base->getPath() === '') {
  90                          $targetPath = '/' . $rel->getPath();
  91                      } else {
  92                          $lastSlashPos = strrpos($base->getPath(), '/');
  93                          if ($lastSlashPos === false) {
  94                              $targetPath = $rel->getPath();
  95                          } else {
  96                              $targetPath = substr($base->getPath(), 0, $lastSlashPos + 1) . $rel->getPath();
  97                          }
  98                      }
  99                  }
 100                  $targetPath = self::removeDotSegments($targetPath);
 101                  $targetQuery = $rel->getQuery();
 102              }
 103          }
 104  
 105          return new Uri(Uri::composeComponents(
 106              $base->getScheme(),
 107              $targetAuthority,
 108              $targetPath,
 109              $targetQuery,
 110              $rel->getFragment()
 111          ));
 112      }
 113  
 114      /**
 115       * Returns the target URI as a relative reference from the base URI.
 116       *
 117       * This method is the counterpart to resolve():
 118       *
 119       *    (string) $target === (string) UriResolver::resolve($base, UriResolver::relativize($base, $target))
 120       *
 121       * One use-case is to use the current request URI as base URI and then generate relative links in your documents
 122       * to reduce the document size or offer self-contained downloadable document archives.
 123       *
 124       *    $base = new Uri('http://example.com/a/b/');
 125       *    echo UriResolver::relativize($base, new Uri('http://example.com/a/b/c'));  // prints 'c'.
 126       *    echo UriResolver::relativize($base, new Uri('http://example.com/a/x/y'));  // prints '../x/y'.
 127       *    echo UriResolver::relativize($base, new Uri('http://example.com/a/b/?q')); // prints '?q'.
 128       *    echo UriResolver::relativize($base, new Uri('http://example.org/a/b/'));   // prints '//example.org/a/b/'.
 129       *
 130       * This method also accepts a target that is already relative and will try to relativize it further. Only a
 131       * relative-path reference will be returned as-is.
 132       *
 133       *    echo UriResolver::relativize($base, new Uri('/a/b/c'));  // prints 'c' as well
 134       *
 135       * @param UriInterface $base   Base URI
 136       * @param UriInterface $target Target URI
 137       *
 138       * @return UriInterface The relative URI reference
 139       */
 140      public static function relativize(UriInterface $base, UriInterface $target)
 141      {
 142          if ($target->getScheme() !== '' &&
 143              ($base->getScheme() !== $target->getScheme() || $target->getAuthority() === '' && $base->getAuthority() !== '')
 144          ) {
 145              return $target;
 146          }
 147  
 148          if (Uri::isRelativePathReference($target)) {
 149              // As the target is already highly relative we return it as-is. It would be possible to resolve
 150              // the target with `$target = self::resolve($base, $target);` and then try make it more relative
 151              // by removing a duplicate query. But let's not do that automatically.
 152              return $target;
 153          }
 154  
 155          if ($target->getAuthority() !== '' && $base->getAuthority() !== $target->getAuthority()) {
 156              return $target->withScheme('');
 157          }
 158  
 159          // We must remove the path before removing the authority because if the path starts with two slashes, the URI
 160          // would turn invalid. And we also cannot set a relative path before removing the authority, as that is also
 161          // invalid.
 162          $emptyPathUri = $target->withScheme('')->withPath('')->withUserInfo('')->withPort(null)->withHost('');
 163  
 164          if ($base->getPath() !== $target->getPath()) {
 165              return $emptyPathUri->withPath(self::getRelativePath($base, $target));
 166          }
 167  
 168          if ($base->getQuery() === $target->getQuery()) {
 169              // Only the target fragment is left. And it must be returned even if base and target fragment are the same.
 170              return $emptyPathUri->withQuery('');
 171          }
 172  
 173          // If the base URI has a query but the target has none, we cannot return an empty path reference as it would
 174          // inherit the base query component when resolving.
 175          if ($target->getQuery() === '') {
 176              $segments = explode('/', $target->getPath());
 177              $lastSegment = end($segments);
 178  
 179              return $emptyPathUri->withPath($lastSegment === '' ? './' : $lastSegment);
 180          }
 181  
 182          return $emptyPathUri;
 183      }
 184  
 185      private static function getRelativePath(UriInterface $base, UriInterface $target)
 186      {
 187          $sourceSegments = explode('/', $base->getPath());
 188          $targetSegments = explode('/', $target->getPath());
 189          array_pop($sourceSegments);
 190          $targetLastSegment = array_pop($targetSegments);
 191          foreach ($sourceSegments as $i => $segment) {
 192              if (isset($targetSegments[$i]) && $segment === $targetSegments[$i]) {
 193                  unset($sourceSegments[$i], $targetSegments[$i]);
 194              } else {
 195                  break;
 196              }
 197          }
 198          $targetSegments[] = $targetLastSegment;
 199          $relativePath = str_repeat('../', count($sourceSegments)) . implode('/', $targetSegments);
 200  
 201          // A reference to am empty last segment or an empty first sub-segment must be prefixed with "./".
 202          // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
 203          // as the first segment of a relative-path reference, as it would be mistaken for a scheme name.
 204          if ('' === $relativePath || false !== strpos(explode('/', $relativePath, 2)[0], ':')) {
 205              $relativePath = "./$relativePath";
 206          } elseif ('/' === $relativePath[0]) {
 207              if ($base->getAuthority() != '' && $base->getPath() === '') {
 208                  // In this case an extra slash is added by resolve() automatically. So we must not add one here.
 209                  $relativePath = ".$relativePath";
 210              } else {
 211                  $relativePath = "./$relativePath";
 212              }
 213          }
 214  
 215          return $relativePath;
 216      }
 217  
 218      private function __construct()
 219      {
 220          // cannot be instantiated
 221      }
 222  }


Generated: Mon Nov 25 19:05:08 2024 Cross-referenced by PHPXref 0.7.1