Imitate the REST api using url parameter based implementation

Reason for this implementation is some clients having trouble configuring the rest api either due to not having proper access to the webserver in a shared hosting environment or security restrictions. But still from icehrm frontend we need to consume the backend rest api.
This commit is contained in:
Alan Cell
2020-11-06 20:00:53 +01:00
parent da55c7a2d2
commit 2abe52963f
7 changed files with 236 additions and 3 deletions

41
core/api.php Normal file
View File

@@ -0,0 +1,41 @@
<?php
define('CLIENT_PATH',dirname(__FILE__));
include ("config.base.php");
include ("include.common.php");
include("server.includes.inc.php");
if(\Classes\SettingsManager::getInstance()->getSetting('Api: REST Api Enabled') == '1') {
\Utils\LogManager::getInstance()->info("Request: " . $_REQUEST);
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit();
}
define('REST_API_PATH', '/');
$echoRoute = \Classes\Macaw::get(REST_API_PATH . 'echo', function () {
echo "Echo " . rand();
});
\Utils\LogManager::getInstance()->debug('Api registered URI: '.$echoRoute);
$moduleManagers = \Classes\BaseService::getInstance()->getModuleManagers();
foreach ($moduleManagers as $moduleManagerObj) {
$moduleManagerObj->setupRestEndPoints();
}
$method = $_SERVER['REQUEST_METHOD'];
if (strtoupper($method) === 'GET') {
\Classes\IceRoute::dispatch($_GET['url'], $method);
} else {
$method = strtoupper($_REQUEST['method']);
\Classes\IceRoute::dispatch($_REQUEST['url'], $method);
}
}else{
echo "REST Api is not enabled. Please set 'Api: REST Api Enabled' setting to true";
}

177
core/src/Classes/IceRoute.php Executable file
View File

@@ -0,0 +1,177 @@
<?php
namespace Classes;
/**
* @method static IceRoute get(string $route, Callable $callback)
* @method static IceRoute post(string $route, Callable $callback)
* @method static IceRoute put(string $route, Callable $callback)
* @method static IceRoute delete(string $route, Callable $callback)
* @method static IceRoute options(string $route, Callable $callback)
* @method static IceRoute head(string $route, Callable $callback)
*/
class IceRoute
{
public static $halts = false;
public static $routes = array();
public static $methods = array();
public static $callbacks = array();
public static $patterns = array(
':any' => '[^/]+',
':num' => '[0-9]+',
':all' => '.*'
);
public static $error_callback;
/**
* Defines a route w/ callback and method
*/
public static function __callstatic($method, $params)
{
$uri = $params[0][0];
$callback = $params[0][1];
array_push(self::$routes, $uri);
array_push(self::$methods, strtoupper($method));
array_push(self::$callbacks, $callback);
return $uri;
}
/**
* Defines callback if route is not found
*/
public static function error($callback)
{
self::$error_callback = $callback;
}
public static function haltOnMatch($flag = true)
{
self::$halts = $flag;
}
/**
* Runs the callback for the given request
*/
public static function dispatch($uri, $method)
{
$searches = array_keys(static::$patterns);
$replaces = array_values(static::$patterns);
$found_route = false;
self::$routes = str_replace('//', '/', self::$routes);
// check if route is defined without regex
if (in_array($uri, self::$routes)) {
$route_pos = array_keys(self::$routes, $uri);
foreach ($route_pos as $route) {
//using an ANY option to match both GET and POST requests
if (self::$methods[$route] == $method || self::$methods[$route] == 'ANY') {
$found_route = true;
//if route is not an object
if (!is_object(self::$callbacks[$route])) {
//grab all parts based on a / separator
$parts = explode('/', self::$callbacks[$route]);
//collect the last index of the array
$last = end($parts);
//grab the controller name and method call
$segments = explode('@', $last);
//instanitate controller
$controller = new $segments[0]();
//call method
$controller->$segments[1]();
if (self::$halts) {
return;
}
} else {
//call closure
call_user_func(self::$callbacks[$route]);
if (self::$halts) {
return;
}
}
}
}
} else {
// check if defined with regex
$pos = 0;
foreach (self::$routes as $route) {
if (strpos($route, ':') !== false) {
$route = str_replace($searches, $replaces, $route);
}
if (preg_match('#^' . $route . '$#', $uri, $matched)) {
if (self::$methods[$pos] == $method) {
$found_route = true;
array_shift($matched); //remove $matched[0] as [1] is the first parameter.
if (!is_object(self::$callbacks[$pos])) {
//grab all parts based on a / separator
$parts = explode('/', self::$callbacks[$pos]);
//collect the last index of the array
$last = end($parts);
//grab the controller name and method call
$segments = explode('@', $last);
//instanitate controller
$controller = new $segments[0]();
//fix multi parameters
if (!method_exists($controller, $segments[1])) {
echo "controller and action not found";
} else {
call_user_func_array(array($controller, $segments[1]), $matched);
}
//call method and pass any extra parameters to the method
// $controller->$segments[1](implode(",", $matched));
if (self::$halts) {
return;
}
} else {
call_user_func_array(self::$callbacks[$pos], $matched);
if (self::$halts) {
return;
}
}
}
}
$pos++;
}
}
// run the error callback if the route was not found
if ($found_route == false) {
if (!self::$error_callback) {
self::$error_callback = function () {
header($_SERVER['SERVER_PROTOCOL']." 404 Not Found");
echo '404';
};
}
call_user_func(self::$error_callback);
}
}
}

View File

@@ -42,6 +42,8 @@ class Macaw
array_push(self::$methods, strtoupper($method));
array_push(self::$callbacks, $callback);
call_user_func('\Classes\IceRoute::'.$method, $params);
return $uri;
}

View File

@@ -420,6 +420,8 @@ class RestEndPoint
if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
$token = $matches[1];
}
} else {
$token = $_GET['token'];
}
if (strlen($token) > 32) {