diff --git a/CHANGELOG.md b/CHANGELOG.md index d8268a73..b06aa79c 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,7 +27,7 @@ This release marked heavy refactorings on internal code structure with the creat - Object: Ability to add object in header, footer, textrun, and footnote - @ivanlanin GH-187 - Media: Add `Media::resetElements()` to reset all media data - @juzi GH-19 - General: Add `Style::resetStyles()`, `Footnote::resetElements()`, and `TOC::resetTitles()` - @ivanlanin GH-187 -- Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, and list - @ivanlanin +- DOCX Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, list, image - @ivanlanin - Endnote: Ability to add endnotes - @ivanlanin - ListItem: Ability to create custom list and reset list number - @ivanlanin GH-10 GH-198 - ODT Writer: Basic table writing support - @ivanlanin diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index c79aee32..2ab5a579 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -16,7 +16,7 @@ $writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' // Set PDF renderer $rendererName = \PhpOffice\PhpWord\Settings::PDF_RENDERER_DOMPDF; -$rendererLibraryPath = ''; // DomPDF library path +$rendererLibraryPath = 'D:\www\local\minerva\dompdf'; // DomPDF library path if (!\PhpOffice\PhpWord\Settings::setPdfRenderer($rendererName, $rendererLibraryPath)) { $writers['PDF'] = null; @@ -85,9 +85,11 @@ function write($phpWord, $filename, $writers) $result .= '

 

'; $result .= '

Results: '; foreach ($types as $type) { - $resultFile = 'results/' . SCRIPT_FILENAME . '.' . $type; - if (file_exists($resultFile)) { - $result .= "{$type} "; + if (!is_null($type)) { + $resultFile = 'results/' . SCRIPT_FILENAME . '.' . $type; + if (file_exists($resultFile)) { + $result .= "{$type} "; + } } } $result .= '

'; diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php index ce4b1609..19451c9e 100755 --- a/src/PhpWord/Element/Image.php +++ b/src/PhpWord/Element/Image.php @@ -85,66 +85,11 @@ class Image extends AbstractElement */ public function __construct($source, $style = null, $isWatermark = false) { - // Detect if it's a memory image, by .php ext or by URL - if (stripos(strrev($source), strrev('.php')) === 0) { - $this->isMemImage = true; - } else { - $this->isMemImage = (filter_var($source, FILTER_VALIDATE_URL) !== false); - } - - // Check supported types - if ($this->isMemImage) { - $supportedTypes = array('image/jpeg', 'image/gif', 'image/png'); - $imgData = @getimagesize($source); - if (!is_array($imgData)) { - throw new InvalidImageException(); - } - $this->imageType = $imgData['mime']; // string - if (!in_array($this->imageType, $supportedTypes)) { - throw new UnsupportedImageTypeException(); - } - } else { - $supportedTypes = array( - IMAGETYPE_JPEG, IMAGETYPE_GIF, - IMAGETYPE_PNG, IMAGETYPE_BMP, - IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM - ); - if (!file_exists($source)) { - throw new InvalidImageException(); - } - $imgData = getimagesize($source); - if (function_exists('exif_imagetype')) { - $this->imageType = exif_imagetype($source); - } else { - // @codeCoverageIgnoreStart - $tmp = getimagesize($source); - $this->imageType = $tmp[2]; - // @codeCoverageIgnoreEnd - } - if (!in_array($this->imageType, $supportedTypes)) { - throw new UnsupportedImageTypeException(); - } - $this->imageType = image_type_to_mime_type($this->imageType); - } - - // Set private properties $this->source = $source; - $this->isWatermark = $isWatermark; + $this->setIsWatermark($isWatermark); $this->style = $this->setStyle(new ImageStyle(), $style, true); - $styleWidth = $this->style->getWidth(); - $styleHeight = $this->style->getHeight(); - list($actualWidth, $actualHeight) = $imgData; - if (!($styleWidth && $styleHeight)) { - if ($styleWidth == null && $styleHeight == null) { - $this->style->setWidth($actualWidth); - $this->style->setHeight($actualHeight); - } elseif ($styleWidth) { - $this->style->setHeight($actualHeight * ($styleWidth / $actualWidth)); - } else { - $this->style->setWidth($actualWidth * ($styleHeight / $actualHeight)); - } - } - $this->setImageFunctions(); + + $this->checkImage($source); } /** @@ -248,10 +193,55 @@ class Image extends AbstractElement } /** - * Set image functions + * Check memory image, supported type, image functions, and proportional width/height + * + * @param string $source */ - private function setImageFunctions() + private function checkImage($source) { + $isArchive = strpos($source, 'zip://') !== false; + + // Check is memory image + if (stripos(strrev($source), strrev('.php')) === 0) { + $this->isMemImage = true; + } elseif ($isArchive) { + $this->isMemImage = false; + } else { + $this->isMemImage = (filter_var($source, FILTER_VALIDATE_URL) !== false); + } + + // Define supported types + if ($this->isMemImage) { + $supportedTypes = array( + IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG + ); + } else { + $supportedTypes = array( + IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG, + IMAGETYPE_BMP, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM + ); + } + + // Check from zip file or actual file + if ($isArchive) { + $imageData = $this->getArchivedImageSize($source); + } else { + $imageData = @getimagesize($source); + } + + // Check if image exists by detecting image data + if (!is_array($imageData)) { + throw new InvalidImageException(); + } + // Put image data into variables + list($actualWidth, $actualHeight, $imageType) = $imageData; + // Check if image type is supported + if (!in_array($imageType, $supportedTypes)) { + throw new UnsupportedImageTypeException(); + } + + // Define image functions + $this->imageType = image_type_to_mime_type($imageType); switch ($this->imageType) { case 'image/png': $this->imageCreateFunc = 'imagecreatefrompng'; @@ -264,13 +254,12 @@ class Image extends AbstractElement $this->imageExtension = 'gif'; break; case 'image/jpeg': - case 'image/jpg': $this->imageCreateFunc = 'imagecreatefromjpeg'; $this->imageFunc = 'imagejpeg'; $this->imageExtension = 'jpg'; break; - case 'image/x-ms-bmp': case 'image/bmp': + case 'image/x-ms-bmp': $this->imageType = 'image/bmp'; $this->imageExtension = 'bmp'; break; @@ -278,5 +267,49 @@ class Image extends AbstractElement $this->imageExtension = 'tif'; break; } + + // Check image width & height + $styleWidth = $this->style->getWidth(); + $styleHeight = $this->style->getHeight(); + if (!($styleWidth && $styleHeight)) { + if ($styleWidth == null && $styleHeight == null) { + $this->style->setWidth($actualWidth); + $this->style->setHeight($actualHeight); + } elseif ($styleWidth) { + $this->style->setHeight($actualHeight * ($styleWidth / $actualWidth)); + } else { + $this->style->setWidth($actualWidth * ($styleHeight / $actualHeight)); + } + } + + } + + /** + * Get image size from archive + * + * @param string $source + * @return array|null + */ + private function getArchivedImageSize($source) + { + $imageData = null; + $source = substr($source, 6); + list($zipFilename, $imageFilename) = explode('#', $source); + $tempFilename = tempnam(sys_get_temp_dir(), 'PHPWordImage'); + + $zip = new \ZipArchive(); + if ($zip->open($zipFilename) !== false) { + if ($zip->locateName($imageFilename)) { + $imageContent = $zip->getFromName($imageFilename); + if ($imageContent !== false) { + file_put_contents($tempFilename, $imageContent); + $imageData = @getimagesize($tempFilename); + unlink($tempFilename); + } + } + $zip->close(); + } + + return $imageData; } } diff --git a/src/PhpWord/Reader/Word2007.php b/src/PhpWord/Reader/Word2007.php index 9d74e540..931ba01a 100644 --- a/src/PhpWord/Reader/Word2007.php +++ b/src/PhpWord/Reader/Word2007.php @@ -38,6 +38,13 @@ class Word2007 extends AbstractReader implements ReaderInterface */ private $rels = array('main' => array(), 'document' => array()); + /** + * Filename + * + * @var string + */ + private $filename; + /** * Loads PhpWord from file * @@ -48,17 +55,17 @@ class Word2007 extends AbstractReader implements ReaderInterface { $this->phpWord = new PhpWord(); - $this->readRelationships($filename); - + $this->filename = $filename; + $this->readRelationships(); // Read styles and numbering first foreach ($this->rels['document'] as $rId => $rel) { switch ($rel['type']) { case 'styles': - $this->readStyles($filename, $rel['target']); + $this->readStyles($rel['target']); break; case 'numbering': - $this->readNumbering($filename, $rel['target']); + $this->readNumbering($rel['target']); break; } } @@ -68,7 +75,7 @@ class Word2007 extends AbstractReader implements ReaderInterface switch ($rel['type']) { case 'officeDocument': - $this->readDocument($filename, $rel['target']); + $this->readDocument($rel['target']); break; case 'core-properties': @@ -84,16 +91,16 @@ class Word2007 extends AbstractReader implements ReaderInterface 'dcterms:modified' => 'setModified', ); $callbacks = array('dcterms:created' => 'strtotime', 'dcterms:modified' => 'strtotime'); - $this->readDocProps($filename, $rel['target'], $mapping, $callbacks); + $this->readDocProps($rel['target'], $mapping, $callbacks); break; case 'extended-properties': $mapping = array('Company' => 'setCompany', 'Manager' => 'setManager'); - $this->readDocProps($filename, $rel['target'], $mapping); + $this->readDocProps($rel['target'], $mapping); break; case 'custom-properties': - $this->readDocPropsCustom($filename, $rel['target']); + $this->readDocPropsCustom($rel['target']); break; } } @@ -103,7 +110,7 @@ class Word2007 extends AbstractReader implements ReaderInterface switch ($rel['type']) { case 'footnotes': case 'endnotes': - $this->readNotes($filename, $rel['target'], $rel['type']); + $this->readNotes($rel['target'], $rel['type']); break; } } @@ -113,24 +120,22 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read all relationship files - * - * @param string $filename */ - private function readRelationships($filename) + private function readRelationships() { // _rels/.rels - $this->rels['main'] = $this->getRels($filename, '_rels/.rels'); + $this->rels['main'] = $this->getRels('_rels/.rels'); // word/_rels/*.xml.rels $wordRelsPath = 'word/_rels/'; $zipClass = Settings::getZipClass(); $zip = new $zipClass(); - if ($zip->open($filename) === true) { + if ($zip->open($this->filename) === true) { for ($i = 0; $i < $zip->numFiles; $i++) { $xmlFile = $zip->getNameIndex($i); if ((substr($xmlFile, 0, strlen($wordRelsPath))) == $wordRelsPath && (substr($xmlFile, -1)) != '/') { $docPart = str_replace('.xml.rels', '', str_replace($wordRelsPath, '', $xmlFile)); - $this->rels[$docPart] = $this->getRels($filename, $xmlFile, 'word/'); + $this->rels[$docPart] = $this->getRels($xmlFile, 'word/'); } } $zip->close(); @@ -140,15 +145,14 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read core and extended document properties * - * @param string $filename * @param string $xmlFile * @param array $mapping * @param array $callbacks */ - private function readDocProps($filename, $xmlFile, $mapping, $callbacks = array()) + private function readDocProps($xmlFile, $mapping, $callbacks = array()) { $xmlReader = new XMLReader(); - $xmlReader->getDomFromZip($filename, $xmlFile); + $xmlReader->getDomFromZip($this->filename, $xmlFile); $docProps = $this->phpWord->getDocumentProperties(); $nodes = $xmlReader->getElements('*'); @@ -172,13 +176,12 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read custom document properties * - * @param string $filename * @param string $xmlFile */ - private function readDocPropsCustom($filename, $xmlFile) + private function readDocPropsCustom($xmlFile) { $xmlReader = new XMLReader(); - $xmlReader->getDomFromZip($filename, $xmlFile); + $xmlReader->getDomFromZip($this->filename, $xmlFile); $docProps = $this->phpWord->getDocumentProperties(); $nodes = $xmlReader->getElements('*'); @@ -198,13 +201,12 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read document.xml * - * @param string $filename * @param string $xmlFile */ - private function readDocument($filename, $xmlFile) + private function readDocument($xmlFile) { $xmlReader = new XMLReader(); - $xmlReader->getDomFromZip($filename, $xmlFile); + $xmlReader->getDomFromZip($this->filename, $xmlFile); $nodes = $xmlReader->getElements('w:body/*'); if ($nodes->length > 0) { @@ -225,7 +227,7 @@ class Word2007 extends AbstractReader implements ReaderInterface $settings = $this->readSectionStyle($xmlReader, $settingsNode); $section->setSettings($settings); if (!is_null($settings)) { - $this->readHeaderFooter($filename, $settings, $section); + $this->readHeaderFooter($settings, $section); } } $section = $this->phpWord->addSection(); @@ -240,7 +242,7 @@ class Word2007 extends AbstractReader implements ReaderInterface $settings = $this->readSectionStyle($xmlReader, $node); $section->setSettings($settings); if (!is_null($settings)) { - $this->readHeaderFooter($filename, $settings, $section); + $this->readHeaderFooter($settings, $section); } break; } @@ -251,13 +253,12 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read styles.xml * - * @param string $filename * @param string $xmlFile */ - private function readStyles($filename, $xmlFile) + private function readStyles($xmlFile) { $xmlReader = new XMLReader(); - $xmlReader->getDomFromZip($filename, $xmlFile); + $xmlReader->getDomFromZip($this->filename, $xmlFile); $nodes = $xmlReader->getElements('w:style'); if ($nodes->length > 0) { @@ -303,15 +304,14 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read numbering.xml * - * @param string $filename * @param string $xmlFile */ - private function readNumbering($filename, $xmlFile) + private function readNumbering($xmlFile) { $abstracts = array(); $numberings = array(); $xmlReader = new XMLReader(); - $xmlReader->getDomFromZip($filename, $xmlFile); + $xmlReader->getDomFromZip($this->filename, $xmlFile); // Abstract numbering definition $nodes = $xmlReader->getElements('w:abstractNum'); @@ -395,11 +395,10 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read header footer * - * @param string $filename * @param array $settings * @param Section $section */ - private function readHeaderFooter($filename, $settings, &$section) + private function readHeaderFooter($settings, &$section) { if (is_array($settings) && array_key_exists('hf', $settings)) { foreach ($settings['hf'] as $rId => $hfSetting) { @@ -410,7 +409,7 @@ class Word2007 extends AbstractReader implements ReaderInterface // Read header/footer content $xmlReader = new XMLReader(); - $xmlReader->getDomFromZip($filename, $xmlFile); + $xmlReader->getDomFromZip($this->filename, $xmlFile); $nodes = $xmlReader->getElements('*'); if ($nodes->length > 0) { foreach ($nodes as $node) { @@ -434,18 +433,17 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Read (footnotes|endnotes).xml * - * @param string $filename * @param string $xmlFile * @param string $notesType */ - private function readNotes($filename, $xmlFile, $notesType = 'footnotes') + private function readNotes($xmlFile, $notesType = 'footnotes') { $notesType = ($notesType == 'endnotes') ? 'endnotes' : 'footnotes'; $collectionClass = 'PhpOffice\\PhpWord\\' . ucfirst($notesType); $collection = $collectionClass::getElements(); $xmlReader = new XMLReader(); - $xmlReader->getDomFromZip($filename, $xmlFile); + $xmlReader->getDomFromZip($this->filename, $xmlFile); $nodes = $xmlReader->getElements('*'); if ($nodes->length > 0) { foreach ($nodes as $node) { @@ -581,8 +579,8 @@ class Word2007 extends AbstractReader implements ReaderInterface $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:pict/v:shape/v:imagedata'); $target = $this->getMediaTarget($docPart, $rId); if (!is_null($target)) { - $textContent = ""; - $parent->addText($textContent, $fStyle, $pStyle); + $imageSource = "zip://{$this->filename}#{$target}"; + $parent->addImage($imageSource); } // Object @@ -943,12 +941,11 @@ class Word2007 extends AbstractReader implements ReaderInterface /** * Get relationship array * - * @param string $filename * @param string $xmlFile * @param string $targetPrefix * @return array */ - private function getRels($filename, $xmlFile, $targetPrefix = '') + private function getRels($xmlFile, $targetPrefix = '') { $metaPrefix = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/'; $officePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/'; @@ -956,7 +953,7 @@ class Word2007 extends AbstractReader implements ReaderInterface $rels = array(); $xmlReader = new XMLReader(); - $xmlReader->getDomFromZip($filename, $xmlFile); + $xmlReader->getDomFromZip($this->filename, $xmlFile); $nodes = $xmlReader->getElements('*'); foreach ($nodes as $node) { $rId = $xmlReader->getAttribute('Id', $node); diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 684a5d32..9403d724 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -62,6 +62,13 @@ abstract class AbstractWriter implements WriterInterface */ private $tempFilename; + /** + * Temporary directory + * + * @var string + */ + private $tempDir; + /** * Get PhpWord object * @@ -156,6 +163,14 @@ abstract class AbstractWriter implements WriterInterface */ protected function getTempFile($filename) { + // Temporary directory + $tempDir = sys_get_temp_dir() . '/PHPWordMedia/'; + if (!is_dir($tempDir)) { + mkdir($tempDir); + } + $this->tempDir = $tempDir; + + // Temporary file $this->originalFilename = $filename; if (strtolower($filename) == 'php://output' || strtolower($filename) == 'php://stdout') { $filename = @tempnam(sys_get_temp_dir(), 'phpword_'); @@ -168,6 +183,16 @@ abstract class AbstractWriter implements WriterInterface return $this->tempFilename; } + /** + * Cleanup temporary file + * + * If a temporary file was used, copy it to the correct file stream + */ + protected function getTempDir() + { + return $this->tempDir; + } + /** * Cleanup temporary file * @@ -175,12 +200,18 @@ abstract class AbstractWriter implements WriterInterface */ protected function cleanupTempFile() { + // File if ($this->originalFilename != $this->tempFilename) { if (copy($this->tempFilename, $this->originalFilename) === false) { throw new Exception("Could not copy temporary zip file {$this->tempFilename} to {$this->originalFilename}."); } @unlink($this->tempFilename); } + + // Directory + if (is_dir($this->tempDir)) { + $this->deleteDir($this->tempDir); + } } /** @@ -215,4 +246,24 @@ abstract class AbstractWriter implements WriterInterface return $objZip; } + + /** + * Delete directory + * + * @param string $dir + */ + private function deleteDir($dir) + { + foreach (scandir($dir) as $file) { + if ($file === '.' || $file === '..') { + continue; + } elseif (is_file($dir . "/" . $file)) { + unlink($dir . "/" . $file); + } elseif (is_dir($dir . "/" . $file)) { + $this->deleteDir($dir . "/" . $file); + } + } + + rmdir($dir); + } } diff --git a/src/PhpWord/Writer/HTML.php b/src/PhpWord/Writer/HTML.php index f0879332..f0720f66 100644 --- a/src/PhpWord/Writer/HTML.php +++ b/src/PhpWord/Writer/HTML.php @@ -347,7 +347,10 @@ class HTML extends AbstractWriter implements WriterInterface */ private function writeListItem($element) { - return $this->writeUnsupportedElement($element, false); + $text = htmlspecialchars($element->getTextObject()->getText()); + $html = '

