public function start()
 {
     if ($this->isActive || $this->isStopped) {
         return;
     }
     $this->isActive = true;
     $this->isStarted = true;
     $curlHandle = curl_multi_init();
     try {
         do {
             // send requests from queue to CURL
             if (count($this->activeRequests) < $this->connectionsLimit) {
                 for ($i = $this->connectionsLimit - count($this->activeRequests); $i > 0; $i--) {
                     $request = $this->queue->pop();
                     if ($request) {
                         $this->sendRequestToMultiCurl($curlHandle, $request);
                         $this->activeRequests[$request->getId()] = $request;
                     } else {
                         break;
                     }
                 }
             }
             while (CURLM_CALL_MULTI_PERFORM === curl_multi_exec($curlHandle, $activeThreads)) {
             }
             // check complete requests
             curl_multi_select($curlHandle, $this->requestingDelay);
             while ($completeCurlInfo = curl_multi_info_read($curlHandle)) {
                 $completeRequestId = Request::getRequestIdByCurlHandle($completeCurlInfo['handle']);
                 $completeRequest = $this->activeRequests[$completeRequestId];
                 unset($this->activeRequests[$completeRequestId]);
                 curl_multi_remove_handle($curlHandle, $completeRequest->getCurlHandle());
                 $completeRequest->handleCurlResult();
                 // check if response code is 301 or 302 and follow location
                 $ignoreNotification = false;
                 $completeRequestCode = $completeRequest->getCode();
                 if ($completeRequestCode == 301 || $completeRequestCode == 302) {
                     $completeRequestOptions = $completeRequest->getCurlOptions();
                     if (!empty($completeRequestOptions[CURLOPT_FOLLOWLOCATION])) {
                         $completeRequest->_permanentlyMoved = empty($completeRequest->_permanentlyMoved) ? 1 : $completeRequest->_permanentlyMoved + 1;
                         $responseHeaders = $completeRequest->getResponseHeaders(true);
                         if ($completeRequest->_permanentlyMoved < 5 && !empty($responseHeaders['Location'])) {
                             // figure out whether we're dealing with an absolute or relative redirect (thanks to kmontag https://github.com/kmontag for this bugfix)
                             $redirectedUrl = (parse_url($responseHeaders['Location'], PHP_URL_SCHEME) === null ? $completeRequest->getBaseUrl() : '') . $responseHeaders['Location'];
                             $completeRequest->setUrl($redirectedUrl);
                             $completeRequest->reInitCurlHandle();
                             $this->pushRequestToQueue($completeRequest);
                             $ignoreNotification = true;
                         }
                     }
                 }
                 if (!$ignoreNotification) {
                     $this->notifyRequestComplete($completeRequest);
                 }
             }
         } while (!$this->isStopped && ($this->activeRequests || $this->queue->count()));
     } catch (Exception $exception) {
     }
     $this->isActive = false;
     if ($curlHandle && is_resource($curlHandle)) {
         curl_multi_close($curlHandle);
     }
     if (!empty($exception)) {
         throw $exception;
     }
     /** @noinspection PhpUndefinedMethodInspection */
     $this->callbacks->onComplete($this);
 }
Example #2
0
	public function start() {
		if($this->isActive || $this->isStopped) {
			return;
		}
		$this->isActive = true;
		$this->isStarted = true;

		try {

			$this->mcurlHandle = $mcurlHandle = curl_multi_init();

			do {

				// send requests from queue to CURL
				if(count($this->activeRequests) < $this->connectionsLimit) {
					for($i = $this->connectionsLimit - count($this->activeRequests); $i > 0; $i --) {
						$request = $this->queue->pop();
						if($request) {
							$this->sendRequestToMultiCurl($mcurlHandle, $request);
							$this->activeRequests[$request->getId()] = $request;
						}
						else {
							break;
						}
					}
				}

				while(CURLM_CALL_MULTI_PERFORM === curl_multi_exec($mcurlHandle, $activeThreads));

				// check complete requests
				curl_multi_select($mcurlHandle, $this->requestingDelay);
				while($completeCurlInfo = curl_multi_info_read($mcurlHandle)) {
					$completeRequestId = Request::getRequestIdByCurlHandle($completeCurlInfo['handle']);
					$completeRequest = $this->activeRequests[$completeRequestId];
					unset($this->activeRequests[$completeRequestId]);
					curl_multi_remove_handle($mcurlHandle, $completeRequest->getCurlHandle());
					$completeRequest->initResponseDataFromHandler($this);

					// check if response code is 301 or 302 and follow location
					$ignoreNotification = false;
					$completeRequestCode = $completeRequest->getCode();

					if($completeRequestCode == 301 || $completeRequestCode == 302) {
						$completeRequestOptions = $completeRequest->getCurlOptions();
						if(!empty($completeRequestOptions[CURLOPT_FOLLOWLOCATION])) {
							$completeRequest->_permanentlyMoved = empty($completeRequest->_permanentlyMoved) ? 1 : $completeRequest->_permanentlyMoved + 1;
							$responseHeaders = $completeRequest->getResponseHeaders(true);
							if($completeRequest->_permanentlyMoved < 5 && !empty($responseHeaders['Location'])) {
								$completeRequest->setUrl($completeRequest->getBaseUrl() . $responseHeaders['Location']);
								$completeRequest->reinitCurlHandle();
								$this->pushRequestToQueue($completeRequest);
								$ignoreNotification = true;
							}
						}
					}
					if(!$ignoreNotification) {
						$this->notifyRequestComplete($completeRequest);
					}
				}
			}
			while(!$this->isStopped && ($this->activeRequests || $this->queue->count()));
		}
		catch(\Exception $exception) {
		}

		$this->isActive = false;

		if($mcurlHandle && is_resource($mcurlHandle)) {
			curl_multi_close($mcurlHandle);
		}

		if(!empty($exception)) {
			throw $exception;
		}

		$this->callbacks->onComplete($this);
	}