2014-12-24 03:28:26 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace JsonRPC;
|
|
|
|
|
|
|
|
use Closure;
|
|
|
|
use Exception;
|
2016-05-08 21:53:45 +02:00
|
|
|
use JsonRPC\Request\BatchRequestParser;
|
|
|
|
use JsonRPC\Request\RequestParser;
|
|
|
|
use JsonRPC\Response\ResponseBuilder;
|
|
|
|
use JsonRPC\Validator\HostValidator;
|
|
|
|
use JsonRPC\Validator\JsonFormatValidator;
|
|
|
|
use JsonRPC\Validator\UserValidator;
|
2014-12-24 03:28:26 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* JsonRPC server class
|
|
|
|
*
|
|
|
|
* @package JsonRPC
|
|
|
|
* @author Frederic Guillot
|
|
|
|
*/
|
|
|
|
class Server
|
|
|
|
{
|
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* Allowed hosts
|
2014-12-24 03:28:26 +01:00
|
|
|
*
|
|
|
|
* @access private
|
2015-08-15 03:33:39 +02:00
|
|
|
* @var array
|
2014-12-24 03:28:26 +01:00
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
private $hosts = array();
|
2014-12-24 03:28:26 +01:00
|
|
|
|
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* Data received from the client
|
2014-12-24 03:28:26 +01:00
|
|
|
*
|
|
|
|
* @access private
|
|
|
|
* @var array
|
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
private $payload = array();
|
2014-12-24 03:28:26 +01:00
|
|
|
|
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* List of exception classes that should be relayed to client
|
2014-12-24 03:28:26 +01:00
|
|
|
*
|
|
|
|
* @access private
|
|
|
|
* @var array
|
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
private $exceptions = array();
|
2014-12-24 03:28:26 +01:00
|
|
|
|
2015-02-06 03:16:34 +01:00
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* Username
|
2015-02-06 03:16:34 +01:00
|
|
|
*
|
|
|
|
* @access private
|
2016-05-08 21:53:45 +02:00
|
|
|
* @var string
|
2015-02-06 03:16:34 +01:00
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
private $username = '';
|
2015-02-06 03:16:34 +01:00
|
|
|
|
2015-06-21 15:56:36 +02:00
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* Password
|
2015-06-21 15:56:36 +02:00
|
|
|
*
|
|
|
|
* @access private
|
2016-05-08 21:53:45 +02:00
|
|
|
* @var string
|
2015-06-21 15:56:36 +02:00
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
private $password = '';
|
2015-06-21 15:56:36 +02:00
|
|
|
|
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* Allowed users
|
2015-06-21 15:56:36 +02:00
|
|
|
*
|
|
|
|
* @access private
|
2016-05-08 21:53:45 +02:00
|
|
|
* @var array
|
2015-06-21 15:56:36 +02:00
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
private $users = array();
|
2015-06-21 15:56:36 +02:00
|
|
|
|
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* $_SERVER
|
2015-06-21 15:56:36 +02:00
|
|
|
*
|
|
|
|
* @access private
|
2016-05-08 21:53:45 +02:00
|
|
|
* @var array
|
2015-06-21 15:56:36 +02:00
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
private $serverVariable;
|
2015-06-21 15:56:36 +02:00
|
|
|
|
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* ProcedureHandler object
|
2015-06-21 15:56:36 +02:00
|
|
|
*
|
|
|
|
* @access private
|
2016-05-08 21:53:45 +02:00
|
|
|
* @var ProcedureHandler
|
2015-06-21 15:56:36 +02:00
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
private $procedureHandler;
|
2015-06-21 15:56:36 +02:00
|
|
|
|
2014-12-24 03:28:26 +01:00
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* @access public
|
2016-05-08 21:53:45 +02:00
|
|
|
* @param string $request
|
|
|
|
* @param array $server
|
2014-12-24 03:28:26 +01:00
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
public function __construct($request = '', array $server = array())
|
2014-12-24 03:28:26 +01:00
|
|
|
{
|
2015-08-15 03:33:39 +02:00
|
|
|
if ($request !== '') {
|
|
|
|
$this->payload = json_decode($request, true);
|
2016-05-08 21:53:45 +02:00
|
|
|
} else {
|
2015-08-15 03:33:39 +02:00
|
|
|
$this->payload = json_decode(file_get_contents('php://input'), true);
|
|
|
|
}
|
2015-06-21 15:56:36 +02:00
|
|
|
|
2016-05-08 21:53:45 +02:00
|
|
|
$this->serverVariable = $server ?: $_SERVER;
|
|
|
|
$this->procedureHandler = new ProcedureHandler();
|
2015-06-21 15:56:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Define alternative authentication header
|
|
|
|
*
|
|
|
|
* @access public
|
|
|
|
* @param string $header Header name
|
|
|
|
* @return Server
|
|
|
|
*/
|
|
|
|
public function setAuthenticationHeader($header)
|
|
|
|
{
|
|
|
|
if (! empty($header)) {
|
|
|
|
$header = 'HTTP_'.str_replace('-', '_', strtoupper($header));
|
2016-05-08 21:53:45 +02:00
|
|
|
$value = $this->getServerVariable($header);
|
2015-06-21 15:56:36 +02:00
|
|
|
|
2016-05-08 21:53:45 +02:00
|
|
|
if (! empty($value)) {
|
|
|
|
list($this->username, $this->password) = explode(':', base64_decode($value));
|
2015-06-21 15:56:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* Get ProcedureHandler
|
2015-06-21 15:56:36 +02:00
|
|
|
*
|
|
|
|
* @access public
|
2016-05-08 21:53:45 +02:00
|
|
|
* @return ProcedureHandler
|
2015-06-21 15:56:36 +02:00
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
public function getProcedureHandler()
|
2015-06-21 15:56:36 +02:00
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
return $this->procedureHandler;
|
2015-06-21 15:56:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* Get username
|
2015-06-21 15:56:36 +02:00
|
|
|
*
|
|
|
|
* @access public
|
|
|
|
* @return string
|
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
public function getUsername()
|
2015-06-21 15:56:36 +02:00
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
return $this->username ?: $this->getServerVariable('PHP_AUTH_USER');
|
2015-06-21 15:56:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* Get password
|
2015-06-21 15:56:36 +02:00
|
|
|
*
|
|
|
|
* @access public
|
2016-05-08 21:53:45 +02:00
|
|
|
* @return string
|
2015-06-21 15:56:36 +02:00
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
public function getPassword()
|
2015-06-21 15:56:36 +02:00
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
return $this->password ?: $this->getServerVariable('PHP_AUTH_PW');
|
2014-12-24 03:28:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* IP based client restrictions
|
|
|
|
*
|
|
|
|
* @access public
|
|
|
|
* @param array $hosts List of hosts
|
2016-05-08 21:53:45 +02:00
|
|
|
* @return Server
|
2014-12-24 03:28:26 +01:00
|
|
|
*/
|
2015-06-21 15:56:36 +02:00
|
|
|
public function allowHosts(array $hosts)
|
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
$this->hosts = $hosts;
|
|
|
|
return $this;
|
2014-12-24 03:28:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* HTTP Basic authentication
|
|
|
|
*
|
|
|
|
* @access public
|
2016-05-08 21:53:45 +02:00
|
|
|
* @param array $users Dictionary of username/password
|
2015-06-21 15:56:36 +02:00
|
|
|
* @return Server
|
2014-12-24 03:28:26 +01:00
|
|
|
*/
|
|
|
|
public function authentication(array $users)
|
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
$this->users = $users;
|
2015-06-21 15:56:36 +02:00
|
|
|
return $this;
|
2014-12-24 03:28:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register a new procedure
|
|
|
|
*
|
|
|
|
* @access public
|
|
|
|
* @param string $procedure Procedure name
|
|
|
|
* @param closure $callback Callback
|
2015-06-21 15:56:36 +02:00
|
|
|
* @return Server
|
2014-12-24 03:28:26 +01:00
|
|
|
*/
|
2015-08-15 03:33:39 +02:00
|
|
|
public function register($procedure, Closure $callback)
|
2014-12-24 03:28:26 +01:00
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
$this->procedureHandler->withCallback($procedure, $callback);
|
2015-06-21 15:56:36 +02:00
|
|
|
return $this;
|
2014-12-24 03:28:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Bind a procedure to a class
|
|
|
|
*
|
|
|
|
* @access public
|
|
|
|
* @param string $procedure Procedure name
|
|
|
|
* @param mixed $class Class name or instance
|
|
|
|
* @param string $method Procedure name
|
2015-06-21 15:56:36 +02:00
|
|
|
* @return Server
|
2014-12-24 03:28:26 +01:00
|
|
|
*/
|
2015-03-31 02:13:07 +02:00
|
|
|
public function bind($procedure, $class, $method = '')
|
2014-12-24 03:28:26 +01:00
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
$this->procedureHandler->withClassAndMethod($procedure, $class, $method);
|
2015-06-21 15:56:36 +02:00
|
|
|
return $this;
|
2014-12-24 03:28:26 +01:00
|
|
|
}
|
|
|
|
|
2015-02-06 03:16:34 +01:00
|
|
|
/**
|
|
|
|
* Bind a class instance
|
|
|
|
*
|
|
|
|
* @access public
|
|
|
|
* @param mixed $instance Instance name
|
2015-06-21 15:56:36 +02:00
|
|
|
* @return Server
|
2015-02-06 03:16:34 +01:00
|
|
|
*/
|
|
|
|
public function attach($instance)
|
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
$this->procedureHandler->withObject($instance);
|
2015-06-21 15:56:36 +02:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Bind an exception
|
|
|
|
* If this exception occurs it is relayed to the client as JSON-RPC error
|
|
|
|
*
|
|
|
|
* @access public
|
|
|
|
* @param mixed $exception Exception class. Defaults to all.
|
|
|
|
* @return Server
|
|
|
|
*/
|
|
|
|
public function attachException($exception = 'Exception')
|
|
|
|
{
|
|
|
|
$this->exceptions[] = $exception;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Attach a method that will be called before the procedure
|
|
|
|
*
|
|
|
|
* @access public
|
|
|
|
* @param string $before
|
|
|
|
* @return Server
|
|
|
|
*/
|
|
|
|
public function before($before)
|
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
$this->procedureHandler->withBeforeMethod($before);
|
2015-06-21 15:56:36 +02:00
|
|
|
return $this;
|
2015-02-06 03:16:34 +01:00
|
|
|
}
|
|
|
|
|
2014-12-24 03:28:26 +01:00
|
|
|
/**
|
|
|
|
* Parse incoming requests
|
|
|
|
*
|
|
|
|
* @access public
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function execute()
|
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
$responseBuilder = ResponseBuilder::create();
|
2014-12-24 03:28:26 +01:00
|
|
|
|
2016-05-08 21:53:45 +02:00
|
|
|
try {
|
|
|
|
$this->procedureHandler
|
|
|
|
->withUsername($this->getUsername())
|
|
|
|
->withPassword($this->getPassword());
|
2014-12-24 03:28:26 +01:00
|
|
|
|
2016-05-08 21:53:45 +02:00
|
|
|
JsonFormatValidator::validate($this->payload);
|
|
|
|
HostValidator::validate($this->hosts, $this->getServerVariable('REMOTE_ADDR'));
|
|
|
|
UserValidator::validate($this->users, $this->getUsername(), $this->getPassword());
|
2014-12-24 03:28:26 +01:00
|
|
|
|
2016-05-08 21:53:45 +02:00
|
|
|
$response = $this->parseRequest();
|
2015-06-21 15:56:36 +02:00
|
|
|
|
2016-05-08 21:53:45 +02:00
|
|
|
} catch (Exception $e) {
|
|
|
|
$response = $responseBuilder->withException($e)->build();
|
2015-06-21 15:56:36 +02:00
|
|
|
}
|
|
|
|
|
2016-05-08 21:53:45 +02:00
|
|
|
$responseBuilder->sendHeaders();
|
|
|
|
return $response;
|
2014-12-24 03:28:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* Parse incoming request
|
2014-12-24 03:28:26 +01:00
|
|
|
*
|
2016-05-08 21:53:45 +02:00
|
|
|
* @access private
|
|
|
|
* @return string
|
2014-12-24 03:28:26 +01:00
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
private function parseRequest()
|
2014-12-24 03:28:26 +01:00
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
if (BatchRequestParser::isBatchRequest($this->payload)) {
|
|
|
|
return BatchRequestParser::create()
|
|
|
|
->withPayload($this->payload)
|
|
|
|
->withProcedureHandler($this->procedureHandler)
|
|
|
|
->parse();
|
2014-12-24 03:28:26 +01:00
|
|
|
}
|
|
|
|
|
2016-05-08 21:53:45 +02:00
|
|
|
return RequestParser::create()
|
|
|
|
->withPayload($this->payload)
|
|
|
|
->withProcedureHandler($this->procedureHandler)
|
|
|
|
->parse();
|
2014-12-24 03:28:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-05-08 21:53:45 +02:00
|
|
|
* Check existence and get value of server variable
|
2014-12-24 03:28:26 +01:00
|
|
|
*
|
2016-05-08 21:53:45 +02:00
|
|
|
* @access private
|
|
|
|
* @param string $variable
|
|
|
|
* @return string|null
|
2014-12-24 03:28:26 +01:00
|
|
|
*/
|
2016-05-08 21:53:45 +02:00
|
|
|
private function getServerVariable($variable)
|
2014-12-24 03:28:26 +01:00
|
|
|
{
|
2016-05-08 21:53:45 +02:00
|
|
|
return isset($this->serverVariable[$variable]) ? $this->serverVariable[$variable] : null;
|
2014-12-24 03:28:26 +01:00
|
|
|
}
|
|
|
|
}
|