Browse Source

Prefer ZipArchive over unzip on Windows

Nicolas Grekas 9 years ago
parent
commit
08d48cb61a
2 changed files with 20 additions and 28 deletions
  1. 4 8
      doc/articles/troubleshooting.md
  2. 16 20
      src/Composer/Downloader/ZipDownloader.php

+ 4 - 8
doc/articles/troubleshooting.md

@@ -346,13 +346,9 @@ composer update
 
 See also https://github.com/composer/composer/issues/4180 for more information.
 
-## Zip archives are being reported as corrupted or not unpacked correctly.
+## Zip archives are not unpacked correctly.
 
 Composer can unpack zipballs using either a system-provided `unzip` utility or PHP's
-native `ZipArchiver` class, preferring the first. The `ZipArchiver` class however is
-known to occassionally report valid zip files as corrupted, and does not support certain
-advanced features with permissions and symlinks.
-
-If you have issues with zip files you should install a native implementation of unzip
-and verify whether the problem persists. If so it is likely a real issue in the file
-itself and you should contact the provider.
+native `ZipArchiver` class. The `ZipArchiver` class is preferred on Windows. On other
+OSes where ZIP files can contain permissions and symlinks, the `unzip` utility is
+preferred. You're advised to install it if you need these features.

+ 16 - 20
src/Composer/Downloader/ZipDownloader.php

@@ -48,7 +48,18 @@ class ZipDownloader extends ArchiveDownloader
         }
 
         if (!class_exists('ZipArchive') && !self::$hasSystemUnzip) {
-            throw new \RuntimeException('The zip extension and unzip command are both missing, skipping');
+            // php.ini path is added to the error message to help users find the correct file
+            $iniPath = php_ini_loaded_file();
+
+            if ($iniPath) {
+                $iniMessage = 'The php.ini used by your command-line PHP is: ' . $iniPath;
+            } else {
+                $iniMessage = 'A php.ini file does not exist. You will have to create one.';
+            }
+
+            $error = "The zip extension and unzip command are both missing, skipping.\n" . $iniMessage;
+
+            throw new \RuntimeException($error);
         }
 
         return parent::download($package, $path);
@@ -58,7 +69,7 @@ class ZipDownloader extends ArchiveDownloader
     {
         $processError = null;
 
-        if (self::$hasSystemUnzip) {
+        if (self::$hasSystemUnzip && !(class_exists('ZipArchive') && Platform::isWindows())) {
             $command = 'unzip '.ProcessExecutor::escape($file).' -d '.ProcessExecutor::escape($path);
             if (!Platform::isWindows()) {
                 $command .= ' && chmod -R u+w ' . ProcessExecutor::escape($path);
@@ -73,22 +84,10 @@ class ZipDownloader extends ArchiveDownloader
             } catch (\Exception $e) {
                 $processError = 'Failed to execute ' . $command . "\n\n" . $e->getMessage();
             }
-        }
 
-        if (!class_exists('ZipArchive')) {
-            // php.ini path is added to the error message to help users find the correct file
-            $iniPath = php_ini_loaded_file();
-
-            if ($iniPath) {
-                $iniMessage = 'The php.ini used by your command-line PHP is: ' . $iniPath;
-            } else {
-                $iniMessage = 'A php.ini file does not exist. You will have to create one.';
+            if (!class_exists('ZipArchive')) {
+                throw new \RuntimeException($processError);
             }
-
-            $error = "Could not decompress the archive, enable the PHP zip extension or install unzip.\n"
-                . $iniMessage . ($processError ? "\n" . $processError : '');
-
-            throw new \RuntimeException($error);
         }
 
         $zipArchive = new ZipArchive();
@@ -98,10 +97,7 @@ class ZipDownloader extends ArchiveDownloader
         }
 
         if (true !== $zipArchive->extractTo($path)) {
-            $this->io->writeError("<warn>As there is no 'unzip' command installed zip files are being unpacked using the PHP zip extension.</warn>");
-            $this->io->writeError("<warn>This may cause invalid reports of corrupted archives. Installing 'unzip' may remediate them.</warn>");
-
-            throw new \RuntimeException("There was an error extracting the ZIP file, it is either corrupted or using an invalid format");
+            throw new \RuntimeException(rtrim("There was an error extracting the ZIP file, it is either corrupted or using an invalid format.\n".$processError));
         }
 
         $zipArchive->close();