-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathStaticFileMiddleware.php
More file actions
89 lines (68 loc) · 2.55 KB
/
StaticFileMiddleware.php
File metadata and controls
89 lines (68 loc) · 2.55 KB
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
<?php
declare(strict_types=1);
namespace CrazyGoat\ReactPHPRuntime\Middleware;
use Fig\Http\Message\StatusCodeInterface;
use League\MimeTypeDetection\FinfoMimeTypeDetector;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use React\Http\Message\Response;
use React\Promise\PromiseInterface;
class StaticFileMiddleware implements MiddlewareInterface
{
use ReturnNextResponse;
public function __construct(private string $rootDirectory)
{
}
public function __invoke(ServerRequestInterface $request, callable $next): PromiseInterface|ResponseInterface
{
if ($this->rootDirectory === '' || $request->getUri()->getPath() === '/') {
return $this->returnResponse($next($request));
}
$fileCandidate = $this->sanitizePathInfo($request->getUri()->getPath(), $this->rootDirectory);
if ($fileCandidate === null) {
return $this->returnResponse($next($request));
}
if (!is_file($fileCandidate) || !is_readable($fileCandidate)) {
return $this->returnResponse($next($request));
}
return new Response(
StatusCodeInterface::STATUS_OK,
[
'Content-Type' => $this->getMimeType($fileCandidate),
'Content-Length' => strval(intval(filesize($fileCandidate))),
],
strval(file_get_contents($fileCandidate)),
);
}
private function sanitizePathInfo(string $pathInfo, string $baseDir): ?string
{
$pathInfo = urldecode($pathInfo);
$pathInfo = trim($pathInfo, '/');
$pathInfo = preg_replace('/(\/){2,}/', '/', $pathInfo);
$fullPath = $baseDir . '/' . $pathInfo;
$realPath = realpath($fullPath);
$baseDirPath = realpath($baseDir);
if ($realPath === false || $baseDirPath === false || !str_starts_with($realPath, $baseDirPath)) {
return null;
}
return $realPath;
}
private function getMimeType(string $filename): string
{
$typeDefault = 'application/octet-stream';
if (function_exists('mime_content_type')) {
$type = mime_content_type($filename);
if (is_string($type)) {
return $type;
}
}
if (class_exists(FinfoMimeTypeDetector::class)) {
$detector = new FinfoMimeTypeDetector();
$type = $detector->detectMimeTypeFromPath($filename);
if (is_string($type)) {
return $type;
}
}
return $typeDefault;
}
}