Initial commit.
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'name' => 'My Site',
|
||||||
|
'debug' => false,
|
||||||
|
];
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'GET' => [
|
||||||
|
'/' => 'home.php',
|
||||||
|
'/about' => 'about.php',
|
||||||
|
],
|
||||||
|
/* Some Examples
|
||||||
|
'POST' => [
|
||||||
|
'/contact' => 'contact.php',
|
||||||
|
],
|
||||||
|
'DELETE' => [
|
||||||
|
'/api/todo' => 'delete_todo.php',
|
||||||
|
],
|
||||||
|
*/
|
||||||
|
];
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
define('ROOT', __DIR__);
|
||||||
|
require ROOT . '/src/bootstrap.php';
|
||||||
|
require ROOT . '/src/router.php';
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
HOST="${HOST:-127.0.0.1}"
|
||||||
|
PORT="${PORT:-3333}"
|
||||||
|
|
||||||
|
echo "Starting development server..."
|
||||||
|
echo "URL: http://${HOST}:${PORT}"
|
||||||
|
|
||||||
|
php -S "${HOST}:${PORT}" index.php
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
// Add the helpers globally
|
||||||
|
require_once ROOT . '/src/helpers.php';
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
|
||||||
|
function escape_string(string $value): string
|
||||||
|
{
|
||||||
|
return htmlspecialchars(
|
||||||
|
$value,
|
||||||
|
ENT_QUOTES | ENT_SUBSTITUTE,
|
||||||
|
'UTF-8'
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<?php declare(strict_types=1);
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Parse request URI
|
||||||
|
// Examples:
|
||||||
|
// / => /
|
||||||
|
// /about => /about
|
||||||
|
// /about/ => /about
|
||||||
|
// /about?id=1 => /about
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
$uri = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH);
|
||||||
|
|
||||||
|
if (!is_string($uri)) {
|
||||||
|
http_response_code(400);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = rtrim($uri, '/');
|
||||||
|
$uri = $uri ?: '/';
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Request method
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
$method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Load route configuration
|
||||||
|
// config/routes.php:
|
||||||
|
// return [
|
||||||
|
// 'GET' => [
|
||||||
|
// '/' => 'home.php',
|
||||||
|
// '/about' => 'about.php',
|
||||||
|
// ],
|
||||||
|
// ];
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
$routes = require ROOT . '/config/routes.php';
|
||||||
|
|
||||||
|
if (!is_array($routes)) {
|
||||||
|
error_log('Router: routes.php must return an array');
|
||||||
|
http_response_code(500);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Find matching route
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
$route = $routes[$method][$uri] ?? null;
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Base directory containing all page files
|
||||||
|
// Every routed file MUST live inside this directory.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
$base = realpath(ROOT . '/src/views/pages');
|
||||||
|
|
||||||
|
if ($base === false) {
|
||||||
|
error_log('Router: pages directory not found');
|
||||||
|
http_response_code(500);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Route not found
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
if ($route === null) {
|
||||||
|
http_response_code(404);
|
||||||
|
$route = '404.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Resolve requested file
|
||||||
|
// realpath() converts:
|
||||||
|
// home.php
|
||||||
|
// ../home.php
|
||||||
|
// ../../etc/passwd
|
||||||
|
// into an absolute canonical path.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
$real = realpath($base . '/' . $route);
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Path traversal protection
|
||||||
|
// Only allow files that resolve inside:
|
||||||
|
// src/views/pages/
|
||||||
|
//
|
||||||
|
// This blocks attempts such as:
|
||||||
|
// ../../etc/passwd
|
||||||
|
// ../../../secret.php
|
||||||
|
// even if they somehow end up in the route table.
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if ($real === false || !str_starts_with($real, $base . DIRECTORY_SEPARATOR)) {
|
||||||
|
error_log("Router: invalid route target [$route]");
|
||||||
|
http_response_code(403);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Dispatch request
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
require $real;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<p>about</p>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<p>home</p>
|
||||||
Reference in New Issue
Block a user