[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |