Skip to content

Commit

Permalink
Merge pull request #8 from clue/filesystem
Browse files Browse the repository at this point in the history
Rewrite FilesystemHandler, improve file access and directory listing, support caching headers
  • Loading branch information
clue authored Feb 10, 2021
2 parents e438803 + 58bdd89 commit ab7fd26
Show file tree
Hide file tree
Showing 7 changed files with 431 additions and 128 deletions.
7 changes: 3 additions & 4 deletions examples/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,11 @@
);
});

$app->redirect('/test', '/');

//$app->cgi('/adminer.php', __DIR__ . '/adminer.php');

$app->fs('/source/', __DIR__);
//$app->redirect('/source', '/source/');
$app->get('/LICENSE', new Frugal\FilesystemHandler(dirname(__DIR__) . '/LICENSE'));
$app->get('/source/{path:.*}', new Frugal\FilesystemHandler(dirname(__DIR__)));
$app->redirect('/source', '/source/');

$app->run();
$loop->run();
11 changes: 0 additions & 11 deletions src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,6 @@ public function redirect($route, $target, $code = 302)
});
}

public function fs(string $route, string $path)
{
$this->get(
rtrim($route, '/') . '[/{path:.*}]',
new RemoveLeadingPath(
$route,
new FsHandler($path)
)
);
}

public function cgi(string $route, string $path)
{
if (\php_sapi_name() === 'cli') {
Expand Down
113 changes: 113 additions & 0 deletions src/FilesystemHandler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php

namespace Frugal;

use Psr\Http\Message\ServerRequestInterface;
use React\Http\Message\Response;

class FilesystemHandler
{
private $root;

public function __construct(string $root)
{
$this->root = $root;
}

public function __invoke(ServerRequestInterface $request)
{
$local = $request->getAttribute('path', '');
$path = \rtrim($this->root . '/' . $local, '/');

// local path should not contain "./", "../", "//" or null bytes or start with slash
$valid = !\preg_match('#(?:^|/)..?(?:$|/)|^/|//|\x00#', $local);

\clearstatcache();
if ($valid && \is_dir($path)) {
if ($local !== '' && \substr($local, -1) !== '/') {
return new Response(
302,
[
'Location' => \basename($path) . '/'
]
);
}

$response = '<strong>' . $this->escapeHtml($local === '' ? '/' : $local) . '</strong>' . "\n<ul>\n";

if ($local !== '') {
$response .= ' <li><a href="../">../</a></li>' . "\n";
}

$files = \scandir($path);
foreach ($files as $file) {
if ($file === '.' || $file === '..') {
continue;
}

$dir = \is_dir($path . '/' . $file) ? '/' : '';
$response .= ' <li><a href="' . \rawurlencode($file) . $dir . '">' . $this->escapeHtml($file) . $dir . '</a></li>' . "\n";
}
$response .= '</ul>' . "\n";

return new Response(
200,
[
'Content-Type' => 'text/html; charset=utf-8'
],
$response
);
} elseif ($valid && \is_file($path)) {
if ($local !== '' && \substr($local, -1) === '/') {
return new Response(
302,
[
'Location' => '../' . \basename($path)
]
);
}

// Assign default MIME type here (same as nginx/Apache).
// Should use mime database in the future with fallback to given default.
// Browers are pretty good at figuring out the correct type if no charset attribute is given.
$headers = [
'Content-Type' => 'text/plain'
];

$stat = @\stat($path);
if ($stat !== false) {
$headers['Last-Modified'] = \gmdate('D, d M Y H:i:s', $stat['mtime']) . ' GMT';

if ($request->getHeaderLine('If-Modified-Since') === $headers['Last-Modified']) {
return new Response(304);
}
}

return new Response(
200,
$headers,
\file_get_contents($path)
);
} else {
return new Response(
404,
[
'Content-Type' => 'text/plain; charset=utf-8'
],
"Error 404: Not Found\n"
);
}
}

private function escapeHtml(string $s): string
{
return \addcslashes(
\str_replace(
' ',
'&nbsp;',
\htmlspecialchars($s, \ENT_NOQUOTES | \ENT_SUBSTITUTE | \ENT_DISALLOWED, 'utf-8')
),
"\0..\032\\"
);
}
}
84 changes: 0 additions & 84 deletions src/FsHandler.php

This file was deleted.

28 changes: 0 additions & 28 deletions src/RemoveLeadingPath.php

This file was deleted.

Loading

0 comments on commit ab7fd26

Please sign in to comment.