protected function execute(InputInterface $input, OutputInterface $output) { $this->rfs = new RemoteFilesystem($this->getIO()); $output->write('Checking platform settings: '); $this->outputResult($output, $this->checkPlatform()); $output->write('Checking http connectivity: '); $this->outputResult($output, $this->checkHttp()); $opts = stream_context_get_options(StreamContextFactory::getContext()); if (!empty($opts['http']['proxy'])) { $output->write('Checking HTTP proxy: '); $this->outputResult($output, $this->checkHttpProxy()); $output->write('Checking HTTPS proxy support for request_fulluri: '); $this->outputResult($output, $this->checkHttpsProxyFullUriRequestParam()); } $composer = $this->getComposer(false); if ($composer) { $output->write('Checking composer.json: '); $this->outputResult($output, $this->checkComposerSchema()); } if ($composer) { $config = $composer->getConfig(); } else { $config = Factory::createConfig(); } if ($oauth = $config->get('github-oauth')) { foreach ($oauth as $domain => $token) { $output->write('Checking ' . $domain . ' oauth access: '); $this->outputResult($output, $this->checkGithubOauth($domain, $token)); } } $output->write('Checking composer version: '); $this->outputResult($output, $this->checkVersion()); return $this->failures; }
/** * {@inheritdoc} */ protected function execute(InputInterface $input, OutputInterface $output) { $composer = $this->getComposer(false); if ($composer) { $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'diagnose', $input, $output); $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); $this->getIO()->write('Checking composer.json: ', false); $this->outputResult($this->checkComposerSchema()); } if ($composer) { $config = $composer->getConfig(); } else { $config = Factory::createConfig(); } $this->rfs = new RemoteFilesystem($this->getIO(), $config); $this->process = new ProcessExecutor($this->getIO()); $this->getIO()->write('Checking platform settings: ', false); $this->outputResult($this->checkPlatform()); $this->getIO()->write('Checking git settings: ', false); $this->outputResult($this->checkGit()); $this->getIO()->write('Checking http connectivity: ', false); $this->outputResult($this->checkHttp()); $opts = stream_context_get_options(StreamContextFactory::getContext('http://example.org')); if (!empty($opts['http']['proxy'])) { $this->getIO()->write('Checking HTTP proxy: ', false); $this->outputResult($this->checkHttpProxy()); $this->getIO()->write('Checking HTTP proxy support for request_fulluri: ', false); $this->outputResult($this->checkHttpProxyFullUriRequestParam()); $this->getIO()->write('Checking HTTPS proxy support for request_fulluri: ', false); $this->outputResult($this->checkHttpsProxyFullUriRequestParam()); } if ($oauth = $config->get('github-oauth')) { foreach ($oauth as $domain => $token) { $this->getIO()->write('Checking ' . $domain . ' oauth access: ', false); $this->outputResult($this->checkGithubOauth($domain, $token)); } } else { $this->getIO()->write('Checking github.com rate limit: ', false); try { $rate = $this->getGithubRateLimit('github.com'); $this->outputResult(true); if (10 > $rate['remaining']) { $this->getIO()->write('<warning>WARNING</warning>'); $this->getIO()->write(sprintf('<comment>Github has a rate limit on their API. ' . 'You currently have <options=bold>%u</options=bold> ' . 'out of <options=bold>%u</options=bold> requests left.' . PHP_EOL . 'See https://developer.github.com/v3/#rate-limiting and also' . PHP_EOL . ' https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens</comment>', $rate['remaining'], $rate['limit'])); } } catch (\Exception $e) { if ($e instanceof TransportException && $e->getCode() === 401) { $this->outputResult('<comment>The oauth token for github.com seems invalid, run "composer config --global --unset github-oauth.github.com" to remove it</comment>'); } else { $this->outputResult($e); } } } $this->getIO()->write('Checking disk free space: ', false); $this->outputResult($this->checkDiskSpace($config)); $this->getIO()->write('Checking composer version: ', false); $this->outputResult($this->checkVersion()); return $this->failures; }
/** * Reads json file. * * @param string $json path or json string * * @return array */ public function read() { $ctx = StreamContextFactory::getContext(array('http' => array('header' => 'User-Agent: Composer/' . Composer::VERSION . "\r\n"))); $json = file_get_contents($this->path, false, $ctx); if (!$json) { throw new \RuntimeException('Could not read ' . $this->path . ', you are probably offline'); } return static::parseJson($json); }
protected function initialize() { parent::initialize(); set_error_handler(function ($severity, $message, $file, $line) { throw new \ErrorException($message, $severity, $severity, $file, $line); }); $this->streamContext = StreamContextFactory::getContext(); $this->fetchFromServer(); restore_error_handler(); }
protected function execute(InputInterface $input, OutputInterface $output) { $ctx = StreamContextFactory::getContext(); $latest = trim(file_get_contents('http://getcomposer.org/version', false, $ctx)); if (Composer::VERSION !== $latest) { $output->writeln(sprintf("Updating to version <info>%s</info>.", $latest)); $remoteFilename = 'http://getcomposer.org/composer.phar'; $localFilename = $_SERVER['argv'][0]; copy($remoteFilename, $localFilename, $ctx); } else { $output->writeln("<info>You are using the latest composer version.</info>"); } }
public function testSSLProxy() { $_SERVER['http_proxy'] = 'https://proxyserver/'; if (extension_loaded('openssl')) { $context = StreamContextFactory::getContext(); $options = stream_context_get_options($context); $this->assertSame(array('http' => array('proxy' => 'ssl://proxyserver/', 'request_fulluri' => true)), $options); } else { try { StreamContextFactory::getContext(); $this->fail(); } catch (\Exception $e) { $this->assertInstanceOf('RuntimeException', $e); } } }
protected function execute(InputInterface $input, OutputInterface $output) { $composer = $this->getComposer(false); if ($composer) { $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'diagnose', $input, $output); $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); $output->write('Checking composer.json: '); $this->outputResult($output, $this->checkComposerSchema()); } if ($composer) { $config = $composer->getConfig(); } else { $config = Factory::createConfig(); } $this->rfs = new RemoteFilesystem($this->getIO(), $config); $this->process = new ProcessExecutor($this->getIO()); $output->write('Checking platform settings: '); $this->outputResult($output, $this->checkPlatform()); $output->write('Checking git settings: '); $this->outputResult($output, $this->checkGit()); $output->write('Checking http connectivity: '); $this->outputResult($output, $this->checkHttp()); $opts = stream_context_get_options(StreamContextFactory::getContext('http://example.org')); if (!empty($opts['http']['proxy'])) { $output->write('Checking HTTP proxy: '); $this->outputResult($output, $this->checkHttpProxy()); $output->write('Checking HTTP proxy support for request_fulluri: '); $this->outputResult($output, $this->checkHttpProxyFullUriRequestParam()); $output->write('Checking HTTPS proxy support for request_fulluri: '); $this->outputResult($output, $this->checkHttpsProxyFullUriRequestParam()); } if ($oauth = $config->get('github-oauth')) { foreach ($oauth as $domain => $token) { $output->write('Checking ' . $domain . ' oauth access: '); $this->outputResult($output, $this->checkGithubOauth($domain, $token)); } } $output->write('Checking disk free space: '); $this->outputResult($output, $this->checkDiskSpace($config)); $output->write('Checking composer version: '); $this->outputResult($output, $this->checkVersion()); return $this->failures; }
protected function get($originUrl, $fileUrl, $additionalOptions = array(), $fileName = null, $progress = true) { if (strpos($originUrl, '.github.com') === strlen($originUrl) - 11) { $originUrl = 'github.com'; } $this->bytesMax = 0; $this->originUrl = $originUrl; $this->fileUrl = $fileUrl; $this->fileName = $fileName; $this->progress = $progress; $this->lastProgress = null; $this->retryAuthFailure = true; $this->lastHeaders = array(); if (preg_match('{^https?://(.+):(.+)@([^/]+)}i', $fileUrl, $match)) { $this->io->setAuthentication($originUrl, urldecode($match[1]), urldecode($match[2])); } if (isset($additionalOptions['retry-auth-failure'])) { $this->retryAuthFailure = (bool) $additionalOptions['retry-auth-failure']; unset($additionalOptions['retry-auth-failure']); } $options = $this->getOptionsForUrl($originUrl, $additionalOptions); if ($this->io->isDebug()) { $this->io->writeError((substr($fileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $fileUrl); } if (isset($options['github-token'])) { $fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token=' . $options['github-token']; unset($options['github-token']); } if (isset($options['http'])) { $options['http']['ignore_errors'] = true; } $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet'))); if ($this->progress) { $this->io->writeError(" Downloading: <comment>Connecting...</comment>", false); } $errorMessage = ''; $errorCode = 0; $result = false; set_error_handler(function ($code, $msg) use(&$errorMessage) { if ($errorMessage) { $errorMessage .= "\n"; } $errorMessage .= preg_replace('{^file_get_contents\\(.*?\\): }', '', $msg); }); try { $result = file_get_contents($fileUrl, false, $ctx); } catch (\Exception $e) { if ($e instanceof TransportException && !empty($http_response_header[0])) { $e->setHeaders($http_response_header); } if ($e instanceof TransportException && $result !== false) { $e->setResponse($result); } $result = false; } if ($errorMessage && !ini_get('allow_url_fopen')) { $errorMessage = 'allow_url_fopen must be enabled in php.ini (' . $errorMessage . ')'; } restore_error_handler(); if (isset($e) && !$this->retry) { throw $e; } if (!empty($http_response_header[0]) && preg_match('{^HTTP/\\S+ ([45]\\d\\d)}i', $http_response_header[0], $match)) { $errorCode = $match[1]; if (!$this->retry) { $e = new TransportException('The "' . $this->fileUrl . '" file could not be downloaded (' . $http_response_header[0] . ')', $errorCode); $e->setHeaders($http_response_header); $e->setResponse($result); throw $e; } $result = false; } if ($result && extension_loaded('zlib') && substr($fileUrl, 0, 4) === 'http') { $decode = false; foreach ($http_response_header as $header) { if (preg_match('{^content-encoding: *gzip *$}i', $header)) { $decode = true; continue; } elseif (preg_match('{^HTTP/}i', $header)) { $decode = false; } } if ($decode) { if (version_compare(PHP_VERSION, '5.4.0', '>=')) { $result = zlib_decode($result); } else { $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,' . base64_encode($result)); } if (!$result) { throw new TransportException('Failed to decode zlib stream'); } } } if ($this->progress && !$this->retry) { $this->io->overwriteError(" Downloading: <comment>100%</comment>"); } if (false !== $result && null !== $fileName) { if ('' === $result) { throw new TransportException('"' . $this->fileUrl . '" appears broken, and returned an empty 200 response'); } $errorMessage = ''; set_error_handler(function ($code, $msg) use(&$errorMessage) { if ($errorMessage) { $errorMessage .= "\n"; } $errorMessage .= preg_replace('{^file_put_contents\\(.*?\\): }', '', $msg); }); $result = (bool) file_put_contents($fileName, $result); restore_error_handler(); if (false === $result) { throw new TransportException('The "' . $this->fileUrl . '" file could not be written to ' . $fileName . ': ' . $errorMessage); } } if ($this->retry) { $this->retry = false; $result = $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress); $authHelper = new AuthHelper($this->io, $this->config); $authHelper->storeAuth($this->originUrl, $this->storeAuth); $this->storeAuth = false; return $result; } if (false === $result) { $e = new TransportException('The "' . $this->fileUrl . '" file could not be downloaded: ' . $errorMessage, $errorCode); if (!empty($http_response_header[0])) { $e->setHeaders($http_response_header); } throw $e; } if (!empty($http_response_header[0])) { $this->lastHeaders = $http_response_header; } return $result; }
public function notifyInstalls() { foreach ($this->notifiablePackages as $repoUrl => $packages) { // non-batch API, deprecated if (strpos($repoUrl, '%package%')) { foreach ($packages as $package) { $url = str_replace('%package%', $package->getPrettyName(), $repoUrl); $params = array('version' => $package->getPrettyVersion(), 'version_normalized' => $package->getVersion()); $opts = array('http' => array('method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => http_build_query($params, '', '&'), 'timeout' => 3)); $context = StreamContextFactory::getContext($opts); @file_get_contents($url, false, $context); } continue; } $postData = array('downloads' => array()); foreach ($packages as $package) { $postData['downloads'][] = array('name' => $package->getPrettyName(), 'version' => $package->getVersion()); } $opts = array('http' => array('method' => 'POST', 'header' => 'Content-Type: application/json', 'content' => json_encode($postData), 'timeout' => 6)); $context = StreamContextFactory::getContext($opts); @file_get_contents($repoUrl, false, $context); } $this->reset(); }
/** * Get file content or copy action. * * @param string $originUrl The origin URL * @param string $fileUrl The file URL * @param array $additionalOptions context options * @param string $fileName the local filename * @param boolean $progress Display the progression * * @throws TransportException|\Exception * @throws TransportException When the file could not be downloaded * * @return bool|string */ protected function get($originUrl, $fileUrl, $additionalOptions = array(), $fileName = null, $progress = true) { $this->bytesMax = 0; $this->originUrl = $originUrl; $this->fileUrl = $fileUrl; $this->fileName = $fileName; $this->progress = $progress; $this->lastProgress = null; // capture username/password from URL if there is one if (preg_match('{^https?://(.+):(.+)@([^/]+)}i', $fileUrl, $match)) { $this->io->setAuthentication($originUrl, urldecode($match[1]), urldecode($match[2])); } $options = $this->getOptionsForUrl($originUrl, $additionalOptions); if ($this->io->isDebug()) { $this->io->write((substr($fileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $fileUrl); } if (isset($options['github-token'])) { $fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token=' . $options['github-token']; unset($options['github-token']); } $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet'))); if ($this->progress) { $this->io->write(" Downloading: <comment>connection...</comment>", false); } $errorMessage = ''; $errorCode = 0; $result = false; set_error_handler(function ($code, $msg) use(&$errorMessage) { if ($errorMessage) { $errorMessage .= "\n"; } $errorMessage .= preg_replace('{^file_get_contents\\(.*?\\): }', '', $msg); }); try { $result = file_get_contents($fileUrl, false, $ctx); } catch (\Exception $e) { if ($e instanceof TransportException && !empty($http_response_header[0])) { $e->setHeaders($http_response_header); } } if ($errorMessage && !ini_get('allow_url_fopen')) { $errorMessage = 'allow_url_fopen must be enabled in php.ini (' . $errorMessage . ')'; } restore_error_handler(); if (isset($e) && !$this->retry) { throw $e; } // fix for 5.4.0 https://bugs.php.net/bug.php?id=61336 if (!empty($http_response_header[0]) && preg_match('{^HTTP/\\S+ ([45]\\d\\d)}i', $http_response_header[0], $match)) { $result = false; $errorCode = $match[1]; } // decode gzip if ($result && extension_loaded('zlib') && substr($fileUrl, 0, 4) === 'http') { $decode = false; foreach ($http_response_header as $header) { if (preg_match('{^content-encoding: *gzip *$}i', $header)) { $decode = true; continue; } elseif (preg_match('{^HTTP/}i', $header)) { $decode = false; } } if ($decode) { if (version_compare(PHP_VERSION, '5.4.0', '>=')) { $result = zlib_decode($result); } else { // work around issue with gzuncompress & co that do not work with all gzip checksums $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,' . base64_encode($result)); } } } if ($this->progress) { $this->io->overwrite(" Downloading: <comment>100%</comment>"); } // handle copy command if download was successful if (false !== $result && null !== $fileName) { if ('' === $result) { throw new TransportException('"' . $this->fileUrl . '" appears broken, and returned an empty 200 response'); } $errorMessage = ''; set_error_handler(function ($code, $msg) use(&$errorMessage) { if ($errorMessage) { $errorMessage .= "\n"; } $errorMessage .= preg_replace('{^file_put_contents\\(.*?\\): }', '', $msg); }); $result = (bool) file_put_contents($fileName, $result); restore_error_handler(); if (false === $result) { throw new TransportException('The "' . $this->fileUrl . '" file could not be written to ' . $fileName . ': ' . $errorMessage); } } if ($this->retry) { $this->retry = false; return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress); } if (false === $result) { $e = new TransportException('The "' . $this->fileUrl . '" file could not be downloaded: ' . $errorMessage, $errorCode); if (!empty($http_response_header[0])) { $e->setHeaders($http_response_header); } throw $e; } return $result; }
/** * @author Markus Tacker <*****@*****.**> */ public function testEnsureThatfixHttpHeaderFieldMovesContentTypeToEndOfOptions() { $options = array('http' => array('header' => "X-Foo: bar\r\nContent-Type: application/json\r\nAuthorization: Basic aW52YWxpZA==")); $expectedOptions = array('http' => array('header' => array("X-Foo: bar", "Authorization: Basic aW52YWxpZA==", "Content-Type: application/json"))); $context = StreamContextFactory::getContext($options); $ctxoptions = stream_context_get_options($context); $this->assertEquals(join("\n", $ctxoptions['http']['header']), join("\n", $expectedOptions['http']['header'])); }
/** * @dataProvider dataSSLProxy */ public function testSSLProxy($expected, $proxy) { $_SERVER['http_proxy'] = $proxy; if (extension_loaded('openssl')) { $context = StreamContextFactory::getContext(); $options = stream_context_get_options($context); $this->assertEquals(array('http' => array( 'proxy' => $expected, 'request_fulluri' => true, )), $options); } else { try { StreamContextFactory::getContext(); $this->fail(); } catch (\Exception $e) { $this->assertInstanceOf('RuntimeException', $e); } } }
/** * Get file content or copy action. * * @param string $originUrl The orgin URL * @param string $fileUrl The file URL * @param string $fileName the local filename * @param boolean $progress Display the progression * @param boolean $firstCall Whether this is the first attempt at fetching this resource * * @throws \RuntimeException When the file could not be downloaded */ protected function get($originUrl, $fileUrl, $fileName = null, $progress = true, $firstCall = true) { $this->firstCall = $firstCall; $this->bytesMax = 0; $this->result = null; $this->originUrl = $originUrl; $this->fileUrl = $fileUrl; $this->fileName = $fileName; $this->progress = $progress; $this->lastProgress = null; $options = $this->getOptionsForUrl($originUrl); $ctx = StreamContextFactory::getContext($options, array('notification' => array($this, 'callbackGet'))); if ($this->progress) { $this->io->overwrite(" Downloading: <comment>connection...</comment>", false); } if (null !== $fileName) { $result = @copy($fileUrl, $fileName, $ctx); } else { $result = @file_get_contents($fileUrl, false, $ctx); } // avoid overriding if content was loaded by a sub-call to get() if (null === $this->result) { $this->result = $result; } if ($this->progress) { $this->io->overwrite(" Downloading", false); } if (false === $this->result) { throw new \RuntimeException("The '{$fileUrl}' file could not be downloaded"); } }
/** * Get file content or copy action. * * @param string $originUrl The origin URL * @param string $fileUrl The file URL * @param string $fileName the local filename * @param boolean $progress Display the progression * * @throws TransportException When the file could not be downloaded */ protected function get($originUrl, $fileUrl, $fileName = null, $progress = true) { $this->bytesMax = 0; $this->result = null; $this->originUrl = $originUrl; $this->fileUrl = $fileUrl; $this->fileName = $fileName; $this->progress = $progress; $this->lastProgress = null; $options = $this->getOptionsForUrl($originUrl); $ctx = StreamContextFactory::getContext($options, array('notification' => array($this, 'callbackGet'))); if ($this->progress) { $this->io->write(" Downloading: <comment>connection...</comment>", false); } $result = @file_get_contents($fileUrl, false, $ctx); // fix for 5.4.0 https://bugs.php.net/bug.php?id=61336 if (!empty($http_response_header[0]) && preg_match('{^HTTP/\\S+ 404}i', $http_response_header[0])) { $result = false; } // decode gzip if (false !== $result && extension_loaded('zlib') && substr($fileUrl, 0, 4) === 'http') { $decode = false; foreach ($http_response_header as $header) { if (preg_match('{^content-encoding: *gzip *$}i', $header)) { $decode = true; continue; } elseif (preg_match('{^HTTP/}i', $header)) { $decode = false; } } if ($decode) { if (version_compare(PHP_VERSION, '5.4.0', '>=')) { $result = zlib_decode($result); } else { // work around issue with gzuncompress & co that do not work with all gzip checksums $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,' . base64_encode($result)); } } } if ($this->progress) { $this->io->overwrite(" Downloading: <comment>100%</comment>"); } // handle copy command if download was successful if (false !== $result && null !== $fileName) { $result = (bool) @file_put_contents($fileName, $result); if (false === $result) { throw new TransportException('The "' . $fileUrl . '" file could not be written to ' . $fileName); } } // avoid overriding if content was loaded by a sub-call to get() if (null === $this->result) { $this->result = $result; } if (false === $this->result) { throw new TransportException('The "' . $fileUrl . '" file could not be downloaded'); } }
/** * Get file content or copy action. * * @param string $originUrl The origin URL * @param string $fileUrl The file URL * @param array $additionalOptions context options * @param string $fileName the local filename * @param boolean $progress Display the progression * * @throws TransportException|\Exception * @throws TransportException When the file could not be downloaded * * @return bool|string */ protected function get($originUrl, $fileUrl, $additionalOptions = array(), $fileName = null, $progress = true) { if (strpos($originUrl, '.github.com') === strlen($originUrl) - 11) { $originUrl = 'github.com'; } $this->bytesMax = 0; $this->originUrl = $originUrl; $this->fileUrl = $fileUrl; $this->fileName = $fileName; $this->progress = $progress; $this->lastProgress = null; $this->retryAuthFailure = true; $this->lastHeaders = array(); // capture username/password from URL if there is one if (preg_match('{^https?://(.+):(.+)@([^/]+)}i', $fileUrl, $match)) { $this->io->setAuthentication($originUrl, urldecode($match[1]), urldecode($match[2])); } if (isset($additionalOptions['retry-auth-failure'])) { $this->retryAuthFailure = (bool) $additionalOptions['retry-auth-failure']; unset($additionalOptions['retry-auth-failure']); } $options = $this->getOptionsForUrl($originUrl, $additionalOptions); if ($this->io->isDebug()) { $this->io->writeError((substr($fileUrl, 0, 4) === 'http' ? 'Downloading ' : 'Reading ') . $fileUrl); } if (isset($options['github-token'])) { $fileUrl .= (false === strpos($fileUrl, '?') ? '?' : '&') . 'access_token=' . $options['github-token']; unset($options['github-token']); } if (isset($options['http'])) { $options['http']['ignore_errors'] = true; } if ($this->degradedMode && substr($fileUrl, 0, 21) === 'http://packagist.org/') { // access packagist using the resolved IPv4 instead of the hostname to force IPv4 protocol $fileUrl = 'http://' . gethostbyname('packagist.org') . substr($fileUrl, 20); } $ctx = StreamContextFactory::getContext($fileUrl, $options, array('notification' => array($this, 'callbackGet'))); if ($this->progress) { $this->io->writeError(" Downloading: <comment>Connecting...</comment>", false); } $errorMessage = ''; $errorCode = 0; $result = false; set_error_handler(function ($code, $msg) use(&$errorMessage) { if ($errorMessage) { $errorMessage .= "\n"; } $errorMessage .= preg_replace('{^file_get_contents\\(.*?\\): }', '', $msg); }); try { $result = file_get_contents($fileUrl, false, $ctx); } catch (\Exception $e) { if ($e instanceof TransportException && !empty($http_response_header[0])) { $e->setHeaders($http_response_header); } if ($e instanceof TransportException && $result !== false) { $e->setResponse($result); } $result = false; } if ($errorMessage && !ini_get('allow_url_fopen')) { $errorMessage = 'allow_url_fopen must be enabled in php.ini (' . $errorMessage . ')'; } restore_error_handler(); if (isset($e) && !$this->retry) { if (!$this->degradedMode && false !== strpos($e->getMessage(), 'Operation timed out')) { $this->degradedMode = true; $this->io->writeError(array('<error>' . $e->getMessage() . '</error>', '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>')); return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress); } throw $e; } // fail 4xx and 5xx responses and capture the response if (!empty($http_response_header[0]) && preg_match('{^HTTP/\\S+ ([45]\\d\\d)}i', $http_response_header[0], $match)) { $errorCode = $match[1]; if (!$this->retry) { $e = new TransportException('The "' . $this->fileUrl . '" file could not be downloaded (' . $http_response_header[0] . ')', $errorCode); $e->setHeaders($http_response_header); $e->setResponse($result); throw $e; } $result = false; } if ($this->progress && !$this->retry) { $this->io->overwriteError(" Downloading: <comment>100%</comment>"); } // decode gzip if ($result && extension_loaded('zlib') && substr($fileUrl, 0, 4) === 'http') { $decode = false; foreach ($http_response_header as $header) { if (preg_match('{^content-encoding: *gzip *$}i', $header)) { $decode = true; } elseif (preg_match('{^HTTP/}i', $header)) { // In case of redirects, http_response_headers contains the headers of all responses // so we reset the flag when a new response is being parsed as we are only interested in the last response $decode = false; } } if ($decode) { try { if (PHP_VERSION_ID >= 50400) { $result = zlib_decode($result); } else { // work around issue with gzuncompress & co that do not work with all gzip checksums $result = file_get_contents('compress.zlib://data:application/octet-stream;base64,' . base64_encode($result)); } if (!$result) { throw new TransportException('Failed to decode zlib stream'); } } catch (\Exception $e) { if ($this->degradedMode) { throw $e; } $this->degradedMode = true; $this->io->writeError(array('<error>Failed to decode response: ' . $e->getMessage() . '</error>', '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>')); return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress); } } } // handle copy command if download was successful if (false !== $result && null !== $fileName) { if ('' === $result) { throw new TransportException('"' . $this->fileUrl . '" appears broken, and returned an empty 200 response'); } $errorMessage = ''; set_error_handler(function ($code, $msg) use(&$errorMessage) { if ($errorMessage) { $errorMessage .= "\n"; } $errorMessage .= preg_replace('{^file_put_contents\\(.*?\\): }', '', $msg); }); $result = (bool) file_put_contents($fileName, $result); restore_error_handler(); if (false === $result) { throw new TransportException('The "' . $this->fileUrl . '" file could not be written to ' . $fileName . ': ' . $errorMessage); } } if ($this->retry) { $this->retry = false; $result = $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress); $authHelper = new AuthHelper($this->io, $this->config); $authHelper->storeAuth($this->originUrl, $this->storeAuth); $this->storeAuth = false; return $result; } if (false === $result) { $e = new TransportException('The "' . $this->fileUrl . '" file could not be downloaded: ' . $errorMessage, $errorCode); if (!empty($http_response_header[0])) { $e->setHeaders($http_response_header); } if (!$this->degradedMode && false !== strpos($e->getMessage(), 'Operation timed out')) { $this->degradedMode = true; $this->io->writeError(array('<error>' . $e->getMessage() . '</error>', '<error>Retrying with degraded mode, check https://getcomposer.org/doc/articles/troubleshooting.md#degraded-mode for more info</error>')); return $this->get($this->originUrl, $this->fileUrl, $additionalOptions, $this->fileName, $this->progress); } throw $e; } if (!empty($http_response_header[0])) { $this->lastHeaders = $http_response_header; } return $result; }
public function notifyInstalls(IOInterface $io) { foreach ($this->notifiablePackages as $repoUrl => $packages) { $repositoryName = parse_url($repoUrl, PHP_URL_HOST); if ($io->hasAuthentication($repositoryName)) { $auth = $io->getAuthentication($repositoryName); $authStr = base64_encode($auth['username'] . ':' . $auth['password']); $authHeader = 'Authorization: Basic ' . $authStr; } // non-batch API, deprecated if (strpos($repoUrl, '%package%')) { foreach ($packages as $package) { $url = str_replace('%package%', $package->getPrettyName(), $repoUrl); $params = array('version' => $package->getPrettyVersion(), 'version_normalized' => $package->getVersion()); $opts = array('http' => array('method' => 'POST', 'header' => array('Content-type: application/x-www-form-urlencoded'), 'content' => http_build_query($params, '', '&'), 'timeout' => 3)); if (isset($authHeader)) { $opts['http']['header'][] = $authHeader; } $context = StreamContextFactory::getContext($url, $opts); @file_get_contents($url, false, $context); } continue; } $postData = array('downloads' => array()); foreach ($packages as $package) { $postData['downloads'][] = array('name' => $package->getPrettyName(), 'version' => $package->getVersion()); } $opts = array('http' => array('method' => 'POST', 'header' => array('Content-Type: application/json'), 'content' => json_encode($postData), 'timeout' => 6)); if (isset($authHeader)) { $opts['http']['header'][] = $authHeader; } $context = StreamContextFactory::getContext($repoUrl, $opts); @file_get_contents($repoUrl, false, $context); } $this->reset(); }
/** * Fetch certificate common name and fingerprint for validation of SAN. * * @todo Remove when PHP 5.6 is minimum supported version. */ private function getCertificateCnAndFp($url, $options) { if (PHP_VERSION_ID >= 50600) { throw new \BadMethodCallException(sprintf('%s must not be used on PHP >= 5.6', __METHOD__)); } $context = StreamContextFactory::getContext($url, $options, array('options' => array('ssl' => array('capture_peer_cert' => true, 'verify_peer' => false)))); // Ideally this would just use stream_socket_client() to avoid sending a // HTTP request but that does not capture the certificate. if (false === ($handle = @fopen($url, 'rb', false, $context))) { return; } // Close non authenticated connection without reading any content. fclose($handle); $handle = null; $params = stream_context_get_params($context); if (!empty($params['options']['ssl']['peer_certificate'])) { $peerCertificate = $params['options']['ssl']['peer_certificate']; if (TlsHelper::checkCertificateHost($peerCertificate, parse_url($url, PHP_URL_HOST), $commonName)) { return array('cn' => $commonName, 'fp' => TlsHelper::getCertificateFingerprint($peerCertificate)); } } }
/** * Get file content or copy action. * * @param string $originUrl The orgin URL * @param string $fileUrl The file URL * @param string $fileName the local filename * @param boolean $progress Display the progression * @param boolean $firstCall Whether this is the first attempt at fetching this resource * * @throws TransportException When the file could not be downloaded */ protected function get($originUrl, $fileUrl, $fileName = null, $progress = true, $firstCall = true) { $this->firstCall = $firstCall; $this->bytesMax = 0; $this->result = null; $this->originUrl = $originUrl; $this->fileUrl = $fileUrl; $this->fileName = $fileName; $this->progress = $progress; $this->lastProgress = null; $options = $this->getOptionsForUrl($originUrl); $ctx = StreamContextFactory::getContext($options, array('notification' => array($this, 'callbackGet'))); if ($this->progress) { $this->io->write(" Downloading: <comment>connection...</comment>", false); } if (null !== $fileName) { $result = @copy($fileUrl, $fileName, $ctx); } else { $result = @file_get_contents($fileUrl, false, $ctx); } // fix for 5.4.0 https://bugs.php.net/bug.php?id=61336 if (!empty($http_response_header[0]) && preg_match('{^HTTP/\\S+ 404}i', $http_response_header[0])) { $result = false; } // avoid overriding if content was loaded by a sub-call to get() if (null === $this->result) { $this->result = $result; } if ($this->progress) { $this->io->overwrite(" Downloading", false); } if (false === $this->result) { throw new TransportException("The '{$fileUrl}' file could not be downloaded"); } }