From 9e711124e95facead17e60730b5e9d382d046017 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Sun, 6 May 2012 23:25:37 +0200 Subject: [PATCH] ADDED : Writer ODText (Version de base) --- src/Examples/Text.php | 5 +- src/PHPWord/HashTable.php | 216 ++++++++++++++++++ src/PHPWord/Writer/ODText.php | 276 +++++++++++++++++++++++ src/PHPWord/Writer/ODText/Content.php | 110 +++++++++ src/PHPWord/Writer/ODText/Manifest.php | 126 +++++++++++ src/PHPWord/Writer/ODText/Meta.php | 100 ++++++++ src/PHPWord/Writer/ODText/Mimetype.php | 51 +++++ src/PHPWord/Writer/ODText/WriterPart.php | 68 ++++++ 8 files changed, 950 insertions(+), 2 deletions(-) create mode 100644 src/PHPWord/HashTable.php create mode 100644 src/PHPWord/Writer/ODText.php create mode 100644 src/PHPWord/Writer/ODText/Content.php create mode 100644 src/PHPWord/Writer/ODText/Manifest.php create mode 100644 src/PHPWord/Writer/ODText/Meta.php create mode 100644 src/PHPWord/Writer/ODText/Mimetype.php create mode 100644 src/PHPWord/Writer/ODText/WriterPart.php diff --git a/src/Examples/Text.php b/src/Examples/Text.php index 4437b926..1db1881e 100644 --- a/src/Examples/Text.php +++ b/src/Examples/Text.php @@ -19,9 +19,10 @@ $PHPWord->addParagraphStyle('pStyle', array('align'=>'center', 'spaceAfter'=>100 $section->addText('I am styled by two style definitions.', 'rStyle', 'pStyle'); $section->addText('I have only a paragraph style definition.', null, 'pStyle'); - - // Save File $objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'Word2007'); $objWriter->save('Text.docx'); + +$objWriter = PHPWord_IOFactory::createWriter($PHPWord, 'ODText'); +$objWriter->save('Text.odt'); ?> \ No newline at end of file diff --git a/src/PHPWord/HashTable.php b/src/PHPWord/HashTable.php new file mode 100644 index 00000000..5f791fd1 --- /dev/null +++ b/src/PHPWord/HashTable.php @@ -0,0 +1,216 @@ +addFromSource($pSource); + } + } + + /** + * Add HashTable items from source + * + * @param PHPWord_IComparable[] $pSource Source array to create HashTable from + * @throws Exception + */ + public function addFromSource($pSource = null) { + // Check if an array was passed + if ($pSource == null) { + return; + } else if (!is_array($pSource)) { + throw new Exception('Invalid array parameter passed.'); + } + + foreach ($pSource as $item) { + $this->add($item); + } + } + + /** + * Add HashTable item + * + * @param PHPWord_IComparable $pSource Item to add + * @throws Exception + */ + public function add(PHPWord_IComparable $pSource = null) { + // Determine hashcode + $hashCode = null; + $hashIndex = $pSource->getHashIndex(); + if ( is_null ( $hashIndex ) ) { + $hashCode = $pSource->getHashCode(); + } else if ( isset ( $this->_keyMap[$hashIndex] ) ) { + $hashCode = $this->_keyMap[$hashIndex]; + } else { + $hashCode = $pSource->getHashCode(); + } + + // Add value + if (!isset($this->_items[ $hashCode ])) { + $this->_items[ $hashCode ] = $pSource; + $index = count($this->_items) - 1; + $this->_keyMap[ $index ] = $hashCode; + $pSource->setHashIndex( $index ); + } else { + $pSource->setHashIndex( $this->_items[ $hashCode ]->getHashIndex() ); + } + } + + /** + * Remove HashTable item + * + * @param PHPWord_IComparable $pSource Item to remove + * @throws Exception + */ + public function remove(PHPWord_IComparable $pSource = null) { + if (isset($this->_items[ $pSource->getHashCode() ])) { + unset($this->_items[ $pSource->getHashCode() ]); + + $deleteKey = -1; + foreach ($this->_keyMap as $key => $value) { + if ($deleteKey >= 0) { + $this->_keyMap[$key - 1] = $value; + } + + if ($value == $pSource->getHashCode()) { + $deleteKey = $key; + } + } + unset($this->_keyMap[ count($this->_keyMap) - 1 ]); + } + } + + /** + * Clear HashTable + * + */ + public function clear() { + $this->_items = array(); + $this->_keyMap = array(); + } + + /** + * Count + * + * @return int + */ + public function count() { + return count($this->_items); + } + + /** + * Get index for hash code + * + * @param string $pHashCode + * @return int Index + */ + public function getIndexForHashCode($pHashCode = '') { + return array_search($pHashCode, $this->_keyMap); + } + + /** + * Get by index + * + * @param int $pIndex + * @return PHPWord_IComparable + * + */ + public function getByIndex($pIndex = 0) { + if (isset($this->_keyMap[$pIndex])) { + return $this->getByHashCode( $this->_keyMap[$pIndex] ); + } + + return null; + } + + /** + * Get by hashcode + * + * @param string $pHashCode + * @return PHPWord_IComparable + * + */ + public function getByHashCode($pHashCode = '') { + if (isset($this->_items[$pHashCode])) { + return $this->_items[$pHashCode]; + } + + return null; + } + + /** + * HashTable to array + * + * @return PHPWord_IComparable[] + */ + public function toArray() { + return $this->_items; + } + + /** + * Implement PHP __clone to create a deep clone, not just a shallow copy. + */ + public function __clone() { + $vars = get_object_vars($this); + foreach ($vars as $key => $value) { + if (is_object($value)) { + $this->$key = clone $value; + } + } + } +} diff --git a/src/PHPWord/Writer/ODText.php b/src/PHPWord/Writer/ODText.php new file mode 100644 index 00000000..e9dd42bb --- /dev/null +++ b/src/PHPWord/Writer/ODText.php @@ -0,0 +1,276 @@ +setPHPWord($pPHPWord); + + // Set up disk caching location + $this->_diskCachingDirectory = './'; + + // Initialise writer parts + $this->_writerParts['content'] = new PHPWord_Writer_ODText_Content(); + $this->_writerParts['manifest'] = new PHPWord_Writer_ODText_Manifest(); + $this->_writerParts['meta'] = new PHPWord_Writer_ODText_Meta(); + $this->_writerParts['mimetype'] = new PHPWord_Writer_ODText_Mimetype(); + + + // Assign parent IWriter + foreach ($this->_writerParts as $writer) { + $writer->setParentWriter($this); + } + + // Set HashTable variables + $this->_drawingHashTable = new PHPWord_HashTable(); + } + + /** + * Save PHPWord to file + * + * @param string $pFileName + * @throws Exception + */ + public function save($pFilename = null) + { + if (!is_null($this->_presentation)) { + // If $pFilename is php://output or php://stdout, make it a temporary file... + $originalFilename = $pFilename; + if (strtolower($pFilename) == 'php://output' || strtolower($pFilename) == 'php://stdout') { + $pFilename = @tempnam('./', 'phppttmp'); + if ($pFilename == '') { + $pFilename = $originalFilename; + } + } + + // Create drawing dictionary + + // Create new ZIP file and open it for writing + $objZip = new ZipArchive(); + + // Try opening the ZIP file + if ($objZip->open($pFilename, ZIPARCHIVE::OVERWRITE) !== true) { + if ($objZip->open($pFilename, ZIPARCHIVE::CREATE) !== true) { + throw new Exception("Could not open " . $pFilename . " for writing."); + } + } + + // Add mimetype to ZIP file + //@todo Not in ZIPARCHIVE::CM_STORE mode + $objZip->addFromString('mimetype', $this->getWriterPart('mimetype')->writeMimetype($this->_presentation)); + + // Add content.xml to ZIP file + $objZip->addFromString('content.xml', $this->getWriterPart('content')->writeContent($this->_presentation)); + + // Add meta.xml to ZIP file + $objZip->addFromString('meta.xml', $this->getWriterPart('meta')->writeMeta($this->_presentation)); + + // Add META-INF/manifest.xml + $objZip->addFromString('META-INF/manifest.xml', $this->getWriterPart('manifest')->writeManifest($this->_presentation)); + + // Add media + for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) { + if ($this->getDrawingHashTable()->getByIndex($i) instanceof PHPWord_Shape_Drawing) { + $imageContents = null; + $imagePath = $this->getDrawingHashTable()->getByIndex($i)->getPath(); + + if (strpos($imagePath, 'zip://') !== false) { + $imagePath = substr($imagePath, 6); + $imagePathSplitted = explode('#', $imagePath); + + $imageZip = new ZipArchive(); + $imageZip->open($imagePathSplitted[0]); + $imageContents = $imageZip->getFromName($imagePathSplitted[1]); + $imageZip->close(); + unset($imageZip); + } else { + $imageContents = file_get_contents($imagePath); + } + + $objZip->addFromString('Pictures/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); + } else if ($this->getDrawingHashTable()->getByIndex($i) instanceof PHPWord_Shape_MemoryDrawing) { + ob_start(); + call_user_func( + $this->getDrawingHashTable()->getByIndex($i)->getRenderingFunction(), + $this->getDrawingHashTable()->getByIndex($i)->getImageResource() + ); + $imageContents = ob_get_contents(); + ob_end_clean(); + + $objZip->addFromString('Pictures/' . str_replace(' ', '_', $this->getDrawingHashTable()->getByIndex($i)->getIndexedFilename()), $imageContents); + } + } + + // Close file + if ($objZip->close() === false) { + throw new Exception("Could not close zip file $pFilename."); + } + + // If a temporary file was used, copy it to the correct file stream + if ($originalFilename != $pFilename) { + if (copy($pFilename, $originalFilename) === false) { + throw new Exception("Could not copy temporary zip file $pFilename to $originalFilename."); + } + @unlink($pFilename); + } + + } else { + throw new Exception("PHPWord object unassigned."); + } + } + + /** + * Get PHPWord object + * + * @return PHPWord + * @throws Exception + */ + public function getPHPWord() { + if (!is_null($this->_presentation)) { + return $this->_presentation; + } else { + throw new Exception("No PHPWord assigned."); + } + } + + /** + * Get PHPWord object + * + * @param PHPWord $pPHPWord PHPWord object + * @throws Exception + * @return PHPWord_Writer_PowerPoint2007 + */ + public function setPHPWord(PHPWord $pPHPWord = null) { + $this->_presentation = $pPHPWord; + return $this; + } + + /** + * Get PHPWord_Worksheet_BaseDrawing HashTable + * + * @return PHPWord_HashTable + */ + public function getDrawingHashTable() { + return $this->_drawingHashTable; + } + + /** + * Get writer part + * + * @param string $pPartName Writer part name + * @return PHPWord_Writer_ODText_WriterPart + */ + function getWriterPart($pPartName = '') { + if ($pPartName != '' && isset($this->_writerParts[strtolower($pPartName)])) { + return $this->_writerParts[strtolower($pPartName)]; + } else { + return null; + } + } + + /** + * Get use disk caching where possible? + * + * @return boolean + */ + public function getUseDiskCaching() { + return $this->_useDiskCaching; + } + + /** + * Set use disk caching where possible? + * + * @param boolean $pValue + * @param string $pDirectory Disk caching directory + * @throws Exception Exception when directory does not exist + * @return PHPWord_Writer_PowerPoint2007 + */ + public function setUseDiskCaching($pValue = false, $pDirectory = null) { + $this->_useDiskCaching = $pValue; + + if (!is_null($pDirectory)) { + if (is_dir($pDirectory)) { + $this->_diskCachingDirectory = $pDirectory; + } else { + throw new Exception("Directory does not exist: $pDirectory"); + } + } + + return $this; + } + + /** + * Get disk caching directory + * + * @return string + */ + public function getDiskCachingDirectory() { + return $this->_diskCachingDirectory; + } +} \ No newline at end of file diff --git a/src/PHPWord/Writer/ODText/Content.php b/src/PHPWord/Writer/ODText/Content.php new file mode 100644 index 00000000..0a6dd607 --- /dev/null +++ b/src/PHPWord/Writer/ODText/Content.php @@ -0,0 +1,110 @@ +getParentWriter()->getUseDiskCaching()) { + $objWriter = new PHPWord_Shared_XMLWriter(PHPWord_Shared_XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); + } else { + $objWriter = new PHPWord_Shared_XMLWriter(PHPWord_Shared_XMLWriter::STORAGE_MEMORY); + } + + // XML header + $objWriter->startDocument('1.0','UTF-8'); + + // office:document-content + $objWriter->startElement('office:document-content'); + $objWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'); + $objWriter->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'); + $objWriter->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'); + $objWriter->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'); + $objWriter->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'); + $objWriter->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'); + $objWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); + $objWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); + $objWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); + $objWriter->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'); + $objWriter->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'); + $objWriter->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'); + $objWriter->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'); + $objWriter->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML'); + $objWriter->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'); + $objWriter->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'); + $objWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); + $objWriter->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer'); + $objWriter->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc'); + $objWriter->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events'); + $objWriter->writeAttribute('xmlns:xforms', 'http://www.w3.org/2002/xforms'); + $objWriter->writeAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema'); + $objWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + $objWriter->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report'); + $objWriter->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2'); + $objWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); + $objWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); + $objWriter->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table'); + $objWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0'); + $objWriter->writeAttribute('xmlns:formx', 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0'); + $objWriter->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/'); + $objWriter->writeAttribute('office:version', '1.2'); + + // office:automatic-styles + $objWriter->startElement('office:automatic-styles'); + + $objWriter->endElement(); + + // office:body + $objWriter->startElement('office:body'); + // office:text + $objWriter->startElement('office:text'); + + $objWriter->endElement(); + $objWriter->endElement(); + $objWriter->endElement(); + + // Return + return $objWriter->getData(); + } +} diff --git a/src/PHPWord/Writer/ODText/Manifest.php b/src/PHPWord/Writer/ODText/Manifest.php new file mode 100644 index 00000000..79519f47 --- /dev/null +++ b/src/PHPWord/Writer/ODText/Manifest.php @@ -0,0 +1,126 @@ +getParentWriter()->getUseDiskCaching()) { + $objWriter = new PHPWord_Shared_XMLWriter(PHPWord_Shared_XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); + } else { + $objWriter = new PHPWord_Shared_XMLWriter(PHPWord_Shared_XMLWriter::STORAGE_MEMORY); + } + + // XML header + $objWriter->startDocument('1.0','UTF-8'); + + // manifest:manifest + $objWriter->startElement('manifest:manifest'); + $objWriter->writeAttribute('xmlns:manifest', 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'); + $objWriter->writeAttribute('manifest:version', '1.2'); + + // manifest:file-entry + $objWriter->startElement('manifest:file-entry'); + $objWriter->writeAttribute('manifest:media-type', 'application/vnd.oasis.opendocument.text'); + $objWriter->writeAttribute('manifest:version', '1.2'); + $objWriter->writeAttribute('manifest:full-path', '/'); + $objWriter->endElement(); + // manifest:file-entry + $objWriter->startElement('manifest:file-entry'); + $objWriter->writeAttribute('manifest:media-type', 'text/xml'); + $objWriter->writeAttribute('manifest:full-path', 'content.xml'); + $objWriter->endElement(); + // manifest:file-entry + $objWriter->startElement('manifest:file-entry'); + $objWriter->writeAttribute('manifest:media-type', 'text/xml'); + $objWriter->writeAttribute('manifest:full-path', 'meta.xml'); + $objWriter->endElement(); + + for ($i = 0; $i < $this->getParentWriter()->getDrawingHashTable()->count(); ++$i) { + if ($this->getParentWriter()->getDrawingHashTable()->getByIndex($i) instanceof PHPWord_Shape_Drawing) { + $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getExtension()); + $mimeType = $this->_getImageMimeType( $this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getPath() ); + + $objWriter->startElement('manifest:file-entry'); + $objWriter->writeAttribute('manifest:media-type', $mimeType); + $objWriter->writeAttribute('manifest:full-path', 'Pictures/' . str_replace(' ', '_', $this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getIndexedFilename())); + $objWriter->endElement(); + } else if ($this->getParentWriter()->getDrawingHashTable()->getByIndex($i) instanceof PHPWord_Shape_MemoryDrawing) { + $extension = strtolower($this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getMimeType()); + $extension = explode('/', $extension); + $extension = $extension[1]; + + $mimeType = $this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getMimeType(); + + $objWriter->startElement('manifest:file-entry'); + $objWriter->writeAttribute('manifest:media-type', $mimeType); + $objWriter->writeAttribute('manifest:full-path', 'Pictures/' . str_replace(' ', '_', $this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getIndexedFilename())); + $objWriter->endElement(); + } + } + + $objWriter->endElement(); + + // Return + return $objWriter->getData(); + } + + + /** + * Get image mime type + * + * @param string $pFile Filename + * @return string Mime Type + * @throws Exception + */ + private function _getImageMimeType($pFile = '') + { + if (PHPWord_Shared_File::file_exists($pFile)) { + $image = getimagesize($pFile); + return image_type_to_mime_type($image[2]); + } else { + throw new Exception("File $pFile does not exist"); + } + } +} diff --git a/src/PHPWord/Writer/ODText/Meta.php b/src/PHPWord/Writer/ODText/Meta.php new file mode 100644 index 00000000..0d470cc1 --- /dev/null +++ b/src/PHPWord/Writer/ODText/Meta.php @@ -0,0 +1,100 @@ +getParentWriter()->getUseDiskCaching()) { + $objWriter = new PHPWord_Shared_XMLWriter(PHPWord_Shared_XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); + } else { + $objWriter = new PHPWord_Shared_XMLWriter(PHPWord_Shared_XMLWriter::STORAGE_MEMORY); + } + + // XML header + $objWriter->startDocument('1.0','UTF-8'); + + // office:document-meta + $objWriter->startElement('office:document-meta'); + $objWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'); + $objWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); + $objWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); + $objWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); + $objWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); + $objWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); + $objWriter->writeAttribute('office:version', '1.2'); + + // office:meta + $objWriter->startElement('office:meta'); + + // dc:creator + $objWriter->writeElement('dc:creator', $pPHPWord->getProperties()->getLastModifiedBy()); + // dc:date + $objWriter->writeElement('dc:date', gmdate('Y-m-d\TH:i:s.000' ,$pPHPWord->getProperties()->getModified())); + // dc:description + $objWriter->writeElement('dc:description', $pPHPWord->getProperties()->getDescription()); + // dc:subject + $objWriter->writeElement('dc:subject', $pPHPWord->getProperties()->getSubject()); + // dc:title + $objWriter->writeElement('dc:title', $pPHPWord->getProperties()->getTitle()); + // meta:creation-date + $objWriter->writeElement('meta:creation-date', gmdate('Y-m-d\TH:i:s.000' ,$pPHPWord->getProperties()->getCreated())); + // meta:initial-creator + $objWriter->writeElement('meta:initial-creator', $pPHPWord->getProperties()->getCreator()); + // meta:keyword + $objWriter->writeElement('meta:keyword', $pPHPWord->getProperties()->getKeywords()); + + // @todo : Where these properties are written ? + // $pPHPWord->getProperties()->getCategory() + // $pPHPWord->getProperties()->getCompany() + + $objWriter->endElement(); + + $objWriter->endElement(); + + // Return + return $objWriter->getData(); + } + +} diff --git a/src/PHPWord/Writer/ODText/Mimetype.php b/src/PHPWord/Writer/ODText/Mimetype.php new file mode 100644 index 00000000..cf301cf3 --- /dev/null +++ b/src/PHPWord/Writer/ODText/Mimetype.php @@ -0,0 +1,51 @@ +_parentWriter = $pWriter; + } + + /** + * Get parent IWriter object + * + * @return PHPWord_Writer_IWriter + * @throws Exception + */ + public function getParentWriter() { + if (!is_null($this->_parentWriter)) { + return $this->_parentWriter; + } else { + throw new Exception("No parent PHPWord_Writer_IWriter assigned."); + } + } +}