|
|
|
@ -1,4 +1,6 @@
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
/**
|
|
|
|
|
* Flight: An extensible micro-framework.
|
|
|
|
|
*
|
|
|
|
@ -8,8 +10,15 @@
|
|
|
|
|
|
|
|
|
|
namespace flight;
|
|
|
|
|
|
|
|
|
|
use flight\core\Loader;
|
|
|
|
|
use ErrorException;
|
|
|
|
|
use Exception;
|
|
|
|
|
use flight\core\Dispatcher;
|
|
|
|
|
use flight\core\Loader;
|
|
|
|
|
use flight\net\Request;
|
|
|
|
|
use flight\net\Response;
|
|
|
|
|
use flight\net\Router;
|
|
|
|
|
use flight\template\View;
|
|
|
|
|
use Throwable;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The Engine class contains the core functionality of the framework.
|
|
|
|
@ -17,23 +26,21 @@ use flight\core\Dispatcher;
|
|
|
|
|
* and generating an HTTP response.
|
|
|
|
|
*
|
|
|
|
|
* Core methods
|
|
|
|
|
*
|
|
|
|
|
* @method void start() Starts engine
|
|
|
|
|
* @method void stop() Stops framework and outputs current response
|
|
|
|
|
* @method void halt(int $code = 200, string $message = '') Stops processing and returns a given response.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* Routing
|
|
|
|
|
* @method void route(string $pattern, callable $callback, bool $pass_route = false) Routes a URL to a callback function.
|
|
|
|
|
* @method \flight\net\Router router() Gets router
|
|
|
|
|
* @method Router router() Gets router
|
|
|
|
|
*
|
|
|
|
|
* Views
|
|
|
|
|
* @method void render(string $file, array $data = null, string $key = null) Renders template
|
|
|
|
|
* @method \flight\template\View view() Gets current view
|
|
|
|
|
* @method View view() Gets current view
|
|
|
|
|
*
|
|
|
|
|
* Request-response
|
|
|
|
|
* @method \flight\net\Request request() Gets current request
|
|
|
|
|
* @method \flight\net\Response response() Gets current response
|
|
|
|
|
* @method void error(\Exception $e) Sends an HTTP 500 response for any errors.
|
|
|
|
|
* @method Request request() Gets current request
|
|
|
|
|
* @method Response response() Gets current response
|
|
|
|
|
* @method void error(Exception $e) Sends an HTTP 500 response for any errors.
|
|
|
|
|
* @method void notFound() Sends an HTTP 404 response when a URL is not found.
|
|
|
|
|
* @method void redirect(string $url, int $code = 303) Redirects the current request to another URL.
|
|
|
|
|
* @method void json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf-8', int $option = 0) Sends a JSON response.
|
|
|
|
@ -43,33 +50,29 @@ use flight\core\Dispatcher;
|
|
|
|
|
* @method void etag($id, string $type = 'strong') Handles ETag HTTP caching.
|
|
|
|
|
* @method void lastModified(int $time) Handles last modified HTTP caching.
|
|
|
|
|
*/
|
|
|
|
|
class Engine {
|
|
|
|
|
class Engine
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* Stored variables.
|
|
|
|
|
*
|
|
|
|
|
* @var array
|
|
|
|
|
*/
|
|
|
|
|
protected $vars;
|
|
|
|
|
protected array $vars;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Class loader.
|
|
|
|
|
*
|
|
|
|
|
* @var Loader
|
|
|
|
|
*/
|
|
|
|
|
protected $loader;
|
|
|
|
|
protected Loader $loader;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Event dispatcher.
|
|
|
|
|
*
|
|
|
|
|
* @var Dispatcher
|
|
|
|
|
*/
|
|
|
|
|
protected $dispatcher;
|
|
|
|
|
protected Dispatcher $dispatcher;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor.
|
|
|
|
|
*/
|
|
|
|
|
public function __construct() {
|
|
|
|
|
$this->vars = array();
|
|
|
|
|
public function __construct()
|
|
|
|
|
{
|
|
|
|
|
$this->vars = [];
|
|
|
|
|
|
|
|
|
|
$this->loader = new Loader();
|
|
|
|
|
$this->dispatcher = new Dispatcher();
|
|
|
|
@ -80,38 +83,42 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Handles calls to class methods.
|
|
|
|
|
*
|
|
|
|
|
* @param string $name Method name
|
|
|
|
|
* @param array $params Method parameters
|
|
|
|
|
* @param string $name Method name
|
|
|
|
|
* @param array $params Method parameters
|
|
|
|
|
*
|
|
|
|
|
*@throws Exception
|
|
|
|
|
*
|
|
|
|
|
* @return mixed Callback results
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
*/
|
|
|
|
|
public function __call($name, $params) {
|
|
|
|
|
public function __call(string $name, array $params)
|
|
|
|
|
{
|
|
|
|
|
$callback = $this->dispatcher->get($name);
|
|
|
|
|
|
|
|
|
|
if (is_callable($callback)) {
|
|
|
|
|
if (\is_callable($callback)) {
|
|
|
|
|
return $this->dispatcher->run($name, $params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!$this->loader->get($name)) {
|
|
|
|
|
throw new \Exception("{$name} must be a mapped method.");
|
|
|
|
|
throw new Exception("{$name} must be a mapped method.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$shared = (!empty($params)) ? (bool)$params[0] : true;
|
|
|
|
|
$shared = (!empty($params)) ? (bool) $params[0] : true;
|
|
|
|
|
|
|
|
|
|
return $this->loader->load($name, $shared);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** Core Methods ***/
|
|
|
|
|
// Core Methods
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initializes the framework.
|
|
|
|
|
*/
|
|
|
|
|
public function init() {
|
|
|
|
|
public function init(): void
|
|
|
|
|
{
|
|
|
|
|
static $initialized = false;
|
|
|
|
|
$self = $this;
|
|
|
|
|
|
|
|
|
|
if ($initialized) {
|
|
|
|
|
$this->vars = array();
|
|
|
|
|
$this->vars = [];
|
|
|
|
|
$this->loader->reset();
|
|
|
|
|
$this->dispatcher->reset();
|
|
|
|
|
}
|
|
|
|
@ -120,18 +127,18 @@ class Engine {
|
|
|
|
|
$this->loader->register('request', '\flight\net\Request');
|
|
|
|
|
$this->loader->register('response', '\flight\net\Response');
|
|
|
|
|
$this->loader->register('router', '\flight\net\Router');
|
|
|
|
|
$this->loader->register('view', '\flight\template\View', array(), function($view) use ($self) {
|
|
|
|
|
$this->loader->register('view', '\flight\template\View', [], function ($view) use ($self) {
|
|
|
|
|
$view->path = $self->get('flight.views.path');
|
|
|
|
|
$view->extension = $self->get('flight.views.extension');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Register framework methods
|
|
|
|
|
$methods = array(
|
|
|
|
|
'start','stop','route','halt','error','notFound',
|
|
|
|
|
'render','redirect','etag','lastModified','json','jsonp'
|
|
|
|
|
);
|
|
|
|
|
$methods = [
|
|
|
|
|
'start', 'stop', 'route', 'halt', 'error', 'notFound',
|
|
|
|
|
'render', 'redirect', 'etag', 'lastModified', 'json', 'jsonp',
|
|
|
|
|
];
|
|
|
|
|
foreach ($methods as $name) {
|
|
|
|
|
$this->dispatcher->set($name, array($this, '_'.$name));
|
|
|
|
|
$this->dispatcher->set($name, [$this, '_' . $name]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Default configuration settings
|
|
|
|
@ -144,11 +151,11 @@ class Engine {
|
|
|
|
|
$this->set('flight.content_length', true);
|
|
|
|
|
|
|
|
|
|
// Startup configuration
|
|
|
|
|
$this->before('start', function() use ($self) {
|
|
|
|
|
$this->before('start', function () use ($self) {
|
|
|
|
|
// Enable error handling
|
|
|
|
|
if ($self->get('flight.handle_errors')) {
|
|
|
|
|
set_error_handler(array($self, 'handleError'));
|
|
|
|
|
set_exception_handler(array($self, 'handleException'));
|
|
|
|
|
set_error_handler([$self, 'handleError']);
|
|
|
|
|
set_exception_handler([$self, 'handleException']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set case-sensitivity
|
|
|
|
@ -163,24 +170,27 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Custom error handler. Converts errors into exceptions.
|
|
|
|
|
*
|
|
|
|
|
* @param int $errno Error number
|
|
|
|
|
* @param int $errstr Error string
|
|
|
|
|
* @param int $errno Error number
|
|
|
|
|
* @param int $errstr Error string
|
|
|
|
|
* @param int $errfile Error file name
|
|
|
|
|
* @param int $errline Error file line number
|
|
|
|
|
* @throws \ErrorException
|
|
|
|
|
*
|
|
|
|
|
* @throws ErrorException
|
|
|
|
|
*/
|
|
|
|
|
public function handleError($errno, $errstr, $errfile, $errline) {
|
|
|
|
|
public function handleError(int $errno, int $errstr, int $errfile, int $errline)
|
|
|
|
|
{
|
|
|
|
|
if ($errno & error_reporting()) {
|
|
|
|
|
throw new \ErrorException($errstr, $errno, 0, $errfile, $errline);
|
|
|
|
|
throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Custom exception handler. Logs exceptions.
|
|
|
|
|
*
|
|
|
|
|
* @param \Exception $e Thrown exception
|
|
|
|
|
* @param Exception $e Thrown exception
|
|
|
|
|
*/
|
|
|
|
|
public function handleException($e) {
|
|
|
|
|
public function handleException($e): void
|
|
|
|
|
{
|
|
|
|
|
if ($this->get('flight.log_errors')) {
|
|
|
|
|
error_log($e->getMessage());
|
|
|
|
|
}
|
|
|
|
@ -191,13 +201,15 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Maps a callback to a framework method.
|
|
|
|
|
*
|
|
|
|
|
* @param string $name Method name
|
|
|
|
|
* @param string $name Method name
|
|
|
|
|
* @param callback $callback Callback function
|
|
|
|
|
* @throws \Exception If trying to map over a framework method
|
|
|
|
|
*
|
|
|
|
|
* @throws Exception If trying to map over a framework method
|
|
|
|
|
*/
|
|
|
|
|
public function map($name, $callback) {
|
|
|
|
|
public function map(string $name, callable $callback): void
|
|
|
|
|
{
|
|
|
|
|
if (method_exists($this, $name)) {
|
|
|
|
|
throw new \Exception('Cannot override an existing framework method.');
|
|
|
|
|
throw new Exception('Cannot override an existing framework method.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->dispatcher->set($name, $callback);
|
|
|
|
@ -206,15 +218,17 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Registers a class to a framework method.
|
|
|
|
|
*
|
|
|
|
|
* @param string $name Method name
|
|
|
|
|
* @param string $class Class name
|
|
|
|
|
* @param array $params Class initialization parameters
|
|
|
|
|
* @param callback $callback Function to call after object instantiation
|
|
|
|
|
* @throws \Exception If trying to map over a framework method
|
|
|
|
|
* @param string $name Method name
|
|
|
|
|
* @param string $class Class name
|
|
|
|
|
* @param array $params Class initialization parameters
|
|
|
|
|
* @param callable|null $callback $callback Function to call after object instantiation
|
|
|
|
|
*
|
|
|
|
|
* @throws Exception If trying to map over a framework method
|
|
|
|
|
*/
|
|
|
|
|
public function register($name, $class, array $params = array(), $callback = null) {
|
|
|
|
|
public function register(string $name, string $class, array $params = [], ?callable $callback = null): void
|
|
|
|
|
{
|
|
|
|
|
if (method_exists($this, $name)) {
|
|
|
|
|
throw new \Exception('Cannot override an existing framework method.');
|
|
|
|
|
throw new Exception('Cannot override an existing framework method.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->loader->register($name, $class, $params, $callback);
|
|
|
|
@ -223,48 +237,54 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Adds a pre-filter to a method.
|
|
|
|
|
*
|
|
|
|
|
* @param string $name Method name
|
|
|
|
|
* @param string $name Method name
|
|
|
|
|
* @param callback $callback Callback function
|
|
|
|
|
*/
|
|
|
|
|
public function before($name, $callback) {
|
|
|
|
|
public function before(string $name, callable $callback): void
|
|
|
|
|
{
|
|
|
|
|
$this->dispatcher->hook($name, 'before', $callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds a post-filter to a method.
|
|
|
|
|
*
|
|
|
|
|
* @param string $name Method name
|
|
|
|
|
* @param string $name Method name
|
|
|
|
|
* @param callback $callback Callback function
|
|
|
|
|
*/
|
|
|
|
|
public function after($name, $callback) {
|
|
|
|
|
public function after(string $name, callable $callback): void
|
|
|
|
|
{
|
|
|
|
|
$this->dispatcher->hook($name, 'after', $callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets a variable.
|
|
|
|
|
*
|
|
|
|
|
* @param string $key Key
|
|
|
|
|
* @return mixed
|
|
|
|
|
* @param string|null $key Key
|
|
|
|
|
*
|
|
|
|
|
* @return array|mixed|null
|
|
|
|
|
*/
|
|
|
|
|
public function get($key = null) {
|
|
|
|
|
if ($key === null) return $this->vars;
|
|
|
|
|
public function get(?string $key = null)
|
|
|
|
|
{
|
|
|
|
|
if (null === $key) {
|
|
|
|
|
return $this->vars;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return isset($this->vars[$key]) ? $this->vars[$key] : null;
|
|
|
|
|
return $this->vars[$key] ?? null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets a variable.
|
|
|
|
|
*
|
|
|
|
|
* @param mixed $key Key
|
|
|
|
|
* @param string $value Value
|
|
|
|
|
* @param mixed $key Key
|
|
|
|
|
* @param mixed|null $value Value
|
|
|
|
|
*/
|
|
|
|
|
public function set($key, $value = null) {
|
|
|
|
|
if (is_array($key) || is_object($key)) {
|
|
|
|
|
public function set($key, $value = null): void
|
|
|
|
|
{
|
|
|
|
|
if (\is_array($key) || \is_object($key)) {
|
|
|
|
|
foreach ($key as $k => $v) {
|
|
|
|
|
$this->vars[$k] = $v;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
$this->vars[$key] = $value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -273,22 +293,24 @@ class Engine {
|
|
|
|
|
* Checks if a variable has been set.
|
|
|
|
|
*
|
|
|
|
|
* @param string $key Key
|
|
|
|
|
*
|
|
|
|
|
* @return bool Variable status
|
|
|
|
|
*/
|
|
|
|
|
public function has($key) {
|
|
|
|
|
public function has(string $key): bool
|
|
|
|
|
{
|
|
|
|
|
return isset($this->vars[$key]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Unsets a variable. If no key is passed in, clear all variables.
|
|
|
|
|
*
|
|
|
|
|
* @param string $key Key
|
|
|
|
|
* @param string|null $key Key
|
|
|
|
|
*/
|
|
|
|
|
public function clear($key = null) {
|
|
|
|
|
if (is_null($key)) {
|
|
|
|
|
$this->vars = array();
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
public function clear(?string $key = null): void
|
|
|
|
|
{
|
|
|
|
|
if (null === $key) {
|
|
|
|
|
$this->vars = [];
|
|
|
|
|
} else {
|
|
|
|
|
unset($this->vars[$key]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -298,17 +320,20 @@ class Engine {
|
|
|
|
|
*
|
|
|
|
|
* @param string $dir Directory path
|
|
|
|
|
*/
|
|
|
|
|
public function path($dir) {
|
|
|
|
|
public function path(string $dir): void
|
|
|
|
|
{
|
|
|
|
|
$this->loader->addDirectory($dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*** Extensible Methods ***/
|
|
|
|
|
// Extensible Methods
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Starts the framework.
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
*
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public function _start() {
|
|
|
|
|
public function _start(): void
|
|
|
|
|
{
|
|
|
|
|
$dispatched = false;
|
|
|
|
|
$self = $this;
|
|
|
|
|
$request = $this->request();
|
|
|
|
@ -316,7 +341,7 @@ class Engine {
|
|
|
|
|
$router = $this->router();
|
|
|
|
|
|
|
|
|
|
// Allow filters to run
|
|
|
|
|
$this->after('start', function() use ($self) {
|
|
|
|
|
$this->after('start', function () use ($self) {
|
|
|
|
|
$self->stop();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
@ -345,7 +370,9 @@ class Engine {
|
|
|
|
|
|
|
|
|
|
$dispatched = true;
|
|
|
|
|
|
|
|
|
|
if (!$continue) break;
|
|
|
|
|
if (!$continue) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$router->next();
|
|
|
|
|
|
|
|
|
@ -360,14 +387,16 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Stops the framework and outputs the current response.
|
|
|
|
|
*
|
|
|
|
|
* @param int $code HTTP status code
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
* @param int|null $code HTTP status code
|
|
|
|
|
*
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public function _stop($code = null) {
|
|
|
|
|
public function _stop(?int $code = null): void
|
|
|
|
|
{
|
|
|
|
|
$response = $this->response();
|
|
|
|
|
|
|
|
|
|
if (!$response->sent()) {
|
|
|
|
|
if ($code !== null) {
|
|
|
|
|
if (null !== $code) {
|
|
|
|
|
$response->status($code);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -380,21 +409,23 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Routes a URL to a callback function.
|
|
|
|
|
*
|
|
|
|
|
* @param string $pattern URL pattern to match
|
|
|
|
|
* @param callback $callback Callback function
|
|
|
|
|
* @param boolean $pass_route Pass the matching route object to the callback
|
|
|
|
|
* @param string $pattern URL pattern to match
|
|
|
|
|
* @param callback $callback Callback function
|
|
|
|
|
* @param bool $pass_route Pass the matching route object to the callback
|
|
|
|
|
*/
|
|
|
|
|
public function _route($pattern, $callback, $pass_route = false) {
|
|
|
|
|
public function _route(string $pattern, callable $callback, bool $pass_route = false): void
|
|
|
|
|
{
|
|
|
|
|
$this->router()->map($pattern, $callback, $pass_route);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Stops processing and returns a given response.
|
|
|
|
|
*
|
|
|
|
|
* @param int $code HTTP status code
|
|
|
|
|
* @param int $code HTTP status code
|
|
|
|
|
* @param string $message Response message
|
|
|
|
|
*/
|
|
|
|
|
public function _halt($code = 200, $message = '') {
|
|
|
|
|
public function _halt(int $code = 200, string $message = ''): void
|
|
|
|
|
{
|
|
|
|
|
$this->response()
|
|
|
|
|
->clear()
|
|
|
|
|
->status($code)
|
|
|
|
@ -406,11 +437,12 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Sends an HTTP 500 response for any errors.
|
|
|
|
|
*
|
|
|
|
|
* @param \Exception|\Throwable $e Thrown exception
|
|
|
|
|
* @param Exception|Throwable $e Thrown exception
|
|
|
|
|
*/
|
|
|
|
|
public function _error($e) {
|
|
|
|
|
$msg = sprintf('<h1>500 Internal Server Error</h1>'.
|
|
|
|
|
'<h3>%s (%s)</h3>'.
|
|
|
|
|
public function _error($e): void
|
|
|
|
|
{
|
|
|
|
|
$msg = sprintf('<h1>500 Internal Server Error</h1>' .
|
|
|
|
|
'<h3>%s (%s)</h3>' .
|
|
|
|
|
'<pre>%s</pre>',
|
|
|
|
|
$e->getMessage(),
|
|
|
|
|
$e->getCode(),
|
|
|
|
@ -423,10 +455,9 @@ class Engine {
|
|
|
|
|
->status(500)
|
|
|
|
|
->write($msg)
|
|
|
|
|
->send();
|
|
|
|
|
}
|
|
|
|
|
catch (\Throwable $t) { // PHP 7.0+
|
|
|
|
|
} catch (Throwable $t) { // PHP 7.0+
|
|
|
|
|
exit($msg);
|
|
|
|
|
} catch(\Exception $e) { // PHP < 7
|
|
|
|
|
} catch (Exception $e) { // PHP < 7
|
|
|
|
|
exit($msg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -434,13 +465,14 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Sends an HTTP 404 response when a URL is not found.
|
|
|
|
|
*/
|
|
|
|
|
public function _notFound() {
|
|
|
|
|
public function _notFound(): void
|
|
|
|
|
{
|
|
|
|
|
$this->response()
|
|
|
|
|
->clear()
|
|
|
|
|
->status(404)
|
|
|
|
|
->write(
|
|
|
|
|
'<h1>404 Not Found</h1>'.
|
|
|
|
|
'<h3>The page you have requested could not be found.</h3>'.
|
|
|
|
|
'<h1>404 Not Found</h1>' .
|
|
|
|
|
'<h3>The page you have requested could not be found.</h3>' .
|
|
|
|
|
str_repeat(' ', 512)
|
|
|
|
|
)
|
|
|
|
|
->send();
|
|
|
|
@ -449,18 +481,19 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Redirects the current request to another URL.
|
|
|
|
|
*
|
|
|
|
|
* @param string $url URL
|
|
|
|
|
* @param int $code HTTP status code
|
|
|
|
|
* @param string $url URL
|
|
|
|
|
* @param int $code HTTP status code
|
|
|
|
|
*/
|
|
|
|
|
public function _redirect($url, $code = 303) {
|
|
|
|
|
public function _redirect(string $url, int $code = 303): void
|
|
|
|
|
{
|
|
|
|
|
$base = $this->get('flight.base_url');
|
|
|
|
|
|
|
|
|
|
if ($base === null) {
|
|
|
|
|
if (null === $base) {
|
|
|
|
|
$base = $this->request()->base;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Append base url to redirect url
|
|
|
|
|
if ($base != '/' && strpos($url, '://') === false) {
|
|
|
|
|
if ('/' != $base && false === strpos($url, '://')) {
|
|
|
|
|
$url = $base . preg_replace('#/+#', '/', '/' . $url);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -474,16 +507,17 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Renders a template.
|
|
|
|
|
*
|
|
|
|
|
* @param string $file Template file
|
|
|
|
|
* @param array $data Template data
|
|
|
|
|
* @param string $key View variable name
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
* @param string $file Template file
|
|
|
|
|
* @param array|null $data Template data
|
|
|
|
|
* @param string|null $key View variable name
|
|
|
|
|
*
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public function _render($file, $data = null, $key = null) {
|
|
|
|
|
if ($key !== null) {
|
|
|
|
|
public function _render(string $file, ?array $data = null, ?string $key = null): void
|
|
|
|
|
{
|
|
|
|
|
if (null !== $key) {
|
|
|
|
|
$this->view()->set($key, $this->view()->fetch($file, $data));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
$this->view()->render($file, $data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -491,67 +525,70 @@ class Engine {
|
|
|
|
|
/**
|
|
|
|
|
* Sends a JSON response.
|
|
|
|
|
*
|
|
|
|
|
* @param mixed $data JSON data
|
|
|
|
|
* @param int $code HTTP status code
|
|
|
|
|
* @param bool $encode Whether to perform JSON encoding
|
|
|
|
|
* @param mixed $data JSON data
|
|
|
|
|
* @param int $code HTTP status code
|
|
|
|
|
* @param bool $encode Whether to perform JSON encoding
|
|
|
|
|
* @param string $charset Charset
|
|
|
|
|
* @param int $option Bitmask Json constant such as JSON_HEX_QUOT
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
* @param int $option Bitmask Json constant such as JSON_HEX_QUOT
|
|
|
|
|
*
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public function _json(
|
|
|
|
|
$data,
|
|
|
|
|
$code = 200,
|
|
|
|
|
$encode = true,
|
|
|
|
|
$charset = 'utf-8',
|
|
|
|
|
$option = 0
|
|
|
|
|
) {
|
|
|
|
|
int $code = 200,
|
|
|
|
|
bool $encode = true,
|
|
|
|
|
string $charset = 'utf-8',
|
|
|
|
|
int $option = 0
|
|
|
|
|
): void {
|
|
|
|
|
$json = ($encode) ? json_encode($data, $option) : $data;
|
|
|
|
|
|
|
|
|
|
$this->response()
|
|
|
|
|
->status($code)
|
|
|
|
|
->header('Content-Type', 'application/json; charset='.$charset)
|
|
|
|
|
->header('Content-Type', 'application/json; charset=' . $charset)
|
|
|
|
|
->write($json)
|
|
|
|
|
->send();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sends a JSONP response.
|
|
|
|
|
*
|
|
|
|
|
* @param mixed $data JSON data
|
|
|
|
|
* @param string $param Query parameter that specifies the callback name.
|
|
|
|
|
* @param int $code HTTP status code
|
|
|
|
|
* @param bool $encode Whether to perform JSON encoding
|
|
|
|
|
* @param mixed $data JSON data
|
|
|
|
|
* @param string $param Query parameter that specifies the callback name.
|
|
|
|
|
* @param int $code HTTP status code
|
|
|
|
|
* @param bool $encode Whether to perform JSON encoding
|
|
|
|
|
* @param string $charset Charset
|
|
|
|
|
* @param int $option Bitmask Json constant such as JSON_HEX_QUOT
|
|
|
|
|
* @throws \Exception
|
|
|
|
|
* @param int $option Bitmask Json constant such as JSON_HEX_QUOT
|
|
|
|
|
*
|
|
|
|
|
* @throws Exception
|
|
|
|
|
*/
|
|
|
|
|
public function _jsonp(
|
|
|
|
|
$data,
|
|
|
|
|
$param = 'jsonp',
|
|
|
|
|
$code = 200,
|
|
|
|
|
$encode = true,
|
|
|
|
|
$charset = 'utf-8',
|
|
|
|
|
$option = 0
|
|
|
|
|
) {
|
|
|
|
|
string $param = 'jsonp',
|
|
|
|
|
int $code = 200,
|
|
|
|
|
bool $encode = true,
|
|
|
|
|
string $charset = 'utf-8',
|
|
|
|
|
int $option = 0
|
|
|
|
|
): void {
|
|
|
|
|
$json = ($encode) ? json_encode($data, $option) : $data;
|
|
|
|
|
|
|
|
|
|
$callback = $this->request()->query[$param];
|
|
|
|
|
|
|
|
|
|
$this->response()
|
|
|
|
|
->status($code)
|
|
|
|
|
->header('Content-Type', 'application/javascript; charset='.$charset)
|
|
|
|
|
->write($callback.'('.$json.');')
|
|
|
|
|
->header('Content-Type', 'application/javascript; charset=' . $charset)
|
|
|
|
|
->write($callback . '(' . $json . ');')
|
|
|
|
|
->send();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Handles ETag HTTP caching.
|
|
|
|
|
*
|
|
|
|
|
* @param string $id ETag identifier
|
|
|
|
|
* @param string $id ETag identifier
|
|
|
|
|
* @param string $type ETag type
|
|
|
|
|
*/
|
|
|
|
|
public function _etag($id, $type = 'strong') {
|
|
|
|
|
$id = (($type === 'weak') ? 'W/' : '').$id;
|
|
|
|
|
public function _etag(string $id, string $type = 'strong'): void
|
|
|
|
|
{
|
|
|
|
|
$id = (('weak' === $type) ? 'W/' : '') . $id;
|
|
|
|
|
|
|
|
|
|
$this->response()->header('ETag', $id);
|
|
|
|
|
|
|
|
|
@ -566,7 +603,8 @@ class Engine {
|
|
|
|
|
*
|
|
|
|
|
* @param int $time Unix timestamp
|
|
|
|
|
*/
|
|
|
|
|
public function _lastModified($time) {
|
|
|
|
|
public function _lastModified(int $time): void
|
|
|
|
|
{
|
|
|
|
|
$this->response()->header('Last-Modified', gmdate('D, d M Y H:i:s \G\M\T', $time));
|
|
|
|
|
|
|
|
|
|
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
|
|
|
|
|