FileDownloader.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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\Package\PackageInterface;
  13. use Symfony\Component\Console\Output\OutputInterface;
  14. use Symfony\Component\Console\Input\InputInterface;
  15. /**
  16. * Base downloader for file packages
  17. *
  18. * @author Kirill chEbba Chebunin <iam@chebba.org>
  19. * @author Jordi Boggiano <j.boggiano@seld.be>
  20. * @author François Pluchino <francois.pluchino@opendisplay.com>
  21. */
  22. abstract class FileDownloader implements DownloaderInterface
  23. {
  24. protected $intput;
  25. protected $output;
  26. /**
  27. * Constructor.
  28. *
  29. * @param InputInterface $input The Input instance
  30. * @param OutputInterface $output The Output instance
  31. */
  32. public function __construct(InputInterface $input, OutputInterface $output)
  33. {
  34. $this->intput = $input;
  35. $this->output = $output;
  36. }
  37. /**
  38. * {@inheritDoc}
  39. */
  40. public function getInstallationSource()
  41. {
  42. return 'dist';
  43. }
  44. /**
  45. * {@inheritDoc}
  46. */
  47. public function download(PackageInterface $package, $path)
  48. {
  49. $url = $package->getDistUrl();
  50. $checksum = $package->getDistSha1Checksum();
  51. if (!is_dir($path)) {
  52. if (file_exists($path)) {
  53. throw new \UnexpectedValueException($path.' exists and is not a directory');
  54. }
  55. if (!mkdir($path, 0777, true)) {
  56. throw new \UnexpectedValueException($path.' does not exist and could not be created');
  57. }
  58. }
  59. $fileName = rtrim($path.'/'.md5(time().rand()).'.'.pathinfo($url, PATHINFO_EXTENSION), '.');
  60. //echo 'Downloading '.$url.' to '.$fileName.PHP_EOL;
  61. $this->output->writeln(" - <info>Downloading</info> <comment>" . $package->getName() . "</comment> (" . $package->getPrettyVersion() . ")");
  62. if (!extension_loaded('openssl') && (0 === strpos($url, 'https:') || 0 === strpos($url, 'http://github.com'))) {
  63. // bypass https for github if openssl is disabled
  64. if (preg_match('{^https?://(github.com/[^/]+/[^/]+/(zip|tar)ball/[^/]+)$}i', $url, $match)) {
  65. $url = 'http://nodeload.'.$match[1];
  66. } else {
  67. throw new \RuntimeException('You must enable the openssl extension to download files via https');
  68. }
  69. }
  70. // Handle system proxy
  71. if (isset($_SERVER['HTTP_PROXY'])) {
  72. // http(s):// is not supported in proxy
  73. $proxy = str_replace(array('http://', 'https://'), array('tcp://', 'ssl://'), $_SERVER['HTTP_PROXY']);
  74. if (0 === strpos($proxy, 'ssl:') && !extension_loaded('openssl')) {
  75. throw new \RuntimeException('You must enable the openssl extension to use a proxy over https');
  76. }
  77. $ctx = stream_context_create(array(
  78. 'http' => array(
  79. 'proxy' => $proxy,
  80. 'request_fulluri' => true,
  81. ),
  82. ));
  83. copy($url, $filename, $ctx);
  84. } else {
  85. copy($url, $fileName);
  86. }
  87. if (!file_exists($fileName)) {
  88. throw new \UnexpectedValueException($url.' could not be saved to '.$fileName.', make sure the'
  89. .' directory is writable and you have internet connectivity');
  90. }
  91. if ($checksum && hash_file('sha1', $fileName) !== $checksum) {
  92. throw new \UnexpectedValueException('The checksum verification of the archive failed (downloaded from '.$url.')');
  93. }
  94. $this->output->writeln(' Unpacking archive');
  95. $this->extract($fileName, $path);
  96. $this->output->writeln(' Cleaning up');
  97. unlink($fileName);
  98. // If we have only a one dir inside it suppose to be a package itself
  99. $contentDir = glob($path . '/*');
  100. if (1 === count($contentDir)) {
  101. $contentDir = $contentDir[0];
  102. foreach (array_merge(glob($contentDir . '/.*'), glob($contentDir . '/*')) as $file) {
  103. if (trim(basename($file), '.')) {
  104. rename($file, $path . '/' . basename($file));
  105. }
  106. }
  107. rmdir($contentDir);
  108. }
  109. }
  110. /**
  111. * {@inheritDoc}
  112. */
  113. public function update(PackageInterface $initial, PackageInterface $target, $path)
  114. {
  115. $fs = new Util\Filesystem();
  116. $fs->removeDirectory($path);
  117. $this->download($target, $path);
  118. }
  119. /**
  120. * {@inheritDoc}
  121. */
  122. public function remove(PackageInterface $package, $path)
  123. {
  124. $fs = new Util\Filesystem();
  125. $fs->removeDirectory($path);
  126. }
  127. /**
  128. * Extract file to directory
  129. *
  130. * @param string $file Extracted file
  131. * @param string $path Directory
  132. *
  133. * @throws \UnexpectedValueException If can not extract downloaded file to path
  134. */
  135. protected abstract function extract($file, $path);
  136. }