You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
4.9 KiB
PHP
161 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace Bsr\Webservice;
|
|
|
|
use Bsr\Webservice\Exception\UsageException;
|
|
use Bsr\Webservice\Exception\ConfigException;
|
|
use Bsr\Webservice\Exception\WebException;
|
|
use Bsr\Utils\Configuration\Configuration;
|
|
use Bsr\Utils\Logger\Logger;
|
|
|
|
abstract class WebService
|
|
{
|
|
private $func = null;
|
|
|
|
private $status = 200;
|
|
|
|
private $version = null;
|
|
|
|
public function __construct($version) {
|
|
$this->version = $version;
|
|
}
|
|
|
|
/**
|
|
* Treat the current request and output the result. This is the only
|
|
* method that should be called on the webservice directly !
|
|
* @param bool $sendSession needed for testing
|
|
*/
|
|
public function run($sendSession = true)
|
|
{
|
|
Logger::start(array('version' => $this->version));
|
|
|
|
$rendererClass = Configuration::get('renderer.class', __NAMESPACE__ . '\Renderer');
|
|
$renderer = new $rendererClass;
|
|
|
|
$data = array();
|
|
|
|
try {
|
|
|
|
$result = $this->call($sendSession);
|
|
$data["result"][$this->func] = $result;
|
|
|
|
} catch (WebException $e) {
|
|
|
|
$data["error"]["code"] = $e->getCode();
|
|
$data["error"]["reason"] = $e->getMessage();
|
|
$data["error"]["name"] = $e->getName();
|
|
|
|
$data['extra'] = Help::exception($e, $this, $this->func);
|
|
|
|
$this->status = 400;
|
|
|
|
Logger::info($e->getName(), 'error');
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
$data["failure"]["code"] = $e->getCode();
|
|
$data["failure"]["reason"] = $e->getMessage();
|
|
$this->status = 500;
|
|
|
|
Logger::info($e->getMessage(), 'error');
|
|
|
|
}
|
|
|
|
Logger::stop(array('status' => $this->status));
|
|
$renderer->render($this->status, $data);
|
|
}
|
|
|
|
/**
|
|
* Determines which method to call based on GET or POST parameters and
|
|
* call it before returning the result.
|
|
*
|
|
* @param bool $sendSession used for testing
|
|
* @return array
|
|
* @throws UsageException
|
|
*/
|
|
private function call($sendSession = true)
|
|
{
|
|
if ($sendSession) {
|
|
session_save_path(Configuration::get('session.save_path'));
|
|
session_start();
|
|
}
|
|
|
|
$params = empty($_GET) ? $_POST : $_GET;
|
|
|
|
if (empty($params)) {
|
|
throw new UsageException("NoArguments", "No arguments specified.", UsageException::NO_ARGS);
|
|
}
|
|
|
|
if (!isset($params["func"])) {
|
|
throw new UsageException("MissingMethod", "No method specified.", UsageException::MISSING_METHOD);
|
|
}
|
|
|
|
$params = $this->filterParams($params);
|
|
|
|
$this->isAllowedMethodNameOrThrow($params["func"]);
|
|
|
|
$this->func = $params["func"];
|
|
unset($params['func']);
|
|
|
|
$this->paramsMatchMethodDeclarationOrThrow($params);
|
|
|
|
Logger::info(array(
|
|
'func' => $this->func.'('.implode(', ', $params).')',
|
|
));
|
|
|
|
return call_user_func_array(array($this, $this->func), $params);
|
|
}
|
|
|
|
/**
|
|
* Verify that the provided params match the declaration of the requested method
|
|
* @param array $params
|
|
* @throws UsageException
|
|
*/
|
|
protected function paramsMatchMethodDeclarationOrThrow($params)
|
|
{
|
|
if (!is_callable(array($this, $this->func))) {
|
|
throw new UsageException("BadMethod", "Method {$this->func} does not exist.", UsageException::BAD_METHOD);
|
|
}
|
|
|
|
$nbParams = count($params);
|
|
$rm = new \ReflectionMethod($this, $this->func);
|
|
$nbArgsFix = $rm->getNumberOfRequiredParameters();
|
|
$nbArgs = $rm->getNumberOfParameters();
|
|
|
|
/* Check the number of arguments. */
|
|
if ($nbParams < $nbArgsFix) {
|
|
throw new UsageException("TooFewArgs", "You must provide at least $nbArgsFix arguments.", UsageException::TOO_FEW_ARGS);
|
|
}
|
|
if ($nbParams > $nbArgs) {
|
|
throw new UsageException("TooManyArgs", "You must provide at most $nbArgs arguments.", UsageException::TOO_MANY_ARGS);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* If no configuration is available assumes that all public methods are allowed
|
|
* @param string the requested method name from api param func
|
|
*/
|
|
protected function isAllowedMethodNameOrThrow($requestedMethodName)
|
|
{
|
|
$allowedMethodNames = Configuration::get('webservice.api_method_names', null);
|
|
if (null === $allowedMethodNames) {
|
|
return;
|
|
}
|
|
if (!is_array($allowedMethodNames)) {
|
|
throw new ConfigException('Bad config. You should pass an array of method names as strings, in "webservice" key and "api_method_names" subkey');
|
|
}
|
|
if (!in_array($requestedMethodName, $allowedMethodNames)) {
|
|
throw new UsageException("BadMethod", "Method {$requestedMethodName} is not whitelisted. Pick one of :" . implode(', ', $allowedMethodNames), UsageException::BAD_METHOD);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Allow subclasses to filter params by overriding this
|
|
* @param $params
|
|
*/
|
|
protected function filterParams($params)
|
|
{
|
|
return $params;
|
|
}
|
|
}
|