[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/spout/src/Spout/Writer/ODS/Helper/ -> FileSystemHelper.php (source)

   1  <?php
   2  
   3  namespace Box\Spout\Writer\ODS\Helper;
   4  
   5  use Box\Spout\Writer\Common\Helper\ZipHelper;
   6  use Box\Spout\Writer\ODS\Internal\Worksheet;
   7  
   8  /**
   9   * Class FileSystemHelper
  10   * This class provides helper functions to help with the file system operations
  11   * like files/folders creation & deletion for ODS files
  12   *
  13   * @package Box\Spout\Writer\ODS\Helper
  14   */
  15  class FileSystemHelper extends \Box\Spout\Common\Helper\FileSystemHelper
  16  {
  17      const APP_NAME = 'Spout';
  18      const MIMETYPE = 'application/vnd.oasis.opendocument.spreadsheet';
  19  
  20      const META_INF_FOLDER_NAME = 'META-INF';
  21      const SHEETS_CONTENT_TEMP_FOLDER_NAME = 'worksheets-temp';
  22  
  23      const MANIFEST_XML_FILE_NAME = 'manifest.xml';
  24      const CONTENT_XML_FILE_NAME = 'content.xml';
  25      const META_XML_FILE_NAME = 'meta.xml';
  26      const MIMETYPE_FILE_NAME = 'mimetype';
  27      const STYLES_XML_FILE_NAME = 'styles.xml';
  28  
  29      /** @var string Path to the root folder inside the temp folder where the files to create the ODS will be stored */
  30      protected $rootFolder;
  31  
  32      /** @var string Path to the "META-INF" folder inside the root folder */
  33      protected $metaInfFolder;
  34  
  35      /** @var string Path to the temp folder, inside the root folder, where specific sheets content will be written to */
  36      protected $sheetsContentTempFolder;
  37  
  38      /**
  39       * @return string
  40       */
  41      public function getRootFolder()
  42      {
  43          return $this->rootFolder;
  44      }
  45  
  46      /**
  47       * @return string
  48       */
  49      public function getSheetsContentTempFolder()
  50      {
  51          return $this->sheetsContentTempFolder;
  52      }
  53  
  54      /**
  55       * Creates all the folders needed to create a ODS file, as well as the files that won't change.
  56       *
  57       * @return void
  58       * @throws \Box\Spout\Common\Exception\IOException If unable to create at least one of the base folders
  59       */
  60      public function createBaseFilesAndFolders()
  61      {
  62          $this
  63              ->createRootFolder()
  64              ->createMetaInfoFolderAndFile()
  65              ->createSheetsContentTempFolder()
  66              ->createMetaFile()
  67              ->createMimetypeFile();
  68      }
  69  
  70      /**
  71       * Creates the folder that will be used as root
  72       *
  73       * @return FileSystemHelper
  74       * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder
  75       */
  76      protected function createRootFolder()
  77      {
  78          $this->rootFolder = $this->createFolder($this->baseFolderPath, uniqid('ods'));
  79          return $this;
  80      }
  81  
  82      /**
  83       * Creates the "META-INF" folder under the root folder as well as the "manifest.xml" file in it
  84       *
  85       * @return FileSystemHelper
  86       * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder or the "manifest.xml" file
  87       */
  88      protected function createMetaInfoFolderAndFile()
  89      {
  90          $this->metaInfFolder = $this->createFolder($this->rootFolder, self::META_INF_FOLDER_NAME);
  91  
  92          $this->createManifestFile();
  93  
  94          return $this;
  95      }
  96  
  97      /**
  98       * Creates the "manifest.xml" file under the "META-INF" folder (under root)
  99       *
 100       * @return FileSystemHelper
 101       * @throws \Box\Spout\Common\Exception\IOException If unable to create the file
 102       */
 103      protected function createManifestFile()
 104      {
 105          $manifestXmlFileContents = <<<EOD
 106  <?xml version="1.0" encoding="UTF-8"?>
 107  <manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">
 108      <manifest:file-entry manifest:full-path="/" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>
 109      <manifest:file-entry manifest:full-path="styles.xml" manifest:media-type="text/xml"/>
 110      <manifest:file-entry manifest:full-path="content.xml" manifest:media-type="text/xml"/>
 111      <manifest:file-entry manifest:full-path="meta.xml" manifest:media-type="text/xml"/>
 112  </manifest:manifest>
 113  EOD;
 114  
 115          $this->createFileWithContents($this->metaInfFolder, self::MANIFEST_XML_FILE_NAME, $manifestXmlFileContents);
 116  
 117          return $this;
 118      }
 119  
 120      /**
 121       * Creates the temp folder where specific sheets content will be written to.
 122       * This folder is not part of the final ODS file and is only used to be able to jump between sheets.
 123       *
 124       * @return FileSystemHelper
 125       * @throws \Box\Spout\Common\Exception\IOException If unable to create the folder
 126       */
 127      protected function createSheetsContentTempFolder()
 128      {
 129          $this->sheetsContentTempFolder = $this->createFolder($this->rootFolder, self::SHEETS_CONTENT_TEMP_FOLDER_NAME);
 130          return $this;
 131      }
 132  
 133      /**
 134       * Creates the "meta.xml" file under the root folder
 135       *
 136       * @return FileSystemHelper
 137       * @throws \Box\Spout\Common\Exception\IOException If unable to create the file
 138       */
 139      protected function createMetaFile()
 140      {
 141          $appName = self::APP_NAME;
 142          $createdDate = (new \DateTime())->format(\DateTime::W3C);
 143  
 144          $metaXmlFileContents = <<<EOD
 145  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 146  <office:document-meta office:version="1.2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink">
 147      <office:meta>
 148          <dc:creator>$appName</dc:creator>
 149          <meta:creation-date>$createdDate</meta:creation-date>
 150          <dc:date>$createdDate</dc:date>
 151      </office:meta>
 152  </office:document-meta>
 153  EOD;
 154  
 155          $this->createFileWithContents($this->rootFolder, self::META_XML_FILE_NAME, $metaXmlFileContents);
 156  
 157          return $this;
 158      }
 159  
 160      /**
 161       * Creates the "mimetype" file under the root folder
 162       *
 163       * @return FileSystemHelper
 164       * @throws \Box\Spout\Common\Exception\IOException If unable to create the file
 165       */
 166      protected function createMimetypeFile()
 167      {
 168          $this->createFileWithContents($this->rootFolder, self::MIMETYPE_FILE_NAME, self::MIMETYPE);
 169          return $this;
 170      }
 171  
 172      /**
 173       * Creates the "content.xml" file under the root folder
 174       *
 175       * @param Worksheet[] $worksheets
 176       * @param StyleHelper $styleHelper
 177       * @return FileSystemHelper
 178       */
 179      public function createContentFile($worksheets, $styleHelper)
 180      {
 181          $contentXmlFileContents = <<<EOD
 182  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 183  <office:document-content office:version="1.2" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:msoxl="http://schemas.microsoft.com/office/excel/formula" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:xlink="http://www.w3.org/1999/xlink">
 184  EOD;
 185  
 186          $contentXmlFileContents .= $styleHelper->getContentXmlFontFaceSectionContent();
 187          $contentXmlFileContents .= $styleHelper->getContentXmlAutomaticStylesSectionContent(count($worksheets));
 188  
 189          $contentXmlFileContents .= '<office:body><office:spreadsheet>';
 190  
 191          $this->createFileWithContents($this->rootFolder, self::CONTENT_XML_FILE_NAME, $contentXmlFileContents);
 192  
 193          // Append sheets content to "content.xml"
 194          $contentXmlFilePath = $this->rootFolder . '/' . self::CONTENT_XML_FILE_NAME;
 195          $contentXmlHandle = fopen($contentXmlFilePath, 'a');
 196  
 197          foreach ($worksheets as $worksheet) {
 198              // write the "<table:table>" node, with the final sheet's name
 199              fwrite($contentXmlHandle, $worksheet->getTableElementStartAsString());
 200  
 201              $worksheetFilePath = $worksheet->getWorksheetFilePath();
 202              $this->copyFileContentsToTarget($worksheetFilePath, $contentXmlHandle);
 203  
 204              fwrite($contentXmlHandle, '</table:table>');
 205          }
 206  
 207          $contentXmlFileContents = '</office:spreadsheet></office:body></office:document-content>';
 208  
 209          fwrite($contentXmlHandle, $contentXmlFileContents);
 210          fclose($contentXmlHandle);
 211  
 212          return $this;
 213      }
 214  
 215      /**
 216       * Streams the content of the file at the given path into the target resource.
 217       * Depending on which mode the target resource was created with, it will truncate then copy
 218       * or append the content to the target file.
 219       *
 220       * @param string $sourceFilePath Path of the file whose content will be copied
 221       * @param resource $targetResource Target resource that will receive the content
 222       * @return void
 223       */
 224      protected function copyFileContentsToTarget($sourceFilePath, $targetResource)
 225      {
 226          $sourceHandle = fopen($sourceFilePath, 'r');
 227          stream_copy_to_stream($sourceHandle, $targetResource);
 228          fclose($sourceHandle);
 229      }
 230  
 231      /**
 232       * Deletes the temporary folder where sheets content was stored.
 233       *
 234       * @return FileSystemHelper
 235       */
 236      public function deleteWorksheetTempFolder()
 237      {
 238          $this->deleteFolderRecursively($this->sheetsContentTempFolder);
 239          return $this;
 240      }
 241  
 242  
 243      /**
 244       * Creates the "styles.xml" file under the root folder
 245       *
 246       * @param StyleHelper $styleHelper
 247       * @param int $numWorksheets Number of created worksheets
 248       * @return FileSystemHelper
 249       */
 250      public function createStylesFile($styleHelper, $numWorksheets)
 251      {
 252          $stylesXmlFileContents = $styleHelper->getStylesXMLFileContent($numWorksheets);
 253          $this->createFileWithContents($this->rootFolder, self::STYLES_XML_FILE_NAME, $stylesXmlFileContents);
 254  
 255          return $this;
 256      }
 257  
 258      /**
 259       * Zips the root folder and streams the contents of the zip into the given stream
 260       *
 261       * @param resource $streamPointer Pointer to the stream to copy the zip
 262       * @return void
 263       */
 264      public function zipRootFolderAndCopyToStream($streamPointer)
 265      {
 266          $zipHelper = new ZipHelper($this->rootFolder);
 267  
 268          // In order to have the file's mime type detected properly, files need to be added
 269          // to the zip file in a particular order.
 270          // @see http://www.jejik.com/articles/2010/03/how_to_correctly_create_odf_documents_using_zip/
 271          $zipHelper->addUncompressedFileToArchive($this->rootFolder, self::MIMETYPE_FILE_NAME);
 272  
 273          $zipHelper->addFolderToArchive($this->rootFolder, ZipHelper::EXISTING_FILES_SKIP);
 274          $zipHelper->closeArchiveAndCopyToStream($streamPointer);
 275  
 276          // once the zip is copied, remove it
 277          $this->deleteFile($zipHelper->getZipFilePath());
 278      }
 279  }


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