' . $text . '' . PHP_EOL; + + return $html; } /** diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php index 3ee96966..be48a9f2 100644 --- a/src/PhpWord/Writer/PDF/AbstractRenderer.php +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -69,7 +69,7 @@ abstract class AbstractRenderer extends \PhpOffice\PhpWord\Writer\HTML public function __construct(PhpWord $phpWord) { parent::__construct($phpWord); - $this->tempDir = sys_get_temp_dir(); + $this->setTempDir(sys_get_temp_dir()); } /** diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php index a5db2d99..d4c7b5f8 100644 --- a/src/PhpWord/Writer/PDF/DomPDF.php +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -13,14 +13,6 @@ use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\Exception\Exception; -/** Require DomPDF library */ -$pdfRendererClassFile = Settings::getPdfRendererPath() . '/dompdf_config.inc.php'; -if (file_exists($pdfRendererClassFile)) { - require_once $pdfRendererClassFile; -} else { - throw new Exception('Unable to load PDF Rendering library'); -} - /** * DomPDF writer */ @@ -34,6 +26,12 @@ class DomPDF extends AbstractRenderer implements \PhpOffice\PhpWord\Writer\Write public function __construct(PhpWord $phpWord) { parent::__construct($phpWord); + $configFile = Settings::getPdfRendererPath() . '/dompdf_config.inc.php'; + if (file_exists($configFile)) { + require_once $configFile; + } else { + throw new Exception('Unable to load PDF Rendering library'); + } } /** diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php index 7b552905..0d0c0f69 100755 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -145,10 +145,11 @@ class Word2007 extends AbstractWriter implements WriterInterface private function addFilesToPackage($objZip, $elements) { foreach ($elements as $element) { - // Do not add link + // Skip link if ($element['type'] == 'link') { continue; } + // Retrieve remote image if (isset($element['isMemImage']) && $element['isMemImage']) { $image = call_user_func($element['createFunction'], $element['source']); @@ -159,8 +160,9 @@ class Word2007 extends AbstractWriter implements WriterInterface $objZip->addFromString('word/' . $element['target'], $imageContents); imagedestroy($image); } else { - $objZip->addFile($element['source'], 'word/' . $element['target']); + $this->addFileToPackage($objZip, $element['source'], $element['target']); } + // Register content types if ($element['type'] == 'image') { $imageExtension = $element['imageExtension']; @@ -176,6 +178,38 @@ class Word2007 extends AbstractWriter implements WriterInterface } } + /** + * Add file to package + * + * @param mixed $objZip + * @param string $source + * @param string $target + */ + private function addFileToPackage($objZip, $source, $target) + { + $isArchive = strpos($source, 'zip://') !== false; + $actualSource = null; + if ($isArchive) { + $source = substr($source, 6); + list($zipFilename, $imageFilename) = explode('#', $source); + + $zip = new \ZipArchive(); + if ($zip->open($zipFilename) !== false) { + if ($zip->locateName($imageFilename)) { + $zip->extractTo($this->getTempDir(), $imageFilename); + $actualSource = $this->getTempDir() . DIRECTORY_SEPARATOR . $imageFilename; + } + } + $zip->close(); + } else { + $actualSource = $source; + } + + if (!is_null($actualSource)) { + $objZip->addFile($actualSource, 'word/' . $target); + } + } + /** * Add header/footer media files * diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php index eae9fc5f..eb482398 100644 --- a/tests/PhpWord/Tests/Element/ImageTest.php +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -51,34 +51,29 @@ class ImageTest extends \PHPUnit_Framework_TestCase /** * Valid image types */ - public function testValidImageTypes() + public function testImages() { - new Image(__DIR__ . "/../_files/images/mars_noext_jpg"); - new Image(__DIR__ . "/../_files/images/mars.jpg"); - new Image(__DIR__ . "/../_files/images/mario.gif"); - new Image(__DIR__ . "/../_files/images/firefox.png"); - new Image(__DIR__ . "/../_files/images/duke_nukem.bmp"); - new Image(__DIR__ . "/../_files/images/angela_merkel.tif"); - } + $images = array( + array('mars.jpg', 'image/jpeg', 'jpg', 'imagecreatefromjpeg', 'imagejpeg'), + array('mario.gif', 'image/gif', 'gif', 'imagecreatefromgif', 'imagegif'), + array('firefox.png', 'image/png', 'png', 'imagecreatefrompng', 'imagepng'), + array('duke_nukem.bmp', 'image/bmp', 'bmp', null, null), + array('angela_merkel.tif', 'image/tiff', 'tif', null, null), + ); - /** - * Image not found - * - * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException - */ - public function testImageNotFound() - { - new Image(__DIR__ . "/../_files/images/thisisnotarealimage"); - } - - /** - * Invalid image types - * - * @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException - */ - public function testInvalidImageTypes() - { - new Image(__DIR__ . "/../_files/images/alexz-johnson.pcx"); + foreach ($images as $imageData) { + list($source, $type, $extension, $createFunction, $imageFunction) = $imageData; + $source = __DIR__ . "/../_files/images/" . $source; + $image = new Image($source); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $image); + $this->assertEquals($image->getSource(), $source); + $this->assertEquals($image->getMediaId(), md5($source)); + $this->assertEquals($image->getImageType(), $type); + $this->assertEquals($image->getImageExtension(), $extension); + $this->assertEquals($image->getImageCreateFunction(), $createFunction); + $this->assertEquals($image->getImageFunction(), $imageFunction); + $this->assertFalse($image->getIsMemImage()); + } } /** @@ -88,18 +83,40 @@ class ImageTest extends \PHPUnit_Framework_TestCase { $oImage = new Image( __DIR__ . "/../_files/images/earth.jpg", - array('width' => 210, 'height' => 210, 'align' => 'center') + array('height' => 210, 'align' => 'center') ); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); } /** - * Test set wrapping style + * Test invalid local image + * + * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException */ - public function testStyleWrappingStyle() + public function testInvalidImageLocal() { + new Image(__DIR__ . "/../_files/images/thisisnotarealimage"); + } + /** + * Test invalid PHP Image + * + * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException + */ + public function testInvalidImagePhp() + { + $object = new Image('test.php'); + } + + /** + * Test unsupported image + * + * @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException + */ + public function testUnsupportedImage() + { + $object = new Image('http://samples.libav.org/image-samples/RACECAR.BMP'); } /** @@ -107,117 +124,20 @@ class ImageTest extends \PHPUnit_Framework_TestCase */ public function testRelationID() { - $oImage = new Image(__DIR__ . "/../_files/images/earth.jpg"); + $oImage = new Image(__DIR__ . "/../_files/images/earth.jpg", array('width' => 100)); $iVal = rand(1, 1000); $oImage->setRelationId($iVal); $this->assertEquals($oImage->getRelationId(), $iVal); } /** - * Get is watermark + * Test archived image */ - public function testWatermark() + public function testArchivedImage() { - $oImage = new Image(__DIR__ . "/../_files/images/earth.jpg"); - $oImage->setIsWatermark(true); - $this->assertEquals($oImage->getIsWatermark(), true); - } - - /** - * Test PNG - */ - public function testPNG() - { - $src = __DIR__ . "/../_files/images/firefox.png"; - $oImage = new Image($src, array('width' => 100)); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); - $this->assertEquals($oImage->getSource(), $src); - $this->assertEquals($oImage->getMediaId(), md5($src)); - $this->assertEquals($oImage->getImageCreateFunction(), 'imagecreatefrompng'); - $this->assertEquals($oImage->getImageFunction(), 'imagepng'); - $this->assertEquals($oImage->getImageExtension(), 'png'); - $this->assertEquals($oImage->getImageType(), 'image/png'); - } - - /** - * Test GIF - */ - public function testGIF() - { - $src = __DIR__ . "/../_files/images/mario.gif"; - $oImage = new Image($src, array('height' => 100)); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); - $this->assertEquals($oImage->getSource(), $src); - $this->assertEquals($oImage->getMediaId(), md5($src)); - $this->assertEquals($oImage->getImageCreateFunction(), 'imagecreatefromgif'); - $this->assertEquals($oImage->getImageFunction(), 'imagegif'); - $this->assertEquals($oImage->getImageExtension(), 'gif'); - $this->assertEquals($oImage->getImageType(), 'image/gif'); - } - - /** - * Test JPG - */ - public function testJPG() - { - $src = __DIR__ . "/../_files/images/earth.jpg"; - $oImage = new Image($src); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); - $this->assertEquals($oImage->getSource(), $src); - $this->assertEquals($oImage->getMediaId(), md5($src)); - $this->assertEquals($oImage->getImageCreateFunction(), 'imagecreatefromjpeg'); - $this->assertEquals($oImage->getImageFunction(), 'imagejpeg'); - $this->assertEquals($oImage->getImageExtension(), 'jpg'); - $this->assertEquals($oImage->getImageType(), 'image/jpeg'); - } - - /** - * Test BMP - */ - public function testBMP() - { - $oImage = new Image(__DIR__ . "/../_files/images/duke_nukem.bmp"); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); - $this->assertEquals($oImage->getImageCreateFunction(), null); - $this->assertEquals($oImage->getImageFunction(), null); - $this->assertEquals($oImage->getImageExtension(), 'bmp'); - $this->assertEquals($oImage->getImageType(), 'image/bmp'); - } - - /** - * Test TIFF - */ - public function testTIFF() - { - $oImage = new Image(__DIR__ . "/../_files/images/angela_merkel.tif"); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); - $this->assertEquals($oImage->getImageCreateFunction(), null); - $this->assertEquals($oImage->getImageFunction(), null); - $this->assertEquals($oImage->getImageType(), 'image/tiff'); - } - - /** - * Test PHP Image - * - * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException - */ - public function testPhpImage() - { - $object = new Image('test.php'); - } - - /** - * Test PCX Image and Memory - * - * @expectedException \PhpOffice\PhpWord\Exception\UnsupportedImageTypeException - */ - public function testPcxImage() - { - $object = new Image('http://samples.libav.org/image-samples/RACECAR.BMP'); + $archiveFile = __DIR__ . "/../_files/documents/reader.docx"; + $imageFile = 'word/media/image1.jpeg'; + $image = new Image("zip://{$archiveFile}#{$imageFile}"); + $this->assertEquals('image/jpeg', $image->getImageType()); } } diff --git a/tests/PhpWord/Tests/SettingsTest.php b/tests/PhpWord/Tests/SettingsTest.php index fa78489e..46efdf76 100644 --- a/tests/PhpWord/Tests/SettingsTest.php +++ b/tests/PhpWord/Tests/SettingsTest.php @@ -19,9 +19,9 @@ use PhpOffice\PhpWord\Settings; class SettingsTest extends \PHPUnit_Framework_TestCase { /** - * Get/set compatibity option + * Test set/get compatibity option */ - public function testGetSetCompatibility() + public function testSetGetCompatibility() { $this->assertTrue(Settings::getCompatibility()); $this->assertTrue(Settings::setCompatibility(false)); @@ -30,12 +30,23 @@ class SettingsTest extends \PHPUnit_Framework_TestCase } /** - * Get/set zip class + * Test set/get zip class */ - public function testGetSetZipClass() + public function testSetGetZipClass() { $this->assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass()); $this->assertTrue(Settings::setZipClass(Settings::PCLZIP)); $this->assertFalse(Settings::setZipClass('foo')); } + + public function testSetGetPdfRenderer() + { + $domPdfPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); + + $this->assertFalse(Settings::setPdfRenderer('FOO', 'dummy/path')); + $this->assertTrue(Settings::setPdfRenderer(Settings::PDF_RENDERER_DOMPDF, $domPdfPath)); + $this->assertEquals(Settings::PDF_RENDERER_DOMPDF, Settings::getPdfRendererName()); + $this->assertEquals($domPdfPath, Settings::getPdfRendererPath()); + $this->assertFalse(Settings::setPdfRendererPath('dummy/path')); + } } diff --git a/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php b/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php new file mode 100644 index 00000000..3282eecb --- /dev/null +++ b/tests/PhpWord/Tests/Writer/PDF/DomPDFTest.php @@ -0,0 +1,70 @@ +addSection(); + $section->addText('Test 1'); + + $rendererName = Settings::PDF_RENDERER_DOMPDF; + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + $writer = new PDF($phpWord); + $writer->save($file); + + $this->assertTrue(file_exists($file)); + + unlink($file); + } + + /** + * Test set/get abstract renderer properties + */ + public function testSetGetAbstractRendererProperties() + { + define('DOMPDF_ENABLE_AUTOLOAD', false); + $file = __DIR__ . "/../../_files/temp.pdf"; + + $rendererName = Settings::PDF_RENDERER_DOMPDF; + $rendererLibraryPath = realpath(PHPWORD_TESTS_BASE_DIR . '/../vendor/dompdf/dompdf'); + Settings::setPdfRenderer($rendererName, $rendererLibraryPath); + $writer = new PDF(new PhpWord()); + + $writer->setFont('arial'); + $this->assertEquals('arial', $writer->getFont()); + + $writer->setPaperSize(); + $this->assertEquals(9, $writer->getPaperSize()); + + $writer->setOrientation(); + $this->assertEquals('default', $writer->getOrientation()); + + $writer->setTempDir(sys_get_temp_dir()); + $this->assertEquals(sys_get_temp_dir(), $writer->getTempDir()); + } +} diff --git a/tests/PhpWord/Tests/Writer/PDFTest.php b/tests/PhpWord/Tests/Writer/PDFTest.php new file mode 100644 index 00000000..fba93054 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/PDFTest.php @@ -0,0 +1,51 @@ +save($file); + + $this->assertTrue(file_exists($file)); + + unlink($file); + } + + /** + * Test construct exception + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @expectedExceptionMessage PDF rendering library or library path has not been defined. + */ + public function testConstructException() + { + $writer = new PDF(new PhpWord()); + } +} diff --git a/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php b/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php index 904f45bd..05002578 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php @@ -159,6 +159,11 @@ class BaseTest extends \PHPUnit_Framework_TestCase $section->addImage(__DIR__ . "/../../_files/images/earth.jpg", $styles); } + $archiveFile = realpath(__DIR__ . '/../../_files/documents/reader.docx'); + $imageFile = 'word/media/image1.jpeg'; + $source = 'zip://D:\www\local\phpword\tests\PhpWord\Tests\_files\documents\reader.docx#' . $imageFile; + $section->addImage($source); + $doc = TestHelperDOCX::getDocument($phpWord); // behind