-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathPathMiddleware.php
102 lines (86 loc) · 3.95 KB
/
PathMiddleware.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
<?php declare(strict_types=1);
/*
* This file is part of Flight Routing.
*
* PHP version 8.0 and above required
*
* @author Divine Niiquaye Ibok <divineibok@gmail.com>
* @copyright 2019 Divine Niiquaye Ibok (https://divinenii.com/)
* @license https://opensource.org/licenses/BSD-3-Clause License
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flight\Routing\Middlewares;
use Flight\Routing\Router;
use Psr\Http\Message\{ResponseInterface, ServerRequestInterface, UriInterface};
use Psr\Http\Server\{MiddlewareInterface, RequestHandlerInterface};
/**
* This middleware increases SEO (search engine optimization) by preventing duplication
* of content at different URLs including resolving sub-directory paths.
*
* The response status code is 302 if the permanent parameter is false (default),
* and 301 if the redirection is permanent on redirection. If keep request method
* parameter is true, response code 307, and if permanent is true status code is 308.
*
* @author Divine Niiquaye Ibok <divineibok@gmail.com>
*/
final class PathMiddleware implements MiddlewareInterface
{
/**
* Slashes supported on browser when used.
*/
public const SUB_FOLDER = __CLASS__.'::subFolder';
/** @var array<string,string> */
private array $uriSuffixes = [];
/**
* @param bool $permanent Whether the redirection is permanent
* @param bool $keepRequestMethod Whether redirect action should keep HTTP request method
* @param array<int,string> $uriSuffixes List of slashes to re-route, defaults to ['/']
*/
public function __construct(
private bool $permanent = false,
private bool $keepRequestMethod = false,
array $uriSuffixes = []
) {
$this->permanent = $permanent;
$this->keepRequestMethod = $keepRequestMethod;
$this->uriSuffixes = empty($uriSuffixes) ? ['/' => '/'] : \array_combine($uriSuffixes, $uriSuffixes);
}
/**
* {@inheritdoc}
*/
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$requestPath = ($requestUri = self::resolveUri($request))->getPath(); // Determine right request uri path.
$response = $handler->handle($request);
if (!empty($route = $request->getAttribute(Router::class, []))) {
$this->uriSuffixes['/'] ??= '/';
$routeEndTail = $this->uriSuffixes[$route['path'][-1]] ?? null;
$requestEndTail = $this->uriSuffixes[$requestPath[-1]] ?? null;
if ($requestEndTail === $requestPath || $routeEndTail === $requestEndTail) {
return $response;
}
// Resolve request tail end to avoid conflicts and infinite redirection looping ...
if (null === $requestEndTail && null !== $routeEndTail) {
$requestPath .= $routeEndTail;
} elseif (null === $routeEndTail && $requestEndTail) {
$requestPath = \substr($requestPath, 0, -1);
}
$statusCode = $this->keepRequestMethod ? ($this->permanent ? 308 : 307) : ($this->permanent ? 301 : 302);
$response = $response->withHeader('Location', (string) $requestUri->withPath($requestPath))->withStatus($statusCode);
}
return $response;
}
public static function resolveUri(ServerRequestInterface &$request): UriInterface
{
$requestUri = $request->getUri();
$pathInfo = $request->getServerParams()['PATH_INFO'] ?? '';
// Checks if the project is in a sub-directory, expect PATH_INFO in $_SERVER.
if ('' !== $pathInfo && $pathInfo !== $requestUri->getPath()) {
$request = $request->withAttribute(self::SUB_FOLDER, \substr($requestUri->getPath(), 0, -\strlen($pathInfo)));
return $requestUri->withPath($pathInfo);
}
return $requestUri;
}
}