diff --git a/.htaccess b/.htaccess index 73a6f2f..5ce41cb 100644 --- a/.htaccess +++ b/.htaccess @@ -2,8 +2,15 @@ php_flag display_errors on Options -Indexes RedirectMatch 404 /\.git +RedirectMatch 404 /src +RedirectMatch 404 /test RewriteEngine On -RewriteRule ^api/(.*)?$ index.php?api=$1&$2 [L,QSA] -RewriteRule ^admin(/(.*)?)?$ index.php?site=admin&$1 [L,QSA] -RewriteRule ^((?!((js|css|img|fonts|api|docs)($|/)))(.*)?)$ index.php?site=$1&$2 [L,QSA] +RewriteRule ^api(/.*)?$ /index.php?api=$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/Api/Routes/Fetch.class.php b/core/Api/Routes/Fetch.class.php index 6180801..7ff247e 100644 --- a/core/Api/Routes/Fetch.class.php +++ b/core/Api/Routes/Fetch.class.php @@ -7,8 +7,6 @@ use \Driver\SQL\Condition\Compare; class Fetch extends Request { - private array $notifications; - public function __construct($user, $externalCall = false) { parent::__construct($user, $externalCall, array()); $this->loginRequired = true; diff --git a/core/Api/Routes/Find.class.php b/core/Api/Routes/Find.class.php new file mode 100644 index 0000000..328720e --- /dev/null +++ b/core/Api/Routes/Find.class.php @@ -0,0 +1,61 @@ + new StringType('request', 128, true, '/') + )); + + $this->isPublic = false; + } + + public function execute($values = array()) { + if(!parent::execute($values)) { + return false; + } + + $request = $this->getParam('request'); + if (!startsWith($request, '/')) { + $request = "/$request"; + } + + $sql = $this->user->getSQL(); + + $res = $sql + ->select("uid", "request", "action", "target", "extra") + ->from("Route") + ->where(new CondBool("active")) + ->where(new Regex("^$request$", new Column("request"))) + ->limit(1) + ->execute(); + + $this->lastError = $sql->getLastError(); + $this->success = ($res !== FALSE); + + if ($this->success) { + if (!empty($res)) { + $row = $res[0]; + $this->result["route"] = array( + "uid" => intval($row["uid"]), + "request" => $row["request"], + "action" => $row["action"], + "target" => $row["target"], + "extra" => $row["extra"] + ); + } else { + $this->result["route"] = NULL; + } + } + + return $this->success; + } +} \ No newline at end of file diff --git a/core/Configuration/CreateDatabase.class.php b/core/Configuration/CreateDatabase.class.php index 9e3b561..7a9c36d 100755 --- a/core/Configuration/CreateDatabase.class.php +++ b/core/Configuration/CreateDatabase.class.php @@ -129,7 +129,8 @@ class CreateDatabase { ->primaryKey("uid"); $queries[] = $sql->insert("Route", array("request", "action", "target")) - ->addRow("/admin(/.*)?", "dynamic", "\\Core\\Documents\\AdminDashboard"); + ->addRow("/admin(/.*)?", "dynamic", "\\Core\\Documents\\AdminDashboard") + ->addRow("/api/(.*)", "dynamic", "\\Core\\Api\\$1"); return $queries; } diff --git a/core/Driver/SQL/Condition/Regex.class.php b/core/Driver/SQL/Condition/Regex.class.php new file mode 100644 index 0000000..f0ba2bf --- /dev/null +++ b/core/Driver/SQL/Condition/Regex.class.php @@ -0,0 +1,17 @@ +leftExpression = $leftExpression; + $this->rightExpression = $rightExpression; + } + + public function getLeftExp() { return $this->leftExpression; } + public function getRightExp() { return $this->rightExpression; } +} \ No newline at end of file diff --git a/core/Driver/SQL/SQL.class.php b/core/Driver/SQL/SQL.class.php index 743ce06..341ba2c 100644 --- a/core/Driver/SQL/SQL.class.php +++ b/core/Driver/SQL/SQL.class.php @@ -6,6 +6,7 @@ use Driver\SQL\Column\Column; use Driver\SQL\Condition\Compare; use Driver\SQL\Condition\CondBool; use Driver\SQL\Condition\CondOr; +use Driver\SQL\Condition\Regex; use Driver\SQL\Constraint\Constraint; use \Driver\SQL\Constraint\Unique; use \Driver\SQL\Constraint\PrimaryKey; @@ -326,11 +327,17 @@ abstract class SQL { return $this->buildCondition($condition[0], $params); } else { $conditions = array(); - foreach($condition as $cond) { + foreach ($condition as $cond) { $conditions[] = $this->buildCondition($cond, $params); } return implode(" AND ", $conditions); } + } else if ($condition instanceof Regex) { + $left = $condition->getLeftExp(); + $right = $condition->getRightExp(); + $left = ($left instanceof Column) ? $this->columnName($left->getName()) : $this->addValue($left, $params); + $right = ($right instanceof Column) ? $this->columnName($right->getName()) : $this->addValue($right, $params); + return $left . " REGEXP " . $right; } else { $this->lastError = "Unsupported condition type: " . get_class($condition); return false; diff --git a/core/core.php b/core/core.php index 42fa3f6..d51fbea 100644 --- a/core/core.php +++ b/core/core.php @@ -85,6 +85,7 @@ function getClassPath($class, $suffix=true) { $path = str_replace('\\', '/', $class); + if (startsWith($path, "/")) $path = substr($path, 1); $suffix = ($suffix ? ".class" : ""); return "core/$path$suffix.php"; } diff --git a/index.php b/index.php index 90c82ae..c85e0b3 100644 --- a/index.php +++ b/index.php @@ -60,7 +60,7 @@ if(isset($_GET["api"]) && is_string($_GET["api"])) { } } } else { - $documentName = $_GET["site"]; + $documentName = $_GET["site"] ?? "/"; if ($installation) { if ($documentName !== "" && $documentName !== "index.php") { $response = "Redirecting to /"; @@ -70,24 +70,47 @@ if(isset($_GET["api"]) && is_string($_GET["api"])) { $response = $document->getCode(); } } else { - if(empty($documentName) || strcasecmp($documentName, "install") === 0) { - $documentName = "home"; - } else if(!preg_match("/[a-zA-Z]+(\/[a-zA-Z]+)*/", $documentName)) { - $documentName = "Document404"; - } - $documentName = strtoupper($documentName[0]) . substr($documentName, 1); - $documentName = str_replace("/", "\\", $documentName); - $class = "\\Documents\\$documentName"; - $file = getClassPath($class); - if(!file_exists($file) || !is_subclass_of($class, Document::class)) { - $document = new Document404($user); + $req = new \Api\Routes\Find($user); + $success = $req->execute(array("request" => $documentName)); + $response = ""; + if (!$success) { + $response = "Unable to find route: " . $req->getLastError(); } else { - $document = new $class($user); + $route = $req->getResult()["route"]; + if (is_null($route)) { + $response = (new Document404($user))->getCode(); + } else { + $target = trim(explode("\n", $route["target"])[0]); + switch ($route["action"]) { + case "redirect_temporary": + http_send_status(307); + header("Location: $target"); + break; + case "redirect_permanently": + http_send_status(308); + header("Location: $target"); + break; + case "static": + http_send_status(501); + $response = "Not implemented yet."; + break; + case "dynamic": + $view = $route["extra"] ?? ""; + $file = getClassPath($target); + if(!file_exists($file) || !is_subclass_of($target, Document::class)) { + $document = new Document404($user); + } else { + $document = new $target($user); + } + + $response = $document->getCode(); + break; + } + } } $user->processVisit(); - $response = $document->getCode(); } } diff --git a/src/src/.htaccess b/src/src/.htaccess deleted file mode 100644 index 3bc3c22..0000000 --- a/src/src/.htaccess +++ /dev/null @@ -1 +0,0 @@ -DENY FROM ALL; \ No newline at end of file diff --git a/test/.htaccess b/test/.htaccess deleted file mode 100644 index d3223d4..0000000 --- a/test/.htaccess +++ /dev/null @@ -1 +0,0 @@ -DENY FROM ALL