From 3dc6a03be3503a0beeedfc90059edd70d9cbf8f2 Mon Sep 17 00:00:00 2001 From: Raruto Date: Wed, 20 Jan 2021 22:26:04 +0100 Subject: [PATCH 1/6] added simple routing script for built-in php server --- .ht.router.php | 41 +++++++++++++++++++++++++++++++++++++++++ index.php | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 .ht.router.php diff --git a/.ht.router.php b/.ht.router.php new file mode 100644 index 000000000..42e3c6e9f --- /dev/null +++ b/.ht.router.php @@ -0,0 +1,41 @@ + Date: Wed, 20 Jan 2021 22:49:11 +0100 Subject: [PATCH 2/6] mispelling --- .ht.router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ht.router.php b/.ht.router.php index 42e3c6e9f..8f454ef45 100644 --- a/.ht.router.php +++ b/.ht.router.php @@ -24,7 +24,7 @@ /* "dot" routes (see: https://bugs.php.net/bug.php?id=61286) */ $_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI']; - /* static files (eg. assetst/app/css/style.css) */ + /* static files (eg. assets/app/css/style.css) */ if (is_file($file) && $path["extension"] != "php") { if ($path["extension"] == "tag") { header("Content-Type: application/javascript"); From eb7415c9b252bd8766e9e00e610fed627deda77f Mon Sep 17 00:00:00 2001 From: Raruto Date: Thu, 21 Jan 2021 22:17:40 +0100 Subject: [PATCH 3/6] strict check --- .ht.router.php | 6 +++--- index.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.ht.router.php b/.ht.router.php index 8f454ef45..18be112fb 100644 --- a/.ht.router.php +++ b/.ht.router.php @@ -25,9 +25,9 @@ $_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI']; /* static files (eg. assets/app/css/style.css) */ - if (is_file($file) && $path["extension"] != "php") { - if ($path["extension"] == "tag") { - header("Content-Type: application/javascript"); + if (is_file($file) && $path['extension'] != "php") { + if ($path['extension'] == 'tag') { + header('Content-Type: application/javascript'); readfile($file); } return false; diff --git a/index.php b/index.php index f3cfb3f20..f9f9a028a 100644 --- a/index.php +++ b/index.php @@ -14,7 +14,7 @@ date_default_timezone_set('UTC'); // handle php webserver -if (PHP_SAPI == 'cli-server' && !include_once(__DIR__.'/.ht.router.php')) { +if (PHP_SAPI == 'cli-server' && false===include_once(__DIR__.'/.ht.router.php')) { return false; } From ba8cd379754068c56ffc5412c12764f22f954c88 Mon Sep 17 00:00:00 2001 From: Raruto Date: Thu, 21 Jan 2021 22:23:49 +0100 Subject: [PATCH 4/6] quotes --- .ht.router.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.ht.router.php b/.ht.router.php index 18be112fb..8d44db205 100644 --- a/.ht.router.php +++ b/.ht.router.php @@ -9,7 +9,7 @@ */ /** - * Handle php webserver (dev-only) + * Handle php command line webserver (dev-only) * * usage: [ php -S localhost:8080 index.php ] * @@ -17,15 +17,15 @@ */ if (PHP_SAPI == 'cli-server') { - $path = pathinfo($_SERVER["SCRIPT_FILENAME"]); + $path = pathinfo($_SERVER['SCRIPT_FILENAME']); $index = realpath($path['dirname'].'/index.php'); - $file = $_SERVER["SCRIPT_FILENAME"]; + $file = $_SERVER['SCRIPT_FILENAME']; /* "dot" routes (see: https://bugs.php.net/bug.php?id=61286) */ $_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI']; /* static files (eg. assets/app/css/style.css) */ - if (is_file($file) && $path['extension'] != "php") { + if (is_file($file) && $path['extension'] != 'php') { if ($path['extension'] == 'tag') { header('Content-Type: application/javascript'); readfile($file); From d3a5e8c7d07fba3987cd567b8b170a86c9e36d1f Mon Sep 17 00:00:00 2001 From: Raruto Date: Sun, 24 Jan 2021 00:33:59 +0100 Subject: [PATCH 5/6] custom MIME types must not return "false" --- .ht.router.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.ht.router.php b/.ht.router.php index 8d44db205..1b1533339 100644 --- a/.ht.router.php +++ b/.ht.router.php @@ -26,11 +26,17 @@ /* static files (eg. assets/app/css/style.css) */ if (is_file($file) && $path['extension'] != 'php') { + + // custom Mime Types if ($path['extension'] == 'tag') { header('Content-Type: application/javascript'); readfile($file); + exit; } + + // standard Mime Types return false; + } /* index files (eg. install/index.php) */ From 01f323fe943be83e971325ea6f240f90e3112172 Mon Sep 17 00:00:00 2001 From: Raruto Date: Thu, 25 Feb 2021 01:10:02 +0100 Subject: [PATCH 6/6] add deny routes + composer "dev" script + improved rewrite engine --- .ht.router.php | 96 +++++++++++++++++++++++++++++++++++++++++++------- composer.json | 8 +++++ 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/.ht.router.php b/.ht.router.php index 1b1533339..77d3951da 100644 --- a/.ht.router.php +++ b/.ht.router.php @@ -17,31 +17,101 @@ */ if (PHP_SAPI == 'cli-server') { - $path = pathinfo($_SERVER['SCRIPT_FILENAME']); - $index = realpath($path['dirname'].'/index.php'); - $file = $_SERVER['SCRIPT_FILENAME']; + // ---------------------------------------------------------------------- + // File access + // ---------------------------------------------------------------------- + + // Deny access to application and system files from being viewed + if (preg_match('#(composer\.(json|lock)|package\.json|(README|CONTRIBUTING)\.md|cp|Dockerfile|LICENSE|\.(sqlite|sdb|s3db|db|yaml|yml))$#', $_SERVER['REQUEST_URI'])) { + header('HTTP/1.0 403 Forbidden'); + exit('HTTP/1.0 403 Forbidden'); + } - /* "dot" routes (see: https://bugs.php.net/bug.php?id=61286) */ - $_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI']; + // ---------------------------------------------------------------------- + // MIME Types + // ---------------------------------------------------------------------- - /* static files (eg. assets/app/css/style.css) */ - if (is_file($file) && $path['extension'] != 'php') { + /* handle static files (eg. assets/app/css/style.css) */ + + $file = $_SERVER['SCRIPT_FILENAME']; + $ext = pathinfo($file, PATHINFO_EXTENSION); + + // Allow any files or directories that exist to be displayed directly + if (is_file($file)) { // custom Mime Types - if ($path['extension'] == 'tag') { + if ($ext == 'tag') { header('Content-Type: application/javascript'); readfile($file); exit; } - // standard Mime Types - return false; + // default Mime Types. + if ($ext != 'php') { + return false; + } } - /* index files (eg. install/index.php) */ - if (is_file($index)) { - include_once($index); + // ---------------------------------------------------------------------- + // Rewrite Engine + // ---------------------------------------------------------------------- + + /* rewrite other URLs to index.php */ + + $htdocs = $_SERVER['DOCUMENT_ROOT']; + $path = str_replace('/', DIRECTORY_SEPARATOR, parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)); + $index = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'index.php'; + $folder = dirname($index); + + if (is_file($htdocs . $path)) { + + // Requested URI matches an existing "php" file + $index = $path; + + } else { + + // Trasverse directories and search for "index.php" + do { + + $script = $folder . DIRECTORY_SEPARATOR . 'index.php'; + + if (is_file($htdocs . $script)) { + $index = $script; + break; + } + + $folder = dirname($folder); + + } while ($folder !== DIRECTORY_SEPARATOR && $folder !== '.'); + } + /* handle php files (eg. install/index.php) */ + + $index = DIRECTORY_SEPARATOR . ltrim($index, DIRECTORY_SEPARATOR); + $file = $htdocs . $index; + + // Update $_SERVER variables to point to the correct index-file. + $_SERVER['SCRIPT_FILENAME'] = $file; + $_SERVER['SCRIPT_NAME'] = $index; + $_SERVER['PHP_SELF'] = $index; + + // Fix "dot" routes (see: https://bugs.php.net/bug.php?id=61286) + $_SERVER['PATH_INFO'] = $path; + + // Deny access to files and directories whose names begin with a period + if (preg_match('#/\.|^\.(?!well-known/)#', $_SERVER['REQUEST_URI'])) { + header('HTTP/1.0 403 Forbidden'); + exit('HTTP/1.0 403 Forbidden'); + } + + // Allow any "php" files that exist to be displayed directly + if (is_file($file) && dirname($index) != DIRECTORY_SEPARATOR) { + include_once $file; + exit; + } + + /* Code execution returns to the main "index.php" file */ + } diff --git a/composer.json b/composer.json index 366a97ab6..9d6af6d97 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,14 @@ } ], + "scripts": { + "dev": [ + "Composer\\Config::disableProcessTimeout", + "php -r \"exec((['Darwin'=>'open', 'WINNT'=>'explorer'][PHP_OS] ?? 'xdg-open').' '.escapeshellarg('http://localhost:8080'));\"", + "php -S localhost:8080 index.php" + ] + }, + "require": { "php": "^7.1.3", "ext-json": "*",