diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f687b9d..6e6efa8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3; new r - Writer: Refactor writer parts using composite pattern - @ivanlanin - Docs: Show code quality and test code coverage badge on README - Style: Change behaviour of `set...` function of boolean properties; when none is defined, assumed true - @ivanlanin +- Shared: Unify PHP ZipArchive and PCLZip features into PhpWord ZipArchive - @ivanlanin ## 0.10.0 - 4 May 2014 diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index 44829ba5..8e30b78c 100644 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -19,7 +19,7 @@ namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Exception\InvalidImageException; use PhpOffice\PhpWord\Exception\UnsupportedImageTypeException; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\ZipArchive; use PhpOffice\PhpWord\Style\Image as ImageStyle; /** @@ -348,8 +348,7 @@ class Image extends AbstractElement list($zipFilename, $imageFilename) = explode('#', $source); $tempFilename = tempnam(sys_get_temp_dir(), 'PHPWordImage'); - $zipClass = Settings::getZipClass(); - $zip = new $zipClass(); + $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { if ($zip->locateName($imageFilename)) { $imageContent = $zip->getFromName($imageFilename); diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index c792a283..6e81d7fc 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Reader; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\ZipArchive; use PhpOffice\PhpWord\Shared\XMLReader; /** @@ -109,8 +109,7 @@ class Word2007 extends AbstractReader implements ReaderInterface // word/_rels/*.xml.rels $wordRelsPath = 'word/_rels/'; - $zipClass = Settings::getZipClass(); - $zip = new $zipClass(); + $zip = new ZipArchive(); if ($zip->open($docFile) === true) { for ($i = 0; $i < $zip->numFiles; $i++) { $xmlFile = $zip->getNameIndex($i); diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php index 6b118c56..ae79757b 100644 --- a/src/PhpWord/Shared/XMLReader.php +++ b/src/PhpWord/Shared/XMLReader.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Exception\Exception; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\ZipArchive; /** * XML Reader wrapper @@ -47,7 +47,6 @@ class XMLReader * @param string $zipFile * @param string $xmlFile * @return \DOMDocument|false - * @throws \PhpOffice\PhpWord\Exception\Exception */ public function getDomFromZip($zipFile, $xmlFile) { @@ -55,12 +54,8 @@ class XMLReader throw new Exception('Cannot find archive file.'); } - $zipClass = Settings::getZipClass(); - $zip = new $zipClass(); - $canOpen = $zip->open($zipFile); - if ($canOpen === false) { - throw new Exception('Cannot open archive file.'); - } + $zip = new ZipArchive(); + $zip->open($zipFile); $contents = $zip->getFromName($xmlFile); $zip->close(); diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index fdc6e29d..653fae70 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -19,12 +19,6 @@ namespace PhpOffice\PhpWord\Shared; use PhpOffice\PhpWord\Settings; -// @codeCoverageIgnoreStart -if (!defined('DATE_W3C')) { - define('DATE_W3C', 'Y-m-d\TH:i:sP'); -} -// @codeCoverageIgnoreEnd - /** * XMLWriter wrapper * @@ -64,6 +58,11 @@ class XMLWriter */ public function __construct($tempLocation = self::STORAGE_MEMORY, $tempFolder = './') { + // Define date format + if (!defined('DATE_W3C')) { + define('DATE_W3C', 'Y-m-d\TH:i:sP'); + } + // Create internal XMLWriter $this->xmlWriter = new \XMLWriter(); diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php index 84d6ab85..04c3e1fe 100644 --- a/src/PhpWord/Shared/ZipArchive.php +++ b/src/PhpWord/Shared/ZipArchive.php @@ -17,32 +17,46 @@ namespace PhpOffice\PhpWord\Shared; -// PCLZIP needs the temp path to end in a back slash -// @codeCoverageIgnoreStart -if (!defined('PCLZIP_TEMPORARY_DIR')) { - define('PCLZIP_TEMPORARY_DIR', sys_get_temp_dir() . '/'); -} -require_once 'PCLZip/pclzip.lib.php'; -// @codeCoverageIgnoreEnd +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Settings; /** - * PCLZip wrapper + * ZipArchive wrapper * + * Wraps zip archive functionality of PHP ZipArchive and PCLZip. PHP ZipArchive + * properties and methods are bypassed and used as the model for the PCLZip + * emulation. Only needed PHP ZipArchive features are implemented. + * + * @method bool addFile(string $filename, string $localname = null) + * @method bool addFromString(string $localname, string $contents) + * @method bool close() + * @method bool extractTo(string $destination, mixed $entries = null) + * @method bool getFromName(string $name) + * @method bool getNameIndex(int $index) + * @method bool locateName (string $name) + * @method bool open(string $filename, int $flags = null) * @since 0.10.0 */ class ZipArchive { - /** constants */ - const OVERWRITE = 'OVERWRITE'; - const CREATE = 'CREATE'; + /** @const int Flags for open method */ + const CREATE = 1; // Emulate \ZipArchive::CREATE + const OVERWRITE = 8; // Emulate \ZipArchive::OVERWRITE /** * Number of files (emulate ZipArchive::$numFiles) * - * @var string + * @var int */ public $numFiles = 0; + /** + * Archive filename (emulate ZipArchive::$filename) + * + * @var string + */ + public $filename; + /** * Temporary storage directory * @@ -51,34 +65,142 @@ class ZipArchive private $tempDir; /** - * Zip Archive Stream Handle + * Internal zip archive object * - * @var string + * @var \ZipArchive|\PclZip */ private $zip; /** - * Open a new zip archive + * Use PCLZip (default behaviour) * - * @param string $filename Filename for the zip archive - * @return boolean + * @var bool */ - public function open($filename) + private $usePclzip = true; + + /** + * Create new instance + */ + public function __construct() { - $this->tempDir = sys_get_temp_dir(); - $this->zip = new \PclZip($filename); - $this->numFiles = count($this->zip->listContent()); + $this->usePclzip = (Settings::getZipClass() != 'ZipArchive'); + if ($this->usePclzip) { + if (!defined('PCLZIP_TEMPORARY_DIR')) { + define('PCLZIP_TEMPORARY_DIR', sys_get_temp_dir() . '/'); + } + require_once 'PCLZip/pclzip.lib.php'; + } else { + $this->zip = new \ZipArchive(); + } + } + + /** + * Catch function calls: pass to ZipArchive or PCLZip + * + * `call_user_func_array` can only used for public function, hence the `public` in all `pcl...` methods + * + * @param mixed $function + * @param mixed $args + * @return mixed + */ + public function __call($function, $args) + { + // Set object and function + $zipFunction = $function; + if (!$this->usePclzip) { + $zipObject = $this->zip; + } else { + $zipObject = $this; + $zipFunction = "pclzip{$zipFunction}"; + } + + // Run function + $result = @call_user_func_array(array($zipObject, $zipFunction), $args); + + return $result; + } + + /** + * Close the active archive + * + * @return bool + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + public function close() + { + if (!$this->usePclzip) { + if ($this->zip->close() === false) { + throw new Exception("Could not close zip file $this->filename."); + } + } return true; } /** - * Close this zip archive (emulate \ZipArchive) + * Extract the archive contents (emulate \ZipArchive) * - * @codeCoverageIgnore + * @param string $destination + * @param string|array $entries + * @return boolean + * @since 0.10.0 */ - public function close() + public function extractTo($destination, $entries = null) { + if (!is_dir($destination)) { + return false; + } + + if (!$this->usePclzip) { + return $this->zip->extractTo($destination, $entries); + } else { + return $this->pclzipExtractTo($destination, $entries); + } + } + + /** + * Open a new zip archive + * + * @param string $filename The file name of the ZIP archive to open + * @param int $flags The mode to use to open the archive + * @return bool + */ + public function open($filename, $flags = null) + { + $result = true; + $this->filename = $filename; + + if (!$this->usePclzip) { + $result = $this->zip->open($this->filename, $flags); + $this->numFiles = $this->zip->numFiles; + } else { + $this->tempDir = sys_get_temp_dir(); + $this->zip = new \PclZip($this->filename); + $this->numFiles = count($this->zip->listContent()); + } + + return $result; + } + + /** + * Extract file from archive by given file name (emulate \ZipArchive) + * + * @param string $filename Filename for the file in zip archive + * @return string|false $contents File string contents + */ + public function getFromName($filename) + { + if (!$this->usePclzip) { + $contents = $this->zip->getFromName($filename); + if ($contents === false) { + $filename = substr($filename, 1); + $contents = $this->zip->getFromName($filename); + } + } else { + $contents = $this->pclzipGetFromName($filename); + } + + return $contents; } /** @@ -88,7 +210,7 @@ class ZipArchive * @param string $localname Directory/Name of the file added to the zip * @return bool */ - public function addFile($filename, $localname = null) + public function pclzipAddFile($filename, $localname = null) { $filename = realpath($filename); $filenameParts = pathinfo($filename); @@ -103,13 +225,9 @@ class ZipArchive $filenameParts = pathinfo($temppath); } - $res = $this->zip->add( - $filename, - PCLZIP_OPT_REMOVE_PATH, - $filenameParts['dirname'], - PCLZIP_OPT_ADD_PATH, - $localnameParts["dirname"] - ); + $pathRemoved = $filenameParts['dirname']; + $pathAdded = $localnameParts['dirname']; + $res = $this->zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded); return ($res == 0) ? false : true; } @@ -121,8 +239,9 @@ class ZipArchive * @param string $contents String of data to add to the zip archive * @return bool */ - public function addFromString($localname, $contents) + public function pclzipAddFromString($localname, $contents) { + // PCLZip emulation $filenameParts = pathinfo($localname); // Write $contents to a temp file @@ -131,13 +250,10 @@ class ZipArchive fclose($handle); // Add temp file to zip - $res = $this->zip->add( - $this->tempDir . '/' . $filenameParts["basename"], - PCLZIP_OPT_REMOVE_PATH, - $this->tempDir, - PCLZIP_OPT_ADD_PATH, - $filenameParts["dirname"] - ); + $filename = $this->tempDir . '/' . $filenameParts["basename"]; + $pathRemoved = $this->tempDir; + $pathAdded = $filenameParts['dirname']; + $res = $this->zip->add($filename, PCLZIP_OPT_REMOVE_PATH, $pathRemoved, PCLZIP_OPT_ADD_PATH, $pathAdded); // Remove temp file @unlink($this->tempDir . '/' . $filenameParts["basename"]); @@ -146,25 +262,34 @@ class ZipArchive } /** - * Returns the index of the entry in the archive (emulate \ZipArchive) + * Extract the archive contents (emulate \ZipArchive) * - * @param string $filename Filename for the file in zip archive - * @return integer|false + * @param string $destination + * @param string|array $entries + * @return boolean + * @since 0.10.0 */ - public function locateName($filename) + public function pclzipExtractTo($destination, $entries = null) { - $list = $this->zip->listContent(); - $listCount = count($list); - $listIndex = -1; - for ($i = 0; $i < $listCount; ++$i) { - if (strtolower($list[$i]["filename"]) == strtolower($filename) || - strtolower($list[$i]["stored_filename"]) == strtolower($filename)) { - $listIndex = $i; - break; + // Extract all files + if (is_null($entries)) { + $result = $this->zip->extract(PCLZIP_OPT_PATH, $destination); + return ($result > 0) ? true : false; + } + + // Extract by entries + if (!is_array($entries)) { + $entries = array($entries); + } + foreach ($entries as $entry) { + $entryIndex = $this->locateName($entry); + $result = $this->zip->extractByIndex($entryIndex, PCLZIP_OPT_PATH, $destination); + if ($result <= 0) { + return false; } } - return ($listIndex > -1) ? $listIndex : false; + return true; } /** @@ -173,7 +298,7 @@ class ZipArchive * @param string $filename Filename for the file in zip archive * @return string|false $contents File string contents */ - public function getFromName($filename) + public function pclzipGetFromName($filename) { $listIndex = $this->locateName($filename); $contents = false; @@ -199,7 +324,7 @@ class ZipArchive * @return string|false * @since 0.10.0 */ - public function getNameIndex($index) + public function pclzipGetNameIndex($index) { $list = $this->zip->listContent(); if (isset($list[$index])) { @@ -210,37 +335,24 @@ class ZipArchive } /** - * Extract the archive contents (emulate \ZipArchive) + * Returns the index of the entry in the archive (emulate \ZipArchive) * - * @param string $destination - * @param string|array $entries - * @return boolean - * @since 0.10.0 + * @param string $filename Filename for the file in zip archive + * @return integer|false */ - public function extractTo($destination, $entries = null) + public function pclzipLocateName($filename) { - if (!is_dir($destination)) { - return false; - } - - // Extract all files - if (is_null($entries)) { - $result = $this->zip->extract(PCLZIP_OPT_PATH, $destination); - return ($result > 0) ? true : false; - } - - // Extract by entries - if (!is_array($entries)) { - $entries = array($entries); - } - foreach ($entries as $entry) { - $entryIndex = $this->locateName($entry); - $result = $this->zip->extractByIndex($entryIndex, PCLZIP_OPT_PATH, $destination); - if ($result <= 0) { - return false; + $list = $this->zip->listContent(); + $listCount = count($list); + $listIndex = -1; + for ($i = 0; $i < $listCount; ++$i) { + if (strtolower($list[$i]["filename"]) == strtolower($filename) || + strtolower($list[$i]["stored_filename"]) == strtolower($filename)) { + $listIndex = $i; + break; } } - return true; + return ($listIndex > -1) ? $listIndex : false; } } diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 68550cfe..21e8b988 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -19,6 +19,7 @@ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\Shared\ZipArchive; /** * Template @@ -78,8 +79,7 @@ class Template throw new Exception("Could not copy the template from {$strFilename} to {$this->tempFileName}."); } - $zipClass = Settings::getZipClass(); - $this->zipClass = new $zipClass(); + $this->zipClass = new ZipArchive(); $this->zipClass->open($this->tempFileName); // Find and load headers and footers diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 628dd045..30c133cd 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -19,7 +19,7 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\ZipArchive; /** * Abstract writer class @@ -257,42 +257,35 @@ abstract class AbstractWriter implements WriterInterface * Get ZipArchive object * * @param string $filename - * @return mixed ZipArchive object + * @return \PhpOffice\PhpWord\Shared\ZipArchive * @throws \PhpOffice\PhpWord\Exception\Exception */ protected function getZipArchive($filename) { - // Create new ZIP file and open it for writing - $zipClass = Settings::getZipClass(); - $objZip = new $zipClass(); - - // Retrieve OVERWRITE and CREATE constants from the instantiated zip class - $reflection = new \ReflectionObject($objZip); - $zipOverWrite = $reflection->getConstant('OVERWRITE'); - $zipCreate = $reflection->getConstant('CREATE'); - // Remove any existing file if (file_exists($filename)) { unlink($filename); } // Try opening the ZIP file - if ($objZip->open($filename, $zipOverWrite) !== true) { - if ($objZip->open($filename, $zipCreate) !== true) { + $zip = new ZipArchive(); + if ($zip->open($filename, ZipArchive::OVERWRITE) !== true) { + if ($zip->open($filename, ZipArchive::CREATE) !== true) { throw new Exception("Could not open " . $filename . " for writing."); } } - return $objZip; + return $zip; } /** * Add files to package * - * @param mixed $objZip + * @param $zip * @param mixed $elements + * @return \PhpOffice\PhpWord\Shared\ZipArchive $zip */ - protected function addFilesToPackage($objZip, $elements) + protected function addFilesToPackage($zip, $elements) { foreach ($elements as $element) { $type = $element['type']; // image|object|link @@ -310,10 +303,10 @@ abstract class AbstractWriter implements WriterInterface call_user_func($element['imageFunction'], $image); $imageContents = ob_get_contents(); ob_end_clean(); - $objZip->addFromString($target, $imageContents); + $zip->addFromString($target, $imageContents); imagedestroy($image); } else { - $this->addFileToPackage($objZip, $element['source'], $target); + $this->addFileToPackage($zip, $element['source'], $target); } } } @@ -323,11 +316,11 @@ abstract class AbstractWriter implements WriterInterface * * Get the actual source from an archive image * - * @param mixed $objZip + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zipPackage * @param string $source * @param string $target */ - protected function addFileToPackage($objZip, $source, $target) + protected function addFileToPackage($zipPackage, $source, $target) { $isArchive = strpos($source, 'zip://') !== false; $actualSource = null; @@ -335,8 +328,7 @@ abstract class AbstractWriter implements WriterInterface $source = substr($source, 6); list($zipFilename, $imageFilename) = explode('#', $source); - $zipClass = Settings::getZipClass(); - $zip = new $zipClass(); + $zip = new ZipArchive; if ($zip->open($zipFilename) !== false) { if ($zip->locateName($imageFilename)) { $zip->extractTo($this->getTempDir(), $imageFilename); @@ -349,7 +341,7 @@ abstract class AbstractWriter implements WriterInterface } if (!is_null($actualSource)) { - $objZip->addFile($actualSource, $target); + $zipPackage->addFile($actualSource, $target); } } diff --git a/src/PhpWord/Writer/HTML/Element/Image.php b/src/PhpWord/Writer/HTML/Element/Image.php index ea06d4e2..dafc1c38 100644 --- a/src/PhpWord/Writer/HTML/Element/Image.php +++ b/src/PhpWord/Writer/HTML/Element/Image.php @@ -18,7 +18,7 @@ namespace PhpOffice\PhpWord\Writer\HTML\Element; use PhpOffice\PhpWord\Element\Image as ImageElement; -use PhpOffice\PhpWord\Settings; +use PhpOffice\PhpWord\Shared\ZipArchive; use PhpOffice\PhpWord\Writer\HTML\Style\Image as ImageStyleWriter; /** @@ -77,8 +77,7 @@ class Image extends Text $source = substr($source, 6); list($zipFilename, $imageFilename) = explode('#', $source); - $zipClass = Settings::getZipClass(); - $zip = new $zipClass(); + $zip = new ZipArchive(); if ($zip->open($zipFilename) !== false) { if ($zip->locateName($imageFilename)) { $zip->extractTo($this->parentWriter->getTempDir(), $imageFilename); diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index dc2c5d2c..a0dfcf74 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -17,7 +17,6 @@ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\PhpWord; @@ -63,31 +62,27 @@ class ODText extends AbstractWriter implements WriterInterface * Save PhpWord to file * * @param string $filename - * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($filename = null) { $filename = $this->getTempFile($filename); - $objZip = $this->getZipArchive($filename); + $zip = $this->getZipArchive($filename); // Add section media files $sectionMedia = Media::getElements('section'); if (!empty($sectionMedia)) { - $this->addFilesToPackage($objZip, $sectionMedia); + $this->addFilesToPackage($zip, $sectionMedia); } // Write parts foreach ($this->parts as $partName => $fileName) { if ($fileName != '') { - $objZip->addFromString($fileName, $this->getWriterPart($partName)->write()); + $zip->addFromString($fileName, $this->getWriterPart($partName)->write()); } } - // Close file - if ($objZip->close() === false) { - throw new Exception("Could not close zip file $filename."); - } - + // Close zip archive and cleanup temp file + $zip->close(); $this->cleanupTempFile(); } } diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 0cb65e6a..79556d64 100644 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -18,9 +18,9 @@ namespace PhpOffice\PhpWord\Writer; use PhpOffice\PhpWord\Element\Section; -use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Media; use PhpOffice\PhpWord\PhpWord; +use PhpOffice\PhpWord\Shared\ZipArchive; /** * Word2007 writer @@ -88,13 +88,12 @@ class Word2007 extends AbstractWriter implements WriterInterface * Save document by name * * @param string $filename - * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($filename = null) { - $phpWord = $this->getPhpWord(); $filename = $this->getTempFile($filename); - $objZip = $this->getZipArchive($filename); + $zip = $this->getZipArchive($filename); + $phpWord = $this->getPhpWord(); // Content types $this->contentTypes['default'] = array( @@ -105,7 +104,7 @@ class Word2007 extends AbstractWriter implements WriterInterface // Add section media files $sectionMedia = Media::getElements('section'); if (!empty($sectionMedia)) { - $this->addFilesToPackage($objZip, $sectionMedia); + $this->addFilesToPackage($zip, $sectionMedia); $this->registerContentTypes($sectionMedia); foreach ($sectionMedia as $element) { $this->relationships[] = $element; @@ -113,32 +112,29 @@ class Word2007 extends AbstractWriter implements WriterInterface } // Add header/footer media files & relations - $this->addHeaderFooterMedia($objZip, 'header'); - $this->addHeaderFooterMedia($objZip, 'footer'); + $this->addHeaderFooterMedia($zip, 'header'); + $this->addHeaderFooterMedia($zip, 'footer'); // Add header/footer contents $rId = Media::countElements('section') + 6; // @see Rels::writeDocRels for 6 first elements $sections = $phpWord->getSections(); foreach ($sections as $section) { - $this->addHeaderFooterContent($section, $objZip, 'header', $rId); - $this->addHeaderFooterContent($section, $objZip, 'footer', $rId); + $this->addHeaderFooterContent($section, $zip, 'header', $rId); + $this->addHeaderFooterContent($section, $zip, 'footer', $rId); } - $this->addNotes($objZip, $rId, 'footnote'); - $this->addNotes($objZip, $rId, 'endnote'); + $this->addNotes($zip, $rId, 'footnote'); + $this->addNotes($zip, $rId, 'endnote'); // Write parts foreach ($this->parts as $partName => $fileName) { if ($fileName != '') { - $objZip->addFromString($fileName, $this->getWriterPart($partName)->write()); + $zip->addFromString($fileName, $this->getWriterPart($partName)->write()); } } - // Close file - if ($objZip->close() === false) { - throw new Exception("Could not close zip file $filename."); - } - + // Close zip archive and cleanup temp file + $zip->close(); $this->cleanupTempFile(); } @@ -165,22 +161,22 @@ class Word2007 extends AbstractWriter implements WriterInterface /** * Add header/footer media files, e.g. footer1.xml.rels * - * @param mixed $objZip + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param string $docPart */ - private function addHeaderFooterMedia($objZip, $docPart) + private function addHeaderFooterMedia(ZipArchive $zip, $docPart) { $elements = Media::getElements($docPart); if (!empty($elements)) { foreach ($elements as $file => $media) { if (count($media) > 0) { if (!empty($media)) { - $this->addFilesToPackage($objZip, $media); + $this->addFilesToPackage($zip, $media); $this->registerContentTypes($media); } $writerPart = $this->getWriterPart('relspart')->setMedia($media); - $objZip->addFromString("word/_rels/{$file}.xml.rels", $writerPart->write()); + $zip->addFromString("word/_rels/{$file}.xml.rels", $writerPart->write()); } } } @@ -190,11 +186,11 @@ class Word2007 extends AbstractWriter implements WriterInterface * Add header/footer content * * @param \PhpOffice\PhpWord\Element\Section $section - * @param mixed $objZip + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param string $elmType header|footer * @param integer $rId */ - private function addHeaderFooterContent(Section &$section, $objZip, $elmType, &$rId) + private function addHeaderFooterContent(Section &$section, ZipArchive $zip, $elmType, &$rId) { $getFunction = $elmType == 'header' ? 'getHeaders' : 'getFooters'; $elmCount = ($section->getSectionId() - 1) * 3; @@ -207,18 +203,18 @@ class Word2007 extends AbstractWriter implements WriterInterface $this->relationships[] = array('target' => $elmFile, 'type' => $elmType, 'rID' => $rId); $writerPart = $this->getWriterPart($elmType)->setElement($element); - $objZip->addFromString("word/$elmFile", $writerPart->write()); + $zip->addFromString("word/$elmFile", $writerPart->write()); } } /** * Add footnotes/endnotes * - * @param mixed $objZip + * @param \PhpOffice\PhpWord\Shared\ZipArchive $zip * @param integer $rId * @param string $noteType */ - private function addNotes($objZip, &$rId, $noteType = 'footnote') + private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote') { $phpWord = $this->getPhpWord(); $noteType = ($noteType == 'endnote') ? 'endnote' : 'footnote'; @@ -229,7 +225,7 @@ class Word2007 extends AbstractWriter implements WriterInterface // Add footnotes media files, relations, and contents if ($collection->countItems() > 0) { $media = Media::getElements($noteType); - $this->addFilesToPackage($objZip, $media); + $this->addFilesToPackage($zip, $media); $this->registerContentTypes($media); $this->contentTypes['override']["/word/{$partName}.xml"] = $partName; $this->relationships[] = array('target' => "{$partName}.xml", 'type' => $partName, 'rID' => ++$rId); @@ -237,12 +233,12 @@ class Word2007 extends AbstractWriter implements WriterInterface // Write relationships file, e.g. word/_rels/footnotes.xml if (!empty($media)) { $writerPart = $this->getWriterPart('relspart')->setMedia($media); - $objZip->addFromString("word/_rels/{$partName}.xml.rels", $writerPart->write()); + $zip->addFromString("word/_rels/{$partName}.xml.rels", $writerPart->write()); } // Write content file, e.g. word/footnotes.xml $writerPart = $this->getWriterPart($partName)->setElements($collection->getItems()); - $objZip->addFromString("word/{$partName}.xml", $writerPart->write()); + $zip->addFromString("word/{$partName}.xml", $writerPart->write()); } } diff --git a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php index 41537a04..d4dad71b 100644 --- a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php +++ b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php @@ -17,6 +17,7 @@ namespace PhpOffice\PhpWord\Tests\Shared; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Shared\ZipArchive; /** @@ -32,23 +33,69 @@ class ZipArchiveTest extends \PHPUnit_Framework_TestCase * * @covers :: */ - public function testAllMethods() + public function testZipArchive() { // Preparation $existingFile = __DIR__ . "/../_files/documents/sheet.xls"; $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; - $destination1 = __DIR__ . "/../_files/extract1"; - $destination2 = __DIR__ . "/../_files/extract2"; - $destination3 = __DIR__ . "/../_files/extract3"; + $destination1 = __DIR__ . "/../_files/documents/extract1"; + $destination2 = __DIR__ . "/../_files/documents/extract2"; @mkdir($destination1); @mkdir($destination2); - @mkdir($destination3); + + Settings::setZipClass('PhpOffice\PhpWord\Shared\ZipArchive'); $object = new ZipArchive(); - $object->open($zipFile); + $object->open($zipFile, ZipArchive::CREATE); $object->addFile($existingFile, 'xls/new.xls'); $object->addFromString('content/string.txt', 'Test'); $object->close(); + $object->open($zipFile); + + // Run tests + $this->assertEquals(0, $object->locateName('xls/new.xls')); + $this->assertFalse($object->locateName('blablabla')); + + $this->assertEquals('Test', $object->getFromName('content/string.txt')); + $this->assertEquals('Test', $object->getFromName('/content/string.txt')); + + $this->assertFalse($object->getNameIndex(-1)); + $this->assertEquals('content/string.txt', $object->getNameIndex(1)); + + $this->assertFalse($object->extractTo('blablabla')); + $this->assertTrue($object->extractTo($destination1)); + $this->assertTrue($object->extractTo($destination2, 'xls/new.xls')); + $this->assertFalse($object->extractTo($destination2, 'blablabla')); + + // Cleanup + $this->deleteDir($destination1); + $this->deleteDir($destination2); + @unlink($zipFile); + } + + /** + * Test all methods + * + * @covers :: + */ + public function testPCLZip() + { + // Preparation + $existingFile = __DIR__ . "/../_files/documents/sheet.xls"; + $zipFile = __DIR__ . "/../_files/documents/ziptest.zip"; + $destination1 = __DIR__ . "/../_files/documents/extract1"; + $destination2 = __DIR__ . "/../_files/documents/extract2"; + @mkdir($destination1); + @mkdir($destination2); + + Settings::setZipClass('ZipArchive'); + + $object = new ZipArchive(); + $object->open($zipFile, ZipArchive::CREATE); + $object->addFile($existingFile, 'xls/new.xls'); + $object->addFromString('content/string.txt', 'Test'); + $object->close(); + $object->open($zipFile); // Run tests $this->assertEquals(0, $object->locateName('xls/new.xls')); @@ -68,7 +115,6 @@ class ZipArchiveTest extends \PHPUnit_Framework_TestCase // Cleanup $this->deleteDir($destination1); $this->deleteDir($destination2); - $this->deleteDir($destination3); @unlink($zipFile); }