1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\HttpFoundation;
13
14use Symfony\Component\Routing\RequestContext;
15
16/**
17 * A helper service for manipulating URLs within and outside the request scope.
18 *
19 * @author Valentin Udaltsov <udaltsov.valentin@gmail.com>
20 */
21final class UrlHelper
22{
23    private $requestStack;
24    private $requestContext;
25
26    public function __construct(RequestStack $requestStack, RequestContext $requestContext = null)
27    {
28        $this->requestStack = $requestStack;
29        $this->requestContext = $requestContext;
30    }
31
32    public function getAbsoluteUrl(string $path): string
33    {
34        if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) {
35            return $path;
36        }
37
38        if (null === $request = $this->requestStack->getMasterRequest()) {
39            return $this->getAbsoluteUrlFromContext($path);
40        }
41
42        if ('#' === $path[0]) {
43            $path = $request->getRequestUri().$path;
44        } elseif ('?' === $path[0]) {
45            $path = $request->getPathInfo().$path;
46        }
47
48        if (!$path || '/' !== $path[0]) {
49            $prefix = $request->getPathInfo();
50            $last = \strlen($prefix) - 1;
51            if ($last !== $pos = strrpos($prefix, '/')) {
52                $prefix = substr($prefix, 0, $pos).'/';
53            }
54
55            return $request->getUriForPath($prefix.$path);
56        }
57
58        return $request->getSchemeAndHttpHost().$path;
59    }
60
61    public function getRelativePath(string $path): string
62    {
63        if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) {
64            return $path;
65        }
66
67        if (null === $request = $this->requestStack->getMasterRequest()) {
68            return $path;
69        }
70
71        return $request->getRelativeUriForPath($path);
72    }
73
74    private function getAbsoluteUrlFromContext(string $path): string
75    {
76        if (null === $this->requestContext || '' === $host = $this->requestContext->getHost()) {
77            return $path;
78        }
79
80        $scheme = $this->requestContext->getScheme();
81        $port = '';
82
83        if ('http' === $scheme && 80 !== $this->requestContext->getHttpPort()) {
84            $port = ':'.$this->requestContext->getHttpPort();
85        } elseif ('https' === $scheme && 443 !== $this->requestContext->getHttpsPort()) {
86            $port = ':'.$this->requestContext->getHttpsPort();
87        }
88
89        if ('#' === $path[0]) {
90            $queryString = $this->requestContext->getQueryString();
91            $path = $this->requestContext->getPathInfo().($queryString ? '?'.$queryString : '').$path;
92        } elseif ('?' === $path[0]) {
93            $path = $this->requestContext->getPathInfo().$path;
94        }
95
96        if ('/' !== $path[0]) {
97            $path = rtrim($this->requestContext->getBaseUrl(), '/').'/'.$path;
98        }
99
100        return $scheme.'://'.$host.$port.$path;
101    }
102}
103