人人商城

libcurl_wrapper.php 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. <?php
  2. namespace qcloudcos;
  3. class HttpRequest {
  4. public $timeoutMs; // int: the maximum number of milliseconds to perform this request.
  5. public $url; // string: the url this request will be sent to.
  6. public $method; // string: POST or GET.
  7. public $customHeaders; // array: custom modified, removed and added headers.
  8. public $dataToPost; // array: the data to post.
  9. public $userData; // any: user custom data.
  10. }
  11. class HttpResponse {
  12. public $curlErrorCode; // int: curl last error code.
  13. public $curlErrorMessage; // string: curl last error message.
  14. public $statusCode; // int: http status code.
  15. public $headers; // array: response headers.
  16. public $body; // string: response body.
  17. }
  18. // A simple wrapper for libcurl using multi interface to do transfers in parallel.
  19. class LibcurlWrapper {
  20. private $curlMultiHandle; // curl handle: curl multi handle.
  21. private $curlHandleInfo; // array: array of active curl handle.
  22. private $idleCurlHandle; // array: idle curl handle which can be reused.
  23. public function __construct() {
  24. $this->curlMultiHandle = curl_multi_init();
  25. $this->idleCurlHandle = array();
  26. }
  27. public function __destruct() {
  28. curl_multi_close($this->curlMultiHandle);
  29. foreach ($this->idleCurlHandle as $handle) {
  30. curl_close($handle);
  31. }
  32. $this->idleCurlHandle = array();
  33. }
  34. public function startSendingRequest($httpRequest, $done) {
  35. if (count($this->idleCurlHandle) !== 0) {
  36. $curlHandle = array_pop($this->idleCurlHandle);
  37. } else {
  38. $curlHandle = curl_init();
  39. if ($curlHandle === false) {
  40. return false;
  41. }
  42. }
  43. curl_setopt($curlHandle, CURLOPT_TIMEOUT_MS, $httpRequest->timeoutMs);
  44. curl_setopt($curlHandle, CURLOPT_URL, $httpRequest->url);
  45. curl_setopt($curlHandle, CURLOPT_HEADER, 1);
  46. curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1);
  47. $headers = $httpRequest->customHeaders;
  48. array_push($headers, 'User-Agent:'.Conf::getUserAgent());
  49. if ($httpRequest->method === 'POST') {
  50. if (defined('CURLOPT_SAFE_UPLOAD')) {
  51. curl_setopt($curlHandle, CURLOPT_SAFE_UPLOAD, true);
  52. }
  53. curl_setopt($curlHandle, CURLOPT_POST, true);
  54. $arr = buildCustomPostFields($httpRequest->dataToPost);
  55. array_push($headers, 'Expect: 100-continue');
  56. array_push($headers, 'Content-Type: multipart/form-data; boundary=' . $arr[0]);
  57. curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $arr[1]);
  58. }
  59. curl_setopt($curlHandle, CURLOPT_HTTPHEADER, $headers);
  60. curl_multi_add_handle($this->curlMultiHandle, $curlHandle);
  61. $this->curlHandleInfo[$curlHandle]['done'] = $done;
  62. $this->curlHandleInfo[$curlHandle]['request'] = $httpRequest;
  63. }
  64. public function performSendingRequest() {
  65. for (;;) {
  66. $active = null;
  67. do {
  68. $mrc = curl_multi_exec($this->curlMultiHandle, $active);
  69. $info = curl_multi_info_read($this->curlMultiHandle);
  70. if ($info !== false) {
  71. $this->processResult($info);
  72. }
  73. } while ($mrc == CURLM_CALL_MULTI_PERFORM);
  74. while ($active && $mrc == CURLM_OK) {
  75. if (curl_multi_select($this->curlMultiHandle) == -1) {
  76. usleep(1);
  77. }
  78. do {
  79. $mrc = curl_multi_exec($this->curlMultiHandle, $active);
  80. $info = curl_multi_info_read($this->curlMultiHandle);
  81. if ($info !== false) {
  82. $this->processResult($info);
  83. }
  84. } while ($mrc == CURLM_CALL_MULTI_PERFORM);
  85. }
  86. if (count($this->curlHandleInfo) == 0) {
  87. break;
  88. }
  89. }
  90. }
  91. private function processResult($info) {
  92. $result = $info['result'];
  93. $handle = $info['handle'];
  94. $request = $this->curlHandleInfo[$handle]['request'];
  95. $done = $this->curlHandleInfo[$handle]['done'];
  96. $response = new HttpResponse();
  97. if ($result !== CURLE_OK) {
  98. $response->curlErrorCode = $result;
  99. $response->curlErrorMessage = curl_error($handle);
  100. call_user_func($done, $request, $response);
  101. } else {
  102. $responseStr = curl_multi_getcontent($handle);
  103. $headerSize = curl_getinfo($handle, CURLINFO_HEADER_SIZE);
  104. $headerStr = substr($responseStr, 0, $headerSize);
  105. $body = substr($responseStr, $headerSize);
  106. $response->curlErrorCode = curl_errno($handle);
  107. $response->curlErrorMessage = curl_error($handle);
  108. $response->statusCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
  109. $headLines = explode("\r\n", $headerStr);
  110. foreach ($headLines as $head) {
  111. $arr = explode(':', $head);
  112. if (count($arr) >= 2) {
  113. $response->headers[trim($arr[0])] = trim($arr[1]);
  114. }
  115. }
  116. $response->body = $body;
  117. call_user_func($done, $request, $response);
  118. }
  119. unset($this->curlHandleInfo[$handle]);
  120. curl_multi_remove_handle($this->curlMultiHandle, $handle);
  121. array_push($this->idleCurlHandle, $handle);
  122. }
  123. private function resetCurl($handle) {
  124. if (function_exists('curl_reset')) {
  125. curl_reset($handle);
  126. } else {
  127. curl_setopt($handler, CURLOPT_URL, '');
  128. curl_setopt($handler, CURLOPT_HTTPHEADER, array());
  129. curl_setopt($handler, CURLOPT_POSTFIELDS, array());
  130. curl_setopt($handler, CURLOPT_TIMEOUT, 0);
  131. curl_setopt($handler, CURLOPT_SSL_VERIFYPEER, false);
  132. curl_setopt($handler, CURLOPT_SSL_VERIFYHOST, 0);
  133. }
  134. }
  135. }