Routing, static views

This commit is contained in:
Roman Hergenreder 2020-06-22 19:09:02 +02:00
parent 0f1c86f210
commit eb04206989
12 changed files with 182 additions and 193 deletions

@ -1,14 +1,16 @@
php_flag display_errors on
Options -Indexes
DirectorySlash Off
RewriteEngine On
RewriteRule ^api(/.*)?$ /index.php?api=$1 [L,QSA]
<IfModule mod_rewrite.c>
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]
</IfModule>
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]

@ -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;
}

@ -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() {

@ -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 .= "<body>" . (new View404($this->getDocument())) . "</body>";
return $html;
protected function getContent() {
return $this->load(View404::class);
}
}
}

@ -1,78 +0,0 @@
<?php
namespace Documents {
use Documents\Welcome\WelcomeBody;
use Documents\Welcome\WelcomeHead;
use Elements\Document;
use Objects\User;
class Welcome extends Document {
public function __construct(User $user, ?string $view) {
parent::__construct($user, WelcomeHead::class, WelcomeBody::class, $view);
}
}
}
namespace Documents\Welcome {
use Elements\Head;
use Elements\SimpleBody;
class WelcomeHead extends Head {
public function __construct($document) {
parent::__construct($document);
}
protected function initSources() {
$this->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
"<div class='container mt-5'>
<div class='row'>
<div class='col-lg-9 col-12 mx-auto'>
<div class='jumbotron'>
<h1>Congratulations!</h1>
<p class='lead'>Your Web-Base Installation is now ready to use!</p>
<hr class='my-4' />
<p>
You can now login into your <a href='/admin'>Administrator Dashboard</a> 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.
</p>
</div>
</div>
</div>
</div>";
}
}
}

@ -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();

@ -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) {

@ -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 {
"<img class=\"p-1 clickable\" src=\"/img/icons/lang/$langCode.gif\" alt=\"$langName\" title=\"$langName\">"
);
}
return implode('', $this->languageFlags);
}
}
public function getCode() {
return implode('', $this->languageFlags);
}
}

@ -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();

@ -1,104 +1,122 @@
<?php
define("WEBBASE_VERSION", "0.1.0-alpha");
define("WEBBASE_VERSION", "0.1.0-alpha");
function getSubclassesOf($parent) {
$result = array();
foreach (get_declared_classes() as $class) {
if (is_subclass_of($class, $parent))
$result[] = $class;
}
return $result;
}
function getProtocol() {
return stripos($_SERVER['SERVER_PROTOCOL'], 'https') === 0 ? 'https' : 'http';
}
function getProtocol() {
return stripos($_SERVER['SERVER_PROTOCOL'],'https') === 0 ? 'https' : 'http';
}
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);
}
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 "<b>Access restricted, requested file outside web root:</b> " . htmlspecialchars($path);
}
if (!file_exists($path) || !is_file($path) || !is_readable($path)) {
http_response_code(500);
return "<b>Unable to read file:</b> " . 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 "<b>Access restricted:</b> Extension '" . htmlspecialchars($ext) . "' not allowed.";
}
$mimeType = mime_content_type($file);
header("Content-Type: $mimeType");
return readfile($file);
}

@ -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"] ?? "";

30
static/welcome.html Normal file

@ -0,0 +1,30 @@
<!DOCTYPE html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="format-detection" content="telephone=yes">
<meta charset="utf-8">
<meta http-equiv="expires" content="0">
<meta name="robots" content="noarchive">
<title>Welcome</title>
<link rel="stylesheet" href="/css/bootstrap.min.css" type="text/css">
<script type="text/javascript" src="/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container mt-5">
<div class="row">
<div class="col-lg-9 col-12 mx-auto">
<div class="jumbotron">
<h1>Congratulations!</h1>
<p class="lead">Your Web-Base Installation is now ready to use!</p>
<hr class="my-4" />
<p>
You can now login into your <a href="/admin">Administrator Dashboard</a> 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.
</p>
</div>
</div>
</div>
</div>
</body>