{@inheritdoc}

Based on https://www.onlineaspect.com/2009/01/26/how-to-use-curl_multi-without-blocking/
197295
public function validate(array $urls)
    {
        if (!$this->options['enabled']) {
            return;
        }

        $master = curl_multi_init();
        $handlers = [];

        // Batch size can't be larger then number of urls
        $batchSize = min(count($urls), $this->options['batch_size']);
        for ($i = 0; $i < $batchSize; ++$i) {
            curl_multi_add_handle($master, $this->createCurlHandlerForUrl($urls[$i], $handlers));
        }

        do {
            while (($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM);

            if ($execrun != CURLM_OK) {
                break;
            }

            while ($done = curl_multi_info_read($master)) {
                $handler = $done['handle'];

                $this->doValidate($handlers[(int)$handler], $handler);

                if ($i < count($urls)) {
                    curl_multi_add_handle($master, $this->createCurlHandlerForUrl($urls[$i], $handlers));
                    ++$i;
                }

                curl_multi_remove_handle($master, $handler);
                curl_close($handler);
            }
        } while ($running);

        curl_multi_close($master);
    }
1189850
public function send()
    {
        $curl = curl_init();

        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HEADER, false);

        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
        curl_setopt($curl, CURLOPT_URL, $this->url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, array());
        curl_setopt($curl, CURLOPT_POSTFIELDS, null);

        curl_setopt($curl, CURLOPT_TIMEOUT, $this->timeout);
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 0 < $this->maxRedirects);
        curl_setopt($curl, CURLOPT_MAXREDIRS, $this->maxRedirects);
        curl_setopt($curl, CURLOPT_FAILONERROR, !$this->ignoreErrors);

        $data = curl_exec($curl);
        if (false === $data) {
            $errorMsg = curl_error($curl);
            $errorNo = curl_errno($curl);

            throw new \RuntimeException($errorMsg, $errorNo);
        }

        $code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        if ((200 > $code || $code >= 300) && $code !== 304) {
            throw new \RuntimeException('Url '.$this->url.' returned invalid code '.$code);
        }

        curl_close($curl);

        return self::getLastResponse($data);
    }
382133
function paypal_curl($params = array()) {
    foreach ($params as $name => $value) {
      $this->setParam($name, $value);
    }
  }
1044151
protected function callMulti($handler)
    {
        $running = null;

        do {
            $stat = curl_multi_exec($handler, $running);
        } while ($stat === CURLM_CALL_MULTI_PERFORM);
        if (!$running || $stat !== CURLM_OK) {
            throw new \RuntimeException('failed to initialized cURL');
        }

        do {
            curl_multi_select($handler, $this->timeout);
            do {
                $stat = curl_multi_exec($handler, $running);
            } while ($stat === CURLM_CALL_MULTI_PERFORM);
            do {
                if ($read = curl_multi_info_read($handler, $remains)) {
                    $response = curl_multi_getcontent($read['handle']);

                    if ($response === false) {
                        $info = curl_getinfo($read['handle']);
                        throw new \RuntimeException("error: {$info['url']}: {$info['http_code']}");
                    }
                    curl_multi_remove_handle($handler, $read['handle']);
                    curl_close($read['handle']);
                }
            } while ($remains);
        } while ($running);
        curl_multi_close($handler);
    }
887734
protected static function curl_multi_exec($urls)
    {
        $nodes = [];
        /* @var $url CurlTrait */
        foreach ($urls as $url) {
            $ch = curl_init();
            $nodes[] = ['ch' => $ch, 'url' => $url];

            curl_setopt_array($ch, $url->getOptions());
        }

        $mh = curl_multi_init();
        foreach ($nodes as $node) {
            curl_multi_add_handle($mh, $node['ch']);
        }

        //execute the handles
        do {
            curl_multi_exec($mh, $running);
            curl_multi_select($mh);
        } while ($running > 0);

        foreach ($nodes as $node) {
            /* @var $url Curl */
            $url = $node['url'];

            $ch = $node['ch'];

            $url->_content = curl_multi_getcontent($ch);

            $url->_errorCode = curl_errno($ch);
            if (!empty($url->_errorCode)) {
                $url->_errorMessage = curl_error($ch);
            }
            $url->_info = curl_getinfo($ch);
        }

        //close the handles
        foreach ($nodes as $node) {
            curl_multi_remove_handle($mh, $node['ch']);
        }
        curl_multi_close($mh);
    }
