File Manager

Current Directory: /home/astoriaah/www/plugins/system/shlib/shl_packages/api
Viewing File: /home/astoriaah/www/plugins/system/shlib/shl_packages/api/route.php
<?php /** * Shlib - programming library * * @author Yannick Gaultier * @copyright (c) Yannick Gaultier 2020 * @package shlib * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL * @version 0.4.0.716 * @date 2020-12-07 */ defined('_JEXEC') or die; /** * Parse and manage the named parameters of an API request. * */ class ShlApi_Route extends \ShlBase { protected $namespace; protected $method; protected $priority; protected $version; protected $route; protected $callback; protected $auth_callback; protected $auth_type; protected $authorizations; protected $query_vars_whitelist; protected $reg_exp; protected $params_list; protected $authorizer; /** * \ShlApi_Route constructor. Stores and sanitizes a route definition. * * @param array $def * * @throws Exception */ public function __construct($def) { // prepare $route = wbArrayGet($def, 'route', ''); if (!is_string($route)) { throw new Exception('Invalid route registered: ' . print_r($route, true)); } $route = trim($route, '/'); if (empty($route)) { throw new Exception('Invalid route registered.'); } $hasParams = (bool) preg_match_all( '/{([a-zA-Z0-9_]+)}/', $route, $matches ); if (empty($hasParams)) { $paramsList = array(); $regExp = ''; } else { $paramsList = $matches[1]; $regExp = preg_replace( '/{[a-zA-Z0-9_]+}/', '([a-zA-Z0-9_]+)', $route ); $regExp = '/^' . str_replace('/', '\/', $regExp) . '$/u'; } // which method this route applies to? $this->method = strtoupper( wbArrayGet($def, 'method', 'GET') ); $this->namespace = wbArrayGet($def, 'namespace', ''); $this->priority = wbArrayGet($def, 'priority', 0); $this->version = wbArrayGet($def, 'version', 'v1'); $this->route = $route; // what to execute $this->callback = wbArrayGet($def, 'callback', null); // authentication/authorization $this->auth_type = wbArrayGet($def, 'auth_type', \ShlApi_Authorizer::AUTH_LOG_IN); $this->auth_callback = wbArrayGet($def, 'auth_callback', null); $this->authorizations = wbArrayGet($def, 'authorizations', array()); // must have authorizations definition, error out if (\ShlApi_Authorizer::AUTH_PUBLIC != $this->auth_type && empty($this->authorizations)) { throw new Exception( sprintf( 'API route %s not public, but no authorizations specified.', $this->namespace . ':' . $this->method . ':' . $this->route ) ); } // whitelist for query vars in incoming request. $this->query_vars_whitelist = wbArrayGet($def, 'query_vars_whitelist', array()); // computed reg_exp based on passed route $this->reg_exp = $regExp; // computed parameters name list, based on passed route $this->params_list = $paramsList; // authorizer will decide to allow requests $this->authorizer = new \ShlApi_Authorizer( $this->auth_type, $this->authorizations, $this->auth_callback ); } /** * Match a path against a route, then parse any parameters. * * /aliases * /aliases/{id} * /aliases/{id}/{alias} * /aliases/{id}/alias/{alias_id} * * @param string $method HTTP method used. * @param string $path Path to match. */ public function match($method, $path) { // check method if (empty($method) || $method !== $this->method) { return false; } // direct match if not a parameterized route. if (empty($this->params_list)) { if ($this->route == $path) { return array( 'callback' => $this->callback, 'parameters' => array() ); } else { return false; } } // parse request if some params. $matched = preg_match_all( $this->reg_exp, $path, $matches, PREG_SET_ORDER ); if (!empty($matched)) { array_shift($matches[0]); return array( 'callback' => $this->callback, 'parameters' => $matches[0] ); } return false; } /** * Fully process a request if it matches this route definition. * * @param \ShlApi_Request $request * * @return mixed|void */ public function processRequest($request) { $path = $request->getPath(); $parsedRoute = $this->match( $request->getMethod(), $path ); if (false === $parsedRoute) { return; } // we have a candidate, check auth $authorization = $this->authorizer->authorize( $request ); $status = wbArrayGet($authorization, 'status', \ShlSystem_Http::RETURN_UNAUTHORIZED); if (\ShlSystem_Http::RETURN_OK != $status) { $processedRequest = $request ->setResponseStatus($status) ->addResponseErrors( wbArrayGet( $authorization, 'errors', array() ) ); return $processedRequest; } // call the handler $request->setParameters( new \ShlApi_Input( $this->params_list, $parsedRoute['parameters'] ) ); // store this router, will be useful later. $request->setActiveRoute( $this ); // call the actual code handling this route. $request = call_user_func_array( $this->callback, array($request) ); // adjust HTTP status according to action return $request; } /** * Filter the query variables against the whitelist. * * @param \ShlApi_Input $queryVars */ public function filterQueryVariables($queryVars) { // we need a whitelist if (empty($this->query_vars_whitelist)) { $queryVars = array(); } else { $queryVars = array_intersect_key( $queryVars->getArray(), array_flip( $this->query_vars_whitelist ) ); } return new \ShlApi_Input( $queryVars ); } /** * Magic getter. * * @param string $name * * @return mixed */ public function __get($name) { if (method_exists($this, $name)) { return $this->{$name}(); } elseif (property_exists($this, $name)) { // Getter/Setter not defined so return property if it exists return $this->{$name}; } return null; } }