Verzeichnisstruktur phpBB-3.1.0


Veröffentlicht
27.10.2014

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