183226
public function initialize()
    {
        if ($this->isInitialized())
        {
            $this->close();
        }

        if ( ! ($this->curl = curl_init()))
        {
            throw new CurlException('Could not initialize a cURL resource');
        }

        return true;
    }
43351
public function push(): array
    {
        $responseCollection = [];

        if (!$this->curlMultiHandle) {
            $this->curlMultiHandle = curl_multi_init();

            if (!defined('CURLPIPE_MULTIPLEX')) {
                define('CURLPIPE_MULTIPLEX', 2);
            }

            curl_multi_setopt($this->curlMultiHandle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
            curl_multi_setopt($this->curlMultiHandle, CURLMOPT_MAX_HOST_CONNECTIONS, $this->maxConcurrentConnections);
        }

        $mh = $this->curlMultiHandle;

        $i = 0;
        while (!empty($this->notifications) && $i++ < $this->nbConcurrentRequests) {
            $notification = array_pop($this->notifications);
            curl_multi_add_handle($mh, $this->prepareHandle($notification));
        }

        // Clear out curl handle buffer
        do {
            $execrun = curl_multi_exec($mh, $running);
        } while ($execrun === CURLM_CALL_MULTI_PERFORM);

        // Continue processing while we have active curl handles
        while ($running > 0 && $execrun === CURLM_OK) {
            // Block until data is available
            $select_fd = curl_multi_select($mh);
            // If select returns -1 while running, wait 250 microseconds before continuing
            // Using curl_multi_timeout would be better but it isn't available in PHP yet
            // https://php.net/manual/en/function.curl-multi-select.php#115381
            if ($running && $select_fd === -1) {
                usleep(250);
            }

            // Continue to wait for more data if needed
            do {
                $execrun = curl_multi_exec($mh, $running);
            } while ($execrun === CURLM_CALL_MULTI_PERFORM);

            // Start reading results
            while ($done = curl_multi_info_read($mh)) {
                $handle = $done['handle'];

                $result = curl_multi_getcontent($handle);

                // find out which token the response is about
                $token = curl_getinfo($handle, CURLINFO_PRIVATE);

                $responseParts = explode("\r\n\r\n", $result, 2);
                $headers = '';
                $body = '';
                if (isset($responseParts[0])) {
                    $headers = $responseParts[0];
                }
                if (isset($responseParts[1])) {
                    $body = $responseParts[1];
                }

                $statusCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
                $responseCollection[] = new Response($statusCode, $headers, (string)$body, $token);
                curl_multi_remove_handle($mh, $handle);
                curl_close($handle);

                if (!empty($this->notifications)) {
                    $notification = array_pop($this->notifications);
                    curl_multi_add_handle($mh, $this->prepareHandle($notification));
                }
            }
        }

        if ($this->autoCloseConnections) {
            curl_multi_close($mh);
            $this->curlMultiHandle = null;
        }

        return $responseCollection;
    }
450774
private function RunRequest()
    {
        $result = curl_exec($this->_curlHandle);
        if ($result === false && curl_errno($this->_curlHandle) != 0) {
            $this->logger->error("cURL error: " . curl_error($this->_curlHandle));
            throw new Exception('cURL error: ' . curl_error($this->_curlHandle));
        }

        $response = new HttpResponse();
        $response->ResponseCode = (int) curl_getinfo($this->_curlHandle, CURLINFO_HTTP_CODE);

        curl_close($this->_curlHandle);

        $explode = explode("\r\n\r\n", $result);

        // multiple query (follow redirect) take only the last request
        $explode = array_slice($explode, sizeof($explode) - 2, 2);

        $response->Headers = explode("\n", implode($explode));
        $response->Body = array_pop($explode);

        return $response;
    }
1145203
private function fetch() {
        if ($this->curl instanceof MultiCurl) {
            $this->curl->complete(function($instance) {
                if ($instance->error) {
                    $this->errors[] = [
                        'errorCode' => $instance->getErrorCode(),
                        'errorMessage' => $instance->getErrorMessage()
                    ];
                } else {
                    $this->headers[] = $instance->getResponseHeaders();
                    $this->body[] = $instance->getResponse();
                }
            });
        } else {
            if ($this->curl->error) {
                $this->errors[] = [
                    'errorCode' => $this->curl->getErrorCode(),
                    'errorMessage' => $this->curl->getErrorMessage()
                ];
            } else {
                $this->headers = $this->curl->getResponseHeaders();
                $this->body = $this->curl->getResponse();
            }
        }

        return $this;
    }
310830
public function process($max = 10)
    {
        $this->_fillup($max);
        curl_multi_exec($this->_curl, $this->_running);

        while ($info = curl_multi_info_read($this->_curl)) {
            $handle = $info['handle'];
            $id = (integer) $handle;

            if (!isset($this->_handles[$id])) {
                continue;
            }

            $meta = [];
            $meta['transfer_stats'] = curl_getinfo($handle);

            if ($info['result'] !== CURLM_OK) {
                $meta['errno'] = $info['result'];
                $meta['error'] = curl_strerror($info['result']);
                throw new NetException($meta['error'], $meta['errno']);
            }

            $socket = $this->_handles[$id]['socket'];

            $mime = curl_getinfo($handle, CURLINFO_CONTENT_TYPE) ?: true;
            $response = $this->_handles[$id]['response'];
            $response->mime($mime);
            $response->stream()->rewind();

            $socket->trigger('complete', $response);
            $this->_results[] = $response;

            curl_multi_remove_handle($this->_curl, $handle);
            curl_close($handle);
            unset($this->_handles[$id]);
        }
    }
1100460
private static function curl($options = array()) {
    $curlOptions = array();
    $curl = curl_init();

    $curlOptions[CURLOPT_URL] = $options["url"];
    $curlOptions[CURLOPT_RETURNTRANSFER] = true;

    if ($options["method"] != "GET") {
      if ($options["method"] != "POST") {
        $curlOptions[CURLOPT_CUSTOMREQUEST] = $options["method"];
      }
      $curlOptions[CURLOPT_POSTFIELDS] = $options["body"];
      $curlOptions[CURLOPT_POST] = true;
    } else {
      $curlOptions[CURLOPT_HTTPGET] = true;
    }

    if (Api::getEnv() == "test") {
      $curlOptions[CURLOPT_VERBOSE] = true;
      $curlOptions[CURLOPT_SSL_VERIFYHOST] = false;
      $curlOptions[CURLOPT_SSL_VERIFYPEER] = false;
    }

    $curlOptions[CURLOPT_HTTPHEADER] = $options["headers"];
    curl_setopt_array($curl, $curlOptions);

    $responseJson = curl_exec($curl);
    $responseStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    $curlErrorCode = curl_errno($curl);
    $curlErrorMessage = curl_error($curl);
    curl_close($curl);

    return array(
      "body" => $responseJson,
      "status" => $responseStatus,
      "errorCode" => $curlErrorCode,
      "errorMessage" => $curlErrorMessage
    );
  }
1124201
public function flush()
    {
        if (!self::$curlHandle) {
            register_shutdown_function(array('Thrift\\Transport\\TCurlClient', 'closeCurlHandle'));
            self::$curlHandle = curl_init();
            curl_setopt(self::$curlHandle, CURLOPT_RETURNTRANSFER, true);
            curl_setopt(self::$curlHandle, CURLOPT_BINARYTRANSFER, true);
            curl_setopt(self::$curlHandle, CURLOPT_USERAGENT, 'PHP/TCurlClient');
            curl_setopt(self::$curlHandle, CURLOPT_CUSTOMREQUEST, 'POST');
            curl_setopt(self::$curlHandle, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt(self::$curlHandle, CURLOPT_MAXREDIRS, 1);
        }
        // God, PHP really has some esoteric ways of doing simple things.
        $host = $this->host_ . ($this->port_ != 80 ? ':' . $this->port_ : '');
        $fullUrl = $this->scheme_ . "://" . $host . $this->uri_;

        $headers = array();
        $defaultHeaders = array('Accept' => 'application/x-thrift',
            'Content-Type' => 'application/x-thrift',
            'Content-Length' => TStringFuncFactory::create()->strlen($this->request_));
        foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) {
            $headers[] = "$key: $value";
        }

        curl_setopt(self::$curlHandle, CURLOPT_HTTPHEADER, $headers);

        if ($this->timeout_ > 0) {
            curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT, $this->timeout_);
        }
        curl_setopt(self::$curlHandle, CURLOPT_POSTFIELDS, $this->request_);
        $this->request_ = '';

        curl_setopt(self::$curlHandle, CURLOPT_URL, $fullUrl);
        $this->response_ = curl_exec(self::$curlHandle);
        $responseError = curl_error(self::$curlHandle);

        $code = curl_getinfo(self::$curlHandle, CURLINFO_HTTP_CODE);

        // Handle non 200 status code / connect failure
        if ($this->response_ === false || $code !== 200) {
            curl_close(self::$curlHandle);
            self::$curlHandle = null;
            $this->response_ = null;
            $error = 'TCurlClient: Could not connect to ' . $fullUrl;
            if ($responseError) {
                $error .= ', ' . $responseError;
            }
            if ($code) {
                $error .= ', HTTP status code: ' . $code;
            }
            throw new TTransportException($error, TTransportException::UNKNOWN);
        }
    }
