<?php namespace WPDesk\HttpClient\Curl; use WPDesk\HttpClient\HttpClient; use WPDesk\HttpClient\HttpClientResponse; use WPDesk\HttpClient\HttpClientRequestException; class CurlClient implements HttpClient { /** @var resource */ private $curlResource; /** @var string|null|boolean */ private $rawResponse; /** @var int */ private $httpResponseCode; /** * @param string $url * @param string $body * @param array $headers * @param int $timeOut * @return HttpClientResponse * @throws HttpClientRequestException */ public function get($url, $body, array $headers, $timeOut) { return $this->send($url, 'GET', $body, $headers, $timeOut); } /** * @param string $url * @param string $method * @param string $body * @param array $headers * @param int $timeOut * @return HttpClientResponse * @throws HttpClientRequestException */ public function send($url, $method, $body, array $headers, $timeOut) { $this->initResource(); try { $this->prepareConnection($url, $method, $body, $headers, $timeOut); $this->sendRequest(); $this->throwExceptionIfError(); $this->closeConnection(); return $this->prepareResponse(); } catch (\Exception $e) { $this->closeConnection(); if ($e instanceof HttpClientRequestException) { throw $e; } throw CurlExceptionFactory::createDefaultException($e->getMessage(), $e->getCode(), $e); } } private function initResource() { $this->curlResource = curl_init(); } /** * Opens a new curl connection. * * @param string $url The endpoint to send the request to. * @param string $method The request method. * @param string $body The body of the request. * @param array $headers The request headers. * @param int $timeOut The timeout in seconds for the request. */ private function prepareConnection($url, $method, $body, array $headers, $timeOut) { $options = [ CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => $this->compileRequestHeaders($headers), CURLOPT_URL => $url, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => $timeOut, CURLOPT_RETURNTRANSFER => true, // Return response as string CURLOPT_HEADER => true, // Enable header processing CURLOPT_SSL_VERIFYHOST => 2, CURLOPT_SSL_VERIFYPEER => true, //CURLOPT_CAINFO => __DIR__ . '/certs/DigiCertHighAssuranceEVRootCA.pem', ]; if ($method !== "GET") { $options[CURLOPT_POSTFIELDS] = $body; } curl_setopt_array($this->curlResource, $options); } /** * Compiles the request headers into a curl-friendly format. * * @param array $headers The request headers. * * @return array */ private function compileRequestHeaders(array $headers) { $return = []; foreach ($headers as $key => $value) { $return[] = $key . ': ' . $value; } return $return; } /** * Send the request and get the raw response from curl */ private function sendRequest() { $this->rawResponse = curl_exec($this->curlResource); $this->httpResponseCode = $this->getHttpResponseCode(); } /** @return int */ private function getHttpResponseCode() { return intval(curl_getinfo($this->curlResource, CURLINFO_HTTP_CODE)); } private function throwExceptionIfError() { $errorNumber = curl_errno($this->curlResource); if ($errorNumber === 0) { return; } $errorMessage = curl_error($this->curlResource); throw CurlExceptionFactory::createCurlException($errorMessage, $errorNumber); } /** * Closes an existing curl connection */ private function closeConnection() { curl_close($this->curlResource); $this->curlResource = null; } private function prepareResponse() { list($rawHeaders, $rawBody) = $this->extractResponseHeadersAndBody(); return new HttpClientResponse($rawHeaders, $rawBody, $this->httpResponseCode); } /** * Extracts the headers and the body into a two-part array * * @return array */ private function extractResponseHeadersAndBody() { $parts = explode("\r\n\r\n", $this->rawResponse); $rawBody = array_pop($parts); $rawHeaders = implode("\r\n\r\n", $parts); return [trim($rawHeaders), trim($rawBody)]; } /** * @param string $url * @param string $body * @param array $headers * @param int $timeOut * @return HttpClientResponse * @throws HttpClientRequestException */ public function post($url, $body, array $headers, $timeOut) { return $this->send($url, 'POST', $body, $headers, $timeOut); } /** * @param string $url * @param string $body * @param array $headers * @param int $timeOut * @return HttpClientResponse * @throws HttpClientRequestException */ public function delete($url, $body, array $headers, $timeOut) { return $this->send($url, 'DELETE', $body, $headers, $timeOut); } /** * @param string $url * @param string $body * @param array $headers * @param int $timeOut * @return HttpClientResponse * @throws HttpClientRequestException */ public function put($url, $body, array $headers, $timeOut) { return $this->send($url, 'PUT', $body, $headers, $timeOut); } }