[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/spout/src/Spout/Writer/Common/Helper/ -> ZipHelper.php (source)

   1  <?php
   2  
   3  namespace Box\Spout\Writer\Common\Helper;
   4  
   5  /**
   6   * Class ZipHelper
   7   * This class provides helper functions to create zip files
   8   *
   9   * @package Box\Spout\Writer\Common\Helper
  10   */
  11  class ZipHelper
  12  {
  13      const ZIP_EXTENSION = '.zip';
  14  
  15      /** Controls what to do when trying to add an existing file */
  16      const EXISTING_FILES_SKIP = 'skip';
  17      const EXISTING_FILES_OVERWRITE = 'overwrite';
  18  
  19      /** @var string Path of the folder where the zip file will be created */
  20      protected $tmpFolderPath;
  21  
  22      /** @var \ZipArchive The ZipArchive instance */
  23      protected $zip;
  24  
  25      /**
  26       * @param string $tmpFolderPath Path of the temp folder where the zip file will be created
  27       */
  28      public function __construct($tmpFolderPath)
  29      {
  30          $this->tmpFolderPath = $tmpFolderPath;
  31      }
  32  
  33      /**
  34       * Returns the already created ZipArchive instance or
  35       * creates one if none exists.
  36       *
  37       * @return \ZipArchive
  38       */
  39      protected function createOrGetZip()
  40      {
  41          if (!isset($this->zip)) {
  42              $this->zip = new \ZipArchive();
  43              $zipFilePath = $this->getZipFilePath();
  44  
  45              $this->zip->open($zipFilePath, \ZipArchive::CREATE|\ZipArchive::OVERWRITE);
  46          }
  47  
  48          return $this->zip;
  49      }
  50  
  51      /**
  52       * @return string Path where the zip file of the given folder will be created
  53       */
  54      public function getZipFilePath()
  55      {
  56          return $this->tmpFolderPath . self::ZIP_EXTENSION;
  57      }
  58  
  59      /**
  60       * Adds the given file, located under the given root folder to the archive.
  61       * The file will be compressed.
  62       *
  63       * Example of use:
  64       *   addFileToArchive('/tmp/xlsx/foo', 'bar/baz.xml');
  65       *   => will add the file located at '/tmp/xlsx/foo/bar/baz.xml' in the archive, but only as 'bar/baz.xml'
  66       *
  67       * @param string $rootFolderPath Path of the root folder that will be ignored in the archive tree.
  68       * @param string $localFilePath Path of the file to be added, under the root folder
  69       * @param string|void $existingFileMode Controls what to do when trying to add an existing file
  70       * @return void
  71       */
  72      public function addFileToArchive($rootFolderPath, $localFilePath, $existingFileMode = self::EXISTING_FILES_OVERWRITE)
  73      {
  74          $this->addFileToArchiveWithCompressionMethod(
  75              $rootFolderPath,
  76              $localFilePath,
  77              $existingFileMode,
  78              \ZipArchive::CM_DEFAULT
  79          );
  80      }
  81  
  82      /**
  83       * Adds the given file, located under the given root folder to the archive.
  84       * The file will NOT be compressed.
  85       *
  86       * Example of use:
  87       *   addUncompressedFileToArchive('/tmp/xlsx/foo', 'bar/baz.xml');
  88       *   => will add the file located at '/tmp/xlsx/foo/bar/baz.xml' in the archive, but only as 'bar/baz.xml'
  89       *
  90       * @param string $rootFolderPath Path of the root folder that will be ignored in the archive tree.
  91       * @param string $localFilePath Path of the file to be added, under the root folder
  92       * @param string|void $existingFileMode Controls what to do when trying to add an existing file
  93       * @return void
  94       */
  95      public function addUncompressedFileToArchive($rootFolderPath, $localFilePath, $existingFileMode = self::EXISTING_FILES_OVERWRITE)
  96      {
  97          $this->addFileToArchiveWithCompressionMethod(
  98              $rootFolderPath,
  99              $localFilePath,
 100              $existingFileMode,
 101              \ZipArchive::CM_STORE
 102          );
 103      }
 104  
 105      /**
 106       * Adds the given file, located under the given root folder to the archive.
 107       * The file will NOT be compressed.
 108       *
 109       * Example of use:
 110       *   addUncompressedFileToArchive('/tmp/xlsx/foo', 'bar/baz.xml');
 111       *   => will add the file located at '/tmp/xlsx/foo/bar/baz.xml' in the archive, but only as 'bar/baz.xml'
 112       *
 113       * @param string $rootFolderPath Path of the root folder that will be ignored in the archive tree.
 114       * @param string $localFilePath Path of the file to be added, under the root folder
 115       * @param string $existingFileMode Controls what to do when trying to add an existing file
 116       * @param int $compressionMethod The compression method
 117       * @return void
 118       */
 119      protected function addFileToArchiveWithCompressionMethod($rootFolderPath, $localFilePath, $existingFileMode, $compressionMethod)
 120      {
 121          $zip = $this->createOrGetZip();
 122  
 123          if (!$this->shouldSkipFile($zip, $localFilePath, $existingFileMode)) {
 124              $normalizedFullFilePath = $this->getNormalizedRealPath($rootFolderPath . '/' . $localFilePath);
 125              $zip->addFile($normalizedFullFilePath, $localFilePath);
 126  
 127              if (self::canChooseCompressionMethod()) {
 128                  $zip->setCompressionName($localFilePath, $compressionMethod);
 129              }
 130          }
 131      }
 132  
 133      /**
 134       * @return bool Whether it is possible to choose the desired compression method to be used
 135       */
 136      public static function canChooseCompressionMethod()
 137      {
 138          // setCompressionName() is a PHP7+ method...
 139          return (method_exists(new \ZipArchive(), 'setCompressionName'));
 140      }
 141  
 142      /**
 143       * @param string $folderPath Path to the folder to be zipped
 144       * @param string|void $existingFileMode Controls what to do when trying to add an existing file
 145       * @return void
 146       */
 147      public function addFolderToArchive($folderPath, $existingFileMode = self::EXISTING_FILES_OVERWRITE)
 148      {
 149          $zip = $this->createOrGetZip();
 150  
 151          $folderRealPath = $this->getNormalizedRealPath($folderPath) . '/';
 152          $itemIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($folderPath, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST);
 153  
 154          foreach ($itemIterator as $itemInfo) {
 155              $itemRealPath = $this->getNormalizedRealPath($itemInfo->getPathname());
 156              $itemLocalPath = str_replace($folderRealPath, '', $itemRealPath);
 157  
 158              if ($itemInfo->isFile() && !$this->shouldSkipFile($zip, $itemLocalPath, $existingFileMode)) {
 159                  $zip->addFile($itemRealPath, $itemLocalPath);
 160              }
 161          }
 162      }
 163  
 164      /**
 165       * @param \ZipArchive $zip
 166       * @param string $itemLocalPath
 167       * @param string $existingFileMode
 168       * @return bool Whether the file should be added to the archive or skipped
 169       */
 170      protected function shouldSkipFile($zip, $itemLocalPath, $existingFileMode)
 171      {
 172          // Skip files if:
 173          //   - EXISTING_FILES_SKIP mode chosen
 174          //   - File already exists in the archive
 175          return ($existingFileMode === self::EXISTING_FILES_SKIP && $zip->locateName($itemLocalPath) !== false);
 176      }
 177  
 178      /**
 179       * Returns canonicalized absolute pathname, containing only forward slashes.
 180       *
 181       * @param string $path Path to normalize
 182       * @return string Normalized and canonicalized path
 183       */
 184      protected function getNormalizedRealPath($path)
 185      {
 186          $realPath = realpath($path);
 187          return str_replace(DIRECTORY_SEPARATOR, '/', $realPath);
 188      }
 189  
 190      /**
 191       * Closes the archive and copies it into the given stream
 192       *
 193       * @param resource $streamPointer Pointer to the stream to copy the zip
 194       * @return void
 195       */
 196      public function closeArchiveAndCopyToStream($streamPointer)
 197      {
 198          $zip = $this->createOrGetZip();
 199          $zip->close();
 200          unset($this->zip);
 201  
 202          $this->copyZipToStream($streamPointer);
 203      }
 204  
 205      /**
 206       * Streams the contents of the zip file into the given stream
 207       *
 208       * @param resource $pointer Pointer to the stream to copy the zip
 209       * @return void
 210       */
 211      protected function copyZipToStream($pointer)
 212      {
 213          $zipFilePointer = fopen($this->getZipFilePath(), 'r');
 214          stream_copy_to_stream($zipFilePointer, $pointer);
 215          fclose($zipFilePointer);
 216      }
 217  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1