From 0a2a4306d79136c1984b6df01f9135918dbb385e Mon Sep 17 00:00:00 2001 From: Friedinger Date: Mon, 29 Jul 2024 18:13:38 +0200 Subject: [PATCH 01/34] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Better=20attribute?= =?UTF-8?q?=20replace=20performance,=20correct=20replaceNode=20order?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/Output.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/function/Output.php b/function/Output.php index f12bf6a..6199fcc 100644 --- a/function/Output.php +++ b/function/Output.php @@ -13,6 +13,7 @@ use DOMDocument; use DOMNode; +use DOMXPath; /** * Class Output @@ -168,7 +169,7 @@ private function replaceNode(string $tag, string $content): void foreach (iterator_to_array($nodeList) as $node) { // Iterate over nodes with tag foreach ($replacement as $child) { $child = $child->cloneNode(true); - $node->parentNode->appendChild($child); // Append content as html nodes to parent node + $node->parentNode->insertBefore($child, $node); // Insert content as html nodes before old node } $node->parentNode->removeChild($node); // Remove old node } @@ -176,13 +177,14 @@ private function replaceNode(string $tag, string $content): void private function replaceAttributes(string $tag, string $content): void { - $nodeList = $this->dom->getElementsByTagName("*"); // Get all nodes - foreach ($nodeList as $node) { - foreach (iterator_to_array($node->attributes) as $attribute) { - $value = $attribute->value; // Get attribute value - if (stripos($value, "<{$tag}") !== false) { // Check if attribute value contains tag - $attribute->value = str_ireplace(["<{$tag}>", "<{$tag} />", "<{$tag}/>"], $content, $attribute->nodeValue); // Replace tag with content in attribute value - } + $xpath = new DOMXPath($this->dom); + $query = "//" . "*[@*[contains(., '<" . $tag . "')]]"; // XPath query to find attributes containing the tag + $nodes = $xpath->query($query); + + foreach ($nodes as $node) { // Iterate over nodes with attributes containing tag + foreach ($node->attributes as $attribute) { + // Replace tag with content in attribute value + $attribute->value = str_replace(["<{$tag}>", "<{$tag} />", "<{$tag}/>"], $content, $attribute->value); } } } From 00bc9435745de9fcd1f5b4f768d67d49cb2613e8 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Mon, 29 Jul 2024 19:06:19 +0200 Subject: [PATCH 02/34] =?UTF-8?q?=F0=9F=90=9B=20Case=20insensitive=20attri?= =?UTF-8?q?bute=20replace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/Output.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/function/Output.php b/function/Output.php index 6199fcc..5d2a510 100644 --- a/function/Output.php +++ b/function/Output.php @@ -177,14 +177,15 @@ private function replaceNode(string $tag, string $content): void private function replaceAttributes(string $tag, string $content): void { + // Find nodes with attributes containing tag $xpath = new DOMXPath($this->dom); - $query = "//" . "*[@*[contains(., '<" . $tag . "')]]"; // XPath query to find attributes containing the tag + $query = "//" . "*[@*[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '" . strtolower($tag) . "')]]"; $nodes = $xpath->query($query); foreach ($nodes as $node) { // Iterate over nodes with attributes containing tag foreach ($node->attributes as $attribute) { // Replace tag with content in attribute value - $attribute->value = str_replace(["<{$tag}>", "<{$tag} />", "<{$tag}/>"], $content, $attribute->value); + $attribute->value = str_ireplace(["<{$tag}>", "<{$tag} />", "<{$tag}/>"], $content, $attribute->value); } } } From 193842af71cc5dc586b7368b9d5056c66737960f Mon Sep 17 00:00:00 2001 From: Friedinger Date: Mon, 29 Jul 2024 19:07:45 +0200 Subject: [PATCH 03/34] =?UTF-8?q?=E2=9C=A8=20Sanitized=20output=20replace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/Output.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/function/Output.php b/function/Output.php index 5d2a510..9a4b4f0 100644 --- a/function/Output.php +++ b/function/Output.php @@ -88,6 +88,22 @@ public function replaceAll(string $tag, string $content): void $this->replaceAttributes($tag, $content); // Replace attributes with tag } + /** + * Replaces all occurrences of a given tag with the specified content. + * This method replaces both nodes and attributes with the given tag. + * Replaces the nodes itself, not only the content of them. + * The tag is case-insensitive. + * The content is sanitized to prevent XSS attacks. + * + * @param string $tag The tag to be replaced. + * @param string $content The content to replace the tag with. + * @return void + */ + public function replaceAllSafe(string $tag, string $content): void + { + $this->replaceAll($tag, htmlspecialchars($content)); + } + /** * Replaces the content of nodes with a specified tag with new content. * Preserves the tag and attributes of the nodes. From ad8288d1ead24ffc146c97410a7cdde9cab848ff Mon Sep 17 00:00:00 2001 From: Friedinger Date: Mon, 29 Jul 2024 19:29:11 +0200 Subject: [PATCH 04/34] =?UTF-8?q?=F0=9F=99=88=20Not=20ignore=20sample=20fi?= =?UTF-8?q?les=20in=20config=20dir?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 016e83c..e3b2917 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,7 @@ build/ # Configuration files config/* -!config/config_sample.php +!config/*_sample.* .env *.local From 84c592e6162772256fefdab7cae9be5321916182 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Mon, 29 Jul 2024 23:07:51 +0200 Subject: [PATCH 05/34] =?UTF-8?q?=E2=9C=A8=20Add=20function=20to=20get=20r?= =?UTF-8?q?equest=20protocol?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/Request.php | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index 97f7fa1..d5a9e44 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -13,7 +13,7 @@ namespace FileRouter; -final class Config +class Config { // Paths (relative to the server root) const PATH_PUBLIC = "/../public/"; // Path to the public folder diff --git a/function/Request.php b/function/Request.php index eab821c..81c8cde 100644 --- a/function/Request.php +++ b/function/Request.php @@ -120,12 +120,19 @@ private static function setSessionNested(array &$session, array $keys, mixed $va } /** - * Retrieves the current HTTP response code. + * Returns the protocol used for the current request. * - * @return int The HTTP response code. + * @return string The protocol used for the current request. It can be either "http" or "https". */ - public static function responseCode(): int + public static function protocol(): string { - return http_response_code(); // Get HTTP response code with php function + if ((!empty($_SERVER["REQUEST_SCHEME"]) && $_SERVER["REQUEST_SCHEME"] == "https") || + (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") || + (!empty($_SERVER["SERVER_PORT"]) && $_SERVER["SERVER_PORT"] == "443") + ) { + return "https"; + } else { + return "http"; + } } } From d1ebd1c0b30e7acf58fb8c67ceffd0ffd2a423ac Mon Sep 17 00:00:00 2001 From: Friedinger Date: Thu, 29 Aug 2024 00:05:14 +0200 Subject: [PATCH 06/34] =?UTF-8?q?=E2=9C=A8=20CSRF=20token=20generation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/Misc.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/function/Misc.php b/function/Misc.php index 536d89a..0cc72ce 100644 --- a/function/Misc.php +++ b/function/Misc.php @@ -34,6 +34,32 @@ public static function session(): string|false return session_id(); } + /** + * Generates a CSRF token and stores it in the session. + * The token is a 64-character hexadecimal string. + * + * @return string The generated CSRF token. + */ + public static function generateCSRFToken(): string + { + $token = bin2hex(random_bytes(32)); + Request::setSession($token, "token"); + return $token; + } + + /** + * Verifies a CSRF token by comparing it to the token stored in the session. + * + * @param string $token The token to verify. + * @return bool True if the token is valid, false otherwise. + */ + public static function verifyCSRFToken(string $token): bool + { + $verify = hash_equals(Request::session("token"), $token); + self::generateCSRFToken(); + return $verify; + } + /** * Retrieves the MIME type of a file. * Uses mime_content_type as default, but also provides a custom list of MIME types based on file extension. From 6b0e3444f384f3ee6992bc098aa8ed04ab84e90f Mon Sep 17 00:00:00 2001 From: Friedinger Date: Thu, 29 Aug 2024 00:06:01 +0200 Subject: [PATCH 07/34] =?UTF-8?q?=F0=9F=94=96=20Version=202.2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/FileRouter.php | 2 +- home/index.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index d5a9e44..e558a68 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.1.4 +Version: 2.2.0 */ diff --git a/function/FileRouter.php b/function/FileRouter.php index 530fb51..c39328c 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.1.4 +Version: 2.2.0 */ diff --git a/home/index.php b/home/index.php index 167ee9a..8d5d5c2 100644 --- a/home/index.php +++ b/home/index.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.1.4 +Version: 2.2.0 */ From 620724473a734aecb39633c3a5ee2f64f264c359 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Thu, 29 Aug 2024 21:08:01 +0200 Subject: [PATCH 08/34] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20?= =?UTF-8?q?=20allowed=20in=20attribute=20replaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/Output.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/function/Output.php b/function/Output.php index 9a4b4f0..3ac70b5 100644 --- a/function/Output.php +++ b/function/Output.php @@ -201,7 +201,7 @@ private function replaceAttributes(string $tag, string $content): void foreach ($nodes as $node) { // Iterate over nodes with attributes containing tag foreach ($node->attributes as $attribute) { // Replace tag with content in attribute value - $attribute->value = str_ireplace(["<{$tag}>", "<{$tag} />", "<{$tag}/>"], $content, $attribute->value); + $attribute->value = str_ireplace(["<{$tag}>", "<{$tag} />", "<{$tag}/>", "<{$tag}>"], $content, $attribute->value); } } } From 35285352af7895f307b6f631ab0699e0499c311c Mon Sep 17 00:00:00 2001 From: Friedinger Date: Thu, 29 Aug 2024 21:08:34 +0200 Subject: [PATCH 09/34] =?UTF-8?q?=E2=9C=A8=20CSRF=20improvements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 1 + function/ControllerHtml.php | 5 +++++ function/Misc.php | 12 ++++++------ modules/header.php | 2 +- public/csrf/index.php | 22 ++++++++++++++++++++++ 5 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 public/csrf/index.php diff --git a/config/config_sample.php b/config/config_sample.php index e558a68..5486c85 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -25,6 +25,7 @@ class Config // Sessions const SESSION = true; // Enable session handling + const CSRF_GENERATE = true; // Generate a CSRF token const SESSION_NAME = "FileRouter"; // Name of the session const SESSION_COOKIE_PARAMS = [ // Session cookie parameters (https://www.php.net/manual/en/function.session-set-cookie-params.php) "lifetime" => 0, diff --git a/function/ControllerHtml.php b/function/ControllerHtml.php index d69a449..3a4d894 100644 --- a/function/ControllerHtml.php +++ b/function/ControllerHtml.php @@ -57,6 +57,11 @@ public static function handleHtml(Output $content): Output $content = self::handleHeader($content); $content = self::handleFooter($content); + // Output CSRF token if enabled + if (Config::SESSION && Config::CSRF_GENERATE) { + $content->replaceAllSafe("csrf-token", Misc::getCsrfToken()); + } + return $content; } diff --git a/function/Misc.php b/function/Misc.php index 0cc72ce..f819e4a 100644 --- a/function/Misc.php +++ b/function/Misc.php @@ -38,26 +38,26 @@ public static function session(): string|false * Generates a CSRF token and stores it in the session. * The token is a 64-character hexadecimal string. * + * @param bool $regenerate Flag indicating if the token should be regenerated. * @return string The generated CSRF token. */ - public static function generateCSRFToken(): string + public static function getCsrfToken(): string { $token = bin2hex(random_bytes(32)); - Request::setSession($token, "token"); + Request::setSession($token, "csrf-token"); return $token; } /** * Verifies a CSRF token by comparing it to the token stored in the session. + * Regenerates the token after verification. * * @param string $token The token to verify. * @return bool True if the token is valid, false otherwise. */ - public static function verifyCSRFToken(string $token): bool + public static function verifyCsrfToken(string $token): bool { - $verify = hash_equals(Request::session("token"), $token); - self::generateCSRFToken(); - return $verify; + return hash_equals(Request::session("csrf-token") ?? "", $token); } /** diff --git a/modules/header.php b/modules/header.php index 773d808..3596a92 100644 --- a/modules/header.php +++ b/modules/header.php @@ -1,3 +1,3 @@
- Header: Home Protect Proxy + Header: Home Protect Proxy CSRF
\ No newline at end of file diff --git a/public/csrf/index.php b/public/csrf/index.php new file mode 100644 index 0000000..234eefa --- /dev/null +++ b/public/csrf/index.php @@ -0,0 +1,22 @@ +
+

CSRF

+

Token should be used inside hidden input, text input just used for demo purpose.

+ +
+ + +
+
+ + "; + echo "Expected token: " . Request::session("csrf-token") . "
"; + echo Misc::verifyCsrfToken(Request::post("csrf-token")) ? "Valid" : "Invalid"; + } + ?> +
\ No newline at end of file From 965cc95d1898f637e2a0b07afb2e29a2f9caece1 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Thu, 29 Aug 2024 21:09:07 +0200 Subject: [PATCH 10/34] =?UTF-8?q?=F0=9F=94=96=20Version=202.2.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/FileRouter.php | 2 +- home/index.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index 5486c85..c1c5737 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.2.0 +Version: 2.2.1 */ diff --git a/function/FileRouter.php b/function/FileRouter.php index c39328c..10c53d9 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.2.0 +Version: 2.2.1 */ diff --git a/home/index.php b/home/index.php index 8d5d5c2..c9a0727 100644 --- a/home/index.php +++ b/home/index.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.2.0 +Version: 2.2.1 */ From 13877775d1fd91560968686417eb0cdee23a4ebb Mon Sep 17 00:00:00 2001 From: Friedinger Date: Thu, 29 Aug 2024 23:39:30 +0200 Subject: [PATCH 11/34] =?UTF-8?q?=F0=9F=9A=B8=20CSRF=20usability=20improve?= =?UTF-8?q?ments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 6 +++++- function/ControllerHtml.php | 4 ++-- function/Misc.php | 33 +++++++++++++++++++++++++++++---- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index c1c5737..3838236 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -25,7 +25,6 @@ class Config // Sessions const SESSION = true; // Enable session handling - const CSRF_GENERATE = true; // Generate a CSRF token const SESSION_NAME = "FileRouter"; // Name of the session const SESSION_COOKIE_PARAMS = [ // Session cookie parameters (https://www.php.net/manual/en/function.session-set-cookie-params.php) "lifetime" => 0, @@ -36,6 +35,11 @@ class Config "samesite" => "Strict", ]; + // Security + const CSRF_TEMPLATE = "csrf-token"; // CSRF token template variable name, also used as session key + const CSRF_PARAMETER = "token"; // CSRF token parameter name for get and post requests + const CSRF_LENGTH = 64; // Length of the CSRF token, set to 0 to disable CSRF protection + // Page titles const TITLE_PREFIX = "FileRouter"; const TITLE_SUFFIX = ""; diff --git a/function/ControllerHtml.php b/function/ControllerHtml.php index 3a4d894..92c8c9e 100644 --- a/function/ControllerHtml.php +++ b/function/ControllerHtml.php @@ -58,8 +58,8 @@ public static function handleHtml(Output $content): Output $content = self::handleFooter($content); // Output CSRF token if enabled - if (Config::SESSION && Config::CSRF_GENERATE) { - $content->replaceAllSafe("csrf-token", Misc::getCsrfToken()); + if (Config::SESSION && COnfig::CSRF_LENGTH > 0) { + $content->replaceAllSafe(Config::CSRF_TEMPLATE, Misc::generateCsrfToken()); } return $content; diff --git a/function/Misc.php b/function/Misc.php index f819e4a..46c0c91 100644 --- a/function/Misc.php +++ b/function/Misc.php @@ -41,9 +41,9 @@ public static function session(): string|false * @param bool $regenerate Flag indicating if the token should be regenerated. * @return string The generated CSRF token. */ - public static function getCsrfToken(): string + public static function generateCsrfToken(): string { - $token = bin2hex(random_bytes(32)); + $token = bin2hex(random_bytes(Config::CSRF_LENGTH / 2)); Request::setSession($token, "csrf-token"); return $token; } @@ -55,9 +55,34 @@ public static function getCsrfToken(): string * @param string $token The token to verify. * @return bool True if the token is valid, false otherwise. */ - public static function verifyCsrfToken(string $token): bool + public static function verifyCsrfToken(string|null $token): bool { - return hash_equals(Request::session("csrf-token") ?? "", $token); + if ($token == null) return false; + $verify = hash_equals(Request::session(Config::CSRF_TEMPLATE) ?? "", $token); + self::generateCsrfToken(); + return $verify; + } + + /** + * Verifies a CSRF token from a GET request. + * The token is retrieved from the query string. + * + * @return bool True if the token is valid, false otherwise. + */ + public static function verifyCsrfTokenGet(): bool + { + return self::verifyCsrfToken(Request::get(Config::CSRF_PARAMETER)); + } + + /** + * Verifies a CSRF token from a POST request. + * The token is retrieved from the request body. + * + * @return bool True if the token is valid, false otherwise. + */ + public static function verifyCsrfTokenPost(): bool + { + return self::verifyCsrfToken(Request::post(Config::CSRF_PARAMETER)); } /** From 8fc8823ebb703c207346ae88f59e9fb06cee8a2d Mon Sep 17 00:00:00 2001 From: Friedinger Date: Thu, 29 Aug 2024 23:40:08 +0200 Subject: [PATCH 12/34] =?UTF-8?q?=F0=9F=94=96=20Version=202.2.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/FileRouter.php | 2 +- home/index.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index 3838236..78664b7 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.2.1 +Version: 2.2.2 */ diff --git a/function/FileRouter.php b/function/FileRouter.php index 10c53d9..a332d03 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.2.1 +Version: 2.2.2 */ diff --git a/home/index.php b/home/index.php index c9a0727..3952c3a 100644 --- a/home/index.php +++ b/home/index.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.2.1 +Version: 2.2.2 */ From 89fb06d3a13a8993327d78e38ce0a103aa849411 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Thu, 29 Aug 2024 23:41:48 +0200 Subject: [PATCH 13/34] =?UTF-8?q?=F0=9F=92=AC=20Change=20csrf=20sample=20p?= =?UTF-8?q?age?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/csrf/index.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/csrf/index.php b/public/csrf/index.php index 234eefa..b35382a 100644 --- a/public/csrf/index.php +++ b/public/csrf/index.php @@ -3,7 +3,7 @@

Token should be used inside hidden input, text input just used for demo purpose.

- +

@@ -14,9 +14,9 @@ use FileRouter\Request; if ($_SERVER["REQUEST_METHOD"] === "POST") { - echo "Send token: " . Request::post("csrf-token") . "
"; + echo "Send token: " . Request::post("token") . "
"; echo "Expected token: " . Request::session("csrf-token") . "
"; - echo Misc::verifyCsrfToken(Request::post("csrf-token")) ? "Valid" : "Invalid"; + echo Misc::verifyCsrfTokenPost() ? "Valid" : "Invalid"; } ?> \ No newline at end of file From c0031d78785e69ba0c4feca2a114d3f344cbabf3 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Sat, 31 Aug 2024 22:24:34 +0200 Subject: [PATCH 14/34] =?UTF-8?q?=E2=9C=A8=20Error=20handling=20and=20logg?= =?UTF-8?q?ing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 5 ++ function/{Error.php => ErrorPage.php} | 2 +- function/FileRouter.php | 84 ++++++++++++++++++++------- function/Misc.php | 18 ++++++ function/Proxy.php | 2 +- function/Router.php | 2 +- home/index.php | 2 + modules/header.php | 2 +- public/error/_route.php | 5 ++ public/protect/_route.php | 2 +- 10 files changed, 99 insertions(+), 25 deletions(-) rename function/{Error.php => ErrorPage.php} (98%) create mode 100644 public/error/_route.php diff --git a/config/config_sample.php b/config/config_sample.php index 78664b7..90db99f 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -45,6 +45,11 @@ class Config const TITLE_SUFFIX = ""; const TITLE_SEPARATOR = " | "; + // Logging + const LOG = true; // Enable logging + const LOG_PATH = "/../logs/"; // Path to the log folder (relative to the server root) + const LOG_FILE = "{date}.log"; // Log file name, {date} will be replaced with the current date in the format "Y-m-d" + // Other const ALLOW_PAGE_PHP = true; // Allow to execute php code in pages. Warning: This can be a security risk if not handled carefully. const IMAGE_RESIZE_QUERY = "res"; // Query parameter to specify the width of an image to resize it diff --git a/function/Error.php b/function/ErrorPage.php similarity index 98% rename from function/Error.php rename to function/ErrorPage.php index b3699e0..52be7c3 100644 --- a/function/Error.php +++ b/function/ErrorPage.php @@ -16,7 +16,7 @@ * * Represents an error with an error code and an error message. */ -class Error extends \Exception +class ErrorPage extends \Exception { /** diff --git a/function/FileRouter.php b/function/FileRouter.php index a332d03..2b3b900 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -13,28 +13,72 @@ namespace FileRouter; -// Autoload classes -spl_autoload_register(function ($class) { - if (str_starts_with($class, __NAMESPACE__ . "\\")) { - $class = str_replace(__NAMESPACE__ . "\\", "", $class); - require_once "{$class}.php"; +class FileRouter +{ + public function __construct() + { + try { + $this->autoload(); // Autoload classes + $this->setup(); // Setup environment + $this->handle(); // Handle request + } catch (ErrorPage $errorPage) { + throw $errorPage; // Rethrow ErrorPage exceptions to display error page + } catch (\Throwable $exception) { + $this->handleException($exception); // Handle unhandled exceptions + } } -}); -// Start session if enabled in config -if (Config::SESSION) { - Misc::session(); -} + private function handle() + { + // Handle route file as proxy of request + $proxy = new Proxy(); + $proxyHandled = $proxy->handle(); + if ($proxyHandled) exit; // Stop handling if request was handled by proxy + + // Handle request with router + $router = new Router(); + $routerHandled = $router->handle(); + if ($routerHandled) exit; // Stop handling if request was handled by router -// Handle route file as proxy of request -$proxy = new Proxy(); -$proxyHandled = $proxy->handle(); -if ($proxyHandled) exit; // Stop handling if request was handled by proxy + // Error 404 if request was not handled before + throw new ErrorPage(404); + } -// Handle request with router -$router = new Router(); -$routerHandled = $router->handle(); -if ($routerHandled) exit; // Stop handling if request was handled by router + private function setup() + { + // Start session if enabled in config + if (Config::SESSION) { + Misc::session(); + } + + // Set error log file if enabled in config + if (Config::LOG) { + $logFile = str_replace("{date}", date("Y-m-d"), Config::LOG_FILE); + ini_set("error_log", $_SERVER["DOCUMENT_ROOT"] . Config::LOG_PATH . $logFile); + } + } -// Error 404 if request was not handled before -throw new Error(404); + private function handleException(\Throwable $exception) + { + try { + ob_end_clean(); // Clear output buffer + Misc::log("{$exception->getMessage()} in {$exception->getFile()}({$exception->getLine()})", E_USER_ERROR); // Log unhandled exceptions + throw new ErrorPage(500); // Internal server error if unhandled exception occurred + } catch (\Throwable $e) { + if (Config::LOG) { + error_log("ERROR {$e->getMessage()} in exception handling"); // Log error message + } + die(Config::ERROR_FATAL ?? "

Error

An error occurred in the request.

Please contact the webmaster

"); + } + } + + private function autoload() + { + spl_autoload_register(function ($class) { + if (str_starts_with($class, __NAMESPACE__ . "\\")) { + $class = str_replace(__NAMESPACE__ . "\\", "", $class); + require_once "{$class}.php"; + } + }); + } +} diff --git a/function/Misc.php b/function/Misc.php index 46c0c91..a7b1c9f 100644 --- a/function/Misc.php +++ b/function/Misc.php @@ -34,6 +34,24 @@ public static function session(): string|false return session_id(); } + public static function log(string $message, int $level): void + { + if (Config::LOG) { + $levelName = match ($level) { + E_NOTICE => "NOTICE", + E_USER_NOTICE => "NOTICE", + E_WARNING => "WARNING", + E_USER_DEPRECATED => "DEPRECATED", + E_DEPRECATED => "DEPRECATED", + E_USER_WARNING => "WARNING", + E_ERROR => "ERROR", + E_USER_ERROR => "ERROR", + default => "UNKNOWN", + }; + error_log("$levelName: $message"); + } + } + /** * Generates a CSRF token and stores it in the session. * The token is a 64-character hexadecimal string. diff --git a/function/Proxy.php b/function/Proxy.php index 8a73474..5aa3970 100644 --- a/function/Proxy.php +++ b/function/Proxy.php @@ -76,7 +76,7 @@ public static function handleCustom(Output $content, Output $settings): Output } } if (!$success) { - throw new Error(500, "Error in route file callable: {$e->getMessage()}"); // Error 500 if callable failed with all parameter combinations + throw new ErrorPage(500, "Error in route file callable: {$e->getMessage()}"); // Error 500 if callable failed with all parameter combinations } } return $content; // Return handled content diff --git a/function/Router.php b/function/Router.php index 286e33f..1f69cfb 100644 --- a/function/Router.php +++ b/function/Router.php @@ -73,7 +73,7 @@ private static function searchPath(string $uri): string $directoryPosition = array_search(strtolower($path), array_map("strtolower", $directoryContent)); // Search for path in directory content (case insensitive) if ($directoryPosition === false) { // If path is not in directory content, return 404 error - throw new Error(404); + throw new ErrorPage(404); } return $directoryContent[$directoryPosition]; // Get path from directory content diff --git a/home/index.php b/home/index.php index 3952c3a..1eb7867 100644 --- a/home/index.php +++ b/home/index.php @@ -13,3 +13,5 @@ require_once $_SERVER["DOCUMENT_ROOT"] . "/../config/config.php"; // Load config file require_once $_SERVER["DOCUMENT_ROOT"] . "/../function/FileRouter.php"; // Start FileRouter by loading main file + +$fileRouter = new FileRouter\FileRouter(); diff --git a/modules/header.php b/modules/header.php index 3596a92..a14df7d 100644 --- a/modules/header.php +++ b/modules/header.php @@ -1,3 +1,3 @@
- Header: Home Protect Proxy CSRF + Header: Home Protect Proxy CSRF Error
\ No newline at end of file diff --git a/public/error/_route.php b/public/error/_route.php new file mode 100644 index 0000000..0c5ff75 --- /dev/null +++ b/public/error/_route.php @@ -0,0 +1,5 @@ + Date: Sat, 31 Aug 2024 22:26:29 +0200 Subject: [PATCH 15/34] =?UTF-8?q?=F0=9F=94=96=20Version=203.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/FileRouter.php | 2 +- home/index.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index 90db99f..07d5512 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.2.2 +Version: 3.0.0 */ diff --git a/function/FileRouter.php b/function/FileRouter.php index 2b3b900..bce7a4d 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.2.2 +Version: 3.0.0 */ diff --git a/home/index.php b/home/index.php index 1eb7867..37cd238 100644 --- a/home/index.php +++ b/home/index.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 2.2.2 +Version: 3.0.0 */ From 53a6805654066b10bce7ecf3fb538576db0fcf8a Mon Sep 17 00:00:00 2001 From: Friedinger Date: Sat, 31 Aug 2024 22:29:14 +0200 Subject: [PATCH 16/34] =?UTF-8?q?=F0=9F=92=A1=20Change=20start=20comment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- home/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/home/index.php b/home/index.php index 37cd238..c740f6f 100644 --- a/home/index.php +++ b/home/index.php @@ -12,6 +12,6 @@ */ require_once $_SERVER["DOCUMENT_ROOT"] . "/../config/config.php"; // Load config file -require_once $_SERVER["DOCUMENT_ROOT"] . "/../function/FileRouter.php"; // Start FileRouter by loading main file +require_once $_SERVER["DOCUMENT_ROOT"] . "/../function/FileRouter.php"; // Load FileRouter main class -$fileRouter = new FileRouter\FileRouter(); +$fileRouter = new FileRouter\FileRouter(); // Start FileRouter From a6daaedd9db51605074fed80a092690a55afaf07 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Sat, 31 Aug 2024 22:59:26 +0200 Subject: [PATCH 17/34] =?UTF-8?q?=F0=9F=97=91=EF=B8=8F=20Refactor=20deprec?= =?UTF-8?q?ated=20mb=20encode=20html=20entities?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/Output.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/function/Output.php b/function/Output.php index 3ac70b5..a2c654a 100644 --- a/function/Output.php +++ b/function/Output.php @@ -49,8 +49,7 @@ public function __construct(string $content, bool $directInput = false) // Get content from file without processing php $output = file_get_contents($content); } - - $output = mb_convert_encoding($output, "HTML-ENTITIES", "UTF-8"); + $output = mb_encode_numericentity($output, [0x80, 0x10FFFF, 0, ~0], "UTF-8"); $this->dom->loadHTML($output, LIBXML_NOERROR); // Load html content into dom } @@ -152,7 +151,7 @@ public function getContent(string ...$tags): string|null $dom = $domNew; } $content = $dom->saveHTML(); // Save html content from dom - $content = mb_convert_encoding($content, "HTML-ENTITIES", "UTF-8"); + $content = mb_encode_numericentity($content, [0x80, 0x10FFFF, 0, ~0], "UTF-8"); $content = str_replace("%20", " ", $content); return trim($content); // Return html content as string } @@ -214,7 +213,7 @@ private function importNodes(string $value): array } $valueDom = new DOMDocument(); - $valueDom->loadHTML(mb_convert_encoding($value, 'HTML-ENTITIES', 'UTF-8'), LIBXML_NOERROR); // Load html value into dom + $valueDom->loadHTML(mb_encode_numericentity($value, [0x80, 0x10FFFF, 0, ~0], "UTF-8"), LIBXML_NOERROR); // Load html value into dom $importedNodes = []; foreach ($valueDom->getElementsByTagName("body")->item(0)->childNodes as $child) { array_push($importedNodes, $this->dom->importNode($child, true)); // Import nodes from value dom to main dom and add to array From 9c87c6b3c0431669e5665f9e6c9b5df5cab5c4bb Mon Sep 17 00:00:00 2001 From: Friedinger Date: Sat, 31 Aug 2024 23:18:24 +0200 Subject: [PATCH 18/34] =?UTF-8?q?=E2=9C=A8=20Debug=20config=20to=20display?= =?UTF-8?q?=20errors=20instead=20of=20logging=20them?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 3 ++- function/FileRouter.php | 31 ++++++++++++++++++++++--------- public/error/_route.php | 2 +- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index 07d5512..7cb2336 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -45,7 +45,8 @@ class Config const TITLE_SUFFIX = ""; const TITLE_SEPARATOR = " | "; - // Logging + // Error handling and logging + const DEBUG = true; // Enable debug mode (shows errors and warnings, disables error logging) const LOG = true; // Enable logging const LOG_PATH = "/../logs/"; // Path to the log folder (relative to the server root) const LOG_FILE = "{date}.log"; // Log file name, {date} will be replaced with the current date in the format "Y-m-d" diff --git a/function/FileRouter.php b/function/FileRouter.php index bce7a4d..d2b062f 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -28,7 +28,7 @@ public function __construct() } } - private function handle() + private function handle(): void { // Handle route file as proxy of request $proxy = new Proxy(); @@ -44,22 +44,35 @@ private function handle() throw new ErrorPage(404); } - private function setup() + private function setup(): void { + // Set error logging if enabled in config + if (Config::LOG) { + $logFile = str_replace("{date}", date("Y-m-d"), Config::LOG_FILE); + ini_set("error_log", $_SERVER["DOCUMENT_ROOT"] . Config::LOG_PATH . $logFile); // Set error log file + } + + // Set error reporting and display errors + if (Config::DEBUG) { + error_reporting(E_ALL); // Report all errors + ini_set("display_errors", 1); // Display errors + ini_set("error_log", null); // Disable error log + } else { + error_reporting(0); // Report no errors + ini_set("display_errors", 0); // Hide errors + } + // Start session if enabled in config if (Config::SESSION) { Misc::session(); } - - // Set error log file if enabled in config - if (Config::LOG) { - $logFile = str_replace("{date}", date("Y-m-d"), Config::LOG_FILE); - ini_set("error_log", $_SERVER["DOCUMENT_ROOT"] . Config::LOG_PATH . $logFile); - } } - private function handleException(\Throwable $exception) + private function handleException(\Throwable $exception): void { + if (CONFIG::DEBUG) { + throw $exception; // Rethrow exception if debug mode is enabled + } try { ob_end_clean(); // Clear output buffer Misc::log("{$exception->getMessage()} in {$exception->getFile()}({$exception->getLine()})", E_USER_ERROR); // Log unhandled exceptions diff --git a/public/error/_route.php b/public/error/_route.php index 0c5ff75..a831051 100644 --- a/public/error/_route.php +++ b/public/error/_route.php @@ -1,5 +1,5 @@ Date: Sat, 31 Aug 2024 23:19:04 +0200 Subject: [PATCH 19/34] =?UTF-8?q?=F0=9F=94=96=20Version=203.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/FileRouter.php | 2 +- home/index.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index 7cb2336..184b304 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.0.0 +Version: 3.0.1 */ diff --git a/function/FileRouter.php b/function/FileRouter.php index d2b062f..018372d 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.0.0 +Version: 3.0.1 */ diff --git a/home/index.php b/home/index.php index c740f6f..91b8bd5 100644 --- a/home/index.php +++ b/home/index.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.0.0 +Version: 3.0.1 */ From 4a013ac85cded250ee8caafa2c14ba51d36e00fa Mon Sep 17 00:00:00 2001 From: Friedinger Date: Mon, 2 Sep 2024 00:05:42 +0200 Subject: [PATCH 20/34] =?UTF-8?q?=F0=9F=8E=A8=20Logging=20improvements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 6 +++-- function/FileRouter.php | 10 ++++---- function/Logger.php | 51 ++++++++++++++++++++++++++++++++++++++++ function/Misc.php | 18 -------------- 4 files changed, 60 insertions(+), 25 deletions(-) create mode 100644 function/Logger.php diff --git a/config/config_sample.php b/config/config_sample.php index 184b304..7014639 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -48,8 +48,10 @@ class Config // Error handling and logging const DEBUG = true; // Enable debug mode (shows errors and warnings, disables error logging) const LOG = true; // Enable logging - const LOG_PATH = "/../logs/"; // Path to the log folder (relative to the server root) - const LOG_FILE = "{date}.log"; // Log file name, {date} will be replaced with the current date in the format "Y-m-d" + const LOG_PATH = [ // Paths to log files (relative to the server root, {date} will be replaced with the current date) + "error" => "/../logs/error_{date}.log", // Error log file required if logging is enabled + "additional" => "/../logs/additional.log", // Additional log files, can be used for custom logging by Logger::log("message", "additional") + ]; // Other const ALLOW_PAGE_PHP = true; // Allow to execute php code in pages. Warning: This can be a security risk if not handled carefully. diff --git a/function/FileRouter.php b/function/FileRouter.php index 018372d..b13fd4d 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -46,17 +46,17 @@ private function handle(): void private function setup(): void { - // Set error logging if enabled in config + // Set error log file if enabled if (Config::LOG) { - $logFile = str_replace("{date}", date("Y-m-d"), Config::LOG_FILE); - ini_set("error_log", $_SERVER["DOCUMENT_ROOT"] . Config::LOG_PATH . $logFile); // Set error log file + ini_set("log_errors", 1); // Enable error logging + ini_set("error_log", Logger::logPath("error")); // Set error log file } // Set error reporting and display errors if (Config::DEBUG) { error_reporting(E_ALL); // Report all errors ini_set("display_errors", 1); // Display errors - ini_set("error_log", null); // Disable error log + ini_set("log_errors", 0); // Disable error log } else { error_reporting(0); // Report no errors ini_set("display_errors", 0); // Hide errors @@ -75,7 +75,7 @@ private function handleException(\Throwable $exception): void } try { ob_end_clean(); // Clear output buffer - Misc::log("{$exception->getMessage()} in {$exception->getFile()}({$exception->getLine()})", E_USER_ERROR); // Log unhandled exceptions + Logger::logError("{$exception->getMessage()} in {$exception->getFile()}({$exception->getLine()})", E_USER_ERROR); // Log unhandled exceptions throw new ErrorPage(500); // Internal server error if unhandled exception occurred } catch (\Throwable $e) { if (Config::LOG) { diff --git a/function/Logger.php b/function/Logger.php new file mode 100644 index 0000000..2e2acda --- /dev/null +++ b/function/Logger.php @@ -0,0 +1,51 @@ + "NOTICE", + E_USER_NOTICE => "NOTICE", + E_WARNING => "WARNING", + E_USER_DEPRECATED => "DEPRECATED", + E_DEPRECATED => "DEPRECATED", + E_USER_WARNING => "WARNING", + E_ERROR => "ERROR", + E_USER_ERROR => "ERROR", + default => "UNKNOWN", + }; + error_log("$levelName: $message"); + } + + public static function logPath(string $type): string + { + $path = Config::LOG_PATH[$type] ?? "filerouter_{date}.log"; + $path = str_replace("{date}", date("Y-m-d"), $path); + return $_SERVER["DOCUMENT_ROOT"] . $path; + } +} diff --git a/function/Misc.php b/function/Misc.php index a7b1c9f..46c0c91 100644 --- a/function/Misc.php +++ b/function/Misc.php @@ -34,24 +34,6 @@ public static function session(): string|false return session_id(); } - public static function log(string $message, int $level): void - { - if (Config::LOG) { - $levelName = match ($level) { - E_NOTICE => "NOTICE", - E_USER_NOTICE => "NOTICE", - E_WARNING => "WARNING", - E_USER_DEPRECATED => "DEPRECATED", - E_DEPRECATED => "DEPRECATED", - E_USER_WARNING => "WARNING", - E_ERROR => "ERROR", - E_USER_ERROR => "ERROR", - default => "UNKNOWN", - }; - error_log("$levelName: $message"); - } - } - /** * Generates a CSRF token and stores it in the session. * The token is a 64-character hexadecimal string. From e16af5e1f73c2bcebe6526def66da556b25627ad Mon Sep 17 00:00:00 2001 From: Friedinger Date: Mon, 2 Sep 2024 00:06:12 +0200 Subject: [PATCH 21/34] =?UTF-8?q?=F0=9F=94=96=20Version=203.1.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/FileRouter.php | 2 +- home/index.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index 7014639..b480ab6 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.0.1 +Version: 3.1.0 */ diff --git a/function/FileRouter.php b/function/FileRouter.php index b13fd4d..34dc180 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.0.1 +Version: 3.1.0 */ diff --git a/home/index.php b/home/index.php index 91b8bd5..a8df9b1 100644 --- a/home/index.php +++ b/home/index.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.0.1 +Version: 3.1.0 */ From 36090638c18a4166beb355b94782f59921b74d07 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Mon, 2 Sep 2024 21:38:24 +0200 Subject: [PATCH 22/34] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Remov?= =?UTF-8?q?e=20exit=20and=20die=20to=20allow=20e.g.=20logging=20afterwards?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/ErrorPage.php | 6 ++++-- function/FileRouter.php | 8 ++++---- function/Router.php | 1 - 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/function/ErrorPage.php b/function/ErrorPage.php index 52be7c3..510de79 100644 --- a/function/ErrorPage.php +++ b/function/ErrorPage.php @@ -34,7 +34,10 @@ public function __construct(int $errorCode, string $errorMessage = null) http_response_code($errorCode); // Set HTTP status code based on error code $pathErrorPage = $_SERVER["DOCUMENT_ROOT"] . Config::PATH_ERROR; - if (!file_exists($pathErrorPage)) die(Config::ERROR_FATAL); // Fatal error if error page does not exist + if (!file_exists($pathErrorPage)) { + // Fatal error if error page does not exist + throw new \ValueError("Error page (Config::PATH_ERROR) not found in {$pathErrorPage}", E_USER_ERROR); + } $output = new Output($pathErrorPage); // Load error page to output handler $settings = $output->getNodeContentArray("settings"); // Get error messages from error page @@ -48,6 +51,5 @@ public function __construct(int $errorCode, string $errorMessage = null) $output->replaceAll("error-message", $errorMessage); // Replace error message placeholder $output = ControllerHtml::handleHtml($output); // Handle html content (e.g. add head, header and footer) $output->print(); // Print output - exit; // Stop further execution } } diff --git a/function/FileRouter.php b/function/FileRouter.php index 34dc180..1528961 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -21,8 +21,8 @@ public function __construct() $this->autoload(); // Autoload classes $this->setup(); // Setup environment $this->handle(); // Handle request - } catch (ErrorPage $errorPage) { - throw $errorPage; // Rethrow ErrorPage exceptions to display error page + } catch (ErrorPage) { + // Error page was displayed in ErrorPage exception } catch (\Throwable $exception) { $this->handleException($exception); // Handle unhandled exceptions } @@ -33,12 +33,12 @@ private function handle(): void // Handle route file as proxy of request $proxy = new Proxy(); $proxyHandled = $proxy->handle(); - if ($proxyHandled) exit; // Stop handling if request was handled by proxy + if ($proxyHandled) return; // Stop handling if request was handled by proxy // Handle request with router $router = new Router(); $routerHandled = $router->handle(); - if ($routerHandled) exit; // Stop handling if request was handled by router + if ($routerHandled) return; // Stop handling if request was handled by router // Error 404 if request was not handled before throw new ErrorPage(404); diff --git a/function/Router.php b/function/Router.php index 1f69cfb..3e39007 100644 --- a/function/Router.php +++ b/function/Router.php @@ -59,7 +59,6 @@ public static function redirect(string $uri): void { $uri = Misc::prepareUri($uri); // Prepare uri header("Location: /$uri/"); // Set location header - exit(); // Stop further execution } private static function searchPath(string $uri): string From f2bd0b3e22a7bf65de11e1082190db8771516a88 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Mon, 2 Sep 2024 21:39:10 +0200 Subject: [PATCH 23/34] =?UTF-8?q?=F0=9F=94=96=20Version=203.2.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/FileRouter.php | 2 +- home/index.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index b480ab6..65f1f41 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.1.0 +Version 3.2.0 */ diff --git a/function/FileRouter.php b/function/FileRouter.php index 1528961..2f31351 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.1.0 +Version 3.2.0 */ diff --git a/home/index.php b/home/index.php index a8df9b1..384d5fa 100644 --- a/home/index.php +++ b/home/index.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.1.0 +Version 3.2.0 */ From fc4c433bffb96f283f5711761fe0876a846e6ed0 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Mon, 2 Sep 2024 21:56:16 +0200 Subject: [PATCH 24/34] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Remov?= =?UTF-8?q?e=20last=20die=20call?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/FileRouter.php | 5 +++-- home/index.php | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index 65f1f41..d9a02d1 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version 3.2.0 +Version: 3.2.1 */ diff --git a/function/FileRouter.php b/function/FileRouter.php index 2f31351..fa919f6 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version 3.2.0 +Version: 3.2.1 */ @@ -81,7 +81,8 @@ private function handleException(\Throwable $exception): void if (Config::LOG) { error_log("ERROR {$e->getMessage()} in exception handling"); // Log error message } - die(Config::ERROR_FATAL ?? "

Error

An error occurred in the request.

Please contact the webmaster

"); + echo Config::ERROR_FATAL ?? "

Error

An error occurred in the request.

Please contact the webmaster

"; + return; } } diff --git a/home/index.php b/home/index.php index 384d5fa..d0f914c 100644 --- a/home/index.php +++ b/home/index.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version 3.2.0 +Version: 3.2.1 */ From 999b9f95bca9a81eedadb26add7da9a46a5a74d4 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Fri, 6 Sep 2024 18:35:25 +0200 Subject: [PATCH 25/34] =?UTF-8?q?=F0=9F=90=9B=20Multiple=20CSRF=20gens=20i?= =?UTF-8?q?n=20one=20request?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/Misc.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/function/Misc.php b/function/Misc.php index 46c0c91..8e34996 100644 --- a/function/Misc.php +++ b/function/Misc.php @@ -18,6 +18,8 @@ */ final class Misc { + private static string $csrfToken; + /** * Starts a session if one is not already started and returns the session ID. * Session name and cookie parameters are set in the Config class. @@ -43,9 +45,11 @@ public static function session(): string|false */ public static function generateCsrfToken(): string { - $token = bin2hex(random_bytes(Config::CSRF_LENGTH / 2)); - Request::setSession($token, "csrf-token"); - return $token; + if (empty(self::$csrfToken)) { + self::$csrfToken = bin2hex(random_bytes(Config::CSRF_LENGTH / 2)); + Request::setSession(self::$csrfToken, Config::CSRF_TEMPLATE); + } + return self::$csrfToken; } /** From dec9443bedf00aeac7e780da92dbf146e42c95f2 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Fri, 6 Sep 2024 18:36:25 +0200 Subject: [PATCH 26/34] =?UTF-8?q?=F0=9F=94=96=20Version=203.2.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/FileRouter.php | 2 +- home/index.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index d9a02d1..15e56f6 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.2.1 +Version: 3.2.2 */ diff --git a/function/FileRouter.php b/function/FileRouter.php index fa919f6..f94a124 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.2.1 +Version: 3.2.2 */ diff --git a/home/index.php b/home/index.php index d0f914c..0e2423b 100644 --- a/home/index.php +++ b/home/index.php @@ -7,7 +7,7 @@ by Friedinger (friedinger.org) -Version: 3.2.1 +Version: 3.2.2 */ From 1e8550ef066704c03cc0267d57162a7be3bb5784 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Fri, 6 Sep 2024 19:28:55 +0200 Subject: [PATCH 27/34] =?UTF-8?q?=F0=9F=92=A1=20Add=20link=20to=20repo=20a?= =?UTF-8?q?s=20comment?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 ++ function/ControllerDefault.php | 2 ++ function/ControllerHtml.php | 2 ++ function/ControllerImage.php | 2 ++ function/ErrorPage.php | 2 ++ function/FileRouter.php | 2 ++ function/Logger.php | 2 ++ function/Misc.php | 2 ++ function/Output.php | 2 ++ function/Proxy.php | 2 ++ function/Request.php | 2 ++ function/Router.php | 2 ++ home/index.php | 2 ++ 13 files changed, 26 insertions(+) diff --git a/config/config_sample.php b/config/config_sample.php index 15e56f6..8d00e53 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) Version: 3.2.2 diff --git a/function/ControllerDefault.php b/function/ControllerDefault.php index acf85bd..82c6218 100644 --- a/function/ControllerDefault.php +++ b/function/ControllerDefault.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) */ diff --git a/function/ControllerHtml.php b/function/ControllerHtml.php index 92c8c9e..b1f6644 100644 --- a/function/ControllerHtml.php +++ b/function/ControllerHtml.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) */ diff --git a/function/ControllerImage.php b/function/ControllerImage.php index fa2223e..ce2ebe5 100644 --- a/function/ControllerImage.php +++ b/function/ControllerImage.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) */ diff --git a/function/ErrorPage.php b/function/ErrorPage.php index 510de79..8819566 100644 --- a/function/ErrorPage.php +++ b/function/ErrorPage.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) */ diff --git a/function/FileRouter.php b/function/FileRouter.php index f94a124..796876d 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) Version: 3.2.2 diff --git a/function/Logger.php b/function/Logger.php index 2e2acda..ff3a959 100644 --- a/function/Logger.php +++ b/function/Logger.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) */ diff --git a/function/Misc.php b/function/Misc.php index 8e34996..f3d00c2 100644 --- a/function/Misc.php +++ b/function/Misc.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) */ diff --git a/function/Output.php b/function/Output.php index a2c654a..6396522 100644 --- a/function/Output.php +++ b/function/Output.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) */ diff --git a/function/Proxy.php b/function/Proxy.php index 5aa3970..7866a66 100644 --- a/function/Proxy.php +++ b/function/Proxy.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) */ diff --git a/function/Request.php b/function/Request.php index 81c8cde..464d703 100644 --- a/function/Request.php +++ b/function/Request.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) */ diff --git a/function/Router.php b/function/Router.php index 3e39007..a0f0d55 100644 --- a/function/Router.php +++ b/function/Router.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) */ diff --git a/home/index.php b/home/index.php index 0e2423b..368bdb7 100644 --- a/home/index.php +++ b/home/index.php @@ -5,6 +5,8 @@ FileRouter A simple php router that allows to run code before accessing a file while keeping the file structure as the url structure. +https://github.com/Friedinger/FileRouter + by Friedinger (friedinger.org) Version: 3.2.2 From 7b1dfed9fb52df9d640e0c9b0a7e3b66d4d46d47 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Wed, 11 Sep 2024 17:49:46 +0200 Subject: [PATCH 28/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20redirect?= =?UTF-8?q?=20to=20exception?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/FileRouter.php | 2 ++ function/Redirect.php | 27 +++++++++++++++++++++++++++ modules/header.php | 2 +- public/redirect/_route.php | 3 +++ 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 function/Redirect.php create mode 100644 public/redirect/_route.php diff --git a/function/FileRouter.php b/function/FileRouter.php index 796876d..f9f09c7 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -25,6 +25,8 @@ public function __construct() $this->handle(); // Handle request } catch (ErrorPage) { // Error page was displayed in ErrorPage exception + } catch (Redirect) { + // Redirect was handled in Redirect exception } catch (\Throwable $exception) { $this->handleException($exception); // Handle unhandled exceptions } diff --git a/function/Redirect.php b/function/Redirect.php new file mode 100644 index 0000000..d406f40 --- /dev/null +++ b/function/Redirect.php @@ -0,0 +1,27 @@ + - Header: Home Protect Proxy CSRF Error + Header: Home Protect Proxy CSRF Error Redirect \ No newline at end of file diff --git a/public/redirect/_route.php b/public/redirect/_route.php new file mode 100644 index 0000000..67cf4ad --- /dev/null +++ b/public/redirect/_route.php @@ -0,0 +1,3 @@ + Date: Wed, 11 Sep 2024 20:51:58 +0200 Subject: [PATCH 29/34] =?UTF-8?q?=F0=9F=97=91=EF=B8=8F=20Mark=20Router::re?= =?UTF-8?q?direct=20as=20deprecated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/Router.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/function/Router.php b/function/Router.php index a0f0d55..ab2cb71 100644 --- a/function/Router.php +++ b/function/Router.php @@ -54,13 +54,14 @@ public static function handle(string $uri = null): bool /** * Redirects to specified URI. + * @deprecated Use "throw new Redirect($uri)" instead. * * @param string $uri URI to redirect to. */ public static function redirect(string $uri): void { - $uri = Misc::prepareUri($uri); // Prepare uri - header("Location: /$uri/"); // Set location header + trigger_error("Method " . __METHOD__ . " is deprecated. Use \"throw new Redirect(\$uri)\" instead.", E_USER_DEPRECATED); + throw new Redirect($uri); } private static function searchPath(string $uri): string From f6612ca89c6b5432d670f640fa7076865129e94b Mon Sep 17 00:00:00 2001 From: Friedinger Date: Wed, 11 Sep 2024 20:58:44 +0200 Subject: [PATCH 30/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20proxy=20c?= =?UTF-8?q?allable=20execution?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/Proxy.php | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/function/Proxy.php b/function/Proxy.php index 7866a66..3be436e 100644 --- a/function/Proxy.php +++ b/function/Proxy.php @@ -20,7 +20,7 @@ */ class Proxy { - private static $handleCustom; + private static mixed $handleCustom; /** * Loads and processes route file. @@ -63,24 +63,21 @@ public function handle(string $uri = null): bool */ public static function handleCustom(Output $content, Output $settings): Output { - $handleCustom = self::$handleCustom ?? null; // Get custom route file callable if set - if (isset($handleCustom)) { - $parameters = [[$content, $settings], [$content], []]; // Define parameter combinations - $success = false; // Flag indicating if callable was successful - foreach ($parameters as $parameter) { - try { - $return = call_user_func_array($handleCustom, $parameter); // Call function with parameters - if ($return instanceof Output) $content = $return; // Set content to return value if output - $success = true; - break; - } catch (\Throwable $e) { - // Continue with next parameter combination if callable failed - } - } - if (!$success) { - throw new ErrorPage(500, "Error in route file callable: {$e->getMessage()}"); // Error 500 if callable failed with all parameter combinations - } - } + // No handling if no custom route file callable set + if (!isset(self::$handleCustom)) return $content; + + // Get parameters of custom route file callable + $reflection = new \ReflectionFunction(self::$handleCustom); + $parameters = array_map(function ($parameter) use ($content, $settings) { + return match ($parameter->getName()) { + "content" => $content, + "settings" => $settings, + default => null, + }; + }, $reflection->getParameters()); + + $return = call_user_func_array(self::$handleCustom, $parameters); // Call custom route file callable with parameters + if ($return instanceof Output) $content = $return; // Set content to return value if output return $content; // Return handled content } From 02a1b24971573e21f60dcdfe6c8e480ceb5fca8e Mon Sep 17 00:00:00 2001 From: Friedinger Date: Wed, 11 Sep 2024 21:13:38 +0200 Subject: [PATCH 31/34] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20getRouteF?= =?UTF-8?q?ile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- function/Proxy.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/function/Proxy.php b/function/Proxy.php index 3be436e..02fb64f 100644 --- a/function/Proxy.php +++ b/function/Proxy.php @@ -83,15 +83,17 @@ public static function handleCustom(Output $content, Output $settings): Output private function getRouteFile(string $path): string|null { - $path = $_SERVER["DOCUMENT_ROOT"] . Config::PATH_PUBLIC . $path; // Combine document root, public path and URI to get file path + // Combine document root, public path and URI to get full path + $path = rtrim($_SERVER["DOCUMENT_ROOT"] . Config::PATH_PUBLIC . $path, '/'); - // Find route file in directory structure up to 100 directories deep - for ($iteration = 0; $iteration < 100; $iteration++) { + while ($path != rtrim($_SERVER["DOCUMENT_ROOT"] . Config::PATH_PUBLIC, '/')) { $file = "{$path}/_route.php"; // Construct route file path - if (file_exists($file)) return $file; // Check if route file exists - if ($path == $_SERVER["DOCUMENT_ROOT"] . Config::PATH_PUBLIC) break; // Stop if public path reached - $path = dirname($path) . "/"; // Move up one directory + if (file_exists($file)) { + return $file; // Check if route file exists + } + $path = dirname($path); // Move up one directory } + return null; // Return null if no route file found } } From 296bf2071e77a4bd5ccebc3873bcd39e6b58cb81 Mon Sep 17 00:00:00 2001 From: Friedinger Date: Mon, 30 Sep 2024 15:18:39 +0200 Subject: [PATCH 32/34] =?UTF-8?q?=F0=9F=94=96=20Version=203.3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/FileRouter.php | 2 +- home/index.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index 8d00e53..6ac6a01 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -9,7 +9,7 @@ by Friedinger (friedinger.org) -Version: 3.2.2 +Version: 3.3.0 */ diff --git a/function/FileRouter.php b/function/FileRouter.php index f9f09c7..18fb8ce 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -9,7 +9,7 @@ by Friedinger (friedinger.org) -Version: 3.2.2 +Version: 3.3.0 */ diff --git a/home/index.php b/home/index.php index 368bdb7..999bdcc 100644 --- a/home/index.php +++ b/home/index.php @@ -9,7 +9,7 @@ by Friedinger (friedinger.org) -Version: 3.2.2 +Version: 3.3.0 */ From ddcb6be07cf3ba30eb710e47a95fc3da3a10e13b Mon Sep 17 00:00:00 2001 From: Friedinger Date: Sat, 23 Nov 2024 13:35:01 +0100 Subject: [PATCH 33/34] =?UTF-8?q?=F0=9F=A7=91=E2=80=8D=F0=9F=92=BB=20Loggi?= =?UTF-8?q?ng=20and=20exception=20handling=20improvements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 1 + function/ControllerHtml.php | 2 +- function/FileRouter.php | 4 ++-- function/Logger.php | 28 +++++++++++++++++++++++++--- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index 6ac6a01..40686f0 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -50,6 +50,7 @@ class Config // Error handling and logging const DEBUG = true; // Enable debug mode (shows errors and warnings, disables error logging) const LOG = true; // Enable logging + const LOG_MAX_FILE_SIZE = 1048576; // Maximum file size of log files before a new file is created (in bytes) const LOG_PATH = [ // Paths to log files (relative to the server root, {date} will be replaced with the current date) "error" => "/../logs/error_{date}.log", // Error log file required if logging is enabled "additional" => "/../logs/additional.log", // Additional log files, can be used for custom logging by Logger::log("message", "additional") diff --git a/function/ControllerHtml.php b/function/ControllerHtml.php index b1f6644..ac25be9 100644 --- a/function/ControllerHtml.php +++ b/function/ControllerHtml.php @@ -60,7 +60,7 @@ public static function handleHtml(Output $content): Output $content = self::handleFooter($content); // Output CSRF token if enabled - if (Config::SESSION && COnfig::CSRF_LENGTH > 0) { + if (Config::SESSION && Config::CSRF_LENGTH > 0) { $content->replaceAllSafe(Config::CSRF_TEMPLATE, Misc::generateCsrfToken()); } diff --git a/function/FileRouter.php b/function/FileRouter.php index 18fb8ce..307a711 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -82,11 +82,11 @@ private function handleException(\Throwable $exception): void Logger::logError("{$exception->getMessage()} in {$exception->getFile()}({$exception->getLine()})", E_USER_ERROR); // Log unhandled exceptions throw new ErrorPage(500); // Internal server error if unhandled exception occurred } catch (\Throwable $e) { + if ($e instanceof ErrorPage) return; if (Config::LOG) { error_log("ERROR {$e->getMessage()} in exception handling"); // Log error message } - echo Config::ERROR_FATAL ?? "

Error

An error occurred in the request.

Please contact the webmaster

"; - return; + die(Config::ERROR_FATAL ?? "

Error

An error occurred in the request.

Please contact the webmaster

"); } } diff --git a/function/Logger.php b/function/Logger.php index ff3a959..21a1a29 100644 --- a/function/Logger.php +++ b/function/Logger.php @@ -22,8 +22,12 @@ public static function log(string $message, string $type): void $date = date("Y-m-d H:i:s"); $file = self::logPath($type); - $logMessage = "[$date] $message" . PHP_EOL; - file_put_contents($file, $logMessage, FILE_APPEND); + + $message = str_replace("\n", "\n\t", $message); + $message = str_replace("\r", "", $message); + $log = "[$date] $message" . PHP_EOL; + + file_put_contents($file, $log, FILE_APPEND); } public static function logError(string $message, int $level): void @@ -48,6 +52,24 @@ public static function logPath(string $type): string { $path = Config::LOG_PATH[$type] ?? "filerouter_{date}.log"; $path = str_replace("{date}", date("Y-m-d"), $path); - return $_SERVER["DOCUMENT_ROOT"] . $path; + $file = $_SERVER["DOCUMENT_ROOT"] . $path; + if (file_exists($file) && filesize($file) >= Config::LOG_MAX_FILE_SIZE) { + $file = self::getNewLogFile($file); + } + return $file; + } + + private static function getNewLogFile($file) + { + $logDir = dirname($file); + $baseName = basename($file, '.log'); + $index = 1; + + do { + $newFile = $logDir . DIRECTORY_SEPARATOR . $baseName . '_' . $index . '.log'; + $index++; + } while (file_exists($newFile)); + + return $newFile; } } From dd5d1f38cecc23368bc215929b0db5168fe86d3e Mon Sep 17 00:00:00 2001 From: Friedinger Date: Sat, 23 Nov 2024 13:35:37 +0100 Subject: [PATCH 34/34] =?UTF-8?q?=F0=9F=94=96=20Version=203.3.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/config_sample.php | 2 +- function/FileRouter.php | 2 +- home/index.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config_sample.php b/config/config_sample.php index 40686f0..f5d7835 100644 --- a/config/config_sample.php +++ b/config/config_sample.php @@ -9,7 +9,7 @@ by Friedinger (friedinger.org) -Version: 3.3.0 +Version: 3.3.1 */ diff --git a/function/FileRouter.php b/function/FileRouter.php index 307a711..8c649d2 100644 --- a/function/FileRouter.php +++ b/function/FileRouter.php @@ -9,7 +9,7 @@ by Friedinger (friedinger.org) -Version: 3.3.0 +Version: 3.3.1 */ diff --git a/home/index.php b/home/index.php index 999bdcc..030d10b 100644 --- a/home/index.php +++ b/home/index.php @@ -9,7 +9,7 @@ by Friedinger (friedinger.org) -Version: 3.3.0 +Version: 3.3.1 */