diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php index dad74fbc4..ef9ae8e6e 100644 --- a/src/Composer/Downloader/FileDownloader.php +++ b/src/Composer/Downloader/FileDownloader.php @@ -11,10 +11,10 @@ namespace Composer\Downloader; -use Composer\Util\RemoteFilesystem; use Composer\IO\IOInterface; use Composer\Package\PackageInterface; use Composer\Util\Filesystem; +use Composer\Util\RemoteFilesystem; /** * Base downloader for file packages @@ -76,7 +76,7 @@ abstract class FileDownloader implements DownloaderInterface } $rfs = new RemoteFilesystem($this->io); - $rfs->copy($package->getSourceUrl(), $fileName, $url); + $rfs->copy($package->getSourceUrl(), $url, $fileName); $this->io->write(''); if (!file_exists($fileName)) { diff --git a/src/Composer/Repository/Vcs/VcsDriver.php b/src/Composer/Repository/Vcs/VcsDriver.php index 5a25fc1be..7008f41be 100644 --- a/src/Composer/Repository/Vcs/VcsDriver.php +++ b/src/Composer/Repository/Vcs/VcsDriver.php @@ -14,6 +14,7 @@ namespace Composer\Repository\Vcs; use Composer\IO\IOInterface; use Composer\Util\ProcessExecutor; +use Composer\Util\RemoteFilesystem; /** * A driver implementation for driver with authorization interaction. @@ -25,9 +26,6 @@ abstract class VcsDriver protected $url; protected $io; protected $process; - private $firstCall; - private $contentUrl; - private $content; /** * Constructor. @@ -41,7 +39,6 @@ abstract class VcsDriver $this->url = $url; $this->io = $io; $this->process = $process ?: new ProcessExecutor; - $this->firstCall = true; } /** @@ -68,85 +65,7 @@ abstract class VcsDriver */ protected function getContents($url) { - $this->contentUrl = $url; - $auth = $this->io->getAuthorization($this->url); - $params = array(); - - // add authorization to curl options - if ($this->io->hasAuthorization($this->url)) { - $authStr = base64_encode($auth['username'] . ':' . $auth['password']); - $params['http'] = array('header' => "Authorization: Basic $authStr\r\n"); - } else if (null !== $this->io->getLastUsername()) { - $authStr = base64_encode($this->io->getLastUsername() . ':' . $this->io->getLastPassword()); - $params['http'] = array('header' => "Authorization: Basic $authStr\r\n"); - $this->io->setAuthorization($this->url, $this->io->getLastUsername(), $this->io->getLastPassword()); - } - - $ctx = stream_context_create($params); - stream_context_set_params($ctx, array("notification" => array($this, 'callbackGet'))); - - $content = @file_get_contents($url, false, $ctx); - - // content get after authorization - if (false === $content) { - $content = $this->content; - $this->content = null; - $this->contentUrl = null; - } - - return $content; - } - - /** - * Get notification action. - * - * @param integer $notificationCode The notification code - * @param integer $severity The severity level - * @param string $message The message - * @param integer $messageCode The message code - * @param integer $bytesTransferred The loaded size - * @param integer $bytesMax The total size - */ - protected function callbackGet($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax) - { - switch ($notificationCode) { - case STREAM_NOTIFY_AUTH_REQUIRED: - case STREAM_NOTIFY_FAILURE: - // for private repository returning 404 error when the authorization is incorrect - $auth = $this->io->getAuthorization($this->url); - $ps = $this->firstCall && 404 === $messageCode - && null === $this->io->getLastUsername() - && null === $auth['username']; - - if (404 === $messageCode && !$this->firstCall) { - throw new \RuntimeException("The '" . $this->contentUrl . "' URL not found"); - } - - $this->firstCall = false; - - // get authorization informations - if (401 === $messageCode || $ps) { - if (!$this->io->isInteractive()) { - $mess = "The '" . $this->contentUrl . "' URL not found"; - - if (401 === $code || $ps) { - $mess = "The '" . $this->contentUrl . "' URL required the authorization.\nYou must be used the interactive console"; - } - - throw new \RuntimeException($mess); - } - - $this->io->write(array('', "Authorization for " . $this->contentUrl . ":")); - $username = $this->io->ask(' Username: '); - $password = $this->io->askAndHideAnswer(' Password: '); - $this->io->setAuthorization($this->url, $username, $password); - - $this->content = $this->getContents($this->contentUrl); - } - break; - - default: - break; - } + $rfs = new RemoteFilesystem($this->io); + return $rfs->getContents($this->url, $url, false); } } diff --git a/src/Composer/Util/RemoteFilesystem.php b/src/Composer/Util/RemoteFilesystem.php index d24d0a4ea..8fdc47b23 100644 --- a/src/Composer/Util/RemoteFilesystem.php +++ b/src/Composer/Util/RemoteFilesystem.php @@ -19,11 +19,14 @@ use Composer\IO\IOInterface; */ class RemoteFilesystem { - protected $io; + private $io; + private $firstCall; private $bytesMax; private $originUrl; private $fileUrl; private $fileName; + private $content; + private $progess; /** * Constructor. @@ -38,20 +41,52 @@ class RemoteFilesystem /** * Copy the remote file in local. * - * @param string $originUrl The origin URL - * @param string $fileName The local filename - * @param string $fileUrl The file URL + * @param string $originUrl The orgin URL + * @param string $fileUrl The file URL + * @param string $fileName the local filename + * @param boolean $progess Display the progression + */ + public function copy($originUrl, $fileUrl, $fileName, $progess = true) + { + $this->get($originUrl, $fileUrl, $fileName, $progess); + } + + /** + * Get the content. + * + * @param string $originUrl The orgin URL + * @param string $fileUrl The file URL + * @param boolean $progess Display the progression + * + * @return false|string The content + */ + public function getContents($originUrl, $fileUrl, $progess = true) + { + $this->get($originUrl, $fileUrl, null, $progess); + + return $this->content; + } + + /** + * 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 $progess Display the progression * - * @throws \RuntimeException When opensll extension is disabled + * @throws \RuntimeException When the openssl extension is disabled */ - public function copy($originUrl, $fileName, $fileUrl) + protected function get($originUrl, $fileUrl, $fileName = null, $progess = true) { $this->firstCall = true; - $this->originUrl = $originUrl; - $this->fileName = $fileName; - $this->fileUrl = $fileUrl; $this->bytesMax = 0; - + $this->content = null; + $this->originUrl = $originUrl; + $this->fileUrl = $fileUrl; + $this->fileName = $fileName; + $this->progress = $progess; + // Handle system proxy $params = array('http' => array()); @@ -69,18 +104,35 @@ class RemoteFilesystem ); } + // add authorization in context if ($this->io->hasAuthorization($originUrl)) { $auth = $this->io->getAuthorization($originUrl); $authStr = base64_encode($auth['username'] . ':' . $auth['password']); $params['http'] = array_merge($params['http'], array('header' => "Authorization: Basic $authStr\r\n")); + + } else if (null !== $this->io->getLastUsername()) { + $authStr = base64_encode($this->io->getLastUsername() . ':' . $this->io->getLastPassword()); + $params['http'] = array('header' => "Authorization: Basic $authStr\r\n"); + $this->io->setAuthorization($originUrl, $this->io->getLastUsername(), $this->io->getLastPassword()); } $ctx = stream_context_create($params); stream_context_set_params($ctx, array("notification" => array($this, 'callbackGet'))); - $this->io->overwrite(" Downloading: connection...", false); - @copy($fileUrl, $fileName, $ctx); - $this->io->overwrite(" Downloading", false); + if ($this->progress) { + $this->io->overwrite(" Downloading: connection...", false); + } + + if (null !== $fileName) { + @copy($fileUrl, $fileName, $ctx); + + } else { + $this->content = @file_get_contents($fileUrl, false, $ctx); + } + + if ($this->progress) { + $this->io->overwrite(" Downloading", false); + } } /** @@ -100,8 +152,7 @@ class RemoteFilesystem case STREAM_NOTIFY_FAILURE: // for private repository returning 404 error when the authorization is incorrect $auth = $this->io->getAuthorization($this->originUrl); - $ps = $this->firstCall && 404 === $messageCode - && null === $auth['username']; + $ps = $this->firstCall && 404 === $messageCode && null === $auth['username']; if (404 === $messageCode && !$this->firstCall) { throw new \RuntimeException("The '" . $this->fileUrl . "' URL not found"); @@ -112,21 +163,21 @@ class RemoteFilesystem // get authorization informations if (401 === $messageCode || $ps) { if (!$this->io->isInteractive()) { - $mess = "The '" . $this->fileUrl . "' URL not found"; + $mess = "The '" . $this->fileUrl . "' URL was not found"; if (401 === $code || $ps) { - $mess = "The '" . $this->fileUrl . "' URL required the authorization.\nYou must be used the interactive console"; + $mess = "The '" . $this->fileUrl . "' URL required the authorization.\nYou must be using the interactive console"; } throw new \RuntimeException($mess); } - $this->io->overwrite(' Authorization required:'); + $this->io->overwrite(' Authorization required (' .$this->getHostname($this->fileUrl).'):'); $username = $this->io->ask(' Username: '); $password = $this->io->askAndHideAnswer(' Password: '); $this->io->setAuthorization($this->originUrl, $username, $password); - $this->copy($this->originUrl, $this->fileName, $this->fileUrl); + $this->content = $this->get($this->originUrl, $this->fileUrl, $this->fileName, $this->progess); } break; @@ -137,7 +188,7 @@ class RemoteFilesystem break; case STREAM_NOTIFY_PROGRESS: - if ($this->bytesMax > 0) { + if ($this->bytesMax > 0 && $this->progress) { $progression = 0; if ($this->bytesMax > 0) { @@ -154,4 +205,19 @@ class RemoteFilesystem break; } } + + /** + * Get the hostname. + * + * @param string $url The file URL + * + * @return string The hostname + */ + protected function getHostname($url) + { + $host = substr($url, strpos($url, '://') + 3); + $host = substr($host, 0, strpos($host, '/')); + + return $host; + } } \ No newline at end of file