Browse Source

Routing, static views

Roman Hergenreder 3 years ago
parent
commit
eb04206989

+ 10 - 8
.htaccess

@@ -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]

+ 1 - 1
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;
   }

+ 0 - 5
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() {

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

+ 0 - 78
core/Documents/Welcome.class.php

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

+ 1 - 0
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();

+ 17 - 0
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) {

+ 7 - 3
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 {
           "<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);
+  }
 }

+ 1 - 1
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();

+ 96 - 78
core/core.php

@@ -1,104 +1,122 @@
 <?php
 
-  define("WEBBASE_VERSION", "0.1.0-alpha");
+define("WEBBASE_VERSION", "0.1.0-alpha");
+
+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);
+      }
 
-  function getSubclassesOf($parent) {
-    $result = array();
-    foreach (get_declared_classes() as $class) {
-        if (is_subclass_of($class, $parent))
-            $result[] = $class;
+      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 $result;
   }
 
-  function getProtocol() {
-    return stripos($_SERVER['SERVER_PROTOCOL'],'https') === 0 ? 'https' : 'http';
-  }
+  return $randomString;
+}
 
-  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);
-      }
+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 $randomString;
-  }
+    $newCode .= str_repeat(" ", $intend);
+    $newCode .= $line;
+    $first = false;
 
-  function startsWith($haystack, $needle) {
-   $length = strlen($needle);
-   return (substr($haystack, 0, $length) === $needle);
+    if (endsWith($line, "{")) {
+      $intend += 2;
+      array_push($brackets, "}");
+    } else if (endsWith($line, "(")) {
+      $intend += 2;
+      array_push($brackets, ")");
+    }
   }
 
-  function endsWith($haystack, $needle) {
-    $length = strlen($needle);
-    if ($length == 0)
-        return true;
+  return $newCode;
+}
 
-    return (substr($haystack, -$length) === $needle);
-  }
+function replaceCssSelector($sel) {
+  return preg_replace("~[.#<>]~", "_", preg_replace("~[:\-]~", "", $sel));
+}
 
-  function intendCode($code, $escape=true) {
-    $newCode = "";
-    $first = true;
-    $brackets = array();
-    $intend = 0;
+function getClassPath($class, $suffix = true) {
+  $path = str_replace('\\', '/', $class);
+  $path = array_values(array_filter(explode("/", $path)));
 
-    foreach(explode("\n", $code) as $line) {
-      if(!$first) $newCode .= "\n";
-      if($escape) $line = htmlspecialchars($line);
-      $line = trim($line);
+  if (strcasecmp($path[0], "api") === 0 && count($path) > 2 && strcasecmp($path[1], "Parameter") !== 0) {
+    $path = "Api/" . $path[1] . "API";
+  } else {
+    $path = implode("/", $path);
+  }
 
-      if(count($brackets) > 0 && startsWith($line, current($brackets))) {
-        $intend = max(0, $intend - 2);
-        array_pop($brackets);
-      }
+  $suffix = ($suffix ? ".class" : "");
+  return "core/$path$suffix.php";
+}
 
-      $newCode .= str_repeat(" ", $intend);
-      $newCode .= $line;
-      $first = false;
+function createError($msg) {
+  return json_encode(array("success" => false, "msg" => $msg));
+}
 
-      if(endsWith($line, "{")) {
-        $intend += 2;
-        array_push($brackets, "}");
-      } else if(endsWith($line, "(")) {
-        $intend += 2;
-        array_push($brackets, ")");
-      }
-    }
+function serveStatic(string $webRoot, string $file): string {
 
-    return $newCode;
+  $path = realpath($webRoot . "/" . $file);
+  if (!startsWith($path, $webRoot . "/")) {
+    http_response_code(406);
+    return "<b>Access restricted, requested file outside web root:</b> " . htmlspecialchars($path);
   }
 
-  function replaceCssSelector($sel) {
-    return preg_replace("~[.#<>]~", "_", preg_replace("~[:\-]~", "", $sel));
+  if (!file_exists($path) || !is_file($path) || !is_readable($path)) {
+    http_response_code(500);
+    return "<b>Unable to read file:</b> " . htmlspecialchars($path);
   }
 
-  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);
-    }
+  $pathInfo = pathinfo($file);
 
-    $suffix = ($suffix ? ".class" : "");
-    return "core/$path$suffix.php";
+  // 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.";
   }
 
-  function createError($msg) {
-    return json_encode(array("success" => false, "msg" => $msg));
-  }
+  $mimeType = mime_content_type($file);
+  header("Content-Type: $mimeType");
+  return readfile($file);
+}

+ 3 - 2
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"] ?? "";

+ 30 - 0
static/welcome.html

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