ZipDownloader.php 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. <?php
  2. /*
  3. * This file is part of Composer.
  4. *
  5. * (c) Nils Adermann <naderman@naderman.de>
  6. * Jordi Boggiano <j.boggiano@seld.be>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. namespace Composer\Downloader;
  12. use Composer\Config;
  13. use Composer\Cache;
  14. use Composer\EventDispatcher\EventDispatcher;
  15. use Composer\Util\ProcessExecutor;
  16. use Composer\IO\IOInterface;
  17. use ZipArchive;
  18. /**
  19. * @author Jordi Boggiano <j.boggiano@seld.be>
  20. */
  21. class ZipDownloader extends ArchiveDownloader
  22. {
  23. protected $process;
  24. public function __construct(IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null, Cache $cache = null, ProcessExecutor $process = null)
  25. {
  26. $this->process = $process ?: new ProcessExecutor($io);
  27. parent::__construct($io, $config, $eventDispatcher, $cache);
  28. }
  29. protected function extract($file, $path)
  30. {
  31. $processError = null;
  32. // try to use unzip on *nix
  33. if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
  34. $command = 'unzip '.ProcessExecutor::escape($file).' -d '.ProcessExecutor::escape($path) . ' && chmod -R u+w ' . ProcessExecutor::escape($path);
  35. try {
  36. if (0 === $this->process->execute($command, $ignoredOutput)) {
  37. return;
  38. }
  39. $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput();
  40. } catch (\Exception $e) {
  41. $processError = 'Failed to execute ' . $command . "\n\n" . $e->getMessage();
  42. }
  43. }
  44. if (!class_exists('ZipArchive')) {
  45. // php.ini path is added to the error message to help users find the correct file
  46. $iniPath = php_ini_loaded_file();
  47. if ($iniPath) {
  48. $iniMessage = 'The php.ini used by your command-line PHP is: ' . $iniPath;
  49. } else {
  50. $iniMessage = 'A php.ini file does not exist. You will have to create one.';
  51. }
  52. $error = "Could not decompress the archive, enable the PHP zip extension or install unzip.\n"
  53. . $iniMessage . "\n" . $processError;
  54. if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
  55. $error = "Could not decompress the archive, enable the PHP zip extension.\n" . $iniMessage;
  56. }
  57. throw new \RuntimeException($error);
  58. }
  59. $zipArchive = new ZipArchive();
  60. if (true !== ($retval = $zipArchive->open($file))) {
  61. throw new \UnexpectedValueException($this->getErrorMessage($retval, $file), $retval);
  62. }
  63. if (true !== $zipArchive->extractTo($path)) {
  64. throw new \RuntimeException("There was an error extracting the ZIP file. Corrupt file?");
  65. }
  66. $zipArchive->close();
  67. }
  68. /**
  69. * Give a meaningful error message to the user.
  70. *
  71. * @param int $retval
  72. * @param string $file
  73. * @return string
  74. */
  75. protected function getErrorMessage($retval, $file)
  76. {
  77. switch ($retval) {
  78. case ZipArchive::ER_EXISTS:
  79. return sprintf("File '%s' already exists.", $file);
  80. case ZipArchive::ER_INCONS:
  81. return sprintf("Zip archive '%s' is inconsistent.", $file);
  82. case ZipArchive::ER_INVAL:
  83. return sprintf("Invalid argument (%s)", $file);
  84. case ZipArchive::ER_MEMORY:
  85. return sprintf("Malloc failure (%s)", $file);
  86. case ZipArchive::ER_NOENT:
  87. return sprintf("No such zip file: '%s'", $file);
  88. case ZipArchive::ER_NOZIP:
  89. return sprintf("'%s' is not a zip archive.", $file);
  90. case ZipArchive::ER_OPEN:
  91. return sprintf("Can't open zip file: %s", $file);
  92. case ZipArchive::ER_READ:
  93. return sprintf("Zip read error (%s)", $file);
  94. case ZipArchive::ER_SEEK:
  95. return sprintf("Zip seek error (%s)", $file);
  96. default:
  97. return sprintf("'%s' is not a valid zip archive, got error code: %s", $file, $retval);
  98. }
  99. }
  100. }