First API implementation
This commit is contained in:
174
vendor/JsonRPC/Client.php
vendored
Normal file
174
vendor/JsonRPC/Client.php
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace JsonRPC;
|
||||
|
||||
/**
|
||||
* JsonRPC client class
|
||||
*
|
||||
* @package JsonRPC
|
||||
* @author Frderic Guillot
|
||||
* @license Unlicense http://unlicense.org/
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
/**
|
||||
* URL of the server
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $url;
|
||||
|
||||
/**
|
||||
* HTTP client timeout
|
||||
*
|
||||
* @access private
|
||||
* @var integer
|
||||
*/
|
||||
private $timeout;
|
||||
|
||||
/**
|
||||
* Debug flag
|
||||
*
|
||||
* @access private
|
||||
* @var bool
|
||||
*/
|
||||
private $debug;
|
||||
|
||||
/**
|
||||
* Username for authentication
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $username;
|
||||
|
||||
/**
|
||||
* Password for authentication
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $password;
|
||||
|
||||
/**
|
||||
* Default HTTP headers to send to the server
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $headers = array(
|
||||
'Connection: close',
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json'
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access public
|
||||
* @param string $url Server URL
|
||||
* @param integer $timeout Server URL
|
||||
* @param bool $debug Debug flag
|
||||
* @param array $headers Custom HTTP headers
|
||||
*/
|
||||
public function __construct($url, $timeout = 5, $debug = false, $headers = array())
|
||||
{
|
||||
$this->url = $url;
|
||||
$this->timeout = $timeout;
|
||||
$this->debug = $debug;
|
||||
$this->headers = array_merge($this->headers, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatic mapping of procedures
|
||||
*
|
||||
* @access public
|
||||
* @param string $method Procedure name
|
||||
* @param array $params Procedure arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $params)
|
||||
{
|
||||
return $this->execute($method, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set authentication parameters
|
||||
*
|
||||
* @access public
|
||||
* @param string $username Username
|
||||
* @param string $password Password
|
||||
*/
|
||||
public function authentication($username, $password)
|
||||
{
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute
|
||||
*
|
||||
* @access public
|
||||
* @param string $procedure Procedure name
|
||||
* @param array $params Procedure arguments
|
||||
* @return mixed
|
||||
*/
|
||||
public function execute($procedure, array $params = array())
|
||||
{
|
||||
$id = mt_rand();
|
||||
|
||||
$payload = array(
|
||||
'jsonrpc' => '2.0',
|
||||
'method' => $procedure,
|
||||
'id' => $id
|
||||
);
|
||||
|
||||
if (! empty($params)) {
|
||||
$payload['params'] = $params;
|
||||
}
|
||||
|
||||
$result = $this->doRequest($payload);
|
||||
|
||||
if (isset($result['id']) && $result['id'] == $id && array_key_exists('result', $result)) {
|
||||
return $result['result'];
|
||||
}
|
||||
else if ($this->debug && isset($result['error'])) {
|
||||
print_r($result['error']);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the HTTP request
|
||||
*
|
||||
* @access public
|
||||
* @param string $payload Data to send
|
||||
*/
|
||||
public function doRequest($payload)
|
||||
{
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $this->url);
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeout);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'JSON-RPC PHP Client');
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
||||
|
||||
if ($this->username && $this->password) {
|
||||
curl_setopt($ch, CURLOPT_USERPWD, $this->username.':'.$this->password);
|
||||
}
|
||||
|
||||
$result = curl_exec($ch);
|
||||
$response = json_decode($result, true);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
return is_array($response) ? $response : array();
|
||||
}
|
||||
}
|
||||
301
vendor/JsonRPC/Server.php
vendored
Normal file
301
vendor/JsonRPC/Server.php
vendored
Normal file
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
|
||||
namespace JsonRPC;
|
||||
|
||||
use ReflectionFunction;
|
||||
use Closure;
|
||||
|
||||
/**
|
||||
* JsonRPC server class
|
||||
*
|
||||
* @package JsonRPC
|
||||
* @author Frderic Guillot
|
||||
* @license Unlicense http://unlicense.org/
|
||||
*/
|
||||
class Server
|
||||
{
|
||||
/**
|
||||
* Data received from the client
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $payload;
|
||||
|
||||
/**
|
||||
* List of procedures
|
||||
*
|
||||
* @static
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
static private $procedures = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access public
|
||||
* @param string $payload Client data
|
||||
*/
|
||||
public function __construct($payload = '')
|
||||
{
|
||||
$this->payload = $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* IP based client restrictions
|
||||
*
|
||||
* Return an HTTP error 403 if the client is not allowed
|
||||
*
|
||||
* @access public
|
||||
* @param array $hosts List of hosts
|
||||
*/
|
||||
public function allowHosts(array $hosts) {
|
||||
|
||||
if (! in_array($_SERVER['REMOTE_ADDR'], $hosts)) {
|
||||
|
||||
header('Content-Type: application/json');
|
||||
header('HTTP/1.0 403 Forbidden');
|
||||
echo '["Access Forbidden"]';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP Basic authentication
|
||||
*
|
||||
* Return an HTTP error 401 if the client is not allowed
|
||||
*
|
||||
* @access public
|
||||
* @param array $users Map of username/password
|
||||
*/
|
||||
public function authentication(array $users)
|
||||
{
|
||||
// OVH workaround
|
||||
if (isset($_SERVER['REMOTE_USER'])) {
|
||||
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['REMOTE_USER'], 6)));
|
||||
}
|
||||
|
||||
if (! isset($_SERVER['PHP_AUTH_USER']) ||
|
||||
! isset($users[$_SERVER['PHP_AUTH_USER']]) ||
|
||||
$users[$_SERVER['PHP_AUTH_USER']] !== $_SERVER['PHP_AUTH_PW']) {
|
||||
|
||||
header('WWW-Authenticate: Basic realm="JsonRPC"');
|
||||
header('Content-Type: application/json');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
echo '["Authentication failed"]';
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new procedure
|
||||
*
|
||||
* @access public
|
||||
* @param string $name Procedure name
|
||||
* @param closure $callback Callback
|
||||
*/
|
||||
public function register($name, Closure $callback)
|
||||
{
|
||||
self::$procedures[$name] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a procedure
|
||||
*
|
||||
* @access public
|
||||
* @param string $name Procedure name
|
||||
*/
|
||||
public function unregister($name)
|
||||
{
|
||||
if (isset(self::$procedures[$name])) {
|
||||
unset(self::$procedures[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister all procedures
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function unregisterAll()
|
||||
{
|
||||
self::$procedures = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the response to the client
|
||||
*
|
||||
* @access public
|
||||
* @param array $data Data to send to the client
|
||||
* @param array $payload Incoming data
|
||||
* @return string
|
||||
*/
|
||||
public function getResponse(array $data, array $payload = array())
|
||||
{
|
||||
if (! array_key_exists('id', $payload)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'jsonrpc' => '2.0',
|
||||
'id' => $payload['id']
|
||||
);
|
||||
|
||||
$response = array_merge($response, $data);
|
||||
|
||||
@header('Content-Type: application/json');
|
||||
return json_encode($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map arguments to the procedure
|
||||
*
|
||||
* @access public
|
||||
* @param array $request_params Incoming arguments
|
||||
* @param array $method_params Procedure arguments
|
||||
* @param array $params Arguments to pass to the callback
|
||||
* @return bool
|
||||
*/
|
||||
public function mapParameters(array $request_params, array $method_params, array &$params)
|
||||
{
|
||||
// Positional parameters
|
||||
if (array_keys($request_params) === range(0, count($request_params) - 1)) {
|
||||
|
||||
if (count($request_params) !== count($method_params)) return false;
|
||||
$params = $request_params;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Named parameters
|
||||
foreach ($method_params as $p) {
|
||||
|
||||
$name = $p->getName();
|
||||
|
||||
if (isset($request_params[$name])) {
|
||||
$params[$name] = $request_params[$name];
|
||||
}
|
||||
else if ($p->isDefaultValueAvailable()) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse incoming requests
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
// Parse payload
|
||||
if (empty($this->payload)) {
|
||||
$this->payload = file_get_contents('php://input');
|
||||
}
|
||||
|
||||
if (is_string($this->payload)) {
|
||||
$this->payload = json_decode($this->payload, true);
|
||||
}
|
||||
|
||||
// Check JSON format
|
||||
if (! is_array($this->payload)) {
|
||||
|
||||
return $this->getResponse(array(
|
||||
'error' => array(
|
||||
'code' => -32700,
|
||||
'message' => 'Parse error'
|
||||
)),
|
||||
array('id' => null)
|
||||
);
|
||||
}
|
||||
|
||||
// Handle batch request
|
||||
if (array_keys($this->payload) === range(0, count($this->payload) - 1)) {
|
||||
|
||||
$responses = array();
|
||||
|
||||
foreach ($this->payload as $payload) {
|
||||
|
||||
if (! is_array($payload)) {
|
||||
|
||||
$responses[] = $this->getResponse(array(
|
||||
'error' => array(
|
||||
'code' => -32600,
|
||||
'message' => 'Invalid Request'
|
||||
)),
|
||||
array('id' => null)
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
||||
$server = new Server($payload);
|
||||
$response = $server->execute();
|
||||
|
||||
if ($response) $responses[] = $response;
|
||||
}
|
||||
}
|
||||
|
||||
return empty($responses) ? '' : '['.implode(',', $responses).']';
|
||||
}
|
||||
|
||||
// Check JSON-RPC format
|
||||
if (! isset($this->payload['jsonrpc']) ||
|
||||
! isset($this->payload['method']) ||
|
||||
! is_string($this->payload['method']) ||
|
||||
$this->payload['jsonrpc'] !== '2.0' ||
|
||||
(isset($this->payload['params']) && ! is_array($this->payload['params']))) {
|
||||
|
||||
return $this->getResponse(array(
|
||||
'error' => array(
|
||||
'code' => -32600,
|
||||
'message' => 'Invalid Request'
|
||||
)),
|
||||
array('id' => null)
|
||||
);
|
||||
}
|
||||
|
||||
// Procedure not found
|
||||
if (! isset(self::$procedures[$this->payload['method']])) {
|
||||
|
||||
return $this->getResponse(array(
|
||||
'error' => array(
|
||||
'code' => -32601,
|
||||
'message' => 'Method not found'
|
||||
)),
|
||||
$this->payload
|
||||
);
|
||||
}
|
||||
|
||||
$callback = self::$procedures[$this->payload['method']];
|
||||
$params = array();
|
||||
|
||||
$reflection = new ReflectionFunction($callback);
|
||||
|
||||
if (isset($this->payload['params'])) {
|
||||
|
||||
$parameters = $reflection->getParameters();
|
||||
|
||||
if (! $this->mapParameters($this->payload['params'], $parameters, $params)) {
|
||||
|
||||
return $this->getResponse(array(
|
||||
'error' => array(
|
||||
'code' => -32602,
|
||||
'message' => 'Invalid params'
|
||||
)),
|
||||
$this->payload
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$result = $reflection->invokeArgs($params);
|
||||
|
||||
return $this->getResponse(array('result' => $result), $this->payload);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user