| <?php |
|
|
| namespace JsonRPC; |
|
|
| use Closure; |
| use JsonRPC\Exception\AccessDeniedException; |
| use JsonRPC\Exception\ConnectionFailureException; |
| use JsonRPC\Exception\ServerErrorException; |
|
|
| |
| |
| |
| |
| |
| |
| class HttpClient |
| { |
| |
| |
| |
| |
| |
| |
| protected $url; |
|
|
| |
| |
| |
| |
| |
| |
| protected $timeout = 5; |
|
|
| |
| |
| |
| |
| |
| |
| protected $headers = array( |
| 'User-Agent: JSON-RPC PHP Client <https://github.com/fguillot/JsonRPC>', |
| 'Content-Type: application/json', |
| 'Accept: application/json', |
| 'Connection: close', |
| ); |
|
|
| |
| |
| |
| |
| |
| |
| protected $username; |
|
|
| |
| |
| |
| |
| |
| |
| protected $password; |
|
|
| |
| |
| |
| |
| |
| |
| protected $debug = false; |
|
|
| |
| |
| |
| |
| |
| |
| protected $cookies = array(); |
|
|
| |
| |
| |
| |
| |
| |
| protected $verifySslCertificate = true; |
|
|
| |
| |
| |
| |
| |
| |
| protected $sslLocalCert; |
|
|
| |
| |
| |
| |
| |
| |
| protected $beforeRequest; |
|
|
| |
| |
| |
| |
| |
| |
| public function __construct($url = '') |
| { |
| $this->url = $url; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public function withUrl($url) |
| { |
| $this->url = $url; |
| return $this; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public function withUsername($username) |
| { |
| $this->username = $username; |
| return $this; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public function withPassword($password) |
| { |
| $this->password = $password; |
| return $this; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public function withTimeout($timeout) |
| { |
| $this->timeout = $timeout; |
| return $this; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public function withHeaders(array $headers) |
| { |
| $this->headers = array_merge($this->headers, $headers); |
| return $this; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public function withCookies(array $cookies, $replace = false) |
| { |
| if ($replace) { |
| $this->cookies = $cookies; |
| } else { |
| $this->cookies = array_merge($this->cookies, $cookies); |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| public function withDebug() |
| { |
| $this->debug = true; |
| return $this; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| public function withoutSslVerification() |
| { |
| $this->verifySslCertificate = false; |
| return $this; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| public function withSslLocalCert($path) |
| { |
| $this->sslLocalCert = $path; |
| return $this; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| public function withBeforeRequestCallback(Closure $closure) |
| { |
| $this->beforeRequest = $closure; |
| return $this; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| public function getCookies() |
| { |
| return $this->cookies; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| public function execute($payload, array $headers = array()) |
| { |
| if (is_callable($this->beforeRequest)) { |
| call_user_func_array($this->beforeRequest, array($this, $payload, $headers)); |
| } |
|
|
| if ($this->isCurlLoaded()) { |
| $ch = curl_init(); |
| $requestHeaders = $this->buildHeaders($headers); |
| $headers = array(); |
| curl_setopt_array($ch, array( |
| CURLOPT_URL => trim($this->url), |
| CURLOPT_RETURNTRANSFER => true, |
| CURLOPT_CONNECTTIMEOUT => $this->timeout, |
| CURLOPT_MAXREDIRS => 2, |
| CURLOPT_SSL_VERIFYPEER => $this->verifySslCertificate, |
| CURLOPT_POST => true, |
| CURLOPT_POSTFIELDS => $payload, |
| CURLOPT_HTTPHEADER => $requestHeaders, |
| CURLOPT_HEADERFUNCTION => function ($curl, $header) use (&$headers) { |
| $headers[] = $header; |
| return strlen($header); |
| } |
| )); |
| if ($this->sslLocalCert !== null) { |
| curl_setopt($ch, CURLOPT_CAINFO, $this->sslLocalCert); |
| } |
| $response = curl_exec($ch); |
| curl_close($ch); |
| if ($response !== false) { |
| $response = json_decode($response, true); |
| } else { |
| throw new ConnectionFailureException('Unable to establish a connection'); |
| } |
| } else { |
| $stream = fopen(trim($this->url), 'r', false, $this->buildContext($payload, $headers)); |
|
|
| if (! is_resource($stream)) { |
| throw new ConnectionFailureException('Unable to establish a connection'); |
| } |
|
|
| $metadata = stream_get_meta_data($stream); |
| $headers = $metadata['wrapper_data']; |
| $response = json_decode(stream_get_contents($stream), true); |
|
|
| fclose($stream); |
| } |
|
|
| if ($this->debug) { |
| error_log('==> Request: '.PHP_EOL.(is_string($payload) ? $payload : json_encode($payload, JSON_PRETTY_PRINT))); |
| error_log('==> Headers: '.PHP_EOL.var_export($headers, true)); |
| error_log('==> Response: '.PHP_EOL.json_encode($response, JSON_PRETTY_PRINT)); |
| } |
|
|
| $this->handleExceptions($headers); |
| $this->parseCookies($headers); |
|
|
| return $response; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| protected function buildContext($payload, array $headers = array()) |
| { |
| $headers = $this->buildHeaders($headers); |
|
|
| $options = array( |
| 'http' => array( |
| 'method' => 'POST', |
| 'protocol_version' => 1.1, |
| 'timeout' => $this->timeout, |
| 'max_redirects' => 2, |
| 'header' => implode("\r\n", $headers), |
| 'content' => $payload, |
| 'ignore_errors' => true, |
| ), |
| 'ssl' => array( |
| 'verify_peer' => $this->verifySslCertificate, |
| 'verify_peer_name' => $this->verifySslCertificate, |
| ) |
| ); |
|
|
| if ($this->sslLocalCert !== null) { |
| $options['ssl']['local_cert'] = $this->sslLocalCert; |
| } |
|
|
| return stream_context_create($options); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| protected function parseCookies(array $headers) |
| { |
| foreach ($headers as $header) { |
| $pos = stripos($header, 'Set-Cookie:'); |
|
|
| if ($pos !== false) { |
| $cookies = explode(';', substr($header, $pos + 11)); |
|
|
| foreach ($cookies as $cookie) { |
| $item = explode('=', $cookie); |
|
|
| if (count($item) === 2) { |
| $name = trim($item[0]); |
| $value = $item[1]; |
| $this->cookies[$name] = $value; |
| } |
| } |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| public function handleExceptions(array $headers) |
| { |
| $exceptions = array( |
| '401' => '\JsonRPC\Exception\AccessDeniedException', |
| '403' => '\JsonRPC\Exception\AccessDeniedException', |
| '404' => '\JsonRPC\Exception\ConnectionFailureException', |
| '500' => '\JsonRPC\Exception\ServerErrorException', |
| ); |
|
|
| foreach ($headers as $header) { |
| foreach ($exceptions as $code => $exception) { |
| if (strpos($header, 'HTTP/1.0 '.$code) !== false || strpos($header, 'HTTP/1.1 '.$code) !== false) { |
| throw new $exception('Response: '.$header); |
| } |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| protected function isCurlLoaded() |
| { |
| return extension_loaded('curl'); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| protected function buildHeaders(array $headers) |
| { |
| $headers = array_merge($this->headers, $headers); |
|
|
| if (!empty($this->username) && !empty($this->password)) { |
| $headers[] = 'Authorization: Basic ' . base64_encode($this->username . ':' . $this->password); |
| } |
|
|
| if (!empty($this->cookies)) { |
| $cookies = array(); |
|
|
| foreach ($this->cookies as $key => $value) { |
| $cookies[] = $key . '=' . $value; |
| } |
|
|
| $headers[] = 'Cookie: ' . implode('; ', $cookies); |
| } |
| return $headers; |
| } |
| } |
|
|