2023-04-07 01:02:39 +03:00
|
|
|
<?php
|
|
|
|
|
|
|
|
include_once "Request.php";
|
|
|
|
include_once "Helpers.php";
|
|
|
|
|
|
|
|
function magicRoute($path)
|
|
|
|
{
|
|
|
|
$regex = [];
|
|
|
|
$names = [];
|
|
|
|
$first = true;
|
|
|
|
$magic = false;
|
|
|
|
foreach (tstring::from($path)->split("/") as $value) {
|
|
|
|
$matched = $value->match("/^(.*?)\{(.+?)\}(.*?)$/");
|
|
|
|
if($first){
|
|
|
|
$first = false;
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
if($matched === false)
|
|
|
|
{
|
|
|
|
$regex[] = "\/" . preg_quote($value);
|
|
|
|
}else{
|
|
|
|
$magic = true;
|
|
|
|
$symbol = tstring::from($matched[2]);
|
|
|
|
if($symbol->endsWith("?"))
|
|
|
|
{
|
|
|
|
$symbol = $symbol->slice(0,-1);
|
|
|
|
$pattern = "([^\/^?]+?)?";
|
|
|
|
}else{
|
|
|
|
$pattern = "([^\/^?]+?)";
|
|
|
|
}
|
|
|
|
$regex[] = "\/". $matched[1] . $pattern . $matched[3];
|
|
|
|
$names[] = $symbol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return [
|
|
|
|
"/^" . implode('', $regex) . "$/",
|
|
|
|
$names,
|
|
|
|
$magic
|
|
|
|
];
|
|
|
|
};
|
|
|
|
function validateMagicRoute($mroute, $path)
|
|
|
|
{
|
|
|
|
if(is_string($mroute))
|
|
|
|
{
|
|
|
|
list($regex, $names) = magicRoute($mroute);
|
|
|
|
}else{
|
|
|
|
list($regex, $names) = $mroute;
|
|
|
|
}
|
|
|
|
$matches = tstring::from($path)->match($regex);
|
|
|
|
if($matches !== false)
|
|
|
|
{
|
|
|
|
array_shift($matches);
|
|
|
|
$matcher = new stdClass;
|
|
|
|
$index = 0;
|
|
|
|
foreach ($matches as $value) {
|
|
|
|
$matcher->{
|
|
|
|
$names[$index]->raw()
|
|
|
|
} = $matches[
|
|
|
|
$index
|
|
|
|
];
|
|
|
|
$index++;
|
|
|
|
};
|
|
|
|
return $matcher;
|
|
|
|
}else{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class Route
|
|
|
|
{
|
|
|
|
public static $routes = [];
|
2023-04-11 22:59:27 +03:00
|
|
|
public static $errors = [];
|
2023-04-11 00:30:15 +03:00
|
|
|
public static $publics = [];
|
2023-04-07 01:02:39 +03:00
|
|
|
public static $current = null;
|
|
|
|
public static function post($path, $callback)
|
|
|
|
{
|
|
|
|
$magic = magicRoute($path);
|
|
|
|
$textPath = false;
|
|
|
|
$type = "text";
|
|
|
|
if($magic[2] == true)
|
|
|
|
{
|
|
|
|
$type = "magic";
|
|
|
|
$textPath = $magic;
|
|
|
|
}else{
|
|
|
|
$textPath = $path;
|
|
|
|
}
|
|
|
|
$route = Route::from([
|
|
|
|
"type" => $type,
|
|
|
|
"path" => $path,
|
|
|
|
"callback" => $callback,
|
|
|
|
"method" => "post"
|
|
|
|
]);
|
|
|
|
Route::$routes[] = $route;
|
|
|
|
return $route;
|
|
|
|
}
|
2023-04-11 22:59:27 +03:00
|
|
|
public static function error($method, $code, $callback)
|
|
|
|
{
|
|
|
|
if(!isset(Route::$errors[$code]))
|
|
|
|
{
|
|
|
|
Route::$errors[$code] = [];
|
|
|
|
}
|
|
|
|
Route::$errors[$code][$method] = $callback;
|
|
|
|
}
|
2023-04-07 01:02:39 +03:00
|
|
|
public static function get($path, $callback)
|
|
|
|
{
|
|
|
|
$magic = magicRoute($path);
|
|
|
|
$textPath = false;
|
|
|
|
$type = "text";
|
|
|
|
if($magic[2] == true)
|
|
|
|
{
|
|
|
|
$type = "magic";
|
|
|
|
$textPath = $magic;
|
|
|
|
}else{
|
|
|
|
$textPath = $path;
|
|
|
|
}
|
|
|
|
$route = Route::from([
|
|
|
|
"type" => $type,
|
|
|
|
"path" => $path,
|
|
|
|
"callback" => $callback,
|
|
|
|
"method" => "get"
|
|
|
|
]);
|
|
|
|
Route::$routes[] = $route;
|
|
|
|
return $route;
|
|
|
|
}
|
2023-04-11 00:30:15 +03:00
|
|
|
public static function public($route, $storagepath)
|
|
|
|
{
|
|
|
|
Route::$publics[] = Route::from([
|
|
|
|
"type" => "public",
|
|
|
|
"path" => preg_quote($route),
|
|
|
|
"src" => $storagepath,
|
|
|
|
"method" => "get"
|
|
|
|
]);
|
|
|
|
}
|
2023-04-07 01:02:39 +03:00
|
|
|
public static function any($path, $callback)
|
|
|
|
{
|
|
|
|
$magic = magicRoute($path);
|
|
|
|
$textPath = false;
|
|
|
|
$type = "text";
|
|
|
|
if($magic[2] == true)
|
|
|
|
{
|
|
|
|
$type = "magic";
|
|
|
|
$textPath = $magic;
|
|
|
|
}else{
|
|
|
|
$textPath = $path;
|
|
|
|
}
|
|
|
|
$route = Route::from([
|
|
|
|
"type" => $type,
|
|
|
|
"path" => $path,
|
|
|
|
"callback" => $callback,
|
|
|
|
"method" => "*"
|
|
|
|
]);
|
|
|
|
Route::$routes[] = $route;
|
|
|
|
return $route;
|
|
|
|
}
|
2023-04-11 22:59:27 +03:00
|
|
|
public static function ThrowErrorCode($code)
|
2023-04-07 01:02:39 +03:00
|
|
|
{
|
2023-04-11 22:59:27 +03:00
|
|
|
$method = Request::$method;
|
|
|
|
if(isset(Route::$errors[$code][$method]))
|
2023-04-07 01:02:39 +03:00
|
|
|
{
|
2023-04-11 22:59:27 +03:00
|
|
|
$callback = Route::$errors[$code][$method];
|
|
|
|
Route::$errors[$code][$method]();
|
|
|
|
return;
|
2023-04-07 01:02:39 +03:00
|
|
|
};
|
2023-04-11 22:59:27 +03:00
|
|
|
Response::Code($code);
|
|
|
|
}
|
|
|
|
public static function CheckCurrent()
|
|
|
|
{
|
|
|
|
try{
|
|
|
|
if(Route::$current == null)
|
|
|
|
{
|
|
|
|
foreach (Route::$routes as $route) {
|
|
|
|
$route->clear();
|
|
|
|
if($route->Run())
|
|
|
|
{
|
|
|
|
Route::$current = $route;
|
|
|
|
return $route;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
foreach (Route::$publics as $route) {
|
|
|
|
$route->clear();
|
|
|
|
if($route->Run())
|
|
|
|
{
|
|
|
|
Route::$current = $route;
|
|
|
|
return $route;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Route::ThrowErrorCode(404);
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
catch(Exception $e)
|
|
|
|
{
|
|
|
|
Route::ThrowErrorCode(500);
|
|
|
|
}
|
2023-04-07 01:02:39 +03:00
|
|
|
return Route::$current;
|
|
|
|
}
|
|
|
|
|
2023-04-08 21:34:10 +03:00
|
|
|
public static function Execute()
|
|
|
|
{
|
|
|
|
$route = Route::CheckCurrent();
|
2023-04-11 22:59:27 +03:00
|
|
|
if($route !== false)
|
2023-04-08 21:34:10 +03:00
|
|
|
{
|
2023-04-11 22:59:27 +03:00
|
|
|
$route->call();
|
2023-04-08 21:34:10 +03:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-04-07 01:02:39 +03:00
|
|
|
public static function from(...$args)
|
|
|
|
{
|
|
|
|
return new Route(...$args);
|
|
|
|
}
|
|
|
|
|
|
|
|
public string $type;
|
|
|
|
public string $path;
|
2023-04-11 00:30:15 +03:00
|
|
|
public string $src;
|
2023-04-07 01:02:39 +03:00
|
|
|
public $callback;
|
|
|
|
public string $method;
|
|
|
|
|
|
|
|
public $match = null;
|
|
|
|
|
|
|
|
public function __construct($obj)
|
|
|
|
{
|
|
|
|
foreach ($obj as $name => $value) {
|
|
|
|
$this->{$name} = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public function clear()
|
|
|
|
{
|
|
|
|
$this->match = null;
|
|
|
|
}
|
2023-04-08 21:34:10 +03:00
|
|
|
public function call(...$args)
|
|
|
|
{
|
2023-04-11 00:30:15 +03:00
|
|
|
switch ($this->type) {
|
|
|
|
case 'magic':
|
|
|
|
case 'text':
|
|
|
|
$callback = $this->callback;
|
|
|
|
$callback(...$args);
|
|
|
|
break;
|
|
|
|
case 'public':
|
|
|
|
$callback = $this->callback;
|
|
|
|
Response::File($callback);
|
|
|
|
break;
|
|
|
|
}
|
2023-04-08 21:34:10 +03:00
|
|
|
}
|
2023-04-07 01:02:39 +03:00
|
|
|
public function Run()
|
|
|
|
{
|
|
|
|
$requestUrl = Request::$url;
|
|
|
|
$method = Request::$method;
|
|
|
|
if($this->method != $method)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
$url = parse_url($requestUrl, PHP_URL_PATH);
|
2023-04-11 00:30:15 +03:00
|
|
|
switch($this->type)
|
2023-04-07 01:02:39 +03:00
|
|
|
{
|
2023-04-11 00:30:15 +03:00
|
|
|
case "text":{
|
|
|
|
if($url == $this->path)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}else{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case "magic":{
|
|
|
|
if($t === false)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}else{
|
|
|
|
$this->match = $t;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case "public":{
|
|
|
|
$path = tstring::from($this->path);
|
|
|
|
$url = tstring::from($url);
|
|
|
|
if($url->startsWith($path))
|
|
|
|
{
|
|
|
|
$filename = $url->slice(strlen($path)); // remove first / char
|
|
|
|
$rpath = realpath($this->src . $filename);
|
2023-04-11 22:59:27 +03:00
|
|
|
if(file_exists($rpath) && is_file($rpath))
|
2023-04-11 00:30:15 +03:00
|
|
|
{
|
|
|
|
$this->callback = $rpath;
|
|
|
|
return true;
|
|
|
|
}else{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
2023-04-07 01:02:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|