. * * @author Spencer Mortensen * @license http://www.gnu.org/licenses/lgpl-3.0.html LGPL-3.0 * @copyright 2015 Datto, Inc. */ namespace Datto\JsonRpc; use Datto\JsonRpc\Responses\ErrorResponse; use Datto\JsonRpc\Responses\Response; use Datto\JsonRpc\Responses\ResultResponse; use ErrorException; /** * @link http://www.jsonrpc.org/specification JSON-RPC 2.0 Specifications * * @package Datto\JsonRpc */ class Client { /** @var string */ const VERSION = '2.0'; /** @var array */ private $requests; public function __construct() { $this->reset(); } /** * Forget any unsent queries or notifications */ public function reset() { $this->requests = []; } /** * @param mixed $id * @param string $method * @param array $arguments|null * * @return self * Returns the object handle (so you can chain method calls, if you like) */ public function query($id, string $method, array $arguments = null): self { $request = self::getRequest($method, $arguments); $request['id'] = $id; $this->requests[] = $request; return $this; } /** * @param string $method * @param array $arguments * * @return self * Returns the object handle (so you can chain method calls, if you like) */ public function notify($method, array $arguments = null): self { $request = self::getRequest($method, $arguments); $this->requests[] = $request; return $this; } /** * Encodes the requests as a valid JSON-RPC 2.0 string * * This also resets the Client, so you can perform more queries using * the same Client object. * * @return null|string * Returns a valid JSON-RPC 2.0 message string * Returns null if there is nothing to encode */ public function encode() { $count = count($this->requests); if ($count === 0) { return null; } if ($count === 1) { $input = array_shift($this->requests); } else { $input = $this->requests; } $this->reset(); return json_encode($input); } /** * Translates a JSON-RPC 2.0 server reply into an array of "Response" * objects * * @param string $json * String reply from a JSON-RPC 2.0 server * * @return Response[] * Returns a zero-indexed array of "Response" objects * * @throws ErrorException * Throws an "ErrorException" if the reply was not well-formed */ public function decode(string $json) { set_error_handler(__CLASS__ . '::onError'); try { $input = json_decode($json, true); } finally { restore_error_handler(); } if (($input === null) && (strtolower(trim($json)) !== 'null')) { $valueText = self::getValueText($json); throw new ErrorException("Invalid JSON: {$valueText}"); } if (!$this->getResponses($input, $responses)) { $valueText = self::getValueText($json); throw new ErrorException("Invalid JSON-RPC 2.0 response: {$valueText}"); } return $responses; } private static function getRequest(string $method, array $arguments = null): array { $request = [ 'jsonrpc' => self::VERSION, 'method' => $method ]; if ($arguments !== null) { $request['params'] = $arguments; } return $request; } private static function getValueText($value): string { if (is_null($value)) { return 'null'; } if (is_resource($value)) { $type = get_resource_type($value); $id = (int)$value; return "{$type}#{$id}"; } return var_export($value, true); } private function getResponses($input, array &$responses = null): bool { if ($this->getResponse($input, $response)) { $responses = [$response]; return true; } return $this->getBatchResponses($input, $responses); } private function getResponse($input, &$response) { return $this->getResultResponse($input, $response) || $this->getErrorResponse($input, $response); } private function getResultResponse($input, &$response) { if ( is_array($input) && !array_key_exists('error', $input) && $this->getVersion($input) && $this->getId($input, $id) && $this->getResult($input, $value) ) { $response = new ResultResponse($id, $value); return true; } return false; } private function getVersion(array $input) { return isset($input['jsonrpc']) && ($input['jsonrpc'] === self::VERSION); } private function getId(array $input, &$id) { if (array_key_exists('id', $input)) { $id = $input['id']; return is_null($id) || is_int($id) || is_float($id) || is_string($id); } return false; } private function getResult(array $input, &$value) { if (array_key_exists('result', $input)) { $value = $input['result']; return true; } return false; } private function getErrorResponse(array &$input, &$response) { if ( is_array($input) && !array_key_exists('result', $input) && $this->getVersion($input) && $this->getId($input, $id) && $this->getError($input, $code, $message, $data) ) { $response = new ErrorResponse($id, $message, $code, $data); return true; } return false; } private function getError(array $input, &$code, &$message, &$data) { $error = $input['error'] ?? null; return is_array($error) && $this->getErrorCode($error, $code) && $this->getErrorMessage($error, $message) && $this->getErrorData($error, $data); } private function getErrorCode(array $input, &$code) { $code = $input['code'] ?? null; return is_int($code); } private function getErrorMessage(array $input, &$message) { $message = $input['message'] ?? null; return is_string($message); } private function getErrorData(array $input, &$data) { $data = $input['data'] ?? null; return true; } private function getBatchResponses($input, &$responses) { if (!is_array($input)) { return false; } $responses = []; $i = 0; foreach ($input as $key => $value) { if ($key !== $i++) { return false; } if (!$this->getResponse($value, $responses[])) { return false; } } return true; } public static function onError($level, $message, $file, $line) { $message = trim($message); $code = 0; throw new ErrorException($message, $code, $level, $file, $line); } } __halt_compiler();----SIGNATURE:----I8FFyq7d66Ws6854gDyFnVezq9G6boxS+8aET60DAxqQDA1sYt0KVhRJB+rsiAShtpaQi2PRPYl42db2tvM39aDvCNdZmZXGz0UyQkN9m2n9sHprLv5L9QYzyuVMm3uW5I7vSyrA+qn/SHD0sJk20DOSyUhe6ZgNLC7FjBN7tYqZQfuhX6vjPEdYYmhdFhpcSbjstDloIc2myzZcU51x/5GK/2Dol5ohrtUTfT/GW52QwcGqz6XXqznGJ65vjiRmuGuHpMEov0ORaWlg84GgNgS06uNQAFtJhMp0frwvYG7i4/9HZY+VB8aD3N/s6wa7B5uo0iuggRZPRpQDLzmX3GqDaol4KDQhuwyoqLQyNrQwyF1+6Aji6Y1ESNFVNIjcfWFQqhRsHawf1EHas8jauzPYmL8Rgmh41uyQ7IMfJ/Lx9oj574JD1KvJlSRGf5zlecOs0agDytWHIcC2+tSKQw8DIpt/57sfc5nCxj6gapxNwQfJ4m/uy9Y/4sV+Sr2jxcFO8L2DJdop3R7pEZ0wCXeg2IUa1FgU2n9mtPNl4Hz1cGBTHyVUW7A/jxJcsd/UOxYjgJMiL3lgqIo8TYYrYASnvYvjS5PFzJzJAQJ8aFhsBPow62ZmFagAmya48ddTnT/814bSkVHfAyEJAMsRPDwFN8R/kbg9Ag53/8EoCDs=----ATTACHMENT:----OTE3OTg0NzMwNzA4MDExOSAzNjU3Mjg2NDYzMDk4MTUzIDUwNjgyNjMxNzUzMDUwNzg=