Includes new page templates (fitness-gym, nonprofit, online-course, photography-studio, real-estate, startup-company, travel-blog, wedding-invitation) with thumbnail SVGs, test specs, documentation files, and minor updates to index.html, router.php, and playwright config. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
91 lines
2.7 KiB
PHP
91 lines
2.7 KiB
PHP
<?php
|
|
/**
|
|
* PHP Built-in Server Router
|
|
*
|
|
* Usage: php -S localhost:8081 router.php
|
|
*
|
|
* Routes /api/* requests to api/index.php and serves all other
|
|
* requests as static files (same behavior as Apache with .htaccess).
|
|
*/
|
|
|
|
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
|
|
|
// Route API requests to the API handler
|
|
if (strpos($uri, '/api/') === 0) {
|
|
require __DIR__ . '/api/index.php';
|
|
return true;
|
|
}
|
|
|
|
// Serve static files
|
|
$filePath = __DIR__ . $uri;
|
|
if ($uri !== '/' && is_file($filePath)) {
|
|
// Video files need range request support for seeking
|
|
$ext = strtolower(pathinfo($filePath, PATHINFO_EXTENSION));
|
|
if (in_array($ext, ['mp4', 'webm', 'ogg', 'mov'])) {
|
|
serveVideoWithRangeSupport($filePath, $ext);
|
|
return true;
|
|
}
|
|
return false; // Let PHP's built-in server handle other files
|
|
}
|
|
|
|
// Default: serve index.html for directory requests
|
|
if (is_dir($filePath)) {
|
|
$indexPath = rtrim($filePath, '/') . '/index.html';
|
|
if (is_file($indexPath)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
|
|
/**
|
|
* Serve video files with HTTP Range request support (required for seeking).
|
|
* PHP's built-in server does not support Range requests for static files.
|
|
*/
|
|
function serveVideoWithRangeSupport($filePath, $ext) {
|
|
$mimeTypes = [
|
|
'mp4' => 'video/mp4',
|
|
'webm' => 'video/webm',
|
|
'ogg' => 'video/ogg',
|
|
'mov' => 'video/quicktime',
|
|
];
|
|
$mime = $mimeTypes[$ext] ?? 'application/octet-stream';
|
|
$fileSize = filesize($filePath);
|
|
|
|
header('Accept-Ranges: bytes');
|
|
header('Content-Type: ' . $mime);
|
|
|
|
if (isset($_SERVER['HTTP_RANGE'])) {
|
|
// Parse range header: "bytes=start-end"
|
|
if (preg_match('/bytes=(\d+)-(\d*)/', $_SERVER['HTTP_RANGE'], $matches)) {
|
|
$start = intval($matches[1]);
|
|
$end = $matches[2] !== '' ? intval($matches[2]) : $fileSize - 1;
|
|
|
|
if ($start > $end || $start >= $fileSize) {
|
|
http_response_code(416);
|
|
header("Content-Range: bytes */$fileSize");
|
|
return;
|
|
}
|
|
$end = min($end, $fileSize - 1);
|
|
$length = $end - $start + 1;
|
|
|
|
http_response_code(206);
|
|
header("Content-Range: bytes $start-$end/$fileSize");
|
|
header("Content-Length: $length");
|
|
|
|
$fp = fopen($filePath, 'rb');
|
|
fseek($fp, $start);
|
|
$remaining = $length;
|
|
while ($remaining > 0 && !feof($fp)) {
|
|
$chunk = min(8192, $remaining);
|
|
echo fread($fp, $chunk);
|
|
$remaining -= $chunk;
|
|
}
|
|
fclose($fp);
|
|
}
|
|
} else {
|
|
header("Content-Length: $fileSize");
|
|
readfile($filePath);
|
|
}
|
|
}
|