You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
6.4 KiB
PHP

<?php
namespace qcloudcos;
class HttpRequest {
public $timeoutMs; // int: the maximum number of milliseconds to perform this request.
public $url; // string: the url this request will be sent to.
public $method; // string: POST or GET.
public $customHeaders; // array: custom modified, removed and added headers.
public $dataToPost; // array: the data to post.
public $userData; // any: user custom data.
}
class HttpResponse {
public $curlErrorCode; // int: curl last error code.
public $curlErrorMessage; // string: curl last error message.
public $statusCode; // int: http status code.
public $headers; // array: response headers.
public $body; // string: response body.
}
// A simple wrapper for libcurl using multi interface to do transfers in parallel.
class LibcurlWrapper {
private $sequence; // integer: sequence id for each request.
private $curlMultiHandle; // curl handle: curl multi handle.
private $curlHandleInfo; // array: array of active curl handle.
private $idleCurlHandle; // array: idle curl handle which can be reused.
public function __construct() {
$this->sequence = 0;
$this->curlMultiHandle = curl_multi_init();
$this->idleCurlHandle = array();
}
public function __destruct() {
curl_multi_close($this->curlMultiHandle);
foreach ($this->idleCurlHandle as $handle) {
curl_close($handle);
}
$this->idleCurlHandle = array();
}
public function startSendingRequest($httpRequest, $done) {
$this->sequence += 1;
if (count($this->idleCurlHandle) !== 0) {
$curlHandle = array_pop($this->idleCurlHandle);
} else {
$curlHandle = curl_init();
if ($curlHandle === false) {
return false;
}
}
curl_setopt($curlHandle, CURLOPT_TIMEOUT_MS, $httpRequest->timeoutMs);
curl_setopt($curlHandle, CURLOPT_URL, $httpRequest->url);
curl_setopt($curlHandle, CURLOPT_HEADER, 1);
curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1);
$headers = $httpRequest->customHeaders;
array_push($headers, 'User-Agent:'.Conf::getUserAgent());
if ($httpRequest->method === 'POST') {
if (defined('CURLOPT_SAFE_UPLOAD')) {
curl_setopt($curlHandle, CURLOPT_SAFE_UPLOAD, true);
}
curl_setopt($curlHandle, CURLOPT_POST, true);
$arr = buildCustomPostFields($httpRequest->dataToPost);
array_push($headers, 'Expect: 100-continue');
array_push($headers, 'Content-Type: multipart/form-data; boundary=' . $arr[0]);
curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $arr[1]);
}
curl_setopt($curlHandle, CURLOPT_HTTPHEADER, $headers);
curl_multi_add_handle($this->curlMultiHandle, $curlHandle);
$this->curlHandleInfo[$this->sequence]['handle'] = $curlHandle;
$this->curlHandleInfo[$this->sequence]['done'] = $done;
$this->curlHandleInfo[$this->sequence]['request'] = $httpRequest;
}
public function performSendingRequest() {
for (;;) {
$active = null;
do {
$mrc = curl_multi_exec($this->curlMultiHandle, $active);
$info = curl_multi_info_read($this->curlMultiHandle);
if ($info !== false) {
$this->processResult($info);
}
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($this->curlMultiHandle) == -1) {
usleep(1);
}
do {
$mrc = curl_multi_exec($this->curlMultiHandle, $active);
$info = curl_multi_info_read($this->curlMultiHandle);
if ($info !== false) {
$this->processResult($info);
}
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
if (count($this->curlHandleInfo) == 0) {
break;
}
}
}
private function processResult($info) {
$result = $info['result'];
$handle = $info['handle'];
$sequence = 0;
foreach ($this->curlHandleInfo as $key => $info) {
if ($info['handle'] === $handle) {
$sequence = $key;
break;
}
}
$request = $this->curlHandleInfo[$sequence]['request'];
$done = $this->curlHandleInfo[$sequence]['done'];
$response = new HttpResponse();
if ($result !== CURLE_OK) {
$response->curlErrorCode = $result;
$response->curlErrorMessage = curl_error($handle);
call_user_func($done, $request, $response);
} else {
$responseStr = curl_multi_getcontent($handle);
$headerSize = curl_getinfo($handle, CURLINFO_HEADER_SIZE);
$headerStr = substr($responseStr, 0, $headerSize);
$body = substr($responseStr, $headerSize);
$response->curlErrorCode = curl_errno($handle);
$response->curlErrorMessage = curl_error($handle);
$response->statusCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
$headLines = explode("\r\n", $headerStr);
foreach ($headLines as $head) {
$arr = explode(':', $head);
if (count($arr) >= 2) {
$response->headers[trim($arr[0])] = trim($arr[1]);
}
}
$response->body = $body;
call_user_func($done, $request, $response);
}
unset($this->curlHandleInfo[$sequence]);
curl_multi_remove_handle($this->curlMultiHandle, $handle);
array_push($this->idleCurlHandle, $handle);
}
private function resetCurl($handle) {
if (function_exists('curl_reset')) {
curl_reset($handle);
} else {
curl_setopt($handler, CURLOPT_URL, '');
curl_setopt($handler, CURLOPT_HTTPHEADER, array());
curl_setopt($handler, CURLOPT_POSTFIELDS, array());
curl_setopt($handler, CURLOPT_TIMEOUT, 0);
curl_setopt($handler, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($handler, CURLOPT_SSL_VERIFYHOST, 0);
}
}
}