diff --git a/src/Composer/Downloader/FileDownloader.php b/src/Composer/Downloader/FileDownloader.php
index df7556b2c..70d8243a0 100644
--- a/src/Composer/Downloader/FileDownloader.php
+++ b/src/Composer/Downloader/FileDownloader.php
@@ -77,19 +77,34 @@ abstract class FileDownloader implements DownloaderInterface
}
}
- $auth = $this->io->getAuthentification($package->getSourceUrl());
+ // Handle system proxy
+ $params = array('http' => array());
if (isset($_SERVER['HTTP_PROXY'])) {
// http(s):// is not supported in proxy
$proxy = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $_SERVER['HTTP_PROXY']);
-
+
if (0 === strpos($proxy, 'ssl:') && !extension_loaded('openssl')) {
throw new \RuntimeException('You must enable the openssl extension to use a proxy over https');
- }
+ }
+
+ $params['http'] = array(
+ 'proxy' => $proxy,
+ 'request_fulluri' => true,
+ );
}
+ if ($this->io->hasAuthentification($package->getSourceUrl())) {
+ $auth = $this->io->getAuthentification($package->getSourceUrl());
+ $authStr = base64_encode($auth['username'] . ':' . $auth['password']);
+ $params['http'] = array_merge($params['http'], array('header' => "Authorization: Basic $authStr\r\n"));
+ }
+
+ $ctx = stream_context_create($params);
+ stream_context_set_params($ctx, array("notification" => array($this, 'callbackGet')));
+
$this->io->overwrite(" Downloading: connection...", 80);
- $this->copy($url, $fileName, $auth['username'], $auth['password']);
+ copy($url, $fileName, $ctx);
$this->io->overwriteln(" Downloading", 80);
if (!file_exists($fileName)) {
@@ -120,7 +135,6 @@ abstract class FileDownloader implements DownloaderInterface
rmdir($contentDir);
}
- $this->io->overwrite('');
$this->io->writeln('');
}
@@ -144,92 +158,56 @@ abstract class FileDownloader implements DownloaderInterface
}
/**
- * Download notification action.
+ * Get notification action.
*
- * @param integer $sizeTotal The total size
- * @param integer $sizeLoaded The loaded size
+ * @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 callbackDownload($sizeTotal, $sizeLoaded)
+ protected function callbackGet($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax)
{
- if ($sizeTotal > 1024) {
- $progression = 0;
-
- if ($sizeTotal > 0) {
- $progression = ($sizeLoaded / $sizeTotal * 100);
- }
-
- $levels = array(0, 5, 10, 15, 20, 25, 30, 35, 40, 35, 50, 55, 60,
- 65, 70, 75, 80, 85, 90, 95, 100);
-
- $progression = round($progression, 0);
-
- if (in_array($progression, $levels)) {
- $this->io->overwrite(" Downloading: $progression%", 80);
- }
+ switch ($notificationCode) {
+ case STREAM_NOTIFY_AUTH_REQUIRED:
+ throw new \LogicException("Authentification is required");
+ break;
+
+ case STREAM_NOTIFY_FAILURE:
+ throw new \LogicException("File not found");
+ break;
+
+ case STREAM_NOTIFY_FILE_SIZE_IS:
+ if ($this->bytesMax < $bytesMax) {
+ $this->bytesMax = $bytesMax;
+ }
+ break;
+
+ case STREAM_NOTIFY_PROGRESS:
+ if ($this->bytesMax > 0) {
+ $progression = 0;
+
+ if ($this->bytesMax > 0) {
+ $progression = ($bytesTransferred / $this->bytesMax * 100);
+ }
+
+ $levels = array(0, 5, 10, 15, 20, 25, 30, 35, 40, 35, 50,
+ 55, 60, 65, 70, 75, 80, 85, 90, 95, 100);
+
+ $progression = round($progression, 0);
+
+ if (in_array($progression, $levels)) {
+ $this->io->overwrite(" Downloading: $progression%", 80);
+ }
+ }
+ break;
+
+ default:
+ break;
}
}
- /**
- * Copy the content in file directory.
- *
- * @param string $url The file URL
- * @param string $filename The local path
- * @param string $username The username
- * @param string $password The password
- */
- protected function copy($url, $filename, $username = null, $password = null)
- {
- // create directory
- if (!file_exists(dirname($filename))) {
- mkdir(dirname($filename), 0777, true);
- }
-
- $fh = fopen($filename, 'c+');
-
- // curl options
- $defaults = array(
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_BINARYTRANSFER => true,
- CURLOPT_BUFFERSIZE => 128000,
- CURLOPT_FOLLOWLOCATION => true,
- CURLOPT_NOPROGRESS => false,
- CURLOPT_PROGRESSFUNCTION => array($this, 'callbackDownload'),
- CURLOPT_URL => $url,
- CURLOPT_HTTPGET => true,
- CURLOPT_SSL_VERIFYPEER => false,
- CURLOPT_FILE => $fh,
- );
-
- // add authorization to curl options
- if (null !== $username && null !== $password) {
- $defaults[CURLOPT_USERPWD] = $username . ':' . $password;
- }
-
- // init curl
- $ch = curl_init();
-
- // curl options
- curl_setopt_array($ch, $defaults);
-
- // run curl
- $curl_result = curl_exec($ch);
- $curl_info = curl_getinfo($ch);
- $curl_errorCode = curl_errno($ch);
- $curl_error = curl_error($ch);
- $code = $curl_info['http_code'];
- $code = null ? 0 : $code;
-
- //close streams
- curl_close($ch);
- fclose($fh);
-
- if (200 !== $code) {
- return false;
- }
-
- return true;
- }
-
/**
* Extract file to directory
*
diff --git a/src/Composer/Repository/Vcs/VcsDriver.php b/src/Composer/Repository/Vcs/VcsDriver.php
index 27eafb3cd..857899cd5 100644
--- a/src/Composer/Repository/Vcs/VcsDriver.php
+++ b/src/Composer/Repository/Vcs/VcsDriver.php
@@ -24,6 +24,8 @@ abstract class VcsDriver
protected $url;
protected $io;
private $firstCall;
+ private $contentUrl;
+ private $content;
/**
* Constructor.
@@ -60,74 +62,87 @@ abstract class VcsDriver
*/
protected function getContents($url)
{
+ $this->contentUrl = $url;
$auth = $this->io->getAuthentification($this->url);
-
- // curl options
- $defaults = array(
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_BINARYTRANSFER => true,
- CURLOPT_BUFFERSIZE => 64000,
- CURLOPT_FOLLOWLOCATION => true,
- CURLOPT_NOPROGRESS => true,
- CURLOPT_URL => $url,
- CURLOPT_HTTPGET => true,
- CURLOPT_SSL_VERIFYPEER => false
- );
+ $params = array();
// add authorization to curl options
if ($this->io->hasAuthentification($this->url)) {
- $defaults[CURLOPT_USERPWD] = $auth['username'] . ':' . $auth['password'];
+ $authStr = base64_encode($auth['username'] . ':' . $auth['password']);
+ $params['http'] = array('header' => "Authorization: Basic $authStr\r\n");
} else if (null !== $this->io->getLastUsername()) {
- $defaults[CURLOPT_USERPWD] = $this->io->getLastUsername() . ':' . $this->io->getLastPassword();
+ $authStr = base64_encode($this->io->getLastUsername() . ':' . $this->io->getLastPassword());
+ $params['http'] = array('header' => "Authorization: Basic $authStr\r\n");
}
- // init curl
- $ch = curl_init();
- curl_setopt_array($ch, $defaults);
+ $ctx = stream_context_create($params);
+ stream_context_set_params($ctx, array("notification" => array($this, 'callbackGet')));
- // run curl
- $curl_result = curl_exec($ch);
- $curl_info = curl_getinfo($ch);
- $curl_errorCode = curl_errno($ch);
- $curl_error = curl_error($ch);
- $code = $curl_info['http_code'];
- $code = null ? 0 : $code;
+ $content = @file_get_contents($url, false, $ctx);
- //close streams
- curl_close($ch);
-
- // for private repository returning 404 error when the authentification is incorrect
- $ps = $this->firstCall && 404 === $code && null === $this->io->getLastUsername() && null === $auth['username'];
-
- if ($this->firstCall) {
- $this->firstCall = false;
+ // content get after authentification
+ if (false === $content) {
+ $content = $this->content;
+ $this->content = null;
+ $this->contentUrl = null;
}
- // auth required
- if (401 === $code || $ps) {
- if (!$this->io->isInteractive()) {
- $mess = "The '$url' URL not found";
+ return $content;
+ }
- if (401 === $code || $ps) {
- $mess = "The '$url' URL required the authentification.\nYou must be used the interactive console";
+ /**
+ * 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 authentification is incorrect
+ $auth = $this->io->getAuthentification($this->url);
+ $ps = $this->firstCall && 404 === $messageCode
+ && null === $this->io->getLastUsername()
+ && null === $auth['username'];
+
+ if (404 === $messageCode && !$this->firstCall) {
+ throw new \LogicException("The '" . $this->contentUrl . "' URL not found");
+ }
+
+ if ($this->firstCall) {
+ $this->firstCall = false;
}
- throw new \LogicException($mess);
- }
+ // get authentification 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 authentification.\nYou must be used the interactive console";
+ }
+
+ throw new \LogicException($mess);
+ }
- $this->io->writeln("Authorization required for " . $this->owner.'/' . $this->repository . ":");
- $username = $this->io->ask(' Username: ');
- $password = $this->io->askAndHideAnswer(' Password: ');
- $this->io->setAuthentification($this->url, $username, $password);
+ $this->io->writeln("Authorization for " . $this->contentUrl . ":");
+ $username = $this->io->ask(' Username: ');
+ $password = $this->io->askAndHideAnswer(' Password: ');
+ $this->io->setAuthentification($this->url, $username, $password);
- return $this->getContents($url);
+ $this->content = $this->getContents($this->contentUrl);
+ }
+ break;
+
+ default:
+ break;
}
-
- if (404 === $code) {
- throw new \LogicException("The '$url' URL not found");
- }
-
- return $curl_result;
}
}