/** * Copy the remote file in local. * * @param string $origin host/domain text * @param string $fileUrl targeturl * @param string $fileName the local filename * @param bool $progress Display the progression * @param array $options Additional context options * * @return bool true */ public function copy($origin, $fileUrl, $fileName, $progress = true, $options = array()) { $that = $this; // for PHP5.3 return $this->fetch($origin, $fileUrl, $progress, $options, function ($ch, $request) use($that, $fileName) { $outputFile = new OutputFile($fileName); curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); curl_setopt($ch, CURLOPT_FILE, $outputFile->getPointer()); list(, $response) = $result = $that->exec($ch, $request); curl_setopt($ch, CURLOPT_FILE, STDOUT); if (200 === $response->info['http_code']) { $outputFile->setSuccess(); } return $result; }); }
/** * @param Package\PackageInterface[] $packages * @param array $pluginConfig * @return void */ public function download(array $packages, array $pluginConfig) { $mh = curl_multi_init(); $unused = array(); $maxConns = $pluginConfig['maxConnections']; for ($i = 0; $i < $maxConns; ++$i) { $unused[] = curl_init(); } /// @codeCoverageIgnoreStart if (function_exists('curl_share_init')) { $sh = curl_share_init(); curl_share_setopt($sh, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); foreach ($unused as $ch) { curl_setopt($ch, CURLOPT_SHARE, $sh); } } if (function_exists('curl_multi_setopt')) { if ($pluginConfig['pipeline']) { curl_multi_setopt($mh, CURLMOPT_PIPELINING, true); } } /// @codeCoverageIgnoreEnd $cachedir = rtrim($this->config->get('cache-files-dir'), '\\/'); $chFpMap = array(); $running = 0; //ref type $remains = 0; //ref type $this->totalCnt = count($packages); $this->successCnt = 0; $this->failureCnt = 0; $this->io->write(" Prefetch start: <comment>success: {$this->successCnt}, failure: {$this->failureCnt}, total: {$this->totalCnt}</comment>"); do { // prepare curl resources while (count($unused) > 0 && count($packages) > 0) { $package = array_pop($packages); $filepath = $cachedir . DIRECTORY_SEPARATOR . static::getCacheKey($package); if (file_exists($filepath)) { ++$this->successCnt; continue; } $ch = array_pop($unused); // make file resource $chFpMap[(int) $ch] = $outputFile = new OutputFile($filepath); // make url $url = $package->getDistUrl(); $host = parse_url($url, PHP_URL_HOST) ?: ''; $request = new Aspects\HttpGetRequest($host, $url, $this->io); $request->verbose = $pluginConfig['verbose']; if (in_array($package->getName(), $pluginConfig['privatePackages'])) { $request->maybePublic = false; } else { $request->maybePublic = (bool) preg_match('%^(?:https|git)://github\\.com%', $package->getSourceUrl()); } $onPreDownload = Factory::getPreEvent($request); $onPreDownload->notify(); $opts = $request->getCurlOpts(); if ($pluginConfig['insecure']) { $opts[CURLOPT_SSL_VERIFYPEER] = false; } if (!empty($pluginConfig['capath'])) { $opts[CURLOPT_CAPATH] = $pluginConfig['capath']; } unset($opts[CURLOPT_ENCODING]); unset($opts[CURLOPT_USERPWD]); // ParallelDownloader doesn't support private packages. curl_setopt_array($ch, $opts); curl_setopt($ch, CURLOPT_FILE, $outputFile->getPointer()); curl_multi_add_handle($mh, $ch); } // wait for any event do { // start multi download do { $stat = curl_multi_exec($mh, $running); } while ($stat === CURLM_CALL_MULTI_PERFORM); switch (curl_multi_select($mh, 5)) { case -1: usleep(250); // fall through // fall through case 0: continue 2; default: do { $stat = curl_multi_exec($mh, $running); } while ($stat === CURLM_CALL_MULTI_PERFORM); do { if ($raised = curl_multi_info_read($mh, $remains)) { $ch = $raised['handle']; $errno = curl_errno($ch); $info = curl_getinfo($ch); curl_setopt($ch, CURLOPT_FILE, STDOUT); $index = (int) $ch; $outputFile = $chFpMap[$index]; unset($chFpMap[$index]); if (CURLE_OK === $errno && 200 === $info['http_code']) { ++$this->successCnt; } else { ++$this->failureCnt; $outputFile->setFailure(); } unset($outputFile); $this->io->write($this->makeDownloadingText($info['url'])); curl_multi_remove_handle($mh, $ch); $unused[] = $ch; } } while ($remains > 0); if (count($packages) > 0) { break 2; } } } while ($running); } while (count($packages) > 0); $this->io->write(" Finished: <comment>success: {$this->successCnt}, failure: {$this->failureCnt}, total: {$this->totalCnt}</comment>"); foreach ($unused as $ch) { curl_close($ch); } curl_multi_close($mh); }