Skip to content

Commit

Permalink
moved curl transport here from yii2-hiart-curl which will be deleted
Browse files Browse the repository at this point in the history
  • Loading branch information
hiqsol committed Mar 30, 2017
1 parent 3a8d8ca commit 7bfbc4d
Show file tree
Hide file tree
Showing 2 changed files with 286 additions and 0 deletions.
128 changes: 128 additions & 0 deletions src/curl/Request.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?php
/**
* ActiveRecord for API
*
* @link https://github.com/hiqdev/yii2-hiart
* @package yii2-hiart
* @license BSD-3-Clause
* @copyright Copyright (c) 2017, HiQDev (http://hiqdev.com/)
*/

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

$curl = curl_init($this->getFullUri());
curl_setopt_array($curl, $this->prepareCurlOptions($options));
$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 array $options
* @throws RequestErrorException
* @return array
*/
protected function prepareCurlOptions($options)
{
$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);
}

return ArrayHelper::merge($this->defaultOptions, $this->getDb()->config, $requestOptions, $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;
}

public static function isSupported()
{
return function_exists('curl_version');
}
}
158 changes: 158 additions & 0 deletions src/curl/Response.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
<?php
/**
* ActiveRecord for API
*
* @link https://github.com/hiqdev/yii2-hiart
* @package yii2-hiart
* @license BSD-3-Clause
* @copyright Copyright (c) 2017, HiQDev (http://hiqdev.com/)
*/

namespace hiqdev\hiart\curl;

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

/**
* Class Response represents response through cURL library.
*/
class Response extends AbstractResponse
{
/**
* @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'];
}

/**
* @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);
}
}

/**
* Returns array of all headers.
* Key - Header name
* Value - array of header values. For example:.
*
* ```php
* ['Location' => ['http://example.com'], 'Expires' => ['Thu, 01 Jan 1970 00:00:00 GMT']]
* @return array
*/
public function getHeaders()
{
return $this->headers;
}
}

0 comments on commit 7bfbc4d

Please sign in to comment.