Ver Fonte

Replace CURL with copy() and file_get_contents()

François Pluchino há 13 anos atrás
pai
commit
541285022d

+ 61 - 83
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: <comment>connection...</comment>", 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,90 +158,54 @@ 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: <comment>$progression%</comment>", 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;
 
-    /**
-     * 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);
+            case STREAM_NOTIFY_PROGRESS:
+                if ($this->bytesMax > 0) {
+                    $progression = 0;
 
-        if (200 !== $code) {
-            return false;
-        }
+                    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);
 
-        return true;
+                    if (in_array($progression, $levels)) {
+                        $this->io->overwrite("    Downloading: <comment>$progression%</comment>", 80);
+                    }
+                }
+                break;
+
+            default:
+                break;
+        }
     }
 
     /**

+ 68 - 53
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);
-
-        // 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);
+        $ctx = stream_context_create($params);
+        stream_context_set_params($ctx, array("notification" => array($this, 'callbackGet')));
 
-        // for private repository returning 404 error when the authentification is incorrect
-        $ps = $this->firstCall && 404 === $code && null === $this->io->getLastUsername() && null === $auth['username'];
+        $content = @file_get_contents($url, false, $ctx);
 
-        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);
-            }
-
-            $this->io->writeln("Authorization required for <info>" . $this->owner.'/' . $this->repository . "</info>:");
-            $username = $this->io->ask('    Username: ');
-            $password = $this->io->askAndHideAnswer('    Password: ');
-            $this->io->setAuthentification($this->url, $username, $password);
-
-            return $this->getContents($url);
+                // 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 for <info>" . $this->contentUrl . "</info>:");
+                    $username = $this->io->ask('    Username: ');
+                    $password = $this->io->askAndHideAnswer('    Password: ');
+                    $this->io->setAuthentification($this->url, $username, $password);
+
+                    $this->content = $this->getContents($this->contentUrl);
+                }
+                break;
+
+            default:
+                break;
         }
-
-        if (404 === $code) {
-            throw new \LogicException("The '$url' URL not found");
-        }
-
-        return $curl_result;
     }
 }