Class
StaticFiles
Serves the files of a directory, and passes every other request on to the application's handler.
Introduction#
It is what --public=<dir> installs; wrap your own handler for the same behaviour.
A GET or HEAD request whose path names a file below the directory gets that file: streamed,
with its Content-Type (by extension), Content-Length, Last-Modified and ETag; 304 Not Modified for If-None-Match or If-Modified-Since; a single byte range (Range: bytes=) as
206 Partial Content, or 416 when it lies past the end. A directory is served by its
index.html, after a redirect to the path with a trailing slash.
Not served, but passed on to the application: other methods, a path that leaves the
directory (.., a symlink pointing outside it), a name starting with a dot (.env,
.git/; .well-known/ is served), a PHP file (.php, .phtml, .phar, .inc: a source is
never sent), and a directory without index.html. Nothing is ever listed.
Class synopsis#
final class StaticFiles {
/* Methods */
public StaticFiles::__construct(string $directory)
public StaticFiles::wrap(Closure $app): Closure
}Methods#
| Method | Description |
|---|---|
__construct | Serve the files below $directory. |
wrap | A handler that answers the requests naming a file from the directory, and calls $app for every other. |
Examples#
use Swerve\ClientRequest;
use Swerve\RequestHandler;
use Swerve\StaticFiles;
// Files below public/ are served; every other request reaches the application
$files = new StaticFiles(__DIR__ . '/public');
$app = new RequestHandler($files->wrap(function (ClientRequest $request) {
$request->sendResponseHeaders(404, ['content-type' => 'text/plain']);
$request->write("No page at {$request->getTarget()}\n");
}));
if (debug_backtrace()) {
return $app; // swerve loads this file: it is the application's swerve.php
}
// Run directly: serve the application with swerve, and send it requests
require __DIR__ . '/../serve.php';
touch(__DIR__ . '/public/hello.txt', 1767225600); // a fixed date, for the same output every run
serve(__FILE__, [
"GET /hello.txt HTTP/1.1\r\nHost: example\r\n\r\n",
"GET /missing.txt HTTP/1.1\r\nHost: example\r\n\r\n",
]);HTTP/1.1 200 OK Content-Type: text/plain; charset=utf-8 Last-Modified: Thu, 01 Jan 2026 00:00:00 GMT ETag: "6955b900-12" Accept-Ranges: bytes Server: Swerve Content-Length: 18 Connection: close Hello from a file HTTP/1.1 404 Not Found content-type: text/plain Server: Swerve Transfer-Encoding: chunked Connection: close 18 No page at /missing.txt 0
$files = new Swerve\StaticFiles(__DIR__ . '/public');
return new Swerve\RequestHandler($files->wrap(function (Swerve\ClientRequest $request) {
// what is not a file
}));