258078
public function execute(\Closure $callback = null)
    {
        $stacks = $this->buildStacks();

        foreach ($stacks as $requests) {
            foreach ($requests as $request) {
                $status = curl_multi_add_handle($this->handle, $request->getHandle());
                if ($status !== CURLM_OK) {
                    throw new \Exception(sprintf(
                        'Unable to add request to cURL multi handle (code #%u)',
                        $status
                    ));
                }
            }

            $this->dispatch();

            foreach ($requests as $request) {
                $request->setRawResponse(curl_multi_getcontent($request->getHandle()));
                curl_multi_remove_handle($this->handle, $request->getHandle());

                if ($callback !== null) {
                    $callback($request->getResponse());
                }
            }
        }
    }
618021
public function waitForSingleRequest(Request $request)
    {
        $this->executeRequest($request);
        while ($this->multiCurl->getStillRunningRequests() > 0
            && $this->multiCurl->getCurrentExecutionCode() === CURLM_OK
            && in_array($request, $this->runningRequests)
        ) {
            $this->multiCurl->select();
            $this->executeMultiCurl();
        }
        return $this;
    }
721487
private function checkCurlResult($code)
    {
        if ($code != CURLM_OK && $code != CURLM_CALL_MULTI_PERFORM) {
            throw new CurlException(isset($this->multiErrors[$code])
                ? "cURL error: {$code} ({$this->multiErrors[$code][0]}): cURL message: {$this->multiErrors[$code][1]}"
                : 'Unexpected cURL error: ' . $code
            );
        }
    }
