Skip to content

Commit

Permalink
Implemented cURL transport
Browse files Browse the repository at this point in the history
  • Loading branch information
SilverFire committed Jan 26, 2017
1 parent 55f40a4 commit a2a733f
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 6 deletions.
99 changes: 99 additions & 0 deletions src/curl/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,113 @@
namespace hiqdev\hiart\curl;

use hiqdev\hiart\AbstractRequest;
use hiqdev\hiart\RequestErrorException;
use yii\helpers\ArrayHelper;

/**
* Class Request represents request using cURL library
*/
class Request extends AbstractRequest
{
protected $responseClass = Response::class;

/**
* @var array default cURL options
*/
public $defaultOptions = [
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
];

/**
* @param array $options
* @return array|mixed
* @throws RequestErrorException
*/
public function send($options = [])
{
try {
$this->build();

$curl = curl_init($this->getFullUri());
$this->setCurlOptions($curl);
$response = curl_exec($curl);
$info = curl_getinfo($curl);
$error = curl_error($curl);
$errorCode = curl_errno($curl);
curl_close($curl);
} catch (RequestErrorException $e) {
throw $e;
} catch (\Exception $e) {
throw new RequestErrorException($e->getMessage(), $this, $e->getCode(), $e);
}

return new $this->responseClass($this, $response, $info, $error, $errorCode);
}

/**
* @param resource $curl
* @throws RequestErrorException
*/
protected function setCurlOptions($curl)
{
$requestOptions = $this->buildMethodOptions();
$requestOptions[CURLOPT_HTTPHEADER] = $this->buildHeaderLines();

if ($this->getVersion() === '1.1') {
$requestOptions[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
} elseif ($this->getVersion() === '1.0') {
$requestOptions[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
} else {
throw new RequestErrorException('Request version "' . $this->getVersion() . '" is not support by cURL', $this);
}

$options = ArrayHelper::merge($this->defaultOptions, $this->getDb()->config, $requestOptions);
curl_setopt_array($curl, $options);
}

/**
* @return array
*/
protected function buildMethodOptions()
{
$options = [];

if ($this->getMethod() === 'GET') {
return $options;
}

if (!empty($this->getBody())) {
$options[CURLOPT_POSTFIELDS] = $this->getBody();
}

if ($this->getMethod() === 'POST') {
$options[CURLOPT_POST] = true;
} else {
$options[CURLOPT_CUSTOMREQUEST] = $this->getMethod();
}

return $options;
}

/**
* @return array
*/
protected function buildHeaderLines()
{
$result = [];

foreach ($this->getHeaders() as $name => $values) {
$name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $name)));
if (is_string($values)) {
$values = [$values];
}
foreach ($values as $value) {
$result[] = "$name: $value";
}
}

return $result;
}
}
115 changes: 109 additions & 6 deletions src/curl/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,135 @@

namespace hiqdev\hiart\curl;

use hiqdev\hiart\AbstractRequest;
use hiqdev\hiart\AbstractResponse;
use hiqdev\hiart\ResponseErrorException;

/**
* cURL response implementation.
*
* @author Andrii Vasyliev <[email protected]>
* Class Response represents response through cURL library
*/
class Response extends AbstractResponse
{
public function getRawData()
/**
* @var string
*/
protected $rawData;

/**
* @var array[]
*/
protected $headers = [];

/**
* @var string
*/
protected $statusCode;

/**
* @var string
*/
protected $reasonPhrase;

/**
* Response constructor
*
* @param AbstractRequest $request
* @param string $rawBody the raw response, returned by `curl_exec()` method.
* @param array $info the cURL information, returned by `curl_getinfo()` method.
* @param string $error the cURL error message, if present. Empty string otherwise.
* @param int $errorCode the cURL error code, if present. Integer `0` otherwise.
* @throws ResponseErrorException
*/
public function __construct(AbstractRequest $request, $rawBody, $info, $error, $errorCode)
{
$this->request = $request;

$this->checkTransportError($error, $errorCode);

$parsedResponse = $this->parseRawResponse($rawBody, $info);
$this->headers = $parsedResponse['headers'];
$this->statusCode = $parsedResponse['statusCode'];
$this->rawData = $parsedResponse['data'];
$this->reasonPhrase = $parsedResponse['reasonPhrase'];
}

public function getHeader($name)
/**
* @return mixed|string
*/
public function getRawData()
{
return $this->rawData;
}

/**
* @param string $name the header name
* @return array|null
*/
public function getHeader($name)
{
return isset($this->headers[$name]) ? $this->headers[$name] : null;
}

/**
* @inheritdoc
*/
public function getStatusCode()
{

return $this->statusCode;
}

/**
* @inheritdoc
*/
public function getReasonPhrase()
{
return $this->reasonPhrase;
}

/**
* Parses raw response and returns parsed information
*
* @param string $data the raw response
* @param array $info the curl information (result of `gurl_getinfo` call)
* @return array Array with the following keys will be returned:
* - data: string, response data;
* - headers: array, response headers;
* - statusCode: string, the response status-code;
* - reasonPhrase: string, the response reason phrase (OK, NOT FOUND, etc).
*/
protected function parseRawResponse($data, $info)
{
$result = [];

$headerSize = $info['header_size'];
$result['data'] = substr($data, $headerSize);

$rawHeaders = explode("\r\n", substr($data, 0, $headerSize));
// First line is status-code HTTP/1.1 200 OK
list(, $result['statusCode'], $result['reasonPhrase']) = explode(' ', array_shift($rawHeaders), 3);
foreach ($rawHeaders as $line) {
if ($line == '') {
continue;
}

list ($key, $value) = explode(': ', $line);
$result['headers'][$key][] = $value;
}

return $result;
}

/**
* Checks $error and $errorCode for transport errors
*
* @param string $error the cURL error message, if present. Empty string otherwise.
* @param int $errorCode the cURL error code, if present. Integer `0` otherwise.
* @throws ResponseErrorException when the error is present
*/
protected function checkTransportError($error, $errorCode)
{
if ($error !== '' || $errorCode !== 0) {
throw new ResponseErrorException($error, $this, $errorCode);
}
}
}

0 comments on commit a2a733f

Please sign in to comment.