/src/Symfony/Component/Security/Http/HttpUtils.php

https://github.com/pulzarraider/symfony · PHP · 185 lines · 102 code · 22 blank · 61 comment · 26 complexity · 68e3a31b88a3f045d1f86079dd37e64c MD5 · raw file

  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Security\Http;
  11. use Symfony\Component\HttpFoundation\RedirectResponse;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\Routing\Exception\MethodNotAllowedException;
  14. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  15. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  16. use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
  17. use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
  18. use Symfony\Component\Security\Core\Security;
  19. /**
  20. * Encapsulates the logic needed to create sub-requests, redirect the user, and match URLs.
  21. *
  22. * @author Fabien Potencier <fabien@symfony.com>
  23. */
  24. class HttpUtils
  25. {
  26. private $urlGenerator;
  27. private $urlMatcher;
  28. private $domainRegexp;
  29. private $secureDomainRegexp;
  30. /**
  31. * @param UrlGeneratorInterface $urlGenerator A UrlGeneratorInterface instance
  32. * @param UrlMatcherInterface|RequestMatcherInterface $urlMatcher The URL or Request matcher
  33. * @param string|null $domainRegexp A regexp the target of HTTP redirections must match, scheme included
  34. * @param string|null $secureDomainRegexp A regexp the target of HTTP redirections must match when the scheme is "https"
  35. *
  36. * @throws \InvalidArgumentException
  37. */
  38. public function __construct(UrlGeneratorInterface $urlGenerator = null, $urlMatcher = null, string $domainRegexp = null, string $secureDomainRegexp = null)
  39. {
  40. $this->urlGenerator = $urlGenerator;
  41. if (null !== $urlMatcher && !$urlMatcher instanceof UrlMatcherInterface && !$urlMatcher instanceof RequestMatcherInterface) {
  42. throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.');
  43. }
  44. $this->urlMatcher = $urlMatcher;
  45. $this->domainRegexp = $domainRegexp;
  46. $this->secureDomainRegexp = $secureDomainRegexp;
  47. }
  48. /**
  49. * Creates a redirect Response.
  50. *
  51. * @param Request $request A Request instance
  52. * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo))
  53. * @param int $status The status code
  54. *
  55. * @return RedirectResponse A RedirectResponse instance
  56. */
  57. public function createRedirectResponse(Request $request, $path, $status = 302)
  58. {
  59. if (null !== $this->secureDomainRegexp && 'https' === $this->urlMatcher->getContext()->getScheme() && preg_match('#^https?:[/\\\\]{2,}+[^/]++#i', $path, $host) && !preg_match(sprintf($this->secureDomainRegexp, preg_quote($request->getHttpHost())), $host[0])) {
  60. $path = '/';
  61. }
  62. if (null !== $this->domainRegexp && preg_match('#^https?:[/\\\\]{2,}+[^/]++#i', $path, $host) && !preg_match(sprintf($this->domainRegexp, preg_quote($request->getHttpHost())), $host[0])) {
  63. $path = '/';
  64. }
  65. return new RedirectResponse($this->generateUri($request, $path), $status);
  66. }
  67. /**
  68. * Creates a Request.
  69. *
  70. * @param Request $request The current Request instance
  71. * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo))
  72. *
  73. * @return Request A Request instance
  74. */
  75. public function createRequest(Request $request, $path)
  76. {
  77. $newRequest = Request::create($this->generateUri($request, $path), 'get', [], $request->cookies->all(), [], $request->server->all());
  78. static $setSession;
  79. if (null === $setSession) {
  80. $setSession = \Closure::bind(function ($newRequest, $request) { $newRequest->session = $request->session; }, null, Request::class);
  81. }
  82. $setSession($newRequest, $request);
  83. if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) {
  84. $newRequest->attributes->set(Security::AUTHENTICATION_ERROR, $request->attributes->get(Security::AUTHENTICATION_ERROR));
  85. }
  86. if ($request->attributes->has(Security::ACCESS_DENIED_ERROR)) {
  87. $newRequest->attributes->set(Security::ACCESS_DENIED_ERROR, $request->attributes->get(Security::ACCESS_DENIED_ERROR));
  88. }
  89. if ($request->attributes->has(Security::LAST_USERNAME)) {
  90. $newRequest->attributes->set(Security::LAST_USERNAME, $request->attributes->get(Security::LAST_USERNAME));
  91. }
  92. if ($request->get('_format')) {
  93. $newRequest->attributes->set('_format', $request->get('_format'));
  94. }
  95. if ($request->getDefaultLocale() !== $request->getLocale()) {
  96. $newRequest->setLocale($request->getLocale());
  97. }
  98. return $newRequest;
  99. }
  100. /**
  101. * Checks that a given path matches the Request.
  102. *
  103. * @param Request $request A Request instance
  104. * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo))
  105. *
  106. * @return bool true if the path is the same as the one from the Request, false otherwise
  107. */
  108. public function checkRequestPath(Request $request, $path)
  109. {
  110. if ('/' !== $path[0]) {
  111. try {
  112. // matching a request is more powerful than matching a URL path + context, so try that first
  113. if ($this->urlMatcher instanceof RequestMatcherInterface) {
  114. $parameters = $this->urlMatcher->matchRequest($request);
  115. } else {
  116. $parameters = $this->urlMatcher->match($request->getPathInfo());
  117. }
  118. return isset($parameters['_route']) && $path === $parameters['_route'];
  119. } catch (MethodNotAllowedException $e) {
  120. return false;
  121. } catch (ResourceNotFoundException $e) {
  122. return false;
  123. }
  124. }
  125. return $path === rawurldecode($request->getPathInfo());
  126. }
  127. /**
  128. * Generates a URI, based on the given path or absolute URL.
  129. *
  130. * @param Request $request A Request instance
  131. * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo))
  132. *
  133. * @return string An absolute URL
  134. *
  135. * @throws \LogicException
  136. */
  137. public function generateUri($request, $path)
  138. {
  139. if (0 === strpos($path, 'http') || !$path) {
  140. return $path;
  141. }
  142. if ('/' === $path[0]) {
  143. return $request->getUriForPath($path);
  144. }
  145. if (null === $this->urlGenerator) {
  146. throw new \LogicException('You must provide a UrlGeneratorInterface instance to be able to use routes.');
  147. }
  148. $url = $this->urlGenerator->generate($path, $request->attributes->all(), UrlGeneratorInterface::ABSOLUTE_URL);
  149. // unnecessary query string parameters must be removed from URL
  150. // (ie. query parameters that are presents in $attributes)
  151. // fortunately, they all are, so we have to remove entire query string
  152. $position = strpos($url, '?');
  153. if (false !== $position) {
  154. $fragment = parse_url($url, PHP_URL_FRAGMENT);
  155. $url = substr($url, 0, $position);
  156. // fragment must be preserved
  157. if ($fragment) {
  158. $url .= "#$fragment";
  159. }
  160. }
  161. return $url;
  162. }
  163. }