1
0

copy a few files from mvu fork

This commit is contained in:
Mike Schwörer 2020-01-13 14:39:35 +01:00
parent 4da4c47915
commit d5783efff7
6 changed files with 445 additions and 17 deletions

View File

@ -1,6 +1,9 @@
<?php <?php
require_once (__DIR__ . '/internals/base.php'); require_once (__DIR__ . '/internals/website.php');
$site = new Website();
$site->init();
$URL_RULES = $URL_RULES =
[ [
@ -79,6 +82,8 @@ $URL_RULES =
[ 'url' => ['404'], 'target' => 'pages/error_404.php', 'options' => [], ], [ 'url' => ['404'], 'target' => 'pages/error_404.php', 'options' => [], ],
]; ];
$site->serve($URL_RULES);
//############################################################################# //#############################################################################
try { try {

View File

@ -0,0 +1,26 @@
<?php if(count(get_included_files()) ==1) exit("Direct access not permitted.");
class PageFrameOptions
{
/** @var string */
public $raw;
/** @var string */
public $title = '';
/** @var int */
public $statuscode = 200;
/** @var bool */
public $force_404 = false;
/** @var string */
public $force_404_message = '';
/** @var string */
public $frame = 'default_frame.php';
/** @var string */
public $contentType = null;
}

View File

@ -0,0 +1,115 @@
<?php if(count(get_included_files()) ==1) exit("Direct access not permitted.");
require_once "website.php";
require_once "utils.php";
class RuleEngine
{
/**
* @param Website $app
* @param array $urlConfig
* @return URLRoute
*/
public static function findRoute(Website $app, array $urlConfig): URLRoute
{
if ($app->isProd())
$requri = $_SERVER['REQUEST_URI'];
else
$requri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : 'localhost:80/';
$parse = parse_url($requri);
$path = isset($parse['path']) ? $parse['path'] : '';
$pathparts = preg_split('@/@', $path, NULL, PREG_SPLIT_NO_EMPTY);
$partcount = count($pathparts);
foreach ($urlConfig as $rule)
{
$route = self::testRule($app, $rule, $requri, $pathparts, $partcount);
if ($route === null) continue;
if ($app->getCurrentRights() >= $route->minimal_access_rights) return $route;
if ($app->isLoggedIn()) return URLRoute::getInsufficentRightsRoute($requri);
if (!$app->isLoggedIn()) return URLRoute::getLoginRoute($route, $requri);
}
return URLRoute::getNotFoundRoute($requri);
}
private static function testRule(Website $app, array $rule, string $requri, array $pathparts, int $partcount)
{
if ($partcount !== count($rule['url'])) return null;
$urlparams = [];
$match = true;
for($i = 0; $i < $partcount; $i++)
{
$comp = $rule['url'][$i];
if (startsWith($comp, '?{') && endsWith($comp, '}'))
{
$ident = substr($comp, 2, strlen($comp)-3);
$urlparams[$ident] = $pathparts[$i];
}
else if ($comp === '*')
{
if (!isset($urlparams['*'])) $urlparams['*'] = [];
$urlparams['*'] []= $pathparts[$i];
}
else
{
if (strtolower($comp) !== strtolower($pathparts[$i])) { $match = false; break; }
}
}
if (!$match) return null;
$route = new URLRoute($rule['target'], $requri);
foreach($rule['parameter'] as $optname => $optvalue)
{
$value = $optvalue;
if ($value === '%GET%')
{
if (!isset($_GET[$optname])) { $match = false; break; }
$value = $_GET[$optname];
}
else if ($value === '%POST%')
{
if (!isset($_POST[$optname])) { $match = false; break; }
$value = $_POST[$optname];
}
else if ($value === '%URL%')
{
if (!isset($urlparams[$optname])) { $match = false; break; }
$value = urldecode($urlparams[$optname]);
}
$route->parameter[strtolower($optname)] = $value;
}
if (!$match) return null;
$ctrlOpt = $rule['options'];
if (in_array('disabled', $ctrlOpt)) return null;
if (in_array('api', $ctrlOpt)) $route->isAPI = true;
if (isset($ctrlOpt['method']) && $_SERVER["REQUEST_METHOD"] !== $ctrlOpt['method']) return null;
$route->minimal_access_rights = (($rule['rights']===null) ? 0 : $rule['rights']);
if ($app->isProd() && $app->config->app_enforce_https && isHTTPRequest() && !in_array('http', $ctrlOpt))
{
// enforce https
$redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
ob_end_clean();
header('HTTP/1.1 301 Moved Permanently');
header('Location: ' . $redirect);
exit();
}
return $route;
}
}

122
www/internals/urlroute.php Normal file
View File

@ -0,0 +1,122 @@
<?php if(count(get_included_files()) ==1) exit("Direct access not permitted.");
require_once "URLRoute.php";
class URLRoute
{
/** @var string */
public $targetpath;
/** @var string */
public $full_url;
/** @var array */
public $parameter;
/** @var int */
public $minimal_access_rights;
/** @var int */
public $isAPI;
public function __construct(string $target, string $url)
{
$this->targetpath = __DIR__ . '/../pages/' . $target;
$this->full_url = $url;
$this->parameter = [];
$this->minimal_access_rights = 0;
$this->isAPI = false;
}
/**
* @param VApp $app
* @return PageFrameOptions
*/
public function get(Website $app): PageFrameOptions
{
$pfo = new PageFrameOptions();
$pfo->title = $app->config->verein_kurzel . " Orga"; // default title
if ($this->isAPI)
{
$pfo->frame = 'no_frame.php';
$pfo->contentType = 'application/json';
}
return $this->getDirect($app, $pfo);
}
/**
* @param Website $app
* @param PageFrameOptions $pfo
* @return PageFrameOptions
*/
public function getDirect(Website $app, PageFrameOptions $pfo): PageFrameOptions
{
@ob_end_clean();
ob_start();
global $ROUTE;
global $FRAME_OPTIONS;
global $APP;
$ROUTE = $this;
$FRAME_OPTIONS = $pfo;
$APP = $app;
/** @noinspection PhpIncludeInspection */
require $this->targetpath;
$FRAME_OPTIONS->raw = ob_get_clean();
return $FRAME_OPTIONS;
}
/**
* @param string $requri
* @return URLRoute
*/
public static function getInsufficentRightsRoute(string $requri): URLRoute
{
$r = new URLRoute('errors/insufficent_rights.php', $requri);
$r->parameter = [];
$r->minimal_access_rights = 0;
return $r;
}
/**
* @param URLRoute $route
* @param string $requri
* @return URLRoute
*/
public static function getLoginRoute(URLRoute $route, string $requri): URLRoute
{
$r = new URLRoute('login.php', $requri);
$r->parameter = [ 'redirect' => $route->full_url ];
$r->minimal_access_rights = 0;
return $r;
}
/**
* @param string $requri
* @return URLRoute
*/
public static function getNotFoundRoute(string $requri): URLRoute
{
$r = new URLRoute('errors/not_found.php', $requri);
$r->parameter = [];
$r->minimal_access_rights = 0;
return $r;
}
/**
* @param string $requri
* @return URLRoute
*/
public static function getServerErrorRoute(string $requri): URLRoute
{
$r = new URLRoute('errors/server_error.php', $requri);
$r->parameter = [];
$r->minimal_access_rights = 0;
return $r;
}
}

View File

@ -11,22 +11,6 @@ global $ADDITIONAL_STYLESHEETS;
$ADDITIONAL_SCRIPTS = []; $ADDITIONAL_SCRIPTS = [];
$ADDITIONAL_STYLESHEETS = []; $ADDITIONAL_STYLESHEETS = [];
function InitPHP() {
set_error_handler("exception_error_handler"); // errors as exceptions for global catch
ob_start(); // buffer outpt so it can be discarded in httpError
}
function exception_error_handler($severity, $message, $file, $line) {
if (!(error_reporting() & $severity)) {
// This error code is not included in error_reporting
return;
}
throw new ErrorException($message, 0, $severity, $file, $line);
}
function startsWith($haystack, $needle) function startsWith($haystack, $needle)
{ {
$length = strlen($needle); $length = strlen($needle);

176
www/internals/website.php Normal file
View File

@ -0,0 +1,176 @@
<?php if(count(get_included_files()) ==1) exit("Direct access not permitted.");
require_once 'ruleengine.php';
require_once 'urlroute.php';
require_once 'pageframeoptions.php';
class Website
{
/** @var Website */
private static $instance;
/** @var array */
private $config;
public function init()
{
set_error_handler("exception_error_handler"); // errors as exceptions for global catch
try
{
$this->config = require (__DIR__ . "/config.php");
}
catch (exception $e)
{
$this->serveServerError("config.php not found", formatException($e), null);
}
try
{
if (!$this->config['prod'])
{
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
}
self::$instance = $this;
}
catch (exception $e)
{
$this->serveServerError("Initialization failed", formatException($e), null);
}
}
public static function getInstance()
{
return self::$instance;
}
public function serve($rules)
{
try
{
$route = RuleEngine::findRoute($this, $rules);
$result = $route->get($this);
if ($result->force_404)
{
$this->serveCustom404($route->full_url, $result);
exit();
}
if ($result->contentType !== null) header('Content-Type: ' . $result->contentType);
http_response_code($result->statuscode);
$this->output($result, $route);
exit();
}
catch (Exception $e)
{
$this->serveServerError(null, formatException($e), null);
}
}
private function serveCustom404(string $uri, PageFrameOptions $frameOpt)
{
try
{
@ob_end_clean();
$frameOpt->statuscode = 404;
$frameOpt->title = 'Page not found';
$route = URLRoute::getNotFoundRoute($uri);
$result = $route->getDirect($this, $frameOpt);
$this->output($result, $route);
}
catch (Exception $e)
{
$this->serveServerError(null, formatException($e), null);
}
exit();
}
/**
* @param string|null $message
* @param string|null $debugInfo
* @param PageFrameOptions|null $frameOpt
*/
private function serveServerError($message, $debugInfo, $frameOpt)
{
try
{
@ob_end_clean();
if ($frameOpt === null) $frameOpt = new PageFrameOptions();
$frameOpt->statuscode = 500;
$frameOpt->title = 'Internal Server Error';
$frameOpt->frame = 'error_frame.php';
$route = URLRoute::getServerErrorRoute($_SERVER['REQUEST_URI']);
$route->parameter['message'] = $message;
$route->parameter['debuginfo'] = $debugInfo;
$result = $route->getDirect($this, $frameOpt);
$this->output($result, $route);
}
catch (Exception $e)
{
http_response_code(500);
die('Internal Server Error');
}
exit();
}
/**
* @param PageFrameOptions $pfo
* @param URLRoute $route
*/
private function output(PageFrameOptions $pfo, URLRoute $route)
{
if ($pfo->contentType !== null) header('Content-Type: ' . $pfo->contentType);
http_response_code($pfo->statuscode);
global $ROUTE;
global $FRAME_OPTIONS;
global $APP;
$ROUTE = $route;
$FRAME_OPTIONS = $pfo;
$APP = $this;
/** @noinspection PhpIncludeInspection */
require __DIR__ . '/../pages/frame/' . $FRAME_OPTIONS->frame;
}
/**
* @return bool
*/
public function isProd()
{
if ($this->config == null) return true;
return $this->config['prod'];
}
}
/**
* @param $severity
* @param $message
* @param $file
* @param $line
* @throws ErrorException
*/
function exception_error_handler($severity, $message, $file, $line) {
// This error code is not included in error_reporting
if (!(error_reporting() & $severity)) return;
throw new ErrorException($message, 0, $severity, $file, $line);
}