|
@@ -2,13 +2,37 @@
|
|
|
require_once('base.class.php');
|
|
|
require_once('router.class.php');
|
|
|
require_once('response.class.php');
|
|
|
+ require_once('uri.class.php');
|
|
|
require_once('events.interface.php');
|
|
|
class App extends Base implements Events {
|
|
|
private static $apps = array();
|
|
|
+ private $domains;
|
|
|
private $routers;
|
|
|
+ private $router;
|
|
|
+ public $_onerror;
|
|
|
public function __construct($name){
|
|
|
$this->name = $name;
|
|
|
+ $this->router = new Router();
|
|
|
$this->routers = array();
|
|
|
+ $this->domains = array();
|
|
|
+ $this->_onerror = function($res, $error){
|
|
|
+ $o = json_encode(array(
|
|
|
+ 'message'=>$error->getMessage(),
|
|
|
+ 'code'=>$error->getCode(),
|
|
|
+ 'file'=>$error->getFile(),
|
|
|
+ 'line'=>$error->getLine(),
|
|
|
+ 'traceback'=>$error->getTrace()
|
|
|
+ ));
|
|
|
+ if($res){
|
|
|
+ $res->code(404);
|
|
|
+ $res->header('Content-Type', 'application/json');
|
|
|
+ $res->end($o);
|
|
|
+ }else{
|
|
|
+ http_response_code(404);
|
|
|
+ header('Content-Type: application/json');
|
|
|
+ print($o);
|
|
|
+ }
|
|
|
+ };
|
|
|
static::$apps[] = $this;
|
|
|
}
|
|
|
public function __destruct(){
|
|
@@ -23,11 +47,22 @@
|
|
|
}
|
|
|
public static function shutdown(){
|
|
|
$verb = $_SERVER['REQUEST_METHOD'];
|
|
|
- $url = parse_url($_SERVER['REDIRECT_URL']);
|
|
|
+ if(isset($_SERVER['REDIRECT_URL'])){
|
|
|
+ $url = 'REDIRECT_URL';
|
|
|
+ }else{
|
|
|
+ $url = 'REQUEST_URI';
|
|
|
+ }
|
|
|
+ if(!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])){
|
|
|
+ $root = $_SERVER['HTTP_X_FORWARDED_PROTO'].'://';
|
|
|
+ }else{
|
|
|
+ $root = !empty($_SERVER['HTTPS']) ? "https://" : "http://";
|
|
|
+ }
|
|
|
+ // @todo - determine if http or http and also check cloudflare
|
|
|
+ $url = parse_url($root.$_SERVER['HTTP_HOST'].$_SERVER[$url]);
|
|
|
$data = file_get_contents( 'php://input','r');
|
|
|
foreach(static::$apps as $k => $app){
|
|
|
if($app instanceof App){
|
|
|
- $app->handle($verb, $url, $data);
|
|
|
+ $app->handle($verb, $url, $data)->shutdown();
|
|
|
}
|
|
|
}
|
|
|
if(is_callable('parent::__destruct')){
|
|
@@ -36,70 +71,65 @@
|
|
|
}
|
|
|
public static function shutdown_error($error){
|
|
|
foreach(static::$apps as $k => $app){
|
|
|
- $app->error($error);
|
|
|
+ if(is_callable($app->onerror)){
|
|
|
+ $app->onerror(null, $error);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
public function handle($verb, $url, $data){
|
|
|
- $res = new Response($url);
|
|
|
+ $res = new Response((string)new Uri($url));
|
|
|
$self = $this;
|
|
|
- $onerror = function($res, $error){
|
|
|
- $self->error($error);
|
|
|
+ $onerror = function($res, $error) use($self){
|
|
|
+ $self->onerror($res, $error);
|
|
|
};
|
|
|
- foreach($this->routers as $type => $routers){
|
|
|
- foreach($routers as $router){
|
|
|
- switch($type){
|
|
|
- case 'prefix':
|
|
|
- $router->handle($url["path"], $res, null, $onerror);
|
|
|
- break;
|
|
|
- case 'domain':
|
|
|
- $router->handle($url["host"], $res, null, $onerror);
|
|
|
- break;
|
|
|
- }
|
|
|
+ $handled = false;
|
|
|
+ // Domain routers
|
|
|
+ foreach($this->domains as $host => $router){
|
|
|
+ if($url['host'] == $host){
|
|
|
+ $router->handle($url["path"], $res, null, $onerror);
|
|
|
+ $handled = $handled || $router->handled;
|
|
|
}
|
|
|
}
|
|
|
- $res->url = $url;
|
|
|
+ // Prefixed path routers
|
|
|
+ foreach($this->routers as $prefix => $router){
|
|
|
+ $router->handle($url["path"], $res, null, $onerror);
|
|
|
+ $handled = $handled || $router->handled;
|
|
|
+ }
|
|
|
+ // Base router for non-prefixed paths
|
|
|
+ $this->router->handle($url["path"], $res, function($res, $url) use($handled, $self){
|
|
|
+ if(!$handled){
|
|
|
+ $self->onerror($res,new Error("Not Found", 404));
|
|
|
+ }
|
|
|
+ }, $onerror);
|
|
|
return $res;
|
|
|
}
|
|
|
- public function error($error){
|
|
|
-
|
|
|
+ public function error(Callable $fn){
|
|
|
+ $this->_onerror = $fn;
|
|
|
+ return $this;
|
|
|
}
|
|
|
- public function get_router($type, $path){
|
|
|
- $ret = false;
|
|
|
- if(isset($this->routers[$type])){
|
|
|
- foreach($this->routers[$type] as $k => $router){
|
|
|
- if($router->base == $path){
|
|
|
- $ret = $router;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return $ret;
|
|
|
+ public function route($path, Callable $fn){
|
|
|
+ $this->router->path($path, $fn);
|
|
|
+ return $this;
|
|
|
}
|
|
|
- public function create_router($type, $path){
|
|
|
- $router = new Router($path);
|
|
|
- if(!isset($this->routers[$type])){
|
|
|
- $this->routers[$type] = array();
|
|
|
+ public function prefix($prefix, Callable $fn){
|
|
|
+ if(!$this->routers[$prefix]){
|
|
|
+ $this->routers[$prefix] = new Router($prefix);
|
|
|
}
|
|
|
- $this->routers[$type][] = $router;
|
|
|
- return $router;
|
|
|
+ $fn($this->routers[$prefix]);
|
|
|
+ return $this;
|
|
|
}
|
|
|
- public function route($type, $path, Callable $fn){
|
|
|
- $router = $this->get_router($type, $prefix);
|
|
|
- if($router == false){
|
|
|
- $router = $this->create_router($type, $prefix);
|
|
|
+ public function domain($host, Callable $fn){
|
|
|
+ if(!isset($this->domains[$host])){
|
|
|
+ $this->domains[$host] = new Router();
|
|
|
}
|
|
|
- call_user_func($fn, $router);
|
|
|
+ $fn($this->domains[$host]);
|
|
|
+ return $this;
|
|
|
}
|
|
|
- public function prefix($prefix, Callable $fn){
|
|
|
- $this->route('prefix', $prefix, function($router){
|
|
|
- $router->base($prefix);
|
|
|
- call_user_func($fn, $router);
|
|
|
- });
|
|
|
- }
|
|
|
- public function domain($prefix, Callable $fn){
|
|
|
- $this->route('domain', $prefix, function($router){
|
|
|
- $router->base($prefix);
|
|
|
- call_user_func($fn, $router);
|
|
|
- });
|
|
|
+ public function onerror($res, $error){
|
|
|
+ $fn = $this->_onerror;
|
|
|
+ if(is_callable($fn)){
|
|
|
+ $fn($res, $error);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
error_reporting(E_ALL);
|