273439
public function get($url_mixed, $data = [])
    {
        if (is_array($url_mixed)) {
            $curl_multi = curl_multi_init();
            $this->_multi_parent = true;

            $this->curls = [];

            foreach ($url_mixed as $url) {
                $curl = new self();
                $curl->_multi_child = true;
                $curl->setOpt(CURLOPT_URL, $this->_buildURL($url, $data), $curl->curl);
                $curl->setOpt(CURLOPT_HTTPGET, true);
                $this->_call($this->_before_send, $curl);
                $this->curls[] = $curl;

                $curlm_error_code = curl_multi_add_handle($curl_multi, $curl->curl);
                if (!(CURLM_OK === $curlm_error_code)) {
                    throw new \ErrorException(
                        'cURL multi add handle error: '.
                        curl_multi_strerror($curlm_error_code)
                    );
                }
            }

            foreach ($this->curls as $ch) {
                foreach ($this->_options as $key => $value) {
                    $ch->setOpt($key, $value);
                }
            }

            do {
                $status = curl_multi_exec($curl_multi, $active);
            } while (CURLM_CALL_MULTI_PERFORM === $status || $active);

            foreach ($this->curls as $ch) {
                $this->exec($ch);
            }
        } else {
            $this->setopt(CURLOPT_URL, $this->_buildURL($url_mixed, $data));
            $this->setopt(CURLOPT_HTTPGET, true);

            return $this->exec();
        }

        return null;
    }
636270
public function send ()
    {
        if ($this->_sent) {
            throw new CAS_OutOfSequenceException(
                'Request has already been sent cannot send again.'
            );
        }
        if (!count($this->_requests)) {
            throw new CAS_OutOfSequenceException(
                'At least one request must be added via addRequest() before the multi-request can be sent.'
            );
        }

        $this->_sent = true;

        // Initialize our handles and configure all requests.
        $handles = array();
        $multiHandle = curl_multi_init();
        foreach ($this->_requests as $i => $request) {
            $handle = $request->initAndConfigure();
            curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
            $handles[$i] = $handle;
            curl_multi_add_handle($multiHandle, $handle);
        }

        // Execute the requests in parallel.
        do {
            curl_multi_exec($multiHandle, $running);
        } while ($running > 0);

        // Populate all of the responses or errors back into the request objects.
        foreach ($this->_requests as $i => $request) {
            $buf = curl_multi_getcontent($handles[$i]);
            $request->_storeResponseBody($buf);
            curl_multi_remove_handle($multiHandle, $handles[$i]);
            curl_close($handles[$i]);
        }

        curl_multi_close($multiHandle);
    }