vendor/ezimuel/ringphp/src/Client/CurlHandler.php line 65

Open in your IDE?
  1. <?php
  2. namespace GuzzleHttp\Ring\Client;
  3. use GuzzleHttp\Ring\Future\CompletedFutureArray;
  4. use GuzzleHttp\Ring\Core;
  5. /**
  6.  * HTTP handler that uses cURL easy handles as a transport layer.
  7.  *
  8.  * Requires PHP 5.5+
  9.  *
  10.  * When using the CurlHandler, custom curl options can be specified as an
  11.  * associative array of curl option constants mapping to values in the
  12.  * **curl** key of the "client" key of the request.
  13.  */
  14. class CurlHandler
  15. {
  16.     /** @var callable */
  17.     private $factory;
  18.     /** @var array Array of curl easy handles */
  19.     private $handles = [];
  20.     /** @var array Array of owned curl easy handles */
  21.     private $ownedHandles = [];
  22.     /** @var int Total number of idle handles to keep in cache */
  23.     private $maxHandles;
  24.     /**
  25.      * Accepts an associative array of options:
  26.      *
  27.      * - factory: Optional callable factory used to create cURL handles.
  28.      *   The callable is passed a request hash when invoked, and returns an
  29.      *   array of the curl handle, headers resource, and body resource.
  30.      * - max_handles: Maximum number of idle handles (defaults to 5).
  31.      *
  32.      * @param array $options Array of options to use with the handler
  33.      */
  34.     public function __construct(array $options = [])
  35.     {
  36.         $this->handles $this->ownedHandles = [];
  37.         $this->factory = isset($options['handle_factory'])
  38.             ? $options['handle_factory']
  39.             : new CurlFactory();
  40.         $this->maxHandles = isset($options['max_handles'])
  41.             ? $options['max_handles']
  42.             : 5;
  43.     }
  44.     public function __destruct()
  45.     {
  46.         foreach ($this->handles as $handle) {
  47.             if (is_resource($handle)) {
  48.                 curl_close($handle);
  49.             }
  50.         }
  51.     }
  52.     /**
  53.      * @param array $request
  54.      *
  55.      * @return CompletedFutureArray
  56.      */
  57.     public function __invoke(array $request)
  58.     {
  59.         return new CompletedFutureArray(
  60.             $this->_invokeAsArray($request)
  61.         );
  62.     }
  63.     /**
  64.      * @internal
  65.      *
  66.      * @param array $request
  67.      *
  68.      * @return array
  69.      */
  70.     public function _invokeAsArray(array $request)
  71.     {
  72.         $factory $this->factory;
  73.         // Ensure headers are by reference. They're updated elsewhere.
  74.         $result $factory($request$this->checkoutEasyHandle());
  75.         $h $result[0];
  76.         $hd =& $result[1];
  77.         $bd $result[2];
  78.         Core::doSleep($request);
  79.         curl_exec($h);
  80.         $response = ['transfer_stats' => curl_getinfo($h)];
  81.         $response['curl']['error'] = curl_error($h);
  82.         $response['curl']['errno'] = curl_errno($h);
  83.         $response['transfer_stats'] = array_merge($response['transfer_stats'], $response['curl']);
  84.         $this->releaseEasyHandle($h);
  85.         return CurlFactory::createResponse([$this'_invokeAsArray'], $request$response$hd$bd);
  86.     }
  87.     private function checkoutEasyHandle()
  88.     {
  89.         // Find an unused handle in the cache
  90.         if (false !== ($key array_search(false$this->ownedHandlestrue))) {
  91.             $this->ownedHandles[$key] = true;
  92.             return $this->handles[$key];
  93.         }
  94.         // Add a new handle
  95.         $handle curl_init();
  96.         $id = (int) $handle;
  97.         $this->handles[$id] = $handle;
  98.         $this->ownedHandles[$id] = true;
  99.         return $handle;
  100.     }
  101.     private function releaseEasyHandle($handle)
  102.     {
  103.         $id = (int) $handle;
  104.         if (count($this->ownedHandles) > $this->maxHandles) {
  105.             curl_close($this->handles[$id]);
  106.             unset($this->handles[$id], $this->ownedHandles[$id]);
  107.         } else {
  108.             // curl_reset doesn't clear these out for some reason
  109.             static $unsetValues = [
  110.                 CURLOPT_HEADERFUNCTION   => null,
  111.                 CURLOPT_WRITEFUNCTION    => null,
  112.                 CURLOPT_READFUNCTION     => null,
  113.                 CURLOPT_PROGRESSFUNCTION => null,
  114.             ];
  115.             curl_setopt_array($handle$unsetValues);
  116.             curl_reset($handle);
  117.             $this->ownedHandles[$id] = false;
  118.         }
  119.     }
  120. }