Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

UrlGenerator.php

Zuletzt modifiziert: 09.10.2024, 12:56 - Dateigröße: 13.83 KiB


001  <?php
002   
003  /*
004   * This file is part of the Symfony package.
005   *
006   * (c) Fabien Potencier <fabien@symfony.com>
007   *
008   * For the full copyright and license information, please view the LICENSE
009   * file that was distributed with this source code.
010   */
011   
012  namespace Symfony\Component\Routing\Generator;
013   
014  use Symfony\Component\Routing\RouteCollection;
015  use Symfony\Component\Routing\RequestContext;
016  use Symfony\Component\Routing\Exception\InvalidParameterException;
017  use Symfony\Component\Routing\Exception\RouteNotFoundException;
018  use Symfony\Component\Routing\Exception\MissingMandatoryParametersException;
019  use Psr\Log\LoggerInterface;
020   
021  /**
022   * UrlGenerator can generate a URL or a path for any route in the RouteCollection
023   * based on the passed parameters.
024   *
025   * @author Fabien Potencier <fabien@symfony.com>
026   * @author Tobias Schultze <http://tobion.de>
027   */
028  class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInterface
029  {
030      /**
031       * @var RouteCollection
032       */
033      protected $routes;
034   
035      /**
036       * @var RequestContext
037       */
038      protected $context;
039   
040      /**
041       * @var bool|null
042       */
043      protected $strictRequirements = true;
044   
045      /**
046       * @var LoggerInterface|null
047       */
048      protected $logger;
049   
050      /**
051       * This array defines the characters (besides alphanumeric ones) that will not be percent-encoded in the path segment of the generated URL.
052       *
053       * PHP's rawurlencode() encodes all chars except "a-zA-Z0-9-._~" according to RFC 3986. But we want to allow some chars
054       * to be used in their literal form (reasons below). Other chars inside the path must of course be encoded, e.g.
055       * "?" and "#" (would be interpreted wrongly as query and fragment identifier),
056       * "'" and """ (are used as delimiters in HTML).
057       */
058      protected $decodedChars = array(
059          // the slash can be used to designate a hierarchical structure and we want allow using it with this meaning
060          // some webservers don't allow the slash in encoded form in the path for security reasons anyway
061          // see http://stackoverflow.com/questions/4069002/http-400-if-2f-part-of-get-url-in-jboss
062          '%2F' => '/',
063          // the following chars are general delimiters in the URI specification but have only special meaning in the authority component
064          // so they can safely be used in the path in unencoded form
065          '%40' => '@',
066          '%3A' => ':',
067          // these chars are only sub-delimiters that have no predefined meaning and can therefore be used literally
068          // so URI producing applications can use these chars to delimit subcomponents in a path segment without being encoded for better readability
069          '%3B' => ';',
070          '%2C' => ',',
071          '%3D' => '=',
072          '%2B' => '+',
073          '%21' => '!',
074          '%2A' => '*',
075          '%7C' => '|',
076      );
077   
078      /**
079       * Constructor.
080       *
081       * @param RouteCollection      $routes  A RouteCollection instance
082       * @param RequestContext       $context The context
083       * @param LoggerInterface|null $logger  A logger instance
084       */
085      public function __construct(RouteCollection $routes, RequestContext $context, LoggerInterface $logger = null)
086      {
087          $this->routes = $routes;
088          $this->context = $context;
089          $this->logger = $logger;
090      }
091   
092      /**
093       * {@inheritdoc}
094       */
095      public function setContext(RequestContext $context)
096      {
097          $this->context = $context;
098      }
099   
100      /**
101       * {@inheritdoc}
102       */
103      public function getContext()
104      {
105          return $this->context;
106      }
107   
108      /**
109       * {@inheritdoc}
110       */
111      public function setStrictRequirements($enabled)
112      {
113          $this->strictRequirements = null === $enabled ? null : (bool) $enabled;
114      }
115   
116      /**
117       * {@inheritdoc}
118       */
119      public function isStrictRequirements()
120      {
121          return $this->strictRequirements;
122      }
123   
124      /**
125       * {@inheritdoc}
126       */
127      public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH)
128      {
129          if (null === $route = $this->routes->get($name)) {
130              throw new RouteNotFoundException(sprintf('Unable to generate a URL for the named route "%s" as such route does not exist.', $name));
131          }
132   
133          // the Route has a cache of its own and is not recompiled as long as it does not get modified
134          $compiledRoute = $route->compile();
135   
136          return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $referenceType, $compiledRoute->getHostTokens(), $route->getSchemes());
137      }
138   
139      /**
140       * @throws MissingMandatoryParametersException When some parameters are missing that are mandatory for the route
141       * @throws InvalidParameterException           When a parameter value for a placeholder is not correct because
142       *                                             it does not match the requirement
143       */
144      protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, array $requiredSchemes = array())
145      {
146          if (is_bool($referenceType) || is_string($referenceType)) {
147              @trigger_error('The hardcoded value you are using for the $referenceType argument of the '.__CLASS__.'::generate method is deprecated since version 2.8 and will not be supported anymore in 3.0. Use the constants defined in the UrlGeneratorInterface instead.', E_USER_DEPRECATED);
148   
149              if (true === $referenceType) {
150                  $referenceType = self::ABSOLUTE_URL;
151              } elseif (false === $referenceType) {
152                  $referenceType = self::ABSOLUTE_PATH;
153              } elseif ('relative' === $referenceType) {
154                  $referenceType = self::RELATIVE_PATH;
155              } elseif ('network' === $referenceType) {
156                  $referenceType = self::NETWORK_PATH;
157              }
158          }
159   
160          $variables = array_flip($variables);
161          $mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters);
162   
163          // all params must be given
164          if ($diff = array_diff_key($variables, $mergedParams)) {
165              throw new MissingMandatoryParametersException(sprintf('Some mandatory parameters are missing ("%s") to generate a URL for route "%s".', implode('", "', array_keys($diff)), $name));
166          }
167   
168          $url = '';
169          $optional = true;
170          foreach ($tokens as $token) {
171              if ('variable' === $token[0]) {
172                  if (!$optional || !array_key_exists($token[3], $defaults) || null !== $mergedParams[$token[3]] && (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) {
173                      // check requirement
174                      if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#', $mergedParams[$token[3]])) {
175                          $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given) to generate a corresponding URL.', $token[3], $name, $token[2], $mergedParams[$token[3]]);
176                          if ($this->strictRequirements) {
177                              throw new InvalidParameterException($message);
178                          }
179   
180                          if ($this->logger) {
181                              $this->logger->error($message);
182                          }
183   
184                          return;
185                      }
186   
187                      $url = $token[1].$mergedParams[$token[3]].$url;
188                      $optional = false;
189                  }
190              } else {
191                  // static text
192                  $url = $token[1].$url;
193                  $optional = false;
194              }
195          }
196   
197          if ('' === $url) {
198              $url = '/';
199          }
200   
201          // the contexts base URL is already encoded (see Symfony\Component\HttpFoundation\Request)
202          $url = strtr(rawurlencode($url), $this->decodedChars);
203   
204          // the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3
205          // so we need to encode them as they are not used for this purpose here
206          // otherwise we would generate a URI that, when followed by a user agent (e.g. browser), does not match this route
207          $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/'));
208          if ('/..' === substr($url, -3)) {
209              $url = substr($url, 0, -2).'%2E%2E';
210          } elseif ('/.' === substr($url, -2)) {
211              $url = substr($url, 0, -1).'%2E';
212          }
213   
214          $schemeAuthority = '';
215          if ($host = $this->context->getHost()) {
216              $scheme = $this->context->getScheme();
217   
218              if ($requiredSchemes) {
219                  if (!in_array($scheme, $requiredSchemes, true)) {
220                      $referenceType = self::ABSOLUTE_URL;
221                      $scheme = current($requiredSchemes);
222                  }
223              } elseif (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme !== $req) {
224                  // We do this for BC; to be removed if _scheme is not supported anymore
225                  $referenceType = self::ABSOLUTE_URL;
226                  $scheme = $req;
227              }
228   
229              if ($hostTokens) {
230                  $routeHost = '';
231                  foreach ($hostTokens as $token) {
232                      if ('variable' === $token[0]) {
233                          if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#i', $mergedParams[$token[3]])) {
234                              $message = sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given) to generate a corresponding URL.', $token[3], $name, $token[2], $mergedParams[$token[3]]);
235   
236                              if ($this->strictRequirements) {
237                                  throw new InvalidParameterException($message);
238                              }
239   
240                              if ($this->logger) {
241                                  $this->logger->error($message);
242                              }
243   
244                              return;
245                          }
246   
247                          $routeHost = $token[1].$mergedParams[$token[3]].$routeHost;
248                      } else {
249                          $routeHost = $token[1].$routeHost;
250                      }
251                  }
252   
253                  if ($routeHost !== $host) {
254                      $host = $routeHost;
255                      if (self::ABSOLUTE_URL !== $referenceType) {
256                          $referenceType = self::NETWORK_PATH;
257                      }
258                  }
259              }
260   
261              if (self::ABSOLUTE_URL === $referenceType || self::NETWORK_PATH === $referenceType) {
262                  $port = '';
263                  if ('http' === $scheme && 80 != $this->context->getHttpPort()) {
264                      $port = ':'.$this->context->getHttpPort();
265                  } elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) {
266                      $port = ':'.$this->context->getHttpsPort();
267                  }
268   
269                  $schemeAuthority = self::NETWORK_PATH === $referenceType ? '//' : "$scheme://";
270                  $schemeAuthority .= $host.$port;
271              }
272          }
273   
274          if (self::RELATIVE_PATH === $referenceType) {
275              $url = self::getRelativePath($this->context->getPathInfo(), $url);
276          } else {
277              $url = $schemeAuthority.$this->context->getBaseUrl().$url;
278          }
279   
280          // add a query string if needed
281          $extra = array_udiff_assoc(array_diff_key($parameters, $variables), $defaults, function ($a, $b) {
282              return $a == $b ? 0 : 1;
283          });
284   
285          if ($extra && $query = http_build_query($extra, '', '&')) {
286              // "/" and "?" can be left decoded for better user experience, see
287              // http://tools.ietf.org/html/rfc3986#section-3.4
288              $url .= '?'.strtr($query, array('%2F' => '/'));
289          }
290   
291          return $url;
292      }
293   
294      /**
295       * Returns the target path as relative reference from the base path.
296       *
297       * Only the URIs path component (no schema, host etc.) is relevant and must be given, starting with a slash.
298       * Both paths must be absolute and not contain relative parts.
299       * Relative URLs from one resource to another are useful when generating self-contained downloadable document archives.
300       * Furthermore, they can be used to reduce the link size in documents.
301       *
302       * Example target paths, given a base path of "/a/b/c/d":
303       * - "/a/b/c/d"     -> ""
304       * - "/a/b/c/"      -> "./"
305       * - "/a/b/"        -> "../"
306       * - "/a/b/c/other" -> "other"
307       * - "/a/x/y"       -> "../../x/y"
308       *
309       * @param string $basePath   The base path
310       * @param string $targetPath The target path
311       *
312       * @return string The relative target path
313       */
314      public static function getRelativePath($basePath, $targetPath)
315      {
316          if ($basePath === $targetPath) {
317              return '';
318          }
319   
320          $sourceDirs = explode('/', isset($basePath[0]) && '/' === $basePath[0] ? substr($basePath, 1) : $basePath);
321          $targetDirs = explode('/', isset($targetPath[0]) && '/' === $targetPath[0] ? substr($targetPath, 1) : $targetPath);
322          array_pop($sourceDirs);
323          $targetFile = array_pop($targetDirs);
324   
325          foreach ($sourceDirs as $i => $dir) {
326              if (isset($targetDirs[$i]) && $dir === $targetDirs[$i]) {
327                  unset($sourceDirs[$i], $targetDirs[$i]);
328              } else {
329                  break;
330              }
331          }
332   
333          $targetDirs[] = $targetFile;
334          $path = str_repeat('../', count($sourceDirs)).implode('/', $targetDirs);
335   
336          // A reference to the same base directory or an empty subdirectory must be prefixed with "./".
337          // This also applies to a segment with a colon character (e.g., "file:colon") that cannot be used
338          // as the first segment of a relative-path reference, as it would be mistaken for a scheme name
339          // (see http://tools.ietf.org/html/rfc3986#section-4.2).
340          return '' === $path || '/' === $path[0]
341              || false !== ($colonPos = strpos($path, ':')) && ($colonPos < ($slashPos = strpos($path, '/')) || false === $slashPos)
342              ? "./$path" : $path;
343      }
344  }
345