diff --git a/.htaccess b/.htaccess
index ac1bc2f..33564f1 100644
--- a/.htaccess
+++ b/.htaccess
@@ -1,14 +1,16 @@
php_flag display_errors on
Options -Indexes
+DirectorySlash Off
+
RewriteEngine On
RewriteRule ^api(/.*)?$ /index.php?api=$1 [L,QSA]
-
- RewriteEngine On
- DirectorySlash Off
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteCond %{REQUEST_FILENAME} !-d [OR]
- RewriteCond %{REQUEST_URI} "(\.idea|\.git|src|test|core)(/.*)?"
- RewriteRule ^(.*)$ /index.php?site=$1 [L,QSA]
-
\ No newline at end of file
+RewriteEngine On
+RewriteOptions AllowNoSlash
+RewriteRule ^((\.idea|\.git|src|test|core|static)(/.*)?)$ /index.php?site=$1 [L,QSA]
+
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteRule ^(.*)$ /index.php?site=$1 [L,QSA]
\ No newline at end of file
diff --git a/core/Configuration/CreateDatabase.class.php b/core/Configuration/CreateDatabase.class.php
index 6eeb3df..d32d9bc 100755
--- a/core/Configuration/CreateDatabase.class.php
+++ b/core/Configuration/CreateDatabase.class.php
@@ -133,7 +133,7 @@ class CreateDatabase {
->addRow("^/register(/)?$", "dynamic", "\\Documents\\Account", "\\Views\\Account\\Register")
->addRow("^/confirmEmail(/)?$", "dynamic", "\\Documents\\Account", "\\Views\\Account\\ConfirmEmail")
->addRow("^/acceptInvite(/)?$", "dynamic", "\\Documents\\Account", "\\Views\\Account\\AcceptInvite")
- ->addRow("^/$", "dynamic", "\\Documents\\Welcome", NULL);
+ ->addRow("^/$", "static", "/static/welcome.html", NULL);
return $queries;
}
diff --git a/core/Documents/Admin.class.php b/core/Documents/Admin.class.php
index 9389ccf..f0bbc29 100644
--- a/core/Documents/Admin.class.php
+++ b/core/Documents/Admin.class.php
@@ -29,12 +29,7 @@ namespace Documents\Admin {
}
protected function initSources() {
-// $this->loadJQuery();
$this->loadFontawesome();
-// $this->addJS(Script::CORE);
-// $this->addCSS(Link::CORE);
-// $this->addJS(Script::ADMIN);
-// $this->addCSS(Link::ADMIN);
}
protected function initMetas() {
diff --git a/core/Documents/Document404.class.php b/core/Documents/Document404.class.php
index b93523e..fa97af3 100644
--- a/core/Documents/Document404.class.php
+++ b/core/Documents/Document404.class.php
@@ -17,6 +17,7 @@ namespace Documents\Document404 {
use Elements\Body;
use Elements\Head;
+ use Elements\SimpleBody;
use Views\View404;
class Head404 extends Head {
@@ -47,7 +48,7 @@ namespace Documents\Document404 {
}
}
- class Body404 extends Body {
+ class Body404 extends SimpleBody {
public function __construct($document) {
parent::__construct($document);
@@ -57,10 +58,8 @@ namespace Documents\Document404 {
http_response_code(404);
}
- public function getCode() {
- $html = parent::getCode();
- $html .= "
" . (new View404($this->getDocument())) . "";
- return $html;
+ protected function getContent() {
+ return $this->load(View404::class);
}
}
}
diff --git a/core/Documents/Welcome.class.php b/core/Documents/Welcome.class.php
deleted file mode 100644
index b573e06..0000000
--- a/core/Documents/Welcome.class.php
+++ /dev/null
@@ -1,78 +0,0 @@
-loadBootstrap();
- }
-
- protected function initMetas() {
- return array(
- array('name' => 'viewport', 'content' => 'width=device-width, initial-scale=1.0'),
- array('name' => 'format-detection', 'content' => 'telephone=yes'),
- array('charset' => 'utf-8'),
- array("http-equiv" => 'expires', 'content' => '0'),
- array("name" => 'robots', 'content' => 'noarchive'),
- );
- }
-
- protected function initRawFields() {
- return array();
- }
-
- protected function initTitle() {
- return "Welcome";
- }
- }
-
- class WelcomeBody extends SimpleBody {
-
- public function __construct($document) {
- parent::__construct($document);
- }
-
- protected function getContent() {
- return
- "
-
-
-
-
Congratulations!
-
Your Web-Base Installation is now ready to use!
-
-
- You can now login into your Administrator Dashboard to adjust your settings
- and add routes & pages.
- You can add new documents and views by adding classes in the corresponding
- directories and link to them, by creating rules in the Administrator Dashboard.
-
-
-
-
-
";
- }
- }
-}
\ No newline at end of file
diff --git a/core/Elements/Head.class.php b/core/Elements/Head.class.php
index ac071ab..a69928d 100644
--- a/core/Elements/Head.class.php
+++ b/core/Elements/Head.class.php
@@ -15,6 +15,7 @@ abstract class Head extends View {
function __construct($document) {
parent::__construct($document);
$this->sources = array();
+ $this->searchable = false;
$this->metas = $this->initMetas();
$this->rawFields = $this->initRawFields();
$this->title = $this->initTitle();
diff --git a/core/Elements/View.class.php b/core/Elements/View.class.php
index 3b16f2f..873c458 100644
--- a/core/Elements/View.class.php
+++ b/core/Elements/View.class.php
@@ -2,6 +2,8 @@
namespace Elements;
+use External\PHPMailer\Exception;
+
abstract class View extends StaticView {
private Document $document;
@@ -25,6 +27,21 @@ abstract class View extends StaticView {
public function isSearchable() { return $this->searchable; }
public function getReference() { return $this->reference; }
+ protected function load(string $viewClass) : string {
+ try {
+ $reflectionClass = new \ReflectionClass($viewClass);
+ if ($reflectionClass->isSubclassOf(View::class) && $reflectionClass->isInstantiable()) {
+ $view = $reflectionClass->newInstanceArgs(array($this->getDocument()));
+ $view->loadView();
+ return $view;
+ }
+ } catch(\ReflectionException $e) {
+ error_log($e->getMessage());
+ }
+
+ return "";
+ }
+
private function loadLanguageModules() {
$lang = $this->document->getUser()->getLanguage();
foreach($this->langModules as $langModule) {
diff --git a/core/Views/LanguageFlags.class.php b/core/Views/LanguageFlags.class.php
index 5a76854..381ef1b 100644
--- a/core/Views/LanguageFlags.class.php
+++ b/core/Views/LanguageFlags.class.php
@@ -11,9 +11,11 @@ class LanguageFlags extends View {
public function __construct($document) {
parent::__construct($document);
$this->languageFlags = array();
+ $this->searchable = false;
}
- public function getCode() {
+ public function loadView() {
+ parent::loadView();
$request = new \Api\Language\Get($this->getDocument()->getUser());
if ($request->execute()) {
@@ -51,8 +53,10 @@ class LanguageFlags extends View {
" "
);
}
-
- return implode('', $this->languageFlags);
}
}
+
+ public function getCode() {
+ return implode('', $this->languageFlags);
+ }
}
\ No newline at end of file
diff --git a/core/Views/LoginBody.class.php b/core/Views/LoginBody.class.php
index fb089f5..25e1c73 100644
--- a/core/Views/LoginBody.class.php
+++ b/core/Views/LoginBody.class.php
@@ -32,7 +32,7 @@ class LoginBody extends Body {
$backToStartPage = L("Back to Start Page");
$stayLoggedIn = L("Stay logged in");
- $flags = new LanguageFlags($this->getDocument());
+ $flags = $this->load(LanguageFlags::class);
$iconBack = $this->createIcon("arrow-circle-left");
$domain = $_SERVER['HTTP_HOST'];
$protocol = getProtocol();
diff --git a/core/core.php b/core/core.php
index 26af7e6..a75510f 100644
--- a/core/core.php
+++ b/core/core.php
@@ -1,104 +1,122 @@
0) {
- $numCharacters = 26 + 26 + 10; // a-z + A-Z + 0-9
- for ($i = 0; $i < $length; $i++)
- {
- try {
- $num = random_int(0, $numCharacters - 1);
- } catch (Exception $e) {
- $num = rand(0, $numCharacters - 1);
- }
-
- if($num < 26) $randomString .= chr(ord('a') + $num);
- else if($num - 26 < 26) $randomString .= chr(ord('A') + $num - 26);
- else $randomString .= chr(ord('0') + $num - 26 - 26);
- }
- }
-
- return $randomString;
- }
-
- function startsWith($haystack, $needle) {
- $length = strlen($needle);
- return (substr($haystack, 0, $length) === $needle);
- }
-
- function endsWith($haystack, $needle) {
- $length = strlen($needle);
- if ($length == 0)
- return true;
-
- return (substr($haystack, -$length) === $needle);
- }
-
- function intendCode($code, $escape=true) {
- $newCode = "";
- $first = true;
- $brackets = array();
- $intend = 0;
-
- foreach(explode("\n", $code) as $line) {
- if(!$first) $newCode .= "\n";
- if($escape) $line = htmlspecialchars($line);
- $line = trim($line);
-
- if(count($brackets) > 0 && startsWith($line, current($brackets))) {
- $intend = max(0, $intend - 2);
- array_pop($brackets);
+function generateRandomString($length): string {
+ $randomString = '';
+ if ($length > 0) {
+ $numCharacters = 26 + 26 + 10; // a-z + A-Z + 0-9
+ for ($i = 0; $i < $length; $i++) {
+ try {
+ $num = random_int(0, $numCharacters - 1);
+ } catch (Exception $e) {
+ $num = rand(0, $numCharacters - 1);
}
- $newCode .= str_repeat(" ", $intend);
- $newCode .= $line;
- $first = false;
+ if ($num < 26) $randomString .= chr(ord('a') + $num);
+ else if ($num - 26 < 26) $randomString .= chr(ord('A') + $num - 26);
+ else $randomString .= chr(ord('0') + $num - 26 - 26);
+ }
+ }
- if(endsWith($line, "{")) {
- $intend += 2;
- array_push($brackets, "}");
- } else if(endsWith($line, "(")) {
- $intend += 2;
- array_push($brackets, ")");
- }
+ return $randomString;
+}
+
+function startsWith($haystack, $needle) {
+ $length = strlen($needle);
+ return (substr($haystack, 0, $length) === $needle);
+}
+
+function endsWith($haystack, $needle) {
+ $length = strlen($needle);
+ if ($length == 0)
+ return true;
+
+ return (substr($haystack, -$length) === $needle);
+}
+
+function intendCode($code, $escape = true) {
+ $newCode = "";
+ $first = true;
+ $brackets = array();
+ $intend = 0;
+
+ foreach (explode("\n", $code) as $line) {
+ if (!$first) $newCode .= "\n";
+ if ($escape) $line = htmlspecialchars($line);
+ $line = trim($line);
+
+ if (count($brackets) > 0 && startsWith($line, current($brackets))) {
+ $intend = max(0, $intend - 2);
+ array_pop($brackets);
}
- return $newCode;
- }
+ $newCode .= str_repeat(" ", $intend);
+ $newCode .= $line;
+ $first = false;
- function replaceCssSelector($sel) {
- return preg_replace("~[.#<>]~", "_", preg_replace("~[:\-]~", "", $sel));
- }
-
- function getClassPath($class, $suffix=true) {
- $path = str_replace('\\', '/', $class);
- $path = array_values(array_filter(explode("/", $path)));
-
- if (strcasecmp($path[0], "api") === 0 && count($path) > 2 && strcasecmp($path[1], "Parameter") !== 0) {
- $path = "Api/" . $path[1] . "API";
- } else {
- $path = implode("/", $path);
+ if (endsWith($line, "{")) {
+ $intend += 2;
+ array_push($brackets, "}");
+ } else if (endsWith($line, "(")) {
+ $intend += 2;
+ array_push($brackets, ")");
}
-
- $suffix = ($suffix ? ".class" : "");
- return "core/$path$suffix.php";
}
- function createError($msg) {
- return json_encode(array("success" => false, "msg" => $msg));
+ return $newCode;
+}
+
+function replaceCssSelector($sel) {
+ return preg_replace("~[.#<>]~", "_", preg_replace("~[:\-]~", "", $sel));
+}
+
+function getClassPath($class, $suffix = true) {
+ $path = str_replace('\\', '/', $class);
+ $path = array_values(array_filter(explode("/", $path)));
+
+ if (strcasecmp($path[0], "api") === 0 && count($path) > 2 && strcasecmp($path[1], "Parameter") !== 0) {
+ $path = "Api/" . $path[1] . "API";
+ } else {
+ $path = implode("/", $path);
}
+
+ $suffix = ($suffix ? ".class" : "");
+ return "core/$path$suffix.php";
+}
+
+function createError($msg) {
+ return json_encode(array("success" => false, "msg" => $msg));
+}
+
+function serveStatic(string $webRoot, string $file): string {
+
+ $path = realpath($webRoot . "/" . $file);
+ if (!startsWith($path, $webRoot . "/")) {
+ http_response_code(406);
+ return "Access restricted, requested file outside web root: " . htmlspecialchars($path);
+ }
+
+ if (!file_exists($path) || !is_file($path) || !is_readable($path)) {
+ http_response_code(500);
+ return "Unable to read file: " . htmlspecialchars($path);
+ }
+
+ $pathInfo = pathinfo($file);
+
+ // maybe I will allow more later…
+ $allowedExtension = array("html", "htm");
+ $ext = $pathInfo["extension"] ?? "";
+ if (!in_array($ext, $allowedExtension)) {
+ http_response_code(406);
+ return "Access restricted: Extension '" . htmlspecialchars($ext) . "' not allowed.";
+ }
+
+ $mimeType = mime_content_type($file);
+ header("Content-Type: $mimeType");
+ return readfile($file);
+}
diff --git a/index.php b/index.php
index 7ead9e1..5136212 100644
--- a/index.php
+++ b/index.php
@@ -89,6 +89,7 @@ if(isset($_GET["api"]) && is_string($_GET["api"])) {
$success = $req->execute(array("request" => $documentName));
$response = "";
if (!$success) {
+ http_response_code(500);
$response = "Unable to find route: " . $req->getLastError();
} else {
$route = $req->getResult()["route"];
@@ -106,8 +107,8 @@ if(isset($_GET["api"]) && is_string($_GET["api"])) {
header("Location: $target");
break;
case "static":
- http_response_code(501);
- $response = "Not implemented yet.";
+ $currentDir = dirname(__FILE__);
+ $response = serveStatic($currentDir, $target);
break;
case "dynamic":
$view = $route["extra"] ?? "";
diff --git a/static/welcome.html b/static/welcome.html
new file mode 100644
index 0000000..4aeac1e
--- /dev/null
+++ b/static/welcome.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+ Welcome
+
+
+
+
+
+
+
+
+
Congratulations!
+
Your Web-Base Installation is now ready to use!
+
+
+ You can now login into your Administrator Dashboard to adjust your settings
+ and add routes & pages.
+ You can add new documents and views by adding classes in the corresponding
+ directories and link to them, by creating rules in the Administrator Dashboard.
+
+
+
+
+
+
\ No newline at end of file