Ejemplo n.º 1
0
 /**
  * Execute multi curl of this Streamer
  *
  * @return boolean
  * @throws Exception
  */
 public function exec()
 {
     if (!$this->isResource()) {
         throw new Exception("Is not a valid cURL Multi Handle resource", Exception::INVALID_MULTI_CURL);
     }
     if (empty($this->streams)) {
         throw new Exception("Pull of streams is empty", Exception::PULL_IS_EMPTY);
     }
     $running = $messages = 0;
     do {
         // executing...
         if (($error = curl_multi_exec($this->curl, $running)) != 0) {
             throw new Exception(curl_multi_strerror($error), Exception::MULTI_CURL_ERROR);
         }
         // we have some completed streams in this iteration
         do {
             if ($read = curl_multi_info_read($this->curl, $messages)) {
                 $handle = $read['handle'];
                 /** @var $stream Stream */
                 $stream = $this->streams[(int) $handle];
                 $stream->setResponse($read['result'], curl_multi_getcontent($handle));
             }
         } while ($messages);
         // in god we trust...
         usleep(1000);
     } while ($running);
     // close descriptors
     $this->closeResource();
     return $this;
 }
 public function get($url_mixed, $data = array())
 {
     if (is_array($url_mixed)) {
         $curl_multi = curl_multi_init();
         $this->_multi_parent = true;
         $this->curls = array();
         foreach ($url_mixed as $url) {
             $curl = new Curl();
             $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_error_code === CURLM_OK)) {
                 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 ($status === CURLM_CALL_MULTI_PERFORM || $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();
     }
 }
Ejemplo n.º 3
0
 public function execute()
 {
     $mh = curl_multi_init();
     $chs = $this->chs();
     $stillRunning = 0;
     $result = array();
     if (function_exists('curl_multi_setopt')) {
         curl_multi_setopt($mh, CURLMOPT_PIPELINING, 1);
         curl_multi_setopt($mh, CURLMOPT_MAXCONNECTS, $this->maxConnectsSize());
     }
     foreach ($chs as $ch) {
         curl_multi_add_handle($mh, $ch);
     }
     do {
         $execReturnValue = curl_multi_exec($mh, $stillRunning);
         curl_multi_select($mh);
     } while ($stillRunning > 0);
     foreach ($chs as $i => $ch) {
         $curlError = curl_error($ch);
         if ($curlError === "") {
             $result[$i] = curl_multi_getcontent($ch);
         } else {
             throw new PubnubException("Curl error on handle {$i}: {$curlError}\n");
         }
         curl_multi_remove_handle($mh, $ch);
         curl_close($ch);
     }
     curl_multi_close($mh);
     $this->requests = array();
     if ($execReturnValue != CURLM_OK) {
         throw new PubnubException(curl_multi_strerror($execReturnValue));
     }
     return $result;
 }
Ejemplo n.º 4
0
 public function get($url_mixed, $data = array())
 {
     if (is_array($url_mixed)) {
         $curl_multi = curl_multi_init();
         $this->multi_parent = true;
         $this->curls = array();
         foreach ($url_mixed as $url) {
             $curl = new Curl();
             $curl->multi_child = true;
             $curl->beforeSend($this->before_send_function);
             $curl->success($this->success_function);
             $curl->error($this->error_function);
             $curl->complete($this->complete_function);
             $curl->base_url = $url;
             $curl->url = $this->buildURL($url, $data);
             $curl->setOpt(CURLOPT_URL, $curl->url, $curl->curl);
             $curl->setOpt(CURLOPT_CUSTOMREQUEST, 'GET');
             $curl->setOpt(CURLOPT_HTTPGET, true);
             $this->curls[] = $curl;
             $curlm_error_code = curl_multi_add_handle($curl_multi, $curl->curl);
             if (!($curlm_error_code === CURLM_OK)) {
                 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 {
             curl_multi_select($curl_multi);
             $status = curl_multi_exec($curl_multi, $active);
         } while ($status === CURLM_CALL_MULTI_PERFORM || $active);
         while (!($info_array = curl_multi_info_read($curl_multi)) === false) {
             if (!($info_array['msg'] === CURLMSG_DONE)) {
                 continue;
             }
             foreach ($this->curls as $ch) {
                 if ($ch->curl === $info_array['handle']) {
                     $ch->curl_error_code = $info_array['result'];
                     break;
                 }
             }
         }
         foreach ($this->curls as $ch) {
             $this->exec($ch);
         }
     } else {
         $this->base_url = $url_mixed;
         $this->url = $this->buildURL($url_mixed, $data);
         $this->setOpt(CURLOPT_URL, $this->url);
         $this->setOpt(CURLOPT_CUSTOMREQUEST, 'GET');
         $this->setOpt(CURLOPT_HTTPGET, true);
         return $this->exec();
     }
 }
Ejemplo n.º 5
0
 /**
  * Call curl_multi_add_handle().
  * @param resource $ch
  * @param Deferred $deferred
  */
 private function addImmediate($ch, Deferred $deferred = null)
 {
     $errno = curl_multi_add_handle($this->mh, $ch);
     if ($errno !== CURLM_OK) {
         // @codeCoverageIgnoreStart
         $msg = curl_multi_strerror($errno) . ": {$ch}";
         $deferred && $deferred->reject(new \RuntimeException($msg));
         return;
         // @codeCoverageIgnoreEnd
     }
     $this->added[(string) $ch] = $ch;
     $deferred && ($this->deferreds[(string) $ch] = $deferred);
 }
Ejemplo n.º 6
0
 /**
  * Call curl_multi_add_handle().
  * @param resource $ch
  * @return PromiseInterface
  */
 public function add($ch)
 {
     $deferred = new Deferred();
     $errno = curl_multi_add_handle($this->mh, $ch);
     if ($errno !== CURLM_OK) {
         // @codeCoverageIgnoreStart
         $msg = curl_multi_strerror($errno) . ": {$ch}";
         $deferred->reject(new \RuntimeException($msg));
         return $deferred->promise();
         // @codeCoverageIgnoreEnd
     }
     $this->added[(string) $ch] = $ch;
     $this->deferreds[(string) $ch] = $deferred;
     return $deferred->promise();
 }
Ejemplo n.º 7
0
<?php

var_dump(strtolower(curl_multi_strerror(CURLM_OK)));
var_dump(strtolower(curl_multi_strerror(CURLM_BAD_HANDLE)));
Ejemplo n.º 8
0
 /**
  * Add Handle
  *
  * @access private
  * @param  $curl
  */
 private function addHandle($curl)
 {
     $curlm_error_code = curl_multi_add_handle($this->multi_curl, $curl->curl);
     if (!($curlm_error_code === CURLM_OK)) {
         throw new \ErrorException('cURL multi add handle error: ' . curl_multi_strerror($curlm_error_code));
     }
     $curl->beforeSend($this->before_send_function);
     $curl->success($this->success_function);
     $curl->error($this->error_function);
     $curl->complete($this->complete_function);
     $this->curls[] = $curl;
     $curl->id = count($this->curls);
 }
Ejemplo n.º 9
0
 /**
  * Throw an exception for a cURL multi response
  *
  * @param int $code Curl response code
  * @throws AdapterException
  */
 public static function throwMultiError($code)
 {
     $buffer = function_exists('curl_multi_strerror') ? curl_multi_strerror($code) : self::ERROR_STR;
     throw new AdapterException(sprintf('cURL error %s: %s', $code, $buffer));
 }
Ejemplo n.º 10
0
 /**
  * @see curl_multi_strerror
  *
  * @param int $errornum
  * @return string
  */
 public static function strerror($errornum)
 {
     return curl_multi_strerror($errornum);
 }
Ejemplo n.º 11
0
 /**
  * @note PHP 5.5.0
  *
  * @since 1.0
  *
  * @return string
  */
 public function getLastError()
 {
     return function_exists('curl_multi_strerror') ? curl_multi_strerror($this->lastErrorCode) : '';
 }
Ejemplo n.º 12
0
 /**
  * Return string describing error code
  *
  * @param int $errornum One of the CURLM error codes constants. 
  * @return string       Error string for valid error code, NULL otherwise.
  */
 public final function curlMultiStrerror($errornum)
 {
     return curl_multi_strerror($this->curl_multi_handle, $errornum);
 }
Ejemplo n.º 13
0
 public function getError($errno)
 {
     return curl_multi_strerror($errno);
 }
Ejemplo n.º 14
0
 /**
  * 发送异步请求
  * @return void
  */
 public function sendRequestAsyn()
 {
     $mh = curl_multi_init();
     $ch_handles = array();
     // 遍历设置的连接
     foreach ($this->asynRequests as $request) {
         $ch = curl_init($request['url']);
         $this->setCurlOptions($ch, $request['options']);
         $ch_handles[] = $ch;
         // 添加$ch到$mh
         curl_multi_add_handle($mh, $ch);
     }
     $running = null;
     do {
         $mrc = curl_multi_exec($mh, $running);
         curl_multi_select($mh);
     } while ($running > 0);
     unset($running);
     if ($mrc !== CURLM_OK) {
         throw new \Exception(curl_multi_strerror($mrc), 1);
     }
     foreach ($ch_handles as $key => $ch) {
         $this->headerInfo = curl_getinfo($ch);
         $this->asynResponses[$key] = new \stdClass();
         $this->asynResponses[$key]->response = curl_multi_getcontent($ch);
         $this->asynResponses[$key]->responseBody = $this->parseResultBody($this->asynResponses[$key]->response);
         $this->asynResponses[$key]->responseHeaders = $this->parseResultHeaders($this->asynResponses[$key]->response);
         curl_multi_remove_handle($mh, $ch);
     }
     curl_multi_close($mh);
 }
Ejemplo n.º 15
0
 /**
  * @param resource $asyncHandle
  * @param array &$asyncPendingRequests
  * @param array &$asyncProcessingRequests
  * @param array $asyncOptions
  * @return bool
  */
 private static function fetchAsyncRequests($asyncHandle, &$asyncPendingRequests, &$asyncProcessingRequests, $asyncOptions)
 {
     $pendingRequestCount = count($asyncPendingRequests);
     $processingRequestCount = count($asyncProcessingRequests);
     $maxConcurrentRequests = self::getAsyncMaxConcurrentRequests($asyncOptions);
     $requestFetchingCallback = self::getAsyncRequestFetchingCallback($asyncOptions);
     $isFetchingCallbackInvoked = false;
     while ($processingRequestCount < $maxConcurrentRequests) {
         if ($pendingRequestCount === 0) {
             if ($isFetchingCallbackInvoked) {
                 return true;
             }
             if ($requestFetchingCallback !== null) {
                 $tmp = call_user_func($requestFetchingCallback);
                 if ($tmp === false) {
                     return false;
                 } elseif ($tmp === true || $tmp === null) {
                     return true;
                 } elseif (is_array($tmp) === false) {
                     $type = gettype($tmp);
                     throw new WebClientAsyncException("The return value of request fetching callback must" . " be an array or a bool, {$type} given.");
                 }
                 $pendingRequestCount = count($tmp);
                 if ($pendingRequestCount === 0) {
                     return true;
                 }
                 $asyncPendingRequests = $tmp;
                 $isFetchingCallbackInvoked = true;
             } else {
                 return false;
             }
         }
         $key = key($asyncPendingRequests);
         $client = $asyncPendingRequests[$key];
         unset($asyncPendingRequests[$key]);
         --$pendingRequestCount;
         ++$processingRequestCount;
         if (is_array($client)) {
             $tmp = new static();
             $tmp->setOptions($client);
             $client = $tmp;
         } elseif ($client instanceof WebClient === false) {
             $type = gettype($client);
             throw new WebClientAsyncException('The request must be an instance of ' . __CLASS__ . " or an option array, {$type} given.");
         }
         $client->requestOptions = $client->options;
         $client->initializeRequest();
         $index = (int) $client->handle;
         if (isset($asyncProcessingRequests[$index])) {
             throw new WebClientAsyncException('The web client already exists in the processing queue.');
         }
         $asyncProcessingRequests[$index] = $client;
         $code = curl_multi_add_handle($asyncHandle, $client->handle);
         if ($code !== CURLM_OK) {
             throw new WebClientAsyncException(curl_multi_strerror($code), $code);
         }
     }
     return true;
 }
Ejemplo n.º 16
0
// /301?to=<url> returns a 301 to a new URL
// /304 returns an HTTP 304
$curl_handles = array();
$master = curl_multi_init();
$urls = ['http://localhost:3001/200', 'http://localhost:3001/200?wait=5', 'http://localhost:3001/301', 'http://localhost:3001/302', 'http://localhost:3001/304', 'http://localhost:3001/404', 'http://localhost:3002/blah', 'http://localhost:3001/slowloris', 'http://localhost:3001/500'];
for ($i = 0; $i < count($urls); $i++) {
    $handle = curl_init($urls[$i]);
    curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($handle, CURLOPT_FOLLOWLOCATION, true);
    curl_multi_add_handle($master, $handle);
    $curl_handles[$i] = $handle;
}
echo "starting\n";
do {
    $mrc = curl_multi_exec($master, $running);
    echo "new state " . curl_multi_strerror($mrc) . "\n";
    echo "startup\n";
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
echo "running\n";
while ($running && $mrc == CURLM_OK) {
    //echo "selecting\n";
    $sel = curl_multi_select($master, 5.0);
    //echo "selected $sel\n";
    if ($sel === -1) {
        echo "sleeping\n";
        usleep(1000 * 1);
    }
    $old_running = $running;
    do {
        $mrc = curl_multi_exec($master, $running);
    } while ($mrc == CURLM_CALL_MULTI_PERFORM);
Ejemplo n.º 17
0
 /**
  * Add Handle
  *
  * @access private
  * @param  $curl
  * @throws \ErrorException
  */
 private function addHandle($curl)
 {
     $curlm_error_code = curl_multi_add_handle($this->multiCurl, $curl->curl);
     if (!($curlm_error_code === CURLM_OK)) {
         throw new \ErrorException('cURL multi add handle error: ' . curl_multi_strerror($curlm_error_code));
     }
     $curl->beforeSend($this->beforeSendFunction);
     $curl->success($this->successFunction);
     $curl->error($this->errorFunction);
     $curl->complete($this->completeFunction);
     $this->curls[] = $curl;
     $curl->id = $this->nextCurlId++;
     if ($this->isStarted) {
         $this->initHandle($curl);
     }
 }
Ejemplo n.º 18
0
$channels = array();
foreach ($urls as $key => $url) {
    // initiate individual channel
    $channels[$key] = curl_init();
    curl_setopt_array($channels[$key], array(CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true));
    // add channel to multihandler
    curl_multi_add_handle($mh, $channels[$key]);
}
// execute - if there is an active connection then keep looping
$active = null;
do {
    $status = curl_multi_exec($mh, $active);
    // Check for errors
    if ($status > 0) {
        // Display error message
        echo "ERROR!\n " . curl_multi_strerror($status);
    }
} while ($active && $status == CURLM_OK);
// done!
$time_end = microtime(true);
$time = $time_end - $time_start;
$download_size = 0;
// echo the content, remove the handlers, then close them
foreach ($channels as $chan) {
    //echo curl_multi_getcontent($chan);
    $download_size += strlen(curl_multi_getcontent($chan));
    curl_multi_remove_handle($mh, $chan);
    curl_close($chan);
}
// ---------------------------------------------------------
// Summary
 /**
  * @param resource $curlHandle
  * @return DefaultConnectionResponse
  * @throws Exception
  */
 private function executeCurlHandle($curlHandle)
 {
     $multiHandle = $this->getCurlMultiHandle();
     curl_multi_add_handle($multiHandle, $curlHandle);
     $running = null;
     do {
         $status = curl_multi_exec($multiHandle, $running);
         if ($status > CURLM_OK) {
             $errorMessage = 'cURL error ' . $status;
             if (function_exists('curl_multi_strerror')) {
                 $errorMessage .= ' (' . curl_multi_strerror($status) . ')';
             }
             throw new ErrorException($errorMessage);
         }
         $info = curl_multi_info_read($multiHandle);
         if ($info && isset($info['result']) && $info['result'] != CURLE_OK) {
             $errorMessage = 'cURL error ' . $info['result'];
             if (function_exists('curl_strerror')) {
                 $errorMessage .= ' (' . curl_strerror($info['result']) . ')';
             }
             throw new ErrorException($errorMessage);
         }
         curl_multi_select($multiHandle);
     } while ($running > 0);
     $content = curl_multi_getcontent($curlHandle);
     $headerSize = curl_getinfo($curlHandle, CURLINFO_HEADER_SIZE);
     $httpCode = curl_getinfo($curlHandle, CURLINFO_HTTP_CODE);
     curl_multi_remove_handle($multiHandle, $curlHandle);
     $httpHeaderHelper = new HttpHeaderHelper();
     $headers = $httpHeaderHelper->parseRawHeaders(explode("\r\n", substr($content, 0, $headerSize)));
     $body = substr($content, $headerSize);
     return new DefaultConnectionResponse($httpCode, $headers, $body);
 }
Ejemplo n.º 20
0
 /**
  * Init Handle
  *
  * @access private
  * @param  $curl
  * @throws \ErrorException
  */
 private function initHandle($curl)
 {
     // Set callbacks if not already individually set.
     if ($curl->beforeSendFunction === null) {
         $curl->beforeSend($this->beforeSendFunction);
     }
     if ($curl->successFunction === null) {
         $curl->success($this->successFunction);
     }
     if ($curl->errorFunction === null) {
         $curl->error($this->errorFunction);
     }
     if ($curl->completeFunction === null) {
         $curl->complete($this->completeFunction);
     }
     foreach ($this->options as $option => $value) {
         $curl->setOpt($option, $value);
     }
     foreach ($this->headers as $key => $value) {
         $curl->setHeader($key, $value);
     }
     foreach ($this->cookies as $key => $value) {
         $curl->setCookie($key, $value);
     }
     $curl->setJsonDecoder($this->jsonDecoder);
     $curl->setXmlDecoder($this->xmlDecoder);
     $curlm_error_code = curl_multi_add_handle($this->multiCurl, $curl->curl);
     if (!($curlm_error_code === CURLM_OK)) {
         throw new \ErrorException('cURL multi add handle error: ' . curl_multi_strerror($curlm_error_code));
     }
     $this->activeCurls[$curl->id] = $curl;
     $this->responseCookies = array();
     $curl->call($curl->beforeSendFunction);
 }
 /** @function process the actual process to send
  * @param $urls the url or array of urls to process required
  * @param $method the method to send pass the url (GET or POST) defaults to GET
  * @param $data the specific data to send (defaults to null)
  * @param $sendAsJSON whether to send the data in JSON or not faults to false
  * @param $auth whether to send an auth string.  Defaults to false, other wise takes the actual auth string to pass
  * @param $callback whether to use a user passed callback to process.  Defaults to false
  * @param $file whether we're downloading a file or not.  Defaults to false, others takes the file resource
  * @return if $file it just closes the handle otherwise it returns the response
  */
 public function process($urls, $method = false, $data = null, $sendAsJSON = false, $auth = false, $callback = false, $file = false)
 {
     if (!is_array($urls)) {
         $urls = array($urls);
     }
     foreach ($urls as $url) {
         $ProxyUsed = false;
         if ($this->DB && $this->FOGCore->getSetting('FOG_PROXY_IP')) {
             foreach ($this->getClass('StorageNodeManager')->find() as $StorageNode) {
                 $IPs[] = $this->FOGCore->resolveHostname($StorageNode->get('ip'));
             }
             $IPs = array_filter(array_unique((array) $IPs));
             if (!preg_match('#^(?!.*' . implode('|', (array) $IPs) . ')$#i', $url)) {
                 $ProxyUsed = true;
             }
             $username = $this->FOGCore->getSetting('FOG_PROXY_USERNAME');
             $password = $this->FOGCore->getSetting('FOG_PROXY_PASSWORD');
         }
         if ($ProxyUsed) {
             $this->contextOptions[CURLOPT_PROXYAUTH] = CURLAUTH_BASIC;
             $this->contextOptions[CURLOPT_PROXYPORT] = $this->FOGCore->getSetting('FOG_PROXY_PORT');
             $this->contextOptions[CURLOPT_PROXY] = $this->FOGCore->getSetting('FOG_PROXY_IP');
             if ($username) {
                 $this->contextOptions[CURLOPT_PROXYUSERPWD] = $username . ':' . $password;
             }
         }
         if ($method == 'GET' && $data !== null) {
             $url .= '?' . http_build_query($data);
         }
         $ch = @curl_init($url);
         $this->contextOptions[CURLOPT_URL] = $url;
         if ($auth) {
             $this->contextOptions[CURLOPT_USERPWD] = $auth;
         }
         if ($file) {
             $this->contextOptions[CURLOPT_FILE] = $file;
             $this->contextOptions[CURLOPT_TIMEOUT_MS] = 300000000;
         }
         if ($method == 'POST' && $data !== null) {
             if ($sendAsJSON) {
                 $data = json_encode($data);
                 $this->contextOptions[CURLOPT_HTTPHEADER] = array('Content-Type: application/json', 'Content-Length: ' . strlen($data));
             }
             $this->contextOptions[CURLOPT_POSTFIELDS] = $data;
         }
         $this->contextOptions[CURLOPT_CUSTOMREQUEST] = $method;
         curl_setopt_array($ch, $this->contextOptions);
         $curl[$url] = $ch;
         @curl_multi_add_handle($this->handle, $ch);
     }
     $active = null;
     do {
         $mrc = @curl_multi_exec($this->handle, $active);
     } while ($mrc == CURLM_CALL_MULTI_PERFORM);
     while ($active && $mrc == CURLM_OK) {
         if (@curl_multi_select($this->handle) == -1) {
             usleep(1);
         }
         do {
             $mrc = @curl_multi_exec($this->handle, $active);
             $httpCode = @curl_multi_info_read($this->handle);
             if ($mrc > 0) {
                 throw new Exception('cURL Error: ' . curl_multi_strerror($mrc));
             }
             if ($httpCode[0] >= 400) {
                 @curl_multi_close($this->handle);
                 throw new Exception('cURL HTTP Error Code: ' . $httpCode[0]);
             }
         } while ($mrc == CURLM_CALL_MULTI_PERFORM);
     }
     if (!$file) {
         foreach ($curl as $url => $ch) {
             if ($callback) {
                 $callback($ch);
             }
             $response[] = @curl_multi_getcontent($ch);
             @curl_multi_remove_handle($this->handle, $ch);
         }
         return $response;
     } else {
         @fclose($file);
     }
 }
Ejemplo n.º 22
0
 /**
  * wait for all responses
  *
  * $wait_function indicates like this:
  *
  * function wait_func($total_wait, $function){
  *     // $total_wait: total wait time in msec
  *     // $function: function name which needs wait
  *     // return value: if you want to break waitForAll, return true.
  *     if ( $total_wait > 2000 )    return true;   // will cancel waitForAll(throws UserCancelException)
  *     usleep(20);
  *     return false;    // continue execution of waitForAll
  * }
  *
  * @param callable $wait_function    user defined wait function.if this set to null, default wait ant default
  *                                   timeout will be applied.
  *
  * @return array
  *
  * @throws UserCancelException
  */
 public function waitForAll($wait_function = null)
 {
     $mh = new CurlMultiHandle();
     $mh->setOptions($this->options);
     foreach ($this->requests as $req) {
         $cho = $this->pool->acquireObject();
         $cho->setRequest($req);
         $mh->addHandle($cho);
     }
     $result = [];
     $total_wait = 0;
     do {
         $mh->select();
         $stat = $mh->execute($running);
         if ($running) {
             $start = microtime(true);
             if ($wait_function && is_callable($wait_function)) {
                 $canceled = call_user_func_array($wait_function, [$total_wait, 'curl_multi_exec']);
                 if ($canceled) {
                     throw new UserCancelException();
                 }
             } else {
                 // default wait
                 if ($total_wait + self::DEFAULT_SLEEP_WAIT > self::DEFAULT_WAIT_TMEOUT) {
                     throw new TimeoutException();
                 }
                 usleep(self::DEFAULT_SLEEP_WAIT);
             }
             $total_wait += microtime(true) - $start;
             continue;
         }
     } while ($stat === CURLM_CALL_MULTI_PERFORM || $running);
     if ($stat !== CURLM_OK) {
         $errmsg = curl_multi_strerror($stat);
         throw new GrasshopperException('curl_multi_exec failed:' . $errmsg, self::ERROR_MULTI_EXEC);
     }
     // read each response
     do {
         $res = $mh->getInfo($remains);
         if (!$res) {
             $start = microtime(true);
             if ($wait_function && is_callable($wait_function)) {
                 $canceled = call_user_func_array($wait_function, [$total_wait, 'curl_multi_info_read']);
                 if ($canceled) {
                     throw new UserCancelException();
                 }
             } else {
                 // default wait
                 if ($total_wait + self::DEFAULT_SLEEP_WAIT > self::DEFAULT_WAIT_TMEOUT) {
                     throw new TimeoutException();
                 }
                 usleep(self::DEFAULT_SLEEP_WAIT);
             }
             $total_wait += microtime(true) - $start;
             $remains = 1;
             continue;
         }
         $response = null;
         /** @var resource $ch */
         $ch = $res['handle'];
         // find cURL handle object
         $cho = $this->pool->findObject($ch);
         /** @var CurlRequest $request */
         $request = $cho->getRequest();
         /** @var string $url */
         $request_url = $request->getUrl();
         if ($res['result'] !== CURLE_OK) {
             $errno = $res['result'];
             $function = 'curl_multi_info_read';
             $error = new CurlError($errno, $function);
             goto REQUEST_FAILED;
         }
         $info = curl_getinfo($ch);
         if ($info === false) {
             $errno = curl_errno($ch);
             $function = 'curl_getinfo';
             $error = new CurlError($errno, $function);
             goto REQUEST_FAILED;
         }
         $effective_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
         if ($effective_url === false) {
             $errno = curl_errno($ch);
             $function = 'curl_getinfo';
             $error = new CurlError($errno, $function);
             goto REQUEST_FAILED;
         }
         $info['effective_url'] = $effective_url;
         $fp = $request->getFileHandle();
         fseek($fp, 0);
         $content = fread($fp, $this->max_download_size);
         fclose($fp);
         REQUEST_SUCCEEDED:
         $response = null;
         try {
             $response = new CurlResponse($info, $content);
         } catch (DeflateException $ex) {
             $error = new HttpError(0, 'failed to deflate');
             goto REQUEST_FAILED;
         }
         $event = new SuccessEvent($request, $response);
         // callback
         $request->onRequestSucceeded($event);
         if ($this->complete_callback) {
             call_user_func_array($this->complete_callback, [$event]);
         }
         $result["{$request_url}"] = $event;
         goto REQUEST_FINISH;
         REQUEST_FAILED:
         $event = new ErrorEvent($request, $error, $response);
         // callback
         $request->onRequestFailed($event);
         if ($this->error_callback) {
             call_user_func_array($this->error_callback, [$event]);
         }
         $result["{$request_url}"] = $event;
         goto REQUEST_FINISH;
         REQUEST_FINISH:
         $mh->removeHandle($cho);
         $this->pool->releaseObject($cho);
     } while ($remains);
     $mh->close();
     return $result;
 }
Ejemplo n.º 23
-1
 /**
  * Starts a session by sending out the added requests.
  *
  * @param  reference $success **OPTIONAL. OUTPUT.** After the method is called with this parameter provided, the
  * parameter's value tells whether the session was successful.
  *
  * @return void
  */
 public function start(&$success = null)
 {
     $success = true;
     if ($this->m_hasError) {
         $success = false;
         return;
     }
     if (CArray::isEmpty($this->m_requestRecordsQueue)) {
         // Nothing to do.
         return;
     }
     // Current policy is to disable HTTP pipelining.
     $res = curl_multi_setopt($this->m_multiCurl, CURLMOPT_PIPELINING, 0);
     if (!$res) {
         // Should never get in here as long as cURL options are being set correctly, hence the assertion.
         assert('false', vs(isset($this), get_defined_vars()));
         $this->m_hasError = true;
         $this->m_errorMessage = "The 'curl_multi_setopt' function failed.";
         $success = false;
         $this->finalize();
         return;
     }
     $anySuccessfulRequests = false;
     // Disable the script's execution timeout before getting into the session.
     $timeoutPause = new CTimeoutPause();
     $numRunningRequests = 0;
     // also the index of the next request to send
     while (true) {
         // From the request queue, add as many normal cURL handles to the multi cURL handle as it is allowed by the
         // maximum number of concurrent requests, priorly setting internal options for every request.
         while ($numRunningRequests < CArray::length($this->m_requestRecordsQueue) && $numRunningRequests < $this->m_maxNumConcurrentRequests) {
             $requestRecord = $this->m_requestRecordsQueue[$numRunningRequests];
             $request = $requestRecord[0];
             $onCompleteCallback = $requestRecord[1];
             $newCookieSession = $requestRecord[2];
             $requestCurl = $request->curl();
             // Set cURL options for the normal cURL handle, having created a temporary file for cookie storage if
             // needed.
             $requestSetOptSuccess;
             if ($this->m_cookiesAreEnabled && $request->isHttp()) {
                 if (!isset($this->m_cookiesFp)) {
                     $this->m_cookiesFp = CFile::createTemporary();
                 }
                 $request->setInternalOptions($requestSetOptSuccess, $this->m_cookiesFp, $newCookieSession);
             } else {
                 $request->setInternalOptions($requestSetOptSuccess);
             }
             if (!$requestSetOptSuccess) {
                 if (isset($onCompleteCallback)) {
                     call_user_func($onCompleteCallback, false, "", $request, $this);
                 }
                 CArray::remove($this->m_requestRecordsQueue, $numRunningRequests);
                 continue;
             }
             // Add the normal cURL handle to the multi cURL handle.
             $res = curl_multi_add_handle($this->m_multiCurl, $requestCurl);
             if ($res != 0) {
                 $this->m_hasError = true;
                 $curlError = curl_multi_strerror($res);
                 $this->m_errorMessage = is_cstring($curlError) && !CString::isEmpty($curlError) ? $curlError : "The 'curl_multi_add_handle' function failed.";
                 $success = false;
                 $timeoutPause->end();
                 $this->finalize();
                 return;
             }
             $numRunningRequests++;
         }
         if ($numRunningRequests == 0) {
             break;
         }
         // Process the currently added requests until complete or no more data is available. Although
         // `CURLM_CALL_MULTI_PERFORM` is deprecated since libcurl 7.20, keep it for compatibility reasons.
         $numRunningTransfers;
         do {
             $multiExecRes = curl_multi_exec($this->m_multiCurl, $numRunningTransfers);
         } while ($multiExecRes == CURLM_CALL_MULTI_PERFORM);
         if ($multiExecRes != CURLM_OK) {
             $this->m_hasError = true;
             $curlError = curl_multi_strerror($multiExecRes);
             $this->m_errorMessage = is_cstring($curlError) && !CString::isEmpty($curlError) ? $curlError : "The 'curl_multi_exec' function failed.";
             $success = false;
             $timeoutPause->end();
             $this->finalize();
             return;
         }
         // Check for completed requests, call the callback function for any completed one (if such a function is
         // defined), finalize completed requests, and remove completed requests from the queue.
         while (true) {
             $completedRequestInfo = curl_multi_info_read($this->m_multiCurl);
             if (!is_cmap($completedRequestInfo)) {
                 break;
             }
             // A request has completed.
             assert('$completedRequestInfo["msg"] == CURLMSG_DONE', vs(isset($this), get_defined_vars()));
             $requestCurl = $completedRequestInfo["handle"];
             $requestRes = $completedRequestInfo["result"];
             $requestRecordPos;
             $found = CArray::find($this->m_requestRecordsQueue, $requestCurl, function ($requestRecord, $requestCurl) {
                 $request = $requestRecord[0];
                 return $request->curl() == $requestCurl;
             }, $requestRecordPos);
             assert('$found', vs(isset($this), get_defined_vars()));
             $requestRecord = $this->m_requestRecordsQueue[$requestRecordPos];
             $request = $requestRecord[0];
             $onCompleteCallback = $requestRecord[1];
             // Remove the normal cURL handle from the multi cURL handle.
             $res = curl_multi_remove_handle($this->m_multiCurl, $requestCurl);
             if ($res != 0) {
                 $this->m_hasError = true;
                 $curlError = curl_multi_strerror($res);
                 $this->m_errorMessage = is_cstring($curlError) && !CString::isEmpty($curlError) ? $curlError : "The 'curl_multi_remove_handle' function failed.";
                 $success = false;
                 $timeoutPause->end();
                 $this->finalize();
                 return;
             }
             if ($requestRes == CURLE_OK) {
                 // The request has succeeded.
                 if (isset($onCompleteCallback)) {
                     $response;
                     if ($request->isReturnTransferSet()) {
                         $response = curl_multi_getcontent($requestCurl);
                         assert('is_cstring($response)', vs(isset($this), get_defined_vars()));
                     } else {
                         $response = "";
                     }
                     $request->onRequestCompleteOk();
                     // also close the normal cURL handle
                     call_user_func($onCompleteCallback, true, $response, $request, $this);
                 } else {
                     $request->onRequestCompleteOk();
                     // also close the normal cURL handle
                 }
                 $anySuccessfulRequests = true;
             } else {
                 // The request has failed.
                 $curlError = curl_strerror($requestRes);
                 if (!is_cstring($curlError)) {
                     $curlError = "";
                 }
                 $request->onRequestCompleteWithError($curlError);
                 // also close the normal cURL handle
                 if (isset($onCompleteCallback)) {
                     call_user_func($onCompleteCallback, false, "", $request, $this);
                 }
             }
             CArray::remove($this->m_requestRecordsQueue, $requestRecordPos);
             $numRunningRequests--;
         }
         assert('$numRunningRequests == $numRunningTransfers', vs(isset($this), get_defined_vars()));
         if ($numRunningTransfers > 0) {
             // Some requests are still being processed (by remote machines). Wait for more data to appear on
             // sockets, without getting hard on the CPU.
             do {
                 $multiSelectRes = curl_multi_select($this->m_multiCurl);
             } while ($multiSelectRes == -1);
         } else {
             // No requests are being processed. Check if any requests are pending.
             if (CArray::isEmpty($this->m_requestRecordsQueue)) {
                 // No requests are pending.
                 break;
             }
         }
     }
     // Set the script's execution time limit like the session has never happened.
     $timeoutPause->end();
     if (!$anySuccessfulRequests) {
         $this->m_hasError = true;
         $this->m_errorMessage = "None of the session's requests succeeded.";
         $success = false;
     }
     $this->finalize();
 }