diff --git a/.gitignore b/.gitignore index 2ea4fd9d..eb0f0679 100644 --- a/.gitignore +++ b/.gitignore @@ -4,13 +4,12 @@ .Trashes Thumbs.db Desktop.ini -.idea -_build -phpunit.xml composer.lock composer.phar -vendor -/report -/.settings +phpunit.xml /.buildpath -/.project \ No newline at end of file +/.idea +/.project +/.settings +/build +/vendor diff --git a/.travis.yml b/.travis.yml index 8ed7a45f..ad3df613 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,8 +18,9 @@ before_script: ## Composer # - curl -s http://getcomposer.org/installer | php # - php composer.phar install --prefer-source + - composer self-update + - composer require dompdf/dompdf:0.6.* - composer install --prefer-source - - composer selfupdate --quiet ## PHP_CodeSniffer - pyrus install pear/PHP_CodeSniffer - phpenv rehash @@ -37,7 +38,7 @@ before_script: script: ## PHP_CodeSniffer - - phpcs --standard=PSR2 -n src/ + - phpcs --standard=PSR2 -n src/ --ignore=src/PhpWord/Shared/PCLZip - phpcs --standard=PSR2 -n tests/ ## PHP Copy/Paste Detector #- php phpcpd.phar --verbose src/ diff --git a/CHANGELOG.md b/CHANGELOG.md old mode 100755 new mode 100644 index 3bb699ea..e23edf91 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,92 @@ This is the changelog between releases of PHPWord. Releases are listed in reverse chronological order with the latest version listed on top, while additions/changes in each release are listed in chronological order. Changes in each release are divided into three parts: added or change features, bugfixes, and miscellaneous improvements. Each line contains short information about the change made, the person who made it, and the related issue number(s) in GitHub. +## 0.10.0 - Not yet released + +This release marked heavy refactorings on internal code structure with the creation of some abstract classes to reduce code duplication. `Element` subnamespace is introduced in this release to replace `Section`. Word2007 reader capability is greatly enhanced. Endnote is introduced. List numbering is now customizable. Basic HTML and PDF writing support is enabled. Basic ODText reader is introduced. + +### Features + +- Image: Get image dimensions without EXIF extension - @andrew-kzoo GH-184 +- Table: Add `tblGrid` element for Libre/Open Office table sizing - @gianis6 GH-183 +- Footnote: Ability to insert textbreak in footnote `$footnote->addTextBreak()` - @ivanlanin +- Footnote: Ability to style footnote reference mark by using `FootnoteReference` style - @ivanlanin +- Font: Add `bgColor` to font style to define background using HEX color - @jcarignan GH-168 +- Table: Add `exactHeight` to row style to define whether row height should be exact or atLeast - @jcarignan GH-168 +- Element: New `CheckBox` element for sections and table cells - @ozilion GH-156 +- Settings: Ability to use PCLZip as alternative to ZipArchive - @bskrtich @ivanlanin GH-106 GH-140 GH-185 +- Template: Ability to find & replace variables in headers & footers - @dgudgeon GH-190 +- Template: Ability to clone & delete block of text using `cloneBlock` and `deleteBlock` - @diego-vieira GH-191 +- TOC: Ability to have two or more TOC in one document and to set min and max depth for TOC - @Pyreweb GH-189 +- Table: Ability to add footnote in table cell - @ivanlanin GH-187 +- Footnote: Ability to add image in footnote - @ivanlanin GH-187 +- ListItem: Ability to add list item in header/footer - @ivanlanin GH-187 +- CheckBox: Ability to add checkbox in header/footer - @ivanlanin GH-187 +- Link: Ability to add link in header/footer - @ivanlanin GH-187 +- 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 +- DOCX Reader: Ability to read header, footer, footnotes, link, preservetext, textbreak, pagebreak, table, list, image, and title - @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 +- Image: Keep image aspect ratio if only 1 dimension styled - @japonicus GH-194 +- HTML Writer: Basic HTML writer: text, textrun, link, title, textbreak, table, image (as Base64), footnote, endnote - @ivanlanin GH-203 GH-67 GH-147 +- PDF Writer: Basic PDF writer using DomPDF: All HTML element except image - @ivanlanin GH-68 +- DOCX Writer: Change `docProps/app.xml` `Application` to `PHPWord` - @ivanlanin +- DOCX Writer: Create `word/settings.xml` and `word/webSettings.xml` dynamically - @ivanlanin +- ODT Writer: Basic image writing - @ivanlanin +- ODT Writer: Link writing - @ivanlanin +- ODT Reader: Basic ODText Reader - @ivanlanin GH-71 +- Section: Ability to define gutter and line numbering - @ivanlanin +- Font: Small caps, all caps, and double strikethrough - @ivanlanin GH-151 +- Settings: Ability to use measurement unit other than twips with `setMeasurementUnit` - @ivanlanin GH-199 +- Style: Remove `bgColor` from `Font`, `Table`, and `Cell` and put it into the new `Shading` style - @ivanlanin +- Style: New `Indentation` and `Spacing` style - @ivanlanin +- Paragraph: Ability to define first line and right indentation - @ivanlanin + +### Bugfixes + +- Footnote: Footnote content doesn't show footnote reference number - @ivanlanin GH-170 +- Documentation: Error in a function - @theBeerNut GH-195 + +### Deprecated + +- `createTextRun` replaced by `addTextRun` +- `createFootnote` replaced by `addFootnote` +- `createHeader` replaced by `addHeader` +- `createFooter` replaced by `addFooter` +- `createSection` replaced by `addSection` +- `Element\Footnote::getReferenceId` replaced by `Element\AbstractElement::getRelationId` +- `Element\Footnote::setReferenceId` replaced by `Element\AbstractElement::setRelationId` +- `Footnote::addFootnoteLinkElement` replaced by `Media::addElement` +- `Footnote::getFootnoteLinkElements` replaced by `Media::getElements` +- All current methods on `Media` +- `Element\Link::getLinkSrc` replaced by `Element\Link::getTarget` +- `Element\Link::getLinkName` replaced by `Element\Link::getText` +- `Style\Cell::getDefaultBorderColor` + +### Miscellaneous + +- Documentation: Simplify page level docblock - @ivanlanin GH-179 +- Writer: Refactor writer classes and create a new `Write\AbstractWriter` abstract class - @ivanlanin GH-160 +- General: Refactor folders: `Element` and `Exception` - @ivanlanin GH-187 +- General: Remove legacy `HashTable` and `Shared\ZipStreamWrapper` and all related properties/methods - @ivanlanin GH-187 +- Element: New `AbstractElement` abstract class - @ivanlanin GH-187 +- Media: Refactor media class to use one method for all docPart (section, header, footer, footnote) - @ivanlanin GH-187 +- General: Remove underscore prefix from all private properties name - @ivanlanin GH-187 +- General: Move Section `Settings` to `Style\Section` - @ivanlanin GH-187 +- General: Give `Abstract` prefix and `Interface` suffix for all abstract classes and interfaces as per [PHP-FIG recommendation](https://github.com/php-fig/fig-standards/blob/master/bylaws/002-psr-naming-conventions.md) - @ivanlanin GH-187 +- Style: New `Style\AbstractStyle` abstract class - @ivanlanin GH-187 +- Writer: New 'ODText\Base` class - @ivanlanin GH-187 +- General: Rename `Footnote` to `Footnotes` to reflect the nature of collection - @ivanlanin +- General: Add some unit tests for Shared & Element (100%!) - @Progi1984 +- Test: Add some samples and tests for image wrapping style - @brunocasado GH-59 +- Refactor: Remove Style\Tabs - @ivanlanin +- Refactor: Apply composite pattern for writers - @ivanlanin +- Refactor: Split `AbstractContainer` from `AbstractElement` - @ivanlanin +- Refactor: Apply composite pattern for Word2007 reader - @ivanlanin + ## 0.9.1 - 27 Mar 2014 This is a bugfix release for PSR-4 compatibility. diff --git a/license.md b/LICENSE.md similarity index 100% rename from license.md rename to LICENSE.md diff --git a/README.md b/README.md old mode 100755 new mode 100644 index 91ddbebf..5a8db0ef --- a/README.md +++ b/README.md @@ -1,111 +1,112 @@ -# ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") - -[![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) -[![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) -[![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads.png)](https://packagist.org/packages/phpoffice/phpword) -[![Latest Unstable Version](https://poser.pugx.org/phpoffice/phpword/v/unstable.png)](https://packagist.org/packages/phpoffice/phpword) -[![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) - - -PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), and [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF). - -With PHPWord, you can create DOCX, ODT, or RTF documents dynamically using your PHP 5.3+ scripts. Below are some of the things that you can do with PHPWord library: - -* Set document properties, e.g. title, subject, and creator. -* Create document sections with different settings, e.g. portrait/landscape, page size, and page numbering -* Create header and footer for each sections -* Set default font type, font size, and paragraph style -* Use UTF-8 and East Asia fonts/characters -* Define custom font styles (e.g. bold, italic, color) and paragraph styles (e.g. centered, multicolumns, spacing) either as named style or inline in text -* Insert paragraphs, either as a simple text or complex one (a text run) that contains other elements -* Insert titles (headers) and table of contents -* Insert text breaks and page breaks -* Insert and format images, either local, remote, or as page watermarks -* Insert binary OLE Objects such as Excel or Visio -* Insert and format table with customized properties for each rows (e.g. repeat as header row) and cells (e.g. background color, rowspan, colspan) -* Insert list items as bulleted, numbered, or multilevel -* Insert hyperlinks -* Create document from templates -* Use XSL 1.0 style sheets to transform main document part of OOXML template -* ... and many more features on progress - -__Want to contribute?__ [Fork us](https://github.com/PHPOffice/PHPWord/fork) or [submit](https://github.com/PHPOffice/PHPWord/issues) your bug reports or feature requests to us. - -## Requirements -* PHP 5.3+ -* PHP [Zip](http://php.net/manual/en/book.zip.php) extension -* PHP [XML Parser](http://www.php.net/manual/en/xml.installation.php) extension - -### Optional PHP extensions -* PHP [GD](http://php.net/manual/en/book.image.php) extension -* PHP [XMLWriter](http://php.net/manual/en/book.xmlwriter.php) extension -* PHP [XSL](http://php.net/manual/en/book.xsl.php) extension - -## Installation - -It is recommended that you install the PHPWord library [through composer](http://getcomposer.org/). To do so, add -the following lines to your ``composer.json``. - -```json -{ - "require": { - "phpoffice/phpword": "dev-master" - } -} -``` - -Alternatively, you can download the latest release from the [releases page](https://github.com/PHPOffice/PHPWord/releases). -In this case, you will have to register the autoloader. - -```php -require_once 'path/to/PhpWord/src/PhpWord/Autoloader.php'; -PhpOffice\PhpWord\Autoloader::register(); -``` - -## Basic usage - -The following is a basic example of the PHPWord library. More examples are provided in the [samples folder](samples/). - -```php -$phpWord = new \PhpOffice\PhpWord\PhpWord(); - -// Every element you want to append to the word document is placed in a section. -// To create a basic section: -$section = $phpWord->createSection(); - -// After creating a section, you can append elements: -$section->addText('Hello world!'); - -// You can directly style your text by giving the addText function an array: -$section->addText('Hello world! I am formatted.', - array('name'=>'Tahoma', 'size'=>16, 'bold'=>true)); - -// If you often need the same style again you can create a user defined style -// to the word document and give the addText function the name of the style: -$phpWord->addFontStyle('myOwnStyle', - array('name'=>'Verdana', 'size'=>14, 'color'=>'1B2232')); -$section->addText('Hello world! I am formatted by a user defined style', - 'myOwnStyle'); - -// You can also put the appended element to local object like this: -$fontStyle = new \PhpOffice\PhpWord\Style\Font(); -$fontStyle->setBold(true); -$fontStyle->setName('Verdana'); -$fontStyle->setSize(22); -$myTextElement = $section->addText('Hello World!'); -$myTextElement->setFontStyle($fontStyle); - -// Finally, write the document: -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); -$objWriter->save('helloWorld.docx'); - -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'ODText'); -$objWriter->save('helloWorld.odt'); - -$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'RTF'); -$objWriter->save('helloWorld.rtf'); -``` - -## Documentation - -__Want to know more?__ Read the full documentation of PHPWord on [Read The Docs](http://phpword.readthedocs.org/). +# ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") + +[![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) +[![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) +[![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads.png)](https://packagist.org/packages/phpoffice/phpword) +[![Latest Unstable Version](https://poser.pugx.org/phpoffice/phpword/v/unstable.png)](https://packagist.org/packages/phpoffice/phpword) +[![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) + + +PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), and [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF). + +With PHPWord, you can create DOCX, ODT, or RTF documents dynamically using your PHP 5.3+ scripts. Below are some of the things that you can do with PHPWord library: + +* Set document properties, e.g. title, subject, and creator. +* Create document sections with different settings, e.g. portrait/landscape, page size, and page numbering +* Create header and footer for each sections +* Set default font type, font size, and paragraph style +* Use UTF-8 and East Asia fonts/characters +* Define custom font styles (e.g. bold, italic, color) and paragraph styles (e.g. centered, multicolumns, spacing) either as named style or inline in text +* Insert paragraphs, either as a simple text or complex one (a text run) that contains other elements +* Insert titles (headers) and table of contents +* Insert text breaks and page breaks +* Insert and format images, either local, remote, or as page watermarks +* Insert binary OLE Objects such as Excel or Visio +* Insert and format table with customized properties for each rows (e.g. repeat as header row) and cells (e.g. background color, rowspan, colspan) +* Insert list items as bulleted, numbered, or multilevel +* Insert hyperlinks +* Insert footnotes and endnotes +* Create document from templates +* Use XSL 1.0 style sheets to transform main document part of OOXML template +* ... and many more features on progress + +__Want to contribute?__ [Fork us](https://github.com/PHPOffice/PHPWord/fork) or [submit](https://github.com/PHPOffice/PHPWord/issues) your bug reports or feature requests to us. + +## Requirements +* PHP 5.3+ +* PHP [Zip](http://php.net/manual/en/book.zip.php) extension +* PHP [XML Parser](http://www.php.net/manual/en/xml.installation.php) extension + +### Optional PHP extensions +* PHP [GD](http://php.net/manual/en/book.image.php) extension +* PHP [XMLWriter](http://php.net/manual/en/book.xmlwriter.php) extension +* PHP [XSL](http://php.net/manual/en/book.xsl.php) extension + +## Installation + +It is recommended that you install the PHPWord library [through composer](http://getcomposer.org/). To do so, add +the following lines to your ``composer.json``. + +```json +{ + "require": { + "phpoffice/phpword": "dev-master" + } +} +``` + +Alternatively, you can download the latest release from the [releases page](https://github.com/PHPOffice/PHPWord/releases). +In this case, you will have to register the autoloader. + +```php +require_once 'path/to/PhpWord/src/PhpWord/Autoloader.php'; +\PhpOffice\PhpWord\Autoloader::register(); +``` + +## Basic usage + +The following is a basic example of the PHPWord library. More examples are provided in the [samples folder](samples/). + +```php +$phpWord = new \PhpOffice\PhpWord\PhpWord(); + +// Every element you want to append to the word document is placed in a section. +// To create a basic section: +$section = $phpWord->addSection(); + +// After creating a section, you can append elements: +$section->addText('Hello world!'); + +// You can directly style your text by giving the addText function an array: +$section->addText('Hello world! I am formatted.', + array('name'=>'Tahoma', 'size'=>16, 'bold'=>true)); + +// If you often need the same style again you can create a user defined style +// to the word document and give the addText function the name of the style: +$phpWord->addFontStyle('myOwnStyle', + array('name'=>'Verdana', 'size'=>14, 'color'=>'1B2232')); +$section->addText('Hello world! I am formatted by a user defined style', + 'myOwnStyle'); + +// You can also put the appended element to local object like this: +$fontStyle = new \PhpOffice\PhpWord\Style\Font(); +$fontStyle->setBold(true); +$fontStyle->setName('Verdana'); +$fontStyle->setSize(22); +$myTextElement = $section->addText('Hello World!'); +$myTextElement->setFontStyle($fontStyle); + +// Finally, write the document: +$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); +$objWriter->save('helloWorld.docx'); + +$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'ODText'); +$objWriter->save('helloWorld.odt'); + +$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'RTF'); +$objWriter->save('helloWorld.rtf'); +``` + +## Documentation + +__Want to know more?__ Read the full documentation of PHPWord on [Read The Docs](http://phpword.readthedocs.org/). diff --git a/composer.json b/composer.json index fcca56e7..fafa9a28 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ ], "homepage": "http://phpoffice.github.io", "type": "library", - "license": "LGPL-3.0+", + "license": "LGPL-2.1+", "authors": [ { "name": "Mark Baker" @@ -25,6 +25,10 @@ { "name": "Ivan Lanin", "homepage": "http://ivan.lanin.org" + }, + { + "name": "Roman Syroeshko", + "homepage": "http://ru.linkedin.com/pub/roman-syroeshko/34/a53/994/" } ], "require": { @@ -36,9 +40,10 @@ "phpunit/phpunit": "3.7.*" }, "suggest": { - "ext-gd2": "*", - "ext-xmlwriter": "*", - "ext-xsl": "*" + "ext-gd2": "Required to add images", + "ext-xmlwriter": "Required to write DOCX and ODT", + "ext-xsl": "Required to apply XSL style sheet to template part", + "dompdf/dompdf": "Required to write PDF" }, "autoload": { "psr-4": { diff --git a/docs/containers.rst b/docs/containers.rst index dc8f2f9a..30566df6 100644 --- a/docs/containers.rst +++ b/docs/containers.rst @@ -16,7 +16,7 @@ section, use the following code: .. code-block:: php - $section = $phpWord->createSection($sectionSettings); + $section = $phpWord->addSection($sectionSettings); The ``$sectionSettings`` is an optional associative array that sets the section. Example: @@ -50,6 +50,7 @@ Below are the available settings for section: - ``borderBottomColor`` Border bottom color - ``headerHeight`` Spacing to top of header - ``footerHeight`` Spacing to bottom of footer +- ``gutter`` Page gutter spacing - ``colsNum`` Number of columns - ``colsSpace`` Spacing between columns - ``breakType`` Section break type (nextPage, nextColumn, continuous, @@ -70,10 +71,10 @@ property of the section. .. code-block:: php // Method 1 - $section = $phpWord->createSection(array('pageNumberingStart' => 1)); + $section = $phpWord->addSection(array('pageNumberingStart' => 1)); // Method 2 - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->getSettings()->setPageNumberingStart(1); Multicolumn @@ -85,22 +86,44 @@ using the ``breakType`` and ``colsNum`` property of the section. .. code-block:: php // Method 1 - $section = $phpWord->createSection(array('breakType' => 'continuous', 'colsNum' => 2)); + $section = $phpWord->addSection(array('breakType' => 'continuous', 'colsNum' => 2)); // Method 2 - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->getSettings()->setBreakType('continuous'); $section->getSettings()->setColsNum(2); + +### Line numbering + +You can apply line numbering to a section by using the ``lineNumbering`` +property of the section. + +.. code-block:: php + + // Method 1 + $section = $phpWord->addSection(array('lineNumbering' => array())); + + // Method 2 + $section = $phpWord->addSection(); + $section->getSettings()->setLineNumbering(array()); + +Below are the properties of the line numbering style. + +- ``start`` Line numbering starting value +- ``increment`` Line number increments +- ``distance`` Distance between text and line numbering in twip +- ``restart`` Line numbering restart setting continuous|newPage|newSection + Headers ------- Each section can have its own header reference. To create a header use -the ``createHeader`` method: +the ``addHeader`` method: .. code-block:: php - $header = $section->createHeader(); + $header = $section->addHeader(); Be sure to save the result in a local object. You can use all elements that are available for the footer. See "Footer" section for detail. @@ -111,11 +134,11 @@ Footers ------- Each section can have its own footer reference. To create a footer, use -the ``createFooter`` method: +the ``addFooter`` method: .. code-block:: php - $footer = $section->createFooter(); + $footer = $section->addFooter(); Be sure to save the result in a local object to add elements to a footer. You can add the following elements to footers: diff --git a/docs/elements.rst b/docs/elements.rst index d0f78d2e..c86d1074 100644 --- a/docs/elements.rst +++ b/docs/elements.rst @@ -3,20 +3,67 @@ Elements ======== +Below are the matrix of element availability in each container. The +column shows the containers while the rows lists the elements. + ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| Num | Element | Section | Header | Footer | Cell | Text Run | Footnote | ++=======+=================+===========+==========+==========+=========+============+============+ +| 1 | Text | v | v | v | v | v | v | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 2 | Text Run | v | v | v | v | - | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 3 | Link | v | v | v | v | v | v | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 4 | Title | v | ? | ? | ? | ? | ? | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 5 | Preserve Text | ? | v | v | v\* | ? | ? | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 6 | Text Break | v | v | v | v | v | v | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 7 | Page Break | v | - | - | - | - | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 8 | List | v | v | v | v | - | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 9 | Table | v | v | v | ? | - | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 10 | Image | v | v | v | v | v | v | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 11 | Watermark | - | v | - | - | - | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 12 | Object | v | v | v | v | v | v | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 13 | TOC | v | - | - | - | - | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 14 | Footnote | v | - | - | v\*\* | v\*\* | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 15 | Endnote | v | - | - | v\*\* | v\*\* | - | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ +| 16 | CheckBox | v | v | v | v | ? | ? | ++-------+-----------------+-----------+----------+----------+---------+------------+------------+ + +Legend: + +- ``v`` Available +- ``v*`` Available only when inside header/footer +- ``v**`` Available only when inside section +- ``-`` Not available +- ``?`` Should be available + Texts ----- -Text can be added by using ``addText`` and ``createTextRun`` method. +Text can be added by using ``addText`` and ``addTextRun`` method. ``addText`` is used for creating simple paragraphs that only contain -texts with the same style. ``createTextRun`` is used for creating -complex paragraphs that contain text with different style (some bold, -other italics, etc) or other elements, e.g. images or links. The -syntaxes are as follow: +texts with the same style. ``addTextRun`` is used for creating complex +paragraphs that contain text with different style (some bold, other +italics, etc) or other elements, e.g. images or links. The syntaxes are +as follow: .. code-block:: php $section->addText($text, [$fontStyle], [$paragraphStyle]); - $textrun = $section->createTextRun([$paragraphStyle]); + $textrun = $section->addTextRun([$paragraphStyle]); Text styles ~~~~~~~~~~~ @@ -34,7 +81,7 @@ Inline style examples: $paragraphStyle = array('align' => 'both'); $section->addText('I am simple paragraph', $fontStyle, $paragraphStyle); - $textrun = $section->createTextRun(); + $textrun = $section->addTextRun(); $textrun->addText('I am bold', array('bold' => true)); $textrun->addText('I am italic', array('italic' => true)); $textrun->addText('I am colored, array('color' => 'AACC00')); @@ -65,8 +112,12 @@ Available font styles: - ``subScript`` Subscript, *true* or *false* - ``underline`` Underline, *dash*, *dotted*, etc. - ``strikethrough`` Strikethrough, *true* or *false* +- ``doubleStrikethrough`` Double strikethrough, *true* or *false* - ``color`` Font color, e.g. *FF0000* - ``fgColor`` Font highlight color, e.g. *yellow*, *green*, *blue* +- ``bgColor`` Font background color, e.g. *FF0000* +- ``smallCaps`` Small caps, *true* or *false* +- ``allCaps`` All caps, *true* or *false* Paragraph style ^^^^^^^^^^^^^^^ @@ -152,17 +203,21 @@ method or using the ``pageBreakBefore`` style of paragraph. :: code-block:: php - $section->addPageBreak(); + \\$section->addPageBreak(); Lists ----- To add a list item use the function ``addListItem``. +Basic usage: + .. code-block:: php $section->addListItem($text, [$depth], [$fontStyle], [$listStyle], [$paragraphStyle]); +Parameters: + - ``$text`` Text that appears in the document. - ``$depth`` Depth of list item. - ``$fontStyle`` See "Font style" section. @@ -171,6 +226,43 @@ To add a list item use the function ``addListItem``. PHPWord\_Style\_ListItem. - ``$paragraphStyle`` See "Paragraph style" section. +Advanced usage: + +You can also create your own numbering style by changing the +``$listStyle`` parameter with the name of your numbering style. + +.. code-block:: php + + $phpWord->addNumberingStyle( + 'multilevel', + array('type' => 'multilevel', 'levels' => array( + array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), + array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), + ) + ) + ); + $section->addListItem('List Item I', 0, null, 'multilevel'); + $section->addListItem('List Item I.a', 1, null, 'multilevel'); + $section->addListItem('List Item I.b', 1, null, 'multilevel'); + $section->addListItem('List Item II', 0, null, 'multilevel'); + +Level styles: + +- ``start`` Starting value +- ``format`` Numbering format + bullet\|decimal\|upperRoman\|lowerRoman\|upperLetter\|lowerLetter +- ``restart`` Restart numbering level symbol +- ``suffix`` Content between numbering symbol and paragraph text + tab\|space\|nothing +- ``text`` Numbering level text e.g. %1 for nonbullet or bullet + character +- ``align`` Numbering symbol align left\|center\|right\|both +- ``left`` See paragraph style +- ``hanging`` See paragraph style +- ``tabPos`` See paragraph style +- ``font`` Font name +- ``hint`` See font style + Tables ------ @@ -201,27 +293,28 @@ Table, row, and cell styles Table styles: -- ``$width`` Table width in percent -- ``$bgColor`` Background color, e.g. '9966CC' -- ``$border(Top|Right|Bottom|Left)Size`` Border size in twips -- ``$border(Top|Right|Bottom|Left)Color`` Border color, e.g. '9966CC' -- ``$cellMargin(Top|Right|Bottom|Left)`` Cell margin in twips +- ``width`` Table width in percent +- ``bgColor`` Background color, e.g. '9966CC' +- ``border(Top|Right|Bottom|Left)Size`` Border size in twips +- ``border(Top|Right|Bottom|Left)Color`` Border color, e.g. '9966CC' +- ``cellMargin(Top|Right|Bottom|Left)`` Cell margin in twips Row styles: - ``tblHeader`` Repeat table row on every new page, *true* or *false* - ``cantSplit`` Table row cannot break across pages, *true* or *false* +- ``exactHeight`` Row height is exact or at least Cell styles: -- ``$width`` Cell width in twips -- ``$valign`` Vertical alignment, *top*, *center*, *both*, *bottom* -- ``$textDirection`` Direction of text -- ``$bgColor`` Background color, e.g. '9966CC' -- ``$border(Top|Right|Bottom|Left)Size`` Border size in twips -- ``$border(Top|Right|Bottom|Left)Color`` Border color, e.g. '9966CC' -- ``$gridSpan`` Number of columns spanned -- ``$vMerge`` *restart* or *continue* +- ``width`` Cell width in twips +- ``valign`` Vertical alignment, *top*, *center*, *both*, *bottom* +- ``textDirection`` Direction of text +- ``bgColor`` Background color, e.g. '9966CC' +- ``border(Top|Right|Bottom|Left)Size`` Border size in twips +- ``border(Top|Right|Bottom|Left)Color`` Border color, e.g. '9966CC' +- ``gridSpan`` Number of columns spanned +- ``vMerge`` *restart* or *continue* Cell span ~~~~~~~~~ @@ -239,21 +332,21 @@ See ``Sample_09_Tables.php`` for more code sample. Images ------ -To add an image, use the ``addImage`` method to sections, headers, footers, -textruns, or table cells. +To add an image, use the ``addImage`` method to sections, headers, +footers, textruns, or table cells. .. code-block:: php $section->addImage($src, [$style]); -- `source` String path to a local image or URL of a remote image -- `styles` Array fo styles for the image. See below. +- source String path to a local image or URL of a remote image +- styles Array fo styles for the image. See below. Examples: .. code-block:: php - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addImage( 'mars.jpg', array( @@ -264,9 +357,9 @@ Examples: 'wrappingStyle' => 'behind' ) ); - $footer = $section->createFooter(); + $footer = $section->addFooter(); $footer->addImage('http://example.com/image.php'); - $textrun = $section->createTextRun(); + $textrun = $section->addTextRun(); $textrun->addImage('http://php.net/logo.jpg'); Image styles @@ -291,8 +384,8 @@ header reference. After creating a header, you can use the .. code-block:: php - $section = $phpWord->createSection(); - $header = $section->createHeader(); + $section = $phpWord->addSection(); + $header = $section->addHeader(); $header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); Objects @@ -314,7 +407,14 @@ Your TOC can only be generated if you have add at least one title (See .. code-block:: php - $section->addTOC([$fontStyle], [$tocStyle]); + $section->addTOC([$fontStyle], [$tocStyle], [$minDepth], [$maxDepth]); + +- ``$fontStyle``: See font style section +- ``$tocStyle``: See available options below +- ``$minDepth``: Minimum depth of header to be shown. Default 1 +- ``$maxDepth``: Maximum depth of header to be shown. Default 9 + +Options for ``$tocStyle``: - ``tabLeader`` Fill type between the title text and the page number. Use the defined constants in PHPWord\_Style\_TOC. @@ -322,26 +422,54 @@ Your TOC can only be generated if you have add at least one title (See twips. - ``indent`` The indent factor of the titles in twips. -Footnotes ---------- +Footnotes & endnotes +-------------------- -You can create footnotes in texts or textruns, but it's recommended to -use textrun to have better layout. +You can create footnotes with ``addFootnote`` and endnotes with +``addEndnote`` in texts or textruns, but it's recommended to use textrun +to have better layout. You can use ``addText``, ``addLink``, +``addTextBreak``, ``addImage``, ``addObject`` on footnotes and endnotes. On textrun: .. code-block:: php - $textrun = $section->createTextRun(); + $textrun = $section->addTextRun(); $textrun->addText('Lead text.'); - $footnote = $textrun->createFootnote(); - $footnote->addText('Footnote text.'); + $footnote = $textrun->addFootnote(); + $footnote->addText('Footnote text can have '); + $footnote->addLink('http://test.com', 'links'); + $footnote->addText('.'); + $footnote->addTextBreak(); + $footnote->addText('And text break.'); $textrun->addText('Trailing text.'); + $endnote = $textrun->addEndnote(); + $endnote->addText('Endnote put at the end'); On text: .. code-block:: php $section->addText('Lead text.'); - $footnote = $section->createFootnote(); + $footnote = $section->addFootnote(); $footnote->addText('Footnote text.'); + +The footnote reference number will be displayed with decimal number +starting from 1. This number use ``FooterReference`` style which you can +redefine by ``addFontStyle`` method. Default value for this style is +``array('superScript' => true)``; + +Checkboxes +---------- + +Checkbox elements can be added to sections or table cells by using +``addCheckBox``. + +.. code-block:: php + + $section->addCheckBox($name, $text, [$fontStyle], [$paragraphStyle]) + +- ``$name`` Name of the check box. +- ``$text`` Text following the check box +- ``$fontStyle`` See "Font style" section. +- ``$paragraphStyle`` See "Paragraph style" section. diff --git a/docs/general.rst b/docs/general.rst index 9b25551a..f08e29ba 100644 --- a/docs/general.rst +++ b/docs/general.rst @@ -7,18 +7,19 @@ Basic example ------------- The following is a basic example of the PHPWord library. More examples -are provided in the `samples folder `__. +are provided in the `samples +folder `__. .. code-block:: php require_once 'src/PhpWord/Autoloader.php'; - PhpOffice\PhpWord\Autoloader::register(); + \PhpOffice\PhpWord\Autoloader::register(); $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Every element you want to append to the word document is placed in a section. // To create a basic section: - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); // After creating a section, you can append elements: $section->addText('Hello world!'); @@ -52,6 +53,43 @@ are provided in the `samples folder save('helloWorld.rtf'); +Settings +-------- + +The ``PhpOffice\PhpWord\Settings`` class provides some options that will +affect the behavior of PHPWord. Below are the options. + +XML Writer compatibility +~~~~~~~~~~~~~~~~~~~~~~~~ + +This option sets +`XMLWriter::setIndent `__ +and +`XMLWriter::setIndentString `__. +The default value of this option is ``true`` (compatible), which is +`required for +OpenOffice `__ to +render OOXML document correctly. You can set this option to ``false`` +during development to make the resulting XML file easier to read. + +.. code-block:: php + + \PhpOffice\PhpWord\Settings::setCompatibility(false); + +Zip class +~~~~~~~~~ + +By default, PHPWord uses PHP +`ZipArchive `__ to read or write +ZIP compressed archive and the files inside them. If you can't have +ZipArchive installed on your server, you can use pure PHP library +alternative, `PCLZip `__, which +included with PHPWord. + +.. code-block:: php + + \PhpOffice\PhpWord\Settings::setZipClass(\PhpOffice\PhpWord\Settings::PCLZIP); + Default font ------------ @@ -71,7 +109,7 @@ name. Use the following functions: .. code-block:: php - $properties = $phpWord->getProperties(); + $properties = $phpWord->getDocumentProperties(); $properties->setCreator('My name'); $properties->setCompany('My factory'); $properties->setTitle('My title'); @@ -99,9 +137,10 @@ points to twips. 'spaceAfter' => \PhpOffice\PhpWord\Shared\Font::pointSizeToTwips(6)) ); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $sectionStyle = $section->getSettings(); // half inch left margin $sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Font::inchSizeToTwips(.5)); // 2 cm right margin $sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Font::centimeterSizeToTwips(2)); + diff --git a/docs/index.rst b/docs/index.rst index 700694a5..fd3a3fa9 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -23,6 +23,7 @@ Format (RTF). containers elements templates + writersreaders recipes faq credits diff --git a/docs/intro.rst b/docs/intro.rst index a30dc553..3e74519e 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -16,9 +16,9 @@ No Windows operating system is needed for usage because the resulting DOCX, ODT, or RTF files can be opened by all major `word processing softwares `__. -PHPWord is an open source project licensed under LGPL. -PHPWord is `unit tested `__ to -make sure that the released versions are stable. +PHPWord is an open source project licensed under LGPL. PHPWord is `unit +tested `__ to make sure that +the released versions are stable. **Want to contribute?** `Fork us `__ or @@ -48,6 +48,7 @@ Features rowspan, colspan) - Insert list items as bulleted, numbered, or multilevel - Insert hyperlinks +- Insert footnotes and endnotes - Create document from templates - Use XSL 1.0 style sheets to transform main document part of OOXML template @@ -61,122 +62,121 @@ Below are the supported features for each file formats. Writers ~~~~~~~ -+-------------------------------------------------+--------+-------+-------+ -| Features | DOCX | ODT | RTF | -+=========================+=======================+========+=======+=======+ -| **Document Properties** | Standard | | | | -+ +-----------------------+--------+-------+-------+ -| | Extended | | | | -+ +-----------------------+--------+-------+-------+ -| | UserDefined | | | | -+-------------------------+-----------------------+--------+-------+-------+ -| **Element Type** | Text | ✓ | ✓ | ✓ | -+ +-----------------------+--------+-------+-------+ -| | Text Run | ✓ | ✓ | ✓ | -+ +-----------------------+--------+-------+-------+ -| | Title | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Link | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Preserve Text | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Text Break | ✓ | ✓ | ✓ | -+ +-----------------------+--------+-------+-------+ -| | Page Break | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | List | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Table | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Image | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | MemoryImage | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Object | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Watermark | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Table of Contents | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Header | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Footer | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Footnote | ✓ | | | -+-------------------------+-----------------------+--------+-------+-------+ -| **Graphs** | 2D basic graphs | | | | -+ +-----------------------+--------+-------+-------+ -| | 2D advanced graphs | | | | -+ +-----------------------+--------+-------+-------+ -| | 3D graphs | | | | -+-------------------------+-----------------------+--------+-------+-------+ -| **Math** | OMML support | | | | -+ +-----------------------+--------+-------+-------+ -| | MathML support | | | | -+-------------------------+-----------------------+--------+-------+-------+ -| **Bonus** | Encryption | | | | -+ +-----------------------+--------+-------+-------+ -| | Protection | | | | -+-------------------------+-----------------------+--------+-------+-------+ - ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| Features | | DOCX | ODT | RTF | HTML | PDF | ++===========================+======================+========+=======+=======+========+=======+ +| **Document Properties** | Standard | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Extended | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | UserDefined | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| **Element Type** | Text | ✓ | ✓ | ✓ | ✓ | ✓ | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Text Run | ✓ | ✓ | ✓ | ✓ | ✓ | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Title | ✓ | | | ✓ | ✓ | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Link | ✓ | ✓ | | ✓ | ✓ | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Preserve Text | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Text Break | ✓ | ✓ | ✓ | ✓ | ✓ | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Page Break | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | List | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Table | ✓ | ✓ | | ✓ | ✓ | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Image | ✓ | ✓ | | ✓ | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Object | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Watermark | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Table of Contents | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Header | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Footer | ✓ | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Footnote | ✓ | | | ✓ | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Endnote | ✓ | | | ✓ | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| **Graphs** | 2D basic graphs | | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | 2D advanced graphs | | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | 3D graphs | | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| **Math** | OMML support | | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | MathML support | | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| **Bonus** | Encryption | | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ +| | Protection | | | | | | ++---------------------------+----------------------+--------+-------+-------+--------+-------+ Readers ~~~~~~~ -+-------------------------------------------------+--------+-------+-------+ -| Features | DOCX | ODT | RTF | -+=========================+=======================+========+=======+=======+ -| **Document Properties** | Standard | | | | -+ +-----------------------+--------+-------+-------+ -| | Extended | | | | -+ +-----------------------+--------+-------+-------+ -| | UserDefined | | | | -+-------------------------+-----------------------+--------+-------+-------+ -| **Element Type** | Text | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Text Run | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Title | | | | -+ +-----------------------+--------+-------+-------+ -| | Link | | | | -+ +-----------------------+--------+-------+-------+ -| | Preserve Text | | | | -+ +-----------------------+--------+-------+-------+ -| | Text Break | ✓ | | | -+ +-----------------------+--------+-------+-------+ -| | Page Break | | | | -+ +-----------------------+--------+-------+-------+ -| | List | | | | -+ +-----------------------+--------+-------+-------+ -| | Table | | | | -+ +-----------------------+--------+-------+-------+ -| | Image | | | | -+ +-----------------------+--------+-------+-------+ -| | MemoryImage | | | | -+ +-----------------------+--------+-------+-------+ -| | Object | | | | -+ +-----------------------+--------+-------+-------+ -| | Watermark | | | | -+ +-----------------------+--------+-------+-------+ -| | Table of Contents | | | | -+ +-----------------------+--------+-------+-------+ -| | Header | | | | -+ +-----------------------+--------+-------+-------+ -| | Footer | | | | -+ +-----------------------+--------+-------+-------+ -| | Footnote | | | | -+-------------------------+-----------------------+--------+-------+-------+ -| **Graphs** | 2D basic graphs | | | | -+ +-----------------------+--------+-------+-------+ -| | 2D advanced graphs | | | | -+ +-----------------------+--------+-------+-------+ -| | 3D graphs | | | | -+-------------------------+-----------------------+--------+-------+-------+ -| **Math** | OMML support | | | | -+ +-----------------------+--------+-------+-------+ -| | MathML support | | | | -+-------------------------+-----------------------+--------+-------+-------+ -| **Bonus** | Encryption | | | | -+ +-----------------------+--------+-------+-------+ -| | Protection | | | | -+-------------------------+-----------------------+--------+-------+-------+ ++---------------------------+----------------------+--------+-------+-------+ +| Features | | DOCX | ODT | RTF | ++===========================+======================+========+=======+=======+ +| **Document Properties** | Standard | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Extended | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | UserDefined | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| **Element Type** | Text | ✓ | ✓ | | ++---------------------------+----------------------+--------+-------+-------+ +| | Text Run | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Title | ✓ | ✓ | | ++---------------------------+----------------------+--------+-------+-------+ +| | Link | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Preserve Text | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Text Break | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Page Break | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | List | ✓ | ✓ | | ++---------------------------+----------------------+--------+-------+-------+ +| | Table | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Image | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Object | | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Watermark | | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Table of Contents | | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Header | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Footer | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Footnote | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Endnote | ✓ | | | ++---------------------------+----------------------+--------+-------+-------+ +| **Graphs** | 2D basic graphs | | | | ++---------------------------+----------------------+--------+-------+-------+ +| | 2D advanced graphs | | | | ++---------------------------+----------------------+--------+-------+-------+ +| | 3D graphs | | | | ++---------------------------+----------------------+--------+-------+-------+ +| **Math** | OMML support | | | | ++---------------------------+----------------------+--------+-------+-------+ +| | MathML support | | | | ++---------------------------+----------------------+--------+-------+-------+ +| **Bonus** | Encryption | | | | ++---------------------------+----------------------+--------+-------+-------+ +| | Protection | | | | ++---------------------------+----------------------+--------+-------+-------+ diff --git a/docs/setup.rst b/docs/setup.rst index c773756f..e5d61b4e 100644 --- a/docs/setup.rst +++ b/docs/setup.rst @@ -1,6 +1,6 @@ .. _setup: -Installing/Configuring +Installing/configuring ====================== Requirements @@ -53,7 +53,7 @@ invoke ``Autoloader::register``. .. code-block:: php require_once '/path/to/src/PhpWord/Autoloader.php'; - PhpOffice\PhpWord\Autoloader::register(); + \PhpOffice\PhpWord\Autoloader::register(); Using samples ------------- diff --git a/docs/src/documentation.md b/docs/src/documentation.md new file mode 100644 index 00000000..bcf38a04 --- /dev/null +++ b/docs/src/documentation.md @@ -0,0 +1,950 @@ + +# Contents + +- [Introduction](#introduction) + - [Features](#features) + - [File formats](#file-formats) +- [Installing/configuring](#installing-configuring) + - [Requirements](#requirements) + - [Installation](#installation) + - [Using samples](#using-samples) +- [General usage](#general-usage) + - [Basic example](#basic-example) + - [Settings](#settings) + - [Default font](#default-font) + - [Document properties](#document-properties) + - [Measurement units](#measurement-units) +- [Containers](#containers) + - [Sections](#sections) + - [Headers](#headers) + - [Footers](#footers) + - [Other containers](#other-containers) +- [Elements](#elements) + - [Texts](#texts) + - [Breaks](#breaks) + - [Lists](#lists) + - [Tables](#tables) + - [Images](#images) + - [Objects](#objects) + - [Table of contents](#table-of-contents) + - [Footnotes & endnotes](#footnotes-endnotes) + - [Checkboxes](#checkboxes) +- [Templates](#templates) +- [Writers & readers](#writers-readers) + - [OOXML](#ooxml) + - [OpenDocument](#opendocument) + - [RTF](#rtf) + - [HTML](#html) + - [PDF](#pdf) +- [Frequently asked questions](#frequently-asked-questions) +- [References](#references) + +# Introduction + +PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), and [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF). + +No Windows operating system is needed for usage because the resulting DOCX, ODT, or RTF files can be opened by all major [word processing softwares](http://en.wikipedia.org/wiki/List_of_word_processors). + +PHPWord is an open source project licensed under LGPL. PHPWord is [unit tested](https://travis-ci.org/PHPOffice/PHPWord) to make sure that the released versions are stable. + +**Want to contribute?** [Fork us](https://github.com/PHPOffice/PHPWord/fork) or [submit](https://github.com/PHPOffice/PHPWord/issues) your bug reports or feature requests to us. + +## Features + +- Set document properties, e.g. title, subject, and creator. +- Create document sections with different settings, e.g. portrait/landscape, page size, and page numbering +- Create header and footer for each sections +- Set default font type, font size, and paragraph style +- Use UTF-8 and East Asia fonts/characters +- Define custom font styles (e.g. bold, italic, color) and paragraph styles (e.g. centered, multicolumns, spacing) either as named style or inline in text +- Insert paragraphs, either as a simple text or complex one (a text run) that contains other elements +- Insert titles (headers) and table of contents +- Insert text breaks and page breaks +- Insert and format images, either local, remote, or as page watermarks +- Insert binary OLE Objects such as Excel or Visio +- Insert and format table with customized properties for each rows (e.g. repeat as header row) and cells (e.g. background color, rowspan, colspan) +- Insert list items as bulleted, numbered, or multilevel +- Insert hyperlinks +- Insert footnotes and endnotes +- Create document from templates +- Use XSL 1.0 style sheets to transform main document part of OOXML template +- ... and many more features on progress + +## File formats + +Below are the supported features for each file formats. + +### Writers + +| Features | | DOCX | ODT | RTF | HTML | PDF | +|-------------------------|--------------------|------|-----|-----|------|-----| +| **Document Properties** | Standard | ✓ | | | | | +| | Extended | ✓ | | | | | +| | UserDefined | ✓ | | | | | +| **Element Type** | Text | ✓ | ✓ | ✓ | ✓ | ✓ | +| | Text Run | ✓ | ✓ | ✓ | ✓ | ✓ | +| | Title | ✓ | | | ✓ | ✓ | +| | Link | ✓ | ✓ | | ✓ | ✓ | +| | Preserve Text | ✓ | | | | | +| | Text Break | ✓ | ✓ | ✓ | ✓ | ✓ | +| | Page Break | ✓ | | | | | +| | List | ✓ | | | | | +| | Table | ✓ | ✓ | | ✓ | ✓ | +| | Image | ✓ | ✓ | | ✓ | | +| | Object | ✓ | | | | | +| | Watermark | ✓ | | | | | +| | Table of Contents | ✓ | | | | | +| | Header | ✓ | | | | | +| | Footer | ✓ | | | | | +| | Footnote | ✓ | | | ✓ | | +| | Endnote | ✓ | | | ✓ | | +| **Graphs** | 2D basic graphs | | | | | | +| | 2D advanced graphs | | | | | | +| | 3D graphs | | | | | | +| **Math** | OMML support | | | | | | +| | MathML support | | | | | | +| **Bonus** | Encryption | | | | | | +| | Protection | | | | | | + +### Readers + +| Features | | DOCX | ODT | RTF | +|-------------------------|--------------------|------|-----|-----| +| **Document Properties** | Standard | ✓ | | | +| | Extended | ✓ | | | +| | UserDefined | ✓ | | | +| **Element Type** | Text | ✓ | ✓ | | +| | Text Run | ✓ | | | +| | Title | ✓ | ✓ | | +| | Link | ✓ | | | +| | Preserve Text | ✓ | | | +| | Text Break | ✓ | | | +| | Page Break | ✓ | | | +| | List | ✓ | ✓ | | +| | Table | ✓ | | | +| | Image | ✓ | | | +| | Object | | | | +| | Watermark | | | | +| | Table of Contents | | | | +| | Header | ✓ | | | +| | Footer | ✓ | | | +| | Footnote | ✓ | | | +| | Endnote | ✓ | | | +| **Graphs** | 2D basic graphs | | | | +| | 2D advanced graphs | | | | +| | 3D graphs | | | | +| **Math** | OMML support | | | | +| | MathML support | | | | +| **Bonus** | Encryption | | | | +| | Protection | | | | + +# Installing/configuring + +## Requirements + +Mandatory: + +- PHP 5.3+ +- PHP [Zip](http://php.net/manual/en/book.zip.php) extension +- PHP [XML Parser](http://www.php.net/manual/en/xml.installation.php) extension + +Optional PHP extensions: + +- [GD](http://php.net/manual/en/book.image.php) +- [XMLWriter](http://php.net/manual/en/book.xmlwriter.php) +- [XSL](http://php.net/manual/en/book.xsl.php) + +## Installation + +There are two ways to install PHPWord, i.e. via [Composer](http://getcomposer.org/) or manually by downloading the library. + +### Using Composer + +To install via Composer, add the following lines to your `composer.json`: + +```json +{ + "require": { + "phpoffice/phpword": "dev-master" + } +} +``` + +### Manual install + +To install manually, [download PHPWord package from github](https://github.com/PHPOffice/PHPWord/archive/master.zip). Extract the package and put the contents to your machine. To use the library, include `src/PhpWord/Autoloader.php` in your script and invoke `Autoloader::register`. + +```php +require_once '/path/to/src/PhpWord/Autoloader.php'; +\PhpOffice\PhpWord\Autoloader::register(); +``` + +## Using samples + +After installation, you can browse and use the samples that we've provided, either by command line or using browser. If you can access your PHPWord library folder using browser, point your browser to the `samples` folder, e.g. `http://localhost/PhpWord/samples/`. + +# General usage + +## Basic example + +The following is a basic example of the PHPWord library. More examples are provided in the [samples folder](https://github.com/PHPOffice/PHPWord/tree/master/samples/). + +```php +require_once 'src/PhpWord/Autoloader.php'; +\PhpOffice\PhpWord\Autoloader::register(); + +$phpWord = new \PhpOffice\PhpWord\PhpWord(); + +// Every element you want to append to the word document is placed in a section. +// To create a basic section: +$section = $phpWord->addSection(); + +// After creating a section, you can append elements: +$section->addText('Hello world!'); + +// You can directly style your text by giving the addText function an array: +$section->addText('Hello world! I am formatted.', + array('name'=>'Tahoma', 'size'=>16, 'bold'=>true)); + +// If you often need the same style again you can create a user defined style +// to the word document and give the addText function the name of the style: +$phpWord->addFontStyle('myOwnStyle', + array('name'=>'Verdana', 'size'=>14, 'color'=>'1B2232')); +$section->addText('Hello world! I am formatted by a user defined style', + 'myOwnStyle'); + +// You can also put the appended element to local object like this: +$fontStyle = new \PhpOffice\PhpWord\Style\Font(); +$fontStyle->setBold(true); +$fontStyle->setName('Verdana'); +$fontStyle->setSize(22); +$myTextElement = $section->addText('Hello World!'); +$myTextElement->setFontStyle($fontStyle); + +// Finally, write the document: +$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); +$objWriter->save('helloWorld.docx'); + +$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'ODText'); +$objWriter->save('helloWorld.odt'); + +$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'RTF'); +$objWriter->save('helloWorld.rtf'); +``` + +## Settings + +The `PhpOffice\PhpWord\Settings` class provides some options that will affect the behavior of PHPWord. Below are the options. + +### XML Writer compatibility + +This option sets [XMLWriter::setIndent](http://www.php.net/manual/en/function.xmlwriter-set-indent.php) and [XMLWriter::setIndentString](http://www.php.net/manual/en/function.xmlwriter-set-indent-string.php). The default value of this option is `true` (compatible), which is [required for OpenOffice](https://github.com/PHPOffice/PHPWord/issues/103) to render OOXML document correctly. You can set this option to `false` during development to make the resulting XML file easier to read. + +```php +\PhpOffice\PhpWord\Settings::setCompatibility(false); +``` + +### Zip class + +By default, PHPWord uses PHP [ZipArchive](http://php.net/manual/en/book.zip.php) to read or write ZIP compressed archive and the files inside them. If you can't have ZipArchive installed on your server, you can use pure PHP library alternative, [PCLZip](http://www.phpconcept.net/pclzip/), which included with PHPWord. + +```php +\PhpOffice\PhpWord\Settings::setZipClass(\PhpOffice\PhpWord\Settings::PCLZIP); +``` + +## Default font + +By default, every text appears in Arial 10 point. You can alter the default font by using the following two functions: + +```php +$phpWord->setDefaultFontName('Times New Roman'); +$phpWord->setDefaultFontSize(12); +``` + +## Document properties + +You can set the document properties such as title, creator, and company name. Use the following functions: + +```php +$properties = $phpWord->getDocumentProperties(); +$properties->setCreator('My name'); +$properties->setCompany('My factory'); +$properties->setTitle('My title'); +$properties->setDescription('My description'); +$properties->setCategory('My category'); +$properties->setLastModifiedBy('My name'); +$properties->setCreated(mktime(0, 0, 0, 3, 12, 2014)); +$properties->setModified(mktime(0, 0, 0, 3, 14, 2014)); +$properties->setSubject('My subject'); +$properties->setKeywords('my, key, word'); +``` + +## Measurement units + +The base length unit in Open Office XML is twip. Twip means "TWentieth of an Inch Point", i.e. 1 twip = 1/1440 inch. + +You can use PHPWord helper functions to convert inches, centimeters, or points to twips. + +```php +// Paragraph with 6 points space after +$phpWord->addParagraphStyle('My Style', array( + 'spaceAfter' => \PhpOffice\PhpWord\Shared\Font::pointSizeToTwips(6)) +); + +$section = $phpWord->addSection(); +$sectionStyle = $section->getSettings(); +// half inch left margin +$sectionStyle->setMarginLeft(\PhpOffice\PhpWord\Shared\Font::inchSizeToTwips(.5)); +// 2 cm right margin +$sectionStyle->setMarginRight(\PhpOffice\PhpWord\Shared\Font::centimeterSizeToTwips(2)); +``` + +# Containers + +Containers are objects where you can put elements (texts, lists, tables, etc). There are 3 main containers, i.e. sections, headers, and footers. There are 3 elements that can also act as containers, i.e. textruns, table cells, and footnotes. + +## Sections + +Every visible element in word is placed inside of a section. To create a section, use the following code: + +```php +$section = $phpWord->addSection($sectionSettings); +``` + +The `$sectionSettings` is an optional associative array that sets the section. Example: + +```php +$sectionSettings = array( + 'orientation' => 'landscape', + 'marginTop' => 600, + 'colsNum' => 2, +); +``` + +### Section settings + +Below are the available settings for section: + +- `orientation` Page orientation, i.e. 'portrait' (default) or 'landscape' +- `marginTop` Page margin top in twips +- `marginLeft` Page margin left in twips +- `marginRight` Page margin right in twips +- `marginBottom` Page margin bottom in twips +- `borderTopSize` Border top size in twips +- `borderTopColor` Border top color +- `borderLeftSize` Border left size in twips +- `borderLeftColor` Border left color +- `borderRightSize` Border right size in twips +- `borderRightColor` Border right color +- `borderBottomSize` Border bottom size in twips +- `borderBottomColor` Border bottom color +- `headerHeight` Spacing to top of header +- `footerHeight` Spacing to bottom of footer +- `gutter` Page gutter spacing +- `colsNum` Number of columns +- `colsSpace` Spacing between columns +- `breakType` Section break type (nextPage, nextColumn, continuous, evenPage, oddPage) + +The following two settings are automatically set by the use of the `orientation` setting. You can alter them but that's not recommended. + +- `pageSizeW` Page width in twips +- `pageSizeH` Page height in twips + +### Page number + +You can change a section page number by using the `pageNumberingStart` property of the section. + +```php +// Method 1 +$section = $phpWord->addSection(array('pageNumberingStart' => 1)); + +// Method 2 +$section = $phpWord->addSection(); +$section->getSettings()->setPageNumberingStart(1); +``` + +### Multicolumn + +You can change a section layout to multicolumn (like in a newspaper) by using the `breakType` and `colsNum` property of the section. + +```php +// Method 1 +$section = $phpWord->addSection(array('breakType' => 'continuous', 'colsNum' => 2)); + +// Method 2 +$section = $phpWord->addSection(); +$section->getSettings()->setBreakType('continuous'); +$section->getSettings()->setColsNum(2); +``` + +### Line numbering + +You can apply line numbering to a section by using the `lineNumbering` property of the section. + +```php +// Method 1 +$section = $phpWord->addSection(array('lineNumbering' => array())); + +// Method 2 +$section = $phpWord->addSection(); +$section->getSettings()->setLineNumbering(array()); +``` + +Below are the properties of the line numbering style. + +- `start` Line numbering starting value +- `increment` Line number increments +- `distance` Distance between text and line numbering in twip +- `restart` Line numbering restart setting continuous|newPage|newSection + +## Headers + +Each section can have its own header reference. To create a header use the `addHeader` method: + +```php +$header = $section->addHeader(); +``` + +Be sure to save the result in a local object. You can use all elements that are available for the footer. See "Footer" section for detail. Additionally, only inside of the header reference you can add watermarks or background pictures. See "Watermarks" section. + +## Footers + +Each section can have its own footer reference. To create a footer, use the `addFooter` method: + +```php +$footer = $section->addFooter(); +``` + +Be sure to save the result in a local object to add elements to a footer. You can add the following elements to footers: + +- Texts `addText` and `createTextrun` +- Text breaks +- Images +- Tables +- Preserve text + +See the "Elements" section for the detail of each elements. + +## Other containers + +Textruns, table cells, and footnotes are elements that can also act as containers. See the corresponding "Elements" section for the detail of each elements. + +# Elements + +Below are the matrix of element availability in each container. The column shows the containers while the rows lists the elements. + +| Num | Element | Section | Header | Footer | Cell | Text Run | Footnote | +|-----|---------------|---------|--------|--------|------|----------|----------| +| 1 | Text | v | v | v | v | v | v | +| 2 | Text Run | v | v | v | v | - | - | +| 3 | Link | v | v | v | v | v | v | +| 4 | Title | v | ? | ? | ? | ? | ? | +| 5 | Preserve Text | ? | v | v | v* | ? | ? | +| 6 | Text Break | v | v | v | v | v | v | +| 7 | Page Break | v | - | - | - | - | - | +| 8 | List | v | v | v | v | - | - | +| 9 | Table | v | v | v | ? | - | - | +| 10 | Image | v | v | v | v | v | v | +| 11 | Watermark | - | v | - | - | - | - | +| 12 | Object | v | v | v | v | v | v | +| 13 | TOC | v | - | - | - | - | - | +| 14 | Footnote | v | - | - | v** | v** | - | +| 15 | Endnote | v | - | - | v** | v** | - | +| 16 | CheckBox | v | v | v | v | ? | ? | + +Legend: + +- `v` Available +- `v*` Available only when inside header/footer +- `v**` Available only when inside section +- `-` Not available +- `?` Should be available + +## Texts + +Text can be added by using `addText` and `addTextRun` method. `addText` is used for creating simple paragraphs that only contain texts with the same style. `addTextRun` is used for creating complex paragraphs that contain text with different style (some bold, other italics, etc) or other elements, e.g. images or links. The syntaxes are as follow: + +```php +$section->addText($text, [$fontStyle], [$paragraphStyle]); +$textrun = $section->addTextRun([$paragraphStyle]); +``` + +### Text styles + +You can use the `$fontStyle` and `$paragraphStyle` variable to define text formatting. There are 2 options to style the inserted text elements, i.e. inline style by using array or defined style by adding style definition. + +Inline style examples: + +```php +$fontStyle = array('name' => 'Times New Roman', 'size' => 9); +$paragraphStyle = array('align' => 'both'); +$section->addText('I am simple paragraph', $fontStyle, $paragraphStyle); + +$textrun = $section->addTextRun(); +$textrun->addText('I am bold', array('bold' => true)); +$textrun->addText('I am italic', array('italic' => true)); +$textrun->addText('I am colored, array('color' => 'AACC00')); +``` + +Defined style examples: + +```php +$fontStyle = array('color' => '006699', 'size' => 18, 'bold' => true); +$phpWord->addFontStyle('fStyle', $fontStyle); +$text = $section->addText('Hello world!', 'fStyle'); + +$paragraphStyle = array('align' => 'center'); +$phpWord->addParagraphStyle('pStyle', $paragraphStyle); +$text = $section->addText('Hello world!', 'pStyle'); +``` + +#### Font style + +Available font styles: + +- `name` Font name, e.g. *Arial* +- `size` Font size, e.g. *20*, *22*, +- `hint` Font content type, *default*, *eastAsia*, or *cs* +- `bold` Bold, *true* or *false* +- `italic` Italic, *true* or *false* +- `superScript` Superscript, *true* or *false* +- `subScript` Subscript, *true* or *false* +- `underline` Underline, *dash*, *dotted*, etc. +- `strikethrough` Strikethrough, *true* or *false* +- `doubleStrikethrough` Double strikethrough, *true* or *false* +- `color` Font color, e.g. *FF0000* +- `fgColor` Font highlight color, e.g. *yellow*, *green*, *blue* +- `bgColor` Font background color, e.g. *FF0000* +- `smallCaps` Small caps, *true* or *false* +- `allCaps` All caps, *true* or *false* + +#### Paragraph style + +Available paragraph styles: + +- `align` Paragraph alignment, *left*, *right* or *center* +- `spaceBefore` Space before paragraph +- `spaceAfter` Space after paragraph +- `indent` Indent by how much +- `hanging` Hanging by how much +- `basedOn` Parent style +- `next` Style for next paragraph +- `widowControl` Allow first/last line to display on a separate page, *true* or *false* +- `keepNext` Keep paragraph with next paragraph, *true* or *false* +- `keepLines` Keep all lines on one page, *true* or *false* +- `pageBreakBefore` Start paragraph on next page, *true* or *false* +- `lineHeight` text line height, e.g. *1.0*, *1.5*, ect... +- `tabs` Set of custom tab stops + +### Titles + +If you want to structure your document or build table of contents, you need titles or headings. To add a title to the document, use the `addTitleStyle` and `addTitle` method. + +```php +$phpWord->addTitleStyle($depth, [$fontStyle], [$paragraphStyle]); +$section->addTitle($text, [$depth]); +``` + +Its necessary to add a title style to your document because otherwise the title won't be detected as a real title. + +### Links + +You can add Hyperlinks to the document by using the function addLink: + +```php +$section->addLink($linkSrc, [$linkName], [$fontStyle], [$paragraphStyle]); +``` + +- `$linkSrc` The URL of the link. +- `$linkName` Placeholder of the URL that appears in the document. +- `$fontStyle` See "Font style" section. +- `$paragraphStyle` See "Paragraph style" section. + +### Preserve texts + +The `addPreserveText` method is used to add a page number or page count to headers or footers. + +```php +$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.'); +``` + +## Breaks + +### Text breaks + +Text breaks are empty new lines. To add text breaks, use the following syntax. All paramaters are optional. + +```php +$section->addTextBreak([$breakCount], [$fontStyle], [$paragraphStyle]); +``` + +- `$breakCount` How many lines +- `$fontStyle` See "Font style" section. +- `$paragraphStyle` See "Paragraph style" section. + +### Page breaks + +There are two ways to insert a page breaks, using the `addPageBreak` method or using the `pageBreakBefore` style of paragraph. + +:: code-block:: php + +> \$section-\>addPageBreak(); + +## Lists + +To add a list item use the function `addListItem`. + +Basic usage: + +```php +$section->addListItem($text, [$depth], [$fontStyle], [$listStyle], [$paragraphStyle]); +``` + +Parameters: + +- `$text` Text that appears in the document. +- `$depth` Depth of list item. +- `$fontStyle` See "Font style" section. +- `$listStyle` List style of the current element TYPE\_NUMBER, TYPE\_ALPHANUM, TYPE\_BULLET\_FILLED, etc. See list of constants in PHPWord\_Style\_ListItem. +- `$paragraphStyle` See "Paragraph style" section. + +Advanced usage: + +You can also create your own numbering style by changing the `$listStyle` parameter with the name of your numbering style. + +```php +$phpWord->addNumberingStyle( + 'multilevel', + array('type' => 'multilevel', 'levels' => array( + array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), + array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), + ) + ) +); +$section->addListItem('List Item I', 0, null, 'multilevel'); +$section->addListItem('List Item I.a', 1, null, 'multilevel'); +$section->addListItem('List Item I.b', 1, null, 'multilevel'); +$section->addListItem('List Item II', 0, null, 'multilevel'); +``` + +Level styles: + +- `start` Starting value +- `format` Numbering format bullet|decimal|upperRoman|lowerRoman|upperLetter|lowerLetter +- `restart` Restart numbering level symbol +- `suffix` Content between numbering symbol and paragraph text tab|space|nothing +- `text` Numbering level text e.g. %1 for nonbullet or bullet character +- `align` Numbering symbol align left|center|right|both +- `left` See paragraph style +- `hanging` See paragraph style +- `tabPos` See paragraph style +- `font` Font name +- `hint` See font style + +## Tables + +To add tables, rows, and cells, use the `addTable`, `addRow`, and `addCell` methods: + +```php +$table = $section->addTable([$tableStyle]); +$table->addRow([$height], [$rowStyle]); +$cell = $table->addCell($width, [$cellStyle]); +``` + +Table style can be defined with `addTableStyle`: + +```php +$tableStyle = array( + 'borderColor' => '006699', + 'borderSize' => 6, + 'cellMargin' => 50 +); +$firstRowStyle = array('bgColor' => '66BBFF'); +$phpWord->addTableStyle('myTable', $tableStyle, $firstRowStyle); +$table = $section->addTable('myTable'); +``` + +### Table, row, and cell styles + +Table styles: + +- `width` Table width in percent +- `bgColor` Background color, e.g. '9966CC' +- `border(Top|Right|Bottom|Left)Size` Border size in twips +- `border(Top|Right|Bottom|Left)Color` Border color, e.g. '9966CC' +- `cellMargin(Top|Right|Bottom|Left)` Cell margin in twips + +Row styles: + +- `tblHeader` Repeat table row on every new page, *true* or *false* +- `cantSplit` Table row cannot break across pages, *true* or *false* +- `exactHeight` Row height is exact or at least + +Cell styles: + +- `width` Cell width in twips +- `valign` Vertical alignment, *top*, *center*, *both*, *bottom* +- `textDirection` Direction of text +- `bgColor` Background color, e.g. '9966CC' +- `border(Top|Right|Bottom|Left)Size` Border size in twips +- `border(Top|Right|Bottom|Left)Color` Border color, e.g. '9966CC' +- `gridSpan` Number of columns spanned +- `vMerge` *restart* or *continue* + +### Cell span + +You can span a cell on multiple columns by using `gridSpan` or multiple rows by using `vMerge`. + +```php +$cell = $table->addCell(200); +$cell->getStyle()->setGridSpan(5); +``` + +See `Sample_09_Tables.php` for more code sample. + +## Images + +To add an image, use the `addImage` method to sections, headers, footers, textruns, or table cells. + +```php +$section->addImage($src, [$style]); +``` + +- source String path to a local image or URL of a remote image +- styles Array fo styles for the image. See below. + +Examples: + +```php +$section = $phpWord->addSection(); +$section->addImage( + 'mars.jpg', + array( + 'width' => 100, + 'height' => 100, + 'marginTop' => -1, + 'marginLeft' => -1, + 'wrappingStyle' => 'behind' + ) +); +$footer = $section->addFooter(); +$footer->addImage('http://example.com/image.php'); +$textrun = $section->addTextRun(); +$textrun->addImage('http://php.net/logo.jpg'); +``` + +### Image styles + +Available image styles: + +- `width` Width in pixels +- `height` Height in pixels +- `align` Image alignment, *left*, *right*, or *center* +- `marginTop` Top margin in inches, can be negative +- `marginLeft` Left margin in inches, can be negative +- `wrappingStyle` Wrapping style, *inline*, *square*, *tight*, *behind*, or *infront* + +### Watermarks + +To add a watermark (or page background image), your section needs a header reference. After creating a header, you can use the `addWatermark` method to add a watermark. + +```php +$section = $phpWord->addSection(); +$header = $section->addHeader(); +$header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); +``` + +## Objects + +You can add OLE embeddings, such as Excel spreadsheets or PowerPoint presentations to the document by using `addObject` method. + +```php +$section->addObject($src, [$style]); +``` + +## Table of contents + +To add a table of contents (TOC), you can use the `addTOC` method. Your TOC can only be generated if you have add at least one title (See "Titles"). + +```php +$section->addTOC([$fontStyle], [$tocStyle], [$minDepth], [$maxDepth]); +``` + +- `$fontStyle`: See font style section +- `$tocStyle`: See available options below +- `$minDepth`: Minimum depth of header to be shown. Default 1 +- `$maxDepth`: Maximum depth of header to be shown. Default 9 + +Options for `$tocStyle`: + +- `tabLeader` Fill type between the title text and the page number. Use the defined constants in PHPWord\_Style\_TOC. +- `tabPos` The position of the tab where the page number appears in twips. +- `indent` The indent factor of the titles in twips. + +## Footnotes & endnotes + +You can create footnotes with `addFootnote` and endnotes with `addEndnote` in texts or textruns, but it's recommended to use textrun to have better layout. You can use `addText`, `addLink`, `addTextBreak`, `addImage`, `addObject` on footnotes and endnotes. + +On textrun: + +```php +$textrun = $section->addTextRun(); +$textrun->addText('Lead text.'); +$footnote = $textrun->addFootnote(); +$footnote->addText('Footnote text can have '); +$footnote->addLink('http://test.com', 'links'); +$footnote->addText('.'); +$footnote->addTextBreak(); +$footnote->addText('And text break.'); +$textrun->addText('Trailing text.'); +$endnote = $textrun->addEndnote(); +$endnote->addText('Endnote put at the end'); +``` + +On text: + +```php +$section->addText('Lead text.'); +$footnote = $section->addFootnote(); +$footnote->addText('Footnote text.'); +``` + +The footnote reference number will be displayed with decimal number starting from 1. This number use `FooterReference` style which you can redefine by `addFontStyle` method. Default value for this style is `array('superScript' => true)`; + +## Checkboxes + +Checkbox elements can be added to sections or table cells by using `addCheckBox`. + +```php +$section->addCheckBox($name, $text, [$fontStyle], [$paragraphStyle]) +``` + +- `$name` Name of the check box. +- `$text` Text following the check box +- `$fontStyle` See "Font style" section. +- `$paragraphStyle` See "Paragraph style" section. + +# Templates + +You can create a docx template with included search-patterns that can be replaced by any value you wish. Only single-line values can be replaced. To load a template file, use the `loadTemplate` method. After loading the docx template, you can use the `setValue` method to change the value of a search pattern. The search-pattern model is: `${search-pattern}`. It is not possible to add new PHPWord elements to a loaded template file. + +Example: + +```php +$template = $phpWord->loadTemplate('Template.docx'); +$template->setValue('Name', 'Somebody someone'); +$template->setValue('Street', 'Coming-Undone-Street 32'); +``` + +See `Sample_07_TemplateCloneRow.php` for example on how to create multirow from a single row in a template by using `cloneRow`. + +See `Sample_23_TemplateBlock.php` for example on how to clone a block of text using `cloneBlock` and delete a block of text using `deleteBlock`. + +# Writers & readers + +## OOXML + +The package of OOXML document consists of the following files. + +- _rels/ + - .rels +- docProps/ + - app.xml + - core.xml + - custom.xml +- word/ + - rels/ + - document.rels.xml + - media/ + - theme/ + - theme1.xml + - document.xml + - fontTable.xml + - numbering.xml + - settings.xml + - styles.xml + - webSettings.xml +- [Content_Types].xml + +## OpenDocument + +### Package + +The package of OpenDocument document consists of the following files. + +- META-INF/ + - manifest.xml +- Pictures/ +- content.xml +- meta.xml +- styles.xml + +### content.xml + +The structure of `content.xml` is described below. + +- office:document-content + - office:font-facedecls + - office:automatic-styles + - office:body + - office:text + - draw:* + - office:forms + - table:table + - text:list + - text:numbered-paragraph + - text:p + - text:table-of-contents + - text:section + - office:chart + - office:image + - office:drawing + +### styles.xml + +The structure of `styles.xml` is described below. + +- office:document-styles + - office:styles + - office:automatic-styles + - office:master-styles + - office:master-page + +## RTF + +To be completed. + +## HTML + +To be completed. + +## PDF + +To be completed. + +# Frequently asked questions + +## Is this the same with PHPWord that I found in CodePlex? + +No. This one is much better with tons of new features that you can’t find in PHPWord 0.6.3. The development in CodePlex is halted and switched to GitHub to allow more participation from the crowd. The more the merrier, right? + +## I’ve been running PHPWord from CodePlex flawlessly, but I can’t use the latest PHPWord from GitHub. Why? + +PHPWord requires PHP 5.3+ since 0.8, while PHPWord 0.6.3 from CodePlex can run with PHP 5.2. There’s a lot of new features that we can get from PHP 5.3 and it’s been around since 2009! You should upgrade your PHP version to use PHPWord 0.8+. + +# References + +## Formal specifications + +- [Office Open XML (OOXML) (ECMA-376) Schema](http://www.schemacentral.com/sc/ooxml/ss.html) +- [Oasis OpenDocument Standard Version 1.2](http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os.html) +- [Rich Text Format (RTF) Specification, version 1.9.1](http://www.microsoft.com/en-us/download/details.aspx?id=10725) + +## Other resources + +- [DocumentFormat.OpenXml.Wordprocessing Namespace on MSDN](http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing%28v=office.14%29.aspx) + diff --git a/docs/templates.rst b/docs/templates.rst index 6b627b06..b1d9d205 100644 --- a/docs/templates.rst +++ b/docs/templates.rst @@ -19,6 +19,9 @@ Example: $template->setValue('Name', 'Somebody someone'); $template->setValue('Street', 'Coming-Undone-Street 32'); -See ``Sample_07_TemplateCloneRow.php`` for more code sample, including -how to create multirow from a single row in a template by using -``cloneRow``. +See ``Sample_07_TemplateCloneRow.php`` for example on how to create +multirow from a single row in a template by using ``cloneRow``. + +See ``Sample_23_TemplateBlock.php`` for example on how to clone a block +of text using ``cloneBlock`` and delete a block of text using +``deleteBlock``. diff --git a/docs/writersreaders.rst b/docs/writersreaders.rst new file mode 100644 index 00000000..34a0805a --- /dev/null +++ b/docs/writersreaders.rst @@ -0,0 +1,110 @@ +.. _writersreaders: + +Writers & readers +================= + +OOXML +----- + +The package of OOXML document consists of the following files. + +- \_rels/ + + - .rels + +- docProps/ + + - app.xml + - core.xml + - custom.xml + +- word/ + + - rels/ + + - document.rels.xml + + - media/ + - theme/ + + - theme1.xml + + - document.xml + - fontTable.xml + - numbering.xml + - settings.xml + - styles.xml + - webSettings.xml + +- [Content\_Types].xml + +OpenDocument +------------ + +Package +~~~~~~~ + +The package of OpenDocument document consists of the following files. + +- META-INF/ + + - manifest.xml + +- Pictures/ +- content.xml +- meta.xml +- styles.xml + +content.xml +~~~~~~~~~~~ + +The structure of ``content.xml`` is described below. + +- office:document-content + + - office:font-facedecls + - office:automatic-styles + - office:body + + - office:text + + - draw:\* + - office:forms + - table:table + - text:list + - text:numbered-paragraph + - text:p + - text:table-of-contents + - text:section + + - office:chart + - office:image + - office:drawing + +styles.xml +~~~~~~~~~~ + +The structure of ``styles.xml`` is described below. + +- office:document-styles + + - office:styles + - office:automatic-styles + - office:master-styles + + - office:master-page + +RTF +--- + +To be completed. + +HTML +---- + +To be completed. + +PDF +--- + +To be completed. diff --git a/phpmd.xml b/phpmd.xml new file mode 100644 index 00000000..c1ebb770 --- /dev/null +++ b/phpmd.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 05b08442..f77b9ce3 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -16,6 +16,9 @@ ./src + + ./src/PhpWord/Shared/PCLZip + \ No newline at end of file diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php old mode 100755 new mode 100644 index 7ada399a..7202ed7e --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -2,14 +2,14 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -$phpWord->addFontStyle('rStyle', array('bold' => true, 'italic' => true, 'size' => 16)); +$phpWord->addFontStyle('rStyle', array('bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true)); $phpWord->addParagraphStyle('pStyle', array('align' => 'center', 'spaceAfter' => 100)); $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); // New portrait section -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Simple text $section->addTitle('Welcome to PhpWord', 1); @@ -34,6 +34,7 @@ $fontStyle['strikethrough'] = true; $fontStyle['superScript'] = true; $fontStyle['color'] = 'FF0000'; $fontStyle['fgColor'] = 'yellow'; +$fontStyle['smallCaps'] = true; $section->addText('I am inline styled.', $fontStyle); $section->addTextBreak(); @@ -45,13 +46,7 @@ $section->addTextBreak(); $section->addImage('resources/_earth.jpg', array('width'=>18, 'height'=>18)); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_02_TabStops.php b/samples/Sample_02_TabStops.php old mode 100755 new mode 100644 index f08f1e15..d6e4cdbc --- a/samples/Sample_02_TabStops.php +++ b/samples/Sample_02_TabStops.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , ' Create new PhpWord object' , \EOL; +echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Ads styles @@ -25,21 +25,15 @@ $phpWord->addParagraphStyle('centerTab', array( )); // New portrait section -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Add listitem elements -$section->addText("Multiple Tabs:\tOne\tTwo\tThree", NULL, 'multipleTab'); -$section->addText("Left Aligned\tRight Aligned", NULL, 'rightTab'); -$section->addText("\tCenter Aligned", NULL, 'centerTab'); +$section->addText("Multiple Tabs:\tOne\tTwo\tThree", null, 'multipleTab'); +$section->addText("Left Aligned\tRight Aligned", null, 'rightTab'); +$section->addText("\tCenter Aligned", null, 'centerTab'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php old mode 100755 new mode 100644 index c16b73db..bfbc84af --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -2,37 +2,31 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , ' Create new PhpWord object' , \EOL; +echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // New portrait section -$section = $phpWord->createSection(array('borderColor' => '00FF00', 'borderSize' => 12)); +$section = $phpWord->addSection(array('borderColor' => '00FF00', 'borderSize' => 12)); $section->addText('I am placed on a default section.'); // New landscape section -$section = $phpWord->createSection(array('orientation' => 'landscape')); +$section = $phpWord->addSection(array('orientation' => 'landscape')); $section->addText('I am placed on a landscape section. Every page starting from this section will be landscape style.'); $section->addPageBreak(); $section->addPageBreak(); // New portrait section -$section = $phpWord->createSection(array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600)); +$section = $phpWord->addSection(array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600)); $section->addText('This section uses other margins.'); // New portrait section with Header & Footer -$section = $phpWord->createSection(array('marginLeft' => 200, 'marginRight' => 200, 'marginTop' => 200, 'marginBottom' => 200, 'headerHeight' => 50, 'footerHeight' => 50,)); +$section = $phpWord->addSection(array('marginLeft' => 200, 'marginRight' => 200, 'marginTop' => 200, 'marginBottom' => 200, 'headerHeight' => 50, 'footerHeight' => 50,)); $section->addText('This section and we play with header/footer height.'); -$section->createHeader()->addText('Header'); -$section->createFooter()->addText('Footer'); +$section->addHeader()->addText('Header'); +$section->addFooter()->addText('Footer'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index 94bc3d5b..e41f4ddb 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -2,20 +2,20 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , ' Create new PhpWord object' , \EOL; +echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Ads styles $phpWord->addParagraphStyle('pStyle', array('spacing'=>100)); $phpWord->addFontStyle('BoldText', array('bold'=>true)); -$phpWord->addFontStyle('ColoredText', array('color'=>'FF8080')); +$phpWord->addFontStyle('ColoredText', array('color'=>'FF8080', 'bgColor' => 'FFFFCC')); $phpWord->addLinkStyle('NLink', array('color'=>'0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE)); // New portrait section -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Add text run -$textrun = $section->createTextRun('pStyle'); +$textrun = $section->addTextRun('pStyle'); $textrun->addText('Each textrun can contain native text, link elements or an image.'); $textrun->addText(' No break is placed after adding an element.', 'BoldText'); @@ -28,17 +28,13 @@ $textrun->addText(' All elements are placed inside a paragraph with the optional $textrun->addText(' Sample Link: '); $textrun->addLink('http://www.google.com', null, 'NLink'); $textrun->addText(' Sample Image: '); -$textrun->addImage('resources/_earth.jpg', array('width'=>18, 'height'=>18)); +$textrun->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); +$textrun->addText(' Sample Object: '); +$textrun->addObject('resources/_sheet.xls'); $textrun->addText(' Here is some more text. '); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php index 541e2e8a..a3083824 100644 --- a/samples/Sample_05_Multicolumn.php +++ b/samples/Sample_05_Multicolumn.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $filler = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' . 'Nulla fermentum, tortor id adipiscing adipiscing, tortor turpis commodo. ' . @@ -10,39 +10,33 @@ $filler = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' . 'Suspendisse congue congue leo sed pellentesque.'; // Normal -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText('Normal paragraph. ' . $filler); // Two columns -$section = $phpWord->createSection(array( +$section = $phpWord->addSection(array( 'colsNum' => 2, 'colsSpace' => 1440, 'breakType' => 'continuous')); $section->addText('Three columns, one inch (1440 twips) spacing. ' . $filler); // Normal -$section = $phpWord->createSection(array('breakType' => 'continuous')); +$section = $phpWord->addSection(array('breakType' => 'continuous')); $section->addText('Normal paragraph again. ' . $filler); // Three columns -$section = $phpWord->createSection(array( +$section = $phpWord->addSection(array( 'colsNum' => 3, 'colsSpace' => 720, 'breakType' => 'continuous')); $section->addText('Three columns, half inch (720 twips) spacing. ' . $filler); // Normal -$section = $phpWord->createSection(array('breakType' => 'continuous')); +$section = $phpWord->addSection(array('breakType' => 'continuous')); $section->addText('Normal paragraph again.'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php old mode 100755 new mode 100644 index c430e548..1bec44e4 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -2,11 +2,12 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); +\PhpOffice\PhpWord\Settings::setCompatibility(false); // New portrait section -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Add style definitions $phpWord->addParagraphStyle('pStyle', array('spacing'=>100)); @@ -15,32 +16,29 @@ $phpWord->addFontStyle('ColoredText', array('color'=>'FF8080')); $phpWord->addLinkStyle('NLink', array('color'=>'0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE)); // Add text elements -$textrun = $section->createTextRun('pStyle'); +$textrun = $section->addTextRun('pStyle'); $textrun->addText('This is some lead text in a paragraph with a following footnote. ','pStyle'); -$footnote = $textrun->createFootnote(); -$footnote->addText('Just like a textrun a footnote can contain native text and link elements.'); -$footnote->addText(' No break is placed after adding an element.', 'BoldText'); -$footnote->addText(' All elements are placed inside a paragraph.', 'ColoredText'); -$footnote->addText(' The best search engine: '); +$footnote = $textrun->addFootnote(); +$footnote->addText('Just like a textrun, a footnote can contain native texts. '); +$footnote->addText('No break is placed after adding an element. ', 'BoldText'); +$footnote->addText('All elements are placed inside a paragraph. ', 'ColoredText'); +$footnote->addTextBreak(); +$footnote->addText('But you can insert a manual text break like above, '); +$footnote->addText('links like '); $footnote->addLink('http://www.google.com', null, 'NLink'); -$footnote->addText('. Also not bad: '); -$footnote->addLink('http://www.bing.com', null, 'NLink'); - -$textrun->addText('The trailing text in the paragraph.'); +$footnote->addText(', image like '); +$footnote->addImage('resources/_earth.jpg', array('width' => 18, 'height' => 18)); +$footnote->addText(', or object like '); +$footnote->addObject('resources/_sheet.xls'); +$footnote->addText('But you can only put footnote in section, not in header or footer.'); $section->addText('You can also create the footnote directly from the section making it wrap in a paragraph like the footnote below this paragraph. But is is best used from within a textrun.'); -$footnote = $section->createFootnote(); +$footnote = $section->addFootnote(); $footnote->addText('The reference for this is wrapped in its own line'); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_07_TemplateCloneRow.php b/samples/Sample_07_TemplateCloneRow.php old mode 100755 new mode 100644 index 4344fafc..899bc82b --- a/samples/Sample_07_TemplateCloneRow.php +++ b/samples/Sample_07_TemplateCloneRow.php @@ -2,11 +2,16 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $document = $phpWord->loadTemplate('resources/Sample_07_TemplateCloneRow.docx'); +// Variables on different parts of document +$document->setValue('weekday', date('l')); // On section/content +$document->setValue('time', date('H:i')); // On footer +$document->setValue('serverName', realpath(__DIR__)); // On header + // Simple table $document->cloneRow('rowValue', 10); @@ -32,9 +37,6 @@ $document->setValue('rowNumber#8', '8'); $document->setValue('rowNumber#9', '9'); $document->setValue('rowNumber#10', '10'); -$document->setValue('weekday', date('l')); -$document->setValue('time', date('H:i')); - // Table with a spanned cell $document->cloneRow('userId', 3); @@ -54,8 +56,11 @@ $document->setValue('userName#3', 'Ray'); $document->setValue('userPhone#3', '+1 428 889 775'); $name = 'Sample_07_TemplateCloneRow.docx'; -echo date('H:i:s'), " Write to Word2007 format", \EOL; +echo date('H:i:s'), " Write to Word2007 format", EOL; $document->saveAs($name); rename($name, "results/{$name}"); -include_once 'Sample_Footer.php'; +echo getEndingNotes(array('Word2007' => 'docx')); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index eeef6058..d3f0c1fb 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord->setDefaultParagraphStyle(array( 'align' => 'both', @@ -11,31 +11,31 @@ $phpWord->setDefaultParagraphStyle(array( )); // Sample -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText('Below are the samples on how to control your paragraph ' . 'pagination. See "Line and Page Break" tab on paragraph properties ' . 'window to see the attribute set by these controls.', - array('bold' => true), null); + array('bold' => true), array('space' => array('before' => 360, 'after' => 480))); $section->addText('Paragraph with widowControl = false (default: true). ' . 'A "widow" is the last line of a paragraph printed by itself at the top ' . 'of a page. An "orphan" is the first line of a paragraph printed by ' . 'itself at the bottom of a page. Set this option to "false" if you want ' . 'to disable this automatic control.', - null, array('widowControl' => false)); + null, array('widowControl' => false, 'indentation' => array('left' => 240, 'right' => 120))); $section->addText('Paragraph with keepNext = true (default: false). ' . '"Keep with next" is used to prevent Word from inserting automatic page ' . 'breaks between paragraphs. Set this option to "true" if you do not want ' . 'your paragraph to be separated with the next paragraph.', - null, array('keepNext' => true)); + null, array('keepNext' => true, 'indentation' => array('firstLine' => 240))); $section->addText('Paragraph with keepLines = true (default: false). ' . '"Keep lines together" will prevent Word from inserting an automatic page ' . 'break within a paragraph. Set this option to "true" if you do not want ' . 'all lines of your paragraph to be in the same page.', - null, array('keepLines' => true)); + null, array('keepLines' => true, 'indentation' => array('left' => 240, 'hanging' => 240))); $section->addText('Keep scrolling. More below.'); @@ -46,13 +46,7 @@ $section->addText('Paragraph with pageBreakBefore = true (default: false). ' . null, array('pageBreakBefore' => true)); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index ea10eec9..5b4b1300 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -2,9 +2,9 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , ' Create new PhpWord object' , \EOL; +echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $header = array('size' => 16, 'bold' => true); // 1. Basic table @@ -55,7 +55,7 @@ $section->addTextBreak(1); $section->addText("Table with colspan and rowspan", $header); $styleTable = array('borderSize' => 6, 'borderColor' => '999999'); -$cellRowSpan = array('vMerge' => 'restart', 'valign' => 'center'); +$cellRowSpan = array('vMerge' => 'restart', 'valign' => 'center', 'bgColor' => 'FFFF00'); $cellRowContinue = array('vMerge' => 'continue'); $cellColSpan = array('gridSpan' => 2, 'valign' => 'center'); $cellHCentered = array('align' => 'center'); @@ -63,10 +63,21 @@ $cellVCentered = array('valign' => 'center'); $phpWord->addTableStyle('Colspan Rowspan', $styleTable); $table = $section->addTable('Colspan Rowspan'); + $table->addRow(); -$table->addCell(2000, $cellRowSpan)->addText('A', null, $cellHCentered); -$table->addCell(4000, $cellColSpan)->addText('B', null, $cellHCentered); + +$cell1 = $table->addCell(2000, $cellRowSpan); +$textrun1 = $cell1->addTextRun($cellHCentered); +$textrun1->addText('A'); +$textrun1->addFootnote()->addText('Row span'); + +$cell2 = $table->addCell(4000, $cellColSpan); +$textrun2 = $cell2->addTextRun($cellHCentered); +$textrun2->addText('B'); +$textrun2->addFootnote()->addText('Colspan span'); + $table->addCell(2000, $cellRowSpan)->addText('E', null, $cellHCentered); + $table->addRow(); $table->addCell(null, $cellRowContinue); $table->addCell(2000, $cellVCentered)->addText('C', null, $cellHCentered); @@ -74,13 +85,7 @@ $table->addCell(2000, $cellVCentered)->addText('D', null, $cellHCentered); $table->addCell(null, $cellRowContinue); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_10_EastAsianFontStyle.php b/samples/Sample_10_EastAsianFontStyle.php index 6e8b26a0..44bca8a6 100644 --- a/samples/Sample_10_EastAsianFontStyle.php +++ b/samples/Sample_10_EastAsianFontStyle.php @@ -2,21 +2,15 @@ include_once 'Sample_Header.php'; // New Word Document -echo date('H:i:s') , ' Create new PhpWord object' , \EOL; +echo date('H:i:s') , ' Create new PhpWord object' , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $header = array('size' => 16, 'bold' => true); //1.Use EastAisa FontStyle $section->addText('中文楷体样式测试',array('name' => '楷体', 'size' => 16, 'color' => '1B2232')); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_11_ReadWord2007.php b/samples/Sample_11_ReadWord2007.php index b2420a53..09d9cab0 100644 --- a/samples/Sample_11_ReadWord2007.php +++ b/samples/Sample_11_ReadWord2007.php @@ -4,16 +4,11 @@ include_once 'Sample_Header.php'; // Read contents $name = basename(__FILE__, '.php'); $source = "resources/{$name}.docx"; -echo date('H:i:s'), " Reading contents from `{$source}`", \EOL; +echo date('H:i:s'), " Reading contents from `{$source}`", EOL; $phpWord = \PhpOffice\PhpWord\IOFactory::load($source); -// (Re)write contents -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index 3c5775ef..8e053286 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -2,30 +2,34 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s') , " Create new PhpWord object" , \EOL; +echo date('H:i:s') , " Create new PhpWord object" , EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // New portrait section -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Add first page header -$header = $section->createHeader(); +$header = $section->addHeader(); $header->firstPage(); $table = $header->addTable(); $table->addRow(); -$table->addCell(4500)->addText('This is the header.'); +$cell = $table->addCell(4500); +$textrun = $cell->addTextRun(); +$textrun->addText('This is the header with '); +$textrun->addLink('http://google.com', 'link to Google'); $table->addCell(4500)->addImage( 'resources/PhpWord.png', array('width' => 80, 'height' => 80, 'align' => 'right') ); // Add header for all other pages -$subsequent = $section->createHeader(); +$subsequent = $section->addHeader(); $subsequent->addText("Subsequent pages in Section 1 will Have this!"); // Add footer -$footer = $section->createFooter(); +$footer = $section->addFooter(); $footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', array('align' => 'center')); +$footer->addLink('http://google.com', 'Direct Google'); // Write some text $section->addTextBreak(); @@ -46,24 +50,17 @@ $section->addTextBreak(); $section->addText('Some text...'); // New portrait section -$section2 = $phpWord->createSection(); +$section2 = $phpWord->addSection(); -$sec2Header = $section2->createHeader(); +$sec2Header = $section2->addHeader(); $sec2Header->addText("All pages in Section 2 will Have this!"); // Write some text $section2->addTextBreak(); $section2->addText('Some text...'); - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index 6841ed64..65e38bf5 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -2,32 +2,37 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText('Local image without any styles:'); $section->addImage('resources/_mars.jpg'); $section->addTextBreak(2); -// + $section->addText('Local image with styles:'); $section->addImage('resources/_earth.jpg', array('width' => 210, 'height' => 210, 'align' => 'center')); $section->addTextBreak(2); +// Remote image $source = 'http://php.net/images/logos/php-med-trans-light.gif'; $section->addText("Remote image from: {$source}"); -$section->addMemoryImage($source); -// End code +$section->addImage($source); -// Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +//Wrapping style +$text = str_repeat('Hello World! ', 15); +$wrappingStyles = array('inline', 'behind', 'infront', 'square', 'tight'); +foreach ($wrappingStyles as $wrappingStyle) { + $section->addTextBreak(5); + $section->addText('Wrapping style ' . $wrappingStyle); + $section->addImage('resources/_earth.jpg', array('marginTop' => -1, 'marginLeft' => 1, + 'width' => 80, 'height' => 80, 'wrappingStyle' => $wrappingStyle)); + $section->addText($text); } -include_once 'Sample_Footer.php'; +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index 45cb73ab..cd22df8e 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -2,56 +2,60 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); -// Add listitem elements -$section->addListItem('List Item 1', 0); -$section->addListItem('List Item 2', 0); -$section->addListItem('List Item 3', 0); -$section->addTextBreak(2); +// Style definition -// Add listitem elements -$section->addListItem('List Item 1', 0); -$section->addListItem('List Item 1.1', 1); -$section->addListItem('List Item 1.2', 1); -$section->addListItem('List Item 1.3 (styled)', 1, array('bold'=>true)); -$section->addListItem('List Item 1.3.1', 2); -$section->addListItem('List Item 1.3.2', 2); -$section->addTextBreak(2); - -// Add listitem elements -$listStyle = array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER); -$section->addListItem('List Item 1', 0, null, $listStyle); -$section->addListItem('List Item 2', 0, null, $listStyle); -$section->addListItem('List Item 3', 0, null, $listStyle); -$section->addTextBreak(2); - -// Add listitem elements $phpWord->addFontStyle('myOwnStyle', array('color'=>'FF0000')); $phpWord->addParagraphStyle('P-Style', array('spaceAfter'=>95)); -$listStyle = array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED); -$section->addListItem('List Item 1', 0, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 2', 0, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 3', 1, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 4', 1, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 5', 2, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 6', 1, 'myOwnStyle', $listStyle, 'P-Style'); -$section->addListItem('List Item 7', 0, 'myOwnStyle', $listStyle, 'P-Style'); +$phpWord->addNumberingStyle( + 'multilevel', + array('type' => 'multilevel', 'levels' => array( + array('format' => 'decimal', 'text' => '%1.', 'left' => 360, 'hanging' => 360, 'tabPos' => 360), + array('format' => 'upperLetter', 'text' => '%2.', 'left' => 720, 'hanging' => 360, 'tabPos' => 720), + ) + ) +); +$predefinedMultilevel = array('listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED); -// End code +// Lists + +$section->addText('Multilevel list.'); +$section->addListItem('List Item I', 0, null, 'multilevel'); +$section->addListItem('List Item I.a', 1, null, 'multilevel'); +$section->addListItem('List Item I.b', 1, null, 'multilevel'); +$section->addListItem('List Item II', 0, null, 'multilevel'); +$section->addListItem('List Item II.a', 1, null, 'multilevel'); +$section->addListItem('List Item III', 0, null, 'multilevel'); +$section->addTextBreak(2); + +$section->addText('Basic simple bulleted list.'); +$section->addListItem('List Item 1'); +$section->addListItem('List Item 2'); +$section->addListItem('List Item 3'); +$section->addTextBreak(2); + +$section->addText('Continue from multilevel list above.'); +$section->addListItem('List Item IV', 0, null, 'multilevel'); +$section->addListItem('List Item IV.a', 1, null, 'multilevel'); +$section->addTextBreak(2); + +$section->addText('Multilevel predefined list.'); +$section->addListItem('List Item 1', 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 2', 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 3', 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 4', 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 5', 2, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 6', 1, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addListItem('List Item 7', 0, 'myOwnStyle', $predefinedMultilevel, 'P-Style'); +$section->addTextBreak(2); // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_15_Link.php b/samples/Sample_15_Link.php index 06628de5..1bd61e79 100644 --- a/samples/Sample_15_Link.php +++ b/samples/Sample_15_Link.php @@ -2,11 +2,11 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Add hyperlink elements $section->addLink('http://www.google.com', 'Best search engine', array('color'=>'0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE)); @@ -16,16 +16,8 @@ $phpWord->addLinkStyle('myOwnLinkStyle', array('bold'=>true, 'color'=>'808000')) $section->addLink('http://www.bing.com', null, 'myOwnLinkStyle'); $section->addLink('http://www.yahoo.com', null, 'myOwnLinkStyle'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_16_Object.php b/samples/Sample_16_Object.php index 1a7f557a..af23a00f 100644 --- a/samples/Sample_16_Object.php +++ b/samples/Sample_16_Object.php @@ -2,25 +2,17 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText('You can open this OLE object by double clicking on the icon:'); $section->addTextBreak(2); $section->addObject('resources/_sheet.xls'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index 27982921..b18b1bc9 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -2,25 +2,41 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); // Define the TOC font style -$fontStyle = array('spaceAfter'=>60, 'size'=>12); +$fontStyle = array('spaceAfter' => 60, 'size' => 12); +$fontStyle2 = array('size' => 10); // Add title styles -$phpWord->addTitleStyle(1, array('size'=>20, 'color'=>'333333', 'bold'=>true)); -$phpWord->addTitleStyle(2, array('size'=>16, 'color'=>'666666')); +$phpWord->addTitleStyle(1, array('size' => 20, 'color' => '333333', 'bold' => true)); +$phpWord->addTitleStyle(2, array('size' => 16, 'color' => '666666')); +$phpWord->addTitleStyle(3, array('size' => 14, 'italic' => true)); +$phpWord->addTitleStyle(4, array('size' => 12)); // Add text elements -$section->addText('Table of contents:'); +$section->addText('Table of contents 1'); $section->addTextBreak(2); -// Add TOC -$section->addTOC($fontStyle); +// Add TOC #1 +$toc = $section->addTOC($fontStyle); +$section->addTextBreak(2); + +// Filler +$section->addText('Text between TOC'); +$section->addTextBreak(2); + +// Add TOC #1 +$section->addText('Table of contents 2'); +$section->addTextBreak(2); +$toc2 = $section->addTOC($fontStyle2); +$toc2->setMinDepth(2); +$toc2->setMaxDepth(3); + // Add Titles $section->addPageBreak(); @@ -41,18 +57,19 @@ $section->addText('And more text...'); $section->addTextBreak(2); $section->addTitle('I am a Subtitle of Title 3', 2); $section->addText('Again and again, more text...'); +$section->addTitle('Subtitle 3.1.1', 3); +$section->addText('Text'); +$section->addTitle('Subtitle 3.1.1.1', 4); +$section->addText('Text'); +$section->addTitle('Subtitle 3.1.1.2', 4); +$section->addText('Text'); +$section->addTitle('Subtitle 3.1.2', 3); +$section->addText('Text'); -echo date('H:i:s'), " Note: Please refresh TOC manually.", \EOL; -// End code +echo date('H:i:s'), " Note: Please refresh TOC manually.", EOL; // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_18_Watermark.php b/samples/Sample_18_Watermark.php index ff299c97..313cfbed 100644 --- a/samples/Sample_18_Watermark.php +++ b/samples/Sample_18_Watermark.php @@ -2,26 +2,18 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code -$section = $phpWord->createSection(); -$header = $section->createHeader(); +$section = $phpWord->addSection(); +$header = $section->addHeader(); $header->addWatermark('resources/_earth.jpg', array('marginTop' => 200, 'marginLeft' => 55)); $section->addText('The header reference to the current section includes a watermark image.'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_19_TextBreak.php b/samples/Sample_19_TextBreak.php index 9433222c..a209ce39 100644 --- a/samples/Sample_19_TextBreak.php +++ b/samples/Sample_19_TextBreak.php @@ -2,7 +2,7 @@ include_once 'Sample_Header.php'; // New Word document -echo date('H:i:s'), " Create new PhpWord object", \EOL; +echo date('H:i:s'), " Create new PhpWord object", EOL; $phpWord = new \PhpOffice\PhpWord\PhpWord(); // Begin code @@ -12,7 +12,7 @@ $phpWord->addFontStyle('fontStyle', array('size' => 9)); $phpWord->addParagraphStyle('paragraphStyle', array('spacing' => 480)); $fontStyle = array('size' => 24); -$section = $phpWord->createSection(); +$section = $phpWord->addSection(); $section->addText('Text break with no style:'); $section->addTextBreak(); $section->addText('Text break with defined font style:'); @@ -25,16 +25,8 @@ $section->addText('Text break with inline paragraph style:'); $section->addTextBreak(1, null, $paragraphStyle); $section->addText('Done.'); -// End code - // Save file -$name = basename(__FILE__, '.php'); -$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf'); -foreach ($writers as $writer => $extension) { - echo date('H:i:s'), " Write to {$writer} format", \EOL; - $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); - $xmlWriter->save("{$name}.{$extension}"); - rename("{$name}.{$extension}", "results/{$name}.{$extension}"); +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; } - -include_once 'Sample_Footer.php'; diff --git a/samples/Sample_20_BGColor.php b/samples/Sample_20_BGColor.php new file mode 100644 index 00000000..892cd8b2 --- /dev/null +++ b/samples/Sample_20_BGColor.php @@ -0,0 +1,17 @@ +addSection(); + +$section->addText("This is some text highlighted using fgColor (limited to 15 colors) ", array("fgColor" => \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW)); +$section->addText("This one uses bgColor and is using hex value (0xfbbb10)", array("bgColor" => "fbbb10")); +$section->addText("Compatible with font colors", array("color"=>"0000ff", "bgColor" => "fbbb10")); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php new file mode 100644 index 00000000..b600ec00 --- /dev/null +++ b/samples/Sample_21_TableRowRules.php @@ -0,0 +1,34 @@ +addSection(); + +$section->addText("By default, when you insert an image, it adds a textbreak after its content."); +$section->addText("If we want a simple border around an image, we wrap the image inside a table->row->cell"); +$section->addText("On the image with the red border, even if we set the row height to the height of the image, the textbreak is still there:"); + +$table1 = $section->addTable(array("cellMargin" => 0, "cellMarginRight" => 0, "cellMarginBottom" => 0, "cellMarginLeft" => 0)); +$table1->addRow(3750); +$cell1 = $table1->addCell(null, array("valign" => "top", "borderSize" => 30, "borderColor" => "ff0000")); +$cell1->addImage("./resources/_earth.jpg", array("width" => 250, "height" => 250, "align" => "center")); + +$section->addTextBreak(); +$section->addText("But if we set the rowStyle 'exactHeight' to true, the real row height is used, removing the textbreak:"); + +$table2 = $section->addTable(array("cellMargin" => 0, "cellMarginRight" => 0, "cellMarginBottom" => 0, "cellMarginLeft" => 0)); +$table2->addRow(3750, array("exactHeight" => true)); +$cell2 = $table2->addCell(null, array("valign" => "top", "borderSize" => 30, "borderColor" => "00ff00")); +$cell2->addImage("./resources/_earth.jpg", array("width" => 250, "height" => 250, "align" => "center")); + +$section->addTextBreak(); +$section->addText("In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips."); +$section->addText("So: $"."table2->addRow(3750, array('exactHeight'=>true));"); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_22_CheckBox.php b/samples/Sample_22_CheckBox.php new file mode 100644 index 00000000..e7aae5ba --- /dev/null +++ b/samples/Sample_22_CheckBox.php @@ -0,0 +1,21 @@ +addSection(); +$section->addText('Check box in section'); +$section->addCheckBox('chkBox1', 'Checkbox 1'); +$section->addText('Check box in table cell'); +$table = $section->addTable(); +$table->addRow(); +$cell = $table->addCell(); +$cell->addCheckBox('chkBox2', 'Checkbox 2'); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_23_TemplateBlock.php b/samples/Sample_23_TemplateBlock.php new file mode 100644 index 00000000..8ee8fc6d --- /dev/null +++ b/samples/Sample_23_TemplateBlock.php @@ -0,0 +1,24 @@ +loadTemplate('resources/Sample_23_TemplateBlock.docx'); + +// Will clone everything between ${tag} and ${/tag}, the number of times. By default, 1. +$document->cloneBlock('CLONEME', 3); + +// Everything between ${tag} and ${/tag}, will be deleted/erased. +$document->deleteBlock('DELETEME'); + +$name = 'Sample_23_TemplateBlock.docx'; +echo date('H:i:s'), " Write to Word2007 format", EOL; +$document->saveAs($name); +rename($name, "results/{$name}"); + +echo getEndingNotes(array('Word2007' => 'docx')); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_24_ReadODText.php b/samples/Sample_24_ReadODText.php new file mode 100644 index 00000000..bb5332e6 --- /dev/null +++ b/samples/Sample_24_ReadODText.php @@ -0,0 +1,14 @@ + 

'; - echo '

Results: '; - foreach ($types as $type) { - $result = "results/{$sampleFile}.{$type}"; - if (file_exists($result)) { - echo "{$type} "; - } - } - echo '

'; - } ?> -'); +define('SCRIPT_FILENAME', basename($_SERVER['SCRIPT_FILENAME'], '.php')); +define('IS_INDEX', SCRIPT_FILENAME == 'index'); require_once '../src/PhpWord/Autoloader.php'; -PhpOffice\PhpWord\Autoloader::register(); +\PhpOffice\PhpWord\Autoloader::register(); + +// Set writers +$writers = array('Word2007' => 'docx', 'ODText' => 'odt', 'RTF' => 'rtf', 'HTML' => 'html', 'PDF' => 'pdf'); + +// Set PDF renderer +$rendererName = \PhpOffice\PhpWord\Settings::PDF_RENDERER_DOMPDF; +$rendererLibraryPath = ''; // DomPDF library path + +if (!\PhpOffice\PhpWord\Settings::setPdfRenderer($rendererName, $rendererLibraryPath)) { + $writers['PDF'] = null; +} // Return to the caller script when runs by CLI if (CLI) { @@ -15,12 +28,11 @@ if (CLI) { } // Set titles and names -$sampleFile = basename($_SERVER['SCRIPT_FILENAME'], '.php'); -$isIndexFile = ($sampleFile == 'index'); -$pageHeading = str_replace('_', ' ', $sampleFile); -$pageTitle = $isIndexFile ? 'Welcome to ' : "{$pageHeading} - "; +$pageHeading = str_replace('_', ' ', SCRIPT_FILENAME); +$pageTitle = IS_INDEX ? 'Welcome to ' : "{$pageHeading} - "; $pageTitle .= 'PHPWord'; -$pageHeading = $isIndexFile ? '' : "

{$pageHeading}

"; +$pageHeading = IS_INDEX ? '' : "

{$pageHeading}

"; + // Populate samples $files = ''; if ($handle = opendir('.')) { @@ -32,12 +44,80 @@ if ($handle = opendir('.')) { } closedir($handle); } + +/** + * Write documents + * + * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param string $filename + * @param array $writers + */ +function write($phpWord, $filename, $writers) +{ + $result = ''; + + // Write documents + foreach ($writers as $writer => $extension) { + $result .= date('H:i:s') . " Write to {$writer} format"; + if (!is_null($extension)) { + $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, $writer); + $xmlWriter->save("{$filename}.{$extension}"); + rename("{$filename}.{$extension}", "results/{$filename}.{$extension}"); + } else { + $result .= ' ... NOT DONE!'; + } + $result .= EOL; + } + + $result .= getEndingNotes($writers); + + return $result; +} + +/** + * Get ending notes + * + * @param array $writers + */ +function getEndingNotes($writers) +{ + $result = ''; + + // Do not show execution time for index + if (!IS_INDEX) { + $result .= date('H:i:s') . " Done writing file(s)" . EOL; + $result .= date('H:i:s') . " Peak memory usage: " . (memory_get_peak_usage(true) / 1024 / 1024) . " MB" . EOL; + } + + // Return + if (CLI) { + $result .= 'The results are stored in the "results" subdirectory.' . EOL; + } else { + if (!IS_INDEX) { + $types = array_values($writers); + $result .= '

 

'; + $result .= '

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

'; + } + } + + return $result; +} ?> <?php echo $pageTitle; ?> + @@ -56,14 +136,14 @@ if ($handle = opendir('.')) { diff --git a/samples/bootstrap/css/font-awesome.min.css b/samples/bootstrap/css/font-awesome.min.css new file mode 100644 index 00000000..449d6ac5 --- /dev/null +++ b/samples/bootstrap/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.0.3');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857142858em;text-align:center}.fa-ul{padding-left:0;margin-left:2.142857142857143em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;top:.14285714285714285em;text-align:center}.fa-li.fa-lg{left:-1.8571428571428572em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0,mirror=1);-webkit-transform:scale(-1,1);-moz-transform:scale(-1,1);-ms-transform:scale(-1,1);-o-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2,mirror=1);-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-asc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-desc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-reply-all:before{content:"\f122"}.fa-mail-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"} \ No newline at end of file diff --git a/samples/bootstrap/css/phpword.css b/samples/bootstrap/css/phpword.css index d7470598..fc410ec2 100644 --- a/samples/bootstrap/css/phpword.css +++ b/samples/bootstrap/css/phpword.css @@ -1,6 +1,7 @@ body { padding-top: 20px; padding-bottom: 20px; + min-height: 1000px; } .navbar { margin-bottom: 20px; diff --git a/samples/bootstrap/fonts/FontAwesome.otf b/samples/bootstrap/fonts/FontAwesome.otf new file mode 100644 index 00000000..8b0f54e4 Binary files /dev/null and b/samples/bootstrap/fonts/FontAwesome.otf differ diff --git a/samples/bootstrap/fonts/fontawesome-webfont.eot b/samples/bootstrap/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..7c79c6a6 Binary files /dev/null and b/samples/bootstrap/fonts/fontawesome-webfont.eot differ diff --git a/samples/bootstrap/fonts/fontawesome-webfont.svg b/samples/bootstrap/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..45fdf338 --- /dev/null +++ b/samples/bootstrap/fonts/fontawesome-webfont.svg @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/bootstrap/fonts/fontawesome-webfont.ttf b/samples/bootstrap/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..e89738de Binary files /dev/null and b/samples/bootstrap/fonts/fontawesome-webfont.ttf differ diff --git a/samples/bootstrap/fonts/fontawesome-webfont.woff b/samples/bootstrap/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..8c1748aa Binary files /dev/null and b/samples/bootstrap/fonts/fontawesome-webfont.woff differ diff --git a/samples/index.php b/samples/index.php index f4446ad4..71e8518a 100644 --- a/samples/index.php +++ b/samples/index.php @@ -3,11 +3,11 @@ include_once 'Sample_Header.php'; if (!CLI) { ?>
-

Welcome to PHPWord, a library written in pure PHP that provides a set of classes to write to and read from different document file formats, i.e. Word (.docx), WordPad (.rtf), and Libre/OpenOffice Writer (.odt).

-

Please use the menu above to browse PHPWord samples.

+

Welcome to PHPWord, a library written in pure PHP that provides a set of classes to write to and read from different document file formats, i.e. Office Open XML (.docx), Open Document Format (.odt), and Rich Text Format (.rtf).

+

 

- Fork us on Github! - Read the Docs + Fork us on Github! + Read the Docs

$value) { echo "
  • {$value[0]} ... {$status}
  • "; } echo ""; -} // if (!CLI) -include_once 'Sample_Footer.php'; +} +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/resources/Sample_07_TemplateCloneRow.docx b/samples/resources/Sample_07_TemplateCloneRow.docx old mode 100755 new mode 100644 index 25a8c418..9ac6c2a1 Binary files a/samples/resources/Sample_07_TemplateCloneRow.docx and b/samples/resources/Sample_07_TemplateCloneRow.docx differ diff --git a/samples/resources/Sample_11_ReadWord2007.docx b/samples/resources/Sample_11_ReadWord2007.docx index fe8ec7ac..2143c628 100644 Binary files a/samples/resources/Sample_11_ReadWord2007.docx and b/samples/resources/Sample_11_ReadWord2007.docx differ diff --git a/samples/resources/Sample_23_TemplateBlock.docx b/samples/resources/Sample_23_TemplateBlock.docx new file mode 100644 index 00000000..049d5ca4 Binary files /dev/null and b/samples/resources/Sample_23_TemplateBlock.docx differ diff --git a/samples/resources/Sample_24_ReadODText.odt b/samples/resources/Sample_24_ReadODText.odt new file mode 100644 index 00000000..9e18e619 Binary files /dev/null and b/samples/resources/Sample_24_ReadODText.odt differ diff --git a/samples/results/.gitignore b/samples/results/.gitignore new file mode 100644 index 00000000..c96a04f0 --- /dev/null +++ b/samples/results/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/samples/results/.gitkeep b/samples/results/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/PhpWord/Autoloader.php b/src/PhpWord/Autoloader.php index d1d96a75..5bb331ab 100644 --- a/src/PhpWord/Autoloader.php +++ b/src/PhpWord/Autoloader.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; diff --git a/src/PhpWord/DocumentProperties.php b/src/PhpWord/DocumentProperties.php index 8ea683ea..137162e7 100644 --- a/src/PhpWord/DocumentProperties.php +++ b/src/PhpWord/DocumentProperties.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; @@ -43,101 +27,101 @@ class DocumentProperties * * @var string */ - private $_creator; + private $creator; /** * LastModifiedBy * * @var string */ - private $_lastModifiedBy; + private $lastModifiedBy; /** * Created * - * @var datetime + * @var int */ - private $_created; + private $created; /** * Modified * - * @var datetime + * @var int */ - private $_modified; + private $modified; /** * Title * * @var string */ - private $_title; + private $title; /** * Description * * @var string */ - private $_description; + private $description; /** * Subject * * @var string */ - private $_subject; + private $subject; /** * Keywords * * @var string */ - private $_keywords; + private $keywords; /** * Category * * @var string */ - private $_category; + private $category; /** * Company * * @var string */ - private $_company; + private $company; /** * Manager * * @var string */ - private $_manager; + private $manager; /** * Custom Properties * - * @var string + * @var array */ - private $_customProperties = array(); + private $customProperties = array(); /** * Create new DocumentProperties */ public function __construct() { - $this->_creator = ''; - $this->_lastModifiedBy = $this->_creator; - $this->_created = time(); - $this->_modified = time(); - $this->_title = ''; - $this->_subject = ''; - $this->_description = ''; - $this->_keywords = ''; - $this->_category = ''; - $this->_company = ''; - $this->_manager = ''; + $this->creator = ''; + $this->lastModifiedBy = $this->creator; + $this->created = time(); + $this->modified = time(); + $this->title = ''; + $this->subject = ''; + $this->description = ''; + $this->keywords = ''; + $this->category = ''; + $this->company = ''; + $this->manager = ''; } /** @@ -147,18 +131,19 @@ class DocumentProperties */ public function getCreator() { - return $this->_creator; + return $this->creator; } /** * Set Creator * - * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @param string $value + * @return self */ - public function setCreator($pValue = '') + public function setCreator($value = '') { - $this->_creator = $pValue; + $this->creator = $this->setValue($value, ''); + return $this; } @@ -169,68 +154,65 @@ class DocumentProperties */ public function getLastModifiedBy() { - return $this->_lastModifiedBy; + return $this->lastModifiedBy; } /** * Set Last Modified By * - * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @param string $value + * @return self */ - public function setLastModifiedBy($pValue = '') + public function setLastModifiedBy($value = '') { - $this->_lastModifiedBy = $pValue; + $this->lastModifiedBy = $this->setValue($value, $this->creator); + return $this; } /** * Get Created * - * @return datetime + * @return int */ public function getCreated() { - return $this->_created; + return $this->created; } /** * Set Created * - * @param datetime $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @param int $value + * @return self */ - public function setCreated($pValue = null) + public function setCreated($value = null) { - if (is_null($pValue)) { - $pValue = time(); - } - $this->_created = $pValue; + $this->created = $this->setValue($value, time()); + return $this; } /** * Get Modified * - * @return datetime + * @return int */ public function getModified() { - return $this->_modified; + return $this->modified; } /** * Set Modified * - * @param datetime $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @param int $value + * @return self */ - public function setModified($pValue = null) + public function setModified($value = null) { - if (is_null($pValue)) { - $pValue = time(); - } - $this->_modified = $pValue; + $this->modified = $this->setValue($value, time()); + return $this; } @@ -241,18 +223,19 @@ class DocumentProperties */ public function getTitle() { - return $this->_title; + return $this->title; } /** * Set Title * - * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @param string $value + * @return self */ - public function setTitle($pValue = '') + public function setTitle($value = '') { - $this->_title = $pValue; + $this->title = $this->setValue($value, ''); + return $this; } @@ -263,18 +246,19 @@ class DocumentProperties */ public function getDescription() { - return $this->_description; + return $this->description; } /** * Set Description * - * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @param string $value + * @return self */ - public function setDescription($pValue = '') + public function setDescription($value = '') { - $this->_description = $pValue; + $this->description = $this->setValue($value, ''); + return $this; } @@ -285,18 +269,19 @@ class DocumentProperties */ public function getSubject() { - return $this->_subject; + return $this->subject; } /** * Set Subject * - * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @param string $value + * @return self */ - public function setSubject($pValue = '') + public function setSubject($value = '') { - $this->_subject = $pValue; + $this->subject = $this->setValue($value, ''); + return $this; } @@ -307,18 +292,19 @@ class DocumentProperties */ public function getKeywords() { - return $this->_keywords; + return $this->keywords; } /** * Set Keywords * - * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @param string $value + * @return self */ - public function setKeywords($pValue = '') + public function setKeywords($value = '') { - $this->_keywords = $pValue; + $this->keywords = $this->setValue($value, ''); + return $this; } @@ -329,18 +315,19 @@ class DocumentProperties */ public function getCategory() { - return $this->_category; + return $this->category; } /** * Set Category * - * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @param string $value + * @return self */ - public function setCategory($pValue = '') + public function setCategory($value = '') { - $this->_category = $pValue; + $this->category = $this->setValue($value, ''); + return $this; } @@ -351,18 +338,19 @@ class DocumentProperties */ public function getCompany() { - return $this->_company; + return $this->company; } /** * Set Company * - * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @param string $value + * @return self */ - public function setCompany($pValue = '') + public function setCompany($value = '') { - $this->_company = $pValue; + $this->company = $this->setValue($value, ''); + return $this; } @@ -373,18 +361,19 @@ class DocumentProperties */ public function getManager() { - return $this->_manager; + return $this->manager; } /** * Set Manager * - * @param string $pValue - * @return \PhpOffice\PhpWord\DocumentProperties + * @param string $value + * @return self */ - public function setManager($pValue = '') + public function setManager($value = '') { - $this->_manager = $pValue; + $this->manager = $this->setValue($value, ''); + return $this; } @@ -395,7 +384,7 @@ class DocumentProperties */ public function getCustomProperties() { - return array_keys($this->_customProperties); + return array_keys($this->customProperties); } /** @@ -406,7 +395,7 @@ class DocumentProperties */ public function isCustomPropertySet($propertyName) { - return isset($this->_customProperties[$propertyName]); + return isset($this->customProperties[$propertyName]); } /** @@ -417,8 +406,8 @@ class DocumentProperties */ public function getCustomPropertyValue($propertyName) { - if (isset($this->_customProperties[$propertyName])) { - return $this->_customProperties[$propertyName]['value']; + if ($this->isCustomPropertySet($propertyName)) { + return $this->customProperties[$propertyName]['value']; } } @@ -431,8 +420,8 @@ class DocumentProperties */ public function getCustomPropertyType($propertyName) { - if (isset($this->_customProperties[$propertyName])) { - return $this->_customProperties[$propertyName]['type']; + if ($this->isCustomPropertySet($propertyName)) { + return $this->customProperties[$propertyName]['type']; } } @@ -448,17 +437,18 @@ class DocumentProperties * 's': String * 'd': Date/Time * 'b': Boolean - * @return \PhpOffice\PhpWord\DocumentProperties + * @return self */ public function setCustomProperty($propertyName, $propertyValue = '', $propertyType = null) { - if (($propertyType === null) || (!in_array($propertyType, array( + $propertyTypes = array( self::PROPERTY_TYPE_INTEGER, self::PROPERTY_TYPE_FLOAT, self::PROPERTY_TYPE_STRING, self::PROPERTY_TYPE_DATE, self::PROPERTY_TYPE_BOOLEAN - )))) { + ); + if (($propertyType === null) || (!in_array($propertyType, $propertyTypes))) { if ($propertyValue === null) { $propertyType = self::PROPERTY_TYPE_STRING; } elseif (is_float($propertyValue)) { @@ -472,7 +462,7 @@ class DocumentProperties } } - $this->_customProperties[$propertyName] = array( + $this->customProperties[$propertyName] = array( 'value' => $propertyValue, 'type' => $propertyType ); @@ -480,52 +470,43 @@ class DocumentProperties } /** - * Convert document propery based on type + * Convert document property based on type * - * @param mixed $propertyValue - * @param string $propertyType - * @return mixed + * @param string $propertyValue + * @param string $propertyType + * @return mixed */ public static function convertProperty($propertyValue, $propertyType) { switch ($propertyType) { case 'empty': // Empty return ''; - break; case 'null': // Null return null; - break; case 'i1': // 1-Byte Signed Integer case 'i2': // 2-Byte Signed Integer case 'i4': // 4-Byte Signed Integer case 'i8': // 8-Byte Signed Integer case 'int': // Integer return (int) $propertyValue; - break; case 'ui1': // 1-Byte Unsigned Integer case 'ui2': // 2-Byte Unsigned Integer case 'ui4': // 4-Byte Unsigned Integer case 'ui8': // 8-Byte Unsigned Integer case 'uint': // Unsigned Integer return abs((int) $propertyValue); - break; case 'r4': // 4-Byte Real Number case 'r8': // 8-Byte Real Number case 'decimal': // Decimal return (float) $propertyValue; - break; - case 'lpstr': // LPSTR - case 'lpwstr': // LPWSTR - case 'bstr': // Basic String - return $propertyValue; - break; case 'date': // Date and Time case 'filetime': // File Time return strtotime($propertyValue); - break; case 'bool': // Boolean return ($propertyValue == 'true') ? true : false; - break; + case 'lpstr': // LPSTR + case 'lpwstr': // LPWSTR + case 'bstr': // Basic String case 'cy': // Currency case 'error': // Error Status Code case 'vector': // Vector @@ -540,7 +521,6 @@ class DocumentProperties case 'clsid': // Class ID case 'cf': // Clipboard Data return $propertyValue; - break; } return $propertyValue; @@ -549,59 +529,40 @@ class DocumentProperties /** * Convert document property type * - * @param string $propertyType - * @return mixed + * @param string $propertyType + * @return string */ public static function convertPropertyType($propertyType) { - switch ($propertyType) { - case 'i1': // 1-Byte Signed Integer - case 'i2': // 2-Byte Signed Integer - case 'i4': // 4-Byte Signed Integer - case 'i8': // 8-Byte Signed Integer - case 'int': // Integer - case 'ui1': // 1-Byte Unsigned Integer - case 'ui2': // 2-Byte Unsigned Integer - case 'ui4': // 4-Byte Unsigned Integer - case 'ui8': // 8-Byte Unsigned Integer - case 'uint': // Unsigned Integer - return self::PROPERTY_TYPE_INTEGER; - break; - case 'r4': // 4-Byte Real Number - case 'r8': // 8-Byte Real Number - case 'decimal': // Decimal - return self::PROPERTY_TYPE_FLOAT; - break; - case 'empty': // Empty - case 'null': // Null - case 'lpstr': // LPSTR - case 'lpwstr': // LPWSTR - case 'bstr': // Basic String - return self::PROPERTY_TYPE_STRING; - break; - case 'date': // Date and Time - case 'filetime': // File Time - return self::PROPERTY_TYPE_DATE; - break; - case 'bool': // Boolean - return self::PROPERTY_TYPE_BOOLEAN; - break; - case 'cy': // Currency - case 'error': // Error Status Code - case 'vector': // Vector - case 'array': // Array - case 'blob': // Binary Blob - case 'oblob': // Binary Blob Object - case 'stream': // Binary Stream - case 'ostream': // Binary Stream Object - case 'storage': // Binary Storage - case 'ostorage': // Binary Storage Object - case 'vstream': // Binary Versioned Stream - case 'clsid': // Class ID - case 'cf': // Clipboard Data - return self::PROPERTY_TYPE_UNKNOWN; - break; + $typeGroups = array( + self::PROPERTY_TYPE_INTEGER => array('i1', 'i2', 'i4', 'i8', 'int', 'ui1', 'ui2', 'ui4', 'ui8', 'uint'), + self::PROPERTY_TYPE_FLOAT => array('r4', 'r8', 'decimal'), + self::PROPERTY_TYPE_STRING => array('empty', 'null', 'lpstr', 'lpwstr', 'bstr'), + self::PROPERTY_TYPE_DATE => array('date', 'filetime'), + self::PROPERTY_TYPE_BOOLEAN => array('bool'), + ); + foreach ($typeGroups as $groupId => $groupMembers) { + if (in_array($propertyType, $groupMembers)) { + return $groupId; + } } + return self::PROPERTY_TYPE_UNKNOWN; } + + /** + * Set default for null and empty value + * + * @param mixed $value + * @param mixed $default + * @return mixed + */ + private function setValue($value, $default) + { + if (is_null($value) || $value == '') { + $value = $default; + } + + return $value; + } } diff --git a/src/PhpWord/Element/AbstractContainer.php b/src/PhpWord/Element/AbstractContainer.php new file mode 100644 index 00000000..8af70d42 --- /dev/null +++ b/src/PhpWord/Element/AbstractContainer.php @@ -0,0 +1,456 @@ +setElementIndex($this->countElements() + 1); + $element->setElementId(); + $this->elements[] = $element; + } + + /** + * Get all elements + * + * @return array + */ + public function getElements() + { + return $this->elements; + } + + /** + * Count elements + * + * @return integer + */ + public function countElements() + { + return count($this->elements); + } + + /** + * Add text element + * + * @param string $text + * @param mixed $fontStyle + * @param mixed $paragraphStyle + * @return Text + */ + public function addText($text, $fontStyle = null, $paragraphStyle = null) + { + $this->checkValidity('text'); + + // Reset paragraph style for footnote and textrun. They have their own + if (in_array($this->container, array('textrun', 'footnote', 'endnote'))) { + $paragraphStyle = null; + } + + $text = String::toUTF8($text); + $textObject = new Text($text, $fontStyle, $paragraphStyle); + $textObject->setDocPart($this->getDocPart(), $this->getDocPartId()); + $this->addElement($textObject); + + return $textObject; + } + + /** + * Add textrun element + * + * @param mixed $paragraphStyle + * @return TextRun + */ + public function addTextRun($paragraphStyle = null) + { + $this->checkValidity('textrun'); + + $textRun = new TextRun($paragraphStyle); + $textRun->setDocPart($this->getDocPart(), $this->getDocPartId()); + $this->addElement($textRun); + + return $textRun; + } + + /** + * Add link element + * + * @param string $linkSrc + * @param string $linkName + * @param mixed $fontStyle + * @param mixed $paragraphStyle + * @return Link + */ + public function addLink($linkSrc, $linkName = null, $fontStyle = null, $paragraphStyle = null) + { + $this->checkValidity('link'); + $elementDocPart = $this->checkElementDocPart(); + + $link = new Link(String::toUTF8($linkSrc), String::toUTF8($linkName), $fontStyle, $paragraphStyle); + $link->setDocPart($this->getDocPart(), $this->getDocPartId()); + $rId = Media::addElement($elementDocPart, 'link', $linkSrc); + $link->setRelationId($rId); + $this->addElement($link); + + return $link; + } + + /** + * Add a Title Element + * + * @param string $text + * @param int $depth + * @return Title + * @todo Enable title element in other containers + */ + public function addTitle($text, $depth = 1) + { + $this->checkValidity('title'); + + $styles = Style::getStyles(); + if (array_key_exists('Heading_' . $depth, $styles)) { + $style = 'Heading' . $depth; + } else { + $style = null; + } + $text = String::toUTF8($text); + $title = new Title($text, $depth, $style); + $title->setDocPart($this->getDocPart(), $this->getDocPartId()); + $data = Titles::addTitle($text, $depth); + $anchor = $data[0]; + $bookmarkId = $data[1]; + $title->setAnchor($anchor); + $title->setBookmarkId($bookmarkId); + $this->addElement($title); + + return $title; + } + + /** + * Add preserve text element + * + * @param string $text + * @param mixed $fontStyle + * @param mixed $paragraphStyle + * @return PreserveText + */ + public function addPreserveText($text, $fontStyle = null, $paragraphStyle = null) + { + $this->checkValidity('preservetext'); + + $preserveText = new PreserveText(String::toUTF8($text), $fontStyle, $paragraphStyle); + $preserveText->setDocPart($this->getDocPart(), $this->getDocPartId()); + $this->addElement($preserveText); + + return $preserveText; + } + + /** + * Add text break element + * + * @param int $count + * @param mixed $fontStyle + * @param mixed $paragraphStyle + */ + public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) + { + $this->checkValidity('textbreak'); + + for ($i = 1; $i <= $count; $i++) { + $textBreak = new TextBreak($fontStyle, $paragraphStyle); + $textBreak->setDocPart($this->getDocPart(), $this->getDocPartId()); + $this->addElement($textBreak); + } + } + + /** + * Add listitem element + * + * @param string $text + * @param int $depth + * @param mixed $fontStyle + * @param mixed $styleList + * @param mixed $paragraphStyle + * @return ListItem + */ + public function addListItem($text, $depth = 0, $fontStyle = null, $styleList = null, $paragraphStyle = null) + { + $this->checkValidity('listitem'); + + $listItem = new ListItem(String::toUTF8($text), $depth, $fontStyle, $styleList, $paragraphStyle); + $listItem->setDocPart($this->getDocPart(), $this->getDocPartId()); + $this->addElement($listItem); + + return $listItem; + } + + /** + * Add table element + * + * @param mixed $style + * @return Table + */ + public function addTable($style = null) + { + $this->checkValidity('table'); + + $table = new Table($this->getDocPart(), $this->getDocPartId(), $style); + $this->addElement($table); + + return $table; + } + + /** + * Add image element + * + * @param string $src + * @param mixed $style Image style + * @param boolean $isWatermark + * @return Image + */ + public function addImage($src, $style = null, $isWatermark = false) + { + $this->checkValidity('image'); + $elementDocPart = $this->checkElementDocPart(); + + $image = new Image($src, $style, $isWatermark); + $image->setDocPart($this->getDocPart(), $this->getDocPartId()); + $rId = Media::addElement($elementDocPart, 'image', $src, $image); + $image->setRelationId($rId); + $this->addElement($image); + + return $image; + } + + /** + * Add OLE-object element + * + * All exceptions should be handled by \PhpOffice\PhpWord\Element\Object + * + * @param string $src + * @param mixed $style + * @return Object + * @throws \PhpOffice\PhpWord\Exception\Exception + * @todo Enable OLE object element in header and footer + */ + public function addObject($src, $style = null) + { + $this->checkValidity('object'); + $elementDocPart = $this->checkElementDocPart(); + + $object = new Object($src, $style); + $object->setDocPart($this->getDocPart(), $this->getDocPartId()); + if (!is_null($object->getSource())) { + $inf = pathinfo($src); + $ext = $inf['extension']; + if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') { + $ext = substr($ext, 0, -1); + } + $icon = realpath(__DIR__ . "/../resources/{$ext}.png"); + $rId = Media::addElement($elementDocPart, 'object', $src); + $object->setRelationId($rId); + $rIdimg = Media::addElement($elementDocPart, 'image', $icon, new Image($icon)); + $object->setImageRelationId($rIdimg); + $this->addElement($object); + + return $object; + } else { + throw new InvalidObjectException(); + } + } + + /** + * Add footnote element + * + * @param mixed $paragraphStyle + * @return Footnote + */ + public function addFootnote($paragraphStyle = null) + { + $this->checkValidity('footnote'); + + $footnote = new Footnote($paragraphStyle); + $rId = Footnotes::addElement($footnote); + + $footnote->setDocPart('footnote', $this->getDocPartId()); + $footnote->setRelationId($rId); + $this->addElement($footnote); + + return $footnote; + } + + /** + * Add endnote element + * + * @param mixed $paragraphStyle + * @return Endnote + */ + public function addEndnote($paragraphStyle = null) + { + $this->checkValidity('endnote'); + + $endnote = new Endnote($paragraphStyle); + $rId = Endnotes::addElement($endnote); + + $endnote->setDocPart('endnote', $this->getDocPartId()); + $endnote->setRelationId($rId); + $this->addElement($endnote); + + return $endnote; + } + + /** + * Add a CheckBox Element + * + * @param string $name + * @param string $text + * @param mixed $fontStyle + * @param mixed $paragraphStyle + * @return CheckBox + */ + public function addCheckBox($name, $text, $fontStyle = null, $paragraphStyle = null) + { + $this->checkValidity('checkbox'); + + $checkBox = new CheckBox(String::toUTF8($name), String::toUTF8($text), $fontStyle, $paragraphStyle); + $checkBox->setDocPart($this->getDocPart(), $this->getDocPartId()); + $this->addElement($checkBox); + + return $checkBox; + } + + /** + * Check if a method is allowed for the current container + * + * @param string $method + * @return boolean + */ + private function checkValidity($method) + { + // Valid containers for each element + $allContainers = array('section', 'header', 'footer', 'cell', 'textrun', 'footnote', 'endnote'); + $validContainers = array( + 'text' => $allContainers, + 'link' => $allContainers, + 'textbreak' => $allContainers, + 'image' => $allContainers, + 'object' => $allContainers, + 'textrun' => array('section', 'header', 'footer', 'cell'), + 'listitem' => array('section', 'header', 'footer', 'cell'), + 'checkbox' => array('section', 'header', 'footer', 'cell'), + 'table' => array('section', 'header', 'footer'), + 'footnote' => array('section', 'textrun', 'cell'), + 'endnote' => array('section', 'textrun', 'cell'), + 'preservetext' => array('header', 'footer', 'cell'), + 'title' => array('section'), + ); + // Special condition, e.g. preservetext can only exists in cell when + // the cell is located in header or footer + $validSubcontainers = array( + 'preservetext' => array(array('cell'), array('header', 'footer')), + 'footnote' => array(array('cell', 'textrun'), array('section')), + 'endnote' => array(array('cell', 'textrun'), array('section')), + ); + + // Check if a method is valid for current container + if (array_key_exists($method, $validContainers)) { + if (!in_array($this->container, $validContainers[$method])) { + throw new \BadMethodCallException(); + } + } + // Check if a method is valid for current container, located in other container + if (array_key_exists($method, $validSubcontainers)) { + $rules = $validSubcontainers[$method]; + $containers = $rules[0]; + $allowedDocParts = $rules[1]; + foreach ($containers as $container) { + if ($this->container == $container && !in_array($this->getDocPart(), $allowedDocParts)) { + throw new \BadMethodCallException(); + } + } + } + + return true; + } + + /** + * Return element location in document: section, headerx, or footerx + */ + private function checkElementDocPart() + { + $isCellTextrun = in_array($this->container, array('cell', 'textrun')); + $docPart = $isCellTextrun ? $this->getDocPart() : $this->container; + $docPartId = $isCellTextrun ? $this->getDocPartId() : $this->sectionId; + $inHeaderFooter = ($docPart == 'header' || $docPart == 'footer'); + + return $inHeaderFooter ? $docPart . $docPartId : $docPart; + } + + /** + * Add memory image element + * + * @param string $src + * @param mixed $style + * @deprecated 0.9.0 + * @codeCoverageIgnore + */ + public function addMemoryImage($src, $style = null) + { + return $this->addImage($src, $style); + } + + /** + * Create textrun element + * + * @param mixed $paragraphStyle + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function createTextRun($paragraphStyle = null) + { + return $this->addTextRun($paragraphStyle); + } + + /** + * Create footnote element + * + * @param mixed $paragraphStyle + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function createFootnote($paragraphStyle = null) + { + return $this->addFootnote($paragraphStyle); + } +} diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php new file mode 100644 index 00000000..6e993748 --- /dev/null +++ b/src/PhpWord/Element/AbstractElement.php @@ -0,0 +1,208 @@ +sectionId; + } + + /** + * Set doc part + * + * @param string $docPart + * @param integer $docPartId + */ + public function setDocPart($docPart, $docPartId = 1) + { + $this->docPart = $docPart; + $this->docPartId = $docPartId; + } + + /** + * Get doc part + * + * @return string + */ + public function getDocPart() + { + return $this->docPart; + } + + /** + * Get doc part Id + * + * @return integer + */ + public function getDocPartId() + { + return $this->docPartId; + } + + /** + * Get element index + * + * @return int + */ + public function getElementIndex() + { + return $this->elementIndex; + } + + /** + * Set element index + * + * @param int $value + */ + public function setElementIndex($value) + { + $this->elementIndex = $value; + } + + /** + * Get element unique ID + * + * @return string + */ + public function getElementId() + { + return $this->elementId; + } + + /** + * Set element unique ID from 6 first digit of md5 + */ + public function setElementId() + { + $this->elementId = substr(md5(rand()), 0, 6); + } + + /** + * Get relation Id + * + * @return int + */ + public function getRelationId() + { + return $this->relationId; + } + + /** + * Set relation Id + * + * @param int $rId + */ + public function setRelationId($rId) + { + $this->relationId = $rId; + } + + /** + * Check if element is located in section doc part (as opposed to header/footer) + * + * @return boolean + */ + public function isInSection() + { + return ($this->docPart == 'section'); + } + + /** + * Set style value + * + * @param mixed $styleObject Style object + * @param mixed $styleValue Style value + * @param boolean $returnObject Always return object + */ + protected function setStyle($styleObject, $styleValue = null, $returnObject = false) + { + if (!is_null($styleValue) && is_array($styleValue)) { + foreach ($styleValue as $key => $value) { + $styleObject->setStyleValue($key, $value); + } + $style = $styleObject; + } else { + $style = $returnObject ? $styleObject : $styleValue; + } + + return $style; + } +} diff --git a/src/PhpWord/Element/Cell.php b/src/PhpWord/Element/Cell.php new file mode 100644 index 00000000..e3d3dd06 --- /dev/null +++ b/src/PhpWord/Element/Cell.php @@ -0,0 +1,68 @@ +container = 'cell'; + $this->setDocPart($docPart, $docPartId); + $this->width = $width; + $this->cellStyle = $this->setStyle(new CellStyle(), $style, true); + } + + /** + * Get cell style + * + * @return \PhpOffice\PhpWord\Style\Cell + */ + public function getStyle() + { + return $this->cellStyle; + } + + /** + * Get cell width + * + * @return int + */ + public function getWidth() + { + return $this->width; + } +} diff --git a/src/PhpWord/Element/CheckBox.php b/src/PhpWord/Element/CheckBox.php new file mode 100644 index 00000000..f273c128 --- /dev/null +++ b/src/PhpWord/Element/CheckBox.php @@ -0,0 +1,61 @@ +setName($name); + parent::__construct($text, $fontStyle, $paragraphStyle); + } + + /** + * Set name content + * + * @param string $name + * @return self + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * Get name content + * + * @return string + */ + public function getName() + { + return $this->name; + } +} diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php new file mode 100644 index 00000000..07d21969 --- /dev/null +++ b/src/PhpWord/Element/Endnote.php @@ -0,0 +1,31 @@ +container = 'endnote'; + $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + } +} diff --git a/src/PhpWord/Element/Footer.php b/src/PhpWord/Element/Footer.php new file mode 100644 index 00000000..50ec8236 --- /dev/null +++ b/src/PhpWord/Element/Footer.php @@ -0,0 +1,64 @@ +container = 'footer'; + $this->sectionId = $sectionId; + $this->setType($type); + $this->setDocPart($this->container, ($sectionId - 1) * 3 + $footerId); + } + + /** + * Set type + * + * @param string $value + * @since 0.10.0 + */ + public function setType($value = self::AUTO) + { + $this->type = $value; + } + + /** + * Get type + * + * @return string + * @since 0.10.0 + */ + public function getType() + { + return $this->type; + } +} diff --git a/src/PhpWord/Element/Footnote.php b/src/PhpWord/Element/Footnote.php new file mode 100644 index 00000000..bb8d6170 --- /dev/null +++ b/src/PhpWord/Element/Footnote.php @@ -0,0 +1,70 @@ +container = 'footnote'; + $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + } + + /** + * Get paragraph style + * + * @return string|\PhpOffice\PhpWord\Style\Paragraph + */ + public function getParagraphStyle() + { + return $this->paragraphStyle; + } + + /** + * Get Footnote Reference ID + * + * @return int + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function getReferenceId() + { + return $this->getRelationId(); + } + + /** + * Set Footnote Reference ID + * + * @param int $rId + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function setReferenceId($rId) + { + $this->setRelationId($rId); + } +} diff --git a/src/PhpWord/Element/Header.php b/src/PhpWord/Element/Header.php new file mode 100644 index 00000000..2c963d84 --- /dev/null +++ b/src/PhpWord/Element/Header.php @@ -0,0 +1,116 @@ +container = 'header'; + $this->sectionId = $sectionId; + $this->setType($type); + $this->setDocPart($this->container, ($sectionId - 1) * 3 + $headerId); + } + + /** + * Add a Watermark Element + * + * @param string $src + * @param mixed $style + * @return Image + */ + public function addWatermark($src, $style = null) + { + return $this->addImage($src, $style, true); + } + + /** + * Set header type + * + * @param string $value + * @since 0.10.0 + */ + public function setType($value = self::AUTO) + { + if (!in_array($value, array(self::AUTO, self::FIRST, self::EVEN))) { + $value = self::AUTO; + } + $this->type = $value; + } + + /** + * Get header type + * + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * Reset type to default + * + * @return string + */ + public function resetType() + { + return $this->type = self::AUTO; + } + + /** + * First page only header + * + * @return string + */ + public function firstPage() + { + return $this->type = self::FIRST; + } + + /** + * Even numbered pages only + * + * @return string + */ + public function evenPage() + { + return $this->type = self::EVEN; + } +} diff --git a/src/PhpWord/Element/Image.php b/src/PhpWord/Element/Image.php new file mode 100644 index 00000000..53becbbf --- /dev/null +++ b/src/PhpWord/Element/Image.php @@ -0,0 +1,412 @@ +source = $source; + $this->setIsWatermark($isWatermark); + $this->style = $this->setStyle(new ImageStyle(), $style, true); + + $this->checkImage($source); + } + + /** + * Get Image style + * + * @return ImageStyle + */ + public function getStyle() + { + return $this->style; + } + + /** + * Get image source + * + * @return string + */ + public function getSource() + { + return $this->source; + } + + /** + * Get image source type + * + * @return string + */ + public function getSourceType() + { + return $this->sourceType; + } + + /** + * Get image media ID + * + * @return string + */ + public function getMediaId() + { + return md5($this->source); + } + + /** + * Get is watermark + * + * @return boolean + */ + public function getIsWatermark() + { + return $this->isWatermark; + } + + /** + * Set is watermark + * + * @param boolean $pValue + */ + public function setIsWatermark($pValue) + { + $this->isWatermark = $pValue; + } + + /** + * Get image type + * + * @return string + */ + public function getImageType() + { + return $this->imageType; + } + + /** + * Get image create function + * + * @return string + */ + public function getImageCreateFunction() + { + return $this->imageCreateFunc; + } + + /** + * Get image function + * + * @return string + */ + public function getImageFunction() + { + return $this->imageFunc; + } + + /** + * Get image extension + * + * @return string + */ + public function getImageExtension() + { + return $this->imageExtension; + } + + /** + * Get is memory image + * + * @return boolean + */ + public function getIsMemImage() + { + return $this->isMemImage; + } + + /** + * Get target file name + * + * @return string + */ + public function getTarget() + { + return $this->target; + } + + /** + * Set target file name + * + * @param string $value + */ + public function setTarget($value) + { + $this->target = $value; + } + + /** + * Get media index + * + * @return integer + */ + public function getMediaIndex() + { + return $this->mediaIndex; + } + + /** + * Set media index + * + * @param integer $value + */ + public function setMediaIndex($value) + { + $this->mediaIndex = $value; + } + + /** + * Check memory image, supported type, image functions, and proportional width/height + * + * @param string $source + */ + private function checkImage($source) + { + $this->setSourceType($source); + + // Check image data + if ($this->sourceType == self::SOURCE_ARCHIVE) { + $imageData = $this->getArchiveImageSize($source); + } else { + $imageData = @getimagesize($source); + } + if (!is_array($imageData)) { + throw new InvalidImageException(); + } + list($actualWidth, $actualHeight, $imageType) = $imageData; + + // Check image type support + $supportedTypes = array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG); + if ($this->sourceType != self::SOURCE_GD) { + $supportedTypes = array_merge($supportedTypes, array(IMAGETYPE_BMP, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM)); + } + if (!in_array($imageType, $supportedTypes)) { + throw new UnsupportedImageTypeException(); + } + + // Define image functions + $this->imageType = image_type_to_mime_type($imageType); + $this->setFunctions(); + $this->setProportionalSize($actualWidth, $actualHeight); + } + + /** + * Set source type + * + * @param string $source + */ + private function setSourceType($source) + { + if (stripos(strrev($source), strrev('.php')) === 0) { + $this->isMemImage = true; + $this->sourceType = self::SOURCE_GD; + } elseif (strpos($source, 'zip://') !== false) { + $this->isMemImage = false; + $this->sourceType = self::SOURCE_ARCHIVE; + } else { + $this->isMemImage = (filter_var($source, FILTER_VALIDATE_URL) !== false); + $this->sourceType = $this->isMemImage ? self::SOURCE_GD : self::SOURCE_LOCAL; + } + } + + /** + * Get image size from archive + * + * @param string $source + * @return array|null + */ + private function getArchiveImageSize($source) + { + $imageData = null; + $source = substr($source, 6); + list($zipFilename, $imageFilename) = explode('#', $source); + $tempFilename = tempnam(sys_get_temp_dir(), 'PHPWordImage'); + + $zipClass = Settings::getZipClass(); + $zip = new $zipClass(); + 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; + } + + /** + * Set image functions and extensions + */ + private function setFunctions() + { + switch ($this->imageType) { + case 'image/png': + $this->imageCreateFunc = 'imagecreatefrompng'; + $this->imageFunc = 'imagepng'; + $this->imageExtension = 'png'; + break; + case 'image/gif': + $this->imageCreateFunc = 'imagecreatefromgif'; + $this->imageFunc = 'imagegif'; + $this->imageExtension = 'gif'; + break; + case 'image/jpeg': + case 'image/jpg': + $this->imageCreateFunc = 'imagecreatefromjpeg'; + $this->imageFunc = 'imagejpeg'; + $this->imageExtension = 'jpg'; + break; + case 'image/bmp': + case 'image/x-ms-bmp': + $this->imageType = 'image/bmp'; + $this->imageExtension = 'bmp'; + break; + case 'image/tiff': + $this->imageExtension = 'tif'; + break; + } + } + + /** + * Set proportional width/height if one dimension not available + * + * @param integer $actualWidth + * @param integer $actualHeight + */ + private function setProportionalSize($actualWidth, $actualHeight) + { + $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)); + } + } + } +} diff --git a/src/PhpWord/Element/Link.php b/src/PhpWord/Element/Link.php new file mode 100644 index 00000000..31b06c68 --- /dev/null +++ b/src/PhpWord/Element/Link.php @@ -0,0 +1,130 @@ +target = $target; + $this->text = is_null($text) ? $target : $text; + $this->fontStyle = $this->setStyle(new Font('text'), $fontStyle); + $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + + return $this; + } + + /** + * Get link target + * + * @return string + */ + public function getTarget() + { + return $this->target; + } + + /** + * Get link text + * + * @return string + */ + public function getText() + { + return $this->text; + } + + /** + * Get Text style + * + * @return string|\PhpOffice\PhpWord\Style\Font + */ + public function getFontStyle() + { + return $this->fontStyle; + } + + /** + * Get Paragraph style + * + * @return string|\PhpOffice\PhpWord\Style\Paragraph + */ + public function getParagraphStyle() + { + return $this->paragraphStyle; + } + + /** + * Get Link source + * + * @return string + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function getLinkSrc() + { + return $this->getTarget(); + } + + /** + * Get Link name + * + * @return string + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function getLinkName() + { + return $this->getText(); + } +} diff --git a/src/PhpWord/Element/ListItem.php b/src/PhpWord/Element/ListItem.php new file mode 100644 index 00000000..66061537 --- /dev/null +++ b/src/PhpWord/Element/ListItem.php @@ -0,0 +1,86 @@ +textObject = new Text($text, $fontStyle, $paragraphStyle); + $this->depth = $depth; + + // Version >= 0.10.0 will pass numbering style name. Older version will use old method + if (!is_null($listStyle) && is_string($listStyle)) { + $this->style = new ListItemStyle($listStyle); + } else { + $this->style = $this->setStyle(new ListItemStyle(), $listStyle, true); + } + } + + /** + * Get ListItem style + */ + public function getStyle() + { + return $this->style; + } + + /** + * Get ListItem TextRun + */ + public function getTextObject() + { + return $this->textObject; + } + + /** + * Get ListItem depth + */ + public function getDepth() + { + return $this->depth; + } +} diff --git a/src/PhpWord/Element/Object.php b/src/PhpWord/Element/Object.php new file mode 100644 index 00000000..7407688a --- /dev/null +++ b/src/PhpWord/Element/Object.php @@ -0,0 +1,123 @@ +source = $src; + $this->style = $this->setStyle(new ImageStyle(), $style, true); + return $this; + } else { + return false; + } + } + + /** + * Get Image style + * + * @return \PhpOffice\PhpWord\Style\Image + */ + public function getStyle() + { + return $this->style; + } + + /** + * Get Source + * + * @return string + */ + public function getSource() + { + return $this->source; + } + + /** + * Get Image Relation ID + * + * @return int + */ + public function getImageRelationId() + { + return $this->imageRelationId; + } + + /** + * Set Image Relation ID + * + * @param int $rId + */ + public function setImageRelationId($rId) + { + $this->imageRelationId = $rId; + } + + /** + * Get Object ID + * + * @return int + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function getObjectId() + { + return $this->relationId + 1325353440; + } + + /** + * Set Object ID + * + * @param int $objId + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function setObjectId($objId) + { + $this->relationId = $objId; + } +} diff --git a/src/PhpWord/Element/PageBreak.php b/src/PhpWord/Element/PageBreak.php new file mode 100644 index 00000000..d2f85f20 --- /dev/null +++ b/src/PhpWord/Element/PageBreak.php @@ -0,0 +1,23 @@ +fontStyle = $this->setStyle(new Font('text'), $fontStyle); + $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + + $matches = preg_split('/({.*?})/', $text, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + if (isset($matches[0])) { + $this->text = $matches; + } + + return $this; + } + + /** + * Get Text style + * + * @return string|\PhpOffice\PhpWord\Style\Font + */ + public function getFontStyle() + { + return $this->fontStyle; + } + + /** + * Get Paragraph style + * + * @return string|\PhpOffice\PhpWord\Style\Paragraph + */ + public function getParagraphStyle() + { + return $this->paragraphStyle; + } + + /** + * Get Text content + * + * @return string + */ + public function getText() + { + return $this->text; + } +} diff --git a/src/PhpWord/Element/Row.php b/src/PhpWord/Element/Row.php new file mode 100644 index 00000000..dc4b8a44 --- /dev/null +++ b/src/PhpWord/Element/Row.php @@ -0,0 +1,99 @@ +setDocPart($docPart, $docPartId); + $this->height = $height; + $this->style = $this->setStyle(new RowStyle(), $style, true); + } + + /** + * Add a cell + * + * @param int $width + * @param mixed $style + */ + public function addCell($width = null, $style = null) + { + $cell = new Cell($this->getDocPart(), $this->getDocPartId(), $width, $style); + $this->cells[] = $cell; + return $cell; + } + + /** + * Get all cells + * + * @return array + */ + public function getCells() + { + return $this->cells; + } + + /** + * Get row style + * + * @return \PhpOffice\PhpWord\Style\Row + */ + public function getStyle() + { + return $this->style; + } + + /** + * Get row height + * + * @return int + */ + public function getHeight() + { + return $this->height; + } +} diff --git a/src/PhpWord/Element/Section.php b/src/PhpWord/Element/Section.php new file mode 100644 index 00000000..64e226ab --- /dev/null +++ b/src/PhpWord/Element/Section.php @@ -0,0 +1,237 @@ +container = 'section'; + $this->sectionId = $sectionCount; + $this->setDocPart($this->container, $this->sectionId); + $this->settings = new SectionSettings(); + $this->setSettings($settings); + } + + /** + * Set section settings + * + * @param array $settings + */ + public function setSettings($settings = null) + { + if (!is_null($settings) && is_array($settings)) { + foreach ($settings as $key => $value) { + if (is_null($value)) { + continue; + } + $this->settings->setSettingValue($key, $value); + } + } + } + + /** + * Get Section Settings + * + * @return \PhpOffice\PhpWord\Style\Section + */ + public function getSettings() + { + return $this->settings; + } + + /** + * Add a PageBreak Element + */ + public function addPageBreak() + { + $this->elements[] = new PageBreak(); + } + + /** + * Add a Table-of-Contents Element + * + * @param mixed $fontStyle + * @param mixed $tocStyle + * @param integer $minDepth + * @param integer $maxDepth + * @return \PhpOffice\PhpWord\Element\TOC + */ + public function addTOC($fontStyle = null, $tocStyle = null, $minDepth = 1, $maxDepth = 9) + { + $toc = new TOC($fontStyle, $tocStyle, $minDepth, $maxDepth); + $this->elements[] = $toc; + return $toc; + } + + /** + * Add header + * + * @param string $type + * @return Header + * @since 0.10.0 + */ + public function addHeader($type = Header::AUTO) + { + return $this->addHeaderFooter($type, true); + } + + /** + * Add footer + * + * @param string $type + * @return Footer + * @since 0.10.0 + */ + public function addFooter($type = Header::AUTO) + { + return $this->addHeaderFooter($type, false); + } + + /** + * Get header elements + * + * @return Header[] + */ + public function getHeaders() + { + return $this->headers; + } + + /** + * Get footer elements + * + * @return Footer[] + */ + public function getFooters() + { + return $this->footers; + } + + /** + * Is there a header for this section that is for the first page only? + * + * If any of the Header instances have a type of Header::FIRST then this method returns true. + * False otherwise. + * + * @return boolean + */ + public function hasDifferentFirstPage() + { + foreach ($this->headers as $header) { + if ($header->getType() == Header::FIRST) { + return true; + } + } + return false; + } + + /** + * Add header/footer + * + * @param string $type + * @param boolean $header + * @return Header|Footer + * @throws \PhpOffice\PhpWord\Exception\Exception + * @since 0.10.0 + */ + private function addHeaderFooter($type = Header::AUTO, $header = true) + { + $collectionArray = $header ? 'headers' : 'footers'; + $containerClass = 'PhpOffice\\PhpWord\\Element\\'; + $containerClass .= ($header ? 'Header' : 'Footer'); + $collection = &$this->$collectionArray; + + if (in_array($type, array(Header::AUTO, Header::FIRST, Header::EVEN))) { + $index = count($collection); + $container = new $containerClass($this->sectionId, ++$index, $type); + $collection[$index] = $container; + return $container; + } else { + throw new Exception('Invalid header/footer type.'); + } + + } + + /** + * Create header + * + * @return Header + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function createHeader() + { + return $this->addHeader(); + } + + /** + * Create footer + * + * @return Footer + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function createFooter() + { + return $this->addFooter(); + } + + /** + * Get footer + * + * @return Footer + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function getFooter() + { + if (empty($this->footers)) { + return null; + } else { + return $this->footers[1]; + } + } +} diff --git a/src/PhpWord/Element/TOC.php b/src/PhpWord/Element/TOC.php new file mode 100644 index 00000000..ac48a49d --- /dev/null +++ b/src/PhpWord/Element/TOC.php @@ -0,0 +1,163 @@ +TOCStyle = new TOCStyle(); + + if (!is_null($tocStyle) && is_array($tocStyle)) { + foreach ($tocStyle as $key => $value) { + $this->TOCStyle->setStyleValue($key, $value); + } + } + + if (!is_null($fontStyle)) { + if (is_array($fontStyle)) { + $this->fontStyle = new Font(); + foreach ($fontStyle as $key => $value) { + $this->fontStyle->setStyleValue($key, $value); + } + } else { + $this->fontStyle = $fontStyle; + } + } + + $this->minDepth = $minDepth; + $this->maxDepth = $maxDepth; + } + + /** + * Get all titles + * + * @return array + */ + public function getTitles() + { + $titles = Titles::getTitles(); + foreach ($titles as $i => $title) { + if ($this->minDepth > $title['depth']) { + unset($titles[$i]); + } + if (($this->maxDepth != 0) && ($this->maxDepth < $title['depth'])) { + unset($titles[$i]); + } + } + $titles = array_merge(array(), $titles); + + return $titles; + } + + /** + * Get TOC Style + * + * @return \PhpOffice\PhpWord\Style\TOC + */ + public function getStyleTOC() + { + return $this->TOCStyle; + } + + /** + * Get Font Style + * + * @return \PhpOffice\PhpWord\Style\Font + */ + public function getStyleFont() + { + return $this->fontStyle; + } + + /** + * Set max depth + * + * @param int $value + */ + public function setMaxDepth($value) + { + $this->maxDepth = $value; + } + + /** + * Get Max Depth + * + * @return int Max depth of titles + */ + public function getMaxDepth() + { + return $this->maxDepth; + } + + /** + * Set min depth + * + * @param int $value + */ + public function setMinDepth($value) + { + $this->minDepth = $value; + } + + /** + * Get Min Depth + * + * @return int Min depth of titles + */ + public function getMinDepth() + { + return $this->minDepth; + } +} diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php new file mode 100644 index 00000000..1fa729e1 --- /dev/null +++ b/src/PhpWord/Element/Table.php @@ -0,0 +1,141 @@ +setDocPart($docPart, $docPartId); + $this->style = $this->setStyle(new TableStyle(), $style); + } + + /** + * Add a row + * + * @param integer $height + * @param mixed $style + */ + public function addRow($height = null, $style = null) + { + $row = new Row($this->getDocPart(), $this->getDocPartId(), $height, $style); + $this->rows[] = $row; + return $row; + } + + /** + * Add a cell + * + * @param integer $width + * @param mixed $style + * @return Cell + */ + public function addCell($width = null, $style = null) + { + $index = count($this->rows) - 1; + $cell = $this->rows[$index]->addCell($width, $style); + return $cell; + } + + /** + * Get all rows + * + * @return array + */ + public function getRows() + { + return $this->rows; + } + + /** + * Get table style + * + * @return \PhpOffice\PhpWord\Style\Table + */ + public function getStyle() + { + return $this->style; + } + + /** + * Set table width + * + * @param integer $width + */ + public function setWidth($width) + { + $this->width = $width; + } + + /** + * Get table width + * + * @return integer + */ + public function getWidth() + { + return $this->width; + } + + /** + * Get column count + * + * @return integer + */ + public function countColumns() + { + $columnCount = 0; + if (is_array($this->rows)) { + $rowCount = count($this->rows); + for ($i = 0; $i < $rowCount; $i++) { + $cellCount = count($this->rows[$i]->getCells()); + if ($columnCount < $cellCount) { + $columnCount = $cellCount; + } + } + } + + return $columnCount; + } +} diff --git a/src/PhpWord/Section/Text.php b/src/PhpWord/Element/Text.php similarity index 59% rename from src/PhpWord/Section/Text.php rename to src/PhpWord/Element/Text.php index 4c1caa29..96e0e164 100644 --- a/src/PhpWord/Section/Text.php +++ b/src/PhpWord/Element/Text.php @@ -2,28 +2,12 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -31,35 +15,35 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Text element */ -class Text +class Text extends AbstractElement { /** * Text content * * @var string */ - private $text; + protected $text; /** * Text style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|\PhpOffice\PhpWord\Style\Font */ - private $fontStyle; + protected $fontStyle; /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Paragraph + * @var string|\PhpOffice\PhpWord\Style\Paragraph */ - private $paragraphStyle; + protected $paragraphStyle; /** * Create a new Text Element * * @param string $text - * @param null|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle + * @param mixed $fontStyle + * @param mixed $paragraphStyle */ public function __construct($text = null, $fontStyle = null, $paragraphStyle = null) { @@ -71,9 +55,9 @@ class Text /** * Set Text style * - * @param null|array|\PhpOffice\PhpWord\Style\Font $style - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - * @return \PhpOffice\PhpWord\Style\Font + * @param string|array|\PhpOffice\PhpWord\Style\Font $style + * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle + * @return string|\PhpOffice\PhpWord\Style\Font */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -89,13 +73,14 @@ class Text $this->fontStyle = $style; $this->setParagraphStyle($paragraphStyle); } + return $this->fontStyle; } /** * Get Text style * - * @return \PhpOffice\PhpWord\Style\Font + * @return string|\PhpOffice\PhpWord\Style\Font */ public function getFontStyle() { @@ -105,8 +90,8 @@ class Text /** * Set Paragraph style * - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $style - * @return null|\PhpOffice\PhpWord\Style\Paragraph + * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $style + * @return string|\PhpOffice\PhpWord\Style\Paragraph */ public function setParagraphStyle($style = null) { @@ -120,13 +105,14 @@ class Text } else { $this->paragraphStyle = $style; } + return $this->paragraphStyle; } /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|\PhpOffice\PhpWord\Style\Paragraph */ public function getParagraphStyle() { @@ -137,11 +123,12 @@ class Text * Set text content * * @param string $text - * @return $this + * @return self */ public function setText($text) { $this->text = $text; + return $this; } diff --git a/src/PhpWord/Section/TextBreak.php b/src/PhpWord/Element/TextBreak.php old mode 100755 new mode 100644 similarity index 58% rename from src/PhpWord/Section/TextBreak.php rename to src/PhpWord/Element/TextBreak.php index a9df1f54..b80ff681 --- a/src/PhpWord/Section/TextBreak.php +++ b/src/PhpWord/Element/TextBreak.php @@ -2,28 +2,12 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Section; +namespace PhpOffice\PhpWord\Element; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; @@ -31,19 +15,19 @@ use PhpOffice\PhpWord\Style\Paragraph; /** * Text break element */ -class TextBreak +class TextBreak extends AbstractElement { /** * Paragraph style * - * @var \PhpOffice\PhpWord\Style\Pagaraph + * @var string|\PhpOffice\PhpWord\Style\Paragraph */ private $paragraphStyle = null; /** * Text style * - * @var \PhpOffice\PhpWord\Style\Font + * @var string|\PhpOffice\PhpWord\Style\Font */ private $fontStyle = null; @@ -66,9 +50,9 @@ class TextBreak /** * Set Text style * - * @param null|array|\PhpOffice\PhpWord\Style\Font $style - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - * @return \PhpOffice\PhpWord\Style\Font + * @param mixed $style + * @param mixed $paragraphStyle + * @return string|\PhpOffice\PhpWord\Style\Font */ public function setFontStyle($style = null, $paragraphStyle = null) { @@ -88,7 +72,7 @@ class TextBreak /** * Get Text style * - * @return \PhpOffice\PhpWord\Style\Font + * @return string|\PhpOffice\PhpWord\Style\Font */ public function getFontStyle() { @@ -98,8 +82,8 @@ class TextBreak /** * Set Paragraph style * - * @param null|array|\PhpOffice\PhpWord\Style\Paragraph $style - * @return null|\PhpOffice\PhpWord\Style\Paragraph + * @param string|array|\PhpOffice\PhpWord\Style\Paragraph $style + * @return string|\PhpOffice\PhpWord\Style\Paragraph */ public function setParagraphStyle($style = null) { @@ -117,7 +101,7 @@ class TextBreak /** * Get Paragraph style * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return string|\PhpOffice\PhpWord\Style\Paragraph */ public function getParagraphStyle() { diff --git a/src/PhpWord/Element/TextRun.php b/src/PhpWord/Element/TextRun.php new file mode 100644 index 00000000..a8428d1e --- /dev/null +++ b/src/PhpWord/Element/TextRun.php @@ -0,0 +1,46 @@ +container = 'textrun'; + $this->paragraphStyle = $this->setStyle(new Paragraph(), $paragraphStyle); + } + + /** + * Get Paragraph style + * + * @return string|\PhpOffice\PhpWord\Style\Paragraph + */ + public function getParagraphStyle() + { + return $this->paragraphStyle; + } +} diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php new file mode 100644 index 00000000..93b48d62 --- /dev/null +++ b/src/PhpWord/Element/Title.php @@ -0,0 +1,141 @@ +style = $style; + } + + $this->text = $text; + $this->depth = $depth; + + return $this; + } + + /** + * Set Anchor + * + * @param int $anchor + */ + public function setAnchor($anchor) + { + $this->anchor = $anchor; + } + + /** + * Get Anchor + * + * @return int + */ + public function getAnchor() + { + return $this->anchor; + } + + /** + * Set Bookmark ID + * + * @param int $bookmarkId + */ + public function setBookmarkId($bookmarkId) + { + $this->bookmarkId = $bookmarkId; + } + + /** + * Get Anchor + * + * @return int + */ + public function getBookmarkId() + { + return $this->bookmarkId; + } + + /** + * Get Title Text content + * + * @return string + */ + public function getText() + { + return $this->text; + } + + /** + * Get depth + * + * @return integer + */ + public function getDepth() + { + return $this->depth; + } + + /** + * Get Title style + * + * @return string + */ + public function getStyle() + { + return $this->style; + } +} diff --git a/src/PhpWord/Endnotes.php b/src/PhpWord/Endnotes.php new file mode 100644 index 00000000..6587dfe9 --- /dev/null +++ b/src/PhpWord/Endnotes.php @@ -0,0 +1,95 @@ +addFromSource($pSource); - } - } - - /** - * Add HashTable items from source - * - * @param \PhpOffice\PhpWord\IComparable[] $pSource Source array to create HashTable from - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - public function addFromSource($pSource = null) - { - // Check if an array was passed - if ($pSource == null) { - return; - } elseif (!is_array($pSource)) { - throw new Exception('Invalid array parameter passed.'); - } - - foreach ($pSource as $item) { - $this->add($item); - } - } - - /** - * Add HashTable item - * - * @param \PhpOffice\PhpWord\IComparable $pSource Item to add - */ - public function add(IComparable $pSource = null) - { - // Determine hashcode - $hashCode = null; - $hashIndex = $pSource->getHashIndex(); - if (is_null($hashIndex)) { - $hashCode = $pSource->getHashCode(); - } elseif (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 \PhpOffice\PhpWord\IComparable $pSource Item to remove - */ - public function remove(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(); - } - - /** - * Get item count - * - * @return int - */ - public function count() - { - return count($this->_items); - } - - /** - * Get hash code index - * - * @param string $pHashCode - * @return int Index - */ - public function getIndexForHashCode($pHashCode = '') - { - return array_search($pHashCode, $this->_keyMap); - } - - /** - * Get by index - * - * @param int $pIndex - * @return \PhpOffice\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 \PhpOffice\PhpWord\IComparable - * - */ - public function getByHashCode($pHashCode = '') - { - if (isset($this->_items[$pHashCode])) { - return $this->_items[$pHashCode]; - } - - return null; - } - - /** - * Convert to array - * - * @return \PhpOffice\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/IOFactory.php b/src/PhpWord/IOFactory.php index 5c8771c2..f28ef088 100644 --- a/src/PhpWord/IOFactory.php +++ b/src/PhpWord/IOFactory.php @@ -2,30 +2,14 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; /** * IO factory @@ -35,14 +19,14 @@ abstract class IOFactory /** * Create new writer * - * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param PhpWord $phpWord * @param string $name - * @return \PhpOffice\PhpWord\Writer\IWriter - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @return \PhpOffice\PhpWord\Writer\WriterInterface + * @throws \PhpOffice\PhpWord\Exception\Exception */ - public static function createWriter(PhpWord $phpWord, $name) + public static function createWriter(PhpWord $phpWord, $name = 'Word2007') { - if ($name !== 'IWriter' && $name !== 'ODText' && $name !== 'RTF' && $name !== 'Word2007') { + if (!in_array($name, array('WriterInterface', 'Word2007', 'ODText', 'RTF', 'HTML', 'PDF'))) { throw new Exception("\"{$name}\" is not a valid writer."); } @@ -54,12 +38,12 @@ abstract class IOFactory * Create new reader * * @param string $name - * @return \PhpOffice\PhpWord\Reader\IReader - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @return \PhpOffice\PhpWord\Reader\ReaderInterface + * @throws \PhpOffice\PhpWord\Exception\Exception */ - public static function createReader($name) + public static function createReader($name = 'Word2007') { - if ($name !== 'IReader' && $name !== 'Word2007') { + if (!in_array($name, array('ReaderInterface', 'Word2007', 'ODText'))) { throw new Exception("\"{$name}\" is not a valid reader."); } @@ -72,7 +56,7 @@ abstract class IOFactory * * @param string $filename The name of the file * @param string $readerName - * @return \PhpOffice\PhpWord + * @return PhpWord */ public static function load($filename, $readerName = 'Word2007') { diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php old mode 100755 new mode 100644 index e617b74e..7d129b86 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -2,143 +2,202 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Section\Image; +use PhpOffice\PhpWord\Element\Image; +use PhpOffice\PhpWord\Exception\Exception; /** - * Media + * Media collection */ class Media { /** - * Section Media Elements + * Media elements * * @var array */ - private static $_sectionMedia = array( - 'images' => array(), - 'embeddings' => array(), - 'links' => array() - ); + private static $elements = array(); /** - * Header Media Elements + * Add new media element * - * @var array + * @param string $container section|headerx|footerx|footnote|endnote + * @param string $mediaType image|object|link + * @param string $source + * @param \PhpOffice\PhpWord\Element\Image $image + * @return integer + * @throws \PhpOffice\PhpWord\Exception\Exception + * @since 0.9.2 + * @since 0.10.0 */ - private static $_headerMedia = array(); + public static function addElement($container, $mediaType, $source, Image &$image = null) + { + // Assign unique media Id and initiate media container if none exists + $mediaId = md5($container . $source); + if (!array_key_exists($container, self::$elements)) { + self::$elements[$container] = array(); + } + + // Add media if not exists or point to existing media + if (!array_key_exists($mediaId, self::$elements[$container])) { + $mediaCount = self::countElements($container); + $mediaTypeCount = self::countElements($container, $mediaType); + $mediaTypeCount++; + $rId = ++$mediaCount; + $target = null; + $mediaData = array('mediaIndex' => $mediaTypeCount); + + switch ($mediaType) { + // Images + case 'image': + if (is_null($image)) { + throw new Exception('Image object not assigned.'); + } + $isMemImage = $image->getIsMemImage(); + $extension = $image->getImageExtension(); + $mediaData['imageExtension'] = $extension; + $mediaData['imageType'] = $image->getImageType(); + if ($isMemImage) { + $mediaData['isMemImage'] = true; + $mediaData['createFunction'] = $image->getImageCreateFunction(); + $mediaData['imageFunction'] = $image->getImageFunction(); + } + $target = "{$container}_image{$mediaTypeCount}.{$extension}"; + $image->setTarget($target); + $image->setMediaIndex($mediaTypeCount); + break; + + // Objects + case 'object': + $target = "{$container}_oleObject{$mediaTypeCount}.bin"; + break; + + // Links + case 'link': + $target = $source; + break; + } + + $mediaData['source'] = $source; + $mediaData['target'] = $target; + $mediaData['type'] = $mediaType; + $mediaData['rID'] = $rId; + self::$elements[$container][$mediaId] = $mediaData; + return $rId; + } else { + $mediaData = self::$elements[$container][$mediaId]; + if (!is_null($image)) { + $image->setTarget($mediaData['target']); + $image->setMediaIndex($mediaData['mediaIndex']); + } + return $mediaData['rID']; + } + } /** - * Footer Media Elements + * Get media elements count * - * @var array + * @param string $container section|headerx|footerx|footnote|endnote + * @param string $mediaType image|object|link + * @return integer + * @since 0.10.0 */ - private static $_footerMedia = array(); + public static function countElements($container, $mediaType = null) + { + $mediaCount = 0; + + if (array_key_exists($container, self::$elements)) { + foreach (self::$elements[$container] as $mediaData) { + if (!is_null($mediaType)) { + if ($mediaType == $mediaData['type']) { + $mediaCount++; + } + } else { + $mediaCount++; + } + } + } + + return $mediaCount; + } /** - * ObjectID Counter + * Get media elements * - * @var int + * @param string $container section|headerx|footerx|footnote|endnote + * @param string $mediaType image|object|link + * @return array + * @since 0.10.0 */ - private static $_objectId = 1325353440; + public static function getElements($container, $mediaType = null) + { + $mediaElements = array(); + + // If header/footer, search for headerx and footerx where x is number + if ($container == 'header' || $container == 'footer') { + foreach (self::$elements as $key => $val) { + if (substr($key, 0, 6) == $container) { + $mediaElements[$key] = $val; + } + } + } else { + if (!array_key_exists($container, self::$elements)) { + return $mediaElements; + } + foreach (self::$elements[$container] as $mediaKey => $mediaData) { + if (!is_null($mediaType)) { + if ($mediaType == $mediaData['type']) { + $mediaElements[$mediaKey] = $mediaData; + } + } else { + $mediaElements[$mediaKey] = $mediaData; + } + } + } + + return $mediaElements; + } + + /** + * Reset media elements + */ + public static function resetElements() + { + self::$elements = array(); + } /** * Add new Section Media Element * * @param string $src * @param string $type - * @param \PhpOffice\PhpWord\Section\Image $image - * @return mixed + * @param \PhpOffice\PhpWord\Element\Image $image + * @return integer + * @deprecated 0.10.0 + * @codeCoverageIgnore */ public static function addSectionMediaElement($src, $type, Image $image = null) { - $mediaId = md5($src); - $key = ($type === 'image') ? 'images' : 'embeddings'; - if (!array_key_exists($mediaId, self::$_sectionMedia[$key])) { - $cImg = self::countSectionMediaElements('images'); - $cObj = self::countSectionMediaElements('embeddings'); - $rID = self::countSectionMediaElements() + 7; - $media = array(); - $folder = null; - $file = null; - if ($type === 'image') { - $cImg++; - if (!is_null($image)) { - $isMemImage = $image->getIsMemImage(); - $extension = $image->getImageExtension(); - } else { - $isMemImage = false; - } - if ($isMemImage) { - $media['isMemImage'] = true; - $media['createfunction'] = $image->getImageCreateFunction(); - $media['imagefunction'] = $image->getImageFunction(); - } - $folder = 'media'; - $file = $type . $cImg . '.' . strtolower($extension); - } elseif ($type === 'oleObject') { - $cObj++; - $folder = 'embedding'; - $file = $type . $cObj . '.bin'; - } - $media['source'] = $src; - $media['target'] = "$folder/section_$file"; - $media['type'] = $type; - $media['rID'] = $rID; - self::$_sectionMedia[$key][$mediaId] = $media; - if ($type === 'oleObject') { - return array($rID, ++self::$_objectId); - } - return $rID; - } else { - if ($type === 'oleObject') { - $rID = self::$_sectionMedia[$key][$mediaId]['rID']; - return array($rID, ++self::$_objectId); - } - return self::$_sectionMedia[$key][$mediaId]['rID']; - } + return self::addElement('section', $type, $src, $image); } /** * Add new Section Link Element * * @param string $linkSrc - * @return mixed + * @return integer + * @deprecated 0.10.0 + * @codeCoverageIgnore */ public static function addSectionLinkElement($linkSrc) { - $rID = self::countSectionMediaElements() + 7; - - $link = array(); - $link['target'] = $linkSrc; - $link['rID'] = $rID; - $link['type'] = 'hyperlink'; - - self::$_sectionMedia['links'][] = $link; - - return $rID; + return self::addElement('section', 'link', $linkSrc); } /** @@ -146,161 +205,104 @@ class Media * * @param string $key * @return array + * @deprecated 0.10.0 + * @codeCoverageIgnore */ public static function getSectionMediaElements($key = null) { - if (!is_null($key)) { - return self::$_sectionMedia[$key]; - } - - $arrImages = self::$_sectionMedia['images']; - $arrObjects = self::$_sectionMedia['embeddings']; - $arrLinks = self::$_sectionMedia['links']; - return array_merge($arrImages, $arrObjects, $arrLinks); + return self::getElements('section', $key); } /** * Get Section Media Elements Count * * @param string $key - * @return int + * @return integer + * @deprecated 0.10.0 + * @codeCoverageIgnore */ public static function countSectionMediaElements($key = null) { - if (!is_null($key)) { - return count(self::$_sectionMedia[$key]); - } - - $cImages = count(self::$_sectionMedia['images']); - $cObjects = count(self::$_sectionMedia['embeddings']); - $cLinks = count(self::$_sectionMedia['links']); - return ($cImages + $cObjects + $cLinks); + return self::countElements('section', $key); } /** * Add new Header Media Element * - * @param int $headerCount + * @param integer $headerCount * @param string $src - * @param \PhpOffice\PhpWord\Section\Image $image - * @return int + * @param \PhpOffice\PhpWord\Element\Image $image + * @return integer + * @deprecated 0.10.0 + * @codeCoverageIgnore */ public static function addHeaderMediaElement($headerCount, $src, Image $image = null) { - $mediaId = md5($src); - $key = 'header' . $headerCount; - if (!array_key_exists($key, self::$_headerMedia)) { - self::$_headerMedia[$key] = array(); - } - if (!array_key_exists($mediaId, self::$_headerMedia[$key])) { - $cImg = self::countHeaderMediaElements($key); - $rID = $cImg + 1; - $cImg++; - $media = array(); - if (!is_null($image)) { - $isMemImage = $image->getIsMemImage(); - $extension = $image->getImageExtension(); - } else { - $isMemImage = false; - } - if ($isMemImage) { - $media['isMemImage'] = true; - $media['createfunction'] = $image->getImageCreateFunction(); - $media['imagefunction'] = $image->getImageFunction(); - } - $file = 'image' . $cImg . '.' . strtolower($extension); - $media['source'] = $src; - $media['target'] = 'media/' . $key . '_' . $file; - $media['type'] = 'image'; - $media['rID'] = $rID; - self::$_headerMedia[$key][$mediaId] = $media; - return $rID; - } else { - return self::$_headerMedia[$key][$mediaId]['rID']; - } + return self::addElement("header{$headerCount}", 'image', $src, $image); } /** * Get Header Media Elements Count * * @param string $key - * @return int + * @return integer + * @deprecated 0.10.0 + * @codeCoverageIgnore */ public static function countHeaderMediaElements($key) { - return count(self::$_headerMedia[$key]); + return self::countElements($key); } /** * Get Header Media Elements * - * @return int + * @return array + * @deprecated 0.10.0 + * @codeCoverageIgnore */ public static function getHeaderMediaElements() { - return self::$_headerMedia; + return self::getElements('header'); } /** * Add new Footer Media Element * - * @param int $footerCount + * @param integer $footerCount * @param string $src - * @param \PhpOffice\PhpWord\Section\Image $image - * @return int + * @param \PhpOffice\PhpWord\Element\Image $image + * @return integer + * @deprecated 0.10.0 + * @codeCoverageIgnore */ public static function addFooterMediaElement($footerCount, $src, Image $image = null) { - $mediaId = md5($src); - $key = 'footer' . $footerCount; - if (!array_key_exists($key, self::$_footerMedia)) { - self::$_footerMedia[$key] = array(); - } - if (!array_key_exists($mediaId, self::$_footerMedia[$key])) { - $cImg = self::countFooterMediaElements($key); - $rID = $cImg + 1; - $cImg++; - if (!is_null($image)) { - $isMemImage = $image->getIsMemImage(); - $extension = $image->getImageExtension(); - } else { - $isMemImage = false; - } - if ($isMemImage) { - $media['isMemImage'] = true; - $media['createfunction'] = $image->getImageCreateFunction(); - $media['imagefunction'] = $image->getImageFunction(); - } - $file = 'image' . $cImg . '.' . strtolower($extension); - $media['source'] = $src; - $media['target'] = 'media/' . $key . '_' . $file; - $media['type'] = 'image'; - $media['rID'] = $rID; - self::$_footerMedia[$key][$mediaId] = $media; - return $rID; - } else { - return self::$_footerMedia[$key][$mediaId]['rID']; - } + return self::addElement("footer{$footerCount}", 'image', $src, $image); } /** * Get Footer Media Elements Count * * @param string $key - * @return int + * @return integer + * @deprecated 0.10.0 + * @codeCoverageIgnore */ public static function countFooterMediaElements($key) { - return count(self::$_footerMedia[$key]); + return self::countElements($key); } /** * Get Footer Media Elements * - * @return int + * @return array + * @deprecated 0.10.0 + * @codeCoverageIgnore */ public static function getFooterMediaElements() { - return self::$_footerMedia; + return self::getElements('footer'); } } diff --git a/src/PhpWord/PhpWord.php b/src/PhpWord/PhpWord.php index eb8c45ec..d4b13356 100644 --- a/src/PhpWord/PhpWord.php +++ b/src/PhpWord/PhpWord.php @@ -2,32 +2,16 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\DocumentProperties; -use PhpOffice\PhpWord\Exceptions\Exception; -use PhpOffice\PhpWord\Section; +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Element\Section; use PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\Template; @@ -39,6 +23,7 @@ class PhpWord const DEFAULT_FONT_COLOR = '000000'; // HEX const DEFAULT_FONT_CONTENT_TYPE = 'default'; // default|eastAsia|cs const DEFAULT_FONT_NAME = 'Arial'; + /** * Default font size, in points. * @@ -50,59 +35,59 @@ class PhpWord /** * Document properties object * - * @var \PhpOffice\PhpWord\DocumentProperties + * @var DocumentProperties */ - private $_documentProperties; + private $documentProperties; /** * Default font name * * @var string */ - private $_defaultFontName; + private $defaultFontName; /** * Default font size * @var int */ - private $_defaultFontSize; + private $defaultFontSize; /** * Collection of sections * - * @var \PhpOffice\PhpWord\Section[] + * @var \PhpOffice\PhpWord\Element\Section[] */ - private $_sections = array(); + private $sections = array(); /** * Create new */ public function __construct() { - $this->_documentProperties = new DocumentProperties(); - $this->_defaultFontName = self::DEFAULT_FONT_NAME; - $this->_defaultFontSize = self::DEFAULT_FONT_SIZE; + $this->documentProperties = new DocumentProperties(); + $this->defaultFontName = self::DEFAULT_FONT_NAME; + $this->defaultFontSize = self::DEFAULT_FONT_SIZE; } /** * Get document properties object * - * @return \PhpOffice\PhpWord\DocumentProperties + * @return DocumentProperties */ public function getDocumentProperties() { - return $this->_documentProperties; + return $this->documentProperties; } /** * Set document properties object * - * @param \PhpOffice\PhpWord\DocumentProperties $documentProperties - * @return \PhpOffice\PhpWord\PhpWord + * @param DocumentProperties $documentProperties + * @return self */ public function setDocumentProperties(DocumentProperties $documentProperties) { - $this->_documentProperties = $documentProperties; + $this->documentProperties = $documentProperties; return $this; } @@ -110,13 +95,13 @@ class PhpWord /** * Create new section * - * @param \PhpOffice\PhpWord\Section\Settings $settings - * @return \PhpOffice\PhpWord\Section + * @param array $settings + * @return \PhpOffice\PhpWord\Element\Section */ - public function createSection($settings = null) + public function addSection($settings = null) { - $section = new Section(\count($this->_sections) + 1, $settings); - $this->_sections[] = $section; + $section = new Section(count($this->sections) + 1, $settings); + $this->sections[] = $section; return $section; } @@ -128,7 +113,7 @@ class PhpWord */ public function getDefaultFontName() { - return $this->_defaultFontName; + return $this->defaultFontName; } /** @@ -138,17 +123,17 @@ class PhpWord */ public function setDefaultFontName($fontName) { - $this->_defaultFontName = $fontName; + $this->defaultFontName = $fontName; } /** * Get default font size * - * @return string + * @return integer */ public function getDefaultFontSize() { - return $this->_defaultFontSize; + return $this->defaultFontSize; } /** @@ -158,7 +143,7 @@ class PhpWord */ public function setDefaultFontSize($fontSize) { - $this->_defaultFontSize = $fontSize; + $this->defaultFontSize = $fontSize; } /** @@ -174,8 +159,8 @@ class PhpWord /** * Adds a paragraph style definition to styles.xml * - * @param $styleName string - * @param $styles array + * @param string $styleName + * @param array $styles */ public function addParagraphStyle($styleName, $styles) { @@ -185,13 +170,13 @@ class PhpWord /** * Adds a font style definition to styles.xml * - * @param $styleName string - * @param mixed $styleFont - * @param mixed $styleParagraph + * @param string $styleName + * @param mixed $fontStyle + * @param mixed $paragraphStyle */ - public function addFontStyle($styleName, $styleFont, $styleParagraph = null) + public function addFontStyle($styleName, $fontStyle, $paragraphStyle = null) { - Style::addFontStyle($styleName, $styleFont, $styleParagraph); + Style::addFontStyle($styleName, $fontStyle, $paragraphStyle); } /** @@ -210,12 +195,12 @@ class PhpWord * Adds a heading style definition to styles.xml * * @param int $titleCount - * @param mixed $styleFont - * @param mixed $styleParagraph + * @param mixed $fontStyle + * @param mixed $paragraphStyle */ - public function addTitleStyle($titleCount, $styleFont, $styleParagraph = null) + public function addTitleStyle($titleCount, $fontStyle, $paragraphStyle = null) { - Style::addTitleStyle($titleCount, $styleFont, $styleParagraph); + Style::addTitleStyle($titleCount, $fontStyle, $paragraphStyle); } /** @@ -229,29 +214,53 @@ class PhpWord Style::addLinkStyle($styleName, $styles); } + /** + * Adds a numbering style + * + * @param string $styleName + * @param mixed $styles + */ + public function addNumberingStyle($styleName, $styles) + { + Style::addNumberingStyle($styleName, $styles); + } + /** * Get all sections * - * @return \PhpOffice\PhpWord\Section[] + * @return \PhpOffice\PhpWord\Element\Section[] */ public function getSections() { - return $this->_sections; + return $this->sections; } /** * Load template by filename * * @param string $filename Fully qualified filename. - * @return \PhpOffice\PhpWord\Template - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @return Template + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function loadTemplate($filename) { - if (\file_exists($filename)) { + if (file_exists($filename)) { return new Template($filename); } else { throw new Exception("Template file {$filename} not found."); } } + + /** + * Create new section + * + * @param array $settings + * @return \PhpOffice\PhpWord\Element\Section + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function createSection($settings = null) + { + return $this->addSection($settings); + } } diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index d1418a54..424ff2cd 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -2,37 +2,21 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Reader; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; /** * Reader abstract class * * @codeCoverageIgnore Abstract class */ -abstract class AbstractReader implements IReader +abstract class AbstractReader implements ReaderInterface { /** * Read data only? @@ -63,7 +47,7 @@ abstract class AbstractReader implements IReader * Set read data only * * @param bool $pValue - * @return \PhpOffice\PhpWord\Reader\IReader + * @return self */ public function setReadDataOnly($pValue = true) { @@ -76,12 +60,12 @@ abstract class AbstractReader implements IReader * * @param string $pFilename * @return resource - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ protected function openFile($pFilename) { // Check if file exists - if (!\file_exists($pFilename) || !is_readable($pFilename)) { + if (!file_exists($pFilename) || !is_readable($pFilename)) { throw new Exception("Could not open " . $pFilename . " for reading! File does not exist."); } @@ -93,7 +77,7 @@ abstract class AbstractReader implements IReader } /** - * Can the current IReader read the file? + * Can the current ReaderInterface read the file? * * @param string $pFilename * @return bool @@ -106,7 +90,10 @@ abstract class AbstractReader implements IReader } catch (Exception $e) { return false; } - fclose($this->fileHandle); + if (is_resource($this->fileHandle)) { + fclose($this->fileHandle); + } + return true; } } diff --git a/src/PhpWord/Reader/IReader.php b/src/PhpWord/Reader/IReader.php deleted file mode 100644 index 0629972d..00000000 --- a/src/PhpWord/Reader/IReader.php +++ /dev/null @@ -1,47 +0,0 @@ -readRelationships($docFile); + + $readerParts = array( + 'content.xml' => 'Content', + ); + + foreach ($readerParts as $xmlFile => $partName) { + $this->readPart($phpWord, $relationships, $partName, $docFile, $xmlFile); + } + + return $phpWord; + } + + /** + * Read document part + * + * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param array $relationships + * @param string $partName + * @param string $docFile + * @param string $xmlFile + */ + private function readPart(PhpWord &$phpWord, $relationships, $partName, $docFile, $xmlFile) + { + $partClass = "PhpOffice\\PhpWord\\Reader\\ODText\\{$partName}"; + if (class_exists($partClass)) { + $part = new $partClass($docFile, $xmlFile); + $part->setRels($relationships); + $part->read($phpWord); + } + + } + + /** + * Read all relationship files + * + * @param string $docFile + * @return array + */ + private function readRelationships($docFile) + { + $rels = array(); + $xmlFile = 'META-INF/manifest.xml'; + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($docFile, $xmlFile); + $nodes = $xmlReader->getElements('manifest:file-entry'); + foreach ($nodes as $node) { + $type = $xmlReader->getAttribute('manifest:media-type', $node); + $target = $xmlReader->getAttribute('manifest:full-path', $node); + $rels[] = array('type' => $type, 'target' => $target); + } + + return $rels; + } +} diff --git a/src/PhpWord/Reader/ODText/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php new file mode 100644 index 00000000..15c67190 --- /dev/null +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -0,0 +1,50 @@ +getDomFromZip($this->docFile, $this->xmlFile); + + $nodes = $xmlReader->getElements('office:body/office:text/*'); + if ($nodes->length > 0) { + $section = $phpWord->addSection(); + foreach ($nodes as $node) { + // $styleName = $xmlReader->getAttribute('text:style-name', $node); + switch ($node->nodeName) { + + case 'text:h': // Heading + $depth = $xmlReader->getAttribute('text:outline-level', $node); + $section->addTitle($node->nodeValue, $depth); + break; + + case 'text:p': // Paragraph + $section->addText($node->nodeValue); + break; + + case 'text:list': // List + $listItems = $xmlReader->getElements('text:list-item/text:p', $node); + foreach ($listItems as $listItem) { + // $listStyleName = $xmlReader->getAttribute('text:style-name', $listItem); + $section->addListItem($listItem->nodeValue); + } + break; + } + } + } + } +} diff --git a/src/PhpWord/Reader/ReaderInterface.php b/src/PhpWord/Reader/ReaderInterface.php new file mode 100644 index 00000000..2829d4ab --- /dev/null +++ b/src/PhpWord/Reader/ReaderInterface.php @@ -0,0 +1,31 @@ +readRelationships($docFile); + + $steps = array( + array('stepPart' => 'document', 'stepItems' => array( + 'styles' => 'Styles', + 'numbering' => 'Numbering', + )), + array('stepPart' => 'main', 'stepItems' => array( + 'officeDocument' => 'Document', + 'core-properties' => 'DocPropsCore', + 'extended-properties' => 'DocPropsApp', + 'custom-properties' => 'DocPropsCustom', + )), + array('stepPart' => 'document', 'stepItems' => array( + 'endnotes' => 'Endnotes', + 'footnotes' => 'Footnotes', + )), + ); + + foreach ($steps as $step) { + $stepPart = $step['stepPart']; + $stepItems = $step['stepItems']; + foreach ($relationships[$stepPart] as $relItem) { + $relType = $relItem['type']; + if (array_key_exists($relType, $stepItems)) { + $partName = $stepItems[$relType]; + $xmlFile = $relItem['target']; + $this->readPart($phpWord, $relationships, $partName, $docFile, $xmlFile); + } + } } - $return = false; - // Load file - $zip = new \ZipArchive(); - if ($zip->open($pFilename) === true) { - // check if it is an OOXML archive - $rels = simplexml_load_string($this->getFromZipArchive($zip, "_rels/.rels")); - if ($rels !== false) { - foreach ($rels->Relationship as $rel) { - switch ($rel["Type"]) { - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument": - if (basename($rel["Target"]) == 'document.xml') { - $return = true; - } - break; + return $phpWord; + } - } + /** + * Read document part + * + * @param \PhpOffice\PhpWord\PhpWord $phpWord + * @param array $relationships + * @param string $partName + * @param string $docFile + * @param string $xmlFile + */ + private function readPart(PhpWord &$phpWord, $relationships, $partName, $docFile, $xmlFile) + { + $partClass = "PhpOffice\\PhpWord\\Reader\\Word2007\\{$partName}"; + if (class_exists($partClass)) { + $part = new $partClass($docFile, $xmlFile); + $part->setRels($relationships); + $part->read($phpWord); + } + + } + + /** + * Read all relationship files + * + * @param string $docFile + * @return array + */ + private function readRelationships($docFile) + { + $relationships = array(); + + // _rels/.rels + $relationships['main'] = $this->getRels($docFile, '_rels/.rels'); + + // word/_rels/*.xml.rels + $wordRelsPath = 'word/_rels/'; + $zipClass = Settings::getZipClass(); + $zip = new $zipClass(); + if ($zip->open($docFile) === 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)); + $relationships[$docPart] = $this->getRels($docFile, $xmlFile, 'word/'); } } $zip->close(); } - return $return; + return $relationships; } /** - * Get zip content + * Get relationship array * - * @param \ZipArchive $archive - * @param string $fileName - * @param bool $removeNamespace - * @return mixed + * @param string $docFile + * @param string $xmlFile + * @param string $targetPrefix + * @return array */ - public function getFromZipArchive($archive, $fileName = '', $removeNamespace = false) + private function getRels($docFile, $xmlFile, $targetPrefix = '') { - // Root-relative paths - // if (strpos($fileName, '//') !== false) { - // $fileName = substr($fileName, strpos($fileName, '//') + 1); - // } - // $fileName = realpath($fileName); + $metaPrefix = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/'; + $officePrefix = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/'; - // Apache POI fixes - $contents = $archive->getFromName($fileName); - if ($contents === false) { - $contents = $archive->getFromName(substr($fileName, 1)); + $rels = array(); + + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($docFile, $xmlFile); + $nodes = $xmlReader->getElements('*'); + foreach ($nodes as $node) { + $rId = $xmlReader->getAttribute('Id', $node); + $type = $xmlReader->getAttribute('Type', $node); + $target = $xmlReader->getAttribute('Target', $node); + + // Remove URL prefixes from $type to make it easier to read + $type = str_replace($metaPrefix, '', $type); + $type = str_replace($officePrefix, '', $type); + $docPart = str_replace('.xml', '', $target); + + // Do not add prefix to link source + if (!in_array($type, array('hyperlink'))) { + $target = $targetPrefix . $target; + } + + // Push to return array + $rels[$rId] = array('type' => $type, 'target' => $target, 'docPart' => $docPart); } + ksort($rels); - // Remove namespaces from elements and attributes name - if ($removeNamespace) { - $contents = preg_replace('~(canRead($pFilename)) { - return null; - } - - // Initialisations - $word = new PhpWord(); - $zip = new \ZipArchive(); - $zip->open($pFilename); - - // Read properties and documents - $rels = simplexml_load_string($this->getFromZipArchive($zip, "_rels/.rels")); - foreach ($rels->Relationship as $rel) { - switch ($rel["Type"]) { - // Core properties - case "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties": - $xmlCore = simplexml_load_string($this->getFromZipArchive($zip, "{$rel['Target']}")); - if (is_object($xmlCore)) { - $xmlCore->registerXPathNamespace("dc", "http://purl.org/dc/elements/1.1/"); - $xmlCore->registerXPathNamespace("dcterms", "http://purl.org/dc/terms/"); - $xmlCore->registerXPathNamespace("cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"); - $docProps = $word->getDocumentProperties(); - $docProps->setCreator((string)self::arrayItem($xmlCore->xpath("dc:creator"))); - $docProps->setLastModifiedBy((string)self::arrayItem($xmlCore->xpath("cp:lastModifiedBy"))); - $docProps->setCreated(strtotime(self::arrayItem($xmlCore->xpath("dcterms:created")))); - $docProps->setModified(strtotime(self::arrayItem($xmlCore->xpath("dcterms:modified")))); - $docProps->setTitle((string)self::arrayItem($xmlCore->xpath("dc:title"))); - $docProps->setDescription((string)self::arrayItem($xmlCore->xpath("dc:description"))); - $docProps->setSubject((string)self::arrayItem($xmlCore->xpath("dc:subject"))); - $docProps->setKeywords((string)self::arrayItem($xmlCore->xpath("cp:keywords"))); - $docProps->setCategory((string)self::arrayItem($xmlCore->xpath("cp:category"))); - } - break; - // Extended properties - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties": - $xmlCore = simplexml_load_string($this->getFromZipArchive($zip, "{$rel['Target']}")); - if (is_object($xmlCore)) { - $docProps = $word->getDocumentProperties(); - if (isset($xmlCore->Company)) { - $docProps->setCompany((string)$xmlCore->Company); - } - if (isset($xmlCore->Manager)) { - $docProps->setManager((string)$xmlCore->Manager); - } - } - break; - // Custom properties - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties": - $xmlCore = simplexml_load_string($this->getFromZipArchive($zip, "{$rel['Target']}")); - if (is_object($xmlCore)) { - $docProps = $word->getDocumentProperties(); - foreach ($xmlCore as $xmlProperty) { - $cellDataOfficeAttributes = $xmlProperty->attributes(); - if (isset($cellDataOfficeAttributes['name'])) { - $propertyName = (string)$cellDataOfficeAttributes['name']; - $cellDataOfficeChildren = $xmlProperty->children("http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"); - $attributeType = $cellDataOfficeChildren->getName(); - $attributeValue = (string)$cellDataOfficeChildren->{$attributeType}; - $attributeValue = DocumentProperties::convertProperty($attributeValue, $attributeType); - $attributeType = DocumentProperties::convertPropertyType($attributeType); - $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType); - } - } - } - break; - // Document - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument": - $dir = dirname($rel["Target"]); - $archive = "$dir/_rels/" . basename($rel["Target"]) . ".rels"; - $relsDoc = simplexml_load_string($this->getFromZipArchive($zip, $archive)); - $relsDoc->registerXPathNamespace("rel", "http://schemas.openxmlformats.org/package/2006/relationships"); - $xpath = self::arrayItem( - $relsDoc->xpath("rel:Relationship[@Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles']") - ); - $xmlDoc = simplexml_load_string($this->getFromZipArchive($zip, "{$rel['Target']}", true)); - if (is_object($xmlDoc)) { - $section = $word->createSection(); - - foreach ($xmlDoc->body->children() as $elm) { - $elmName = $elm->getName(); - if ($elmName == 'p') { // Paragraph/section - // Create new section if section setting found - if ($elm->pPr->sectPr) { - $section->setSettings($this->loadSectionSettings($elm->pPr)); - $section = $word->createSection(); - continue; - } - // Has w:r? It's either text or textrun - if ($elm->r) { - // w:r = 1? It's a plain paragraph - if (count($elm->r) == 1) { - $section->addText( - $elm->r->t, - $this->loadFontStyle($elm->r) - ); - // w:r more than 1? It's a textrun - } else { - $textRun = $section->createTextRun(); - foreach ($elm->r as $r) { - $textRun->addText( - $r->t, - $this->loadFontStyle($r) - ); - } - } - // No, it's a textbreak - } else { - $section->addTextBreak(); - } - } elseif ($elmName == 'sectPr') { - // Last section setting - $section->setSettings($this->loadSectionSettings($xmlDoc->body)); - } - } - } - break; - } - } - - // Read styles - $docRels = simplexml_load_string($this->getFromZipArchive($zip, "word/_rels/document.xml.rels")); - foreach ($docRels->Relationship as $rel) { - switch ($rel["Type"]) { - case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles": - $xmlStyle = simplexml_load_string($this->getFromZipArchive($zip, "word/{$rel['Target']}", true)); - if (is_object($xmlStyle)) { - foreach ($xmlStyle->children() as $elm) { - if ($elm->getName() != 'style') { - continue; - } - $pStyle = null; - $fStyle = null; - $hasParagraphStyle = isset($elm->pPr); - $hasFontStyle = isset($elm->rPr); - $styleName = (string)$elm->name['val']; - if ($hasParagraphStyle) { - $pStyle = $this->loadParagraphStyle($elm); - if (!$hasFontStyle) { - $word->addParagraphStyle($styleName, $pStyle); - } - } - if ($hasFontStyle) { - $fStyle = $this->loadFontStyle($elm); - $word->addFontStyle($styleName, $fStyle, $pStyle); - } - } - } - break; - } - } - $zip->close(); - - return $word; - } - - /** - * Load section settings from SimpleXMLElement - * - * @param \SimpleXMLElement $elm - * @return array|string|null - * - * @todo Implement gutter - */ - private function loadSectionSettings($elm) - { - if ($xml = $elm->sectPr) { - $setting = array(); - if ($xml->type) { - $setting['breakType'] = (string)$xml->type['val']; - } - if ($xml->pgSz) { - if (isset($xml->pgSz['w'])) { - $setting['pageSizeW'] = (int)$xml->pgSz['w']; - } - if (isset($xml->pgSz['h'])) { - $setting['pageSizeH'] = (int)$xml->pgSz['h']; - } - if (isset($xml->pgSz['orient'])) { - $setting['orientation'] = (string)$xml->pgSz['orient']; - } - } - if ($xml->pgMar) { - if (isset($xml->pgMar['top'])) { - $setting['topMargin'] = (int)$xml->pgMar['top']; - } - if (isset($xml->pgMar['left'])) { - $setting['leftMargin'] = (int)$xml->pgMar['left']; - } - if (isset($xml->pgMar['bottom'])) { - $setting['bottomMargin'] = (int)$xml->pgMar['bottom']; - } - if (isset($xml->pgMar['right'])) { - $setting['rightMargin'] = (int)$xml->pgMar['right']; - } - if (isset($xml->pgMar['header'])) { - $setting['headerHeight'] = (int)$xml->pgMar['header']; - } - if (isset($xml->pgMar['footer'])) { - $setting['footerHeight'] = (int)$xml->pgMar['footer']; - } - if (isset($xml->pgMar['gutter'])) { - // $setting['gutter'] = (int)$xml->pgMar['gutter']; - } - } - if ($xml->cols) { - if (isset($xml->cols['num'])) { - $setting['colsNum'] = (int)$xml->cols['num']; - } - if (isset($xml->cols['space'])) { - $setting['colsSpace'] = (int)$xml->cols['space']; - } - } - return $setting; - } - return null; - } - - /** - * Load paragraph style from SimpleXMLElement - * - * @param \SimpleXMLElement $elm - * @return array|string|null - */ - private function loadParagraphStyle($elm) - { - if ($xml = $elm->pPr) { - if ($xml->pStyle) { - return (string)$xml->pStyle['val']; - } - $style = array(); - if ($xml->jc) { - $style['align'] = (string)$xml->jc['val']; - } - if ($xml->ind) { - if (isset($xml->ind->left)) { - $style['indent'] = (int)$xml->ind->left; - } - if (isset($xml->ind->hanging)) { - $style['hanging'] = (int)$xml->ind->hanging; - } - if (isset($xml->ind->line)) { - $style['spacing'] = (int)$xml->ind->line; - } - } - if ($xml->spacing) { - if (isset($xml->spacing['after'])) { - $style['spaceAfter'] = (int)$xml->spacing['after']; - } - if (isset($xml->spacing['before'])) { - $style['spaceBefore'] = (int)$xml->spacing['before']; - } - if (isset($xml->spacing['line'])) { - $style['spacing'] = (int)$xml->spacing['line']; - } - } - if ($xml->basedOn) { - $style['basedOn'] = (string)$xml->basedOn['val']; - } - if ($xml->next) { - $style['next'] = (string)$xml->next['val']; - } - if ($xml->widowControl) { - $style['widowControl'] = false; - } - if ($xml->keepNext) { - $style['keepNext'] = true; - } - if ($xml->keepLines) { - $style['keepLines'] = true; - } - if ($xml->pageBreakBefore) { - $style['pageBreakBefore'] = true; - } - return $style; - } - return null; - } - - /** - * Load font style from SimpleXMLElement - * - * @param \SimpleXMLElement $elm - * @return array|string|null - */ - private function loadFontStyle($elm) - { - if ($xml = $elm->rPr) { - if ($xml->rStyle) { - return (string)$xml->rStyle['val']; - } - $style = array(); - if ($xml->rFonts) { - $style['name'] = (string)$xml->rFonts['ascii']; - } - if ($xml->sz) { - $style['size'] = (int)$xml->sz['val'] / 2; - } - if ($xml->color) { - $style['color'] = (string)$xml->color['val']; - } - if ($xml->b) { - $style['bold'] = true; - } - if ($xml->i) { - $style['italic'] = true; - } - if ($xml->u) { - $style['underline'] = (string)$xml->u['val']; - } - if ($xml->strike) { - $style['strikethrough'] = true; - } - if ($xml->highlight) { - $style['fgColor'] = (string)$xml->highlight['val']; - } - if ($xml->vertAlign) { - if ($xml->vertAlign['val'] == 'superscript') { - $style['superScript'] = true; - } else { - $style['subScript'] = true; - } - } - return $style; - } - return null; - } - - /** - * Return item of array - * - * @param array $array - * @param mixed $key - * @return mixed|null - */ - private static function arrayItem($array, $key = 0) - { - return (isset($array[$key]) ? $array[$key] : null); + return $rels; } } diff --git a/src/PhpWord/Reader/Word2007/AbstractPart.php b/src/PhpWord/Reader/Word2007/AbstractPart.php new file mode 100644 index 00000000..57ad4815 --- /dev/null +++ b/src/PhpWord/Reader/Word2007/AbstractPart.php @@ -0,0 +1,336 @@ +docFile = $docFile; + $this->xmlFile = $xmlFile; + } + + /** + * Set relationships + * + * @param array $value + */ + public function setRels($value) + { + $this->rels = $value; + } + + /** + * Read w:r + * + * @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader + * @param \DOMElement $domNode + * @param mixed $parent + * @param string $docPart + * @param mixed $paragraphStyle + * + * @todo Footnote paragraph style + */ + protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart, $paragraphStyle = null) + { + if (!in_array($domNode->nodeName, array('w:r', 'w:hyperlink'))) { + return; + } + $fontStyle = $this->readFontStyle($xmlReader, $domNode); + + // Link + if ($domNode->nodeName == 'w:hyperlink') { + $rId = $xmlReader->getAttribute('r:id', $domNode); + $textContent = $xmlReader->getValue('w:r/w:t', $domNode); + $target = $this->getMediaTarget($docPart, $rId); + if (!is_null($target)) { + $parent->addLink($target, $textContent, $fontStyle, $paragraphStyle); + } + } else { + // Footnote + if ($xmlReader->elementExists('w:footnoteReference', $domNode)) { + $parent->addFootnote(); + + // Endnote + } elseif ($xmlReader->elementExists('w:endnoteReference', $domNode)) { + $parent->addEndnote(); + + // Image + } elseif ($xmlReader->elementExists('w:pict', $domNode)) { + $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:pict/v:shape/v:imagedata'); + $target = $this->getMediaTarget($docPart, $rId); + if (!is_null($target)) { + $imageSource = "zip://{$this->docFile}#{$target}"; + $parent->addImage($imageSource); + } + + // Object + } elseif ($xmlReader->elementExists('w:object', $domNode)) { + $rId = $xmlReader->getAttribute('r:id', $domNode, 'w:object/o:OLEObject'); + // $rIdIcon = $xmlReader->getAttribute('r:id', $domNode, 'w:object/v:shape/v:imagedata'); + $target = $this->getMediaTarget($docPart, $rId); + if (!is_null($target)) { + $textContent = ""; + $parent->addText($textContent, $fontStyle, $paragraphStyle); + } + + // TextRun + } else { + $textContent = $xmlReader->getValue('w:t', $domNode); + $parent->addText($textContent, $fontStyle, $paragraphStyle); + } + } + } + + /** + * Read w:pPr + * + * @return string|array|null + */ + protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode) + { + $style = null; + if ($xmlReader->elementExists('w:pPr', $domNode)) { + if ($xmlReader->elementExists('w:pPr/w:pStyle', $domNode)) { + $style = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:pStyle'); + } else { + $style = array(); + $mapping = array( + 'w:ind' => 'indent', 'w:spacing' => 'spacing', + 'w:jc' => 'align', 'w:basedOn' => 'basedOn', 'w:next' => 'next', + 'w:widowControl' => 'widowControl', 'w:keepNext' => 'keepNext', + 'w:keepLines' => 'keepLines', 'w:pageBreakBefore' => 'pageBreakBefore', + ); + + $nodes = $xmlReader->getElements('w:pPr/*', $domNode); + foreach ($nodes as $node) { + if (!array_key_exists($node->nodeName, $mapping)) { + continue; + } + $property = $mapping[$node->nodeName]; + switch ($node->nodeName) { + + case 'w:ind': + $style['indent'] = $xmlReader->getAttribute('w:left', $node); + $style['hanging'] = $xmlReader->getAttribute('w:hanging', $node); + break; + + case 'w:spacing': + $style['spaceAfter'] = $xmlReader->getAttribute('w:after', $node); + $style['spaceBefore'] = $xmlReader->getAttribute('w:before', $node); + // Commented. Need to adjust the number when return value is null + // $style['spacing'] = $xmlReader->getAttribute('w:line', $node); + break; + + case 'w:keepNext': + case 'w:keepLines': + case 'w:pageBreakBefore': + $style[$property] = true; + break; + + case 'w:widowControl': + $style[$property] = false; + break; + + case 'w:jc': + case 'w:basedOn': + case 'w:next': + $style[$property] = $xmlReader->getAttribute('w:val', $node); + break; + } + } + } + } + + return $style; + } + + /** + * Read w:rPr + * + * @return string|array|null + */ + protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode) + { + $style = null; + // Hyperlink has an extra w:r child + if ($domNode->nodeName == 'w:hyperlink') { + $domNode = $xmlReader->getElement('w:r', $domNode); + } + if (is_null($domNode)) { + return $style; + } + if ($xmlReader->elementExists('w:rPr', $domNode)) { + if ($xmlReader->elementExists('w:rPr/w:rStyle', $domNode)) { + $style = $xmlReader->getAttribute('w:val', $domNode, 'w:rPr/w:rStyle'); + } else { + $style = array(); + $mapping = array( + 'w:b' => 'bold', 'w:i' => 'italic', 'w:color' => 'color', + 'w:strike' => 'strikethrough', 'w:u' => 'underline', + 'w:highlight' => 'fgColor', 'w:sz' => 'size', + 'w:rFonts' => 'name', 'w:vertAlign' => 'superScript', + ); + + $nodes = $xmlReader->getElements('w:rPr/*', $domNode); + foreach ($nodes as $node) { + if (!array_key_exists($node->nodeName, $mapping)) { + continue; + } + $property = $mapping[$node->nodeName]; + switch ($node->nodeName) { + + case 'w:rFonts': + $style['name'] = $xmlReader->getAttribute('w:ascii', $node); + $style['hint'] = $xmlReader->getAttribute('w:hint', $node); + break; + + case 'w:b': + case 'w:i': + case 'w:strike': + $style[$property] = true; + break; + + case 'w:u': + case 'w:highlight': + case 'w:color': + $style[$property] = $xmlReader->getAttribute('w:val', $node); + break; + + case 'w:sz': + $style[$property] = $xmlReader->getAttribute('w:val', $node) / 2; + break; + + case 'w:vertAlign': + $style[$property] = $xmlReader->getAttribute('w:val', $node); + if ($style[$property] == 'superscript') { + $style['superScript'] = true; + } else { + $style['superScript'] = false; + $style['subScript'] = true; + } + break; + } + } + } + } + + return $style; + } + + /** + * Read w:tblPr + * + * @return string|array|null + * @todo Capture w:tblStylePr w:type="firstRow" + */ + protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode) + { + $style = null; + $margins = array('top', 'left', 'bottom', 'right'); + $borders = $margins + array('insideH', 'insideV'); + + if ($xmlReader->elementExists('w:tblPr', $domNode)) { + if ($xmlReader->elementExists('w:tblPr/w:tblStyle', $domNode)) { + $style = $xmlReader->getAttribute('w:val', $domNode, 'w:tblPr/w:tblStyle'); + } else { + $style = array(); + $mapping = array( + 'w:tblCellMar' => 'cellMargin', + 'w:tblBorders' => 'border', + ); + + $nodes = $xmlReader->getElements('w:tblPr/*', $domNode); + foreach ($nodes as $node) { + if (!array_key_exists($node->nodeName, $mapping)) { + continue; + } + // $property = $mapping[$node->nodeName]; + switch ($node->nodeName) { + + case 'w:tblCellMar': + foreach ($margins as $side) { + $ucfSide = ucfirst($side); + $style["cellMargin$ucfSide"] = $xmlReader->getAttribute('w:w', $node, "w:$side"); + } + break; + + case 'w:tblBorders': + foreach ($borders as $side) { + $ucfSide = ucfirst($side); + $style["border{$ucfSide}Size"] = $xmlReader->getAttribute('w:sz', $node, "w:$side"); + $style["border{$ucfSide}Color"] = $xmlReader->getAttribute('w:color', $node, "w:$side"); + } + break; + } + } + } + } + + return $style; + } + + /** + * Returns the target of image, object, or link as stored in ::readMainRels + * + * @param string $docPart + * @param string $rId + * @return string|null + */ + private function getMediaTarget($docPart, $rId) + { + $target = null; + if (array_key_exists($docPart, $this->rels)) { + if (array_key_exists($rId, $this->rels[$docPart])) { + $target = $this->rels[$docPart][$rId]['target']; + } + } + + return $target; + } +} diff --git a/src/PhpWord/Reader/Word2007/DocProps.php b/src/PhpWord/Reader/Word2007/DocProps.php new file mode 100644 index 00000000..2c76417a --- /dev/null +++ b/src/PhpWord/Reader/Word2007/DocProps.php @@ -0,0 +1,63 @@ +getDomFromZip($this->docFile, $this->xmlFile); + + $docProps = $phpWord->getDocumentProperties(); + + $nodes = $xmlReader->getElements('*'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + if (!array_key_exists($node->nodeName, $this->mapping)) { + continue; + } + $method = $this->mapping[$node->nodeName]; + $value = $node->nodeValue == '' ? null : $node->nodeValue; + if (array_key_exists($node->nodeName, $this->callbacks)) { + $value = $this->callbacks[$node->nodeName]($value); + } + if (method_exists($docProps, $method)) { + $docProps->$method($value); + } + } + } + } +} diff --git a/src/PhpWord/Reader/Word2007/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php new file mode 100644 index 00000000..7797528a --- /dev/null +++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php @@ -0,0 +1,23 @@ + 'setCompany', 'Manager' => 'setManager'); +} diff --git a/src/PhpWord/Reader/Word2007/DocPropsCore.php b/src/PhpWord/Reader/Word2007/DocPropsCore.php new file mode 100644 index 00000000..fd943875 --- /dev/null +++ b/src/PhpWord/Reader/Word2007/DocPropsCore.php @@ -0,0 +1,40 @@ + 'setCreator', + 'dc:title' => 'setTitle', + 'dc:description' => 'setDescription', + 'dc:subject' => 'setSubject', + 'cp:keywords' => 'setKeywords', + 'cp:category' => 'setCategory', + 'cp:lastModifiedBy' => 'setLastModifiedBy', + 'dcterms:created' => 'setCreated', + 'dcterms:modified' => 'setModified', + ); + + /** + * Callback functions + * + * @var array + */ + protected $callbacks = array('dcterms:created' => 'strtotime', 'dcterms:modified' => 'strtotime'); +} diff --git a/src/PhpWord/Reader/Word2007/DocPropsCustom.php b/src/PhpWord/Reader/Word2007/DocPropsCustom.php new file mode 100644 index 00000000..6c67dc7a --- /dev/null +++ b/src/PhpWord/Reader/Word2007/DocPropsCustom.php @@ -0,0 +1,45 @@ +getDomFromZip($this->docFile, $this->xmlFile); + $docProps = $phpWord->getDocumentProperties(); + + $nodes = $xmlReader->getElements('*'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $propertyName = $xmlReader->getAttribute('name', $node); + $attributeNode = $xmlReader->getElement('*', $node); + $attributeType = $attributeNode->nodeName; + $attributeValue = $attributeNode->nodeValue; + $attributeValue = DocumentProperties::convertProperty($attributeValue, $attributeType); + $attributeType = DocumentProperties::convertPropertyType($attributeType); + $docProps->setCustomProperty($propertyName, $attributeValue, $attributeType); + } + } + } +} diff --git a/src/PhpWord/Reader/Word2007/Document.php b/src/PhpWord/Reader/Word2007/Document.php new file mode 100644 index 00000000..21b28f45 --- /dev/null +++ b/src/PhpWord/Reader/Word2007/Document.php @@ -0,0 +1,350 @@ +getDomFromZip($this->docFile, $this->xmlFile); + + $nodes = $xmlReader->getElements('w:body/*'); + if ($nodes->length > 0) { + $section = $phpWord->addSection(); + foreach ($nodes as $node) { + switch ($node->nodeName) { + + case 'w:p': // Paragraph + // Page break + // @todo + if ($xmlReader->getAttribute('w:type', $node, 'w:r/w:br') == 'page') { + $section->addPageBreak(); // PageBreak + } + + // Paragraph + $this->readParagraph($xmlReader, $node, $section, 'document'); + // Section properties + if ($xmlReader->elementExists('w:pPr/w:sectPr', $node)) { + $settingsNode = $xmlReader->getElement('w:pPr/w:sectPr', $node); + if (!is_null($settingsNode)) { + $settings = $this->readSectionStyle($xmlReader, $settingsNode); + $section->setSettings($settings); + if (!is_null($settings)) { + $this->readHeaderFooter($settings, $section); + } + } + $section = $phpWord->addSection(); + } + break; + + case 'w:tbl': // Table + $this->readTable($xmlReader, $node, $section, 'document'); + break; + + case 'w:sectPr': // Last section + $settings = $this->readSectionStyle($xmlReader, $node); + $section->setSettings($settings); + if (!is_null($settings)) { + $this->readHeaderFooter($settings, $section); + } + break; + } + } + } + } + + /** + * Read header footer + * + * @param array $settings + * @param \PhpOffice\PhpWord\Element\Section $section + */ + private function readHeaderFooter($settings, &$section) + { + if (is_array($settings) && array_key_exists('hf', $settings)) { + foreach ($settings['hf'] as $rId => $hfSetting) { + if (array_key_exists($rId, $this->rels['document'])) { + list($hfType, $xmlFile, $docPart) = array_values($this->rels['document'][$rId]); + $method = "add{$hfType}"; + $hfObject = $section->$method($hfSetting['type']); + + // Read header/footer content + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($this->docFile, $xmlFile); + $nodes = $xmlReader->getElements('*'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + switch ($node->nodeName) { + + case 'w:p': // Paragraph + $this->readParagraph($xmlReader, $node, $hfObject, $docPart); + break; + + case 'w:tbl': // Table + $this->readTable($xmlReader, $node, $hfObject, $docPart); + break; + } + } + } + } + } + } + } + + /** + * Read w:p + * + * @param mixed $parent + * @param string $docPart + * + * @todo Get font style for preserve text + */ + private function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart) + { + // Paragraph style + $paragraphStyle = null; + $headingMatches = array(); + if ($xmlReader->elementExists('w:pPr', $domNode)) { + $paragraphStyle = $this->readParagraphStyle($xmlReader, $domNode); + if (is_string($paragraphStyle)) { + preg_match('/Heading(\d)/', $paragraphStyle, $headingMatches); + } + } + + // PreserveText + if ($xmlReader->elementExists('w:r/w:instrText', $domNode)) { + $ignoreText = false; + $textContent = ''; + $fontStyle = $this->readFontStyle($xmlReader, $domNode); + $nodes = $xmlReader->getElements('w:r', $domNode); + foreach ($nodes as $node) { + $instrText = $xmlReader->getValue('w:instrText', $node); + if ($xmlReader->elementExists('w:fldChar', $node)) { + $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar'); + if ($fldCharType == 'begin') { + $ignoreText = true; + } elseif ($fldCharType == 'end') { + $ignoreText = false; + } + } + if (!is_null($instrText)) { + $textContent .= '{' . $instrText . '}'; + } else { + if ($ignoreText === false) { + $textContent .= $xmlReader->getValue('w:t', $node); + } + } + } + $parent->addPreserveText($textContent, $fontStyle, $paragraphStyle); + + // List item + } elseif ($xmlReader->elementExists('w:pPr/w:numPr', $domNode)) { + $textContent = ''; + $numId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:numId'); + $levelId = $xmlReader->getAttribute('w:val', $domNode, 'w:pPr/w:numPr/w:ilvl'); + $nodes = $xmlReader->getElements('w:r', $domNode); + foreach ($nodes as $node) { + $textContent .= $xmlReader->getValue('w:t', $node); + } + $parent->addListItem($textContent, $levelId, null, "PHPWordList{$numId}", $paragraphStyle); + + // Heading + } elseif (!empty($headingMatches)) { + $textContent = ''; + $nodes = $xmlReader->getElements('w:r', $domNode); + foreach ($nodes as $node) { + $textContent .= $xmlReader->getValue('w:t', $node); + } + $parent->addTitle($textContent, $headingMatches[1]); + + // Text and TextRun + } else { + $runCount = $xmlReader->countElements('w:r', $domNode); + $linkCount = $xmlReader->countElements('w:hyperlink', $domNode); + $runLinkCount = $runCount + $linkCount; + if ($runLinkCount == 0) { + $parent->addTextBreak(null, $paragraphStyle); + } else { + if ($runLinkCount > 1) { + $textrun = $parent->addTextRun($paragraphStyle); + $textParent = &$textrun; + } else { + $textParent = &$parent; + } + $nodes = $xmlReader->getElements('*', $domNode); + foreach ($nodes as $node) { + $this->readRun($xmlReader, $node, $textParent, $docPart, $paragraphStyle); + } + } + } + } + + /** + * Read w:tbl + * + * @param mixed $parent + * @param string $docPart + */ + private function readTable(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart) + { + // Table style + $tblStyle = null; + if ($xmlReader->elementExists('w:tblPr', $domNode)) { + $tblStyle = $this->readTableStyle($xmlReader, $domNode); + } + + $table = $parent->addTable($tblStyle); + $tblNodes = $xmlReader->getElements('*', $domNode); + foreach ($tblNodes as $tblNode) { + if ($tblNode->nodeName == 'w:tblGrid') { // Column + // @todo Do something with table columns + + } elseif ($tblNode->nodeName == 'w:tr') { // Row + $rowHeight = $xmlReader->getAttribute('w:val', $tblNode, 'w:trPr/w:trHeight'); + $rowHRule = $xmlReader->getAttribute('w:hRule', $tblNode, 'w:trPr/w:trHeight'); + $rowHRule = $rowHRule == 'exact' ? true : false; + $rowStyle = array( + 'tblHeader' => $xmlReader->elementExists('w:trPr/w:tblHeader', $tblNode), + 'cantSplit' => $xmlReader->elementExists('w:trPr/w:cantSplit', $tblNode), + 'exactHeight' => $rowHRule, + ); + + $row = $table->addRow($rowHeight, $rowStyle); + $rowNodes = $xmlReader->getElements('*', $tblNode); + foreach ($rowNodes as $rowNode) { + if ($rowNode->nodeName == 'w:trPr') { // Row style + // @todo Do something with row style + + } elseif ($rowNode->nodeName == 'w:tc') { // Cell + $cellWidth = $xmlReader->getAttribute('w:w', $rowNode, 'w:tcPr/w:tcW'); + $cellStyle = null; + $cellStyleNode = $xmlReader->getElement('w:tcPr', $rowNode); + if (!is_null($cellStyleNode)) { + $cellStyle = $this->readCellStyle($xmlReader, $cellStyleNode); + } + + $cell = $row->addCell($cellWidth, $cellStyle); + $cellNodes = $xmlReader->getElements('*', $rowNode); + foreach ($cellNodes as $cellNode) { + if ($cellNode->nodeName == 'w:p') { // Paragraph + $this->readParagraph($xmlReader, $cellNode, $cell, $docPart); + } + } + } + } + } + } + } + + /** + * Read w:sectPr + * + * @return array|null + */ + private function readSectionStyle(XMLReader $xmlReader, \DOMElement $domNode) + { + $ret = null; + $mapping = array( + 'w:type' => 'breakType', 'w:pgSz' => 'pageSize', + 'w:pgMar' => 'pageMargin', 'w:cols' => 'columns', + 'w:headerReference' => 'header', 'w:footerReference' => 'footer', + ); + $nodes = $xmlReader->getElements('*', $domNode); + foreach ($nodes as $node) { + if (!array_key_exists($node->nodeName, $mapping)) { + continue; + } + $property = $mapping[$node->nodeName]; + switch ($node->nodeName) { + + case 'w:type': + $ret['breakType'] = $xmlReader->getAttribute('w:val', $node); + break; + + case 'w:pgSz': + $ret['pageSizeW'] = $xmlReader->getAttribute('w:w', $node); + $ret['pageSizeH'] = $xmlReader->getAttribute('w:h', $node); + $ret['orientation'] = $xmlReader->getAttribute('w:orient', $node); + break; + + case 'w:pgMar': + $ret['topMargin'] = $xmlReader->getAttribute('w:top', $node); + $ret['leftMargin'] = $xmlReader->getAttribute('w:left', $node); + $ret['bottomMargin'] = $xmlReader->getAttribute('w:bottom', $node); + $ret['rightMargin'] = $xmlReader->getAttribute('w:right', $node); + $ret['headerHeight'] = $xmlReader->getAttribute('w:header', $node); + $ret['footerHeight'] = $xmlReader->getAttribute('w:footer', $node); + $ret['gutter'] = $xmlReader->getAttribute('w:gutter', $node); + break; + + case 'w:cols': + $ret['colsNum'] = $xmlReader->getAttribute('w:num', $node); + $ret['colsSpace'] = $xmlReader->getAttribute('w:space', $node); + break; + + case 'w:headerReference': + case 'w:footerReference': + $id = $xmlReader->getAttribute('r:id', $node); + $ret['hf'][$id] = array( + 'method' => $property, + 'type' => $xmlReader->getAttribute('w:type', $node), + ); + break; + } + } + + return $ret; + } + + /** + * Read w:tcPr + * + * @return array|null + */ + private function readCellStyle(XMLReader $xmlReader, \DOMElement $domNode) + { + $style = null; + $mapping = array( + 'w:shd' => 'bgColor', + 'w:vAlign' => 'valign', 'w:textDirection' => 'textDirection', + 'w:gridSpan' => 'gridSpan', 'w:vMerge' => 'vMerge', + ); + $nodes = $xmlReader->getElements('*', $domNode); + foreach ($nodes as $node) { + if (!array_key_exists($node->nodeName, $mapping)) { + continue; + } + $property = $mapping[$node->nodeName]; + switch ($node->nodeName) { + case 'w:shd': + $style['bgColor'] = $xmlReader->getAttribute('w:fill', $node); + break; + + default: + $style[$property] = $xmlReader->getAttribute('w:val', $node); + break; + } + } + + return $style; + } +} diff --git a/src/PhpWord/Reader/Word2007/Endnotes.php b/src/PhpWord/Reader/Word2007/Endnotes.php new file mode 100644 index 00000000..235dab4b --- /dev/null +++ b/src/PhpWord/Reader/Word2007/Endnotes.php @@ -0,0 +1,23 @@ +type = ($this->type == 'endnotes') ? 'endnotes' : 'footnotes'; + $collectionClass = 'PhpOffice\\PhpWord\\' . ucfirst($this->type); + $collection = $collectionClass::getElements(); + + $xmlReader = new XMLReader(); + $xmlReader->getDomFromZip($this->docFile, $this->xmlFile); + $nodes = $xmlReader->getElements('*'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $id = $xmlReader->getAttribute('w:id', $node); + $type = $xmlReader->getAttribute('w:type', $node); + + // Avoid w:type "separator" and "continuationSeparator" + // Only look for or without w:type attribute + if (is_null($type) && array_key_exists($id, $collection)) { + $element = $collection[$id]; + $pNodes = $xmlReader->getElements('w:p/*', $node); + foreach ($pNodes as $pNode) { + $this->readRun($xmlReader, $pNode, $element, $type); + } + $collectionClass::setElement($id, $element); + } + } + } + } +} diff --git a/src/PhpWord/Reader/Word2007/Numbering.php b/src/PhpWord/Reader/Word2007/Numbering.php new file mode 100644 index 00000000..5cd3f7ae --- /dev/null +++ b/src/PhpWord/Reader/Word2007/Numbering.php @@ -0,0 +1,110 @@ +getDomFromZip($this->docFile, $this->xmlFile); + + // Abstract numbering definition + $nodes = $xmlReader->getElements('w:abstractNum'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $abstractId = $xmlReader->getAttribute('w:abstractNumId', $node); + $abstracts[$abstractId] = array('levels' => array()); + $abstract = &$abstracts[$abstractId]; + $subnodes = $xmlReader->getElements('*', $node); + foreach ($subnodes as $subnode) { + switch ($subnode->nodeName) { + case 'w:multiLevelType': + $abstract['type'] = $xmlReader->getAttribute('w:val', $subnode); + break; + case 'w:lvl': + $levelId = $xmlReader->getAttribute('w:ilvl', $subnode); + $abstract['levels'][$levelId] = $this->readLevel($xmlReader, $subnode, $levelId); + break; + } + } + } + } + + // Numbering instance definition + $nodes = $xmlReader->getElements('w:num'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $numId = $xmlReader->getAttribute('w:numId', $node); + $abstractId = $xmlReader->getAttribute('w:val', $node, 'w:abstractNumId'); + $numberings[$numId] = $abstracts[$abstractId]; + $numberings[$numId]['numId'] = $numId; + $subnodes = $xmlReader->getElements('w:lvlOverride/w:lvl', $node); + foreach ($subnodes as $subnode) { + $levelId = $xmlReader->getAttribute('w:ilvl', $subnode); + $overrides = $this->readLevel($xmlReader, $subnode, $levelId); + foreach ($overrides as $key => $value) { + $numberings[$numId]['levels'][$levelId][$key] = $value; + } + } + } + } + + // Push to Style collection + foreach ($numberings as $numId => $numbering) { + $phpWord->addNumberingStyle("PHPWordList{$numId}", $numbering); + } + } + + /** + * Read numbering level definition from w:abstractNum and w:num + * + * @param integer $levelId + * @return array + */ + private function readLevel(XMLReader $xmlReader, \DOMElement $subnode, $levelId) + { + $level = array(); + + $level['level'] = $levelId; + $level['start'] = $xmlReader->getAttribute('w:val', $subnode, 'w:start'); + $level['format'] = $xmlReader->getAttribute('w:val', $subnode, 'w:numFmt'); + $level['restart'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlRestart'); + $level['suffix'] = $xmlReader->getAttribute('w:val', $subnode, 'w:suff'); + $level['text'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlText'); + $level['align'] = $xmlReader->getAttribute('w:val', $subnode, 'w:lvlJc'); + $level['tab'] = $xmlReader->getAttribute('w:pos', $subnode, 'w:pPr/w:tabs/w:tab'); + $level['left'] = $xmlReader->getAttribute('w:left', $subnode, 'w:pPr/w:ind'); + $level['hanging'] = $xmlReader->getAttribute('w:hanging', $subnode, 'w:pPr/w:ind'); + $level['font'] = $xmlReader->getAttribute('w:ascii', $subnode, 'w:rPr/w:rFonts'); + $level['hint'] = $xmlReader->getAttribute('w:hint', $subnode, 'w:rPr/w:rFonts'); + + foreach ($level as $key => $value) { + if (is_null($value)) { + unset($level[$key]); + } + } + + return $level; + } +} diff --git a/src/PhpWord/Reader/Word2007/Styles.php b/src/PhpWord/Reader/Word2007/Styles.php new file mode 100644 index 00000000..afc4f9c0 --- /dev/null +++ b/src/PhpWord/Reader/Word2007/Styles.php @@ -0,0 +1,75 @@ +getDomFromZip($this->docFile, $this->xmlFile); + + $nodes = $xmlReader->getElements('w:style'); + if ($nodes->length > 0) { + foreach ($nodes as $node) { + $type = $xmlReader->getAttribute('w:type', $node); + $name = $xmlReader->getAttribute('w:styleId', $node); + if (is_null($name)) { + $name = $xmlReader->getAttribute('w:val', $node, 'w:name'); + } + preg_match('/Heading(\d)/', $name, $headingMatches); + // $default = ($xmlReader->getAttribute('w:default', $node) == 1); + switch ($type) { + + case 'paragraph': + $paragraphStyle = $this->readParagraphStyle($xmlReader, $node); + $fontStyle = $this->readFontStyle($xmlReader, $node); + if (!empty($headingMatches)) { + $phpWord->addTitleStyle($headingMatches[1], $fontStyle, $paragraphStyle); + } else { + if (empty($fontStyle)) { + if (is_array($paragraphStyle)) { + $phpWord->addParagraphStyle($name, $paragraphStyle); + } + } else { + $phpWord->addFontStyle($name, $fontStyle, $paragraphStyle); + } + } + break; + + case 'character': + $fontStyle = $this->readFontStyle($xmlReader, $node); + if (!empty($fontStyle)) { + $phpWord->addFontStyle($name, $fontStyle); + } + break; + + case 'table': + $tStyle = $this->readTableStyle($xmlReader, $node); + if (!empty($tStyle)) { + $phpWord->addTableStyle($name, $tStyle); + } + break; + } + } + } + } +} diff --git a/src/PhpWord/Section.php b/src/PhpWord/Section.php deleted file mode 100644 index 082c7e8b..00000000 --- a/src/PhpWord/Section.php +++ /dev/null @@ -1,445 +0,0 @@ -_sectionCount = $sectionCount; - $this->_settings = new Settings(); - $this->setSettings($settings); - } - - /** - * Set Section Settings - * - * @param array $settings - */ - public function setSettings($settings = null) - { - if (!is_null($settings) && is_array($settings)) { - foreach ($settings as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_settings->setSettingValue($key, $value); - } - } - } - - /** - * Get Section Settings - * - * @return \PhpOffice\PhpWord\Section\Settings - */ - public function getSettings() - { - return $this->_settings; - } - - /** - * Add a Text Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Text - */ - public function addText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::IsUTF8($text)) { - $text = utf8_encode($text); - } - $text = new Text($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add a Link Element - * - * @param string $linkSrc - * @param string $linkName - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Link - */ - public function addLink($linkSrc, $linkName = null, $styleFont = null, $styleParagraph = null) - { - if (!String::IsUTF8($linkSrc)) { - $linkSrc = utf8_encode($linkSrc); - } - if (!is_null($linkName)) { - if (!String::IsUTF8($linkName)) { - $linkName = utf8_encode($linkName); - } - } - - $link = new Link($linkSrc, $linkName, $styleFont, $styleParagraph); - $rID = Media::addSectionLinkElement($linkSrc); - $link->setRelationId($rID); - - $this->_elementCollection[] = $link; - return $link; - } - - /** - * Add a TextBreak Element - * - * @param int $count - * @param null|string|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); - } - } - - /** - * Add a PageBreak Element - */ - public function addPageBreak() - { - $this->_elementCollection[] = new PageBreak(); - } - - /** - * Add a Table Element - * - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Table - */ - public function addTable($style = null) - { - $table = new Table('section', $this->_sectionCount, $style); - $this->_elementCollection[] = $table; - return $table; - } - - /** - * Add a ListItem Element - * - * @param string $text - * @param int $depth - * @param mixed $styleFont - * @param mixed $styleList - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\ListItem - */ - public function addListItem($text, $depth = 0, $styleFont = null, $styleList = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $listItem = new ListItem($text, $depth, $styleFont, $styleList, $styleParagraph); - $this->_elementCollection[] = $listItem; - return $listItem; - } - - /** - * Add a OLE-Object Element - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Object - * @throws \PhpOffice\PhpWord\Exceptions\InvalidObjectException - */ - public function addObject($src, $style = null) - { - $object = new Object($src, $style); - - if (!is_null($object->getSource())) { - $inf = pathinfo($src); - $ext = $inf['extension']; - if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') { - $ext = substr($ext, 0, -1); - } - - $iconSrc = __DIR__ . '/_staticDocParts/'; - if (!\file_exists($iconSrc . '_' . $ext . '.png')) { - $iconSrc = $iconSrc . '_default.png'; - } else { - $iconSrc .= '_' . $ext . '.png'; - } - - $rIDimg = Media::addSectionMediaElement($iconSrc, 'image', new Image($iconSrc)); - $data = Media::addSectionMediaElement($src, 'oleObject'); - $rID = $data[0]; - $objectId = $data[1]; - - $object->setRelationId($rID); - $object->setObjectId($objectId); - $object->setImageRelationId($rIDimg); - - $this->_elementCollection[] = $object; - return $object; - } else { - throw new InvalidObjectException; - } - } - - /** - * Add a Image Element - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image - * @throws \PhpOffice\PhpWord\Exceptions\InvalidImageException - */ - public function addImage($src, $style = null) - { - $image = new Image($src, $style); - if (!is_null($image->getSource())) { - $rID = Media::addSectionMediaElement($src, 'image', $image); - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } - } - - /** - * Add a by PHP created Image Element - * - * @param string $link - * @param mixed $style - * @deprecated - */ - public function addMemoryImage($src, $style = null) - { - return $this->addImage($src, $style); - } - - /** - * Add a Table-of-Contents Element - * - * @param mixed $styleFont - * @param mixed $styleTOC - * @return \PhpOffice\PhpWord\TOC - */ - public function addTOC($styleFont = null, $styleTOC = null) - { - $toc = new TOC($styleFont, $styleTOC); - $this->_elementCollection[] = $toc; - return $toc; - } - - /** - * Add a Title Element - * - * @param string $text - * @param int $depth - * @return \PhpOffice\PhpWord\Section\Title - */ - public function addTitle($text, $depth = 1) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $styles = Style::getStyles(); - if (array_key_exists('Heading_' . $depth, $styles)) { - $style = 'Heading' . $depth; - } else { - $style = null; - } - - $title = new Title($text, $depth, $style); - - $data = TOC::addTitle($text, $depth); - $anchor = $data[0]; - $bookmarkId = $data[1]; - - $title->setAnchor($anchor); - $title->setBookmarkId($bookmarkId); - - $this->_elementCollection[] = $title; - return $title; - } - - /** - * Create a new TextRun - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\TextRun - */ - public function createTextRun($styleParagraph = null) - { - $textRun = new TextRun($styleParagraph); - $this->_elementCollection[] = $textRun; - return $textRun; - } - - /** - * Get all Elements - * - * @return array - */ - public function getElements() - { - return $this->_elementCollection; - } - - /** - * Create a new Header - * - * @return \PhpOffice\PhpWord\Section\Header - */ - public function createHeader() - { - $header = new Header($this->_sectionCount); - $this->_headers[] = $header; - return $header; - } - - /** - * Get Headers - * - * @return array - */ - public function getHeaders() - { - return $this->_headers; - } - - /** - * Is there a header for this section that is for the first page only? - * - * If any of the Header instances have a type of Header::FIRST then this method returns true. - * False otherwise. - * - * @return Boolean - */ - public function hasDifferentFirstPage() - { - $value = array_filter($this->_headers, function (Header &$header) { - return $header->getType() == Header::FIRST; - }); - return count($value) > 0; - } - - /** - * Create a new Footer - * - * @return \PhpOffice\PhpWord\Section\Footer - */ - public function createFooter() - { - $footer = new Footer($this->_sectionCount); - $this->_footer = $footer; - return $footer; - } - - /** - * Get footer element - * - * @return \PhpOffice\PhpWord\Section\Footer - */ - public function getFooter() - { - return $this->_footer; - } - - /** - * Create a new Footnote Element - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Footnote - */ - public function createFootnote($styleParagraph = null) - { - $footnote = new \PhpOffice\PhpWord\Section\Footnote($styleParagraph); - $refID = Footnote::addFootnoteElement($footnote); - $footnote->setReferenceId($refID); - $this->_elementCollection[] = $footnote; - return $footnote; - } -} diff --git a/src/PhpWord/Section/Footer.php b/src/PhpWord/Section/Footer.php deleted file mode 100755 index 2589854e..00000000 --- a/src/PhpWord/Section/Footer.php +++ /dev/null @@ -1,211 +0,0 @@ -_footerCount = $sectionCount; - } - - /** - * Add a Text Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Text - */ - public function addText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $text = new Text($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add TextBreak - * - * @param int $count - * @param null|string|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); - } - } - - /** - * Create a new TextRun - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\TextRun - */ - public function createTextRun($styleParagraph = null) - { - $textRun = new TextRun($styleParagraph); - $this->_elementCollection[] = $textRun; - return $textRun; - } - - /** - * Add a Table Element - * - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Table - */ - public function addTable($style = null) - { - $table = new Table('footer', $this->_footerCount, $style); - $this->_elementCollection[] = $table; - return $table; - } - - /** - * Add a Image Element - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image - */ - public function addImage($src, $style = null) - { - $image = new Image($src, $style); - if (!is_null($image->getSource())) { - $rID = Media::addFooterMediaElement($this->_footerCount, $src, $image); - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } - } - - /** - * Add a by PHP created Image Element - * - * @param string $link - * @param mixed $style - * @deprecated - */ - public function addMemoryImage($src, $style = null) - { - return $this->addImage($src, $style); - } - - /** - * Add a PreserveText Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Footer\PreserveText - */ - public function addPreserveText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $ptext = new PreserveText($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $ptext; - return $ptext; - } - - /** - * Get Footer Relation ID - */ - public function getRelationId() - { - return $this->_rId; - } - - /** - * Set Footer Relation ID - * - * @param int $rId - */ - public function setRelationId($rId) - { - $this->_rId = $rId; - } - - /** - * Get all Footer Elements - * @return array - */ - public function getElements() - { - return $this->_elementCollection; - } - - /** - * Get Footer Count - */ - public function getFooterCount() - { - return $this->_footerCount; - } -} diff --git a/src/PhpWord/Section/Footer/PreserveText.php b/src/PhpWord/Section/Footer/PreserveText.php deleted file mode 100644 index 5a94c3db..00000000 --- a/src/PhpWord/Section/Footer/PreserveText.php +++ /dev/null @@ -1,133 +0,0 @@ -_styleFont = new Font('text'); - - foreach ($styleFont as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_styleFont->setStyleValue($key, $value); - } - } else { - $this->_styleFont = $styleFont; - } - - // Set paragraph style - if (is_array($styleParagraph)) { - $this->_styleParagraph = new Paragraph(); - - foreach ($styleParagraph as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_styleParagraph->setStyleValue($key, $value); - } - } else { - $this->_styleParagraph = $styleParagraph; - } - - $matches = preg_split('/({.*?})/', $text, null, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); - if (isset($matches[0])) { - $this->_text = $matches; - } - - return $this; - } - - /** - * Get Text style - * - * @return \PhpOffice\PhpWord\Style\Font - */ - public function getFontStyle() - { - return $this->_styleFont; - } - - /** - * Get Paragraph style - * - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function getParagraphStyle() - { - return $this->_styleParagraph; - } - - /** - * Get Text content - * - * @return string - */ - public function getText() - { - return $this->_text; - } -} diff --git a/src/PhpWord/Section/Footnote.php b/src/PhpWord/Section/Footnote.php deleted file mode 100644 index 4079812a..00000000 --- a/src/PhpWord/Section/Footnote.php +++ /dev/null @@ -1,154 +0,0 @@ -_elementCollection = array(); - - // Set paragraph style - if (is_array($styleParagraph)) { - $this->_styleParagraph = new Paragraph(); - - foreach ($styleParagraph as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_styleParagraph->setStyleValue($key, $value); - } - } else { - $this->_styleParagraph = $styleParagraph; - } - } - - - /** - * Add a Text Element - * - * @param string $text - * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Section\Text - */ - public function addText($text = null, $styleFont = null) - { - $givenText = $text; - $text = new Text($givenText, $styleFont); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add a Link Element - * - * @param string $linkSrc - * @param string $linkName - * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Section\Link - */ - public function addLink($linkSrc, $linkName = null, $styleFont = null) - { - - $link = new Link($linkSrc, $linkName, $styleFont); - $rID = \PhpOffice\PhpWord\Footnote::addFootnoteLinkElement($linkSrc); - $link->setRelationId($rID); - - $this->_elementCollection[] = $link; - return $link; - } - - /** - * Get Footnote content - * - * @return array - */ - public function getElements() - { - return $this->_elementCollection; - } - - /** - * Get paragraph style - * - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function getParagraphStyle() - { - return $this->_styleParagraph; - } - - /** - * Get Footnote Reference ID - * - * @return int - */ - public function getReferenceId() - { - return $this->_refId; - } - - /** - * Set Footnote Reference ID - * - * @param int $refId - */ - public function setReferenceId($refId) - { - $this->_refId = $refId; - } -} diff --git a/src/PhpWord/Section/Header.php b/src/PhpWord/Section/Header.php deleted file mode 100755 index b023f175..00000000 --- a/src/PhpWord/Section/Header.php +++ /dev/null @@ -1,291 +0,0 @@ -_headerCount = $sectionCount; - } - - /** - * Add a Text Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Text - */ - public function addText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $text = new Text($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add TextBreak - * - * @param int $count - * @param null|string|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); - } - } - - /** - * Create a new TextRun - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\TextRun - */ - public function createTextRun($styleParagraph = null) - { - $textRun = new TextRun($styleParagraph); - $this->_elementCollection[] = $textRun; - return $textRun; - } - - /** - * Add a Table Element - * - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Table - */ - public function addTable($style = null) - { - $table = new Table('header', $this->_headerCount, $style); - $this->_elementCollection[] = $table; - return $table; - } - - /** - * Add a Image Element - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image - */ - public function addImage($src, $style = null) - { - $image = new Image($src, $style); - if (!is_null($image->getSource())) { - $rID = Media::addHeaderMediaElement($this->_headerCount, $src, $image); - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } - } - - /** - * Add a by PHP created Image Element - * - * @param string $link - * @param mixed $style - * @deprecated - */ - public function addMemoryImage($src, $style = null) - { - return $this->addImage($src, $style); - } - - /** - * Add a PreserveText Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Footer\PreserveText - */ - public function addPreserveText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $ptext = new PreserveText($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $ptext; - return $ptext; - } - - /** - * Add a Watermark Element - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image - */ - public function addWatermark($src, $style = null) - { - $image = new Image($src, $style, true); - if (!is_null($image->getSource())) { - $rID = Media::addHeaderMediaElement($this->_headerCount, $src, $image); - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } - } - - /** - * Get Header Relation ID - */ - public function getRelationId() - { - return $this->_rId; - } - - /** - * Set Header Relation ID - * - * @param int $rId - */ - public function setRelationId($rId) - { - $this->_rId = $rId; - } - - /** - * Get all Header Elements - */ - public function getElements() - { - return $this->_elementCollection; - } - - /** - * Get Header Count - */ - public function getHeaderCount() - { - return $this->_headerCount; - } - - /** - * Get Header Type - */ - public function getType() - { - return $this->_type; - } - - /** - * Reset back to default - */ - public function resetType() - { - return $this->_type = self::AUTO; - } - - /** - * First page only header - */ - public function firstPage() - { - return $this->_type = self::FIRST; - } - - /** - * Even numbered Pages only - */ - public function evenPage() - { - return $this->_type = self::EVEN; - } -} diff --git a/src/PhpWord/Section/Image.php b/src/PhpWord/Section/Image.php deleted file mode 100755 index 931f906f..00000000 --- a/src/PhpWord/Section/Image.php +++ /dev/null @@ -1,316 +0,0 @@ -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); - $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); - $this->imageType = exif_imagetype($source); - 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->style = new \PhpOffice\PhpWord\Style\Image(); - if (!is_null($style) && is_array($style)) { - foreach ($style as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->style->setStyleValue($key, $value); - } - } - if (isset($style['wrappingStyle'])) { - $this->style->setWrappingStyle($style['wrappingStyle']); - } - if ($this->style->getWidth() == null && $this->style->getHeight() == null) { - $this->style->setWidth($imgData[0]); - $this->style->setHeight($imgData[1]); - } - $this->setImageFunctions(); - } - - /** - * Get Image style - * - * @return \PhpOffice\PhpWord\Style\Image - */ - public function getStyle() - { - return $this->style; - } - - /** - * Get image relation ID - * - * @return int - */ - public function getRelationId() - { - return $this->rId; - } - - /** - * Set image relation ID - * - * @param int $rId - */ - public function setRelationId($rId) - { - $this->rId = $rId; - } - - /** - * Get image source - * - * @return string - */ - public function getSource() - { - return $this->source; - } - - /** - * Get image media ID - * - * @return string - */ - public function getMediaId() - { - return md5($this->source); - } - - /** - * Get is watermark - * - * @return int - */ - public function getIsWatermark() - { - return $this->isWatermark; - } - - /** - * Set is watermark - * - * @param bool $pValue - */ - public function setIsWatermark($pValue) - { - $this->isWatermark = $pValue; - } - - /** - * Get image type - * - * @return string - */ - public function getImageType() - { - return $this->imageType; - } - - /** - * Get image create function - * - * @return string - */ - public function getImageCreateFunction() - { - return $this->imageCreateFunc; - } - - /** - * Get image function - * - * @return string - */ - public function getImageFunction() - { - return $this->imageFunc; - } - - /** - * Get image extension - * - * @return string - */ - public function getImageExtension() - { - return $this->imageExtension; - } - - /** - * Get is memory image - * - * @return boolean - */ - public function getIsMemImage() - { - return $this->isMemImage; - } - - /** - * Set image functions - */ - private function setImageFunctions() - { - switch ($this->imageType) { - case 'image/png': - $this->imageCreateFunc = 'imagecreatefrompng'; - $this->imageFunc = 'imagepng'; - $this->imageExtension = 'png'; - break; - case 'image/gif': - $this->imageCreateFunc = 'imagecreatefromgif'; - $this->imageFunc = 'imagegif'; - $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': - $this->imageType = 'image/bmp'; - $this->imageExtension = 'bmp'; - break; - case 'image/tiff': - $this->imageExtension = 'tif'; - break; - } - } -} diff --git a/src/PhpWord/Section/Link.php b/src/PhpWord/Section/Link.php deleted file mode 100644 index d39c5459..00000000 --- a/src/PhpWord/Section/Link.php +++ /dev/null @@ -1,175 +0,0 @@ -_linkSrc = $linkSrc; - $this->_linkName = $linkName; - - // Set font style - if (is_array($styleFont)) { - $this->_styleFont = new Font('text'); - - foreach ($styleFont as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_styleFont->setStyleValue($key, $value); - } - } else { - $this->_styleFont = $styleFont; - } - - // Set paragraph style - if (is_array($styleParagraph)) { - $this->_styleParagraph = new Paragraph(); - - foreach ($styleParagraph as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_styleParagraph->setStyleValue($key, $value); - } - } else { - $this->_styleParagraph = $styleParagraph; - } - - return $this; - } - - /** - * Get Link Relation ID - * - * @return int - */ - public function getRelationId() - { - return $this->_rId; - } - - /** - * Set Link Relation ID - * - * @param int $rId - */ - public function setRelationId($rId) - { - $this->_rId = $rId; - } - - /** - * Get Link source - * - * @return string - */ - public function getLinkSrc() - { - return $this->_linkSrc; - } - - /** - * Get Link name - * - * @return string - */ - public function getLinkName() - { - return $this->_linkName; - } - - /** - * Get Text style - * - * @return \PhpOffice\PhpWord\Style\Font - */ - public function getFontStyle() - { - return $this->_styleFont; - } - - /** - * Get Paragraph style - * - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function getParagraphStyle() - { - return $this->_styleParagraph; - } -} diff --git a/src/PhpWord/Section/ListItem.php b/src/PhpWord/Section/ListItem.php deleted file mode 100644 index 5394fc6f..00000000 --- a/src/PhpWord/Section/ListItem.php +++ /dev/null @@ -1,103 +0,0 @@ -_style = new \PhpOffice\PhpWord\Style\ListItem(); - $this->_textObject = new Text($text, $styleFont, $styleParagraph); - $this->_depth = $depth; - - if (!is_null($styleList) && is_array($styleList)) { - foreach ($styleList as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_style->setStyleValue($key, $value); - } - } - } - - /** - * Get ListItem style - */ - public function getStyle() - { - return $this->_style; - } - - /** - * Get ListItem TextRun - */ - public function getTextObject() - { - return $this->_textObject; - } - - /** - * Get ListItem depth - */ - public function getDepth() - { - return $this->_depth; - } -} diff --git a/src/PhpWord/Section/Object.php b/src/PhpWord/Section/Object.php deleted file mode 100644 index 487e6297..00000000 --- a/src/PhpWord/Section/Object.php +++ /dev/null @@ -1,178 +0,0 @@ -_src = $src; - $this->_style = new \PhpOffice\PhpWord\Style\Image(); - - if (!is_null($style) && is_array($style)) { - foreach ($style as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_style->setStyleValue($key, $value); - } - } - - return $this; - } else { - return false; - } - } - - /** - * Get Image style - * - * @return \PhpOffice\PhpWord\Style\Image - */ - public function getStyle() - { - return $this->_style; - } - - /** - * Get Source - * - * @return string - */ - public function getSource() - { - return $this->_src; - } - - /** - * Get Object Relation ID - * - * @return int - */ - public function getRelationId() - { - return $this->_rId; - } - - /** - * Set Object Relation ID - * - * @param int $rId - */ - public function setRelationId($rId) - { - $this->_rId = $rId; - } - - /** - * Get Image Relation ID - * - * @return int - */ - public function getImageRelationId() - { - return $this->_rIdImg; - } - - /** - * Set Image Relation ID - * - * @param int $rId - */ - public function setImageRelationId($rId) - { - $this->_rIdImg = $rId; - } - - /** - * Get Object ID - * - * @return int - */ - public function getObjectId() - { - return $this->_objId; - } - - /** - * Set Object ID - * - * @param int $objId - */ - public function setObjectId($objId) - { - $this->_objId = $objId; - } -} diff --git a/src/PhpWord/Section/PageBreak.php b/src/PhpWord/Section/PageBreak.php deleted file mode 100644 index d3f6d204..00000000 --- a/src/PhpWord/Section/PageBreak.php +++ /dev/null @@ -1,39 +0,0 @@ -_orientation = null; - $this->_marginTop = 1418; - $this->_marginLeft = 1418; - $this->_marginRight = 1418; - $this->_marginBottom = 1134; - $this->_pageSizeW = $this->_defaultPageSizeW; - $this->_pageSizeH = $this->_defaultPageSizeH; - $this->_borderTopSize = null; - $this->_borderTopColor = null; - $this->_borderLeftSize = null; - $this->_borderLeftColor = null; - $this->_borderRightSize = null; - $this->_borderRightColor = null; - $this->_borderBottomSize = null; - $this->_borderBottomColor = null; - $this->headerHeight = 720; // set default header and footer to 720 twips (.5 inches) - $this->footerHeight = 720; - $this->_colsNum = 1; - $this->_colsSpace = 720; - $this->_breakType = null; - } - - /** - * Set Setting Value - * - * @param string $key - * @param string $value - */ - public function setSettingValue($key, $value) - { - if ($key == '_orientation' && $value == 'landscape') { - $this->setLandscape(); - } elseif ($key == '_orientation' && is_null($value)) { - $this->setPortrait(); - } elseif ($key == '_borderSize') { - $this->setBorderSize($value); - } elseif ($key == '_borderColor') { - $this->setBorderColor($value); - } else { - $this->$key = $value; - } - } - - /** - * Get Margin Top - * - * @return int - */ - public function getMarginTop() - { - return $this->_marginTop; - } - - /** - * Set Margin Top - * - * @param int $pValue - */ - public function setMarginTop($pValue = '') - { - $this->_marginTop = $pValue; - return $this; - } - - /** - * Get Margin Left - * - * @return int - */ - public function getMarginLeft() - { - return $this->_marginLeft; - } - - /** - * Set Margin Left - * - * @param int $pValue - */ - public function setMarginLeft($pValue = '') - { - $this->_marginLeft = $pValue; - return $this; - } - - /** - * Get Margin Right - * - * @return int - */ - public function getMarginRight() - { - return $this->_marginRight; - } - - /** - * Set Margin Right - * - * @param int $pValue - */ - public function setMarginRight($pValue = '') - { - $this->_marginRight = $pValue; - return $this; - } - - /** - * Get Margin Bottom - * - * @return int - */ - public function getMarginBottom() - { - return $this->_marginBottom; - } - - /** - * Set Margin Bottom - * - * @param int $pValue - */ - public function setMarginBottom($pValue = '') - { - $this->_marginBottom = $pValue; - return $this; - } - - /** - * Set Landscape Orientation - */ - public function setLandscape() - { - $this->_orientation = 'landscape'; - $this->_pageSizeW = $this->_defaultPageSizeH; - $this->_pageSizeH = $this->_defaultPageSizeW; - } - - /** - * Set Portrait Orientation - */ - public function setPortrait() - { - $this->_orientation = null; - $this->_pageSizeW = $this->_defaultPageSizeW; - $this->_pageSizeH = $this->_defaultPageSizeH; - } - - /** - * Get Page Size Width - * - * @return int - */ - public function getPageSizeW() - { - return $this->_pageSizeW; - } - - /** - * Get Page Size Height - * - * @return int - */ - public function getPageSizeH() - { - return $this->_pageSizeH; - } - - /** - * Get Page Orientation - * - * @return string - */ - public function getOrientation() - { - return $this->_orientation; - } - - /** - * Set Border Size - * - * @param int $pValue - */ - public function setBorderSize($pValue = null) - { - $this->_borderTopSize = $pValue; - $this->_borderLeftSize = $pValue; - $this->_borderRightSize = $pValue; - $this->_borderBottomSize = $pValue; - } - - /** - * Get Border Size - * - * @return array - */ - public function getBorderSize() - { - $t = $this->getBorderTopSize(); - $l = $this->getBorderLeftSize(); - $r = $this->getBorderRightSize(); - $b = $this->getBorderBottomSize(); - - return array($t, $l, $r, $b); - } - - /** - * Set Border Color - * - * @param string $pValue - */ - public function setBorderColor($pValue = null) - { - $this->_borderTopColor = $pValue; - $this->_borderLeftColor = $pValue; - $this->_borderRightColor = $pValue; - $this->_borderBottomColor = $pValue; - } - - /** - * Get Border Color - * - * @return array - */ - public function getBorderColor() - { - $t = $this->getBorderTopColor(); - $l = $this->getBorderLeftColor(); - $r = $this->getBorderRightColor(); - $b = $this->getBorderBottomColor(); - - return array($t, $l, $r, $b); - } - - /** - * Set Border Top Size - * - * @param int $pValue - */ - public function setBorderTopSize($pValue = null) - { - $this->_borderTopSize = $pValue; - } - - /** - * Get Border Top Size - * - * @return int - */ - public function getBorderTopSize() - { - return $this->_borderTopSize; - } - - /** - * Set Border Top Color - * - * @param string $pValue - */ - public function setBorderTopColor($pValue = null) - { - $this->_borderTopColor = $pValue; - } - - /** - * Get Border Top Color - * - * @return string - */ - public function getBorderTopColor() - { - return $this->_borderTopColor; - } - - /** - * Set Border Left Size - * - * @param int $pValue - */ - public function setBorderLeftSize($pValue = null) - { - $this->_borderLeftSize = $pValue; - } - - /** - * Get Border Left Size - * - * @return int - */ - public function getBorderLeftSize() - { - return $this->_borderLeftSize; - } - - /** - * Set Border Left Color - * - * @param string $pValue - */ - public function setBorderLeftColor($pValue = null) - { - $this->_borderLeftColor = $pValue; - } - - /** - * Get Border Left Color - * - * @return string - */ - public function getBorderLeftColor() - { - return $this->_borderLeftColor; - } - - /** - * Set Border Right Size - * - * @param int $pValue - */ - public function setBorderRightSize($pValue = null) - { - $this->_borderRightSize = $pValue; - } - - /** - * Get Border Right Size - * - * @return int - */ - public function getBorderRightSize() - { - return $this->_borderRightSize; - } - - /** - * Set Border Right Color - * - * @param string $pValue - */ - public function setBorderRightColor($pValue = null) - { - $this->_borderRightColor = $pValue; - } - - /** - * Get Border Right Color - * - * @return string - */ - public function getBorderRightColor() - { - return $this->_borderRightColor; - } - - /** - * Set Border Bottom Size - * - * @param int $pValue - */ - public function setBorderBottomSize($pValue = null) - { - $this->_borderBottomSize = $pValue; - } - - /** - * Get Border Bottom Size - * - * @return int - */ - public function getBorderBottomSize() - { - return $this->_borderBottomSize; - } - - /** - * Set Border Bottom Color - * - * @param string $pValue - */ - public function setBorderBottomColor($pValue = null) - { - $this->_borderBottomColor = $pValue; - } - - /** - * Get Border Bottom Color - * - * @return string - */ - public function getBorderBottomColor() - { - return $this->_borderBottomColor; - } - - /** - * Set page numbering start - * - * @param null|int $pageNumberingStart - * @return $this - */ - public function setPageNumberingStart($pageNumberingStart = null) - { - $this->pageNumberingStart = $pageNumberingStart; - return $this; - } - - /** - * Get page numbering start - * - * @return null|int - */ - public function getPageNumberingStart() - { - return $this->pageNumberingStart; - } - - /** - * Get Header Height - * - * @return int - */ - public function getHeaderHeight() - { - return $this->headerHeight; - } - - /** - * Set Header Height - * - * @param int $pValue - */ - public function setHeaderHeight($pValue = '') - { - if (!is_numeric($pValue)) { - $pValue = 720; - } - $this->headerHeight = $pValue; - return $this; - } - - /** - * Get Footer Height - * - * @return int - */ - public function getFooterHeight() - { - return $this->footerHeight; - } - - /** - * Set Footer Height - * - * @param int $pValue - */ - public function setFooterHeight($pValue = '') - { - if (!is_numeric($pValue)) { - $pValue = 720; - } - $this->footerHeight = $pValue; - return $this; - } - - /** - * Set Section Columns Count - * - * @param int $pValue - */ - public function setColsNum($pValue = '') - { - if (!is_numeric($pValue)) { - $pValue = 1; - } - $this->_colsNum = $pValue; - return $this; - } - - /** - * Get Section Columns Count - * - * @return int - */ - public function getColsNum() - { - return $this->_colsNum; - } - - /** - * Set Section Space Between Columns - * - * @param int $pValue - */ - public function setColsSpace($pValue = '') - { - if (!is_numeric($pValue)) { - $pValue = 720; - } - $this->_colsSpace = $pValue; - return $this; - } - - /** - * Get Section Space Between Columns - * - * @return int - */ - public function getColsSpace() - { - return $this->_colsSpace; - } - - /** - * Set Break Type - * - * @param string $pValue - */ - public function setBreakType($pValue = null) - { - $this->_breakType = $pValue; - return $this; - } - - /** - * Get Break Type - * - * @return string - */ - public function getBreakType() - { - return $this->_breakType; - } -} diff --git a/src/PhpWord/Section/Table.php b/src/PhpWord/Section/Table.php deleted file mode 100644 index e0cee34e..00000000 --- a/src/PhpWord/Section/Table.php +++ /dev/null @@ -1,165 +0,0 @@ -_insideOf = $insideOf; - $this->_pCount = $pCount; - - if (!is_null($style)) { - if (is_array($style)) { - $this->_style = new \PhpOffice\PhpWord\Style\Table(); - - foreach ($style as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_style->setStyleValue($key, $value); - } - } else { - $this->_style = $style; - } - } - } - - /** - * Add a row - * - * @param int $height - * @param mixed $style - */ - public function addRow($height = null, $style = null) - { - $row = new Row($this->_insideOf, $this->_pCount, $height, $style); - $this->_rows[] = $row; - return $row; - } - - /** - * Add a cell - * - * @param int $width - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Table\Cell - */ - public function addCell($width = null, $style = null) - { - $i = count($this->_rows) - 1; - $cell = $this->_rows[$i]->addCell($width, $style); - return $cell; - } - - /** - * Get all rows - * - * @return array - */ - public function getRows() - { - return $this->_rows; - } - - /** - * Get table style - * - * @return \PhpOffice\PhpWord\Style\Table - */ - public function getStyle() - { - return $this->_style; - } - - /** - * Set table width - * - * @param int $width - */ - public function setWidth($width) - { - $this->_width = $width; - } - - /** - * Get table width - * - * @return int - */ - public function getWidth() - { - return $this->_width; - } -} diff --git a/src/PhpWord/Section/Table/Cell.php b/src/PhpWord/Section/Table/Cell.php deleted file mode 100755 index 5255ee4f..00000000 --- a/src/PhpWord/Section/Table/Cell.php +++ /dev/null @@ -1,338 +0,0 @@ -_insideOf = $insideOf; - $this->_pCount = $pCount; - $this->_width = $width; - $this->_style = new \PhpOffice\PhpWord\Style\Cell(); - - if (!is_null($style)) { - if (is_array($style)) { - foreach ($style as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_style->setStyleValue($key, $value); - } - } else { - $this->_style = $style; - } - } - } - - /** - * Add a Text Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Text - */ - public function addText($text, $styleFont = null, $styleParagraph = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $text = new Text($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add a Link Element - * - * @param string $linkSrc - * @param string $linkName - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Link - */ - public function addLink($linkSrc, $linkName = null, $style = null) - { - if ($this->_insideOf == 'section') { - if (!String::isUTF8($linkSrc)) { - $linkSrc = utf8_encode($linkSrc); - } - if (!is_null($linkName)) { - if (!String::isUTF8($linkName)) { - $linkName = utf8_encode($linkName); - } - } - - $link = new Link($linkSrc, $linkName, $style); - $rID = Media::addSectionLinkElement($linkSrc); - $link->setRelationId($rID); - - $this->_elementCollection[] = $link; - return $link; - } else { - throw new Exception('Unsupported Link header / footer reference'); - return false; - } - } - - /** - * Add TextBreak - * - * @param int $count - * @param null|string|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); - } - } - - /** - * Add a ListItem Element - * - * @param string $text - * @param int $depth - * @param mixed $styleText - * @param mixed $styleList - * @return \PhpOffice\PhpWord\Section\ListItem - */ - public function addListItem($text, $depth = 0, $styleText = null, $styleList = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $listItem = new ListItem($text, $depth, $styleText, $styleList); - $this->_elementCollection[] = $listItem; - return $listItem; - } - - /** - * Add a Image Element - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image - */ - public function addImage($src, $style = null) - { - $image = new Image($src, $style); - if (!is_null($image->getSource())) { - if ($this->_insideOf == 'section') { - $rID = Media::addSectionMediaElement($src, 'image', $image); - } elseif ($this->_insideOf == 'header') { - $rID = Media::addHeaderMediaElement($this->_pCount, $src, $image); - } elseif ($this->_insideOf == 'footer') { - $rID = Media::addFooterMediaElement($this->_pCount, $src, $image); - } - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } - } - - /** - * Add a by PHP created Image Element - * - * @param string $link - * @param mixed $style - * @deprecated - */ - public function addMemoryImage($src, $style = null) - { - return $this->addImage($src, $style); - } - - /** - * Add a OLE-Object Element - * - * @param string $src - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Object - */ - public function addObject($src, $style = null) - { - $object = new Object($src, $style); - - if (!is_null($object->getSource())) { - $inf = pathinfo($src); - $ext = $inf['extension']; - if (strlen($ext) == 4 && strtolower(substr($ext, -1)) == 'x') { - $ext = substr($ext, 0, -1); - } - - $iconSrc = __DIR__ . '/../../_staticDocParts/'; - if (!\file_exists($iconSrc . '_' . $ext . '.png')) { - $iconSrc = $iconSrc . '_default.png'; - } else { - $iconSrc .= '_' . $ext . '.png'; - } - - $rIDimg = Media::addSectionMediaElement($iconSrc, 'image', new Image($iconSrc)); - $data = Media::addSectionMediaElement($src, 'oleObject'); - $rID = $data[0]; - $objectId = $data[1]; - - $object->setRelationId($rID); - $object->setObjectId($objectId); - $object->setImageRelationId($rIDimg); - - $this->_elementCollection[] = $object; - return $object; - } else { - throw new InvalidObjectException; - } - } - - /** - * Add a PreserveText Element - * - * @param string $text - * @param mixed $styleFont - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Footer\PreserveText - */ - public function addPreserveText($text, $styleFont = null, $styleParagraph = null) - { - if ($this->_insideOf == 'footer' || $this->_insideOf == 'header') { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $ptext = new PreserveText($text, $styleFont, $styleParagraph); - $this->_elementCollection[] = $ptext; - return $ptext; - } else { - throw new Exception('addPreserveText only supported in footer/header.'); - } - } - - /** - * Create a new TextRun - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\TextRun - */ - public function createTextRun($styleParagraph = null) - { - $textRun = new TextRun($styleParagraph); - $this->_elementCollection[] = $textRun; - return $textRun; - } - - /** - * Get all Elements - * - * @return array - */ - public function getElements() - { - return $this->_elementCollection; - } - - /** - * Get Cell Style - * - * @return \PhpOffice\PhpWord\Style\Cell - */ - public function getStyle() - { - return $this->_style; - } - - /** - * Get Cell width - * - * @return int - */ - public function getWidth() - { - return $this->_width; - } -} diff --git a/src/PhpWord/Section/Table/Row.php b/src/PhpWord/Section/Table/Row.php deleted file mode 100644 index c81a0115..00000000 --- a/src/PhpWord/Section/Table/Row.php +++ /dev/null @@ -1,140 +0,0 @@ -_insideOf = $insideOf; - $this->_pCount = $pCount; - $this->_height = $height; - $this->_style = new \PhpOffice\PhpWord\Style\Row(); - - if (!is_null($style)) { - if (is_array($style)) { - - foreach ($style as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_style->setStyleValue($key, $value); - } - } - } - } - - /** - * Add a cell - * - * @param int $width - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Table\Cell - */ - public function addCell($width = null, $style = null) - { - $cell = new Cell($this->_insideOf, $this->_pCount, $width, $style); - $this->_cells[] = $cell; - return $cell; - } - - /** - * Get all cells - * - * @return array - */ - public function getCells() - { - return $this->_cells; - } - - /** - * Get row style - * - * @return \PhpOffice\PhpWord\Style\Row - */ - public function getStyle() - { - return $this->_style; - } - - /** - * Get row height - * - * @return int - */ - public function getHeight() - { - return $this->_height; - } -} diff --git a/src/PhpWord/Section/TextRun.php b/src/PhpWord/Section/TextRun.php deleted file mode 100755 index d6c2ea48..00000000 --- a/src/PhpWord/Section/TextRun.php +++ /dev/null @@ -1,186 +0,0 @@ -_elementCollection = array(); - - // Set paragraph style - if (is_array($styleParagraph)) { - $this->_styleParagraph = new Paragraph(); - - foreach ($styleParagraph as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $this->_styleParagraph->setStyleValue($key, $value); - } - } else { - $this->_styleParagraph = $styleParagraph; - } - } - - - /** - * Add a Text Element - * - * @param string $text - * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Section\Text - */ - public function addText($text = null, $styleFont = null) - { - if (!String::isUTF8($text)) { - $text = utf8_encode($text); - } - $text = new Text($text, $styleFont); - $this->_elementCollection[] = $text; - return $text; - } - - /** - * Add a Link Element - * - * @param string $linkSrc - * @param string $linkName - * @param mixed $styleFont - * @return \PhpOffice\PhpWord\Section\Link - */ - public function addLink($linkSrc, $linkName = null, $styleFont = null) - { - $linkSrc = utf8_encode($linkSrc); - if (!is_null($linkName)) { - $linkName = utf8_encode($linkName); - } - - $link = new Link($linkSrc, $linkName, $styleFont); - $rID = Media::addSectionLinkElement($linkSrc); - $link->setRelationId($rID); - - $this->_elementCollection[] = $link; - return $link; - } - - /** - * Add a Image Element - * - * @param string $imageSrc - * @param mixed $style - * @return \PhpOffice\PhpWord\Section\Image - */ - public function addImage($imageSrc, $style = null) - { - $image = new Image($imageSrc, $style); - if (!is_null($image->getSource())) { - $rID = Media::addSectionMediaElement($imageSrc, 'image', $image); - $image->setRelationId($rID); - $this->_elementCollection[] = $image; - return $image; - } else { - throw new InvalidImageException; - } - } - - /** - * Add TextBreak - * - * @param int $count - * @param null|string|array|\PhpOffice\PhpWord\Style\Font $fontStyle - * @param null|string|array|\PhpOffice\PhpWord\Style\Paragraph $paragraphStyle - */ - public function addTextBreak($count = 1, $fontStyle = null, $paragraphStyle = null) - { - for ($i = 1; $i <= $count; $i++) { - $this->_elementCollection[] = new TextBreak($fontStyle, $paragraphStyle); - } - } - - /** - * Create a new Footnote Element - * - * @param mixed $styleParagraph - * @return \PhpOffice\PhpWord\Section\Footnote - */ - public function createFootnote($styleParagraph = null) - { - $footnote = new \PhpOffice\PhpWord\Section\Footnote($styleParagraph); - $refID = \PhpOffice\PhpWord\Footnote::addFootnoteElement($footnote); - $footnote->setReferenceId($refID); - $this->_elementCollection[] = $footnote; - return $footnote; - } - - /** - * Get TextRun content - * - * @return string - */ - public function getElements() - { - return $this->_elementCollection; - } - - /** - * Get Paragraph style - * - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function getParagraphStyle() - { - return $this->_styleParagraph; - } -} diff --git a/src/PhpWord/Section/Title.php b/src/PhpWord/Section/Title.php deleted file mode 100644 index 81628a88..00000000 --- a/src/PhpWord/Section/Title.php +++ /dev/null @@ -1,147 +0,0 @@ -_style = $style; - } - - $this->_text = $text; - $this->_depth = $depth; - - return $this; - } - - /** - * Set Anchor - * - * @param int $anchor - */ - public function setAnchor($anchor) - { - $this->_anchor = $anchor; - } - - /** - * Get Anchor - * - * @return int - */ - public function getAnchor() - { - return $this->_anchor; - } - - /** - * Set Bookmark ID - * - * @param int $bookmarkId - */ - public function setBookmarkId($bookmarkId) - { - $this->_bookmarkId = $bookmarkId; - } - - /** - * Get Anchor - * - * @return int - */ - public function getBookmarkId() - { - return $this->_bookmarkId; - } - - /** - * Get Title Text content - * - * @return string - */ - public function getText() - { - return $this->_text; - } - - /** - * Get Title style - * - * @return string - */ - public function getStyle() - { - return $this->_style; - } -} diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index c23e1093..bd18df48 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -2,63 +2,239 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; /** - * Settings + * PHPWord settings class + * + * @since 0.8.0 */ class Settings { + /** + * Zip libraries + * + * @const string + */ + const PCLZIP = 'PhpOffice\\PhpWord\\Shared\\ZipArchive'; + const ZIPARCHIVE = 'ZipArchive'; + + /** + * PDF rendering libraries + * + * @const string + */ + const PDF_RENDERER_DOMPDF = 'DomPDF'; + + /** + * Measurement units multiplication factor + * + * Applied to: + * - Section: margins, header/footer height, gutter, column spacing + * - Tab: position + * - Indentation: left, right, firstLine, hanging + * - Spacing: before, after + * + * @const int|float + */ + const UNIT_TWIP = 1; // = 1/20 point + const UNIT_CM = 567; + const UNIT_MM = 56.7; + const UNIT_INCH = 1440; + const UNIT_POINT = 20; // = 1/72 inch + const UNIT_PICA = 240; // = 1/6 inch = 12 points + /** * Compatibility option for XMLWriter * - * @var boolean + * @var bool */ - private static $_xmlWriterCompatibility = true; + private static $xmlWriterCompatibility = true; + + /** + * Name of the class used for Zip file management + * + * @var string + */ + private static $zipClass = self::ZIPARCHIVE; + + /** + * Name of the classes used for PDF renderer + * + * @var array + */ + private static $pdfRenderers = array(self::PDF_RENDERER_DOMPDF); + + /** + * Name of the external Library used for rendering PDF files + * + * @var string + */ + private static $pdfRendererName = null; + + /** + * Directory Path to the external Library used for rendering PDF files + * + * @var string + */ + private static $pdfRendererPath = null; + + /** + * Measurement unit + * + * @var string + */ + private static $measurementUnit = self::UNIT_TWIP; /** * Set the compatibility option used by the XMLWriter * - * @param boolean $compatibility This sets the setIndent and setIndentString for better compatibility - * @return boolean Success or failure + * This sets the setIndent and setIndentString for better compatibility + * + * @param bool $compatibility + * @return bool */ public static function setCompatibility($compatibility) { if (is_bool($compatibility)) { - self::$_xmlWriterCompatibility = $compatibility; + self::$xmlWriterCompatibility = $compatibility; return true; } + return false; } /** * Return the compatibility option used by the XMLWriter * - * @return boolean Compatibility + * @return bool Compatibility */ public static function getCompatibility() { - return self::$_xmlWriterCompatibility; + return self::$xmlWriterCompatibility; + } + + /** + * Set zip handler class + * + * @param string $zipClass + * @return bool + */ + public static function setZipClass($zipClass) + { + if (($zipClass === self::PCLZIP) || + ($zipClass === self::ZIPARCHIVE)) { + self::$zipClass = $zipClass; + return true; + } + + return false; + } + + /** + * Get zip handler class + * + * @return string + */ + public static function getZipClass() + { + return self::$zipClass; + } + + /** + * Set details of the external library for rendering PDF files + * + * @param string $libraryName + * @param string $libraryBaseDir + * @return bool Success or failure + */ + public static function setPdfRenderer($libraryName, $libraryBaseDir) + { + if (!self::setPdfRendererName($libraryName)) { + return false; + } + + return self::setPdfRendererPath($libraryBaseDir); + } + + /** + * Return the PDF Rendering Library + */ + public static function getPdfRendererName() + { + return self::$pdfRendererName; + } + + /** + * Identify the external library to use for rendering PDF files + * + * @param string $libraryName + * @return bool + */ + public static function setPdfRendererName($libraryName) + { + if (!in_array($libraryName, self::$pdfRenderers)) { + return false; + } + self::$pdfRendererName = $libraryName; + + return true; + } + + + /** + * Return the directory path to the PDF Rendering Library + */ + public static function getPdfRendererPath() + { + return self::$pdfRendererPath; + } + + /** + * Location of external library to use for rendering PDF files + * + * @param string $libraryBaseDir Directory path to the library's base folder + * @return bool Success or failure + */ + public static function setPdfRendererPath($libraryBaseDir) + { + if ((file_exists($libraryBaseDir) === false) || (is_readable($libraryBaseDir) === false)) { + return false; + } + self::$pdfRendererPath = $libraryBaseDir; + + return true; + } + + /** + * Get measurement unit + * + * @return int|float + */ + public static function getMeasurementUnit() + { + return self::$measurementUnit; + } + + /** + * Set measurement unit + * + * @param int|float $value + * @return bool + */ + public static function setMeasurementUnit($value) + { + $units = array(self::UNIT_TWIP, self::UNIT_CM, self::UNIT_MM, self::UNIT_INCH, self::UNIT_POINT, self::UNIT_PICA); + if (!in_array($value, $units)) { + return false; + } + self::$measurementUnit = $value; + + return true; } } diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php index 514a5c55..58a6ee1a 100644 --- a/src/PhpWord/Shared/Drawing.php +++ b/src/PhpWord/Shared/Drawing.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Shared; @@ -33,8 +17,8 @@ class Drawing /** * Convert pixels to EMU * - * @param int $pValue Value in pixels - * @return int Value in EMU + * @param integer $pValue Value in pixels + * @return double Value in EMU */ public static function pixelsToEMU($pValue = 0) { @@ -44,8 +28,8 @@ class Drawing /** * Convert EMU to pixels * - * @param int $pValue Value in EMU - * @return int Value in pixels + * @param integer $pValue Value in EMU + * @return integer Value in pixels */ public static function EMUToPixels($pValue = 0) { @@ -59,8 +43,8 @@ class Drawing /** * Convert pixels to points * - * @param int $pValue Value in pixels - * @return int Value in points + * @param integer $pValue Value in pixels + * @return double Value in points */ public static function pixelsToPoints($pValue = 0) { @@ -70,8 +54,8 @@ class Drawing /** * Convert points width to pixels * - * @param int $pValue Value in points - * @return int Value in pixels + * @param integer $pValue Value in points + * @return integer Value in pixels */ public static function pointsToPixels($pValue = 0) { @@ -85,19 +69,19 @@ class Drawing /** * Convert degrees to angle * - * @param int $pValue Degrees - * @return int Angle + * @param integer $pValue Degrees + * @return integer Angle */ public static function degreesToAngle($pValue = 0) { - return (int)round($pValue * 60000); + return (integer)round($pValue * 60000); } /** * Convert angle to degrees * - * @param int $pValue Angle - * @return int Degrees + * @param integer $pValue Angle + * @return integer Degrees */ public static function angleToDegrees($pValue = 0) { @@ -111,8 +95,8 @@ class Drawing /** * Convert pixels to centimeters * - * @param int $pValue Value in pixels - * @return int Value in centimeters + * @param integer $pValue Value in pixels + * @return double Value in centimeters */ public static function pixelsToCentimeters($pValue = 0) { @@ -122,8 +106,8 @@ class Drawing /** * Convert centimeters width to pixels * - * @param int $pValue Value in centimeters - * @return int Value in pixels + * @param integer $pValue Value in centimeters + * @return integer Value in pixels */ public static function centimetersToPixels($pValue = 0) { @@ -137,8 +121,8 @@ class Drawing /** * Convert HTML hexadecimal to RGB * - * @param str $pValue HTML Color in hexadecimal - * @return array Value in RGB + * @param string $pValue HTML Color in hexadecimal + * @return array Value in RGB */ public static function htmlToRGB($pValue) { diff --git a/src/PhpWord/Shared/Font.php b/src/PhpWord/Shared/Font.php index 1abba078..f5317abb 100644 --- a/src/PhpWord/Shared/Font.php +++ b/src/PhpWord/Shared/Font.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Shared; @@ -33,8 +17,8 @@ class Font /** * Calculate an (approximate) pixel size, based on a font points size * - * @param int $fontSizeInPoints Font size (in points) - * @return int Font size (in pixels) + * @param int $fontSizeInPoints Font size (in points) + * @return int Font size (in pixels) */ public static function fontSizeToPixels($fontSizeInPoints = 12) { @@ -56,7 +40,7 @@ class Font * Calculate an (approximate) pixel size, based on centimeter size * * @param int $sizeInCm Font size (in centimeters) - * @return int Size (in pixels) + * @return double Size (in pixels) */ public static function centimeterSizeToPixels($sizeInCm = 1) { @@ -67,7 +51,7 @@ class Font * Convert centimeter to twip * * @param int $sizeInCm - * @return int + * @return double */ public static function centimeterSizeToTwips($sizeInCm = 1) { @@ -78,7 +62,7 @@ class Font * Convert inch to twip * * @param int $sizeInInch - * @return int + * @return double */ public static function inchSizeToTwips($sizeInInch = 1) { @@ -89,7 +73,7 @@ class Font * Convert pixel to twip * * @param int $sizeInPixel - * @return int + * @return double */ public static function pixelSizeToTwips($sizeInPixel = 1) { @@ -99,8 +83,8 @@ class Font /** * Calculate twip based on point size, used mainly for paragraph spacing * - * @param int|float $sizeInPoint Size in point - * @return int|float Size (in twips) + * @param integer $sizeInPoint Size in point + * @return integer Size (in twips) */ public static function pointSizeToTwips($sizeInPoint = 1) { diff --git a/src/PhpWord/Shared/PCLZip/pclzip.lib.php b/src/PhpWord/Shared/PCLZip/pclzip.lib.php new file mode 100644 index 00000000..4e2a496f --- /dev/null +++ b/src/PhpWord/Shared/PCLZip/pclzip.lib.php @@ -0,0 +1,5691 @@ +zipname = $p_zipname; + $this->zip_fd = 0; + $this->magic_quotes_status = -1; + + // ----- Return + return; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // create($p_filelist, $p_add_dir="", $p_remove_dir="") + // create($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two different synopsis. The first one is historical. + // This method creates a Zip Archive. The Zip file is created in the + // filesystem. The files and directories indicated in $p_filelist + // are added in the archive. See the parameters description for the + // supported format of $p_filelist. + // When a directory is in the list, the directory and its content is added + // in the archive. + // In this synopsis, the function takes an optional variable list of + // options. See bellow the supported options. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function create($p_filelist) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove from the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } + else if ($v_size > 2) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Invalid number / type of arguments"); + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); + + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { + + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; + } + + // ----- The list is a list of string names + else { + $v_string_list = $p_filelist; + } + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); + } + + // ----- Invalid variable type for $p_filelist + else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_filelist"); + return 0; + } + + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + if ($v_string != '') { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } + else { + } + } + } + + // ----- For each file in the list check the attributes + $v_supported_attributes + = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' + ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' + ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' + ,PCLZIP_ATT_FILE_MTIME => 'optional' + ,PCLZIP_ATT_FILE_CONTENT => 'optional' + ,PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, + $v_filedescr_list[], + $v_options, + $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Call the create fct + $v_result = $this->privCreate($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // add($p_filelist, $p_add_dir="", $p_remove_dir="") + // add($p_filelist, $p_option, $p_option_value, ...) + // Description : + // This method supports two synopsis. The first one is historical. + // This methods add the list of files in an existing archive. + // If a file with the same name already exists, it is added at the end of the + // archive, the first one is still present. + // If the archive does not exist, it is created. + // Parameters : + // $p_filelist : An array containing file or directory names, or + // a string containing one filename or one directory name, or + // a string containing a list of filenames and/or directory + // names separated by spaces. + // $p_add_dir : A path to add before the real path of the archived file, + // in order to have it memorized in the archive. + // $p_remove_dir : A path to remove from the real path of the file to archive, + // in order to have a shorter path memorized in the archive. + // When $p_add_dir and $p_remove_dir are set, $p_remove_dir + // is removed first, before $p_add_dir is added. + // Options : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_COMMENT : + // PCLZIP_OPT_ADD_COMMENT : + // PCLZIP_OPT_PREPEND_COMMENT : + // PCLZIP_CB_PRE_ADD : + // PCLZIP_CB_POST_ADD : + // Return Values : + // 0 on failure, + // The list of the added files, with a status of the add action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function add($p_filelist) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Set default values + $v_options = array(); + $v_options[PCLZIP_OPT_NO_COMPRESSION] = FALSE; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_ADD => 'optional', + PCLZIP_CB_POST_ADD => 'optional', + PCLZIP_OPT_NO_COMPRESSION => 'optional', + PCLZIP_OPT_COMMENT => 'optional', + PCLZIP_OPT_ADD_COMMENT => 'optional', + PCLZIP_OPT_PREPEND_COMMENT => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + //, PCLZIP_OPT_CRYPT => 'optional' + )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_options[PCLZIP_OPT_ADD_PATH] = $v_add_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_options[PCLZIP_OPT_REMOVE_PATH] = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Init + $v_string_list = array(); + $v_att_list = array(); + $v_filedescr_list = array(); + $p_result_list = array(); + + // ----- Look if the $p_filelist is really an array + if (is_array($p_filelist)) { + + // ----- Look if the first element is also an array + // This will mean that this is a file description entry + if (isset($p_filelist[0]) && is_array($p_filelist[0])) { + $v_att_list = $p_filelist; + } + + // ----- The list is a list of string names + else { + $v_string_list = $p_filelist; + } + } + + // ----- Look if the $p_filelist is a string + else if (is_string($p_filelist)) { + // ----- Create a list from the string + $v_string_list = explode(PCLZIP_SEPARATOR, $p_filelist); + } + + // ----- Invalid variable type for $p_filelist + else { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type '".gettype($p_filelist)."' for p_filelist"); + return 0; + } + + // ----- Reformat the string list + if (sizeof($v_string_list) != 0) { + foreach ($v_string_list as $v_string) { + $v_att_list[][PCLZIP_ATT_FILE_NAME] = $v_string; + } + } + + // ----- For each file in the list check the attributes + $v_supported_attributes + = array ( PCLZIP_ATT_FILE_NAME => 'mandatory' + ,PCLZIP_ATT_FILE_NEW_SHORT_NAME => 'optional' + ,PCLZIP_ATT_FILE_NEW_FULL_NAME => 'optional' + ,PCLZIP_ATT_FILE_MTIME => 'optional' + ,PCLZIP_ATT_FILE_CONTENT => 'optional' + ,PCLZIP_ATT_FILE_COMMENT => 'optional' + ); + foreach ($v_att_list as $v_entry) { + $v_result = $this->privFileDescrParseAtt($v_entry, + $v_filedescr_list[], + $v_options, + $v_supported_attributes); + if ($v_result != 1) { + return 0; + } + } + + // ----- Expand the filelist (expand directories) + $v_result = $this->privFileDescrExpand($v_filedescr_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Call the create fct + $v_result = $this->privAdd($v_filedescr_list, $p_result_list, $v_options); + if ($v_result != 1) { + return 0; + } + + // ----- Return + return $p_result_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : listContent() + // Description : + // This public method, gives the list of the files and directories, with their + // properties. + // The properties of each entries in the list are (used also in other functions) : + // filename : Name of the file. For a create or add action it is the filename + // given by the user. For an extract function it is the filename + // of the extracted file. + // stored_filename : Name of the file / directory stored in the archive. + // size : Size of the stored file. + // compressed_size : Size of the file's data compressed in the archive + // (without the headers overhead) + // mtime : Last known modification date of the file (UNIX timestamp) + // comment : Comment associated with the file + // folder : true | false + // index : index of the file in the archive + // status : status of the action (depending of the action) : + // Values are : + // ok : OK ! + // filtered : the file / dir is not extracted (filtered by user) + // already_a_directory : the file can not be extracted because a + // directory with the same name already exists + // write_protected : the file can not be extracted because a file + // with the same name already exists and is + // write protected + // newer_exist : the file was not extracted because a newer file exists + // path_creation_fail : the file is not extracted because the folder + // does not exist and can not be created + // write_error : the file was not extracted because there was a + // error while writing the file + // read_error : the file was not extracted because there was a error + // while reading the file + // invalid_header : the file was not extracted because of an archive + // format error (bad file header) + // Note that each time a method can continue operating when there + // is an action error on a file, the error is only logged in the file status. + // Return Values : + // 0 on an unrecoverable failure, + // The list of the files in the archive. + // -------------------------------------------------------------------------------- + function listContent() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Call the extracting fct + $p_list = array(); + if (($v_result = $this->privList($p_list)) != 1) + { + unset($p_list); + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // extract($p_path="./", $p_remove_path="") + // extract([$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method extract all the files / directories from the archive to the + // folder indicated in $p_path. + // If you want to ignore the 'root' part of path of the memorized files + // you can indicate this in the optional $p_remove_path parameter. + // By default, if a newer file with the same name already exists, the + // file is not extracted. + // + // If both PCLZIP_OPT_PATH and PCLZIP_OPT_ADD_PATH aoptions + // are used, the path indicated in PCLZIP_OPT_ADD_PATH is append + // at the end of the path value of PCLZIP_OPT_PATH. + // Parameters : + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 or a negative value on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function extract() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); +// $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_EXTRACT_IN_OUTPUT => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional' + ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' + ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Trace + + // ----- Call the extracting fct + $p_list = array(); + $v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, + $v_remove_all_path, $v_options); + if ($v_result < 1) { + unset($p_list); + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + + // -------------------------------------------------------------------------------- + // Function : + // extractByIndex($p_index, $p_path="./", $p_remove_path="") + // extractByIndex($p_index, [$p_option, $p_option_value, ...]) + // Description : + // This method supports two synopsis. The first one is historical. + // This method is doing a partial extract of the archive. + // The extracted files or folders are identified by their index in the + // archive (from 0 to n). + // Note that if the index identify a folder, only the folder entry is + // extracted, not all the files included in the archive. + // Parameters : + // $p_index : A single index (integer) or a string of indexes of files to + // extract. The form of the string is "0,4-6,8-12" with only numbers + // and '-' for range or ',' to separate ranges. No spaces or ';' + // are allowed. + // $p_path : Path where the files and directories are to be extracted + // $p_remove_path : First part ('root' part) of the memorized path + // (if any similar) to remove while extracting. + // Options : + // PCLZIP_OPT_PATH : + // PCLZIP_OPT_ADD_PATH : + // PCLZIP_OPT_REMOVE_PATH : + // PCLZIP_OPT_REMOVE_ALL_PATH : + // PCLZIP_OPT_EXTRACT_AS_STRING : The files are extracted as strings and + // not as files. + // The resulting content is in a new field 'content' in the file + // structure. + // This option must be used alone (any other options are ignored). + // PCLZIP_CB_PRE_EXTRACT : + // PCLZIP_CB_POST_EXTRACT : + // Return Values : + // 0 on failure, + // The list of the extracted files, with a status of the action. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + //function extractByIndex($p_index, options...) + function extractByIndex($p_index) + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); +// $v_path = "./"; + $v_path = ''; + $v_remove_path = ""; + $v_remove_all_path = false; + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Default values for option + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + + // ----- Look for arguments + if ($v_size > 1) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Remove form the options list the first argument + array_shift($v_arg_list); + $v_size--; + + // ----- Look for first arg + if ((is_integer($v_arg_list[0])) && ($v_arg_list[0] > 77000)) { + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_PATH => 'optional', + PCLZIP_OPT_REMOVE_PATH => 'optional', + PCLZIP_OPT_REMOVE_ALL_PATH => 'optional', + PCLZIP_OPT_EXTRACT_AS_STRING => 'optional', + PCLZIP_OPT_ADD_PATH => 'optional', + PCLZIP_CB_PRE_EXTRACT => 'optional', + PCLZIP_CB_POST_EXTRACT => 'optional', + PCLZIP_OPT_SET_CHMOD => 'optional', + PCLZIP_OPT_REPLACE_NEWER => 'optional' + ,PCLZIP_OPT_STOP_ON_ERROR => 'optional' + ,PCLZIP_OPT_EXTRACT_DIR_RESTRICTION => 'optional', + PCLZIP_OPT_TEMP_FILE_THRESHOLD => 'optional', + PCLZIP_OPT_TEMP_FILE_ON => 'optional', + PCLZIP_OPT_TEMP_FILE_OFF => 'optional' + )); + if ($v_result != 1) { + return 0; + } + + // ----- Set the arguments + if (isset($v_options[PCLZIP_OPT_PATH])) { + $v_path = $v_options[PCLZIP_OPT_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_PATH])) { + $v_remove_path = $v_options[PCLZIP_OPT_REMOVE_PATH]; + } + if (isset($v_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $v_remove_all_path = $v_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + if (isset($v_options[PCLZIP_OPT_ADD_PATH])) { + // ----- Check for '/' in last path char + if ((strlen($v_path) > 0) && (substr($v_path, -1) != '/')) { + $v_path .= '/'; + } + $v_path .= $v_options[PCLZIP_OPT_ADD_PATH]; + } + if (!isset($v_options[PCLZIP_OPT_EXTRACT_AS_STRING])) { + $v_options[PCLZIP_OPT_EXTRACT_AS_STRING] = FALSE; + } + else { + } + } + + // ----- Look for 2 args + // Here we need to support the first historic synopsis of the + // method. + else { + + // ----- Get the first argument + $v_path = $v_arg_list[0]; + + // ----- Look for the optional second argument + if ($v_size == 2) { + $v_remove_path = $v_arg_list[1]; + } + else if ($v_size > 2) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid number / type of arguments"); + + // ----- Return + return 0; + } + } + } + + // ----- Trace + + // ----- Trick + // Here I want to reuse extractByRule(), so I need to parse the $p_index + // with privParseOptions() + $v_arg_trick = array (PCLZIP_OPT_BY_INDEX, $p_index); + $v_options_trick = array(); + $v_result = $this->privParseOptions($v_arg_trick, sizeof($v_arg_trick), $v_options_trick, + array (PCLZIP_OPT_BY_INDEX => 'optional' )); + if ($v_result != 1) { + return 0; + } + $v_options[PCLZIP_OPT_BY_INDEX] = $v_options_trick[PCLZIP_OPT_BY_INDEX]; + + // ----- Look for default option values + $this->privOptionDefaultThreshold($v_options); + + // ----- Call the extracting fct + if (($v_result = $this->privExtractByRule($p_list, $v_path, $v_remove_path, $v_remove_all_path, $v_options)) < 1) { + return(0); + } + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : + // delete([$p_option, $p_option_value, ...]) + // Description : + // This method removes files from the archive. + // If no parameters are given, then all the archive is emptied. + // Parameters : + // None or optional arguments. + // Options : + // PCLZIP_OPT_BY_INDEX : + // PCLZIP_OPT_BY_NAME : + // PCLZIP_OPT_BY_EREG : + // PCLZIP_OPT_BY_PREG : + // Return Values : + // 0 on failure, + // The list of the files which are still present in the archive. + // (see PclZip::listContent() for list entry format) + // -------------------------------------------------------------------------------- + function delete() + { + $v_result=1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Set default values + $v_options = array(); + + // ----- Look for variable options arguments + $v_size = func_num_args(); + + // ----- Look for arguments + if ($v_size > 0) { + // ----- Get the arguments + $v_arg_list = func_get_args(); + + // ----- Parse the options + $v_result = $this->privParseOptions($v_arg_list, $v_size, $v_options, + array (PCLZIP_OPT_BY_NAME => 'optional', + PCLZIP_OPT_BY_EREG => 'optional', + PCLZIP_OPT_BY_PREG => 'optional', + PCLZIP_OPT_BY_INDEX => 'optional' )); + if ($v_result != 1) { + return 0; + } + } + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Call the delete fct + $v_list = array(); + if (($v_result = $this->privDeleteByRule($v_list, $v_options)) != 1) { + $this->privSwapBackMagicQuotes(); + unset($v_list); + return(0); + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : deleteByIndex() + // Description : + // ***** Deprecated ***** + // delete(PCLZIP_OPT_BY_INDEX, $p_index) should be prefered. + // -------------------------------------------------------------------------------- + function deleteByIndex($p_index) + { + + $p_list = $this->delete(PCLZIP_OPT_BY_INDEX, $p_index); + + // ----- Return + return $p_list; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : properties() + // Description : + // This method gives the properties of the archive. + // The properties are : + // nb : Number of files in the archive + // comment : Comment associated with the archive file + // status : not_exist, ok + // Parameters : + // None + // Return Values : + // 0 on failure, + // An array with the archive properties. + // -------------------------------------------------------------------------------- + function properties() + { + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + $this->privSwapBackMagicQuotes(); + return(0); + } + + // ----- Default properties + $v_prop = array(); + $v_prop['comment'] = ''; + $v_prop['nb'] = 0; + $v_prop['status'] = 'not_exist'; + + // ----- Look if file exists + if (@is_file($this->zipname)) + { + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) + { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + + // ----- Return + return 0; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + return 0; + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Set the user attributes + $v_prop['comment'] = $v_central_dir['comment']; + $v_prop['nb'] = $v_central_dir['entries']; + $v_prop['status'] = 'ok'; + } + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_prop; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : duplicate() + // Description : + // This method creates an archive by copying the content of an other one. If + // the archive already exist, it is replaced by the new one without any warning. + // Parameters : + // $p_archive : The filename of a valid archive, or + // a valid PclZip object. + // Return Values : + // 1 on success. + // 0 or a negative value on error (error code). + // -------------------------------------------------------------------------------- + function duplicate($p_archive) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the $p_archive is a PclZip object + if ((is_object($p_archive)) && (get_class($p_archive) == 'pclzip')) + { + + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive->zipname); + } + + // ----- Look if the $p_archive is a string (so a filename) + else if (is_string($p_archive)) + { + + // ----- Check that $p_archive is a valid zip file + // TBC : Should also check the archive format + if (!is_file($p_archive)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "No file with filename '".$p_archive."'"); + $v_result = PCLZIP_ERR_MISSING_FILE; + } + else { + // ----- Duplicate the archive + $v_result = $this->privDuplicate($p_archive); + } + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : merge() + // Description : + // This method merge the $p_archive_to_add archive at the end of the current + // one ($this). + // If the archive ($this) does not exist, the merge becomes a duplicate. + // If the $p_archive_to_add archive does not exist, the merge is a success. + // Parameters : + // $p_archive_to_add : It can be directly the filename of a valid zip archive, + // or a PclZip object archive. + // Return Values : + // 1 on success, + // 0 or negative values on error (see below). + // -------------------------------------------------------------------------------- + function merge($p_archive_to_add) + { + $v_result = 1; + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Check archive + if (!$this->privCheckFormat()) { + return(0); + } + + // ----- Look if the $p_archive_to_add is a PclZip object + if ((is_object($p_archive_to_add)) && (get_class($p_archive_to_add) == 'pclzip')) + { + + // ----- Merge the archive + $v_result = $this->privMerge($p_archive_to_add); + } + + // ----- Look if the $p_archive_to_add is a string (so a filename) + else if (is_string($p_archive_to_add)) + { + + // ----- Create a temporary archive + $v_object_archive = new PclZip($p_archive_to_add); + + // ----- Merge the archive + $v_result = $this->privMerge($v_object_archive); + } + + // ----- Invalid variable + else + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid variable type p_archive_to_add"); + $v_result = PCLZIP_ERR_INVALID_PARAMETER; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + + + // -------------------------------------------------------------------------------- + // Function : errorCode() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorCode() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return(PclErrorCode()); + } + else { + return($this->error_code); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorName() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorName($p_with_code=false) + { + $v_name = array ( PCLZIP_ERR_NO_ERROR => 'PCLZIP_ERR_NO_ERROR', + PCLZIP_ERR_WRITE_OPEN_FAIL => 'PCLZIP_ERR_WRITE_OPEN_FAIL', + PCLZIP_ERR_READ_OPEN_FAIL => 'PCLZIP_ERR_READ_OPEN_FAIL', + PCLZIP_ERR_INVALID_PARAMETER => 'PCLZIP_ERR_INVALID_PARAMETER', + PCLZIP_ERR_MISSING_FILE => 'PCLZIP_ERR_MISSING_FILE', + PCLZIP_ERR_FILENAME_TOO_LONG => 'PCLZIP_ERR_FILENAME_TOO_LONG', + PCLZIP_ERR_INVALID_ZIP => 'PCLZIP_ERR_INVALID_ZIP', + PCLZIP_ERR_BAD_EXTRACTED_FILE => 'PCLZIP_ERR_BAD_EXTRACTED_FILE', + PCLZIP_ERR_DIR_CREATE_FAIL => 'PCLZIP_ERR_DIR_CREATE_FAIL', + PCLZIP_ERR_BAD_EXTENSION => 'PCLZIP_ERR_BAD_EXTENSION', + PCLZIP_ERR_BAD_FORMAT => 'PCLZIP_ERR_BAD_FORMAT', + PCLZIP_ERR_DELETE_FILE_FAIL => 'PCLZIP_ERR_DELETE_FILE_FAIL', + PCLZIP_ERR_RENAME_FILE_FAIL => 'PCLZIP_ERR_RENAME_FILE_FAIL', + PCLZIP_ERR_BAD_CHECKSUM => 'PCLZIP_ERR_BAD_CHECKSUM', + PCLZIP_ERR_INVALID_ARCHIVE_ZIP => 'PCLZIP_ERR_INVALID_ARCHIVE_ZIP', + PCLZIP_ERR_MISSING_OPTION_VALUE => 'PCLZIP_ERR_MISSING_OPTION_VALUE', + PCLZIP_ERR_INVALID_OPTION_VALUE => 'PCLZIP_ERR_INVALID_OPTION_VALUE', + PCLZIP_ERR_UNSUPPORTED_COMPRESSION => 'PCLZIP_ERR_UNSUPPORTED_COMPRESSION', + PCLZIP_ERR_UNSUPPORTED_ENCRYPTION => 'PCLZIP_ERR_UNSUPPORTED_ENCRYPTION' + ,PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE => 'PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE' + ,PCLZIP_ERR_DIRECTORY_RESTRICTION => 'PCLZIP_ERR_DIRECTORY_RESTRICTION' + ); + + if (isset($v_name[$this->error_code])) { + $v_value = $v_name[$this->error_code]; + } + else { + $v_value = 'NoName'; + } + + if ($p_with_code) { + return($v_value.' ('.$this->error_code.')'); + } + else { + return($v_value); + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : errorInfo() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function errorInfo($p_full=false) + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + return(PclErrorString()); + } + else { + if ($p_full) { + return($this->errorName(true)." : ".$this->error_string); + } + else { + return($this->error_string." [code ".$this->error_code."]"); + } + } + } + // -------------------------------------------------------------------------------- + + +// -------------------------------------------------------------------------------- +// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** +// ***** ***** +// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** +// -------------------------------------------------------------------------------- + + + + // -------------------------------------------------------------------------------- + // Function : privCheckFormat() + // Description : + // This method check that the archive exists and is a valid zip archive. + // Several level of check exists. (futur) + // Parameters : + // $p_level : Level of check. Default 0. + // 0 : Check the first bytes (magic codes) (default value)) + // 1 : 0 + Check the central directory (futur) + // 2 : 1 + Check each file header (futur) + // Return Values : + // true on success, + // false on error, the error code is set. + // -------------------------------------------------------------------------------- + function privCheckFormat($p_level=0) + { + $v_result = true; + + // ----- Reset the file system cache + clearstatcache(); + + // ----- Reset the error handler + $this->privErrorReset(); + + // ----- Look if the file exits + if (!is_file($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_FILE, "Missing archive file '".$this->zipname."'"); + return(false); + } + + // ----- Check that the file is readeable + if (!is_readable($this->zipname)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to read archive '".$this->zipname."'"); + return(false); + } + + // ----- Check the magic code + // TBC + + // ----- Check the central header + // TBC + + // ----- Check each file header + // TBC + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privParseOptions() + // Description : + // This internal methods reads the variable list of arguments ($p_options_list, + // $p_size) and generate an array with the options and values ($v_result_list). + // $v_requested_options contains the options that can be present and those that + // must be present. + // $v_requested_options is an array, with the option value as key, and 'optional', + // or 'mandatory' as value. + // Parameters : + // See above. + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privParseOptions(&$p_options_list, $p_size, &$v_result_list, $v_requested_options=false) + { + $v_result=1; + + // ----- Read the options + $i=0; + while ($i<$p_size) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$p_options_list[$i]])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid optional parameter '".$p_options_list[$i]."' for this method"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for next option + switch ($p_options_list[$i]) { + // ----- Look for options that request a path value + case PCLZIP_OPT_PATH : + case PCLZIP_OPT_REMOVE_PATH : + case PCLZIP_OPT_ADD_PATH : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_THRESHOLD : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } + + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + return PclZip::errorCode(); + } + + // ----- Check the value + $v_value = $p_options_list[$i+1]; + if ((!is_integer($v_value)) || ($v_value<0)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Integer expected for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + return PclZip::errorCode(); + } + + // ----- Get the value (and convert it in bytes) + $v_result_list[$p_options_list[$i]] = $v_value*1048576; + $i++; + break; + + case PCLZIP_OPT_TEMP_FILE_ON : + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_OFF])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_OFF'"); + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_TEMP_FILE_OFF : + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_ON])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_ON'"); + return PclZip::errorCode(); + } + // ----- Check for incompatible options + if (isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Option '".PclZipUtilOptionText($p_options_list[$i])."' can not be used with option 'PCLZIP_OPT_TEMP_FILE_THRESHOLD'"); + return PclZip::errorCode(); + } + + $v_result_list[$p_options_list[$i]] = true; + break; + + case PCLZIP_OPT_EXTRACT_DIR_RESTRICTION : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if ( is_string($p_options_list[$i+1]) + && ($p_options_list[$i+1] != '')) { + $v_result_list[$p_options_list[$i]] = PclZipUtilTranslateWinPath($p_options_list[$i+1], FALSE); + $i++; + } + else { + } + break; + + // ----- Look for options that request an array of string for value + case PCLZIP_OPT_BY_NAME : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]][0] = $p_options_list[$i+1]; + } + else if (is_array($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an EREG or PREG expression + case PCLZIP_OPT_BY_EREG : + // ereg() is deprecated starting with PHP 5.3. Move PCLZIP_OPT_BY_EREG + // to PCLZIP_OPT_BY_PREG + $p_options_list[$i] = PCLZIP_OPT_BY_PREG; + case PCLZIP_OPT_BY_PREG : + //case PCLZIP_OPT_CRYPT : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Wrong parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that takes a string + case PCLZIP_OPT_COMMENT : + case PCLZIP_OPT_ADD_COMMENT : + case PCLZIP_OPT_PREPEND_COMMENT : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, + "Missing parameter value for option '" + .PclZipUtilOptionText($p_options_list[$i]) + ."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + if (is_string($p_options_list[$i+1])) { + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, + "Wrong parameter value for option '" + .PclZipUtilOptionText($p_options_list[$i]) + ."'"); + + // ----- Return + return PclZip::errorCode(); + } + $i++; + break; + + // ----- Look for options that request an array of index + case PCLZIP_OPT_BY_INDEX : + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_work_list = array(); + if (is_string($p_options_list[$i+1])) { + + // ----- Remove spaces + $p_options_list[$i+1] = strtr($p_options_list[$i+1], ' ', ''); + + // ----- Parse items + $v_work_list = explode(",", $p_options_list[$i+1]); + } + else if (is_integer($p_options_list[$i+1])) { + $v_work_list[0] = $p_options_list[$i+1].'-'.$p_options_list[$i+1]; + } + else if (is_array($p_options_list[$i+1])) { + $v_work_list = $p_options_list[$i+1]; + } + else { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Value must be integer, string or array for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Reduce the index list + // each index item in the list must be a couple with a start and + // an end value : [0,3], [5-5], [8-10], ... + // ----- Check the format of each item + $v_sort_flag=false; + $v_sort_value=0; + for ($j=0; $j= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_result_list[$p_options_list[$i]] = $p_options_list[$i+1]; + $i++; + break; + + // ----- Look for options that request a call-back + case PCLZIP_CB_PRE_EXTRACT : + case PCLZIP_CB_POST_EXTRACT : + case PCLZIP_CB_PRE_ADD : + case PCLZIP_CB_POST_ADD : + /* for futur use + case PCLZIP_CB_PRE_DELETE : + case PCLZIP_CB_POST_DELETE : + case PCLZIP_CB_PRE_LIST : + case PCLZIP_CB_POST_LIST : + */ + // ----- Check the number of parameters + if (($i+1) >= $p_size) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_MISSING_OPTION_VALUE, "Missing parameter value for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Get the value + $v_function_name = $p_options_list[$i+1]; + + // ----- Check that the value is a valid existing function + if (!function_exists($v_function_name)) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_OPTION_VALUE, "Function '".$v_function_name."()' is not an existing function for option '".PclZipUtilOptionText($p_options_list[$i])."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Set the attribute + $v_result_list[$p_options_list[$i]] = $v_function_name; + $i++; + break; + + default : + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Unknown parameter '" + .$p_options_list[$i]."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Next options + $i++; + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($v_result_list[$key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + + // ----- Return + return PclZip::errorCode(); + } + } + } + } + + // ----- Look for default values + if (!isset($v_result_list[PCLZIP_OPT_TEMP_FILE_THRESHOLD])) { + + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOptionDefaultThreshold() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privOptionDefaultThreshold(&$p_options) + { + $v_result=1; + + if (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + || isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) { + return $v_result; + } + + // ----- Get 'memory_limit' configuration value + $v_memory_limit = ini_get('memory_limit'); + $v_memory_limit = trim($v_memory_limit); + $last = strtolower(substr($v_memory_limit, -1)); + + if($last == 'g') + //$v_memory_limit = $v_memory_limit*1024*1024*1024; + $v_memory_limit = $v_memory_limit*1073741824; + if($last == 'm') + //$v_memory_limit = $v_memory_limit*1024*1024; + $v_memory_limit = $v_memory_limit*1048576; + if($last == 'k') + $v_memory_limit = $v_memory_limit*1024; + + $p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] = floor($v_memory_limit*PCLZIP_TEMPORARY_FILE_RATIO); + + + // ----- Sanity check : No threshold if value lower than 1M + if ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] < 1048576) { + unset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrParseAtt() + // Description : + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privFileDescrParseAtt(&$p_file_list, &$p_filedescr, $v_options, $v_requested_options=false) + { + $v_result=1; + + // ----- For each file in the list check the attributes + foreach ($p_file_list as $v_key => $v_value) { + + // ----- Check if the option is supported + if (!isset($v_requested_options[$v_key])) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file attribute '".$v_key."' for this file"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for attribute + switch ($v_key) { + case PCLZIP_ATT_FILE_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['filename'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['filename'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + break; + + case PCLZIP_ATT_FILE_NEW_SHORT_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['new_short_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_short_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty short filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + break; + + case PCLZIP_ATT_FILE_NEW_FULL_NAME : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['new_full_name'] = PclZipUtilPathReduction($v_value); + + if ($p_filedescr['new_full_name'] == '') { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid empty full filename for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + break; + + // ----- Look for options that takes a string + case PCLZIP_ATT_FILE_COMMENT : + if (!is_string($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". String expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['comment'] = $v_value; + break; + + case PCLZIP_ATT_FILE_MTIME : + if (!is_integer($v_value)) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ATTRIBUTE_VALUE, "Invalid type ".gettype($v_value).". Integer expected for attribute '".PclZipUtilOptionText($v_key)."'"); + return PclZip::errorCode(); + } + + $p_filedescr['mtime'] = $v_value; + break; + + case PCLZIP_ATT_FILE_CONTENT : + $p_filedescr['content'] = $v_value; + break; + + default : + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, + "Unknown parameter '".$v_key."'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for mandatory options + if ($v_requested_options !== false) { + for ($key=reset($v_requested_options); $key=key($v_requested_options); $key=next($v_requested_options)) { + // ----- Look for mandatory option + if ($v_requested_options[$key] == 'mandatory') { + // ----- Look if present + if (!isset($p_file_list[$key])) { + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Missing mandatory parameter ".PclZipUtilOptionText($key)."(".$key.")"); + return PclZip::errorCode(); + } + } + } + } + + // end foreach + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privFileDescrExpand() + // Description : + // This method look for each item of the list to see if its a file, a folder + // or a string to be added as file. For any other type of files (link, other) + // just ignore the item. + // Then prepare the information that will be stored for that file. + // When its a folder, expand the folder with all the files that are in that + // folder (recursively). + // Parameters : + // Return Values : + // 1 on success. + // 0 on failure. + // -------------------------------------------------------------------------------- + function privFileDescrExpand(&$p_filedescr_list, &$p_options) + { + $v_result=1; + + // ----- Create a result list + $v_result_list = array(); + + // ----- Look each entry + for ($i=0; $iprivCalculateStoredFilename($v_descr, $p_options); + + // ----- Add the descriptor in result list + $v_result_list[sizeof($v_result_list)] = $v_descr; + + // ----- Look for folder + if ($v_descr['type'] == 'folder') { + // ----- List of items in folder + $v_dirlist_descr = array(); + $v_dirlist_nb = 0; + if ($v_folder_handler = @opendir($v_descr['filename'])) { + while (($v_item_handler = @readdir($v_folder_handler)) !== false) { + + // ----- Skip '.' and '..' + if (($v_item_handler == '.') || ($v_item_handler == '..')) { + continue; + } + + // ----- Compose the full filename + $v_dirlist_descr[$v_dirlist_nb]['filename'] = $v_descr['filename'].'/'.$v_item_handler; + + // ----- Look for different stored filename + // Because the name of the folder was changed, the name of the + // files/sub-folders also change + if (($v_descr['stored_filename'] != $v_descr['filename']) + && (!isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH]))) { + if ($v_descr['stored_filename'] != '') { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_descr['stored_filename'].'/'.$v_item_handler; + } + else { + $v_dirlist_descr[$v_dirlist_nb]['new_full_name'] = $v_item_handler; + } + } + + $v_dirlist_nb++; + } + + @closedir($v_folder_handler); + } + else { + // TBC : unable to open folder in read mode + } + + // ----- Expand each element of the list + if ($v_dirlist_nb != 0) { + // ----- Expand + if (($v_result = $this->privFileDescrExpand($v_dirlist_descr, $p_options)) != 1) { + return $v_result; + } + + // ----- Concat the resulting list + $v_result_list = array_merge($v_result_list, $v_dirlist_descr); + } + else { + } + + // ----- Free local array + unset($v_dirlist_descr); + } + } + + // ----- Get the result list + $p_filedescr_list = $v_result_list; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCreate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privCreate($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the file in write mode + if (($v_result = $this->privOpenFd('wb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Add the list of files + $v_result = $this->privAddList($p_filedescr_list, $p_result_list, $p_options); + + // ----- Close + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAdd() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAdd($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Look if the archive exists or is empty + if ((!is_file($this->zipname)) || (filesize($this->zipname) == 0)) + { + + // ----- Do a create + $v_result = $this->privCreate($p_filedescr_list, $p_result_list, $p_options); + + // ----- Return + return $v_result; + } + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) + { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) + { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Create the Central Dir files header + for ($i=0, $v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + fclose($v_zip_temp_fd); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = $v_central_dir['comment']; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_ADD_COMMENT])) { + $v_comment = $v_comment.$p_options[PCLZIP_OPT_ADD_COMMENT]; + } + if (isset($p_options[PCLZIP_OPT_PREPEND_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_PREPEND_COMMENT].$v_comment; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count+$v_central_dir['entries'], $v_size, $v_offset, $v_comment)) != 1) + { + // ----- Reset the file list + unset($v_header_list); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privOpenFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privOpenFd($p_mode) + { + $v_result=1; + + // ----- Look if already open + if ($this->zip_fd != 0) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Zip file \''.$this->zipname.'\' already open'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, $p_mode)) == 0) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in '.$p_mode.' mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCloseFd() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privCloseFd() + { + $v_result=1; + + if ($this->zip_fd != 0) + @fclose($this->zip_fd); + $this->zip_fd = 0; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddList() + // Description : + // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is + // different from the real path of the file. This is usefull if you want to have PclTar + // running in any directory, and memorize relative path from an other directory. + // Parameters : + // $p_list : An array containing the file or directory names to add in the tar + // $p_result_list : list of added files with their properties (specially the status field) + // $p_add_dir : Path to add in the filename path archived + // $p_remove_dir : Path to remove in the filename path archived + // Return Values : + // -------------------------------------------------------------------------------- +// function privAddList($p_list, &$p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_options) + function privAddList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + + // ----- Add the files + $v_header_list = array(); + if (($v_result = $this->privAddFileList($p_filedescr_list, $v_header_list, $p_options)) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($this->zip_fd); + + // ----- Create the Central Dir files header + for ($i=0,$v_count=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + // ----- Return + return $v_result; + } + $v_count++; + } + + // ----- Transform the header to a 'usable' info + $this->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($this->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_count, $v_size, $v_offset, $v_comment)) != 1) + { + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileList() + // Description : + // Parameters : + // $p_filedescr_list : An array containing the file description + // or directory names to add in the zip + // $p_result_list : list of added files with their properties (specially the status field) + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFileList($p_filedescr_list, &$p_result_list, &$p_options) + { + $v_result=1; + $v_header = array(); + + // ----- Recuperate the current number of elt in list + $v_nb = sizeof($p_result_list); + + // ----- Loop on the files + for ($j=0; ($jprivAddFile($p_filedescr_list[$j], $v_header, + $p_options); + if ($v_result != 1) { + return $v_result; + } + + // ----- Store the file infos + $p_result_list[$v_nb++] = $v_header; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFile($p_filedescr, &$p_header, &$p_options) + { + $v_result=1; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + // TBC : Already done in the fileAtt check ... ? + if ($p_filename == "") { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for a stored different filename + /* TBC : Removed + if (isset($p_filedescr['stored_filename'])) { + $v_stored_filename = $p_filedescr['stored_filename']; + } + else { + $v_stored_filename = $p_filedescr['stored_filename']; + } + */ + + // ----- Set the file properties + clearstatcache(); + $p_header['version'] = 20; + $p_header['version_extracted'] = 10; + $p_header['flag'] = 0; + $p_header['compression'] = 0; + $p_header['crc'] = 0; + $p_header['compressed_size'] = 0; + $p_header['filename_len'] = strlen($p_filename); + $p_header['extra_len'] = 0; + $p_header['disk'] = 0; + $p_header['internal'] = 0; + $p_header['offset'] = 0; + $p_header['filename'] = $p_filename; +// TBC : Removed $p_header['stored_filename'] = $v_stored_filename; + $p_header['stored_filename'] = $p_filedescr['stored_filename']; + $p_header['extra'] = ''; + $p_header['status'] = 'ok'; + $p_header['index'] = -1; + + // ----- Look for regular file + if ($p_filedescr['type']=='file') { + $p_header['external'] = 0x00000000; + $p_header['size'] = filesize($p_filename); + } + + // ----- Look for regular folder + else if ($p_filedescr['type']=='folder') { + $p_header['external'] = 0x00000010; + $p_header['mtime'] = filemtime($p_filename); + $p_header['size'] = filesize($p_filename); + } + + // ----- Look for virtual file + else if ($p_filedescr['type'] == 'virtual_file') { + $p_header['external'] = 0x00000000; + $p_header['size'] = strlen($p_filedescr['content']); + } + + + // ----- Look for filetime + if (isset($p_filedescr['mtime'])) { + $p_header['mtime'] = $p_filedescr['mtime']; + } + else if ($p_filedescr['type'] == 'virtual_file') { + $p_header['mtime'] = time(); + } + else { + $p_header['mtime'] = filemtime($p_filename); + } + + // ------ Look for file comment + if (isset($p_filedescr['comment'])) { + $p_header['comment_len'] = strlen($p_filedescr['comment']); + $p_header['comment'] = $p_filedescr['comment']; + } + else { + $p_header['comment_len'] = 0; + $p_header['comment'] = ''; + } + + // ----- Look for pre-add callback + if (isset($p_options[PCLZIP_CB_PRE_ADD])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_ADD].'(PCLZIP_CB_PRE_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_ADD](PCLZIP_CB_PRE_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_header['status'] = "skipped"; + $v_result = 1; + } + + // ----- Update the informations + // Only some fields can be modified + if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { + $p_header['stored_filename'] = PclZipUtilPathReduction($v_local_header['stored_filename']); + } + } + + // ----- Look for empty stored filename + if ($p_header['stored_filename'] == "") { + $p_header['status'] = "filtered"; + } + + // ----- Check the path length + if (strlen($p_header['stored_filename']) > 0xFF) { + $p_header['status'] = 'filename_too_long'; + } + + // ----- Look if no error, or file not skipped + if ($p_header['status'] == 'ok') { + + // ----- Look for a file + if ($p_filedescr['type'] == 'file') { + // ----- Look for using temporary file to zip + if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) + && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) + || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_header['size'])) ) ) { + $v_result = $this->privAddFileUsingTempFile($p_filedescr, $p_header, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + } + + // ----- Use "in memory" zip algo + else { + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + return PclZip::errorCode(); + } + + // ----- Read the file content + $v_content = @fread($v_file, $p_header['size']); + + // ----- Close the file + @fclose($v_file); + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + } + + // ----- Look for normal compression + else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + + } + + } + + // ----- Look for a virtual file (a file from string) + else if ($p_filedescr['type'] == 'virtual_file') { + + $v_content = $p_filedescr['content']; + + // ----- Calculate the CRC + $p_header['crc'] = @crc32($v_content); + + // ----- Look for no compression + if ($p_options[PCLZIP_OPT_NO_COMPRESSION]) { + // ----- Set header parameters + $p_header['compressed_size'] = $p_header['size']; + $p_header['compression'] = 0; + } + + // ----- Look for normal compression + else { + // ----- Compress the content + $v_content = @gzdeflate($v_content); + + // ----- Set header parameters + $p_header['compressed_size'] = strlen($v_content); + $p_header['compression'] = 8; + } + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + @fclose($v_file); + return $v_result; + } + + // ----- Write the compressed (or not) content + @fwrite($this->zip_fd, $v_content, $p_header['compressed_size']); + } + + // ----- Look for a directory + else if ($p_filedescr['type'] == 'folder') { + // ----- Look for directory last '/' + if (@substr($p_header['stored_filename'], -1) != '/') { + $p_header['stored_filename'] .= '/'; + } + + // ----- Set the file properties + $p_header['size'] = 0; + //$p_header['external'] = 0x41FF0010; // Value for a folder : to be checked + $p_header['external'] = 0x00000010; // Value for a folder : to be checked + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) + { + return $v_result; + } + } + } + + // ----- Look for post-add callback + if (isset($p_options[PCLZIP_CB_POST_ADD])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_header, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_ADD].'(PCLZIP_CB_POST_ADD, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_ADD](PCLZIP_CB_POST_ADD, $v_local_header); + if ($v_result == 0) { + // ----- Ignored + $v_result = 1; + } + + // ----- Update the informations + // Nothing can be modified + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privAddFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privAddFileUsingTempFile($p_filedescr, &$p_header, &$p_options) + { + $v_result=PCLZIP_ERR_NO_ERROR; + + // ----- Working variable + $p_filename = $p_filedescr['filename']; + + + // ----- Open the source file + if (($v_file = @fopen($p_filename, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); + return PclZip::errorCode(); + } + + // ----- Creates a compressed temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; + if (($v_file_compressed = @gzopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); + return PclZip::errorCode(); + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = filesize($p_filename); + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @gzputs($v_file_compressed, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close the file + @fclose($v_file); + @gzclose($v_file_compressed); + + // ----- Check the minimum file size + if (filesize($v_gzip_temp_name) < 18) { + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'gzip temporary file \''.$v_gzip_temp_name.'\' has invalid filesize - should be minimum 18 bytes'); + return PclZip::errorCode(); + } + + // ----- Extract the compressed attributes + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + // ----- Read the gzip file header + $v_binary_data = @fread($v_file_compressed, 10); + $v_data_header = unpack('a1id1/a1id2/a1cm/a1flag/Vmtime/a1xfl/a1os', $v_binary_data); + + // ----- Check some parameters + $v_data_header['os'] = bin2hex($v_data_header['os']); + + // ----- Read the gzip file footer + @fseek($v_file_compressed, filesize($v_gzip_temp_name)-8); + $v_binary_data = @fread($v_file_compressed, 8); + $v_data_footer = unpack('Vcrc/Vcompressed_size', $v_binary_data); + + // ----- Set the attributes + $p_header['compression'] = ord($v_data_header['cm']); + //$p_header['mtime'] = $v_data_header['mtime']; + $p_header['crc'] = $v_data_footer['crc']; + $p_header['compressed_size'] = filesize($v_gzip_temp_name)-18; + + // ----- Close the file + @fclose($v_file_compressed); + + // ----- Call the header generation + if (($v_result = $this->privWriteFileHeader($p_header)) != 1) { + return $v_result; + } + + // ----- Add the compressed data + if (($v_file_compressed = @fopen($v_gzip_temp_name, "rb")) == 0) + { + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + fseek($v_file_compressed, 10); + $v_size = $p_header['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($v_file_compressed, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close the file + @fclose($v_file_compressed); + + // ----- Unlink the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCalculateStoredFilename() + // Description : + // Based on file descriptor properties and global options, this method + // calculate the filename that will be stored in the archive. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privCalculateStoredFilename(&$p_filedescr, &$p_options) + { + $v_result=1; + + // ----- Working variables + $p_filename = $p_filedescr['filename']; + if (isset($p_options[PCLZIP_OPT_ADD_PATH])) { + $p_add_dir = $p_options[PCLZIP_OPT_ADD_PATH]; + } + else { + $p_add_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_PATH])) { + $p_remove_dir = $p_options[PCLZIP_OPT_REMOVE_PATH]; + } + else { + $p_remove_dir = ''; + } + if (isset($p_options[PCLZIP_OPT_REMOVE_ALL_PATH])) { + $p_remove_all_dir = $p_options[PCLZIP_OPT_REMOVE_ALL_PATH]; + } + else { + $p_remove_all_dir = 0; + } + + + // ----- Look for full name change + if (isset($p_filedescr['new_full_name'])) { + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($p_filedescr['new_full_name']); + } + + // ----- Look for path and/or short name change + else { + + // ----- Look for short name change + // Its when we cahnge just the filename but not the path + if (isset($p_filedescr['new_short_name'])) { + $v_path_info = pathinfo($p_filename); + $v_dir = ''; + if ($v_path_info['dirname'] != '') { + $v_dir = $v_path_info['dirname'].'/'; + } + $v_stored_filename = $v_dir.$p_filedescr['new_short_name']; + } + else { + // ----- Calculate the stored filename + $v_stored_filename = $p_filename; + } + + // ----- Look for all path to remove + if ($p_remove_all_dir) { + $v_stored_filename = basename($p_filename); + } + // ----- Look for partial path remove + else if ($p_remove_dir != "") { + if (substr($p_remove_dir, -1) != '/') + $p_remove_dir .= "/"; + + if ( (substr($p_filename, 0, 2) == "./") + || (substr($p_remove_dir, 0, 2) == "./")) { + + if ( (substr($p_filename, 0, 2) == "./") + && (substr($p_remove_dir, 0, 2) != "./")) { + $p_remove_dir = "./".$p_remove_dir; + } + if ( (substr($p_filename, 0, 2) != "./") + && (substr($p_remove_dir, 0, 2) == "./")) { + $p_remove_dir = substr($p_remove_dir, 2); + } + } + + $v_compare = PclZipUtilPathInclusion($p_remove_dir, + $v_stored_filename); + if ($v_compare > 0) { + if ($v_compare == 2) { + $v_stored_filename = ""; + } + else { + $v_stored_filename = substr($v_stored_filename, + strlen($p_remove_dir)); + } + } + } + + // ----- Remove drive letter if any + $v_stored_filename = PclZipUtilTranslateWinPath($v_stored_filename); + + // ----- Look for path to add + if ($p_add_dir != "") { + if (substr($p_add_dir, -1) == "/") + $v_stored_filename = $p_add_dir.$v_stored_filename; + else + $v_stored_filename = $p_add_dir."/".$v_stored_filename; + } + } + + // ----- Filename (reduce the path of stored name) + $v_stored_filename = PclZipUtilPathReduction($v_stored_filename); + $p_filedescr['stored_filename'] = $v_stored_filename; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteFileHeader(&$p_header) + { + $v_result=1; + + // ----- Store the offset position of the file + $p_header['offset'] = ftell($this->zip_fd); + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + // ----- Packed data + $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, + $p_header['version_extracted'], $p_header['flag'], + $p_header['compression'], $v_mtime, $v_mdate, + $p_header['crc'], $p_header['compressed_size'], + $p_header['size'], + strlen($p_header['stored_filename']), + $p_header['extra_len']); + + // ----- Write the first 148 bytes of the header in the archive + fputs($this->zip_fd, $v_binary_data, 30); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralFileHeader(&$p_header) + { + $v_result=1; + + // TBC + //for(reset($p_header); $key = key($p_header); next($p_header)) { + //} + + // ----- Transform UNIX mtime to DOS format mdate/mtime + $v_date = getdate($p_header['mtime']); + $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; + $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + + + // ----- Packed data + $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, + $p_header['version'], $p_header['version_extracted'], + $p_header['flag'], $p_header['compression'], + $v_mtime, $v_mdate, $p_header['crc'], + $p_header['compressed_size'], $p_header['size'], + strlen($p_header['stored_filename']), + $p_header['extra_len'], $p_header['comment_len'], + $p_header['disk'], $p_header['internal'], + $p_header['external'], $p_header['offset']); + + // ----- Write the 42 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 46); + + // ----- Write the variable fields + if (strlen($p_header['stored_filename']) != 0) + { + fputs($this->zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); + } + if ($p_header['extra_len'] != 0) + { + fputs($this->zip_fd, $p_header['extra'], $p_header['extra_len']); + } + if ($p_header['comment_len'] != 0) + { + fputs($this->zip_fd, $p_header['comment'], $p_header['comment_len']); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privWriteCentralHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privWriteCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) + { + $v_result=1; + + // ----- Packed data + $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, + $p_nb_entries, $p_size, + $p_offset, strlen($p_comment)); + + // ----- Write the 22 bytes of the header in the zip file + fputs($this->zip_fd, $v_binary_data, 22); + + // ----- Write the variable fields + if (strlen($p_comment) != 0) + { + fputs($this->zip_fd, $p_comment, strlen($p_comment)); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privList() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privList(&$p_list) + { + $v_result=1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Open the zip file + if (($this->zip_fd = @fopen($this->zipname, 'rb')) == 0) + { + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->zipname.'\' in binary read mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Go to beginning of Central Dir + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_central_dir['offset'])) + { + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read each entry + for ($i=0; $i<$v_central_dir['entries']; $i++) + { + // ----- Read the file header + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + $v_header['index'] = $i; + + // ----- Get the only interesting attributes + $this->privConvertHeader2FileInfo($v_header, $p_list[$i]); + unset($v_header); + } + + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Magic quotes trick + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privConvertHeader2FileInfo() + // Description : + // This function takes the file informations from the central directory + // entries and extract the interesting parameters that will be given back. + // The resulting file infos are set in the array $p_info + // $p_info['filename'] : Filename with full path. Given by user (add), + // extracted in the filesystem (extract). + // $p_info['stored_filename'] : Stored filename in the archive. + // $p_info['size'] = Size of the file. + // $p_info['compressed_size'] = Compressed size of the file. + // $p_info['mtime'] = Last modification date of the file. + // $p_info['comment'] = Comment associated with the file. + // $p_info['folder'] = true/false : indicates if the entry is a folder or not. + // $p_info['status'] = status of the action on the file. + // $p_info['crc'] = CRC of the file content. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privConvertHeader2FileInfo($p_header, &$p_info) + { + $v_result=1; + + // ----- Get the interesting attributes + $v_temp_path = PclZipUtilPathReduction($p_header['filename']); + $p_info['filename'] = $v_temp_path; + $v_temp_path = PclZipUtilPathReduction($p_header['stored_filename']); + $p_info['stored_filename'] = $v_temp_path; + $p_info['size'] = $p_header['size']; + $p_info['compressed_size'] = $p_header['compressed_size']; + $p_info['mtime'] = $p_header['mtime']; + $p_info['comment'] = $p_header['comment']; + $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); + $p_info['index'] = $p_header['index']; + $p_info['status'] = $p_header['status']; + $p_info['crc'] = $p_header['crc']; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractByRule() + // Description : + // Extract a file or directory depending of rules (by index, by name, ...) + // Parameters : + // $p_file_list : An array where will be placed the properties of each + // extracted file + // $p_path : Path to add while writing the extracted files + // $p_remove_path : Path to remove (from the file memorized path) while writing the + // extracted files. If the path does not match the file path, + // the file is extracted with its memorized path. + // $p_remove_path does not apply to 'list' mode. + // $p_path and $p_remove_path are commulative. + // Return Values : + // 1 on success,0 or less on error (see error code list) + // -------------------------------------------------------------------------------- + function privExtractByRule(&$p_file_list, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result=1; + + // ----- Magic quotes trick + $this->privDisableMagicQuotes(); + + // ----- Check the path + if ( ($p_path == "") + || ( (substr($p_path, 0, 1) != "/") + && (substr($p_path, 0, 3) != "../") + && (substr($p_path,1,2)!=":/"))) + $p_path = "./".$p_path; + + // ----- Reduce the path last (and duplicated) '/' + if (($p_path != "./") && ($p_path != "/")) + { + // ----- Look for the path end '/' + while (substr($p_path, -1) == "/") + { + $p_path = substr($p_path, 0, strlen($p_path)-1); + } + } + + // ----- Look for path to remove format (should end by /) + if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) + { + $p_remove_path .= '/'; + } + $p_remove_path_size = strlen($p_remove_path); + + // ----- Open the zip file + if (($v_result = $this->privOpenFd('rb')) != 1) + { + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + + // ----- Read each entry + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) + { + + // ----- Read next Central dir entry + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header)) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Store the index + $v_header['index'] = $i; + + // ----- Store the file position + $v_pos_entry = ftell($this->zip_fd); + + // ----- Look for the specific extract rules + $v_extract = false; + + // ----- Look for extract by name rule + if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) + && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) + && (substr($v_header['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_extract = true; + } + } + // ----- Look for a filename + elseif ($v_header['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_extract = true; + } + } + } + + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + */ + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header['stored_filename'])) { + $v_extract = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) + && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_extract = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + break; + } + } + } + + // ----- Look for no rule, which means extract all the archive + else { + $v_extract = true; + } + + // ----- Check compression method + if ( ($v_extract) + && ( ($v_header['compression'] != 8) + && ($v_header['compression'] != 0))) { + $v_header['status'] = 'unsupported_compression'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_COMPRESSION, + "Filename '".$v_header['stored_filename']."' is " + ."compressed by an unsupported compression " + ."method (".$v_header['compression'].") "); + + return PclZip::errorCode(); + } + } + + // ----- Check encrypted files + if (($v_extract) && (($v_header['flag'] & 1) == 1)) { + $v_header['status'] = 'unsupported_encryption'; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + $this->privSwapBackMagicQuotes(); + + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, + "Unsupported encryption for " + ." filename '".$v_header['stored_filename'] + ."'"); + + return PclZip::errorCode(); + } + } + + // ----- Look for real extraction + if (($v_extract) && ($v_header['status'] != 'ok')) { + $v_result = $this->privConvertHeader2FileInfo($v_header, + $p_file_list[$v_nb_extracted++]); + if ($v_result != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + $v_extract = false; + } + + // ----- Look for real extraction + if ($v_extract) + { + + // ----- Go to the file position + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_header['offset'])) + { + // ----- Close the zip file + $this->privCloseFd(); + + $this->privSwapBackMagicQuotes(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Look for extraction as string + if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) { + + $v_string = ''; + + // ----- Extracting the file + $v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Set the file content + $p_file_list[$v_nb_extracted]['content'] = $v_string; + + // ----- Next extracted file + $v_nb_extracted++; + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + // ----- Look for extraction in standard output + elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) + && ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) { + // ----- Extracting the file in standard output + $v_result1 = $this->privExtractFileInOutput($v_header, $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + // ----- Look for normal extraction + else { + // ----- Extracting the file + $v_result1 = $this->privExtractFile($v_header, + $p_path, $p_remove_path, + $p_remove_all_path, + $p_options); + if ($v_result1 < 1) { + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + return $v_result1; + } + + // ----- Get the only interesting attributes + if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + return $v_result; + } + + // ----- Look for user callback abort + if ($v_result1 == 2) { + break; + } + } + } + } + + // ----- Close the zip file + $this->privCloseFd(); + $this->privSwapBackMagicQuotes(); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFile() + // Description : + // Parameters : + // Return Values : + // + // 1 : ... ? + // PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback + // -------------------------------------------------------------------------------- + function privExtractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_options) + { + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for all path to remove + if ($p_remove_all_path == true) { + // ----- Look for folder entry that not need to be extracted + if (($p_entry['external']&0x00000010)==0x00000010) { + + $p_entry['status'] = "filtered"; + + return $v_result; + } + + // ----- Get the basename of the path + $p_entry['filename'] = basename($p_entry['filename']); + } + + // ----- Look for path to remove + else if ($p_remove_path != "") + { + if (PclZipUtilPathInclusion($p_remove_path, $p_entry['filename']) == 2) + { + + // ----- Change the file status + $p_entry['status'] = "filtered"; + + // ----- Return + return $v_result; + } + + $p_remove_path_size = strlen($p_remove_path); + if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) + { + + // ----- Remove the path + $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); + + } + } + + // ----- Add the path + if ($p_path != '') { + $p_entry['filename'] = $p_path."/".$p_entry['filename']; + } + + // ----- Check a base_dir_restriction + if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) { + $v_inclusion + = PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION], + $p_entry['filename']); + if ($v_inclusion == 0) { + + PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION, + "Filename '".$p_entry['filename']."' is " + ."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION"); + + return PclZip::errorCode(); + } + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Look for specific actions while the file exist + if (file_exists($p_entry['filename'])) + { + + // ----- Look if file is a directory + if (is_dir($p_entry['filename'])) + { + + // ----- Change the file status + $p_entry['status'] = "already_a_directory"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY, + "Filename '".$p_entry['filename']."' is " + ."already used by an existing directory"); + + return PclZip::errorCode(); + } + } + // ----- Look if file is write protected + else if (!is_writeable($p_entry['filename'])) + { + + // ----- Change the file status + $p_entry['status'] = "write_protected"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Filename '".$p_entry['filename']."' exists " + ."and is write protected"); + + return PclZip::errorCode(); + } + } + + // ----- Look if the extracted file is older + else if (filemtime($p_entry['filename']) > $p_entry['mtime']) + { + // ----- Change the file status + if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER])) + && ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) { + } + else { + $p_entry['status'] = "newer_exist"; + + // ----- Look for PCLZIP_OPT_STOP_ON_ERROR + // For historical reason first PclZip implementation does not stop + // when this kind of error occurs. + if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR])) + && ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) { + + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, + "Newer version of '".$p_entry['filename']."' exists " + ."and option PCLZIP_OPT_REPLACE_NEWER is not selected"); + + return PclZip::errorCode(); + } + } + } + else { + } + } + + // ----- Check the directory availability and create it if necessary + else { + if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) + $v_dir_to_check = $p_entry['filename']; + else if (!strstr($p_entry['filename'], "/")) + $v_dir_to_check = ""; + else + $v_dir_to_check = dirname($p_entry['filename']); + + if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { + + // ----- Change the file status + $p_entry['status'] = "path_creation_fail"; + + // ----- Return + //return $v_result; + $v_result = 1; + } + } + } + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) + { + // ----- Look for not compressed file + if ($p_entry['compression'] == 0) { + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) + { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + // ----- Return + return $v_result; + } + + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + /* Try to speed up the code + $v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_binary_data, $v_read_size); + */ + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Closing the destination file + fclose($v_dest_file); + + // ----- Change the file mtime + touch($p_entry['filename'], $p_entry['mtime']); + + + } + else { + // ----- TBC + // Need to be finished + if (($p_entry['flag'] & 1) == 1) { + PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.'); + return PclZip::errorCode(); + } + + + // ----- Look for using temporary file to unzip + if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF])) + && (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON]) + || (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD]) + && ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) { + $v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options); + if ($v_result < PCLZIP_ERR_NO_ERROR) { + return $v_result; + } + } + + // ----- Look for extract in memory + else { + + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = @gzinflate($v_buffer); + unset($v_buffer); + if ($v_file_content === FALSE) { + + // ----- Change the file status + // TBC + $p_entry['status'] = "error"; + + return $v_result; + } + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + + // ----- Change the file status + $p_entry['status'] = "write_error"; + + return $v_result; + } + + // ----- Write the uncompressed data + @fwrite($v_dest_file, $v_file_content, $p_entry['size']); + unset($v_file_content); + + // ----- Closing the destination file + @fclose($v_dest_file); + + } + + // ----- Change the file mtime + @touch($p_entry['filename'], $p_entry['mtime']); + } + + // ----- Look for chmod option + if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) { + + // ----- Change the mode of the file + @chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]); + } + + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileUsingTempFile() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileUsingTempFile(&$p_entry, &$p_options) + { + $v_result=1; + + // ----- Creates a temporary file + $v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz'; + if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) { + fclose($v_file); + PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode'); + return PclZip::errorCode(); + } + + + // ----- Write gz file format header + $v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3)); + @fwrite($v_dest_file, $v_binary_data, 10); + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['compressed_size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Write gz file format footer + $v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']); + @fwrite($v_dest_file, $v_binary_data, 8); + + // ----- Close the temporary file + @fclose($v_dest_file); + + // ----- Opening destination file + if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + $p_entry['status'] = "write_error"; + return $v_result; + } + + // ----- Open the temporary gz file + if (($v_src_file = @gzopen($v_gzip_temp_name, 'rb')) == 0) { + @fclose($v_dest_file); + $p_entry['status'] = "read_error"; + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary read mode'); + return PclZip::errorCode(); + } + + + // ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks + $v_size = $p_entry['size']; + while ($v_size != 0) { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($v_src_file, $v_read_size); + //$v_binary_data = pack('a'.$v_read_size, $v_buffer); + @fwrite($v_dest_file, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + @fclose($v_dest_file); + @gzclose($v_src_file); + + // ----- Delete the temporary file + @unlink($v_gzip_temp_name); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileInOutput() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileInOutput(&$p_entry, &$p_options) + { + $v_result=1; + + // ----- Read the file header + if (($v_result = $this->privReadFileHeader($v_header)) != 1) { + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + // ----- Trace + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) { + // ----- Look for not compressed file + if ($p_entry['compressed_size'] == $p_entry['size']) { + + // ----- Read the file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Send the file to the output + echo $v_buffer; + unset($v_buffer); + } + else { + + // ----- Read the compressed file in a buffer (one shot) + $v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + $v_file_content = gzinflate($v_buffer); + unset($v_buffer); + + // ----- Send the file to the output + echo $v_file_content; + unset($v_file_content); + } + } + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privExtractFileAsString() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privExtractFileAsString(&$p_entry, &$p_string, &$p_options) + { + $v_result=1; + + // ----- Read the file header + $v_header = array(); + if (($v_result = $this->privReadFileHeader($v_header)) != 1) + { + // ----- Return + return $v_result; + } + + + // ----- Check that the file header is coherent with $p_entry info + if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) { + // TBC + } + + // ----- Look for pre-extract callback + if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header); + if ($v_result == 0) { + // ----- Change the file status + $p_entry['status'] = "skipped"; + $v_result = 1; + } + + // ----- Look for abort result + if ($v_result == 2) { + // ----- This status is internal and will be changed in 'skipped' + $p_entry['status'] = "aborted"; + $v_result = PCLZIP_ERR_USER_ABORTED; + } + + // ----- Update the informations + // Only some fields can be modified + $p_entry['filename'] = $v_local_header['filename']; + } + + + // ----- Look if extraction should be done + if ($p_entry['status'] == 'ok') { + + // ----- Do the extraction (if not a folder) + if (!(($p_entry['external']&0x00000010)==0x00000010)) { + // ----- Look for not compressed file + // if ($p_entry['compressed_size'] == $p_entry['size']) + if ($p_entry['compression'] == 0) { + + // ----- Reading the file + $p_string = @fread($this->zip_fd, $p_entry['compressed_size']); + } + else { + + // ----- Reading the file + $v_data = @fread($this->zip_fd, $p_entry['compressed_size']); + + // ----- Decompress the file + if (($p_string = @gzinflate($v_data)) === FALSE) { + // TBC + } + } + + // ----- Trace + } + else { + // TBC : error : can not extract a folder in a string + } + + } + + // ----- Change abort status + if ($p_entry['status'] == "aborted") { + $p_entry['status'] = "skipped"; + } + + // ----- Look for post-extract callback + elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) { + + // ----- Generate a local information + $v_local_header = array(); + $this->privConvertHeader2FileInfo($p_entry, $v_local_header); + + // ----- Swap the content to header + $v_local_header['content'] = $p_string; + $p_string = ''; + + // ----- Call the callback + // Here I do not use call_user_func() because I need to send a reference to the + // header. +// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);'); + $v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header); + + // ----- Swap back the content to header + $p_string = $v_local_header['content']; + unset($v_local_header['content']); + + // ----- Look for abort result + if ($v_result == 2) { + $v_result = PCLZIP_ERR_USER_ABORTED; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadFileHeader(&$p_header) + { + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x04034b50) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 26); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 26) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); + + // ----- Get filename + $p_header['filename'] = fread($this->zip_fd, $v_data['filename_len']); + + // ----- Get extra_fields + if ($v_data['extra_len'] != 0) { + $p_header['extra'] = fread($this->zip_fd, $v_data['extra_len']); + } + else { + $p_header['extra'] = ''; + } + + // ----- Extract properties + $p_header['version_extracted'] = $v_data['version']; + $p_header['compression'] = $v_data['compression']; + $p_header['size'] = $v_data['size']; + $p_header['compressed_size'] = $v_data['compressed_size']; + $p_header['crc'] = $v_data['crc']; + $p_header['flag'] = $v_data['flag']; + $p_header['filename_len'] = $v_data['filename_len']; + + // ----- Recuperate date in UNIX format + $p_header['mdate'] = $v_data['mdate']; + $p_header['mtime'] = $v_data['mtime']; + if ($p_header['mdate'] && $p_header['mtime']) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } + else + { + $p_header['mtime'] = time(); + } + + // TBC + //for(reset($v_data); $key = key($v_data); next($v_data)) { + //} + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set the status field + $p_header['status'] = "ok"; + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadCentralFileHeader() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadCentralFileHeader(&$p_header) + { + $v_result=1; + + // ----- Read the 4 bytes signature + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] != 0x02014b50) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the first 42 bytes of the header + $v_binary_data = fread($this->zip_fd, 42); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 42) + { + $p_header['filename'] = ""; + $p_header['status'] = "invalid_header"; + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); + + // ----- Get filename + if ($p_header['filename_len'] != 0) + $p_header['filename'] = fread($this->zip_fd, $p_header['filename_len']); + else + $p_header['filename'] = ''; + + // ----- Get extra + if ($p_header['extra_len'] != 0) + $p_header['extra'] = fread($this->zip_fd, $p_header['extra_len']); + else + $p_header['extra'] = ''; + + // ----- Get comment + if ($p_header['comment_len'] != 0) + $p_header['comment'] = fread($this->zip_fd, $p_header['comment_len']); + else + $p_header['comment'] = ''; + + // ----- Extract properties + + // ----- Recuperate date in UNIX format + //if ($p_header['mdate'] && $p_header['mtime']) + // TBC : bug : this was ignoring time with 0/0/0 + if (1) + { + // ----- Extract time + $v_hour = ($p_header['mtime'] & 0xF800) >> 11; + $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; + $v_seconde = ($p_header['mtime'] & 0x001F)*2; + + // ----- Extract date + $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; + $v_month = ($p_header['mdate'] & 0x01E0) >> 5; + $v_day = $p_header['mdate'] & 0x001F; + + // ----- Get UNIX date format + $p_header['mtime'] = @mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + + } + else + { + $p_header['mtime'] = time(); + } + + // ----- Set the stored filename + $p_header['stored_filename'] = $p_header['filename']; + + // ----- Set default status to ok + $p_header['status'] = 'ok'; + + // ----- Look if it is a directory + if (substr($p_header['filename'], -1) == '/') { + //$p_header['external'] = 0x41FF0010; + $p_header['external'] = 0x00000010; + } + + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privCheckFileHeaders() + // Description : + // Parameters : + // Return Values : + // 1 on success, + // 0 on error; + // -------------------------------------------------------------------------------- + function privCheckFileHeaders(&$p_local_header, &$p_central_header) + { + $v_result=1; + + // ----- Check the static values + // TBC + if ($p_local_header['filename'] != $p_central_header['filename']) { + } + if ($p_local_header['version_extracted'] != $p_central_header['version_extracted']) { + } + if ($p_local_header['flag'] != $p_central_header['flag']) { + } + if ($p_local_header['compression'] != $p_central_header['compression']) { + } + if ($p_local_header['mtime'] != $p_central_header['mtime']) { + } + if ($p_local_header['filename_len'] != $p_central_header['filename_len']) { + } + + // ----- Look for flag bit 3 + if (($p_local_header['flag'] & 8) == 8) { + $p_local_header['size'] = $p_central_header['size']; + $p_local_header['compressed_size'] = $p_central_header['compressed_size']; + $p_local_header['crc'] = $p_central_header['crc']; + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privReadEndCentralDir() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privReadEndCentralDir(&$p_central_dir) + { + $v_result=1; + + // ----- Go to the end of the zip file + $v_size = filesize($this->zipname); + @fseek($this->zip_fd, $v_size); + if (@ftell($this->zip_fd) != $v_size) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to go to the end of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- First try : look if this is an archive with no commentaries (most of the time) + // in this case the end of central dir is at 22 bytes of the file end + $v_found = 0; + if ($v_size > 26) { + @fseek($this->zip_fd, $v_size-22); + if (($v_pos = @ftell($this->zip_fd)) != ($v_size-22)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read for bytes + $v_binary_data = @fread($this->zip_fd, 4); + $v_data = @unpack('Vid', $v_binary_data); + + // ----- Check signature + if ($v_data['id'] == 0x06054b50) { + $v_found = 1; + } + + $v_pos = ftell($this->zip_fd); + } + + // ----- Go back to the maximum possible size of the Central Dir End Record + if (!$v_found) { + $v_maximum_size = 65557; // 0xFFFF + 22; + if ($v_maximum_size > $v_size) + $v_maximum_size = $v_size; + @fseek($this->zip_fd, $v_size-$v_maximum_size); + if (@ftell($this->zip_fd) != ($v_size-$v_maximum_size)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, 'Unable to seek back to the middle of the archive \''.$this->zipname.'\''); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read byte per byte in order to find the signature + $v_pos = ftell($this->zip_fd); + $v_bytes = 0x00000000; + while ($v_pos < $v_size) + { + // ----- Read a byte + $v_byte = @fread($this->zip_fd, 1); + + // ----- Add the byte + //$v_bytes = ($v_bytes << 8) | Ord($v_byte); + // Note we mask the old value down such that once shifted we can never end up with more than a 32bit number + // Otherwise on systems where we have 64bit integers the check below for the magic number will fail. + $v_bytes = ( ($v_bytes & 0xFFFFFF) << 8) | Ord($v_byte); + + // ----- Compare the bytes + if ($v_bytes == 0x504b0506) + { + $v_pos++; + break; + } + + $v_pos++; + } + + // ----- Look if not found end of central dir + if ($v_pos == $v_size) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Unable to find End of Central Dir Record signature"); + + // ----- Return + return PclZip::errorCode(); + } + } + + // ----- Read the first 18 bytes of the header + $v_binary_data = fread($this->zip_fd, 18); + + // ----- Look for invalid block size + if (strlen($v_binary_data) != 18) + { + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, "Invalid End of Central Dir Record size : ".strlen($v_binary_data)); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Extract the values + $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); + + // ----- Check the global size + if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { + + // ----- Removed in release 2.2 see readme file + // The check of the file size is a little too strict. + // Some bugs where found when a zip is encrypted/decrypted with 'crypt'. + // While decrypted, zip has training 0 bytes + if (0) { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_BAD_FORMAT, + 'The central dir is not at the end of the archive.' + .' Some trailing bytes exists after the archive.'); + + // ----- Return + return PclZip::errorCode(); + } + } + + // ----- Get comment + if ($v_data['comment_size'] != 0) { + $p_central_dir['comment'] = fread($this->zip_fd, $v_data['comment_size']); + } + else + $p_central_dir['comment'] = ''; + + $p_central_dir['entries'] = $v_data['entries']; + $p_central_dir['disk_entries'] = $v_data['disk_entries']; + $p_central_dir['offset'] = $v_data['offset']; + $p_central_dir['size'] = $v_data['size']; + $p_central_dir['disk'] = $v_data['disk']; + $p_central_dir['disk_start'] = $v_data['disk_start']; + + // TBC + //for(reset($p_central_dir); $key = key($p_central_dir); next($p_central_dir)) { + //} + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDeleteByRule() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDeleteByRule(&$p_result_list, &$p_options) + { + $v_result=1; + $v_list_detail = array(); + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Scan all the files + // ----- Start at beginning of Central Dir + $v_pos_entry = $v_central_dir['offset']; + @rewind($this->zip_fd); + if (@fseek($this->zip_fd, $v_pos_entry)) + { + // ----- Close the zip file + $this->privCloseFd(); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read each entry + $v_header_list = array(); + $j_start = 0; + for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) + { + + // ----- Read the file header + $v_header_list[$v_nb_extracted] = array(); + if (($v_result = $this->privReadCentralFileHeader($v_header_list[$v_nb_extracted])) != 1) + { + // ----- Close the zip file + $this->privCloseFd(); + + return $v_result; + } + + + // ----- Store the index + $v_header_list[$v_nb_extracted]['index'] = $i; + + // ----- Look for the specific extract rules + $v_found = false; + + // ----- Look for extract by name rule + if ( (isset($p_options[PCLZIP_OPT_BY_NAME])) + && ($p_options[PCLZIP_OPT_BY_NAME] != 0)) { + + // ----- Look if the filename is in the list + for ($j=0; ($j strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) + && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_options[PCLZIP_OPT_BY_NAME][$j])) == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } + elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ + && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_options[PCLZIP_OPT_BY_NAME][$j])) { + $v_found = true; + } + } + // ----- Look for a filename + elseif ($v_header_list[$v_nb_extracted]['stored_filename'] == $p_options[PCLZIP_OPT_BY_NAME][$j]) { + $v_found = true; + } + } + } + + // ----- Look for extract by ereg rule + // ereg() is deprecated with PHP 5.3 + /* + else if ( (isset($p_options[PCLZIP_OPT_BY_EREG])) + && ($p_options[PCLZIP_OPT_BY_EREG] != "")) { + + if (ereg($p_options[PCLZIP_OPT_BY_EREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + */ + + // ----- Look for extract by preg rule + else if ( (isset($p_options[PCLZIP_OPT_BY_PREG])) + && ($p_options[PCLZIP_OPT_BY_PREG] != "")) { + + if (preg_match($p_options[PCLZIP_OPT_BY_PREG], $v_header_list[$v_nb_extracted]['stored_filename'])) { + $v_found = true; + } + } + + // ----- Look for extract by index rule + else if ( (isset($p_options[PCLZIP_OPT_BY_INDEX])) + && ($p_options[PCLZIP_OPT_BY_INDEX] != 0)) { + + // ----- Look if the index is in the list + for ($j=$j_start; ($j=$p_options[PCLZIP_OPT_BY_INDEX][$j]['start']) && ($i<=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end'])) { + $v_found = true; + } + if ($i>=$p_options[PCLZIP_OPT_BY_INDEX][$j]['end']) { + $j_start = $j+1; + } + + if ($p_options[PCLZIP_OPT_BY_INDEX][$j]['start']>$i) { + break; + } + } + } + else { + $v_found = true; + } + + // ----- Look for deletion + if ($v_found) + { + unset($v_header_list[$v_nb_extracted]); + } + else + { + $v_nb_extracted++; + } + } + + // ----- Look if something need to be deleted + if ($v_nb_extracted > 0) { + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Creates a temporary zip archive + $v_temp_zip = new PclZip($v_zip_temp_name); + + // ----- Open the temporary zip file in write mode + if (($v_result = $v_temp_zip->privOpenFd('wb')) != 1) { + $this->privCloseFd(); + + // ----- Return + return $v_result; + } + + // ----- Look which file need to be kept + for ($i=0; $izip_fd); + if (@fseek($this->zip_fd, $v_header_list[$i]['offset'])) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Read the file header + $v_local_header = array(); + if (($v_result = $this->privReadFileHeader($v_local_header)) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Check that local file header is same as central file header + if ($this->privCheckFileHeaders($v_local_header, + $v_header_list[$i]) != 1) { + // TBC + } + unset($v_local_header); + + // ----- Write the file header + if (($v_result = $v_temp_zip->privWriteFileHeader($v_header_list[$i])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Read/write the data block + if (($v_result = PclZipUtilCopyBlock($this->zip_fd, $v_temp_zip->zip_fd, $v_header_list[$i]['compressed_size'])) != 1) { + // ----- Close the zip file + $this->privCloseFd(); + $v_temp_zip->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_temp_zip->zip_fd); + + // ----- Re-Create the Central Dir files header + for ($i=0; $iprivWriteCentralFileHeader($v_header_list[$i])) != 1) { + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Transform the header to a 'usable' info + $v_temp_zip->privConvertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); + } + + + // ----- Zip file comment + $v_comment = ''; + if (isset($p_options[PCLZIP_OPT_COMMENT])) { + $v_comment = $p_options[PCLZIP_OPT_COMMENT]; + } + + // ----- Calculate the size of the central header + $v_size = @ftell($v_temp_zip->zip_fd)-$v_offset; + + // ----- Create the central dir footer + if (($v_result = $v_temp_zip->privWriteCentralHeader(sizeof($v_header_list), $v_size, $v_offset, $v_comment)) != 1) { + // ----- Reset the file list + unset($v_header_list); + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + @unlink($v_zip_temp_name); + + // ----- Return + return $v_result; + } + + // ----- Close + $v_temp_zip->privCloseFd(); + $this->privCloseFd(); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Destroy the temporary archive + unset($v_temp_zip); + } + + // ----- Remove every files : reset the file + else if ($v_central_dir['entries'] != 0) { + $this->privCloseFd(); + + if (($v_result = $this->privOpenFd('wb')) != 1) { + return $v_result; + } + + if (($v_result = $this->privWriteCentralHeader(0, 0, 0, '')) != 1) { + return $v_result; + } + + $this->privCloseFd(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDirCheck() + // Description : + // Check if a directory exists, if not it creates it and all the parents directory + // which may be useful. + // Parameters : + // $p_dir : Directory path to check. + // Return Values : + // 1 : OK + // -1 : Unable to create directory + // -------------------------------------------------------------------------------- + function privDirCheck($p_dir, $p_is_dir=false) + { + $v_result = 1; + + + // ----- Remove the final '/' + if (($p_is_dir) && (substr($p_dir, -1)=='/')) + { + $p_dir = substr($p_dir, 0, strlen($p_dir)-1); + } + + // ----- Check the directory availability + if ((is_dir($p_dir)) || ($p_dir == "")) + { + return 1; + } + + // ----- Extract parent directory + $p_parent_dir = dirname($p_dir); + + // ----- Just a check + if ($p_parent_dir != $p_dir) + { + // ----- Look for parent directory + if ($p_parent_dir != "") + { + if (($v_result = $this->privDirCheck($p_parent_dir)) != 1) + { + return $v_result; + } + } + } + + // ----- Create the directory + if (!@mkdir($p_dir, 0777)) + { + // ----- Error log + PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'"); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privMerge() + // Description : + // If $p_archive_to_add does not exist, the function exit with a success result. + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privMerge(&$p_archive_to_add) + { + $v_result=1; + + // ----- Look if the archive_to_add exists + if (!is_file($p_archive_to_add->zipname)) + { + + // ----- Nothing to merge, so merge is a success + $v_result = 1; + + // ----- Return + return $v_result; + } + + // ----- Look if the archive exists + if (!is_file($this->zipname)) + { + + // ----- Do a duplicate + $v_result = $this->privDuplicate($p_archive_to_add->zipname); + + // ----- Return + return $v_result; + } + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('rb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir = array(); + if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1) + { + $this->privCloseFd(); + return $v_result; + } + + // ----- Go to beginning of File + @rewind($this->zip_fd); + + // ----- Open the archive_to_add file + if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1) + { + $this->privCloseFd(); + + // ----- Return + return $v_result; + } + + // ----- Read the central directory informations + $v_central_dir_to_add = array(); + if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + return $v_result; + } + + // ----- Go to beginning of File + @rewind($p_archive_to_add->zip_fd); + + // ----- Creates a temporay file + $v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp'; + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = $v_central_dir['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the files from the archive_to_add into the temporary file + $v_size = $v_central_dir_to_add['offset']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Store the offset of the central dir + $v_offset = @ftell($v_zip_temp_fd); + + // ----- Copy the block of file headers from the old archive + $v_size = $v_central_dir['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($this->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Copy the block of file headers from the archive_to_add + $v_size = $v_central_dir_to_add['size']; + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size); + @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Merge the file comments + $v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment']; + + // ----- Calculate the size of the (new) central header + $v_size = @ftell($v_zip_temp_fd)-$v_offset; + + // ----- Swap the file descriptor + // Here is a trick : I swap the temporary fd with the zip fd, in order to use + // the following methods on the temporary fil and not the real archive fd + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Create the central dir footer + if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1) + { + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + @fclose($v_zip_temp_fd); + $this->zip_fd = null; + + // ----- Reset the file list + unset($v_header_list); + + // ----- Return + return $v_result; + } + + // ----- Swap back the file descriptor + $v_swap = $this->zip_fd; + $this->zip_fd = $v_zip_temp_fd; + $v_zip_temp_fd = $v_swap; + + // ----- Close + $this->privCloseFd(); + $p_archive_to_add->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Delete the zip file + // TBC : I should test the result ... + @unlink($this->zipname); + + // ----- Rename the temporary file + // TBC : I should test the result ... + //@rename($v_zip_temp_name, $this->zipname); + PclZipUtilRename($v_zip_temp_name, $this->zipname); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDuplicate() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDuplicate($p_archive_filename) + { + $v_result=1; + + // ----- Look if the $p_archive_filename exists + if (!is_file($p_archive_filename)) + { + + // ----- Nothing to duplicate, so duplicate is a success. + $v_result = 1; + + // ----- Return + return $v_result; + } + + // ----- Open the zip file + if (($v_result=$this->privOpenFd('wb')) != 1) + { + // ----- Return + return $v_result; + } + + // ----- Open the temporary file in write mode + if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) + { + $this->privCloseFd(); + + PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode'); + + // ----- Return + return PclZip::errorCode(); + } + + // ----- Copy the files from the archive to the temporary file + // TBC : Here I should better append the file and go back to erase the central dir + $v_size = filesize($p_archive_filename); + while ($v_size != 0) + { + $v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = fread($v_zip_temp_fd, $v_read_size); + @fwrite($this->zip_fd, $v_buffer, $v_read_size); + $v_size -= $v_read_size; + } + + // ----- Close + $this->privCloseFd(); + + // ----- Close the temporary file + @fclose($v_zip_temp_fd); + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorLog() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privErrorLog($p_error_code=0, $p_error_string='') + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclError($p_error_code, $p_error_string); + } + else { + $this->error_code = $p_error_code; + $this->error_string = $p_error_string; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privErrorReset() + // Description : + // Parameters : + // -------------------------------------------------------------------------------- + function privErrorReset() + { + if (PCLZIP_ERROR_EXTERNAL == 1) { + PclErrorReset(); + } + else { + $this->error_code = 0; + $this->error_string = ''; + } + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privDisableMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privDisableMagicQuotes() + { + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } + + // ----- Look if already done + if ($this->magic_quotes_status != -1) { + return $v_result; + } + + // ----- Get and memorize the magic_quote value + $this->magic_quotes_status = @get_magic_quotes_runtime(); + + // ----- Disable magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime(0); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : privSwapBackMagicQuotes() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function privSwapBackMagicQuotes() + { + $v_result=1; + + // ----- Look if function exists + if ( (!function_exists("get_magic_quotes_runtime")) + || (!function_exists("set_magic_quotes_runtime"))) { + return $v_result; + } + + // ----- Look if something to do + if ($this->magic_quotes_status != -1) { + return $v_result; + } + + // ----- Swap back magic_quotes + if ($this->magic_quotes_status == 1) { + @set_magic_quotes_runtime($this->magic_quotes_status); + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + } + // End of class + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilPathReduction() + // Description : + // Parameters : + // Return Values : + // -------------------------------------------------------------------------------- + function PclZipUtilPathReduction($p_dir) + { + $v_result = ""; + + // ----- Look for not empty path + if ($p_dir != "") { + // ----- Explode path by directory names + $v_list = explode("/", $p_dir); + + // ----- Study directories from last to first + $v_skip = 0; + for ($i=sizeof($v_list)-1; $i>=0; $i--) { + // ----- Look for current path + if ($v_list[$i] == ".") { + // ----- Ignore this directory + // Should be the first $i=0, but no check is done + } + else if ($v_list[$i] == "..") { + $v_skip++; + } + else if ($v_list[$i] == "") { + // ----- First '/' i.e. root slash + if ($i == 0) { + $v_result = "/".$v_result; + if ($v_skip > 0) { + // ----- It is an invalid path, so the path is not modified + // TBC + $v_result = $p_dir; + $v_skip = 0; + } + } + // ----- Last '/' i.e. indicates a directory + else if ($i == (sizeof($v_list)-1)) { + $v_result = $v_list[$i]; + } + // ----- Double '/' inside the path + else { + // ----- Ignore only the double '//' in path, + // but not the first and last '/' + } + } + else { + // ----- Look for item to skip + if ($v_skip > 0) { + $v_skip--; + } + else { + $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); + } + } + } + + // ----- Look for skip + if ($v_skip > 0) { + while ($v_skip > 0) { + $v_result = '../'.$v_result; + $v_skip--; + } + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilPathInclusion() + // Description : + // This function indicates if the path $p_path is under the $p_dir tree. Or, + // said in an other way, if the file or sub-dir $p_path is inside the dir + // $p_dir. + // The function indicates also if the path is exactly the same as the dir. + // This function supports path with duplicated '/' like '//', but does not + // support '.' or '..' statements. + // Parameters : + // Return Values : + // 0 if $p_path is not inside directory $p_dir + // 1 if $p_path is inside directory $p_dir + // 2 if $p_path is exactly the same as $p_dir + // -------------------------------------------------------------------------------- + function PclZipUtilPathInclusion($p_dir, $p_path) + { + $v_result = 1; + + // ----- Look for path beginning by ./ + if ( ($p_dir == '.') + || ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) { + $p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1); + } + if ( ($p_path == '.') + || ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) { + $p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1); + } + + // ----- Explode dir and path by directory separator + $v_list_dir = explode("/", $p_dir); + $v_list_dir_size = sizeof($v_list_dir); + $v_list_path = explode("/", $p_path); + $v_list_path_size = sizeof($v_list_path); + + // ----- Study directories paths + $i = 0; + $j = 0; + while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { + + // ----- Look for empty dir (path reduction) + if ($v_list_dir[$i] == '') { + $i++; + continue; + } + if ($v_list_path[$j] == '') { + $j++; + continue; + } + + // ----- Compare the items + if (($v_list_dir[$i] != $v_list_path[$j]) && ($v_list_dir[$i] != '') && ( $v_list_path[$j] != '')) { + $v_result = 0; + } + + // ----- Next items + $i++; + $j++; + } + + // ----- Look if everything seems to be the same + if ($v_result) { + // ----- Skip all the empty items + while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; + while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; + + if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { + // ----- There are exactly the same + $v_result = 2; + } + else if ($i < $v_list_dir_size) { + // ----- The path is shorter than the dir + $v_result = 0; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilCopyBlock() + // Description : + // Parameters : + // $p_mode : read/write compression mode + // 0 : src & dest normal + // 1 : src gzip, dest normal + // 2 : src normal, dest gzip + // 3 : src & dest gzip + // Return Values : + // -------------------------------------------------------------------------------- + function PclZipUtilCopyBlock($p_src, $p_dest, $p_size, $p_mode=0) + { + $v_result = 1; + + if ($p_mode==0) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==1) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @fwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==2) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @fread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + else if ($p_mode==3) + { + while ($p_size != 0) + { + $v_read_size = ($p_size < PCLZIP_READ_BLOCK_SIZE ? $p_size : PCLZIP_READ_BLOCK_SIZE); + $v_buffer = @gzread($p_src, $v_read_size); + @gzwrite($p_dest, $v_buffer, $v_read_size); + $p_size -= $v_read_size; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilRename() + // Description : + // This function tries to do a simple rename() function. If it fails, it + // tries to copy the $p_src file in a new $p_dest file and then unlink the + // first one. + // Parameters : + // $p_src : Old filename + // $p_dest : New filename + // Return Values : + // 1 on success, 0 on failure. + // -------------------------------------------------------------------------------- + function PclZipUtilRename($p_src, $p_dest) + { + $v_result = 1; + + // ----- Try to rename the files + if (!@rename($p_src, $p_dest)) { + + // ----- Try to copy & unlink the src + if (!@copy($p_src, $p_dest)) { + $v_result = 0; + } + else if (!@unlink($p_src)) { + $v_result = 0; + } + } + + // ----- Return + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilOptionText() + // Description : + // Translate option value in text. Mainly for debug purpose. + // Parameters : + // $p_option : the option value. + // Return Values : + // The option text value. + // -------------------------------------------------------------------------------- + function PclZipUtilOptionText($p_option) + { + + $v_list = get_defined_constants(); + for (reset($v_list); $v_key = key($v_list); next($v_list)) { + $v_prefix = substr($v_key, 0, 10); + if (( ($v_prefix == 'PCLZIP_OPT') + || ($v_prefix == 'PCLZIP_CB_') + || ($v_prefix == 'PCLZIP_ATT')) + && ($v_list[$v_key] == $p_option)) { + return $v_key; + } + } + + $v_result = 'Unknown'; + + return $v_result; + } + // -------------------------------------------------------------------------------- + + // -------------------------------------------------------------------------------- + // Function : PclZipUtilTranslateWinPath() + // Description : + // Translate windows path by replacing '\' by '/' and optionally removing + // drive letter. + // Parameters : + // $p_path : path to translate. + // $p_remove_disk_letter : true | false + // Return Values : + // The path translated. + // -------------------------------------------------------------------------------- + function PclZipUtilTranslateWinPath($p_path, $p_remove_disk_letter=true) + { + if (stristr(php_uname(), 'windows')) { + // ----- Look for potential disk letter + if (($p_remove_disk_letter) && (($v_position = strpos($p_path, ':')) != false)) { + $p_path = substr($p_path, $v_position+1); + } + // ----- Change potential windows directory separator + if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { + $p_path = strtr($p_path, '\\', '/'); + } + } + return $p_path; + } + // -------------------------------------------------------------------------------- diff --git a/src/PhpWord/Shared/String.php b/src/PhpWord/Shared/String.php index 08d6f6a5..95f75f13 100644 --- a/src/PhpWord/Shared/String.php +++ b/src/PhpWord/Shared/String.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Shared; @@ -35,66 +19,36 @@ class String * * @var string[] */ - private static $_controlCharacters = array(); - - /** - * Build control characters array - */ - private static function _buildControlCharacters() - { - for ($i = 0; $i <= 19; ++$i) { - if ($i != 9 && $i != 10 && $i != 13) { - $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_'; - $replace = chr($i); - self::$_controlCharacters[$find] = $replace; - } - } - } + private static $controlCharacters = array(); /** * Convert from OpenXML escaped control character to PHP control character * - * Excel 2007 team: - * ---------------- - * That's correct, control characters are stored directly in the shared-strings table. - * We do encode characters that cannot be represented in XML using the following escape sequence: - * _xHHHH_ where H represents a hexadecimal character in the character's value... - * So you could end up with something like _x0008_ in a string (either in a cell value () - * element or in the shared string element. - * - * @param string $value Value to unescape - * @return string + * @param string $value Value to unescape + * @return string */ public static function controlCharacterOOXML2PHP($value = '') { - if (empty(self::$_controlCharacters)) { - self::_buildControlCharacters(); + if (empty(self::$controlCharacters)) { + self::buildControlCharacters(); } - return str_replace(array_keys(self::$_controlCharacters), array_values(self::$_controlCharacters), $value); + return str_replace(array_keys(self::$controlCharacters), array_values(self::$controlCharacters), $value); } /** * Convert from PHP control character to OpenXML escaped control character * - * Excel 2007 team: - * ---------------- - * That's correct, control characters are stored directly in the shared-strings table. - * We do encode characters that cannot be represented in XML using the following escape sequence: - * _xHHHH_ where H represents a hexadecimal character in the character's value... - * So you could end up with something like _x0008_ in a string (either in a cell value () - * element or in the shared string element. - * - * @param string $value Value to escape - * @return string + * @param string $value Value to escape + * @return string */ public static function controlCharacterPHP2OOXML($value = '') { - if (empty(self::$_controlCharacters)) { - self::_buildControlCharacters(); + if (empty(self::$controlCharacters)) { + self::buildControlCharacters(); } - return str_replace(array_values(self::$_controlCharacters), array_keys(self::$_controlCharacters), $value); + return str_replace(array_values(self::$controlCharacters), array_keys(self::$controlCharacters), $value); } /** @@ -107,4 +61,50 @@ class String { return $value === '' || preg_match('/^./su', $value) === 1; } + + /** + * Return UTF8 encoded value + * + * @param string $value + * @return string + */ + public static function toUTF8($value = '') + { + if (!is_null($value) && !self::isUTF8($value)) { + $value = utf8_encode($value); + } + + return $value; + } + + /** + * Return name without underscore for < 0.10.0 variable name compatibility + * + * @param string $value + * @return string + */ + public static function removeUnderscorePrefix($value) + { + if (!is_null($value)) { + if (substr($value, 0, 1) == '_') { + $value = substr($value, 1); + } + } + + return $value; + } + + /** + * Build control characters array + */ + private static function buildControlCharacters() + { + for ($i = 0; $i <= 19; ++$i) { + if ($i != 9 && $i != 10 && $i != 13) { + $find = '_x' . sprintf('%04s', strtoupper(dechex($i))) . '_'; + $replace = chr($i); + self::$controlCharacters[$find] = $replace; + } + } + } } diff --git a/src/PhpWord/Shared/XMLReader.php b/src/PhpWord/Shared/XMLReader.php new file mode 100644 index 00000000..b7f5549e --- /dev/null +++ b/src/PhpWord/Shared/XMLReader.php @@ -0,0 +1,163 @@ +open($zipFile); + if ($canOpen === false) { + throw new Exception('Cannot open archive file.'); + } + $contents = $zip->getFromName($xmlFile); + $zip->close(); + + if ($contents === false) { + return false; + } else { + $this->dom = new \DOMDocument(); + $this->dom->loadXML($contents); + return $this->dom; + } + } + + /** + * Get elements + * + * @param string $path + * @return \DOMNodeList + */ + public function getElements($path, \DOMElement $contextNode = null) + { + if ($this->dom === null) { + return array(); + } + if ($this->xpath === null) { + $this->xpath = new \DOMXpath($this->dom); + } + + return $this->xpath->query($path, $contextNode); + } + + /** + * Get element + * + * @param string $path + * @return \DOMElement|null + */ + public function getElement($path, \DOMElement $contextNode) + { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + return $elements->item(0); + } else { + return null; + } + } + + /** + * Get element attribute + * + * @param string $attribute + * @param string $path + * @return string|null + */ + public function getAttribute($attribute, \DOMElement $contextNode, $path = null) + { + if (is_null($path)) { + $return = $contextNode->getAttribute($attribute); + } else { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + $return = $elements->item(0)->getAttribute($attribute); + } else { + $return = null; + } + } + + return ($return == '') ? null : $return; + } + + /** + * Get element value + * + * @param string $path + * @return string|null + */ + public function getValue($path, \DOMElement $contextNode) + { + $elements = $this->getElements($path, $contextNode); + if ($elements->length > 0) { + return $elements->item(0)->nodeValue; + } else { + return null; + } + } + + /** + * Count elements + * + * @param string $path + * @return integer + */ + public function countElements($path, \DOMElement $contextNode) + { + $elements = $this->getElements($path, $contextNode); + + return $elements->length; + } + + /** + * Element exists + * + * @param string $path + * @return boolean + */ + public function elementExists($path, \DOMElement $contextNode) + { + return $this->getElements($path, $contextNode)->length > 0; + } +} diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php index 26d037bc..53f5e893 100644 --- a/src/PhpWord/Shared/XMLWriter.php +++ b/src/PhpWord/Shared/XMLWriter.php @@ -2,45 +2,34 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ 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 * + * @method bool writeElement(string $name, string $content = null) * @method bool startElement(string $name) * @method bool writeAttribute(string $name, string $value) * @method bool endElement() + * @method bool startDocument(string $version = 1.0, string $encoding = null, string $standalone = null) + * @method bool text(string $content) */ class XMLWriter { - /** Temporary storage method */ + /** Temporary storage location */ const STORAGE_MEMORY = 1; const STORAGE_DISK = 2; @@ -49,48 +38,48 @@ class XMLWriter * * @var \XMLWriter */ - private $_xmlWriter; + private $xmlWriter; /** * Temporary filename * * @var string */ - private $_tempFileName = ''; + private $tempFile = ''; /** * Create new XMLWriter * - * @param int $pTemporaryStorage Temporary storage location - * @param string $pTemporaryStorageFolder Temporary storage folder + * @param int $tempLocation Temporary storage location + * @param string $tempFolder Temporary storage folder */ - public function __construct($pTemporaryStorage = self::STORAGE_MEMORY, $pTemporaryStorageFolder = './') + public function __construct($tempLocation = self::STORAGE_MEMORY, $tempFolder = './') { // Create internal XMLWriter - $this->_xmlWriter = new \XMLWriter(); + $this->xmlWriter = new \XMLWriter(); // Open temporary storage - if ($pTemporaryStorage == self::STORAGE_MEMORY) { - $this->_xmlWriter->openMemory(); + if ($tempLocation == self::STORAGE_MEMORY) { + $this->xmlWriter->openMemory(); } else { // Create temporary filename - $this->_tempFileName = @tempnam($pTemporaryStorageFolder, 'xml'); + $this->tempFile = @tempnam($tempFolder, 'xml'); // Open storage - if ($this->_xmlWriter->openUri($this->_tempFileName) === false) { + if ($this->xmlWriter->openUri($this->tempFile) === false) { // Fallback to memory... - $this->_xmlWriter->openMemory(); + $this->xmlWriter->openMemory(); } } // Set xml Compatibility $compatibility = Settings::getCompatibility(); if ($compatibility) { - $this->_xmlWriter->setIndent(false); - $this->_xmlWriter->setIndentString(''); + $this->xmlWriter->setIndent(false); + $this->xmlWriter->setIndentString(''); } else { - $this->_xmlWriter->setIndent(true); - $this->_xmlWriter->setIndentString(' '); + $this->xmlWriter->setIndent(true); + $this->xmlWriter->setIndentString(' '); } } @@ -99,27 +88,12 @@ class XMLWriter */ public function __destruct() { - // Desctruct XMLWriter - unset($this->_xmlWriter); + // Destruct XMLWriter + unset($this->xmlWriter); // Unlink temporary files - if ($this->_tempFileName != '') { - @unlink($this->_tempFileName); - } - } - - /** - * Get written data - * - * @return string XML data - */ - public function getData() - { - if ($this->_tempFileName == '') { - return $this->_xmlWriter->outputMemory(true); - } else { - $this->_xmlWriter->flush(); - return file_get_contents($this->_tempFileName); + if ($this->tempFile != '') { + @unlink($this->tempFile); } } @@ -132,22 +106,37 @@ class XMLWriter public function __call($function, $args) { try { - @call_user_func_array(array($this->_xmlWriter, $function), $args); + @call_user_func_array(array($this->xmlWriter, $function), $args); } catch (\Exception $ex) { // Do nothing! } } + /** + * Get written data + * + * @return string XML data + */ + public function getData() + { + if ($this->tempFile == '') { + return $this->xmlWriter->outputMemory(true); + } else { + $this->xmlWriter->flush(); + return file_get_contents($this->tempFile); + } + } + /** * Fallback method for writeRaw, introduced in PHP 5.2 * * @param string $text - * @return string + * @return bool */ public function writeRaw($text) { - if (isset($this->_xmlWriter) && is_object($this->_xmlWriter) && (method_exists($this->_xmlWriter, 'writeRaw'))) { - return $this->_xmlWriter->writeRaw($text); + if (isset($this->xmlWriter) && is_object($this->xmlWriter) && (method_exists($this->xmlWriter, 'writeRaw'))) { + return $this->xmlWriter->writeRaw($text); } return $this->text($text); diff --git a/src/PhpWord/Shared/ZipArchive.php b/src/PhpWord/Shared/ZipArchive.php new file mode 100644 index 00000000..2da7573c --- /dev/null +++ b/src/PhpWord/Shared/ZipArchive.php @@ -0,0 +1,236 @@ +tempDir = sys_get_temp_dir(); + $this->zip = new \PclZip($filename); + $this->numFiles = count($this->zip->listContent()); + + return true; + } + + /** + * Close this zip archive (emulate \ZipArchive) + * + * @codeCoverageIgnore + */ + public function close() + { + } + + /** + * Add a new file to the zip archive (emulate \ZipArchive) + * + * @param string $filename Directory/Name of the file to add to the zip archive + * @param string $localname Directory/Name of the file added to the zip + */ + public function addFile($filename, $localname = null) + { + $filename = realpath($filename); + $filenameParts = pathinfo($filename); + $localnameParts = pathinfo($localname); + + // To Rename the file while adding it to the zip we + // need to create a temp file with the correct name + if ($filenameParts['basename'] != $localnameParts['basename']) { + $temppath = $this->tempDir . '/' . $localnameParts['basename']; + copy($filename, $temppath); + $filename = $temppath; + $filenameParts = pathinfo($temppath); + } + + $res = $this->zip->add( + $filename, + PCLZIP_OPT_REMOVE_PATH, + $filenameParts['dirname'], + PCLZIP_OPT_ADD_PATH, + $localnameParts["dirname"] + ); + + return ($res == 0) ? false : true; + } + + /** + * Add a new file to the zip archive from a string of raw data (emulate \ZipArchive) + * + * @param string $localname Directory/Name of the file to add to the zip archive + * @param string $contents String of data to add to the zip archive + */ + public function addFromString($localname, $contents) + { + $filenameParts = pathinfo($localname); + + // Write $contents to a temp file + $handle = fopen($this->tempDir . '/' . $filenameParts["basename"], "wb"); + fwrite($handle, $contents); + 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"] + ); + + // Remove temp file + @unlink($this->tempDir . '/' . $filenameParts["basename"]); + + return ($res == 0) ? false : true; + } + + /** + * Returns the index of the entry in the archive (emulate \ZipArchive) + * + * @param string $filename Filename for the file in zip archive + * @return integer|false + */ + public function locateName($filename) + { + $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 ($listIndex > -1) ? $listIndex : false; + } + + /** + * 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) + { + $listIndex = $this->locateName($filename); + $contents = false; + + if ($listIndex !== false) { + $extracted = $this->zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING); + } else { + $filename = substr($filename, 1); + $listIndex = $this->locateName($filename); + $extracted = $this->zip->extractByIndex($listIndex, PCLZIP_OPT_EXTRACT_AS_STRING); + } + if ((is_array($extracted)) && ($extracted != 0)) { + $contents = $extracted[0]["content"]; + } + + return $contents; + } + + /** + * Returns the name of an entry using its index (emulate \ZipArchive) + * + * @param integer $index + * @return string|false + * @since 0.10.0 + */ + public function getNameIndex($index) + { + $list = $this->zip->listContent(); + if (isset($list[$index])) { + return $list[$index]['filename']; + } else { + return false; + } + } + + /** + * Extract the archive contents (emulate \ZipArchive) + * + * @param string $destination + * @param string|array $entries + * @return boolean + * @since 0.10.0 + */ + public function extractTo($destination, $entries = null) + { + 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; + } + } + + return true; + } +} diff --git a/src/PhpWord/Shared/ZipStreamWrapper.php b/src/PhpWord/Shared/ZipStreamWrapper.php deleted file mode 100644 index 7e0369cd..00000000 --- a/src/PhpWord/Shared/ZipStreamWrapper.php +++ /dev/null @@ -1,195 +0,0 @@ -_archive = new \ZipArchive(); - $this->_archive->open($url['host']); - - $this->_fileNameInArchive = $url['fragment']; - $this->_position = 0; - $this->_data = $this->_archive->getFromName($this->_fileNameInArchive); - - return true; - } - - /** - * Stat stream - */ - public function streamStat() - { - return $this->_archive->statName($this->_fileNameInArchive); - } - - /** - * Read stream - * - * @param int $count - */ - public function streamRead($count) - { - $ret = substr($this->_data, $this->_position, $count); - $this->_position += strlen($ret); - return $ret; - } - - /** - * Tell stream - */ - public function streamTell() - { - return $this->_position; - } - - /** - * EOF stream - */ - public function streamEof() - { - return $this->_position >= strlen($this->_data); - } - - /** - * Seek stream - * - * @param int $offset - * @param mixed $whence - */ - public function streamSeek($offset, $whence) - { - switch ($whence) { - case \SEEK_SET: - if ($offset < strlen($this->_data) && $offset >= 0) { - $this->_position = $offset; - return true; - } else { - return false; - } - break; - - case \SEEK_CUR: - if ($offset >= 0) { - $this->_position += $offset; - return true; - } else { - return false; - } - break; - - case \SEEK_END: - if (strlen($this->_data) + $offset >= 0) { - $this->_position = strlen($this->_data) + $offset; - return true; - } else { - return false; - } - break; - - default: - return false; - } - } -} diff --git a/src/PhpWord/Style.php b/src/PhpWord/Style.php old mode 100755 new mode 100644 index c88ae00b..85743a22 --- a/src/PhpWord/Style.php +++ b/src/PhpWord/Style.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; @@ -28,9 +12,10 @@ namespace PhpOffice\PhpWord; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; use PhpOffice\PhpWord\Style\Table; +use PhpOffice\PhpWord\Style\Numbering; /** - * Style + * Style collection */ class Style { @@ -39,7 +24,7 @@ class Style * * @var array */ - private static $_styleElements = array(); + private static $styles = array(); /** * Add paragraph style @@ -49,38 +34,19 @@ class Style */ public static function addParagraphStyle($styleName, $styles) { - if (!array_key_exists($styleName, self::$_styleElements)) { - $style = new Paragraph(); - foreach ($styles as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $style->setStyleValue($key, $value); - } - - self::$_styleElements[$styleName] = $style; - } + self::setStyleValues($styleName, new Paragraph(), $styles); } /** * Add font style * * @param string $styleName - * @param array $styleFont - * @param array $styleParagraph + * @param array $fontStyle + * @param array $paragraphStyle */ - public static function addFontStyle($styleName, $styleFont, $styleParagraph = null) + public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = null) { - if (!array_key_exists($styleName, self::$_styleElements)) { - $font = new Font('text', $styleParagraph); - foreach ($styleFont as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $font->setStyleValue($key, $value); - } - self::$_styleElements[$styleName] = $font; - } + self::setStyleValues($styleName, new Font('text', $paragraphStyle), $fontStyle); } /** @@ -91,17 +57,7 @@ class Style */ public static function addLinkStyle($styleName, $styles) { - if (!array_key_exists($styleName, self::$_styleElements)) { - $style = new Font('link'); - foreach ($styles as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $style->setStyleValue($key, $value); - } - - self::$_styleElements[$styleName] = $style; - } + self::setStyleValues($styleName, new Font('link'), $styles); } /** @@ -109,38 +65,56 @@ class Style * * @param string $styleName * @param array $styleTable - * @param array $styleFirstRow + * @param array|null $styleFirstRow */ public static function addTableStyle($styleName, $styleTable, $styleFirstRow = null) { - if (!array_key_exists($styleName, self::$_styleElements)) { - $style = new Table($styleTable, $styleFirstRow); - - self::$_styleElements[$styleName] = $style; - } + self::setStyleValues($styleName, new Table($styleTable, $styleFirstRow), null); } /** * Add title style * * @param int $titleCount - * @param array $styleFont - * @param array $styleParagraph + * @param array $fontStyle + * @param array $paragraphStyle */ - public static function addTitleStyle($titleCount, $styleFont, $styleParagraph = null) + public static function addTitleStyle($titleCount, $fontStyle, $paragraphStyle = null) { - $styleName = 'Heading_' . $titleCount; - if (!array_key_exists($styleName, self::$_styleElements)) { - $font = new Font('title', $styleParagraph); - foreach ($styleFont as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - $font->setStyleValue($key, $value); - } + self::setStyleValues("Heading_{$titleCount}", new Font('title', $paragraphStyle), $fontStyle); + } - self::$_styleElements[$styleName] = $font; - } + /** + * Add numbering style + * + * @param string $styleName + * @param array $styleValues + * @return Numbering + * @since 0.10.0 + */ + public static function addNumberingStyle($styleName, $styleValues) + { + self::setStyleValues($styleName, new Numbering(), $styleValues); + } + + /** + * Count styles + * + * @return integer + * @since 0.10.0 + */ + public static function countStyles() + { + return count(self::$styles); + } + + /** + * Reset styles + * @since 0.10.0 + */ + public static function resetStyles() + { + self::$styles = array(); } /** @@ -156,24 +130,46 @@ class Style /** * Get all styles * - * @return \PhpOffice\PhpWord\Style\Font[] + * @return array */ public static function getStyles() { - return self::$_styleElements; + return self::$styles; } /** * Get style by name * * @param string $styleName + * @return Paragraph|Font|Table|Numbering|null */ public static function getStyle($styleName) { - if (array_key_exists($styleName, self::$_styleElements)) { - return self::$_styleElements[$styleName]; + if (array_key_exists($styleName, self::$styles)) { + return self::$styles[$styleName]; } else { return null; } } + + /** + * Set style values and put it to static style collection + * + * @param string $styleName + * @param Paragraph|Font|Table|Numbering $styleObject + * @param array|null $styleValues + */ + private static function setStyleValues($styleName, $styleObject, $styleValues = null) + { + if (!array_key_exists($styleName, self::$styles)) { + if (!is_null($styleValues) && is_array($styleValues)) { + foreach ($styleValues as $key => $value) { + $styleObject->setStyleValue($key, $value); + } + } + $styleObject->setStyleName($styleName); + $styleObject->setIndex(self::countStyles() + 1); // One based index + self::$styles[$styleName] = $styleObject; + } + } } diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php new file mode 100644 index 00000000..c498575a --- /dev/null +++ b/src/PhpWord/Style/AbstractStyle.php @@ -0,0 +1,215 @@ +styleName; + } + + /** + * Set style name + * + * @param string $value + * @return self + */ + public function setStyleName($value) + { + $this->styleName = $value; + + return $this; + } + + /** + * Get index number + * + * @return integer|null + */ + public function getIndex() + { + return $this->index; + } + + /** + * Set index number + * + * @param integer|null $value + * @return self + */ + public function setIndex($value = null) + { + $this->index = $this->setIntVal($value, $this->index); + + return $this; + } + + /** + * Set style value template method + * + * Some child classes have their own specific overrides. + * Backward compability check for versions < 0.10.0 which use underscore + * prefix for their private properties. + * Check if the set method is exists. Throws an exception? + * + * @param string $key + * @param string $value + * @return self + */ + public function setStyleValue($key, $value) + { + $method = 'set' . String::removeUnderscorePrefix($key); + if (method_exists($this, $method)) { + $this->$method($value); + } + + return $this; + } + + /** + * Set style by using associative array + * + * @param array $styles + * @return self + */ + public function setStyleByArray($styles = array()) + { + foreach ($styles as $key => $value) { + $this->setStyleValue($key, $value); + } + + return $this; + } + + /** + * Set default for null and empty value + * + * @param mixed $value + * @param mixed $default + * @return mixed + */ + protected function setNonEmptyVal($value, $default) + { + if (is_null($value) || $value == '') { + $value = $default; + } + + return $value; + } + + /** + * Set boolean value + * + * @param mixed $value + * @param boolean|null $default + * @return boolean|null + */ + protected function setBoolVal($value, $default = null) + { + if (!is_bool($value)) { + $value = $default; + } + + return $value; + } + + /** + * Set numeric value + * + * @param mixed $value + * @param integer|float|null $default + * @return integer|float|null + */ + protected function setNumericVal($value, $default = null) + { + if (!is_numeric($value)) { + $value = $default; + } + + return $value; + } + + /** + * Set integer value + * + * @param mixed $value + * @param integer|null $default + * @return integer|null + */ + protected function setIntVal($value, $default = null) + { + if (!is_int($value)) { + $value = $default; + } + + return $value; + } + + /** + * Set float value + * + * @param mixed $value + * @param float|null $default + * @return float|null + */ + protected function setFloatVal($value, $default = null) + { + if (!is_float($value)) { + $value = $default; + } + + return $value; + } + + /** + * Set enum value + * + * @param mixed $value + * @param array $enum + * @param mixed $default + */ + protected function setEnumVal($value, $enum, $default = null) + { + if (!in_array($value, $enum)) { + $value = $default; + } + + return $value; + } +} diff --git a/src/PhpWord/Style/Border.php b/src/PhpWord/Style/Border.php new file mode 100644 index 00000000..13230863 --- /dev/null +++ b/src/PhpWord/Style/Border.php @@ -0,0 +1,318 @@ +setBorderTopSize($value); + $this->setBorderLeftSize($value); + $this->setBorderRightSize($value); + $this->setBorderBottomSize($value); + + return $this; + } + + /** + * Get border size + * + * @return int[] + */ + public function getBorderSize() + { + return array( + $this->getBorderTopSize(), + $this->getBorderLeftSize(), + $this->getBorderRightSize(), + $this->getBorderBottomSize(), + ); + } + + /** + * Set border color + * + * @param string $value + * @return self + */ + public function setBorderColor($value = null) + { + $this->setBorderTopColor($value); + $this->setBorderLeftColor($value); + $this->setBorderRightColor($value); + $this->setBorderBottomColor($value); + + return $this; + } + + /** + * Get border color + * + * @return string[] + */ + public function getBorderColor() + { + return array( + $this->getBorderTopColor(), + $this->getBorderLeftColor(), + $this->getBorderRightColor(), + $this->getBorderBottomColor(), + ); + } + + /** + * Set border top size + * + * @param int|float $value + * @return self + */ + public function setBorderTopSize($value = null) + { + $this->borderTopSize = $value; + + return $this; + } + + /** + * Get border top size + * + * @return int|float + */ + public function getBorderTopSize() + { + return $this->borderTopSize; + } + + /** + * Set border top color + * + * @param string $value + * @return self + */ + public function setBorderTopColor($value = null) + { + $this->borderTopColor = $value; + + return $this; + } + + /** + * Get border top color + * + * @return string + */ + public function getBorderTopColor() + { + return $this->borderTopColor; + } + + /** + * Set border left size + * + * @param int|float $value + * @return self + */ + public function setBorderLeftSize($value = null) + { + $this->borderLeftSize = $value; + + return $this; + } + + /** + * Get border left size + * + * @return int|float + */ + public function getBorderLeftSize() + { + return $this->borderLeftSize; + } + + /** + * Set border left color + * + * @param string $value + * @return self + */ + public function setBorderLeftColor($value = null) + { + $this->borderLeftColor = $value; + + return $this; + } + + /** + * Get border left color + * + * @return string + */ + public function getBorderLeftColor() + { + return $this->borderLeftColor; + } + + /** + * Set border right size + * + * @param int|float $value + * @return self + */ + public function setBorderRightSize($value = null) + { + $this->borderRightSize = $value; + + return $this; + } + + /** + * Get border right size + * + * @return int|float + */ + public function getBorderRightSize() + { + return $this->borderRightSize; + } + + /** + * Set border right color + * + * @param string $value + * @return self + */ + public function setBorderRightColor($value = null) + { + $this->borderRightColor = $value; + + return $this; + } + + /** + * Get border right color + * + * @return string + */ + public function getBorderRightColor() + { + return $this->borderRightColor; + } + + /** + * Set border bottom size + * + * @param int|float $value + * @return self + */ + public function setBorderBottomSize($value = null) + { + $this->borderBottomSize = $value; + + return $this; + } + + /** + * Get border bottom size + * + * @return int|float + */ + public function getBorderBottomSize() + { + return $this->borderBottomSize; + } + + /** + * Set border bottom color + * + * @param string $value + * @return self + */ + public function setBorderBottomColor($value = null) + { + $this->borderBottomColor = $value; + + return $this; + } + + /** + * Get border bottom color + * + * @return string + */ + public function getBorderBottomColor() + { + return $this->borderBottomColor; + } +} diff --git a/src/PhpWord/Style/Cell.php b/src/PhpWord/Style/Cell.php index b88bcd0b..d7597e0e 100644 --- a/src/PhpWord/Style/Cell.php +++ b/src/PhpWord/Style/Cell.php @@ -2,127 +2,55 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style\Shading; + /** * Table cell style */ -class Cell +class Cell extends Border { + /** + * Text direction constants + * + * @const string + */ const TEXT_DIR_BTLR = 'btLr'; const TEXT_DIR_TBRL = 'tbRl'; + /** + * Default border color + * + * @const string + */ + const DEFAULT_BORDER_COLOR = '000000'; + /** * Vertical align (top, center, both, bottom) * * @var string */ - private $_valign; + private $valign; /** * Text Direction * * @var string */ - private $_textDirection; - - /** - * Background-Color - * - * @var string - */ - private $_bgColor; - - /** - * Border Top Size - * - * @var int - */ - private $_borderTopSize; - - /** - * Border Top Color - * - * @var string - */ - private $_borderTopColor; - - /** - * Border Left Size - * - * @var int - */ - private $_borderLeftSize; - - /** - * Border Left Color - * - * @var string - */ - private $_borderLeftColor; - - /** - * Border Right Size - * - * @var int - */ - private $_borderRightSize; - - /** - * Border Right Color - * - * @var string - */ - private $_borderRightColor; - - /** - * Border Bottom Size - * - * @var int - */ - private $_borderBottomSize; - - /** - * Border Bottom Color - * - * @var string - */ - private $_borderBottomColor; - - /** - * Border Default Color - * - * @var string - */ - private $_defaultBorderColor; + private $textDirection; /** * colspan * * @var integer */ - private $_gridSpan = null; + private $gridSpan = null; /** * rowspan (restart, continue) @@ -132,60 +60,31 @@ class Cell * * @var string */ - private $_vMerge = null; + private $vMerge = null; /** - * Create a new Cell Style - */ - public function __construct() - { - $this->_valign = null; - $this->_textDirection = null; - $this->_bgColor = null; - $this->_borderTopSize = null; - $this->_borderTopColor = null; - $this->_borderLeftSize = null; - $this->_borderLeftColor = null; - $this->_borderRightSize = null; - $this->_borderRightColor = null; - $this->_borderBottomSize = null; - $this->_borderBottomColor = null; - $this->_defaultBorderColor = '000000'; - } - - /** - * Set style value + * Shading * - * @param string $key - * @param mixed $value + * @var \PhpOffice\PhpWord\Style\Shading */ - public function setStyleValue($key, $value) - { - if ($key == '_borderSize') { - $this->setBorderSize($value); - } elseif ($key == '_borderColor') { - $this->setBorderColor($value); - } else { - $this->$key = $value; - } - } + private $shading; /** * Get vertical align */ public function getVAlign() { - return $this->_valign; + return $this->valign; } /** * Set vertical align * - * @param string $pValue + * @param string $value */ - public function setVAlign($pValue = null) + public function setVAlign($value = null) { - $this->_valign = $pValue; + $this->valign = $value; } /** @@ -193,249 +92,50 @@ class Cell */ public function getTextDirection() { - return $this->_textDirection; + return $this->textDirection; } /** * Set text direction * - * @param string $pValue + * @param string $value */ - public function setTextDirection($pValue = null) + public function setTextDirection($value = null) { - $this->_textDirection = $pValue; + $this->textDirection = $value; } /** - * Get background color + * Get background + * + * @return string */ public function getBgColor() { - return $this->_bgColor; + if (!is_null($this->shading)) { + return $this->shading->getFill(); + } } /** - * Set background color + * Set background * - * @param string $pValue + * @param string $value + * @return self */ - public function setBgColor($pValue = null) + public function setBgColor($value = null) { - $this->_bgColor = $pValue; - } - - /** - * Set border size - * - * @param int $pValue - */ - public function setBorderSize($pValue = null) - { - $this->_borderTopSize = $pValue; - $this->_borderLeftSize = $pValue; - $this->_borderRightSize = $pValue; - $this->_borderBottomSize = $pValue; - } - - /** - * Get border size - */ - public function getBorderSize() - { - $t = $this->getBorderTopSize(); - $l = $this->getBorderLeftSize(); - $r = $this->getBorderRightSize(); - $b = $this->getBorderBottomSize(); - - return array($t, $l, $r, $b); - } - - /** - * Set border color - * - * @param string $pValue - */ - public function setBorderColor($pValue = null) - { - $this->_borderTopColor = $pValue; - $this->_borderLeftColor = $pValue; - $this->_borderRightColor = $pValue; - $this->_borderBottomColor = $pValue; - } - - /** - * Get border color - */ - public function getBorderColor() - { - $t = $this->getBorderTopColor(); - $l = $this->getBorderLeftColor(); - $r = $this->getBorderRightColor(); - $b = $this->getBorderBottomColor(); - - return array($t, $l, $r, $b); - } - - /** - * Set border top size - * - * @param int $pValue - */ - public function setBorderTopSize($pValue = null) - { - $this->_borderTopSize = $pValue; - } - - /** - * Get border top size - */ - public function getBorderTopSize() - { - return $this->_borderTopSize; - } - - /** - * Set border top color - * - * @param string $pValue - */ - public function setBorderTopColor($pValue = null) - { - $this->_borderTopColor = $pValue; - } - - /** - * Get border top color - */ - public function getBorderTopColor() - { - return $this->_borderTopColor; - } - - /** - * Set border left size - * - * @param int $pValue - */ - public function setBorderLeftSize($pValue = null) - { - $this->_borderLeftSize = $pValue; - } - - /** - * Get border left size - */ - public function getBorderLeftSize() - { - return $this->_borderLeftSize; - } - - /** - * Set border left color - * - * @param string $pValue - */ - public function setBorderLeftColor($pValue = null) - { - $this->_borderLeftColor = $pValue; - } - - /** - * Get border left color - */ - public function getBorderLeftColor() - { - return $this->_borderLeftColor; - } - - /** - * Set border right size - * - * @param int $pValue - */ - public function setBorderRightSize($pValue = null) - { - $this->_borderRightSize = $pValue; - } - - /** - * Get border right size - */ - public function getBorderRightSize() - { - return $this->_borderRightSize; - } - - /** - * Set border right color - * - * @param string $pValue - */ - public function setBorderRightColor($pValue = null) - { - $this->_borderRightColor = $pValue; - } - - /** - * Get border right color - */ - public function getBorderRightColor() - { - return $this->_borderRightColor; - } - - /** - * Set border bottom size - * - * @param int $pValue - */ - public function setBorderBottomSize($pValue = null) - { - $this->_borderBottomSize = $pValue; - } - - /** - * Get border bottom size - */ - public function getBorderBottomSize() - { - return $this->_borderBottomSize; - } - - /** - * Set border bottom color - * - * @param string $pValue - */ - public function setBorderBottomColor($pValue = null) - { - $this->_borderBottomColor = $pValue; - } - - /** - * Get border bottom color - */ - public function getBorderBottomColor() - { - return $this->_borderBottomColor; - } - - /** - * Get default border color - */ - public function getDefaultBorderColor() - { - return $this->_defaultBorderColor; + return $this->setShading(array('fill' => $value)); } /** * Set grid span (colspan) * - * @param int $pValue + * @param int $value */ - public function setGridSpan($pValue = null) + public function setGridSpan($value = null) { - $this->_gridSpan = $pValue; + $this->gridSpan = $value; } /** @@ -443,17 +143,17 @@ class Cell */ public function getGridSpan() { - return $this->_gridSpan; + return $this->gridSpan; } /** * Set vertical merge (rowspan) * - * @param string $pValue + * @param string $value */ - public function setVMerge($pValue = null) + public function setVMerge($value = null) { - $this->_vMerge = $pValue; + $this->vMerge = $value; } /** @@ -461,6 +161,47 @@ class Cell */ public function getVMerge() { - return $this->_vMerge; + return $this->vMerge; + } + + /** + * Get shading + * + * @return \PhpOffice\PhpWord\Style\Shading + */ + public function getShading() + { + return $this->shading; + } + + /** + * Set shading + * + * @param array $value + * @return self + */ + public function setShading($value = null) + { + if (is_array($value)) { + if (!$this->shading instanceof Shading) { + $this->shading = new Shading(); + } + $this->shading->setStyleByArray($value); + } else { + $this->shading = null; + } + + return $this; + } + + /** + * Get default border color + * + * @deprecated 0.10.0 + * @codeCoverageIgnore + */ + public function getDefaultBorderColor() + { + return self::DEFAULT_BORDER_COLOR; } } diff --git a/src/PhpWord/Style/Font.php b/src/PhpWord/Style/Font.php index 0b3df2ac..86467d02 100644 --- a/src/PhpWord/Style/Font.php +++ b/src/PhpWord/Style/Font.php @@ -2,37 +2,27 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Exceptions\InvalidStyleException; +use PhpOffice\PhpWord\Exception\InvalidStyleException; +use PhpOffice\PhpWord\Style\Shading; /** * Font style */ -class Font +class Font extends AbstractStyle { + /** + * Underline types + * + * @const string + */ const UNDERLINE_NONE = 'none'; const UNDERLINE_DASH = 'dash'; const UNDERLINE_DASHHEAVY = 'dashHeavy'; @@ -51,6 +41,12 @@ class Font const UNDERLINE_WAVYDOUBLE = 'wavyDbl'; const UNDERLINE_WAVYHEAVY = 'wavyHeavy'; const UNDERLINE_WORDS = 'words'; + + /** + * Foreground colors + * + * @const string + */ const FGCOLOR_YELLOW = 'yellow'; const FGCOLOR_LIGHTGREEN = 'green'; const FGCOLOR_CYAN = 'cyan'; @@ -72,84 +68,97 @@ class Font * * @var string */ - private $_type; + private $type; /** * Paragraph style * * @var \PhpOffice\PhpWord\Style\Paragraph */ - private $_paragraphStyle; + private $paragraphStyle; /** * Font name * * @var int|float */ - private $_name = PhpWord::DEFAULT_FONT_NAME; + private $name = PhpWord::DEFAULT_FONT_NAME; /** * Font size * * @var int|float */ - private $_size = PhpWord::DEFAULT_FONT_SIZE; + private $size = PhpWord::DEFAULT_FONT_SIZE; /** * Bold * * @var bool */ - private $_bold = false; + private $bold = false; /** * Italic * * @var bool */ - private $_italic = false; + private $italic = false; /** * Superscript * * @var bool */ - private $_superScript = false; + private $superScript = false; /** * Subscript * * @var bool */ - private $_subScript = false; + private $subScript = false; /** * Undeline * * @var string */ - private $_underline = self::UNDERLINE_NONE; + private $underline = self::UNDERLINE_NONE; /** * Strikethrough * * @var bool */ - private $_strikethrough = false; + private $strikethrough = false; + + /** + * Double strikethrough + * + * @var bool + */ + private $doubleStrikethrough = false; /** * Font color * * @var string */ - private $_color = PhpWord::DEFAULT_FONT_COLOR; + private $color = PhpWord::DEFAULT_FONT_COLOR; /** * Foreground/highlight * * @var string */ - private $_fgColor = null; + private $fgColor = null; + + /** + * Text line height + * + * @var int + */ /** * Text line height @@ -163,7 +172,30 @@ class Font * * @var string */ - private $_hint = PhpWord::DEFAULT_FONT_CONTENT_TYPE; + private $hint = PhpWord::DEFAULT_FONT_CONTENT_TYPE; + + /** + * Small caps + * + * @var bool + * @link http://www.schemacentral.com/sc/ooxml/e-w_smallCaps-1.html + */ + private $smallCaps = false; + + /** + * All caps + * + * @var bool + * @link http://www.schemacentral.com/sc/ooxml/e-w_caps-1.html + */ + private $allCaps = false; + + /** + * Shading + * + * @var \PhpOffice\PhpWord\Style\Shading + */ + private $shading; /** * Create new font style @@ -173,15 +205,15 @@ class Font */ public function __construct($type = 'text', $paragraphStyle = null) { - $this->_type = $type; + $this->type = $type; if ($paragraphStyle instanceof Paragraph) { - $this->_paragraphStyle = $paragraphStyle; + $this->paragraphStyle = $paragraphStyle; } elseif (is_array($paragraphStyle)) { - $this->_paragraphStyle = new Paragraph; - $this->_paragraphStyle->setArrayStyle($paragraphStyle); + $this->paragraphStyle = new Paragraph; + $this->paragraphStyle->setArrayStyle($paragraphStyle); } else { - $this->_paragraphStyle = $paragraphStyle; + $this->paragraphStyle = $paragraphStyle; } } @@ -197,8 +229,6 @@ class Font if ($key === 'line-height') { $this->setLineHeight($value); null; - } elseif (substr($key, 0, 1) !== '_') { - $key = '_' . $key; } $this->setStyleValue($key, $value); } @@ -206,42 +236,26 @@ class Font return $this; } - /** - * Set style value - * - * @param string $key - * @param mixed $value - */ - public function setStyleValue($key, $value) - { - $method = 'set' . substr($key, 1); - if (method_exists($this, $method)) { - $this->$method($value); - } - } - /** * Get font name * - * @return bool + * @return string */ public function getName() { - return $this->_name; + return $this->name; } /** * Set font name * - * @param string $pValue - * @return \PhpOffice\PhpWord\Style\Font + * @param string $value + * @return self */ - public function setName($pValue = PhpWord::DEFAULT_FONT_NAME) + public function setName($value = PhpWord::DEFAULT_FONT_NAME) { - if (is_null($pValue) || $pValue == '') { - $pValue = PhpWord::DEFAULT_FONT_NAME; - } - $this->_name = $pValue; + $this->name = $this->setNonEmptyVal($value, PhpWord::DEFAULT_FONT_NAME); + return $this; } @@ -253,21 +267,19 @@ class Font */ public function getSize() { - return $this->_size; + return $this->size; } /** * Set font size * - * @param int|float $pValue - * @return \PhpOffice\PhpWord\Style\Font + * @param int|float $value + * @return self */ - public function setSize($pValue = PhpWord::DEFAULT_FONT_SIZE) + public function setSize($value = PhpWord::DEFAULT_FONT_SIZE) { - if (!is_numeric($pValue)) { - $pValue = PhpWord::DEFAULT_FONT_SIZE; - } - $this->_size = $pValue; + $this->size = $this->setNumericVal($value, PhpWord::DEFAULT_FONT_SIZE); + return $this; } @@ -278,21 +290,19 @@ class Font */ public function getBold() { - return $this->_bold; + return $this->bold; } /** * Set bold * - * @param bool $pValue - * @return \PhpOffice\PhpWord\Style\Font + * @param bool $value + * @return self */ - public function setBold($pValue = false) + public function setBold($value = false) { - if (!is_bool($pValue)) { - $pValue = false; - } - $this->_bold = $pValue; + $this->bold = $this->setBoolVal($value, $this->bold); + return $this; } @@ -303,21 +313,19 @@ class Font */ public function getItalic() { - return $this->_italic; + return $this->italic; } /** * Set italic * - * @param bool $pValue - * @return \PhpOffice\PhpWord\Style\Font + * @param bool $value + * @return self */ - public function setItalic($pValue = false) + public function setItalic($value = false) { - if (!is_bool($pValue)) { - $pValue = false; - } - $this->_italic = $pValue; + $this->italic = $this->setBoolVal($value, $this->italic); + return $this; } @@ -328,22 +336,22 @@ class Font */ public function getSuperScript() { - return $this->_superScript; + return $this->superScript; } /** * Set superscript * - * @param bool $pValue - * @return \PhpOffice\PhpWord\Style\Font + * @param bool $value + * @return self */ - public function setSuperScript($pValue = false) + public function setSuperScript($value = false) { - if (!is_bool($pValue)) { - $pValue = false; + $this->superScript = $this->setBoolVal($value, $this->superScript); + if ($this->superScript) { + $this->subScript = false; } - $this->_superScript = $pValue; - $this->_subScript = !$pValue; + return $this; } @@ -354,22 +362,22 @@ class Font */ public function getSubScript() { - return $this->_subScript; + return $this->subScript; } /** * Set subscript * - * @param bool $pValue - * @return \PhpOffice\PhpWord\Style\Font + * @param bool $value + * @return self */ - public function setSubScript($pValue = false) + public function setSubScript($value = false) { - if (!is_bool($pValue)) { - $pValue = false; + $this->subScript = $this->setBoolVal($value, $this->subScript); + if ($this->subScript) { + $this->superScript = false; } - $this->_subScript = $pValue; - $this->_superScript = !$pValue; + return $this; } @@ -380,21 +388,19 @@ class Font */ public function getUnderline() { - return $this->_underline; + return $this->underline; } /** * Set underline * - * @param string $pValue - * @return \PhpOffice\PhpWord\Style\Font + * @param string $value + * @return self */ - public function setUnderline($pValue = self::UNDERLINE_NONE) + public function setUnderline($value = self::UNDERLINE_NONE) { - if ($pValue == '') { - $pValue = self::UNDERLINE_NONE; - } - $this->_underline = $pValue; + $this->underline = $this->setNonEmptyVal($value, self::UNDERLINE_NONE); + return $this; } @@ -405,21 +411,48 @@ class Font */ public function getStrikethrough() { - return $this->_strikethrough; + return $this->strikethrough; } /** * Set strikethrough * - * @param bool $pValue - * @return \PhpOffice\PhpWord\Style\Font + * @param bool $value + * @return self */ - public function setStrikethrough($pValue = false) + public function setStrikethrough($value = false) { - if (!is_bool($pValue)) { - $pValue = false; + $this->strikethrough = $this->setBoolVal($value, $this->strikethrough); + if ($this->strikethrough) { + $this->doubleStrikethrough = false; } - $this->_strikethrough = $pValue; + + return $this; + } + + /** + * Get double strikethrough + * + * @return bool + */ + public function getDoubleStrikethrough() + { + return $this->doubleStrikethrough; + } + + /** + * Set double strikethrough + * + * @param bool $value + * @return self + */ + public function setDoubleStrikethrough($value = false) + { + $this->doubleStrikethrough = $this->setBoolVal($value, $this->doubleStrikethrough); + if ($this->doubleStrikethrough) { + $this->strikethrough = false; + } + return $this; } @@ -430,46 +463,68 @@ class Font */ public function getColor() { - return $this->_color; + return $this->color; } /** * Set font color * - * @param string $pValue - * @return \PhpOffice\PhpWord\Style\Font + * @param string $value + * @return self */ - public function setColor($pValue = PhpWord::DEFAULT_FONT_COLOR) + public function setColor($value = PhpWord::DEFAULT_FONT_COLOR) { - if (is_null($pValue) || $pValue == '') { - $pValue = PhpWord::DEFAULT_FONT_COLOR; - } - $this->_color = $pValue; + $this->color = $this->setNonEmptyVal($value, PhpWord::DEFAULT_FONT_COLOR); + return $this; } /** * Get foreground/highlight color * - * @return bool + * @return string */ public function getFgColor() { - return $this->_fgColor; + return $this->fgColor; } /** * Set foreground/highlight color * - * @param string $pValue - * @return \PhpOffice\PhpWord\Style\Font + * @param string $value + * @return self */ - public function setFgColor($pValue = null) + public function setFgColor($value = null) { - $this->_fgColor = $pValue; + $this->fgColor = $value; + return $this; } + /** + * Get background + * + * @return string + */ + public function getBgColor() + { + if (!is_null($this->shading)) { + return $this->shading->getFill(); + } + } + + /** + * Set background + * + * @param string $value + * @return \PhpOffice\PhpWord\Style\Table + */ + public function setBgColor($value = null) + { + $this->setShading(array('fill' => $value)); + } + /** * Get style type * @@ -477,7 +532,7 @@ class Font */ public function getStyleType() { - return $this->_type; + return $this->type; } /** @@ -487,7 +542,7 @@ class Font */ public function getParagraphStyle() { - return $this->_paragraphStyle; + return $this->paragraphStyle; } /** @@ -495,7 +550,7 @@ class Font * * @param int|float|string $lineHeight * @return $this - * @throws \PhpOffice\PhpWord\Exceptions\InvalidStyleException + * @throws \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function setLineHeight($lineHeight) { @@ -525,25 +580,105 @@ class Font /** * Get Font Content Type * - * @return bool + * @return string */ public function getHint() { - return $this->_hint; + return $this->hint; } /** * Set Font Content Type * - * @param string $pValue - * @return \PhpOffice\PhpWord\Style\Font + * @param string $value + * @return self */ - public function setHint($pValue = PhpWord::DEFAULT_FONT_CONTENT_TYPE) + public function setHint($value = PhpWord::DEFAULT_FONT_CONTENT_TYPE) { - if (is_null($pValue) || $pValue == '') { - $pValue = PhpWord::DEFAULT_FONT_CONTENT_TYPE; + $this->hint = $this->setNonEmptyVal($value, PhpWord::DEFAULT_FONT_CONTENT_TYPE); + + return $this; + } + + /** + * Get small caps + * + * @return bool + */ + public function getSmallCaps() + { + return $this->smallCaps; + } + + /** + * Set small caps + * + * @param bool $value + * @return self + */ + public function setSmallCaps($value = false) + { + $this->smallCaps = $this->setBoolVal($value, $this->smallCaps); + if ($this->smallCaps) { + $this->allCaps = false; } - $this->_hint = $pValue; + + return $this; + } + + /** + * Get all caps + * + * @return bool + */ + public function getAllCaps() + { + return $this->allCaps; + } + + /** + * Set all caps + * + * @param bool $value + * @return self + */ + public function setAllCaps($value = false) + { + $this->allCaps = $this->setBoolVal($value, $this->allCaps); + if ($this->allCaps) { + $this->smallCaps = false; + } + + return $this; + } + + /** + * Get shading + * + * @return \PhpOffice\PhpWord\Style\Shading + */ + public function getShading() + { + return $this->shading; + } + + /** + * Set shading + * + * @param array $value + * @return self + */ + public function setShading($value = null) + { + if (is_array($value)) { + if (!$this->shading instanceof Shading) { + $this->shading = new Shading(); + } + $this->shading->setStyleByArray($value); + } else { + $this->shading = null; + } + return $this; } } diff --git a/src/PhpWord/Style/Image.php b/src/PhpWord/Style/Image.php index 30fa73f7..f21e6674 100644 --- a/src/PhpWord/Style/Image.php +++ b/src/PhpWord/Style/Image.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; @@ -28,7 +12,7 @@ namespace PhpOffice\PhpWord\Style; /** * Image and memory image style */ -class Image +class Image extends AbstractStyle { const WRAPPING_STYLE_INLINE = 'inline'; const WRAPPING_STYLE_SQUARE = 'square'; @@ -41,21 +25,35 @@ class Image * * @var int */ - private $_width; + private $width; /** * Image width * * @var int */ - private $_height; + private $height; /** * Alignment * * @var string */ - private $_align; + private $align; + + /** + * Margin Top + * + * @var int + */ + private $marginTop; + + /** + * Margin Left + * + * @var int + */ + private $marginLeft; /** * Wrapping style @@ -64,50 +62,25 @@ class Image */ private $wrappingStyle; - /** - * Margin Top - * - * @var int - */ - private $_marginTop; - - /** - * Margin Left - * - * @var int - */ - private $_marginLeft; - /** * Create new image style */ public function __construct() { - $this->_width = null; - $this->_height = null; - $this->_align = null; - $this->_marginTop = null; - $this->_marginLeft = null; + $this->width = null; + $this->height = null; + $this->align = null; + $this->marginTop = null; + $this->marginLeft = null; $this->setWrappingStyle(self::WRAPPING_STYLE_INLINE); } - /** - * Set style value - * - * @param string $key - * @param mixed $value - */ - public function setStyleValue($key, $value) - { - $this->$key = $value; - } - /** * Get width */ public function getWidth() { - return $this->_width; + return $this->width; } /** @@ -117,7 +90,7 @@ class Image */ public function setWidth($pValue = null) { - $this->_width = $pValue; + $this->width = $pValue; } /** @@ -125,7 +98,7 @@ class Image */ public function getHeight() { - return $this->_height; + return $this->height; } /** @@ -135,7 +108,7 @@ class Image */ public function setHeight($pValue = null) { - $this->_height = $pValue; + $this->height = $pValue; } /** @@ -143,7 +116,7 @@ class Image */ public function getAlign() { - return $this->_align; + return $this->align; } /** @@ -153,7 +126,7 @@ class Image */ public function setAlign($pValue = null) { - $this->_align = $pValue; + $this->align = $pValue; } /** @@ -163,7 +136,7 @@ class Image */ public function getMarginTop() { - return $this->_marginTop; + return $this->marginTop; } /** @@ -174,7 +147,7 @@ class Image */ public function setMarginTop($pValue = null) { - $this->_marginTop = $pValue; + $this->marginTop = $pValue; return $this; } @@ -185,7 +158,7 @@ class Image */ public function getMarginLeft() { - return $this->_marginLeft; + return $this->marginLeft; } /** @@ -196,7 +169,7 @@ class Image */ public function setMarginLeft($pValue = null) { - $this->_marginLeft = $pValue; + $this->marginLeft = $pValue; return $this; } @@ -219,7 +192,6 @@ class Image break; default: throw new \InvalidArgumentException('Wrapping style does not exists'); - break; } return $this; } diff --git a/src/PhpWord/Style/Indentation.php b/src/PhpWord/Style/Indentation.php new file mode 100644 index 00000000..bda2c9ad --- /dev/null +++ b/src/PhpWord/Style/Indentation.php @@ -0,0 +1,149 @@ +setStyleByArray($style); + } + + /** + * Get left + * + * @return int|float + */ + public function getLeft() + { + return $this->left; + } + + /** + * Set left + * + * @param int|float $value + * @return self + */ + public function setLeft($value = null) + { + $this->left = $this->setNumericVal($value, $this->left); + + return $this; + } + + /** + * Get right + * + * @return int|float + */ + public function getRight() + { + return $this->right; + } + + /** + * Set right + * + * @param int|float $value + * @return self + */ + public function setRight($value = null) + { + $this->right = $this->setNumericVal($value, $this->right); + + return $this; + } + + /** + * Get first line + * + * @return int|float + */ + public function getFirstLine() + { + return $this->firstLine; + } + + /** + * Set first line + * + * @param int|float $value + * @return self + */ + public function setFirstLine($value = null) + { + $this->firstLine = $this->setNumericVal($value, $this->firstLine); + + return $this; + } + + /** + * Get hanging + * + * @return int|float + */ + public function getHanging() + { + return $this->hanging; + } + + /** + * Set hanging + * + * @param int|float $value + * @return self + */ + public function setHanging($value = null) + { + $this->hanging = $this->setNumericVal($value, $this->hanging); + + return $this; + } +} diff --git a/src/PhpWord/Style/LineNumbering.php b/src/PhpWord/Style/LineNumbering.php new file mode 100644 index 00000000..384d5d42 --- /dev/null +++ b/src/PhpWord/Style/LineNumbering.php @@ -0,0 +1,155 @@ +setStyleByArray($style); + } + + /** + * Get start + * + * @return int + */ + public function getStart() + { + return $this->start; + } + + /** + * Set start + * + * @param int $value + * @return self + */ + public function setStart($value = null) + { + $this->start = $this->setIntVal($value, $this->start); + + return $this; + } + + /** + * Get increment + * + * @return int + */ + public function getIncrement() + { + return $this->increment; + } + + /** + * Set increment + * + * @param int $value + * @return self + */ + public function setIncrement($value = null) + { + $this->increment = $this->setIntVal($value, $this->increment); + + return $this; + } + + /** + * Get distance + * + * @return int|float + */ + public function getDistance() + { + return $this->distance; + } + + /** + * Set distance + * + * @param int|float $value + * @return self + */ + public function setDistance($value = null) + { + $this->distance = $this->setNumericVal($value, $this->distance); + + return $this; + } + + /** + * Get restart + * + * @return string + */ + public function getRestart() + { + return $this->restart; + } + + /** + * Set distance + * + * @param string $value + * @return self + */ + public function setRestart($value = null) + { + $enum = array(self::LINE_NUMBERING_CONTINUOUS, self::LINE_NUMBERING_NEW_PAGE, self::LINE_NUMBERING_NEW_SECTION); + $this->restart = $this->setEnumVal($value, $enum, $this->restart); + + return $this; + } +} diff --git a/src/PhpWord/Style/ListItem.php b/src/PhpWord/Style/ListItem.php index 1efd67fd..a4f4933d 100644 --- a/src/PhpWord/Style/ListItem.php +++ b/src/PhpWord/Style/ListItem.php @@ -2,80 +2,246 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style; + /** * List item style + * + * Before version 0.10.0, numbering style is defined statically with $listType. + * After version 0.10.0, numbering style is defined by using Numbering and + * recorded by $numStyle. $listStyle is maintained for backward compatility */ -class ListItem +class ListItem extends AbstractStyle { + const TYPE_SQUARE_FILLED = 1; + const TYPE_BULLET_FILLED = 3; // default + const TYPE_BULLET_EMPTY = 5; const TYPE_NUMBER = 7; const TYPE_NUMBER_NESTED = 8; const TYPE_ALPHANUM = 9; - const TYPE_BULLET_FILLED = 3; - const TYPE_BULLET_EMPTY = 5; - const TYPE_SQUARE_FILLED = 1; /** - * List Type - */ - private $_listType; - - /** - * Create a new ListItem Style - */ - public function __construct() - { - $this->_listType = self::TYPE_BULLET_FILLED; - } - - /** - * Set style value + * Legacy list type * - * @param string $key - * @param string $value + * @var integer */ - public function setStyleValue($key, $value) - { - $this->$key = $value; - } + private $listType; /** - * Set List Type + * Numbering style name * - * @param int $pValue + * @var string + * @since 0.10.0 */ - public function setListType($pValue = self::TYPE_BULLET_FILLED) + private $numStyle; + + /** + * Numbering definition instance ID + * + * @var integer + * @since 0.10.0 + */ + private $numId; + + /** + * Create new instance + * + * @param string $numStyle + */ + public function __construct($numStyle = null) { - $this->_listType = $pValue; + if (!is_null($numStyle)) { + $this->setNumStyle($numStyle); + } else { + $this->setListType(); + } } /** * Get List Type + * + * @return integer */ public function getListType() { - return $this->_listType; + return $this->listType; + } + + /** + * Set legacy list type for version < 0.10.0 + * + * @param integer $value + */ + public function setListType($value = self::TYPE_BULLET_FILLED) + { + $enum = array(self::TYPE_SQUARE_FILLED, self::TYPE_BULLET_FILLED, + self::TYPE_BULLET_EMPTY, self::TYPE_NUMBER, + self::TYPE_NUMBER_NESTED, self::TYPE_ALPHANUM); + $this->listType = $this->setEnumVal($value, $enum, $this->listType); + $this->getListTypeStyle(); + } + + /** + * Get numbering style name + * + * @return string + */ + public function getNumStyle() + { + return $this->numStyle; + } + + /** + * Set numbering style name + * + * @param string $value + */ + public function setNumStyle($value) + { + $this->numStyle = $value; + $numStyleObject = Style::getStyle($this->numStyle); + if ($numStyleObject instanceof Numbering) { + $this->numId = $numStyleObject->getIndex(); + $numStyleObject->setNumId($this->numId); + } + } + + /** + * Get numbering Id + * + * @return integer + */ + public function getNumId() + { + return $this->numId; + } + + /** + * Get legacy numbering definition + * + * @return array + * @since 0.10.0 + */ + private function getListTypeStyle() + { + // Check if legacy style already registered in global Style collection + $numStyle = "PHPWordList{$this->listType}"; + if (!is_null(Style::getStyle($numStyle))) { + $this->setNumStyle($numStyle); + return; + } + + // Property mapping for numbering level information + $properties = array('start', 'format', 'text', 'align', 'tabPos', 'left', 'hanging', 'font', 'hint'); + + // Legacy level information + $listTypeStyles = array( + self::TYPE_SQUARE_FILLED => array( + 'type' => 'hybridMultilevel', + 'levels' => array( + 0 => '1, bullet, , left, 720, 720, 360, Wingdings, default', + 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', + 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', + 3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default', + 4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default', + 5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default', + 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', + 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', + 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', + ), + ), + self::TYPE_BULLET_FILLED => array( + 'type' => 'hybridMultilevel', + 'levels' => array( + 0 => '1, bullet, , left, 720, 720, 360, Symbol, default', + 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', + 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', + 3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default', + 4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default', + 5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default', + 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', + 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', + 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', + ), + ), + self::TYPE_BULLET_EMPTY => array( + 'type' => 'hybridMultilevel', + 'levels' => array( + 0 => '1, bullet, o, left, 720, 720, 360, Courier New, default', + 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', + 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', + 3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default', + 4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default', + 5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default', + 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', + 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', + 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', + ), + ), + self::TYPE_NUMBER => array( + 'type' => 'hybridMultilevel', + 'levels' => array( + 0 => '1, decimal, %1., left, 720, 720, 360, , default', + 1 => '1, bullet, o, left, 1440, 1440, 360, Courier New, default', + 2 => '1, bullet, , left, 2160, 2160, 360, Wingdings, default', + 3 => '1, bullet, , left, 2880, 2880, 360, Symbol, default', + 4 => '1, bullet, o, left, 3600, 3600, 360, Courier New, default', + 5 => '1, bullet, , left, 4320, 4320, 360, Wingdings, default', + 6 => '1, bullet, , left, 5040, 5040, 360, Symbol, default', + 7 => '1, bullet, o, left, 5760, 5760, 360, Courier New, default', + 8 => '1, bullet, , left, 6480, 6480, 360, Wingdings, default', + ), + ), + self::TYPE_NUMBER_NESTED => array( + 'type' => 'multilevel', + 'levels' => array( + 0 => '1, decimal, %1., left, 360, 360, 360, , ', + 1 => '1, decimal, %1.%2., left, 792, 792, 432, , ', + 2 => '1, decimal, %1.%2.%3., left, 1224, 1224, 504, , ', + 3 => '1, decimal, %1.%2.%3.%4., left, 1800, 1728, 648, , ', + 4 => '1, decimal, %1.%2.%3.%4.%5., left, 2520, 2232, 792, , ', + 5 => '1, decimal, %1.%2.%3.%4.%5.%6., left, 2880, 2736, 936, , ', + 6 => '1, decimal, %1.%2.%3.%4.%5.%6.%7., left, 3600, 3240, 1080, , ', + 7 => '1, decimal, %1.%2.%3.%4.%5.%6.%7.%8., left, 3960, 3744, 1224, , ', + 8 => '1, decimal, %1.%2.%3.%4.%5.%6.%7.%8.%9., left, 4680, 4320, 1440, , ', + ), + ), + self::TYPE_ALPHANUM => array( + 'type' => 'multilevel', + 'levels' => array( + 0 => '1, decimal, %1., left, 720, 720, 360, , ', + 1 => '1, lowerLetter, %2., left, 1440, 1440, 360, , ', + 2 => '1, lowerRoman, %3., right, 2160, 2160, 180, , ', + 3 => '1, decimal, %4., left, 2880, 2880, 360, , ', + 4 => '1, lowerLetter, %5., left, 3600, 3600, 360, , ', + 5 => '1, lowerRoman, %6., right, 4320, 4320, 180, , ', + 6 => '1, decimal, %7., left, 5040, 5040, 360, , ', + 7 => '1, lowerLetter, %8., left, 5760, 5760, 360, , ', + 8 => '1, lowerRoman, %9., right, 6480, 6480, 180, , ', + ), + ), + ); + + // Populate style and register to global Style register + $style = $listTypeStyles[$this->listType]; + foreach ($style['levels'] as $key => $value) { + $level = array(); + $levelProperties = explode(', ', $value); + $level['level'] = $key; + for ($i = 0; $i < count($properties); $i++) { + $property = $properties[$i]; + $level[$property] = $levelProperties[$i]; + } + $style['levels'][$key] = $level; + } + Style::addNumberingStyle($numStyle, $style); + $this->setNumStyle($numStyle); } } diff --git a/src/PhpWord/Style/Numbering.php b/src/PhpWord/Style/Numbering.php new file mode 100644 index 00000000..8c2e4a69 --- /dev/null +++ b/src/PhpWord/Style/Numbering.php @@ -0,0 +1,123 @@ +numId; + } + + /** + * Set Id + * + * @param integer $value + * @return self + */ + public function setNumId($value) + { + $this->numId = $this->setIntVal($value, $this->numId); + return $this; + } + + /** + * Get multilevel type + * + * @return string + */ + public function getType() + { + return $this->type; + } + + /** + * Set multilevel type + * + * @param string $value + * @return self + */ + public function setType($value) + { + $enum = array('singleLevel', 'multilevel', 'hybridMultilevel'); + $this->type = $this->setEnumVal($value, $enum, $this->type); + return $this; + } + + /** + * Get levels + * + * @return NumberingLevel[] + */ + public function getLevels() + { + return $this->levels; + } + + /** + * Set multilevel type + * + * @param array $values + * @return self + */ + public function setLevels($values) + { + if (is_array($values)) { + foreach ($values as $key => $value) { + $numberingLevel = new NumberingLevel(); + if (is_array($value)) { + $numberingLevel->setStyleByArray($value); + $numberingLevel->setLevel($key); + } + $this->levels[$key] = $numberingLevel; + } + } + + return $this; + } +} diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php new file mode 100644 index 00000000..dff7de22 --- /dev/null +++ b/src/PhpWord/Style/NumberingLevel.php @@ -0,0 +1,378 @@ +level; + } + + /** + * Set level + * + * @param integer $value + * @return self + */ + public function setLevel($value) + { + $this->level = $this->setIntVal($value, $this->level); + return $this; + } + + /** + * Get start + * + * @return integer + */ + public function getStart() + { + return $this->start; + } + + /** + * Set start + * + * @param integer $value + * @return self + */ + public function setStart($value) + { + $this->start = $this->setIntVal($value, $this->start); + return $this; + } + + /** + * Get format + * + * @return string + */ + public function getFormat() + { + return $this->format; + } + + /** + * Set format + * + * @param string $value + * @return self + */ + public function setFormat($value) + { + $enum = array('bullet', 'decimal', 'upperRoman', 'lowerRoman', 'upperLetter', 'lowerLetter'); + $this->format = $this->setEnumVal($value, $enum, $this->format); + return $this; + } + + /** + * Get start + * + * @return integer + */ + public function getRestart() + { + return $this->restart; + } + + /** + * Set start + * + * @param integer $value + * @return self + */ + public function setRestart($value) + { + $this->restart = $this->setIntVal($value, $this->restart); + return $this; + } + + /** + * Get suffix + * + * @return string + */ + public function getSuffix() + { + return $this->suffix; + } + + /** + * Set suffix + * + * @param string $value + * @return self + */ + public function setSuffix($value) + { + $enum = array('tab', 'space', 'nothing'); + $this->suffix = $this->setEnumVal($value, $enum, $this->suffix); + return $this; + } + + /** + * Get text + * + * @return string + */ + public function getText() + { + return $this->text; + } + + /** + * Set text + * + * @param string $value + * @return self + */ + public function setText($value) + { + $this->text = $value; + return $this; + } + + /** + * Get align + * + * @return string + */ + public function getAlign() + { + return $this->align; + } + + /** + * Set align + * + * @param string $value + * @return self + */ + public function setAlign($value) + { + $enum = array('left', 'center', 'right', 'both'); + $this->align = $this->setEnumVal($value, $enum, $this->align); + return $this; + } + + /** + * Get left + * + * @return integer + */ + public function getLeft() + { + return $this->left; + } + + /** + * Set left + * + * @param integer $value + * @return self + */ + public function setLeft($value) + { + $this->left = $this->setIntVal($value, $this->left); + return $this; + } + + /** + * Get hanging + * + * @return integer + */ + public function getHanging() + { + return $this->hanging; + } + + /** + * Set hanging + * + * @param integer $value + * @return self + */ + public function setHanging($value) + { + $this->hanging = $this->setIntVal($value, $this->hanging); + return $this; + } + + /** + * Get tab + * + * @return integer + */ + public function getTabPos() + { + return $this->tabPos; + } + + /** + * Set tab + * + * @param integer $value + * @return self + */ + public function setTabPos($value) + { + $this->tabPos = $this->setIntVal($value, $this->tabPos); + return $this; + } + + /** + * Get font + * + * @return string + */ + public function getFont() + { + return $this->font; + } + + /** + * Set font + * + * @param string $value + * @return self + */ + public function setFont($value) + { + $this->font = $value; + return $this; + } + + /** + * Get hint + * + * @return string + */ + public function getHint() + { + return $this->hint; + } + + /** + * Set hint + * + * @param string $value + * @return self + */ + public function setHint($value) + { + $enum = array('default', 'eastAsia', 'cs'); + $this->hint = $this->setEnumVal($value, $enum, $this->hint); + return $this; + } +} diff --git a/src/PhpWord/Style/Paragraph.php b/src/PhpWord/Style/Paragraph.php old mode 100755 new mode 100644 index 5f7ebbed..b6f482bf --- a/src/PhpWord/Style/Paragraph.php +++ b/src/PhpWord/Style/Paragraph.php @@ -2,38 +2,32 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; -use PhpOffice\PhpWord\Exceptions\InvalidStyleException; +use PhpOffice\PhpWord\Exception\InvalidStyleException; +use PhpOffice\PhpWord\Shared\String; +use PhpOffice\PhpWord\Style\Indentation; +use PhpOffice\PhpWord\Style\Spacing; /** * Paragraph style */ -class Paragraph +class Paragraph extends AbstractStyle { const LINE_HEIGHT = 240; + /** + * Paragraph alignment + * + * @var string + */ + private $align; + /** * Text line height * @@ -41,96 +35,68 @@ class Paragraph */ private $lineHeight; - /** - * Paragraph alignment - * - * @var string - */ - private $_align; - - /** - * Space before Paragraph - * - * @var int - */ - private $_spaceBefore; - - /** - * Space after Paragraph - * - * @var int - */ - private $_spaceAfter; - - /** - * Spacing between breaks - * - * @var int - */ - private $_spacing; - /** * Set of Custom Tab Stops * - * @var array + * @var \PhpOffice\PhpWord\Style\Tab[] */ - private $_tabs; - - /** - * Indent by how much - * - * @var int - */ - private $_indent; - - /** - * Hanging by how much - * - * @var int - */ - private $_hanging; + private $tabs = array(); /** * Parent style * * @var string */ - private $_basedOn = 'Normal'; + private $basedOn = 'Normal'; /** * Style for next paragraph * * @var string */ - private $_next; + private $next; /** * Allow first/last line to display on a separate page * * @var bool */ - private $_widowControl = true; + private $widowControl = true; /** * Keep paragraph with next paragraph * * @var bool */ - private $_keepNext = false; + private $keepNext = false; /** * Keep all lines on one page * * @var bool */ - private $_keepLines = false; + private $keepLines = false; /** * Start paragraph on next page * * @var bool */ - private $_pageBreakBefore = false; + private $pageBreakBefore = false; + + /** + * Indentation + * + * @var \PhpOffice\PhpWord\Style\Indentation + */ + private $indentation; + + /** + * Spacing + * + * @var \PhpOffice\PhpWord\Style\Spacing + */ + private $spacing; /** * Set style by array @@ -143,8 +109,6 @@ class Paragraph foreach ($style as $key => $value) { if ($key === 'line-height') { null; - } elseif (substr($key, 0, 1) !== '_') { - $key = '_' . $key; } $this->setStyleValue($key, $value); } @@ -160,16 +124,16 @@ class Paragraph */ public function setStyleValue($key, $value) { - if ($key == '_indent' || $key == '_hanging') { + $key = String::removeUnderscorePrefix($key); + if ($key == 'indent' || $key == 'hanging') { $value = $value * 720; - } elseif ($key == '_spacing') { + } elseif ($key == 'spacing') { $value += 240; // because line height of 1 matches 240 twips } elseif ($key === 'line-height') { $this->setLineHeight($value); return; } - $this->$key = $value; - $method = 'set' . substr($key, 1); + $method = 'set' . $key; if (method_exists($this, $method)) { $this->$method($value); } @@ -182,301 +146,102 @@ class Paragraph */ public function getAlign() { - return $this->_align; + return $this->align; } /** * Set Paragraph Alignment * - * @param string $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph + * @param string $value + * @return self */ - public function setAlign($pValue = null) + public function setAlign($value = null) { - if (strtolower($pValue) == 'justify') { + if (strtolower($value) == 'justify') { // justify becames both - $pValue = 'both'; + $value = 'both'; } - $this->_align = $pValue; + $this->align = $value; return $this; } /** - * Get Space before Paragraph + * Get space before paragraph * - * @return string + * @return integer */ public function getSpaceBefore() { - return $this->_spaceBefore; + if (!is_null($this->spacing)) { + return $this->spacing->getBefore(); + } } /** - * Set Space before Paragraph + * Set space before paragraph * - * @param int $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph + * @param int $value + * @return self */ - public function setSpaceBefore($pValue = null) + public function setSpaceBefore($value = null) { - $this->_spaceBefore = $pValue; - return $this; + return $this->setSpace(array('before' => $value)); } /** - * Get Space after Paragraph + * Get space after paragraph * - * @return string + * @return integer */ public function getSpaceAfter() { - return $this->_spaceAfter; + if (!is_null($this->spacing)) { + return $this->spacing->getAfter(); + } } /** - * Set Space after Paragraph + * Set space after paragraph * - * @param int $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph + * @param int $value + * @return self */ - public function setSpaceAfter($pValue = null) + public function setSpaceAfter($value = null) { - $this->_spaceAfter = $pValue; - return $this; + return $this->setSpace(array('after' => $value)); } /** - * Get Spacing between breaks + * Get spacing between lines * * @return int */ public function getSpacing() { - return $this->_spacing; - } - - /** - * Set Spacing between breaks - * - * @param int $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function setSpacing($pValue = null) - { - $this->_spacing = $pValue; - return $this; - } - - /** - * Get indentation - * - * @return int - */ - public function getIndent() - { - return $this->_indent; - } - - /** - * Set indentation - * - * @param int $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function setIndent($pValue = null) - { - $this->_indent = $pValue; - return $this; - } - - /** - * Get hanging - * - * @return int - */ - public function getHanging() - { - return $this->_hanging; - } - - /** - * Set hanging - * - * @param int $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function setHanging($pValue = null) - { - $this->_hanging = $pValue; - return $this; - } - - /** - * Get tabs - * - * @return \PhpOffice\PhpWord\Style\Tabs - */ - public function getTabs() - { - return $this->_tabs; - } - - /** - * Set tabs - * - * @param array $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function setTabs($pValue = null) - { - if (is_array($pValue)) { - $this->_tabs = new Tabs($pValue); + if (!is_null($this->spacing)) { + return $this->spacing->getLine(); } - return $this; } /** - * Get parent style ID + * Set spacing between lines * - * @return string + * @param int $value + * @return self */ - public function getBasedOn() + public function setSpacing($value = null) { - return $this->_basedOn; + return $this->setSpace(array('line' => $value)); } /** - * Set parent style ID + * Get line height * - * @param string $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return int|float */ - public function setBasedOn($pValue = 'Normal') + public function getLineHeight() { - $this->_basedOn = $pValue; - return $this; - } - - /** - * Get style for next paragraph - * - * @return string - */ - public function getNext() - { - return $this->_next; - } - - /** - * Set style for next paragraph - * - * @param string $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function setNext($pValue = null) - { - $this->_next = $pValue; - return $this; - } - - /** - * Get allow first/last line to display on a separate page setting - * - * @return bool - */ - public function getWidowControl() - { - return $this->_widowControl; - } - - /** - * Set keep paragraph with next paragraph setting - * - * @param bool $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function setWidowControl($pValue = true) - { - if (!is_bool($pValue)) { - $pValue = true; - } - $this->_widowControl = $pValue; - return $this; - } - - /** - * Get keep paragraph with next paragraph setting - * - * @return bool - */ - public function getKeepNext() - { - return $this->_keepNext; - } - - /** - * Set keep paragraph with next paragraph setting - * - * @param bool $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function setKeepNext($pValue = false) - { - if (!is_bool($pValue)) { - $pValue = false; - } - $this->_keepNext = $pValue; - return $this; - } - - /** - * Get keep all lines on one page setting - * - * @return bool - */ - public function getKeepLines() - { - return $this->_keepLines; - } - - /** - * Set keep all lines on one page setting - * - * @param bool $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function setKeepLines($pValue = false) - { - if (!is_bool($pValue)) { - $pValue = false; - } - $this->_keepLines = $pValue; - return $this; - } - - /** - * Get start paragraph on next page setting - * - * @return bool - */ - public function getPageBreakBefore() - { - return $this->_pageBreakBefore; - } - - /** - * Set start paragraph on next page setting - * - * @param bool $pValue - * @return \PhpOffice\PhpWord\Style\Paragraph - */ - public function setPageBreakBefore($pValue = false) - { - if (!is_bool($pValue)) { - $pValue = false; - } - $this->_pageBreakBefore = $pValue; - return $this; + return $this->lineHeight; } /** @@ -484,7 +249,7 @@ class Paragraph * * @param int|float|string $lineHeight * @return $this - * @throws \PhpOffice\PhpWord\Exceptions\InvalidStyleException + * @throws \PhpOffice\PhpWord\Exception\InvalidStyleException */ public function setLineHeight($lineHeight) { @@ -502,12 +267,279 @@ class Paragraph } /** - * Get line height + * Get indentation * - * @return int|float + * @return int */ - public function getLineHeight() + public function getIndent() { - return $this->lineHeight; + if (!is_null($this->indentation)) { + return $this->indentation->getLeft(); + } + } + + /** + * Set indentation + * + * @param int $value + * @return self + */ + public function setIndent($value = null) + { + return $this->setIndentation(array('left' => $value)); + } + + /** + * Get hanging + * + * @return int + */ + public function getHanging() + { + if (!is_null($this->indentation)) { + return $this->indentation->getHanging(); + } + } + + /** + * Set hanging + * + * @param int $value + * @return self + */ + public function setHanging($value = null) + { + return $this->setIndentation(array('hanging' => $value)); + } + + /** + * Get tabs + * + * @return \PhpOffice\PhpWord\Style\Tab[] + */ + public function getTabs() + { + return $this->tabs; + } + + /** + * Set tabs + * + * @param array $value + * @return self + */ + public function setTabs($value = null) + { + if (is_array($value)) { + $this->tabs = $value; + } + + return $this; + } + + /** + * Get parent style ID + * + * @return string + */ + public function getBasedOn() + { + return $this->basedOn; + } + + /** + * Set parent style ID + * + * @param string $value + * @return self + */ + public function setBasedOn($value = 'Normal') + { + $this->basedOn = $value; + return $this; + } + + /** + * Get style for next paragraph + * + * @return string + */ + public function getNext() + { + return $this->next; + } + + /** + * Set style for next paragraph + * + * @param string $value + * @return self + */ + public function setNext($value = null) + { + $this->next = $value; + return $this; + } + + /** + * Get allow first/last line to display on a separate page setting + * + * @return bool + */ + public function getWidowControl() + { + return $this->widowControl; + } + + /** + * Set keep paragraph with next paragraph setting + * + * @param bool $value + * @return self + */ + public function setWidowControl($value = true) + { + if (!is_bool($value)) { + $value = true; + } + $this->widowControl = $value; + return $this; + } + + /** + * Get keep paragraph with next paragraph setting + * + * @return bool + */ + public function getKeepNext() + { + return $this->keepNext; + } + + /** + * Set keep paragraph with next paragraph setting + * + * @param bool $value + * @return self + */ + public function setKeepNext($value = false) + { + if (!is_bool($value)) { + $value = false; + } + $this->keepNext = $value; + return $this; + } + + /** + * Get keep all lines on one page setting + * + * @return bool + */ + public function getKeepLines() + { + return $this->keepLines; + } + + /** + * Set keep all lines on one page setting + * + * @param bool $value + * @return self + */ + public function setKeepLines($value = false) + { + if (!is_bool($value)) { + $value = false; + } + $this->keepLines = $value; + return $this; + } + + /** + * Get start paragraph on next page setting + * + * @return bool + */ + public function getPageBreakBefore() + { + return $this->pageBreakBefore; + } + + /** + * Set start paragraph on next page setting + * + * @param bool $value + * @return self + */ + public function setPageBreakBefore($value = false) + { + if (!is_bool($value)) { + $value = false; + } + $this->pageBreakBefore = $value; + return $this; + } + + /** + * Get shading + * + * @return \PhpOffice\PhpWord\Style\Indentation + */ + public function getIndentation() + { + return $this->indentation; + } + + /** + * Set shading + * + * @param array $value + * @return self + */ + public function setIndentation($value = null) + { + if (is_array($value)) { + if (!$this->indentation instanceof Indentation) { + $this->indentation = new Indentation(); + } + $this->indentation->setStyleByArray($value); + } else { + $this->indentation = null; + } + + return $this; + } + + /** + * Get shading + * + * @return \PhpOffice\PhpWord\Style\Spacing + * @todo Rename to getSpacing in 1.0 + */ + public function getSpace() + { + return $this->spacing; + } + + /** + * Set shading + * + * @param array $value + * @return self + * @todo Rename to setSpacing in 1.0 + */ + public function setSpace($value = null) + { + if (is_array($value)) { + if (!$this->spacing instanceof Spacing) { + $this->spacing = new Spacing(); + } + $this->spacing->setStyleByArray($value); + } else { + $this->spacing = null; + } + + return $this; } } diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 0043c151..e2a07b85 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -2,47 +2,40 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2013 PhpWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; /** * Table row style + * + * @since 0.8.0 */ -class Row +class Row extends AbstractStyle { /** * Repeat table row on every new page * * @var bool */ - private $_tblHeader = false; + private $tblHeader = false; /** * Table row cannot break across pages * * @var bool */ - private $_cantSplit = false; + private $cantSplit = false; + + /** + * Table row exact height + * + * @var bool + */ + private $exactHeight = false; /** * Create a new row style @@ -51,30 +44,15 @@ class Row { } - /** - * Set style value - * - * @param string $key - * @param mixed $value - */ - public function setStyleValue($key, $value) - { - $this->$key = $value; - } - /** * Set tblHeader * - * @param boolean $pValue - * @return PHPWord_Style_Row + * @param boolean $value + * @return self */ - public function setTblHeader($pValue = false) + public function setTblHeader($value = false) { - if (!is_bool($pValue)) { - $pValue = false; - } - $this->_tblHeader = $pValue; - return $this; + $this->tblHeader = $this->setBoolVal($value, $this->tblHeader); } /** @@ -84,22 +62,18 @@ class Row */ public function getTblHeader() { - return $this->_tblHeader; + return $this->tblHeader; } /** * Set cantSplit * - * @param boolean $pValue - * @return PHPWord_Style_Row + * @param boolean $value + * @return self */ - public function setCantSplit($pValue = false) + public function setCantSplit($value = false) { - if (!is_bool($pValue)) { - $pValue = false; - } - $this->_cantSplit = $pValue; - return $this; + $this->cantSplit = $this->setBoolVal($value, $this->cantSplit); } /** @@ -109,6 +83,28 @@ class Row */ public function getCantSplit() { - return $this->_cantSplit; + return $this->cantSplit; + } + + /** + * Set exactHeight + * + * @param bool $value + * @return self + */ + public function setExactHeight($value = false) + { + $this->exactHeight = $this->setBoolVal($value, $this->exactHeight); + return $this; + } + + /** + * Get exactHeight + * + * @return boolean + */ + public function getExactHeight() + { + return $this->exactHeight; } } diff --git a/src/PhpWord/Style/Section.php b/src/PhpWord/Style/Section.php new file mode 100644 index 00000000..e109526f --- /dev/null +++ b/src/PhpWord/Style/Section.php @@ -0,0 +1,522 @@ +setStyleValue($key, $value); + } + + /** + * Set orientation + * + * @param string $value + * @return self + */ + public function setOrientation($value = null) + { + $enum = array(self::ORIENTATION_PORTRAIT, self::ORIENTATION_LANDSCAPE); + $this->orientation = $this->setEnumVal($value, $enum, $this->orientation); + $longSize = $this->pageSizeW >= $this->pageSizeH ? $this->pageSizeW : $this->pageSizeH; + $shortSize = $this->pageSizeW < $this->pageSizeH ? $this->pageSizeW : $this->pageSizeH; + + if ($this->orientation == self::ORIENTATION_PORTRAIT) { + $this->pageSizeW = $shortSize; + $this->pageSizeH = $longSize; + } else { + $this->pageSizeW = $longSize; + $this->pageSizeH = $shortSize; + } + + return $this; + } + + /** + * Get Page Orientation + * + * @return string + */ + public function getOrientation() + { + return $this->orientation; + } + + /** + * Set Portrait Orientation + * + * @return self + */ + public function setPortrait() + { + return $this->setOrientation(self::ORIENTATION_PORTRAIT); + } + + /** + * Set Landscape Orientation + * + * @return self + */ + public function setLandscape() + { + return $this->setOrientation(self::ORIENTATION_LANDSCAPE); + } + + /** + * Get Page Size Width + * + * @return int|float + */ + public function getPageSizeW() + { + return $this->pageSizeW; + } + + /** + * Get Page Size Height + * + * @return int|float + */ + public function getPageSizeH() + { + return $this->pageSizeH; + } + + /** + * Get Margin Top + * + * @return int|float + */ + public function getMarginTop() + { + return $this->marginTop; + } + + /** + * Set Margin Top + * + * @param int|float $value + * @return self + */ + public function setMarginTop($value = '') + { + $this->marginTop = $this->setNumericVal($value, self::DEFAULT_MARGIN); + + return $this; + } + + /** + * Get Margin Left + * + * @return int|float + */ + public function getMarginLeft() + { + return $this->marginLeft; + } + + /** + * Set Margin Left + * + * @param int|float $value + * @return self + */ + public function setMarginLeft($value = '') + { + $this->marginLeft = $this->setNumericVal($value, self::DEFAULT_MARGIN); + + return $this; + } + + /** + * Get Margin Right + * + * @return int|float + */ + public function getMarginRight() + { + return $this->marginRight; + } + + /** + * Set Margin Right + * + * @param int|float $value + * @return self + */ + public function setMarginRight($value = '') + { + $this->marginRight = $this->setNumericVal($value, self::DEFAULT_MARGIN); + + return $this; + } + + /** + * Get Margin Bottom + * + * @return int|float + */ + public function getMarginBottom() + { + return $this->marginBottom; + } + + /** + * Set Margin Bottom + * + * @param int|float $value + * @return self + */ + public function setMarginBottom($value = '') + { + $this->marginBottom = $this->setNumericVal($value, self::DEFAULT_MARGIN); + + return $this; + } + + /** + * Get gutter + * + * @return int|float + */ + public function getGutter() + { + return $this->gutter; + } + + /** + * Set gutter + * + * @param int|float $value + * @return self + */ + public function setGutter($value = '') + { + $this->gutter = $this->setNumericVal($value, self::DEFAULT_GUTTER); + + return $this; + } + + /** + * Get Header Height + * + * @return int|float + */ + public function getHeaderHeight() + { + return $this->headerHeight; + } + + /** + * Set Header Height + * + * @param int|float $value + * @return self + */ + public function setHeaderHeight($value = '') + { + $this->headerHeight = $this->setNumericVal($value, self::DEFAULT_HEADER_HEIGHT); + + return $this; + } + + /** + * Get Footer Height + * + * @return int|float + */ + public function getFooterHeight() + { + return $this->footerHeight; + } + + /** + * Set Footer Height + * + * @param int|float $value + * @return self + */ + public function setFooterHeight($value = '') + { + $this->footerHeight = $this->setNumericVal($value, self::DEFAULT_FOOTER_HEIGHT); + + return $this; + } + + /** + * Get page numbering start + * + * @return null|int + */ + public function getPageNumberingStart() + { + return $this->pageNumberingStart; + } + + /** + * Set page numbering start + * + * @param null|int $pageNumberingStart + * @return $this + */ + public function setPageNumberingStart($pageNumberingStart = null) + { + $this->pageNumberingStart = $pageNumberingStart; + return $this; + } + + /** + * Get Section Columns Count + * + * @return int + */ + public function getColsNum() + { + return $this->colsNum; + } + + /** + * Set Section Columns Count + * + * @param int $value + * @return self + */ + public function setColsNum($value = '') + { + $this->colsNum = $this->setIntVal($value, self::DEFAULT_COLUMN_COUNT); + + return $this; + } + + /** + * Get Section Space Between Columns + * + * @return int|float + */ + public function getColsSpace() + { + return $this->colsSpace; + } + + /** + * Set Section Space Between Columns + * + * @param int|float $value + * @return self + */ + public function setColsSpace($value = '') + { + $this->colsSpace = $this->setNumericVal($value, self::DEFAULT_COLUMN_SPACING); + + return $this; + } + + /** + * Get Break Type + * + * @return string + */ + public function getBreakType() + { + return $this->breakType; + } + + /** + * Set Break Type + * + * @param string $value + * @return self + */ + public function setBreakType($value = null) + { + $this->breakType = $value; + return $this; + } + + /** + * Get line numbering + * + * @return \PhpOffice\PhpWord\Style\LineNumbering + */ + public function getLineNumbering() + { + return $this->lineNumbering; + } + + /** + * Set line numbering + * + * @param array $value + * @return self + */ + public function setLineNumbering($value = null) + { + if (is_array($value)) { + if (!$this->lineNumbering instanceof LineNumbering) { + $this->lineNumbering = new LineNumbering($value); + } + $this->lineNumbering->setStyleByArray($value); + } else { + $this->lineNumbering = null; + } + + return $this; + } +} diff --git a/src/PhpWord/Style/Shading.php b/src/PhpWord/Style/Shading.php new file mode 100644 index 00000000..fee66a08 --- /dev/null +++ b/src/PhpWord/Style/Shading.php @@ -0,0 +1,120 @@ +setStyleByArray($style); + } + + /** + * Get pattern + * + * @return string + */ + public function getPattern() + { + return $this->pattern; + } + + /** + * Set pattern + * + * @param string $value + * @return self + */ + public function setPattern($value = null) + { + $this->pattern = $value; + + return $this; + } + + /** + * Get color + * + * @return string + */ + public function getColor() + { + return $this->color; + } + + /** + * Set pattern + * + * @param string $value + * @return self + */ + public function setColor($value = null) + { + $this->color = $value; + + return $this; + } + + /** + * Get fill + * + * @return string + */ + public function getFill() + { + return $this->fill; + } + + /** + * Set fill + * + * @param string $value + * @return self + */ + public function setFill($value = null) + { + $this->fill = $value; + + return $this; + } +} diff --git a/src/PhpWord/Style/Spacing.php b/src/PhpWord/Style/Spacing.php new file mode 100644 index 00000000..db173061 --- /dev/null +++ b/src/PhpWord/Style/Spacing.php @@ -0,0 +1,149 @@ +setStyleByArray($style); + } + + /** + * Get before + * + * @return int|float + */ + public function getBefore() + { + return $this->before; + } + + /** + * Set before + * + * @param int|float $value + * @return self + */ + public function setBefore($value = null) + { + $this->before = $this->setNumericVal($value, $this->before); + + return $this; + } + + /** + * Get after + * + * @return int|float + */ + public function getAfter() + { + return $this->after; + } + + /** + * Set after + * + * @param int|float $value + * @return self + */ + public function setAfter($value = null) + { + $this->after = $this->setNumericVal($value, $this->after); + + return $this; + } + + /** + * Get line + * + * @return int|float + */ + public function getLine() + { + return $this->line; + } + + /** + * Set distance + * + * @param int|float $value + * @return self + */ + public function setLine($value = null) + { + $this->line = $this->setNumericVal($value, $this->line); + + return $this; + } + + /** + * Get line rule + * + * @return string + */ + public function getRule() + { + return $this->rule; + } + + /** + * Set line rule + * + * @param string $value + * @return self + */ + public function setRule($value = null) + { + $this->rule = $value; + + return $this; + } +} diff --git a/src/PhpWord/Style/TOC.php b/src/PhpWord/Style/TOC.php index d4019d0a..e8a781b0 100644 --- a/src/PhpWord/Style/TOC.php +++ b/src/PhpWord/Style/TOC.php @@ -2,25 +2,9 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; @@ -28,7 +12,7 @@ namespace PhpOffice\PhpWord\Style; /** * TOC style */ -class TOC +class TOC extends AbstractStyle { const TABLEADER_DOT = 'dot'; const TABLEADER_UNDERSCORE = 'underscore'; @@ -40,21 +24,21 @@ class TOC * * @var string */ - private $_tabLeader; + private $tabLeader; /** * Tab Position * * @var int */ - private $_tabPos; + private $tabPos; /** * Indent * * @var int */ - private $_indent; + private $indent; /** @@ -62,9 +46,9 @@ class TOC */ public function __construct() { - $this->_tabPos = 9062; - $this->_tabLeader = self::TABLEADER_DOT; - $this->_indent = 200; + $this->tabPos = 9062; + $this->tabLeader = self::TABLEADER_DOT; + $this->indent = 200; } /** @@ -74,7 +58,7 @@ class TOC */ public function getTabPos() { - return $this->_tabPos; + return $this->tabPos; } /** @@ -84,7 +68,7 @@ class TOC */ public function setTabPos($pValue) { - $this->_tabPos = $pValue; + $this->tabPos = $pValue; } /** @@ -94,7 +78,7 @@ class TOC */ public function getTabLeader() { - return $this->_tabLeader; + return $this->tabLeader; } /** @@ -104,7 +88,7 @@ class TOC */ public function setTabLeader($pValue = self::TABLEADER_DOT) { - $this->_tabLeader = $pValue; + $this->tabLeader = $pValue; } /** @@ -114,7 +98,7 @@ class TOC */ public function getIndent() { - return $this->_indent; + return $this->indent; } /** @@ -124,17 +108,6 @@ class TOC */ public function setIndent($pValue) { - $this->_indent = $pValue; - } - - /** - * Set style value - * - * @param string $key - * @param string $value - */ - public function setStyleValue($key, $value) - { - $this->$key = $value; + $this->indent = $pValue; } } diff --git a/src/PhpWord/Style/Tab.php b/src/PhpWord/Style/Tab.php index 1d5092aa..dfcb3b95 100644 --- a/src/PhpWord/Style/Tab.php +++ b/src/PhpWord/Style/Tab.php @@ -2,87 +2,63 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; -use PhpOffice\PhpWord\Shared\XMLWriter; - /** * Tab style */ -class Tab +class Tab extends AbstractStyle { /** - * Tab Stop Type + * Tab stop types + * + * @const string + */ + const TAB_STOP_CLEAR = 'clear'; + const TAB_STOP_LEFT = 'left'; + const TAB_STOP_CENTER = 'center'; + const TAB_STOP_RIGHT = 'right'; + const TAB_STOP_DECIMAL = 'decimal'; + const TAB_STOP_BAR = 'bar'; + const TAB_STOP_NUM = 'num'; + + /** + * Tab leader types + * + * @const string + */ + const TAB_LEADER_NONE = 'none'; + const TAB_LEADER_DOT = 'dot'; + const TAB_LEADER_HYPHEN = 'hyphen'; + const TAB_LEADER_UNDERSCORE = 'underscore'; + const TAB_LEADER_HEAVY = 'heavy'; + const TAB_LEADER_MIDDLEDOT = 'middleDot'; + + /** + * Tab stop type * * @var string */ - private $_val; + private $val = self::TAB_STOP_CLEAR; /** - * Tab Leader Character + * Tab leader character * * @var string */ - private $_leader; + private $leader = self::TAB_LEADER_NONE; /** - * Tab Stop Position + * Tab stop position * * @var int */ - private $_position; - - /** - * Tab Stop Type - * - * @var array - * @link http://www.schemacentral.com/sc/ooxml/a-w_val-26.html Tab Stop Type - */ - private static $_possibleStopTypes = array( - 'clear', // No Tab Stop - 'left', // Left Tab Stop - 'center', // Center Tab Stop - 'right', // Right Tab Stop - 'decimal', // Decimal Tab - 'bar', // Bar Tab - 'num' // List tab - ); - - /** - * Tab Leader Character - * - * @var array - * @link http://www.schemacentral.com/sc/ooxml/a-w_leader-1.html Tab Leader Character - */ - private static $_possibleLeaders = array( - 'none', // No tab stop leader - 'dot', // Dotted leader line - 'hyphen', // Dashed tab stop leader line - 'underscore', // Solid leader line - 'heavy', // Heavy solid leader line - 'middleDot' // Middle dot leader line - ); + private $position = 0; /** * Create a new instance of Tab. Both $val and $leader @@ -90,58 +66,52 @@ class Tab * they will be changed to default values. * * @param string $val Defaults to 'clear' if value is not possible. - * @param int $position Must be an integer; otherwise defaults to 0. - * @param string $leader Defaults to NULL if value is not possible. + * @param int $position Must be numeric; otherwise defaults to 0. + * @param string $leader Defaults to null if value is not possible. */ public function __construct($val = null, $position = 0, $leader = null) { - // Default to clear if the stop type is not matched - $this->_val = (self::isStopType($val)) ? $val : 'clear'; + $stopTypes = array( + self::TAB_STOP_CLEAR, self::TAB_STOP_LEFT,self::TAB_STOP_CENTER, + self::TAB_STOP_RIGHT, self::TAB_STOP_DECIMAL, self::TAB_STOP_BAR, self::TAB_STOP_NUM + ); + $leaderTypes = array( + self::TAB_LEADER_NONE, self::TAB_LEADER_DOT, self::TAB_LEADER_HYPHEN, + self::TAB_LEADER_UNDERSCORE, self::TAB_LEADER_HEAVY, self::TAB_LEADER_MIDDLEDOT + ); - // Default to 0 if the position is non-numeric - $this->_position = (is_numeric($position)) ? intval($position) : 0; - - // Default to NULL if no tab leader - $this->_leader = (self::isLeaderType($leader)) ? $leader : null; + $this->val = $this->setEnumVal($val, $stopTypes, $this->val); + $this->position = $this->setNumericVal($position, $this->position); + $this->leader = $this->setEnumVal($leader, $leaderTypes, $this->leader); } /** - * Creates the XML DOM for the instance of Tab. + * Get stop type * - * @param \PhpOffice\PhpWord\Shared\XMLWriter &$xmlWriter + * @return string */ - public function toXml(XMLWriter &$xmlWriter = null) + public function getStopType() { - if (isset($xmlWriter)) { - $xmlWriter->startElement("w:tab"); - $xmlWriter->writeAttribute("w:val", $this->_val); - if (!is_null($this->_leader)) { - $xmlWriter->writeAttribute("w:leader", $this->_leader); - } - $xmlWriter->writeAttribute("w:pos", $this->_position); - $xmlWriter->endElement(); - } + return $this->val; } /** - * Test if attribute is a valid stop type. + * Get leader * - * @param string $attribute - * @return bool True if it is; false otherwise. + * @return string */ - private static function isStopType($attribute) + public function getLeader() { - return in_array($attribute, self::$_possibleStopTypes); + return $this->leader; } /** - * Test if attribute is a valid leader type. + * Get position * - * @param string $attribute - * @return bool True if it is; false otherwise. + * @return integer */ - private static function isLeaderType($attribute) + public function getPosition() { - return in_array($attribute, self::$_possibleLeaders); + return $this->position; } } diff --git a/src/PhpWord/Style/Table.php b/src/PhpWord/Style/Table.php old mode 100755 new mode 100644 index 1dd36808..c4ec8b68 --- a/src/PhpWord/Style/Table.php +++ b/src/PhpWord/Style/Table.php @@ -2,159 +2,89 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Style\Shading; + /** * Table style */ -class Table +class Table extends Border { /** * Style for first row * * @var \PhpOffice\PhpWord\Style\Table */ - private $_firstRow = null; + private $firstRow = null; /** * Cell margin top * * @var int */ - private $_cellMarginTop = null; + private $cellMarginTop = null; /** * Cell margin left * * @var int */ - private $_cellMarginLeft = null; + private $cellMarginLeft = null; /** * Cell margin right * * @var int */ - private $_cellMarginRight = null; + private $cellMarginRight = null; /** * Cell margin bottom * * @var int */ - private $_cellMarginBottom = null; - - /** - * Background color - * - * @var string - */ - private $_bgColor; - - /** - * Border size top - * - * @var int - */ - private $_borderTopSize; - - /** - * Border color - * - * @var string top - */ - private $_borderTopColor; - - /** - * Border size left - * - * @var int - */ - private $_borderLeftSize; - - /** - * Border color left - * - * @var string - */ - private $_borderLeftColor; - - /** - * Border size right - * - * @var int - */ - private $_borderRightSize; - - /** - * Border color right - * - * @var string - */ - private $_borderRightColor; - - /** - * Border size bottom - * - * @var int - */ - private $_borderBottomSize; - - /** - * Border color bottom - * - * @var string - */ - private $_borderBottomColor; + private $cellMarginBottom = null; /** * Border size inside horizontal * * @var int */ - private $_borderInsideHSize; + private $borderInsideHSize; /** * Border color inside horizontal * * @var string */ - private $_borderInsideHColor; + private $borderInsideHColor; /** * Border size inside vertical * * @var int */ - private $_borderInsideVSize; + private $borderInsideVSize; /** * Border color inside vertical * * @var string */ - private $_borderInsideVColor; + private $borderInsideVColor; + + /** + * Shading + * + * @var \PhpOffice\PhpWord\Style\Shading + */ + private $shading; /** * Create new table style @@ -165,55 +95,29 @@ class Table public function __construct($styleTable = null, $styleFirstRow = null) { if (!is_null($styleFirstRow) && is_array($styleFirstRow)) { - $this->_firstRow = clone $this; + $this->firstRow = clone $this; - unset($this->_firstRow->_firstRow); - unset($this->_firstRow->_cellMarginBottom); - unset($this->_firstRow->_cellMarginTop); - unset($this->_firstRow->_cellMarginLeft); - unset($this->_firstRow->_cellMarginRight); - unset($this->_firstRow->_borderInsideVColor); - unset($this->_firstRow->_borderInsideVSize); - unset($this->_firstRow->_borderInsideHColor); - unset($this->_firstRow->_borderInsideHSize); + unset($this->firstRow->firstRow); + unset($this->firstRow->cellMarginBottom); + unset($this->firstRow->cellMarginTop); + unset($this->firstRow->cellMarginLeft); + unset($this->firstRow->cellMarginRight); + unset($this->firstRow->borderInsideVColor); + unset($this->firstRow->borderInsideVSize); + unset($this->firstRow->borderInsideHColor); + unset($this->firstRow->borderInsideHSize); foreach ($styleFirstRow as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - - $this->_firstRow->setStyleValue($key, $value); + $this->firstRow->setStyleValue($key, $value); } } if (!is_null($styleTable) && is_array($styleTable)) { foreach ($styleTable as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } $this->setStyleValue($key, $value); } } } - /** - * Set style value - * - * @param string $key - * @param mixed $value - */ - public function setStyleValue($key, $value) - { - if ($key == '_borderSize') { - $this->setBorderSize($value); - } elseif ($key == '_borderColor') { - $this->setBorderColor($value); - } elseif ($key == '_cellMargin') { - $this->setCellMargin($value); - } else { - $this->$key = $value; - } - } - /** * Get First Row Style * @@ -221,311 +125,110 @@ class Table */ public function getFirstRow() { - return $this->_firstRow; - } - - /** - * Get Last Row Style - * - * @return \PhpOffice\PhpWord\Style\Table - */ - public function getLastRow() - { - return $this->_lastRow; + return $this->firstRow; } /** * Get background * - * @return \PhpOffice\PhpWord\Style\Table + * @return string */ public function getBgColor() { - return $this->_bgColor; + if (!is_null($this->shading)) { + return $this->shading->getFill(); + } } /** * Set background * - * @param string $pValue + * @param string $value * @return \PhpOffice\PhpWord\Style\Table */ - public function setBgColor($pValue = null) + public function setBgColor($value = null) { - $this->_bgColor = $pValue; + $this->setShading(array('fill' => $value)); } /** - * Set TLRBVH Border Size + * Set TLRBHV Border Size * - * @param int $pValue Border size in eighths of a point (1/8 point) + * @param int $value Border size in eighths of a point (1/8 point) + * @return self */ - public function setBorderSize($pValue = null) + public function setBorderSize($value = null) { - $this->_borderTopSize = $pValue; - $this->_borderLeftSize = $pValue; - $this->_borderRightSize = $pValue; - $this->_borderBottomSize = $pValue; - $this->_borderInsideHSize = $pValue; - $this->_borderInsideVSize = $pValue; + $this->setBorderTopSize($value); + $this->setBorderLeftSize($value); + $this->setBorderRightSize($value); + $this->setBorderBottomSize($value); + $this->setBorderInsideHSize($value); + $this->setBorderInsideVSize($value); + + return $this; } /** - * Get TLRBVH Border Size + * Get TLRBHV Border Size * - * @return array + * @return int[] */ public function getBorderSize() { - $t = $this->getBorderTopSize(); - $l = $this->getBorderLeftSize(); - $r = $this->getBorderRightSize(); - $b = $this->getBorderBottomSize(); - $h = $this->getBorderInsideHSize(); - $v = $this->getBorderInsideVSize(); - - return array($t, $l, $r, $b, $h, $v); + return array( + $this->getBorderTopSize(), + $this->getBorderLeftSize(), + $this->getBorderRightSize(), + $this->getBorderBottomSize(), + $this->getBorderInsideHSize(), + $this->getBorderInsideVSize(), + ); } /** - * Set TLRBVH Border Color - * @param string $pValue - */ - public function setBorderColor($pValue = null) - { - $this->_borderTopColor = $pValue; - $this->_borderLeftColor = $pValue; - $this->_borderRightColor = $pValue; - $this->_borderBottomColor = $pValue; - $this->_borderInsideHColor = $pValue; - $this->_borderInsideVColor = $pValue; - } - - /** - * Get TLRB Border Color + * Set TLRBHV Border Color * - * @return array + * @param string $value + * @return self + */ + public function setBorderColor($value = null) + { + $this->setBorderTopColor($value); + $this->setBorderLeftColor($value); + $this->setBorderRightColor($value); + $this->setBorderBottomColor($value); + $this->setBorderInsideHColor($value); + $this->setBorderInsideVColor($value); + + return $this; + } + + /** + * Get TLRBHV Border Color + * + * @return string[] */ public function getBorderColor() { - $t = $this->getBorderTopColor(); - $l = $this->getBorderLeftColor(); - $r = $this->getBorderRightColor(); - $b = $this->getBorderBottomColor(); - $h = $this->getBorderInsideHColor(); - $v = $this->getBorderInsideVColor(); - - return array($t, $l, $r, $b, $h, $v); - } - - /** - * Set border size top - * - * @param $pValue - */ - public function setBorderTopSize($pValue = null) - { - $this->_borderTopSize = $pValue; - } - - /** - * Get border size top - * - * @return - */ - public function getBorderTopSize() - { - return $this->_borderTopSize; - } - - /** - * Set border color top - * - * @param $pValue - */ - public function setBorderTopColor($pValue = null) - { - $this->_borderTopColor = $pValue; - } - - /** - * Get border color top - * - * @return - */ - public function getBorderTopColor() - { - return $this->_borderTopColor; - } - - /** - * Set border size left - * - * @param $pValue - */ - public function setBorderLeftSize($pValue = null) - { - $this->_borderLeftSize = $pValue; - } - - /** - * Get border size left - * - * @return - */ - public function getBorderLeftSize() - { - return $this->_borderLeftSize; - } - - /** - * Set border color left - * - * @param $pValue - */ - public function setBorderLeftColor($pValue = null) - { - $this->_borderLeftColor = $pValue; - } - - /** - * Get border color left - * - * @return - */ - public function getBorderLeftColor() - { - return $this->_borderLeftColor; - } - - /** - * Set border size right - * - * @param $pValue - */ - public function setBorderRightSize($pValue = null) - { - $this->_borderRightSize = $pValue; - } - - /** - * Get border size right - * - * @return - */ - public function getBorderRightSize() - { - return $this->_borderRightSize; - } - - /** - * Set border color right - * - * @param $pValue - */ - public function setBorderRightColor($pValue = null) - { - $this->_borderRightColor = $pValue; - } - - /** - * Get border color right - * - * @return - */ - public function getBorderRightColor() - { - return $this->_borderRightColor; - } - - /** - * Set border size bottom - * - * @param $pValue - */ - public function setBorderBottomSize($pValue = null) - { - $this->_borderBottomSize = $pValue; - } - - /** - * Get border size bottom - * - * @return - */ - public function getBorderBottomSize() - { - return $this->_borderBottomSize; - } - - /** - * Set border color bottom - * - * @param $pValue - */ - public function setBorderBottomColor($pValue = null) - { - $this->_borderBottomColor = $pValue; - } - - /** - * Get border color bottom - * - * @return - */ - public function getBorderBottomColor() - { - return $this->_borderBottomColor; - } - - /** - * Set border color inside horizontal - * - * @param $pValue - */ - public function setBorderInsideHColor($pValue = null) - { - $this->_borderInsideHColor = $pValue; - } - - /** - * Get border color inside horizontal - * - * @return - */ - public function getBorderInsideHColor() - { - return (isset($this->_borderInsideHColor)) ? $this->_borderInsideHColor : null; - } - - /** - * Set border color inside vertical - * - * @param $pValue - */ - public function setBorderInsideVColor($pValue = null) - { - $this->_borderInsideVColor = $pValue; - } - - /** - * Get border color inside vertical - * - * @return - */ - public function getBorderInsideVColor() - { - return (isset($this->_borderInsideVColor)) ? $this->_borderInsideVColor : null; + return array( + $this->getBorderTopColor(), + $this->getBorderLeftColor(), + $this->getBorderRightColor(), + $this->getBorderBottomColor(), + $this->getBorderInsideHColor(), + $this->getBorderInsideVColor(), + ); } /** * Set border size inside horizontal * - * @param $pValue + * @param $value */ - public function setBorderInsideHSize($pValue = null) + public function setBorderInsideHSize($value = null) { - $this->_borderInsideHSize = $pValue; + $this->borderInsideHSize = $value; } /** @@ -535,17 +238,17 @@ class Table */ public function getBorderInsideHSize() { - return (isset($this->_borderInsideHSize)) ? $this->_borderInsideHSize : null; + return (isset($this->borderInsideHSize)) ? $this->borderInsideHSize : null; } /** * Set border size inside vertical * - * @param $pValue + * @param $value */ - public function setBorderInsideVSize($pValue = null) + public function setBorderInsideVSize($value = null) { - $this->_borderInsideVSize = $pValue; + $this->borderInsideVSize = $value; } /** @@ -555,17 +258,57 @@ class Table */ public function getBorderInsideVSize() { - return (isset($this->_borderInsideVSize)) ? $this->_borderInsideVSize : null; + return (isset($this->borderInsideVSize)) ? $this->borderInsideVSize : null; + } + + /** + * Set border color inside horizontal + * + * @param $value + */ + public function setBorderInsideHColor($value = null) + { + $this->borderInsideHColor = $value; + } + + /** + * Get border color inside horizontal + * + * @return + */ + public function getBorderInsideHColor() + { + return (isset($this->borderInsideHColor)) ? $this->borderInsideHColor : null; + } + + /** + * Set border color inside vertical + * + * @param $value + */ + public function setBorderInsideVColor($value = null) + { + $this->borderInsideVColor = $value; + } + + /** + * Get border color inside vertical + * + * @return + */ + public function getBorderInsideVColor() + { + return (isset($this->borderInsideVColor)) ? $this->borderInsideVColor : null; } /** * Set cell margin top * - * @param int $pValue + * @param int $value */ - public function setCellMarginTop($pValue = null) + public function setCellMarginTop($value = null) { - $this->_cellMarginTop = $pValue; + $this->cellMarginTop = $value; } /** @@ -575,17 +318,17 @@ class Table */ public function getCellMarginTop() { - return $this->_cellMarginTop; + return $this->cellMarginTop; } /** * Set cell margin left * - * @param int $pValue + * @param int $value */ - public function setCellMarginLeft($pValue = null) + public function setCellMarginLeft($value = null) { - $this->_cellMarginLeft = $pValue; + $this->cellMarginLeft = $value; } /** @@ -595,17 +338,17 @@ class Table */ public function getCellMarginLeft() { - return $this->_cellMarginLeft; + return $this->cellMarginLeft; } /** * Set cell margin right * - * @param int $pValue + * @param int $value */ - public function setCellMarginRight($pValue = null) + public function setCellMarginRight($value = null) { - $this->_cellMarginRight = $pValue; + $this->cellMarginRight = $value; } /** @@ -615,17 +358,17 @@ class Table */ public function getCellMarginRight() { - return $this->_cellMarginRight; + return $this->cellMarginRight; } /** * Set cell margin bottom * - * @param int $pValue + * @param int $value */ - public function setCellMarginBottom($pValue = null) + public function setCellMarginBottom($value = null) { - $this->_cellMarginBottom = $pValue; + $this->cellMarginBottom = $value; } /** @@ -635,29 +378,59 @@ class Table */ public function getCellMarginBottom() { - return $this->_cellMarginBottom; + return $this->cellMarginBottom; } /** * Set TLRB cell margin * - * @param int $pValue Margin in twips + * @param int $value Margin in twips */ - public function setCellMargin($pValue = null) + public function setCellMargin($value = null) { - $this->_cellMarginTop = $pValue; - $this->_cellMarginLeft = $pValue; - $this->_cellMarginRight = $pValue; - $this->_cellMarginBottom = $pValue; + $this->setCellMarginTop($value); + $this->setCellMarginLeft($value); + $this->setCellMarginRight($value); + $this->setCellMarginBottom($value); } /** * Get cell margin * - * @return array + * @return int[] */ public function getCellMargin() { - return array($this->_cellMarginTop, $this->_cellMarginLeft, $this->_cellMarginRight, $this->_cellMarginBottom); + return array($this->cellMarginTop, $this->cellMarginLeft, $this->cellMarginRight, $this->cellMarginBottom); + } + + /** + * Get shading + * + * @return \PhpOffice\PhpWord\Style\Shading + */ + public function getShading() + { + return $this->shading; + } + + /** + * Set shading + * + * @param array $value + * @return self + */ + public function setShading($value = null) + { + if (is_array($value)) { + if (!$this->shading instanceof Shading) { + $this->shading = new Shading(); + } + $this->shading->setStyleByArray($value); + } else { + $this->shading = null; + } + + return $this; } } diff --git a/src/PhpWord/Style/Tabs.php b/src/PhpWord/Style/Tabs.php deleted file mode 100755 index f0a5fcd6..00000000 --- a/src/PhpWord/Style/Tabs.php +++ /dev/null @@ -1,67 +0,0 @@ -_tabs = $tabs; - } - - /** - * Return XML - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter &$xmlWriter - */ - public function toXml(XMLWriter &$xmlWriter = null) - { - if (isset($xmlWriter)) { - $xmlWriter->startElement("w:tabs"); - foreach ($this->_tabs as &$tab) { - $tab->toXml($xmlWriter); - } - $xmlWriter->endElement(); - } - } -} diff --git a/src/PhpWord/TOC.php b/src/PhpWord/TOC.php index 1445ee17..ea75c10d 100644 --- a/src/PhpWord/TOC.php +++ b/src/PhpWord/TOC.php @@ -2,106 +2,38 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Style\Font; - /** * Table of contents */ class TOC { /** - * Title Elements + * Title elements * * @var array */ - private static $_titles = array(); + private static $titles = array(); /** - * TOC Style + * Title anchor * - * @var array + * @var int */ - private static $_styleTOC; + private static $anchor = 252634154; /** - * Font Style + * Title bookmark * - * @var array + * @var int */ - private static $_styleFont; - - /** - * Title Anchor - * - * @var array - */ - private static $_anchor = 252634154; - - /** - * Title Bookmark - * - * @var array - */ - private static $_bookmarkId = 0; - - - /** - * Create a new Table-of-Contents Element - * - * @param array $styleFont - * @param array $styleTOC - */ - public function __construct($styleFont = null, $styleTOC = null) - { - self::$_styleTOC = new \PhpOffice\PhpWord\Style\TOC(); - - if (!is_null($styleTOC) && is_array($styleTOC)) { - foreach ($styleTOC as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - self::$_styleTOC->setStyleValue($key, $value); - } - } - - if (!is_null($styleFont)) { - if (is_array($styleFont)) { - self::$_styleFont = new Font(); - - foreach ($styleFont as $key => $value) { - if (substr($key, 0, 1) != '_') { - $key = '_' . $key; - } - self::$_styleFont->setStyleValue($key, $value); - } - } else { - self::$_styleFont = $styleFont; - } - } - } + private static $bookmarkId = 0; /** * Add a Title @@ -112,8 +44,8 @@ class TOC */ public static function addTitle($text, $depth = 0) { - $anchor = '_Toc' . ++self::$_anchor; - $bookmarkId = self::$_bookmarkId++; + $anchor = '_Toc' . ++self::$anchor; + $bookmarkId = self::$bookmarkId++; $title = array(); $title['text'] = $text; @@ -121,7 +53,7 @@ class TOC $title['anchor'] = $anchor; $title['bookmarkId'] = $bookmarkId; - self::$_titles[] = $title; + self::$titles[] = $title; return array($anchor, $bookmarkId); } @@ -133,26 +65,14 @@ class TOC */ public static function getTitles() { - return self::$_titles; + return self::$titles; } /** - * Get TOC Style - * - * @return \PhpOffice\PhpWord\Style\TOC + * Reset titles */ - public static function getStyleTOC() + public static function resetTitles() { - return self::$_styleTOC; - } - - /** - * Get Font Style - * - * @return \PhpOffice\PhpWord\Style\Font - */ - public static function getStyleFont() - { - return self::$_styleFont; + self::$titles = array(); } } diff --git a/src/PhpWord/Template.php b/src/PhpWord/Template.php index 635d5d6f..a8a221d7 100644 --- a/src/PhpWord/Template.php +++ b/src/PhpWord/Template.php @@ -2,30 +2,14 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord; -use PhpOffice\PhpWord\Exceptions\Exception; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\Shared\String; /** @@ -36,47 +20,74 @@ class Template /** * ZipArchive object * - * @var \ZipArchive + * @var mixed */ - private $_objZip; + private $zipClass; /** * Temporary file name * * @var string */ - private $_tempFileName; + private $tempFileName; /** * Document XML * * @var string */ - private $_documentXML; + private $documentXML; + /** + * Document header XML + * + * @var string[] + */ + private $headerXMLs = array(); + + /** + * Document footer XML + * + * @var string[] + */ + private $footerXMLs = array(); /** * Create a new Template Object * * @param string $strFilename - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function __construct($strFilename) { - $this->_tempFileName = tempnam(sys_get_temp_dir(), ''); - if ($this->_tempFileName === false) { + $this->tempFileName = tempnam(sys_get_temp_dir(), ''); + if ($this->tempFileName === false) { throw new Exception('Could not create temporary file with unique name in the default temporary directory.'); } // Copy the source File to the temp File - if (!copy($strFilename, $this->_tempFileName)) { - throw new Exception("Could not copy the template from {$strFilename} to {$this->_tempFileName}."); + if (!copy($strFilename, $this->tempFileName)) { + throw new Exception("Could not copy the template from {$strFilename} to {$this->tempFileName}."); } - $this->_objZip = new \ZipArchive(); - $this->_objZip->open($this->_tempFileName); + $zipClass = Settings::getZipClass(); + $this->zipClass = new $zipClass(); + $this->zipClass->open($this->tempFileName); - $this->_documentXML = $this->_objZip->getFromName('word/document.xml'); + // Find and load headers and footers + $index = 1; + while ($this->zipClass->locateName($this->getHeaderName($index)) !== false) { + $this->headerXMLs[$index] = $this->zipClass->getFromName($this->getHeaderName($index)); + $index++; + } + + $index = 1; + while ($this->zipClass->locateName($this->getFooterName($index)) !== false) { + $this->footerXMLs[$index] = $this->zipClass->getFromName($this->getFooterName($index)); + $index++; + } + + $this->documentXML = $this->zipClass->getFromName('word/document.xml'); } /** @@ -85,7 +96,7 @@ class Template * @param \DOMDocument $xslDOMDocument * @param array $xslOptions * @param string $xslOptionsURI - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function applyXslStyleSheet(&$xslDOMDocument, $xslOptions = array(), $xslOptionsURI = '') { @@ -98,7 +109,7 @@ class Template } $xmlDOMDocument = new \DOMDocument(); - if ($xmlDOMDocument->loadXML($this->_documentXML) === false) { + if ($xmlDOMDocument->loadXML($this->documentXML) === false) { throw new Exception('Could not load XML from the given template.'); } @@ -107,7 +118,7 @@ class Template throw new Exception('Could not transform the given XML document.'); } - $this->_documentXML = $xmlTransformed; + $this->documentXML = $xmlTransformed; } /** @@ -118,56 +129,265 @@ class Template * @param integer $limit */ public function setValue($search, $replace, $limit = -1) + { + foreach ($this->headerXMLs as $index => $headerXML) { + $this->headerXMLs[$index] = $this->setValueForPart($this->headerXMLs[$index], $search, $replace, $limit); + } + + $this->documentXML = $this->setValueForPart($this->documentXML, $search, $replace, $limit); + + foreach ($this->footerXMLs as $index => $headerXML) { + $this->footerXMLs[$index] = $this->setValueForPart($this->footerXMLs[$index], $search, $replace, $limit); + } + } + + /** + * Returns array of all variables in template + * @return string[] + */ + public function getVariables() + { + $variables = $this->getVariablesForPart($this->documentXML); + + foreach ($this->headerXMLs as $headerXML) { + $variables = array_merge($variables, $this->getVariablesForPart($headerXML)); + } + + foreach ($this->footerXMLs as $footerXML) { + $variables = array_merge($variables, $this->getVariablesForPart($footerXML)); + } + + return array_unique($variables); + } + + /** + * Clone a table row in a template document + * + * @param string $search + * @param integer $numberOfClones + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + public function cloneRow($search, $numberOfClones) + { + if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { + $search = '${' . $search . '}'; + } + + $tagPos = strpos($this->documentXML, $search); + if (!$tagPos) { + throw new Exception("Can not clone row, template variable not found or variable contains markup."); + } + + $rowStart = $this->findRowStart($tagPos); + $rowEnd = $this->findRowEnd($tagPos); + $xmlRow = $this->getSlice($rowStart, $rowEnd); + + // Check if there's a cell spanning multiple rows. + if (preg_match('##', $xmlRow)) { + $extraRowStart = $rowEnd; + $extraRowEnd = $rowEnd; + while (true) { + $extraRowStart = $this->findRowStart($extraRowEnd + 1); + $extraRowEnd = $this->findRowEnd($extraRowEnd + 1); + + // If extraRowEnd is lower then 7, there was no next row found. + if ($extraRowEnd < 7) { + break; + } + + // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. + $tmpXmlRow = $this->getSlice($extraRowStart, $extraRowEnd); + if (!preg_match('##', $tmpXmlRow) && !preg_match('##', $tmpXmlRow)) { + break; + } + // This row was a spanned row, update $rowEnd and search for the next row. + $rowEnd = $extraRowEnd; + } + $xmlRow = $this->getSlice($rowStart, $rowEnd); + } + + $result = $this->getSlice(0, $rowStart); + for ($i = 1; $i <= $numberOfClones; $i++) { + $result .= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow); + } + $result .= $this->getSlice($rowEnd); + + $this->documentXML = $result; + } + + /** + * Clone a block + * + * @param string $blockname + * @param integer $clones + * @param boolean $replace + * @return string|null + */ + public function cloneBlock($blockname, $clones = 1, $replace = true) + { + $xmlBlock = null; + preg_match('/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->documentXML, $matches); + + if (isset($matches[3])) { + $xmlBlock = $matches[3]; + $cloned = array(); + for ($i = 1; $i <= $clones; $i++) { + $cloned[] = $xmlBlock; + } + + if ($replace) { + $this->documentXML = str_replace($matches[2] . $matches[3] . $matches[4], implode('', $cloned), $this->documentXML); + } + } + + return $xmlBlock; + } + + /** + * Replace a block + * + * @param string $blockname + * @param string $replacement + */ + public function replaceBlock($blockname, $replacement) + { + preg_match('/(<\?xml.*)(\${' . $blockname . '}<\/w:.*?p>)(.*)()/is', $this->documentXML, $matches); + + if (isset($matches[3])) { + $this->documentXML = str_replace($matches[2] . $matches[3] . $matches[4], $replacement, $this->documentXML); + } + } + + /** + * Delete a block of text + * + * @param string $blockname + */ + public function deleteBlock($blockname) + { + $this->replaceBlock($blockname, ''); + } + + /** + * Save XML to temporary file + * + * @return string + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + public function save() + { + foreach ($this->headerXMLs as $index => $headerXML) { + $this->zipClass->addFromString($this->getHeaderName($index), $this->headerXMLs[$index]); + } + + $this->zipClass->addFromString('word/document.xml', $this->documentXML); + + foreach ($this->footerXMLs as $index => $headerXML) { + $this->zipClass->addFromString($this->getFooterName($index), $this->footerXMLs[$index]); + } + + // Close zip file + if ($this->zipClass->close() === false) { + throw new Exception('Could not close zip file.'); + } + + return $this->tempFileName; + } + + /** + * Save XML to defined name + * + * @param string $strFilename + * @since 0.8.0 + */ + public function saveAs($strFilename) + { + $tempFilename = $this->save(); + + if (file_exists($strFilename)) { + unlink($strFilename); + } + + rename($tempFilename, $strFilename); + } + + /** + * Find and replace placeholders in the given XML section. + * + * @param string $documentPartXML + * @param string $search + * @param string $replace + * @param integer $limit + * @return string + */ + protected function setValueForPart($documentPartXML, $search, $replace, $limit) { $pattern = '|\$\{([^\}]+)\}|U'; - preg_match_all($pattern, $this->_documentXML, $matches); + preg_match_all($pattern, $documentPartXML, $matches); foreach ($matches[0] as $value) { $valueCleaned = preg_replace('/<[^>]+>/', '', $value); $valueCleaned = preg_replace('/<\/[^>]+>/', '', $valueCleaned); - $this->_documentXML = str_replace($value, $valueCleaned, $this->_documentXML); + $documentPartXML = str_replace($value, $valueCleaned, $documentPartXML); } if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { $search = '${' . $search . '}'; } - if (!is_array($replace)) { - if (!String::isUTF8($replace)) { - $replace = utf8_encode($replace); - } - $replace = htmlspecialchars($replace); - } else { - foreach ($replace as $key => $value) { - $replace[$key] = htmlspecialchars($value); - } + if (!String::isUTF8($replace)) { + $replace = utf8_encode($replace); } + $replace = htmlspecialchars($replace); $regExpDelim = '/'; $escapedSearch = preg_quote($search, $regExpDelim); - $this->_documentXML = preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $this->_documentXML, $limit); + return preg_replace("{$regExpDelim}{$escapedSearch}{$regExpDelim}u", $replace, $documentPartXML, $limit); } /** - * Returns array of all variables in template + * Find all variables in $documentPartXML + * @param string $documentPartXML + * @return string[] */ - public function getVariables() + protected function getVariablesForPart($documentPartXML) { - preg_match_all('/\$\{(.*?)}/i', $this->_documentXML, $matches); + preg_match_all('/\$\{(.*?)}/i', $documentPartXML, $matches); + return $matches[1]; } + /** + * Get the name of the footer file for $index + * @param integer $index + * @return string + */ + private function getFooterName($index) + { + return sprintf('word/footer%d.xml', $index); + } + + /** + * Get the name of the header file for $index + * @param integer $index + * @return string + */ + private function getHeaderName($index) + { + return sprintf('word/header%d.xml', $index); + } + /** * Find the start position of the nearest table row before $offset * - * @param int $offset - * @return int - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @param integer $offset + * @return integer + * @throws \PhpOffice\PhpWord\Exception\Exception */ - private function _findRowStart($offset) + private function findRowStart($offset) { - $rowStart = strrpos($this->_documentXML, "_documentXML) - $offset) * -1)); + $rowStart = strrpos($this->documentXML, "documentXML) - $offset) * -1)); if (!$rowStart) { - $rowStart = strrpos($this->_documentXML, "", ((strlen($this->_documentXML) - $offset) * -1)); + $rowStart = strrpos($this->documentXML, "", ((strlen($this->documentXML) - $offset) * -1)); } if (!$rowStart) { throw new Exception("Can not find the start position of the row to clone."); @@ -178,116 +398,27 @@ class Template /** * Find the end position of the nearest table row after $offset * - * @param int $offset - * @return int + * @param integer $offset + * @return integer */ - private function _findRowEnd($offset) + private function findRowEnd($offset) { - $rowEnd = strpos($this->_documentXML, "", $offset) + 7; + $rowEnd = strpos($this->documentXML, "", $offset) + 7; return $rowEnd; } /** * Get a slice of a string * - * @param int $startPosition - * @param int $endPosition + * @param integer $startPosition + * @param integer $endPosition * @return string */ - private function _getSlice($startPosition, $endPosition = 0) + private function getSlice($startPosition, $endPosition = 0) { if (!$endPosition) { - $endPosition = strlen($this->_documentXML); + $endPosition = strlen($this->documentXML); } - return substr($this->_documentXML, $startPosition, ($endPosition - $startPosition)); - } - - /** - * Clone a table row in a template document - * - * @param string $search - * @param int $numberOfClones - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - public function cloneRow($search, $numberOfClones) - { - if (substr($search, 0, 2) !== '${' && substr($search, -1) !== '}') { - $search = '${' . $search . '}'; - } - - $tagPos = strpos($this->_documentXML, $search); - if (!$tagPos) { - throw new Exception("Can not clone row, template variable not found or variable contains markup."); - } - - $rowStart = $this->_findRowStart($tagPos); - $rowEnd = $this->_findRowEnd($tagPos); - $xmlRow = $this->_getSlice($rowStart, $rowEnd); - - // Check if there's a cell spanning multiple rows. - if (preg_match('##', $xmlRow)) { - $extraRowStart = $rowEnd; - $extraRowEnd = $rowEnd; - while (true) { - $extraRowStart = $this->_findRowStart($extraRowEnd + 1); - $extraRowEnd = $this->_findRowEnd($extraRowEnd + 1); - - // If extraRowEnd is lower then 7, there was no next row found. - if ($extraRowEnd < 7) { - break; - } - - // If tmpXmlRow doesn't contain continue, this row is no longer part of the spanned row. - $tmpXmlRow = $this->_getSlice($extraRowStart, $extraRowEnd); - if (!preg_match('##', $tmpXmlRow) && !preg_match('##', $tmpXmlRow)) { - break; - } - // This row was a spanned row, update $rowEnd and search for the next row. - $rowEnd = $extraRowEnd; - } - $xmlRow = $this->_getSlice($rowStart, $rowEnd); - } - - $result = $this->_getSlice(0, $rowStart); - for ($i = 1; $i <= $numberOfClones; $i++) { - $result .= preg_replace('/\$\{(.*?)\}/', '\${\\1#' . $i . '}', $xmlRow); - } - $result .= $this->_getSlice($rowEnd); - - $this->_documentXML = $result; - } - - /** - * Save XML to temporary file - * - * @return string - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - public function save() - { - $this->_objZip->addFromString('word/document.xml', $this->_documentXML); - - // Close zip file - if ($this->_objZip->close() === false) { - throw new Exception('Could not close zip file.'); - } - - return $this->_tempFileName; - } - - /** - * Save XML to defined name - * - * @param string $strFilename - */ - public function saveAs($strFilename) - { - $tempFilename = $this->save(); - - if (\file_exists($strFilename)) { - unlink($strFilename); - } - - rename($tempFilename, $strFilename); + return substr($this->documentXML, $startPosition, ($endPosition - $startPosition)); } } diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php new file mode 100644 index 00000000..0d713bc5 --- /dev/null +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -0,0 +1,359 @@ + '', 'object' => ''); + + /** + * Use disk caching + * + * @var boolean + */ + private $useDiskCaching = false; + + /** + * Disk caching directory + * + * @var string + */ + private $diskCachingDirectory = './'; + + /** + * Temporary directory + * + * @var string + */ + private $tempDir = ''; + + /** + * Original file name + * + * @var string + */ + private $originalFilename; + + /** + * Temporary file name + * + * @var string + */ + private $tempFilename; + + /** + * Get PhpWord object + * + * @return \PhpOffice\PhpWord\PhpWord + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + public function getPhpWord() + { + if (!is_null($this->phpWord)) { + return $this->phpWord; + } else { + throw new Exception("No PhpWord assigned."); + } + } + + /** + * Set PhpWord object + * + * @param \PhpOffice\PhpWord\PhpWord + * @return self + */ + public function setPhpWord(PhpWord $phpWord = null) + { + $this->phpWord = $phpWord; + return $this; + } + + /** + * Get writer part + * + * @param string $pPartName Writer part name + * @return mixed + */ + public function getWriterPart($pPartName = '') + { + if ($pPartName != '' && isset($this->writerParts[strtolower($pPartName)])) { + return $this->writerParts[strtolower($pPartName)]; + } else { + return null; + } + } + + /** + * Get use disk caching status + * + * @return boolean + */ + public function getUseDiskCaching() + { + return $this->useDiskCaching; + } + + /** + * Set use disk caching status + * + * @param boolean $pValue + * @param string $pDirectory + * @return self + */ + 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; + } + + /** + * Get temporary directory + * + * @return string + */ + public function getTempDir() + { + return $this->tempDir; + } + + /** + * Set temporary directory + * + * @param string $value + * @return self + */ + public function setTempDir($value) + { + if (!is_dir($value)) { + mkdir($value); + } + $this->tempDir = $value; + + return $this; + } + + /** + * Get temporary file name + * + * If $filename is php://output or php://stdout, make it a temporary file + * + * @param string $filename + * @return string + */ + protected function getTempFile($filename) + { + // Temporary directory + $this->setTempDir(sys_get_temp_dir() . '/PHPWordWriter/'); + + // Temporary file + $this->originalFilename = $filename; + if (strtolower($filename) == 'php://output' || strtolower($filename) == 'php://stdout') { + $filename = @tempnam(sys_get_temp_dir(), 'phpword_'); + if ($filename == '') { + $filename = $this->originalFilename; + } + } + $this->tempFilename = $filename; + + return $this->tempFilename; + } + + /** + * Cleanup temporary file + */ + protected function cleanupTempFile() + { + 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); + } + + $this->clearTempDir(); + } + + /** + * Clear temporary directory + */ + protected function clearTempDir() + { + if (is_dir($this->tempDir)) { + $this->deleteDir($this->tempDir); + } + } + + /** + * Get ZipArchive object + * + * @param string $filename + * @return mixed ZipArchive object + */ + 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 + // This method of accessing constant values from a dynamic class should work with all appropriate versions of PHP + $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) { + throw new Exception("Could not open " . $filename . " for writing."); + } + } + + return $objZip; + } + + /** + * Add files to package + * + * @param mixed $objZip + * @param mixed $elements + */ + protected function addFilesToPackage($objZip, $elements) + { + foreach ($elements as $element) { + $type = $element['type']; // image|object|link + + // Skip nonregistered types and set target + if (!array_key_exists($type, $this->mediaPaths)) { + continue; + } + $target = $this->mediaPaths[$type] . $element['target']; + + // Retrive GD image content or get local media + if (isset($element['isMemImage']) && $element['isMemImage']) { + $image = call_user_func($element['createFunction'], $element['source']); + ob_start(); + call_user_func($element['imageFunction'], $image); + $imageContents = ob_get_contents(); + ob_end_clean(); + $objZip->addFromString($target, $imageContents); + imagedestroy($image); + } else { + $this->addFileToPackage($objZip, $element['source'], $target); + } + } + } + + /** + * Add file to package + * + * Get the actual source from an archive image + * + * @param mixed $objZip + * @param string $source + * @param string $target + */ + protected function addFileToPackage($objZip, $source, $target) + { + $isArchive = strpos($source, 'zip://') !== false; + $actualSource = null; + if ($isArchive) { + $source = substr($source, 6); + list($zipFilename, $imageFilename) = explode('#', $source); + + $zipClass = \PhpOffice\PhpWord\Settings::getZipClass(); + $zip = new $zipClass(); + 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, $target); + } + } + + /** + * 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 new file mode 100644 index 00000000..d4b8adb3 --- /dev/null +++ b/src/PhpWord/Writer/HTML.php @@ -0,0 +1,275 @@ +setPhpWord($phpWord); + } + + /** + * Save PhpWord to file + * + * @param string $filename + * @throws Exception + */ + public function save($filename = null) + { + if (!is_null($this->getPhpWord())) { + $this->setTempDir(sys_get_temp_dir() . '/PHPWordWriter/'); + $hFile = fopen($filename, 'w'); + if ($hFile !== false) { + fwrite($hFile, $this->writeDocument()); + fclose($hFile); + } else { + throw new Exception("Can't open file"); + } + $this->clearTempDir(); + } else { + throw new Exception("No PHPWord assigned."); + } + } + + /** + * Get phpWord data + * + * @return string + */ + public function writeDocument() + { + $html = ''; + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= $this->writeHTMLHead(); + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + $html .= $this->writeHTMLBody(); + $html .= $this->writeNotes(); + $html .= '' . PHP_EOL; + $html .= '' . PHP_EOL; + + return $html; + } + + /** + * Generate HTML header + * + * @return string + */ + private function writeHTMLHead() + { + $properties = $this->getPhpWord()->getDocumentProperties(); + $propertiesMapping = array( + 'creator' => 'author', + 'title' => '', + 'description' => '', + 'subject' => '', + 'keywords' => '', + 'category' => '', + 'company' => '', + 'manager' => '' + ); + $title = $properties->getTitle(); + $title = ($title != '') ? $title : 'PHPWord'; + + $html = ''; + $html .= '' . PHP_EOL; + $html .= '' . htmlspecialchars($title) . '' . PHP_EOL; + foreach ($propertiesMapping as $key => $value) { + $value = ($value == '') ? $key : $value; + $method = "get" . $key; + if ($properties->$method() != '') { + $html .= '' . PHP_EOL; + } + } + $html .= $this->writeStyles(); + + return $html; + } + + /** + * Get content + * + * @return string + */ + private function writeHTMLBody() + { + $phpWord = $this->getPhpWord(); + $html = ''; + + $sections = $phpWord->getSections(); + $countSections = count($sections); + + if ($countSections > 0) { + foreach ($sections as $section) { + $elements = $section->getElements(); + foreach ($elements as $element) { + if ($element instanceof AbstractElement) { + $elementWriter = new ElementWriter($this, $element, false); + $html .= $elementWriter->write(); + } + } + } + } + + return $html; + } + + /** + * Write footnote/endnote contents as textruns + */ + private function writeNotes() + { + $html = ''; + if (!empty($this->notes)) { + $html .= "
    "; + foreach ($this->notes as $noteId => $noteMark) { + $noteAnchor = "note-{$noteId}"; + list($noteType, $noteTypeId) = explode('-', $noteMark); + $collectionObject = 'PhpOffice\\PhpWord\\' . ($noteType == 'endnote' ? 'Endnotes' : 'Footnotes'); + $collection = $collectionObject::getElements(); + if (array_key_exists($noteTypeId, $collection)) { + $element = $collection[$noteTypeId]; + $elmWriter = new TextRunWriter($this, $element, true); + $content = "{$noteId}" . $elmWriter->write(); + $html .= "

    {$content}

    " . PHP_EOL; + } + } + } + + return $html; + } + + /** + * Get styles + * + * @return string + */ + private function writeStyles() + { + $css = '' . PHP_EOL; + + return $css; + } + + /** + * Get is PDF + * + * @return bool + */ + public function isPdf() + { + return $this->isPdf; + } + + /** + * Get notes + * + * @return array + */ + public function getNotes() + { + return $this->notes; + } + + /** + * Add note + * + * @param int $noteId + * @param string $noteMark + */ + public function addNote($noteId, $noteMark) + { + $this->notes[$noteId] = $noteMark; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/Element.php b/src/PhpWord/Writer/HTML/Element/Element.php new file mode 100644 index 00000000..434760f9 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/Element.php @@ -0,0 +1,76 @@ +parentWriter = $parentWriter; + $this->element = $element; + $this->withoutP = $withoutP; + } + + /** + * Write element + * + * @return string + */ + public function write() + { + $html = ''; + $elmName = str_replace('PhpOffice\\PhpWord\\Element\\', '', get_class($this->element)); + $elmWriterClass = 'PhpOffice\\PhpWord\\Writer\\HTML\\Element\\' . $elmName; + if (class_exists($elmWriterClass) === true) { + $elmWriter = new $elmWriterClass($this->parentWriter, $this->element, $this->withoutP); + $html = $elmWriter->write(); + } + + return $html; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/Endnote.php b/src/PhpWord/Writer/HTML/Element/Endnote.php new file mode 100644 index 00000000..66efcf4d --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/Endnote.php @@ -0,0 +1,19 @@ +element instanceof ImageElement) { + return $html; + } + if (!$this->parentWriter->isPdf()) { + $imageData = $this->getBase64ImageData($this->element); + if (!is_null($imageData)) { + $styleWriter = new ImageStyleWriter($this->element->getStyle()); + $style = $styleWriter->write(); + + $html = ""; + if (!$this->withoutP) { + $html = "

    {$html}

    " . PHP_EOL; + } + } + } + + return $html; + } + + /** + * Get Base64 image data + * + * @return string|null + */ + private function getBase64ImageData(ImageElement $element) + { + $source = $element->getSource(); + $imageType = $element->getImageType(); + $imageData = null; + $imageBinary = null; + $actualSource = null; + + // Get actual source from archive image or other source + // Return null if not found + if ($element->getSourceType() == ImageElement::SOURCE_ARCHIVE) { + $source = substr($source, 6); + list($zipFilename, $imageFilename) = explode('#', $source); + + $zipClass = \PhpOffice\PhpWord\Settings::getZipClass(); + $zip = new $zipClass(); + if ($zip->open($zipFilename) !== false) { + if ($zip->locateName($imageFilename)) { + $zip->extractTo($this->parentWriter->getTempDir(), $imageFilename); + $actualSource = $this->parentWriter->getTempDir() . DIRECTORY_SEPARATOR . $imageFilename; + } + } + $zip->close(); + } else { + $actualSource = $source; + } + if (is_null($actualSource)) { + return null; + } + + // Read image binary data and convert into Base64 + if ($element->getSourceType() == ImageElement::SOURCE_GD) { + $imageResource = call_user_func($element->getImageCreateFunction(), $actualSource); + ob_start(); + call_user_func($element->getImageFunction(), $imageResource); + $imageBinary = ob_get_contents(); + ob_end_clean(); + } else { + if ($fileHandle = fopen($actualSource, 'rb', false)) { + $imageBinary = fread($fileHandle, filesize($actualSource)); + fclose($fileHandle); + } + } + if (!is_null($imageBinary)) { + $base64 = chunk_split(base64_encode($imageBinary)); + $imageData = 'data:' . $imageType . ';base64,' . $base64; + } + + return $imageData; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/Link.php b/src/PhpWord/Writer/HTML/Element/Link.php new file mode 100644 index 00000000..1680edfc --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/Link.php @@ -0,0 +1,33 @@ +element->getTarget()}\">{$this->element->getText()}
    " . PHP_EOL; + if (!$this->withoutP) { + $html = '

    ' . $html . '

    ' . PHP_EOL; + } + + return $html; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/ListItem.php b/src/PhpWord/Writer/HTML/Element/ListItem.php new file mode 100644 index 00000000..f8aa6073 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/ListItem.php @@ -0,0 +1,31 @@ +element->getTextObject()->getText()); + $html = '

    ' . $text . '

    ' . PHP_EOL; + + return $html; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/Note.php b/src/PhpWord/Writer/HTML/Element/Note.php new file mode 100644 index 00000000..cac84cbe --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/Note.php @@ -0,0 +1,34 @@ +parentWriter->getNotes()) + 1; + $prefix = ($this->element instanceof \PhpOffice\PhpWord\Element\Endnote) ? 'endnote' : 'footnote'; + $noteMark = $prefix . '-' . $this->element->getRelationId(); + $this->parentWriter->addNote($noteId, $noteMark); + $html = "{$noteId}"; + + return $html; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/PageBreak.php b/src/PhpWord/Writer/HTML/Element/PageBreak.php new file mode 100644 index 00000000..b05e43ca --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/PageBreak.php @@ -0,0 +1,19 @@ +element->getRows(); + $rowCount = count($rows); + if ($rowCount > 0) { + $html .= '' . PHP_EOL; + foreach ($rows as $row) { + // $height = $row->getHeight(); + $rowStyle = $row->getStyle(); + $tblHeader = $rowStyle->getTblHeader(); + $html .= '' . PHP_EOL; + foreach ($row->getCells() as $cell) { + $cellTag = $tblHeader ? 'th' : 'td'; + $cellContents = $cell->getElements(); + $html .= "<{$cellTag}>" . PHP_EOL; + if (count($cellContents) > 0) { + foreach ($cellContents as $content) { + $writer = new Element($this->parentWriter, $content, false); + $html .= $writer->write(); + } + } else { + $writer = new Element($this->parentWriter, new \PhpOffice\PhpWord\Element\TextBreak(), false); + $html .= $writer->write(); + } + $html .= '' . PHP_EOL; + } + $html .= '' . PHP_EOL; + } + $html .= '
    ' . PHP_EOL; + } + + return $html; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php new file mode 100644 index 00000000..56839c34 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -0,0 +1,65 @@ +element->getParagraphStyle(); + $pStyleIsObject = ($paragraphStyle instanceof Paragraph); + if ($pStyleIsObject) { + $styleWriter = new ParagraphStyleWriter($paragraphStyle); + $paragraphStyle = $styleWriter->write(); + } + // Font style + $fontStyle = $this->element->getFontStyle(); + $fontStyleIsObject = ($fontStyle instanceof Font); + if ($fontStyleIsObject) { + $styleWriter = new FontStyleWriter($fontStyle); + $fontStyle = $styleWriter->write(); + } + + if ($paragraphStyle && !$this->withoutP) { + $attribute = $pStyleIsObject ? 'style' : 'class'; + $html .= "

    "; + } + if ($fontStyle) { + $attribute = $fontStyleIsObject ? 'style' : 'class'; + $html .= ""; + } + $html .= htmlspecialchars($this->element->getText()); + if ($fontStyle) { + $html .= ''; + } + if ($paragraphStyle && !$this->withoutP) { + $html .= '

    ' . PHP_EOL; + } + + return $html; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/TextBreak.php b/src/PhpWord/Writer/HTML/Element/TextBreak.php new file mode 100644 index 00000000..ed8f9f71 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/TextBreak.php @@ -0,0 +1,34 @@ +withoutP) { + $html = '
    ' . PHP_EOL; + } else { + $html = '

     

    ' . PHP_EOL; + } + + return $html; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/TextRun.php b/src/PhpWord/Writer/HTML/Element/TextRun.php new file mode 100644 index 00000000..712c1b33 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/TextRun.php @@ -0,0 +1,52 @@ +element->getElements(); + if (count($elements) > 0) { + // Paragraph style + $paragraphStyle = $this->element->getParagraphStyle(); + $pStyleIsObject = ($paragraphStyle instanceof Paragraph); + if ($pStyleIsObject) { + $styleWriter = new ParagraphStyleWriter($paragraphStyle); + $paragraphStyle = $styleWriter->write(); + } + $tag = $this->withoutP ? 'span' : 'p'; + $attribute = $pStyleIsObject ? 'style' : 'class'; + $html .= "<{$tag} {$attribute}=\"{$paragraphStyle}\">"; + foreach ($elements as $element) { + $elementWriter = new Element($this->parentWriter, $element, true); + $html .= $elementWriter->write(); + } + $html .= ""; + $html .= PHP_EOL; + } + + return $html; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php new file mode 100644 index 00000000..1395afed --- /dev/null +++ b/src/PhpWord/Writer/HTML/Element/Title.php @@ -0,0 +1,32 @@ +element->getDepth(); + $text = htmlspecialchars($this->element->getText()); + $html = "<{$tag}>{$text}" . PHP_EOL; + + return $html; + } +} diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php new file mode 100644 index 00000000..eeb0a767 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -0,0 +1,62 @@ +style = $style; + } + + /** + * Takes array where of CSS properties / values and converts to CSS string + * + * @param array $css + * @return string + */ + protected function assembleCss($css) + { + $pairs = array(); + $string = ''; + foreach ($css as $key => $value) { + if ($value != '') { + $pairs[] = $key . ': ' . $value; + } + } + if (!empty($pairs)) { + $string = implode('; ', $pairs) . ';'; + } + + return $string; + } +} diff --git a/src/PhpWord/Writer/HTML/Style/Font.php b/src/PhpWord/Writer/HTML/Style/Font.php new file mode 100644 index 00000000..73ae14c1 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Style/Font.php @@ -0,0 +1,65 @@ +style instanceof \PhpOffice\PhpWord\Style\Font)) { + return; + } + + $css = array(); + if (PhpWord::DEFAULT_FONT_NAME != $this->style->getName()) { + $css['font-family'] = "'" . $this->style->getName() . "'"; + } + if (PhpWord::DEFAULT_FONT_SIZE != $this->style->getSize()) { + $css['font-size'] = $this->style->getSize() . 'pt'; + } + if (PhpWord::DEFAULT_FONT_COLOR != $this->style->getColor()) { + $css['color'] = '#' . $this->style->getColor(); + } + $css['background'] = $this->style->getFgColor(); + if ($this->style->getBold()) { + $css['font-weight'] = 'bold'; + } + if ($this->style->getItalic()) { + $css['font-style'] = 'italic'; + } + if ($this->style->getSuperScript()) { + $css['vertical-align'] = 'super'; + } elseif ($this->style->getSubScript()) { + $css['vertical-align'] = 'sub'; + } + $css['text-decoration'] = ''; + if ($this->style->getUnderline() != FontStyle::UNDERLINE_NONE) { + $css['text-decoration'] .= 'underline '; + } + if ($this->style->getStrikethrough()) { + $css['text-decoration'] .= 'line-through '; + } + + return $this->assembleCss($css); + } +} diff --git a/src/PhpWord/Writer/HTML/Style/Generic.php b/src/PhpWord/Writer/HTML/Style/Generic.php new file mode 100644 index 00000000..841f20d8 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Style/Generic.php @@ -0,0 +1,34 @@ +style) && !empty($this->style)) { + $css = $this->style; + } + + return $this->assembleCss($css); + } +} diff --git a/src/PhpWord/Writer/HTML/Style/Image.php b/src/PhpWord/Writer/HTML/Style/Image.php new file mode 100644 index 00000000..fb59b60d --- /dev/null +++ b/src/PhpWord/Writer/HTML/Style/Image.php @@ -0,0 +1,40 @@ +style instanceof \PhpOffice\PhpWord\Style\Image)) { + return; + } + + $css = array(); + if ($this->style->getWidth()) { + $css['width'] = $this->style->getWidth() . 'px'; + } + if ($this->style->getWidth()) { + $css['height'] = $this->style->getHeight() . 'px'; + } + + return $this->assembleCss($css); + } +} diff --git a/src/PhpWord/Writer/HTML/Style/Paragraph.php b/src/PhpWord/Writer/HTML/Style/Paragraph.php new file mode 100644 index 00000000..dd025ee2 --- /dev/null +++ b/src/PhpWord/Writer/HTML/Style/Paragraph.php @@ -0,0 +1,37 @@ +style instanceof \PhpOffice\PhpWord\Style\Paragraph)) { + return; + } + + $css = array(); + if ($this->style->getAlign()) { + $css['text-align'] = $this->style->getAlign(); + } + + return $this->assembleCss($css); + } +} diff --git a/src/PhpWord/Writer/IWriter.php b/src/PhpWord/Writer/IWriter.php deleted file mode 100755 index 2bafdd5b..00000000 --- a/src/PhpWord/Writer/IWriter.php +++ /dev/null @@ -1,39 +0,0 @@ -setPhpWord($phpWord); - // Set up disk caching location - $this->_diskCachingDirectory = './'; - - // Initialise writer parts - $this->_writerParts['content'] = new Content(); - $this->_writerParts['manifest'] = new Manifest(); - $this->_writerParts['meta'] = new Meta(); - $this->_writerParts['mimetype'] = new Mimetype(); - $this->_writerParts['styles'] = new Styles(); - - - // Assign parent IWriter - foreach ($this->_writerParts as $writer) { - $writer->setParentWriter($this); + // Create parts + $parts = array('Content', 'Manifest', 'Meta', 'Mimetype', 'Styles'); + foreach ($parts as $part) { + $partName = strtolower($part); + $partClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Part\\' . $part; + if (class_exists($partClass)) { + $partObject = new $partClass(); + $partObject->setParentWriter($this); + $this->writerParts[$partName] = $partObject; + } } - // Set HashTable variables - $this->_drawingHashTable = new HashTable(); + // Set package paths + $this->mediaPaths = array('image' => 'Pictures/'); } /** * Save PhpWord to file * - * @param string $pFilename - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @param string $filename + * @throws \PhpOffice\PhpWord\Exception\Exception */ - public function save($pFilename = null) + public function save($filename = null) { - if (!is_null($this->_document)) { - // 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; - } + if (!is_null($this->phpWord)) { + $filename = $this->getTempFile($filename); + $objZip = $this->getZipArchive($filename); + + // Add section media files + $sectionMedia = Media::getElements('section'); + if (!empty($sectionMedia)) { + $this->addFilesToPackage($objZip, $sectionMedia); } - // 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->_document)); - - // Add content.xml to ZIP file - $objZip->addFromString('content.xml', $this->getWriterPart('content')->writeContent($this->_document)); - - // Add meta.xml to ZIP file - $objZip->addFromString('meta.xml', $this->getWriterPart('meta')->writeMeta($this->_document)); - - // Add styles.xml to ZIP file - $objZip->addFromString('styles.xml', $this->getWriterPart('styles')->writeStyles($this->_document)); - - // Add META-INF/manifest.xml - $objZip->addFromString('META-INF/manifest.xml', $this->getWriterPart('manifest')->writeManifest($this->_document)); - - // Add media. Has not used yet. Legacy from PHPExcel. - // @codeCoverageIgnoreStart - 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); - } elseif ($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); - } - } - // @codeCoverageIgnoreEnd + // Add parts + $objZip->addFromString('mimetype', $this->getWriterPart('mimetype')->writeMimetype()); + $objZip->addFromString('content.xml', $this->getWriterPart('content')->writeContent($this->phpWord)); + $objZip->addFromString('meta.xml', $this->getWriterPart('meta')->writeMeta($this->phpWord)); + $objZip->addFromString('styles.xml', $this->getWriterPart('styles')->writeStyles($this->phpWord)); + $objZip->addFromString('META-INF/manifest.xml', $this->getWriterPart('manifest')->writeManifest()); // 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); + throw new Exception("Could not close zip file $filename."); } + $this->cleanupTempFile(); } else { throw new Exception("PhpWord object unassigned."); } } - - /** - * Get PhpWord object - * - * @return \PhpOffice\PhpWord\PhpWord - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - public function getPhpWord() - { - if (!is_null($this->_document)) { - return $this->_document; - } else { - throw new Exception("No PhpWord assigned."); - } - } - - /** - * Set PhpWord object - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return \PhpOffice\PhpWord\Writer\ODText - */ - public function setPhpWord(PhpWord $phpWord = null) - { - $this->_document = $phpWord; - return $this; - } - - /** - * Get PHPWord_Worksheet_BaseDrawing HashTable - * - * @return \PhpOffice\PhpWord\HashTable - */ - public function getDrawingHashTable() - { - return $this->_drawingHashTable; - } - - /** - * Get writer part - * - * @param string $pPartName Writer part name - * @return \PhpOffice\PhpWord\Writer\ODText\WriterPart - */ - public 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 \PhpOffice\PhpWord\Exceptions\Exception Exception when directory does not exist - * @return \PhpOffice\PhpWord\Writer\ODText - */ - 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; - } } diff --git a/src/PhpWord/Writer/ODText/Content.php b/src/PhpWord/Writer/ODText/Content.php deleted file mode 100644 index fc3c53b0..00000000 --- a/src/PhpWord/Writer/ODText/Content.php +++ /dev/null @@ -1,424 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8'); - - // office:document-content - $xmlWriter->startElement('office:document-content'); - $xmlWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'); - $xmlWriter->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'); - $xmlWriter->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'); - $xmlWriter->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'); - $xmlWriter->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'); - $xmlWriter->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'); - $xmlWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); - $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); - $xmlWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); - $xmlWriter->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'); - $xmlWriter->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'); - $xmlWriter->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'); - $xmlWriter->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'); - $xmlWriter->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML'); - $xmlWriter->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'); - $xmlWriter->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'); - $xmlWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); - $xmlWriter->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer'); - $xmlWriter->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc'); - $xmlWriter->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events'); - $xmlWriter->writeAttribute('xmlns:xforms', 'http://www.w3.org/2002/xforms'); - $xmlWriter->writeAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema'); - $xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); - $xmlWriter->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report'); - $xmlWriter->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2'); - $xmlWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); - $xmlWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); - $xmlWriter->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table'); - $xmlWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0'); - $xmlWriter->writeAttribute('xmlns:formx', 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0'); - $xmlWriter->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/'); - $xmlWriter->writeAttribute('office:version', '1.2'); - - // We firstly search all fonts used - $_sections = $phpWord->getSections(); - $countSections = count($_sections); - if ($countSections > 0) { - $pSection = 0; - $numPStyles = 0; - $numFStyles = 0; - - foreach ($_sections as $section) { - $pSection++; - $_elements = $section->getElements(); - - foreach ($_elements as $element) { - if ($element instanceof Text) { - $fStyle = $element->getFontStyle(); - $pStyle = $element->getParagraphStyle(); - - if ($fStyle instanceof Font) { - $numFStyles++; - - $arrStyle = array( - 'color' => $fStyle->getColor(), - 'name' => $fStyle->getName() - ); - $phpWord->addFontStyle('T' . $numFStyles, $arrStyle); - $element->setFontStyle('T' . $numFStyles); - } elseif ($pStyle instanceof Paragraph) { - $numPStyles++; - - $phpWord->addParagraphStyle('P' . $numPStyles, array()); - $element->setParagraphStyle('P' . $numPStyles); - } - } - } - } - } - - // office:font-face-decls - $xmlWriter->startElement('office:font-face-decls'); - $arrFonts = array(); - - $styles = Style::getStyles(); - $numFonts = 0; - if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { - // PhpOffice\PhpWord\Style\Font - if ($style instanceof Font) { - $numFonts++; - $name = $style->getName(); - if (!in_array($name, $arrFonts)) { - $arrFonts[] = $name; - - // style:font-face - $xmlWriter->startElement('style:font-face'); - $xmlWriter->writeAttribute('style:name', $name); - $xmlWriter->writeAttribute('svg:font-family', $name); - $xmlWriter->endElement(); - } - } - } - if (!in_array(PhpWord::DEFAULT_FONT_NAME, $arrFonts)) { - $xmlWriter->startElement('style:font-face'); - $xmlWriter->writeAttribute('style:name', PhpWord::DEFAULT_FONT_NAME); - $xmlWriter->writeAttribute('svg:font-family', PhpWord::DEFAULT_FONT_NAME); - $xmlWriter->endElement(); - } - } - $xmlWriter->endElement(); - - $xmlWriter->startElement('office:automatic-styles'); - $styles = Style::getStyles(); - $numPStyles = 0; - if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { - if (preg_match('#^T[0-9]+$#', $styleName) != 0 - || preg_match('#^P[0-9]+$#', $styleName) != 0 - ) { - // PhpOffice\PhpWord\Style\Font - if ($style instanceof Font) { - $xmlWriter->startElement('style:style'); - $xmlWriter->writeAttribute('style:name', $styleName); - $xmlWriter->writeAttribute('style:family', 'text'); - // style:text-properties - $xmlWriter->startElement('style:text-properties'); - $xmlWriter->writeAttribute('fo:color', '#' . $style->getColor()); - $xmlWriter->writeAttribute('style:font-name', $style->getName()); - $xmlWriter->writeAttribute('style:font-name-complex', $style->getName()); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - if ($style instanceof Paragraph) { - $numPStyles++; - // style:style - $xmlWriter->startElement('style:style'); - $xmlWriter->writeAttribute('style:name', $styleName); - $xmlWriter->writeAttribute('style:family', 'paragraph'); - $xmlWriter->writeAttribute('style:parent-style-name', 'Standard'); - $xmlWriter->writeAttribute('style:master-page-name', 'Standard'); - // style:paragraph-properties - $xmlWriter->startElement('style:paragraph-properties'); - $xmlWriter->writeAttribute('style:page-number', 'auto'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - } - - if ($numPStyles == 0) { - // style:style - $xmlWriter->startElement('style:style'); - $xmlWriter->writeAttribute('style:name', 'P1'); - $xmlWriter->writeAttribute('style:family', 'paragraph'); - $xmlWriter->writeAttribute('style:parent-style-name', 'Standard'); - $xmlWriter->writeAttribute('style:master-page-name', 'Standard'); - // style:paragraph-properties - $xmlWriter->startElement('style:paragraph-properties'); - $xmlWriter->writeAttribute('style:page-number', 'auto'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - $xmlWriter->endElement(); - - // office:body - $xmlWriter->startElement('office:body'); - // office:text - $xmlWriter->startElement('office:text'); - // text:sequence-decls - $xmlWriter->startElement('text:sequence-decls'); - // text:sequence-decl - $xmlWriter->startElement('text:sequence-decl'); - $xmlWriter->writeAttribute('text:display-outline-level', 0); - $xmlWriter->writeAttribute('text:name', 'Illustration'); - $xmlWriter->endElement(); - // text:sequence-decl - $xmlWriter->startElement('text:sequence-decl'); - $xmlWriter->writeAttribute('text:display-outline-level', 0); - $xmlWriter->writeAttribute('text:name', 'Table'); - $xmlWriter->endElement(); - // text:sequence-decl - $xmlWriter->startElement('text:sequence-decl'); - $xmlWriter->writeAttribute('text:display-outline-level', 0); - $xmlWriter->writeAttribute('text:name', 'Text'); - $xmlWriter->endElement(); - // text:sequence-decl - $xmlWriter->startElement('text:sequence-decl'); - $xmlWriter->writeAttribute('text:display-outline-level', 0); - $xmlWriter->writeAttribute('text:name', 'Drawing'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $_sections = $phpWord->getSections(); - $countSections = count($_sections); - $pSection = 0; - - if ($countSections > 0) { - foreach ($_sections as $section) { - $pSection++; - - $_elements = $section->getElements(); - - foreach ($_elements as $element) { - if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter); - } elseif ($element instanceof Link) { - $this->writeUnsupportedElement($xmlWriter, 'Link'); - } elseif ($element instanceof Title) { - $this->writeUnsupportedElement($xmlWriter, 'Title'); - } elseif ($element instanceof PageBreak) { - $this->writeUnsupportedElement($xmlWriter, 'Page Break'); - } elseif ($element instanceof Table) { - $this->writeUnsupportedElement($xmlWriter, 'Table'); - } elseif ($element instanceof ListItem) { - $this->writeUnsupportedElement($xmlWriter, 'List Item'); - } elseif ($element instanceof Image) { - $this->writeUnsupportedElement($xmlWriter, 'Image'); - } elseif ($element instanceof Object) { - $this->writeUnsupportedElement($xmlWriter, 'Object'); - } elseif ($element instanceof TOC) { - $this->writeUnsupportedElement($xmlWriter, 'TOC'); - } else { - $this->writeUnsupportedElement($xmlWriter, 'Element'); - } - } - - if ($pSection == $countSections) { - $this->_writeEndSection($xmlWriter, $section); - } else { - $this->_writeSection($xmlWriter, $section); - } - } - } - $xmlWriter->endElement(); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } - - /** - * Write text - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Section\Text $text - * @param bool $withoutP - */ - protected function _writeText(XMLWriter $xmlWriter, Text $text, $withoutP = false) - { - $styleFont = $text->getFontStyle(); - $styleParagraph = $text->getParagraphStyle(); - - // @todo Commented for TextRun. Should really checkout this value - // $SfIsObject = ($styleFont instanceof Font) ? true : false; - $SfIsObject = false; - - if ($SfIsObject) { - // Don't never be the case, because I browse all sections for cleaning all styles not declared - die('PhpWord : $SfIsObject wouldn\'t be an object'); - } else { - if (!$withoutP) { - $xmlWriter->startElement('text:p'); // text:p - } - if (empty($styleFont)) { - if (empty($styleParagraph)) { - $xmlWriter->writeAttribute('text:style-name', 'P1'); - } else { - $xmlWriter->writeAttribute('text:style-name', $text->getParagraphStyle()); - } - $xmlWriter->writeRaw($text->getText()); - } else { - if (empty($styleParagraph)) { - $xmlWriter->writeAttribute('text:style-name', 'Standard'); - } else { - $xmlWriter->writeAttribute('text:style-name', $text->getParagraphStyle()); - } - // text:span - $xmlWriter->startElement('text:span'); - $xmlWriter->writeAttribute('text:style-name', $styleFont); - $xmlWriter->writeRaw($text->getText()); - $xmlWriter->endElement(); - } - if (!$withoutP) { - $xmlWriter->endElement(); // text:p - } - } - } - - /** - * Write TextRun section - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Section\TextRun $textrun - * @todo Enable all other section types - */ - protected function _writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) - { - $elements = $textrun->getElements(); - $xmlWriter->startElement('text:p'); - if (count($elements) > 0) { - foreach ($elements as $element) { - if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element, true); - } - } - } - $xmlWriter->endElement(); - } - - /** - * Write TextBreak - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - */ - protected function _writeTextBreak(XMLWriter $xmlWriter = null) - { - $xmlWriter->startElement('text:p'); - $xmlWriter->writeAttribute('text:style-name', 'Standard'); - $xmlWriter->endElement(); - } - - // @codeCoverageIgnoreStart - /** - * Write end section - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section - */ - private function _writeEndSection(XMLWriter $xmlWriter = null, Section $section = null) - { - } - - /** - * Write section - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section - */ - private function _writeSection(XMLWriter $xmlWriter = null, Section $section = null) - { - } - // @codeCoverageIgnoreEnd - - /** - * Write unsupported element - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param string $element - */ - private function writeUnsupportedElement($xmlWriter, $element) - { - $xmlWriter->startElement('text:p'); - $xmlWriter->writeRaw($element); - $xmlWriter->endElement(); - } -} diff --git a/src/PhpWord/Writer/ODText/Element/Element.php b/src/PhpWord/Writer/ODText/Element/Element.php new file mode 100644 index 00000000..67ee9c20 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Element.php @@ -0,0 +1,78 @@ +xmlWriter = $xmlWriter; + $this->parentWriter = $parentWriter; + $this->element = $element; + $this->withoutP = $withoutP; + } + + /** + * Write element + * + * @return string + */ + public function write() + { + $elmName = str_replace('PhpOffice\\PhpWord\\Element\\', '', get_class($this->element)); + $elmWriterClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Element\\' . $elmName; + if (class_exists($elmWriterClass) === true) { + $elmWriter = new $elmWriterClass($this->xmlWriter, $this->parentWriter, $this->element, $this->withoutP); + $elmWriter->write(); + } + } +} diff --git a/src/PhpWord/Writer/ODText/Element/Image.php b/src/PhpWord/Writer/ODText/Element/Image.php new file mode 100644 index 00000000..d096a03b --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Image.php @@ -0,0 +1,54 @@ +element->getMediaIndex(); + $target = 'Pictures/' . $this->element->getTarget(); + $style = $this->element->getStyle(); + $width = Drawing::pixelsToCentimeters($style->getWidth()); + $height = Drawing::pixelsToCentimeters($style->getHeight()); + + $this->xmlWriter->startElement('text:p'); + $this->xmlWriter->writeAttribute('text:style-name', 'Standard'); + + $this->xmlWriter->startElement('draw:frame'); + $this->xmlWriter->writeAttribute('draw:style-name', 'fr' . $mediaIndex); + $this->xmlWriter->writeAttribute('draw:name', $this->element->getElementId()); + $this->xmlWriter->writeAttribute('text:anchor-type', 'as-char'); + $this->xmlWriter->writeAttribute('svg:width', $width . 'cm'); + $this->xmlWriter->writeAttribute('svg:height', $height . 'cm'); + $this->xmlWriter->writeAttribute('draw:z-index', $mediaIndex); + + $this->xmlWriter->startElement('draw:image'); + $this->xmlWriter->writeAttribute('xlink:href', $target); + $this->xmlWriter->writeAttribute('xlink:type', 'simple'); + $this->xmlWriter->writeAttribute('xlink:show', 'embed'); + $this->xmlWriter->writeAttribute('xlink:actuate', 'onLoad'); + $this->xmlWriter->endElement(); // draw:image + + $this->xmlWriter->endElement(); // draw:frame + + $this->xmlWriter->endElement(); // text:p + } +} diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php new file mode 100644 index 00000000..08235519 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -0,0 +1,38 @@ +withoutP) { + $this->xmlWriter->startElement('text:p'); // text:p + } + + $this->xmlWriter->startElement('text:a'); + $this->xmlWriter->writeAttribute('xlink:type', 'simple'); + $this->xmlWriter->writeAttribute('xlink:href', $this->element->getTarget()); + $this->xmlWriter->writeRaw($this->element->getText()); + $this->xmlWriter->endElement(); // text:a + + if (!$this->withoutP) { + $this->xmlWriter->endElement(); // text:p + } + } +} diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php new file mode 100644 index 00000000..7972eb37 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -0,0 +1,61 @@ +element->getRows(); + $rowCount = count($rows); + $colCount = $this->element->countColumns(); + if ($rowCount > 0) { + $this->xmlWriter->startElement('table:table'); + $this->xmlWriter->writeAttribute('table:name', $this->element->getElementId()); + $this->xmlWriter->writeAttribute('table:style', $this->element->getElementId()); + + $this->xmlWriter->startElement('table:table-column'); + $this->xmlWriter->writeAttribute('table:number-columns-repeated', $colCount); + $this->xmlWriter->endElement(); // table:table-column + + foreach ($rows as $row) { + $this->xmlWriter->startElement('table:table-row'); + foreach ($row->getCells() as $cell) { + $this->xmlWriter->startElement('table:table-cell'); + $this->xmlWriter->writeAttribute('office:value-type', 'string'); + $elements = $cell->getElements(); + if (count($elements) > 0) { + foreach ($elements as $element) { + $elementWriter = new ElementWriter($this->xmlWriter, $this->parentWriter, $element); + $elementWriter->write(); + } + } else { + $elementWriter = new ElementWriter($this->xmlWriter, $this->parentWriter, new TextBreakElement()); + $elementWriter->write(); + } + $this->xmlWriter->endElement(); // table:table-cell + } + $this->xmlWriter->endElement(); // table:table-row + } + $this->xmlWriter->endElement(); // table:table + } + } +} diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php new file mode 100644 index 00000000..63ce7b68 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -0,0 +1,64 @@ +element->getFontStyle(); + $paragraphStyle = $this->element->getParagraphStyle(); + + // @todo Commented for TextRun. Should really checkout this value + // $SfIsObject = ($fontStyle instanceof Font) ? true : false; + $SfIsObject = false; + + if ($SfIsObject) { + // Don't never be the case, because I browse all sections for cleaning all styles not declared + throw new Exception('PhpWord : $SfIsObject wouldn\'t be an object'); + } else { + if (!$this->withoutP) { + $this->xmlWriter->startElement('text:p'); // text:p + } + if (empty($fontStyle)) { + if (empty($paragraphStyle)) { + $this->xmlWriter->writeAttribute('text:style-name', 'P1'); + } elseif (is_string($paragraphStyle)) { + $this->xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } + $this->xmlWriter->writeRaw($this->element->getText()); + } else { + if (empty($paragraphStyle)) { + $this->xmlWriter->writeAttribute('text:style-name', 'Standard'); + } elseif (is_string($paragraphStyle)) { + $this->xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } + // text:span + $this->xmlWriter->startElement('text:span'); + if (is_string($fontStyle)) { + $this->xmlWriter->writeAttribute('text:style-name', $fontStyle); + } + $this->xmlWriter->writeRaw($this->element->getText()); + $this->xmlWriter->endElement(); + } + if (!$this->withoutP) { + $this->xmlWriter->endElement(); // text:p + } + } + } +} diff --git a/src/PhpWord/Writer/ODText/Element/TextBreak.php b/src/PhpWord/Writer/ODText/Element/TextBreak.php new file mode 100644 index 00000000..ce342399 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/TextBreak.php @@ -0,0 +1,28 @@ +xmlWriter->startElement('text:p'); + $this->xmlWriter->writeAttribute('text:style-name', 'Standard'); + $this->xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/ODText/Element/TextRun.php b/src/PhpWord/Writer/ODText/Element/TextRun.php new file mode 100644 index 00000000..f97d9c8c --- /dev/null +++ b/src/PhpWord/Writer/ODText/Element/TextRun.php @@ -0,0 +1,41 @@ +element->getElements(); + $this->xmlWriter->startElement('text:p'); + if (count($elements) > 0) { + foreach ($elements as $element) { + if ($element instanceof TextElement) { + $elementWriter = new Text($this->xmlWriter, $this->parentWriter, $element, true); + $elementWriter->write(); + } elseif ($element instanceof Link) { + $elementWriter = new Link($this->xmlWriter, $this->parentWriter, $element, true); + $elementWriter->write(); + } + } + } + $this->xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/ODText/Manifest.php b/src/PhpWord/Writer/ODText/Manifest.php deleted file mode 100755 index 18e09440..00000000 --- a/src/PhpWord/Writer/ODText/Manifest.php +++ /dev/null @@ -1,132 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8'); - - // manifest:manifest - $xmlWriter->startElement('manifest:manifest'); - $xmlWriter->writeAttribute('xmlns:manifest', 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'); - $xmlWriter->writeAttribute('manifest:version', '1.2'); - - // manifest:file-entry - $xmlWriter->startElement('manifest:file-entry'); - $xmlWriter->writeAttribute('manifest:media-type', 'application/vnd.oasis.opendocument.text'); - $xmlWriter->writeAttribute('manifest:version', '1.2'); - $xmlWriter->writeAttribute('manifest:full-path', '/'); - $xmlWriter->endElement(); - // manifest:file-entry - $xmlWriter->startElement('manifest:file-entry'); - $xmlWriter->writeAttribute('manifest:media-type', 'text/xml'); - $xmlWriter->writeAttribute('manifest:full-path', 'content.xml'); - $xmlWriter->endElement(); - // manifest:file-entry - $xmlWriter->startElement('manifest:file-entry'); - $xmlWriter->writeAttribute('manifest:media-type', 'text/xml'); - $xmlWriter->writeAttribute('manifest:full-path', 'meta.xml'); - $xmlWriter->endElement(); - // manifest:file-entry - $xmlWriter->startElement('manifest:file-entry'); - $xmlWriter->writeAttribute('manifest:media-type', 'text/xml'); - $xmlWriter->writeAttribute('manifest:full-path', 'styles.xml'); - $xmlWriter->endElement(); - - // Not used yet. Legacy from PHPExcel - // @codeCoverageIgnoreStart - 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()); - - $xmlWriter->startElement('manifest:file-entry'); - $xmlWriter->writeAttribute('manifest:media-type', $mimeType); - $xmlWriter->writeAttribute('manifest:full-path', 'Pictures/' . str_replace(' ', '_', $this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getIndexedFilename())); - $xmlWriter->endElement(); - } elseif ($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(); - - $xmlWriter->startElement('manifest:file-entry'); - $xmlWriter->writeAttribute('manifest:media-type', $mimeType); - $xmlWriter->writeAttribute('manifest:full-path', 'Pictures/' . str_replace(' ', '_', $this->getParentWriter()->getDrawingHashTable()->getByIndex($i)->getIndexedFilename())); - $xmlWriter->endElement(); - } - } - // @codeCoverageIgnoreEnd - - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } - - - /** - * Get image mime type - * - * @param string $pFile Filename - * @return string Mime Type - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - private function _getImageMimeType($pFile = '') - { - if (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/Mimetype.php b/src/PhpWord/Writer/ODText/Mimetype.php deleted file mode 100644 index fa119136..00000000 --- a/src/PhpWord/Writer/ODText/Mimetype.php +++ /dev/null @@ -1,45 +0,0 @@ -writeAttribute('office:version', '1.2'); + $xmlWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'); + $xmlWriter->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'); + $xmlWriter->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'); + $xmlWriter->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'); + $xmlWriter->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'); + $xmlWriter->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'); + $xmlWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); + $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); + $xmlWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); + $xmlWriter->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'); + $xmlWriter->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'); + $xmlWriter->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'); + $xmlWriter->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'); + $xmlWriter->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML'); + $xmlWriter->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'); + $xmlWriter->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'); + $xmlWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); + $xmlWriter->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer'); + $xmlWriter->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc'); + $xmlWriter->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events'); + $xmlWriter->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report'); + $xmlWriter->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2'); + $xmlWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); + $xmlWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); + $xmlWriter->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table'); + $xmlWriter->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/'); + } + + /** + * Write font faces declaration + */ + protected function writeFontFaces(XMLWriter $xmlWriter) + { + $xmlWriter->startElement('office:font-face-decls'); + $arrFonts = array(); + $styles = Style::getStyles(); + $numFonts = 0; + if (count($styles) > 0) { + foreach ($styles as $style) { + // Font + if ($style instanceof Font) { + $numFonts++; + $name = $style->getName(); + if (!in_array($name, $arrFonts)) { + $arrFonts[] = $name; + + // style:font-face + $xmlWriter->startElement('style:font-face'); + $xmlWriter->writeAttribute('style:name', $name); + $xmlWriter->writeAttribute('svg:font-family', $name); + $xmlWriter->endElement(); + } + } + } + } + if (!in_array(PhpWord::DEFAULT_FONT_NAME, $arrFonts)) { + $xmlWriter->startElement('style:font-face'); + $xmlWriter->writeAttribute('style:name', PhpWord::DEFAULT_FONT_NAME); + $xmlWriter->writeAttribute('svg:font-family', PhpWord::DEFAULT_FONT_NAME); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/ODText/Part/Content.php b/src/PhpWord/Writer/ODText/Part/Content.php new file mode 100644 index 00000000..fbeb6982 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Part/Content.php @@ -0,0 +1,205 @@ +getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8'); + $xmlWriter->startElement('office:document-content'); + $this->writeCommonRootAttributes($xmlWriter); + $xmlWriter->writeAttribute('xmlns:xforms', 'http://www.w3.org/2002/xforms'); + $xmlWriter->writeAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema'); + $xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + $xmlWriter->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0'); + $xmlWriter->writeAttribute('xmlns:formx', 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0'); + + $this->getAutomaticStyles($phpWord); + $this->writeFontFaces($xmlWriter); // office:font-face-decls + $this->writeAutomaticStyles($xmlWriter, $phpWord); // office:automatic-styles + + $xmlWriter->startElement('office:body'); + $xmlWriter->startElement('office:text'); + + // text:sequence-decls + $sequences = array('Illustration', 'Table', 'Text', 'Drawing'); + $xmlWriter->startElement('text:sequence-decls'); + foreach ($sequences as $sequence) { + $xmlWriter->startElement('text:sequence-decl'); + $xmlWriter->writeAttribute('text:display-outline-level', 0); + $xmlWriter->writeAttribute('text:name', $sequence); + $xmlWriter->endElement(); + } + $xmlWriter->endElement(); // text:sequence-decl + + $sections = $phpWord->getSections(); + $sectionCount = count($sections); + if ($sectionCount > 0) { + foreach ($sections as $section) { + $elements = $section->getElements(); + // $xmlWriter->startElement('text:section'); + foreach ($elements as $element) { + $elementWriter = new ElementWriter($xmlWriter, $this, $element, false); + $elementWriter->write(); + } + // $xmlWriter->endElement(); // text:section + } + } + $xmlWriter->endElement(); // office:text + $xmlWriter->endElement(); // office:body + $xmlWriter->endElement(); // office:document-content + + return $xmlWriter->getData(); + } + + /** + * Write automatic styles + */ + private function writeAutomaticStyles(XMLWriter $xmlWriter, PhpWord $phpWord) + { + $xmlWriter->startElement('office:automatic-styles'); + + // Font and paragraph + $styles = Style::getStyles(); + $paragraphStyleCount = 0; + if (count($styles) > 0) { + foreach ($styles as $styleName => $style) { + if (preg_match('#^T[0-9]+$#', $styleName) != 0 + || preg_match('#^P[0-9]+$#', $styleName) != 0 + ) { + $styleClass = str_replace('Style', 'Writer\\ODText\\Style', get_class($style)); + if (class_exists($styleClass)) { + $styleWriter = new $styleClass($xmlWriter, $style); + $styleWriter->setIsAuto(true); + $styleWriter->write(); + } + if ($style instanceof Paragraph) { + $paragraphStyleCount++; + } + } + } + if ($paragraphStyleCount == 0) { + $style = new Paragraph(); + $style->setStyleName('P1'); + $styleWriter = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $style); + $styleWriter->setIsAuto(true); + $styleWriter->write(); + } + } + + // Images + $images = Media::getElements('section'); + foreach ($images as $image) { + if ($image['type'] == 'image') { + $xmlWriter->startElement('style:style'); + $xmlWriter->writeAttribute('style:name', 'fr' . $image['rID']); + $xmlWriter->writeAttribute('style:family', 'graphic'); + $xmlWriter->writeAttribute('style:parent-style-name', 'Graphics'); + $xmlWriter->startElement('style:graphic-properties'); + $xmlWriter->writeAttribute('style:vertical-pos', 'top'); + $xmlWriter->writeAttribute('style:vertical-rel', 'baseline'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + } + + // Tables + $sections = $phpWord->getSections(); + $sectionCount = count($sections); + if ($sectionCount > 0) { + $sectionId = 0; + foreach ($sections as $section) { + $sectionId++; + $elements = $section->getElements(); + foreach ($elements as $element) { + if ($elements instanceof Table) { + $xmlWriter->startElement('style:style'); + $xmlWriter->writeAttribute('style:name', $element->getElementId()); + $xmlWriter->writeAttribute('style:family', 'table'); + $xmlWriter->startElement('style:table-properties'); + //$xmlWriter->writeAttribute('style:width', 'table'); + $xmlWriter->writeAttribute('style:rel-width', 100); + $xmlWriter->writeAttribute('table:align', 'center'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + } + } + } + + $xmlWriter->endElement(); // office:automatic-styles + } + + /** + * Set automatic styles + */ + private function getAutomaticStyles(PhpWord $phpWord) + { + $sections = $phpWord->getSections(); + $sectionCount = count($sections); + if ($sectionCount > 0) { + $paragraphStyleCount = 0; + $fontStyleCount = 0; + foreach ($sections as $section) { + $elements = $section->getElements(); + foreach ($elements as $element) { + if ($element instanceof Text) { + $fontStyle = $element->getFontStyle(); + $paragraphStyle = $element->getParagraphStyle(); + + // Font + if ($fontStyle instanceof Font) { + $fontStyleCount++; + $arrStyle = array( + 'color' => $fontStyle->getColor(), + 'name' => $fontStyle->getName() + ); + $phpWord->addFontStyle('T' . $fontStyleCount, $arrStyle); + $element->setFontStyle('T' . $fontStyleCount); + + // Paragraph + } elseif ($paragraphStyle instanceof Paragraph) { + $paragraphStyleCount++; + + $phpWord->addParagraphStyle('P' . $paragraphStyleCount, array()); + $element->setParagraphStyle('P' . $paragraphStyleCount); + } + } + } + } + } + } +} diff --git a/src/PhpWord/Writer/ODText/Part/Manifest.php b/src/PhpWord/Writer/ODText/Part/Manifest.php new file mode 100644 index 00000000..4462e7ef --- /dev/null +++ b/src/PhpWord/Writer/ODText/Part/Manifest.php @@ -0,0 +1,74 @@ +getXmlWriter(); + + // XML header + $xmlWriter->startDocument('1.0', 'UTF-8'); + + // manifest:manifest + $xmlWriter->startElement('manifest:manifest'); + $xmlWriter->writeAttribute('manifest:version', '1.2'); + $xmlWriter->writeAttribute('xmlns:manifest', 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'); + + // manifest:file-entry + $xmlWriter->startElement('manifest:file-entry'); + $xmlWriter->writeAttribute('manifest:media-type', 'application/vnd.oasis.opendocument.text'); + $xmlWriter->writeAttribute('manifest:version', '1.2'); + $xmlWriter->writeAttribute('manifest:full-path', '/'); + $xmlWriter->endElement(); + // manifest:file-entry + $xmlWriter->startElement('manifest:file-entry'); + $xmlWriter->writeAttribute('manifest:media-type', 'text/xml'); + $xmlWriter->writeAttribute('manifest:full-path', 'content.xml'); + $xmlWriter->endElement(); + // manifest:file-entry + $xmlWriter->startElement('manifest:file-entry'); + $xmlWriter->writeAttribute('manifest:media-type', 'text/xml'); + $xmlWriter->writeAttribute('manifest:full-path', 'meta.xml'); + $xmlWriter->endElement(); + // manifest:file-entry + $xmlWriter->startElement('manifest:file-entry'); + $xmlWriter->writeAttribute('manifest:media-type', 'text/xml'); + $xmlWriter->writeAttribute('manifest:full-path', 'styles.xml'); + $xmlWriter->endElement(); + + // Media files + $media = Media::getElements('section'); + foreach ($media as $medium) { + if ($medium['type'] == 'image') { + $xmlWriter->startElement('manifest:file-entry'); + $xmlWriter->writeAttribute('manifest:media-type', $medium['imageType']); + $xmlWriter->writeAttribute('manifest:full-path', 'Pictures/' . $medium['target']); + $xmlWriter->endElement(); + } + } + + $xmlWriter->endElement(); // manifest:manifest + + return $xmlWriter->getData(); + } +} diff --git a/src/PhpWord/Writer/ODText/Meta.php b/src/PhpWord/Writer/ODText/Part/Meta.php similarity index 65% rename from src/PhpWord/Writer/ODText/Meta.php rename to src/PhpWord/Writer/ODText/Part/Meta.php index e30836e8..355e288b 100644 --- a/src/PhpWord/Writer/ODText/Meta.php +++ b/src/PhpWord/Writer/ODText/Part/Meta.php @@ -2,36 +2,20 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Writer\ODText; +namespace PhpOffice\PhpWord\Writer\ODText\Part; +use PhpOffice\PhpWord\Exception\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLWriter; /** * ODText meta part writer */ -class Meta extends WriterPart +class Meta extends AbstractPart { /** * Write Meta file to XML format @@ -41,26 +25,25 @@ class Meta extends WriterPart */ public function writeMeta(PhpWord $phpWord = null) { - // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); + if (is_null($phpWord)) { + throw new Exception("No PhpWord assigned."); } + // Create XML writer + $xmlWriter = $this->getXmlWriter(); + // XML header $xmlWriter->startDocument('1.0', 'UTF-8'); // office:document-meta $xmlWriter->startElement('office:document-meta'); + $xmlWriter->writeAttribute('office:version', '1.2'); $xmlWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'); $xmlWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); $xmlWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); $xmlWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); $xmlWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); - $xmlWriter->writeAttribute('office:version', '1.2'); // office:meta $xmlWriter->startElement('office:meta'); diff --git a/src/PhpWord/Writer/ODText/Part/Mimetype.php b/src/PhpWord/Writer/ODText/Part/Mimetype.php new file mode 100644 index 00000000..3c3af1a5 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Part/Mimetype.php @@ -0,0 +1,26 @@ +getXmlWriter(); + + // XML header + $xmlWriter->startDocument('1.0', 'UTF-8'); + + // Styles:Styles + $xmlWriter->startElement('office:document-styles'); + $this->writeCommonRootAttributes($xmlWriter); + + // office:font-face-decls + $this->writeFontFaces($xmlWriter); + + // office:styles + $xmlWriter->startElement('office:styles'); + + // style:default-style + $xmlWriter->startElement('style:default-style'); + $xmlWriter->writeAttribute('style:family', 'paragraph'); + + // style:paragraph-properties + $xmlWriter->startElement('style:paragraph-properties'); + $xmlWriter->writeAttribute('fo:hyphenation-ladder-count', 'no-limit'); + $xmlWriter->writeAttribute('style:text-autospace', 'ideograph-alpha'); + $xmlWriter->writeAttribute('style:punctuation-wrap', 'hanging'); + $xmlWriter->writeAttribute('style:line-break', 'strict'); + $xmlWriter->writeAttribute('style:tab-stop-distance', '1.249cm'); + $xmlWriter->writeAttribute('style:writing-mode', 'page'); + $xmlWriter->endElement(); + + // style:text-properties + $xmlWriter->startElement('style:text-properties'); + $xmlWriter->writeAttribute('style:use-window-font-color', 'true'); + $xmlWriter->writeAttribute('style:font-name', PhpWord::DEFAULT_FONT_NAME); + $xmlWriter->writeAttribute('fo:font-size', PhpWord::DEFAULT_FONT_SIZE . 'pt'); + $xmlWriter->writeAttribute('fo:language', 'fr'); + $xmlWriter->writeAttribute('fo:country', 'FR'); + $xmlWriter->writeAttribute('style:letter-kerning', 'true'); + $xmlWriter->writeAttribute('style:font-name-asian', PhpWord::DEFAULT_FONT_NAME . '2'); + $xmlWriter->writeAttribute('style:font-size-asian', PhpWord::DEFAULT_FONT_SIZE . 'pt'); + $xmlWriter->writeAttribute('style:language-asian', 'zh'); + $xmlWriter->writeAttribute('style:country-asian', 'CN'); + $xmlWriter->writeAttribute('style:font-name-complex', PhpWord::DEFAULT_FONT_NAME . '2'); + $xmlWriter->writeAttribute('style:font-size-complex', PhpWord::DEFAULT_FONT_SIZE . 'pt'); + $xmlWriter->writeAttribute('style:language-complex', 'hi'); + $xmlWriter->writeAttribute('style:country-complex', 'IN'); + $xmlWriter->writeAttribute('fo:hyphenate', 'false'); + $xmlWriter->writeAttribute('fo:hyphenation-remain-char-count', '2'); + $xmlWriter->writeAttribute('fo:hyphenation-push-char-count', '2'); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + + // Write Style Definitions + $styles = Style::getStyles(); + if (count($styles) > 0) { + foreach ($styles as $styleName => $style) { + if (preg_match('#^T[0-9]+$#', $styleName) == 0 + && preg_match('#^P[0-9]+$#', $styleName) == 0 + ) { + $styleClass = str_replace('Style', 'Writer\\ODText\\Style', get_class($style)); + if (class_exists($styleClass)) { + $styleWriter = new $styleClass($xmlWriter, $style); + $styleWriter->write(); + } + } + } + } + $xmlWriter->endElement(); + + // office:automatic-styles + $xmlWriter->startElement('office:automatic-styles'); + // style:page-layout + $xmlWriter->startElement('style:page-layout'); + $xmlWriter->writeAttribute('style:name', 'Mpm1'); + // style:page-layout-properties + $xmlWriter->startElement('style:page-layout-properties'); + $xmlWriter->writeAttribute('fo:page-width', "21.001cm"); + $xmlWriter->writeAttribute('fo:page-height', '29.7cm'); + $xmlWriter->writeAttribute('style:num-format', '1'); + $xmlWriter->writeAttribute('style:print-orientation', 'portrait'); + $xmlWriter->writeAttribute('fo:margin-top', '2.501cm'); + $xmlWriter->writeAttribute('fo:margin-bottom', '2cm'); + $xmlWriter->writeAttribute('fo:margin-left', '2.501cm'); + $xmlWriter->writeAttribute('fo:margin-right', '2.501cm'); + $xmlWriter->writeAttribute('style:writing-mode', 'lr-tb'); + $xmlWriter->writeAttribute('style:layout-grid-color', '#c0c0c0'); + $xmlWriter->writeAttribute('style:layout-grid-lines', '25199'); + $xmlWriter->writeAttribute('style:layout-grid-base-height', '0.423cm'); + $xmlWriter->writeAttribute('style:layout-grid-ruby-height', '0cm'); + $xmlWriter->writeAttribute('style:layout-grid-mode', 'none'); + $xmlWriter->writeAttribute('style:layout-grid-ruby-below', 'false'); + $xmlWriter->writeAttribute('style:layout-grid-print', 'false'); + $xmlWriter->writeAttribute('style:layout-grid-display', 'false'); + $xmlWriter->writeAttribute('style:layout-grid-base-width', '0.37cm'); + $xmlWriter->writeAttribute('style:layout-grid-snap-to', 'true'); + $xmlWriter->writeAttribute('style:footnote-max-height', '0cm'); + //style:footnote-sep + $xmlWriter->startElement('style:footnote-sep'); + $xmlWriter->writeAttribute('style:width', '0.018cm'); + $xmlWriter->writeAttribute('style:line-style', 'solid'); + $xmlWriter->writeAttribute('style:adjustment', 'left'); + $xmlWriter->writeAttribute('style:rel-width', '25%'); + $xmlWriter->writeAttribute('style:color', '#000000'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + // style:header-style + $xmlWriter->startElement('style:header-style'); + $xmlWriter->endElement(); + // style:footer-style + $xmlWriter->startElement('style:footer-style'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + // office:master-styles + $xmlWriter->startElement('office:master-styles'); + // style:master-page + $xmlWriter->startElement('style:master-page'); + $xmlWriter->writeAttribute('style:name', 'Standard'); + $xmlWriter->writeAttribute('style:page-layout-name', 'Mpm1'); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); + + // Return + return $xmlWriter->getData(); + } +} diff --git a/src/PhpWord/Writer/ODText/Style/AbstractStyle.php b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php new file mode 100644 index 00000000..30416b5d --- /dev/null +++ b/src/PhpWord/Writer/ODText/Style/AbstractStyle.php @@ -0,0 +1,19 @@ +style instanceof \PhpOffice\PhpWord\Style\Font)) { + return; + } + + $this->xmlWriter->startElement('style:style'); + $this->xmlWriter->writeAttribute('style:name', $this->style->getStyleName()); + $this->xmlWriter->writeAttribute('style:family', 'text'); + $this->xmlWriter->startElement('style:text-properties'); + if ($this->style->getName()) { + $this->xmlWriter->writeAttribute('style:font-name', $this->style->getName()); + $this->xmlWriter->writeAttribute('style:font-name-complex', $this->style->getName()); + } + if ($this->style->getSize()) { + $this->xmlWriter->writeAttribute('fo:font-size', ($this->style->getSize()) . 'pt'); + $this->xmlWriter->writeAttribute('style:font-size-asian', ($this->style->getSize()) . 'pt'); + $this->xmlWriter->writeAttribute('style:font-size-complex', ($this->style->getSize()) . 'pt'); + } + if ($this->style->getColor()) { + $this->xmlWriter->writeAttribute('fo:color', '#' . $this->style->getColor()); + } + if ($this->style->getItalic()) { + $this->xmlWriter->writeAttribute('fo:font-style', 'italic'); + $this->xmlWriter->writeAttribute('style:font-style-asian', 'italic'); + $this->xmlWriter->writeAttribute('style:font-style-complex', 'italic'); + } + if ($this->style->getBold()) { + $this->xmlWriter->writeAttribute('fo:font-weight', 'bold'); + $this->xmlWriter->writeAttribute('style:font-weight-asian', 'bold'); + } + $this->xmlWriter->endElement(); // style:text-properties + $this->xmlWriter->endElement(); // style:style + } + + /** + * Set is automatic style + * + * @param bool $value + */ + public function setIsAuto($value) + { + $this->isAuto = $value; + } +} diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php new file mode 100644 index 00000000..7bd490c3 --- /dev/null +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -0,0 +1,68 @@ +style instanceof \PhpOffice\PhpWord\Style\Paragraph)) { + return; + } + + $marginTop = is_null($this->style->getSpaceBefore()) ? '0' : round(17.6 / $this->style->getSpaceBefore(), 2); + $marginBottom = is_null($this->style->getSpaceAfter()) ? '0' : round(17.6 / $this->style->getSpaceAfter(), 2); + + $this->xmlWriter->startElement('style:style'); + $this->xmlWriter->writeAttribute('style:name', $this->style->getStyleName()); + $this->xmlWriter->writeAttribute('style:family', 'paragraph'); + if ($this->isAuto) { + $this->xmlWriter->writeAttribute('style:parent-style-name', 'Standard'); + $this->xmlWriter->writeAttribute('style:master-page-name', 'Standard'); + } + + $this->xmlWriter->startElement('style:paragraph-properties'); + if ($this->isAuto) { + $this->xmlWriter->writeAttribute('style:page-number', 'auto'); + } else { + $this->xmlWriter->writeAttribute('fo:margin-top', $marginTop . 'cm'); + $this->xmlWriter->writeAttribute('fo:margin-bottom', $marginBottom . 'cm'); + $this->xmlWriter->writeAttribute('fo:text-align', $this->style->getAlign()); + } + $this->xmlWriter->endElement(); //style:paragraph-properties + + $this->xmlWriter->endElement(); //style:style + } + + /** + * Set is automatic style + * + * @param bool $value + */ + public function setIsAuto($value) + { + $this->isAuto = $value; + } +} diff --git a/src/PhpWord/Writer/ODText/Styles.php b/src/PhpWord/Writer/ODText/Styles.php deleted file mode 100644 index 75a37915..00000000 --- a/src/PhpWord/Writer/ODText/Styles.php +++ /dev/null @@ -1,273 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8'); - - // Styles:Styles - $xmlWriter->startElement('office:document-styles'); - $xmlWriter->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'); - $xmlWriter->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'); - $xmlWriter->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'); - $xmlWriter->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'); - $xmlWriter->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0'); - $xmlWriter->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'); - $xmlWriter->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink'); - $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); - $xmlWriter->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'); - $xmlWriter->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0'); - $xmlWriter->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'); - $xmlWriter->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'); - $xmlWriter->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'); - $xmlWriter->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML'); - $xmlWriter->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'); - $xmlWriter->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'); - $xmlWriter->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office'); - $xmlWriter->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer'); - $xmlWriter->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc'); - $xmlWriter->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events'); - $xmlWriter->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report'); - $xmlWriter->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2'); - $xmlWriter->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml'); - $xmlWriter->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#'); - $xmlWriter->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table'); - $xmlWriter->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/'); - $xmlWriter->writeAttribute('office:version', '1.2'); - - - // office:font-face-decls - $xmlWriter->startElement('office:font-face-decls'); - $arrFonts = array(); - $styles = Style::getStyles(); - $numFonts = 0; - if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { - // PhpOffice\PhpWord\Style\Font - if ($style instanceof Font) { - $numFonts++; - $name = $style->getName(); - if (!in_array($name, $arrFonts)) { - $arrFonts[] = $name; - - // style:font-face - $xmlWriter->startElement('style:font-face'); - $xmlWriter->writeAttribute('style:name', $name); - $xmlWriter->writeAttribute('svg:font-family', $name); - $xmlWriter->endElement(); - } - } - } - } - if (!in_array(PhpWord::DEFAULT_FONT_NAME, $arrFonts)) { - $xmlWriter->startElement('style:font-face'); - $xmlWriter->writeAttribute('style:name', PhpWord::DEFAULT_FONT_NAME); - $xmlWriter->writeAttribute('svg:font-family', PhpWord::DEFAULT_FONT_NAME); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - - // office:styles - $xmlWriter->startElement('office:styles'); - - // style:default-style - $xmlWriter->startElement('style:default-style'); - $xmlWriter->writeAttribute('style:family', 'paragraph'); - - // style:paragraph-properties - $xmlWriter->startElement('style:paragraph-properties'); - $xmlWriter->writeAttribute('fo:hyphenation-ladder-count', 'no-limit'); - $xmlWriter->writeAttribute('style:text-autospace', 'ideograph-alpha'); - $xmlWriter->writeAttribute('style:punctuation-wrap', 'hanging'); - $xmlWriter->writeAttribute('style:line-break', 'strict'); - $xmlWriter->writeAttribute('style:tab-stop-distance', '1.249cm'); - $xmlWriter->writeAttribute('style:writing-mode', 'page'); - $xmlWriter->endElement(); - - // style:text-properties - $xmlWriter->startElement('style:text-properties'); - $xmlWriter->writeAttribute('style:use-window-font-color', 'true'); - $xmlWriter->writeAttribute('style:font-name', PhpWord::DEFAULT_FONT_NAME); - $xmlWriter->writeAttribute('fo:font-size', PhpWord::DEFAULT_FONT_SIZE . 'pt'); - $xmlWriter->writeAttribute('fo:language', 'fr'); - $xmlWriter->writeAttribute('fo:country', 'FR'); - $xmlWriter->writeAttribute('style:letter-kerning', 'true'); - $xmlWriter->writeAttribute('style:font-name-asian', PhpWord::DEFAULT_FONT_NAME . '2'); - $xmlWriter->writeAttribute('style:font-size-asian', PhpWord::DEFAULT_FONT_SIZE . 'pt'); - $xmlWriter->writeAttribute('style:language-asian', 'zh'); - $xmlWriter->writeAttribute('style:country-asian', 'CN'); - $xmlWriter->writeAttribute('style:font-name-complex', PhpWord::DEFAULT_FONT_NAME . '2'); - $xmlWriter->writeAttribute('style:font-size-complex', PhpWord::DEFAULT_FONT_SIZE . 'pt'); - $xmlWriter->writeAttribute('style:language-complex', 'hi'); - $xmlWriter->writeAttribute('style:country-complex', 'IN'); - $xmlWriter->writeAttribute('fo:hyphenate', 'false'); - $xmlWriter->writeAttribute('fo:hyphenation-remain-char-count', '2'); - $xmlWriter->writeAttribute('fo:hyphenation-push-char-count', '2'); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - // Write Style Definitions - $styles = Style::getStyles(); - if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { - if (preg_match('#^T[0-9]+$#', $styleName) == 0 - && preg_match('#^P[0-9]+$#', $styleName) == 0 - ) { - // PhpOffice\PhpWord\Style\Font - if ($style instanceof Font) { - // style:style - $xmlWriter->startElement('style:style'); - $xmlWriter->writeAttribute('style:name', $styleName); - $xmlWriter->writeAttribute('style:family', 'text'); - - // style:text-properties - $xmlWriter->startElement('style:text-properties'); - $xmlWriter->writeAttribute('fo:font-size', ($style->getSize()) . 'pt'); - $xmlWriter->writeAttribute('style:font-size-asian', ($style->getSize()) . 'pt'); - $xmlWriter->writeAttribute('style:font-size-complex', ($style->getSize()) . 'pt'); - if ($style->getItalic()) { - $xmlWriter->writeAttribute('fo:font-style', 'italic'); - $xmlWriter->writeAttribute('style:font-style-asian', 'italic'); - $xmlWriter->writeAttribute('style:font-style-complex', 'italic'); - } - if ($style->getBold()) { - $xmlWriter->writeAttribute('fo:font-weight', 'bold'); - $xmlWriter->writeAttribute('style:font-weight-asian', 'bold'); - } - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } elseif ($style instanceof Paragraph) { - // PhpOffice\PhpWord\Style\Paragraph - // style:style - $xmlWriter->startElement('style:style'); - $xmlWriter->writeAttribute('style:name', $styleName); - $xmlWriter->writeAttribute('style:family', 'paragraph'); - - //style:paragraph-properties - $xmlWriter->startElement('style:paragraph-properties'); - $xmlWriter->writeAttribute('fo:margin-top', ((is_null($style->getSpaceBefore())) ? '0' : round(17.6 / $style->getSpaceBefore(), 2)) . 'cm'); - $xmlWriter->writeAttribute('fo:margin-bottom', ((is_null($style->getSpaceAfter())) ? '0' : round(17.6 / $style->getSpaceAfter(), 2)) . 'cm'); - $xmlWriter->writeAttribute('fo:text-align', $style->getAlign()); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - } elseif ($style instanceof Table) { - // PhpOffice\PhpWord\Style\Table - } - } - } - } - $xmlWriter->endElement(); - - // office:automatic-styles - $xmlWriter->startElement('office:automatic-styles'); - // style:page-layout - $xmlWriter->startElement('style:page-layout'); - $xmlWriter->writeAttribute('style:name', 'Mpm1'); - // style:page-layout-properties - $xmlWriter->startElement('style:page-layout-properties'); - $xmlWriter->writeAttribute('fo:page-width', "21.001cm"); - $xmlWriter->writeAttribute('fo:page-height', '29.7cm'); - $xmlWriter->writeAttribute('style:num-format', '1'); - $xmlWriter->writeAttribute('style:print-orientation', 'portrait'); - $xmlWriter->writeAttribute('fo:margin-top', '2.501cm'); - $xmlWriter->writeAttribute('fo:margin-bottom', '2cm'); - $xmlWriter->writeAttribute('fo:margin-left', '2.501cm'); - $xmlWriter->writeAttribute('fo:margin-right', '2.501cm'); - $xmlWriter->writeAttribute('style:writing-mode', 'lr-tb'); - $xmlWriter->writeAttribute('style:layout-grid-color', '#c0c0c0'); - $xmlWriter->writeAttribute('style:layout-grid-lines', '25199'); - $xmlWriter->writeAttribute('style:layout-grid-base-height', '0.423cm'); - $xmlWriter->writeAttribute('style:layout-grid-ruby-height', '0cm'); - $xmlWriter->writeAttribute('style:layout-grid-mode', 'none'); - $xmlWriter->writeAttribute('style:layout-grid-ruby-below', 'false'); - $xmlWriter->writeAttribute('style:layout-grid-print', 'false'); - $xmlWriter->writeAttribute('style:layout-grid-display', 'false'); - $xmlWriter->writeAttribute('style:layout-grid-base-width', '0.37cm'); - $xmlWriter->writeAttribute('style:layout-grid-snap-to', 'true'); - $xmlWriter->writeAttribute('style:footnote-max-height', '0cm'); - //style:footnote-sep - $xmlWriter->startElement('style:footnote-sep'); - $xmlWriter->writeAttribute('style:width', '0.018cm'); - $xmlWriter->writeAttribute('style:line-style', 'solid'); - $xmlWriter->writeAttribute('style:adjustment', 'left'); - $xmlWriter->writeAttribute('style:rel-width', '25%'); - $xmlWriter->writeAttribute('style:color', '#000000'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - // style:header-style - $xmlWriter->startElement('style:header-style'); - $xmlWriter->endElement(); - // style:footer-style - $xmlWriter->startElement('style:footer-style'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - // office:master-styles - $xmlWriter->startElement('office:master-styles'); - // style:master-page - $xmlWriter->startElement('style:master-page'); - $xmlWriter->writeAttribute('style:name', 'Standard'); - $xmlWriter->writeAttribute('style:page-layout-name', 'Mpm1'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } -} diff --git a/src/PhpWord/Writer/ODText/WriterPart.php b/src/PhpWord/Writer/ODText/WriterPart.php deleted file mode 100644 index e61c758f..00000000 --- a/src/PhpWord/Writer/ODText/WriterPart.php +++ /dev/null @@ -1,67 +0,0 @@ -_parentWriter = $pWriter; - } - - /** - * Get parent IWriter object - * - * @return \PhpOffice\PhpWord\Writer\IWriter - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - public function getParentWriter() - { - if (!is_null($this->_parentWriter)) { - return $this->_parentWriter; - } else { - throw new Exception("No parent IWriter assigned."); - } - } -} diff --git a/src/PhpWord/Writer/PDF.php b/src/PhpWord/Writer/PDF.php new file mode 100644 index 00000000..7421e3e4 --- /dev/null +++ b/src/PhpWord/Writer/PDF.php @@ -0,0 +1,66 @@ +renderer = new $rendererName($phpWord); + } + + /** + * Magic method to handle direct calls to the configured PDF renderer wrapper class. + * + * @param string $name Renderer library method name + * @param mixed[] $arguments Array of arguments to pass to the renderer method + * @return mixed Returned data from the PDF renderer wrapper method + */ + public function __call($name, $arguments) + { + if ($this->renderer === null) { + throw new Exception("PDF Rendering library has not been defined."); + } + + return call_user_func_array(array($this->renderer, $name), $arguments); + } +} diff --git a/src/PhpWord/Writer/PDF/AbstractRenderer.php b/src/PhpWord/Writer/PDF/AbstractRenderer.php new file mode 100644 index 00000000..860a29dc --- /dev/null +++ b/src/PhpWord/Writer/PDF/AbstractRenderer.php @@ -0,0 +1,163 @@ + 'A4', // (210 mm by 297 mm) + ); + + /** + * Create new instance + * + * @param PhpWord $phpWord PhpWord object + */ + public function __construct(PhpWord $phpWord) + { + parent::__construct($phpWord); + } + + /** + * Get Font + * + * @return string + */ + public function getFont() + { + return $this->font; + } + + /** + * Set font. Examples: + * 'arialunicid0-chinese-simplified' + * 'arialunicid0-chinese-traditional' + * 'arialunicid0-korean' + * 'arialunicid0-japanese' + * + * @param string $fontName + */ + public function setFont($fontName) + { + $this->font = $fontName; + return $this; + } + + /** + * Get Paper Size + * + * @return int + */ + public function getPaperSize() + { + return $this->paperSize; + } + + /** + * Set Paper Size + * + * @param int $pValue Paper size = PAPERSIZE_A4 + * @return self + */ + public function setPaperSize($pValue = 9) + { + $this->paperSize = $pValue; + return $this; + } + + /** + * Get Orientation + * + * @return string + */ + public function getOrientation() + { + return $this->orientation; + } + + /** + * Set Orientation + * + * @param string $pValue Page orientation ORIENTATION_DEFAULT + * @return self + */ + public function setOrientation($pValue = 'default') + { + $this->orientation = $pValue; + return $this; + } + + /** + * Save PhpWord to PDF file, pre-save + * + * @param string $pFilename Name of the file to save as + * @return resource + */ + protected function prepareForSave($pFilename = null) + { + $fileHandle = fopen($pFilename, 'w'); + if ($fileHandle === false) { + throw new Exception("Could not open file $pFilename for writing."); + } + $this->isPdf = true; + + return $fileHandle; + } + + /** + * Save PhpWord to PDF file, post-save + * + * @param resource $fileHandle + * @throws Exception + */ + protected function restoreStateAfterSave($fileHandle) + { + fclose($fileHandle); + } +} diff --git a/src/PhpWord/Writer/PDF/DomPDF.php b/src/PhpWord/Writer/PDF/DomPDF.php new file mode 100644 index 00000000..d4c7b5f8 --- /dev/null +++ b/src/PhpWord/Writer/PDF/DomPDF.php @@ -0,0 +1,70 @@ +set_paper(strtolower($paperSize), $orientation); + + $pdf->load_html($this->writeDocument()); + $pdf->render(); + + // Write to file + fwrite($fileHandle, $pdf->output()); + + parent::restoreStateAfterSave($fileHandle); + } +} diff --git a/src/PhpWord/Writer/RTF.php b/src/PhpWord/Writer/RTF.php old mode 100755 new mode 100644 index 81f8e0eb..dca6bc1f --- a/src/PhpWord/Writer/RTF.php +++ b/src/PhpWord/Writer/RTF.php @@ -2,87 +2,48 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Exceptions\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\HashTable; -use PhpOffice\PhpWord\Section\Image; -use PhpOffice\PhpWord\Section\Link; -use PhpOffice\PhpWord\Section\ListItem; -use PhpOffice\PhpWord\Section\Object; -use PhpOffice\PhpWord\Section\PageBreak; -use PhpOffice\PhpWord\Section\Table; -use PhpOffice\PhpWord\Section\Text; -use PhpOffice\PhpWord\Section\TextBreak; -use PhpOffice\PhpWord\Section\TextRun; -use PhpOffice\PhpWord\Section\Title; -use PhpOffice\PhpWord\Shared\Drawing; use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Element\Text; +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\Drawing; use PhpOffice\PhpWord\Style\Font; -use PhpOffice\PhpWord\Style\Paragraph; -use PhpOffice\PhpWord\TOC; +use PhpOffice\PhpWord\Writer\RTF\Element\Element as ElementWriter; /** * RTF writer + * + * @since 0.7.0 */ -class RTF implements IWriter +class RTF extends AbstractWriter implements WriterInterface { - /** - * Private PhpWord - * - * @var \PhpOffice\PhpWord\PhpWord - */ - private $_document; - - /** - * Private unique PHPWord_Worksheet_BaseDrawing HashTable - * - * @var \PhpOffice\PhpWord\HashTable - */ - private $_drawingHashTable; - /** * Color register * * @var array */ - private $_colorTable; + private $colorTable; /** * Font register * * @var array */ - private $_fontTable; + private $fontTable; /** * Last paragraph style * * @var mixed */ - private $_lastParagraphStyle; + private $lastParagraphStyle; /** * Create new RTF writer @@ -92,81 +53,64 @@ class RTF implements IWriter { // Assign PhpWord $this->setPhpWord($phpWord); - - // Set HashTable variables - $this->_drawingHashTable = new HashTable(); } /** * Save PhpWord to file * * @param string $pFilename - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * @throws \PhpOffice\PhpWord\Exception\Exception */ public function save($pFilename = null) { - if (!is_null($this->_document)) { - // 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; - } + if (!is_null($this->phpWord)) { + $pFilename = $this->getTempFile($pFilename); + + $hFile = fopen($pFilename, 'w'); + if ($hFile !== false) { + fwrite($hFile, $this->writeDocument()); + fclose($hFile); + } else { + throw new Exception("Can't open file"); } - - $hFile = fopen($pFilename, 'w') or die("can't open file"); - fwrite($hFile, $this->getData()); - fclose($hFile); - - // 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); - } - + $this->cleanupTempFile(); } else { throw new Exception("PhpWord object unassigned."); } } /** - * Get PhpWord object - * - * @return \PhpOffice\PhpWord\PhpWord - * @throws \PhpOffice\PhpWord\Exceptions\Exception + * Get color table */ - public function getPhpWord() + public function getColorTable() { - if (!is_null($this->_document)) { - return $this->_document; - } else { - throw new Exception("No PhpWord assigned."); - } + return $this->colorTable; } /** - * Set PhpWord object - * - * @param \PhpOffice\PhpWord\PhpWord $phpWord - * @return \PhpOffice\PhpWord\Writer\RTF + * Get font table */ - public function setPhpWord(PhpWord $phpWord = null) + public function getFontTable() { - $this->_document = $phpWord; - return $this; + return $this->fontTable; } /** - * Get PHPWord_Worksheet_BaseDrawing HashTable - * - * @return \PhpOffice\PhpWord\HashTable + * Get last paragraph style */ - public function getDrawingHashTable() + public function getLastParagraphStyle() { - return $this->_drawingHashTable; + return $this->lastParagraphStyle; + } + + /** + * Set last paragraph style + * + * @param mixed $value + */ + public function setLastParagraphStyle($value = '') + { + $this->lastParagraphStyle = $value; } /** @@ -174,79 +118,97 @@ class RTF implements IWriter * * @return string */ - private function getData() + private function writeDocument() { - // PhpWord object : $this->_document - $this->_fontTable = $this->getDataFont(); - $this->_colorTable = $this->getDataColor(); + $this->fontTable = $this->populateFontTable(); + $this->colorTable = $this->populateColorTable(); - $sRTFContent = '{\rtf1'; // Set the default character set - $sRTFContent .= '\ansi\ansicpg1252'; - // Set the default font (the first one) - $sRTFContent .= '\deff0'; - // Set the default tab size (720 twips) + $sRTFContent = '{\rtf1'; + $sRTFContent .= '\ansi\ansicpg1252'; // Set the default font (the first one) + $sRTFContent .= '\deff0'; // Set the default tab size (720 twips) $sRTFContent .= '\deftab720'; - $sRTFContent .= \PHP_EOL; + $sRTFContent .= PHP_EOL; + // Set the font tbl group $sRTFContent .= '{\fonttbl'; - foreach ($this->_fontTable as $idx => $font) { + foreach ($this->fontTable as $idx => $font) { $sRTFContent .= '{\f' . $idx . '\fnil\fcharset0 ' . $font . ';}'; } - $sRTFContent .= '}' . \PHP_EOL; + $sRTFContent .= '}' . PHP_EOL; + // Set the color tbl group $sRTFContent .= '{\colortbl '; - foreach ($this->_colorTable as $idx => $color) { + foreach ($this->colorTable as $idx => $color) { $arrColor = Drawing::htmlToRGB($color); $sRTFContent .= ';\red' . $arrColor[0] . '\green' . $arrColor[1] . '\blue' . $arrColor[2] . ''; } - $sRTFContent .= ';}' . \PHP_EOL; - // Set the generator - $sRTFContent .= '{\*\generator PhpWord;}' . \PHP_EOL; - // Set the view mode of the document - $sRTFContent .= '\viewkind4'; - // Set the numberof bytes that follows a unicode character - $sRTFContent .= '\uc1'; - // Resets to default paragraph properties. - $sRTFContent .= '\pard'; - // No widow/orphan control - $sRTFContent .= '\nowidctlpar'; - // Applies a language to a text run (1036 : French (France)) - $sRTFContent .= '\lang1036'; - // Point size (in half-points) above which to kern character pairs - $sRTFContent .= '\kerning1'; - // Set the font size in half-points - $sRTFContent .= '\fs' . (PhpWord::DEFAULT_FONT_SIZE * 2); - $sRTFContent .= \PHP_EOL; - // Body - $sRTFContent .= $this->getDataContent(); + $sRTFContent .= ';}' . PHP_EOL; + $sRTFContent .= '{\*\generator PhpWord;}' . PHP_EOL; // Set the generator + $sRTFContent .= '\viewkind4'; // Set the view mode of the document + $sRTFContent .= '\uc1'; // Set the numberof bytes that follows a unicode character + $sRTFContent .= '\pard'; // Resets to default paragraph properties. + $sRTFContent .= '\nowidctlpar'; // No widow/orphan control + $sRTFContent .= '\lang1036'; // Applies a language to a text run (1036 : French (France)) + $sRTFContent .= '\kerning1'; // Point size (in half-points) above which to kern character pairs + $sRTFContent .= '\fs' . (PhpWord::DEFAULT_FONT_SIZE * 2); // Set the font size in half-points + $sRTFContent .= PHP_EOL; + + // Body + $sRTFContent .= $this->writeContent(); $sRTFContent .= '}'; return $sRTFContent; } + /** + * Get content data + * + * @return string + */ + private function writeContent() + { + $phpWord = $this->phpWord; + $sRTFBody = ''; + + $sections = $phpWord->getSections(); + $countSections = count($sections); + $pSection = 0; + + if ($countSections > 0) { + foreach ($sections as $section) { + $pSection++; + $elements = $section->getElements(); + foreach ($elements as $element) { + $elementWriter = new ElementWriter($this, $element); + $sRTFBody .= $elementWriter->write(); + } + } + } + return $sRTFBody; + } + /** * Get all fonts * * @return array */ - private function getDataFont() + private function populateFontTable() { - $phpWord = $this->_document; + $phpWord = $this->phpWord; $arrFonts = array(); // Default font : PhpWord::DEFAULT_FONT_NAME $arrFonts[] = PhpWord::DEFAULT_FONT_NAME; - // PhpWord object : $this->_document + // PhpWord object : $this->phpWord // Browse styles $styles = Style::getStyles(); - $numPStyles = 0; if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { - // PhpOffice\PhpWord\Style\Font + foreach ($styles as $style) { + // Font if ($style instanceof Font) { if (in_array($style->getName(), $arrFonts) == false) { $arrFonts[] = $style->getName(); @@ -256,22 +218,22 @@ class RTF implements IWriter } // Search all fonts used - $_sections = $phpWord->getSections(); - $countSections = count($_sections); + $sections = $phpWord->getSections(); + $countSections = count($sections); if ($countSections > 0) { $pSection = 0; - foreach ($_sections as $section) { + foreach ($sections as $section) { $pSection++; - $_elements = $section->getElements(); + $elements = $section->getElements(); - foreach ($_elements as $element) { + foreach ($elements as $element) { if ($element instanceof Text) { - $fStyle = $element->getFontStyle(); + $fontStyle = $element->getFontStyle(); - if ($fStyle instanceof Font) { - if (in_array($fStyle->getName(), $arrFonts) == false) { - $arrFonts[] = $fStyle->getName(); + if ($fontStyle instanceof Font) { + if (in_array($fontStyle->getName(), $arrFonts) == false) { + $arrFonts[] = $fontStyle->getName(); } } } @@ -287,18 +249,17 @@ class RTF implements IWriter * * @return array */ - private function getDataColor() + private function populateColorTable() { - $phpWord = $this->_document; + $phpWord = $this->phpWord; $arrColors = array(); - // PhpWord object : $this->_document + // PhpWord object : $this->phpWord // Browse styles $styles = Style::getStyles(); - $numPStyles = 0; if (count($styles) > 0) { - foreach ($styles as $styleName => $style) { + foreach ($styles as $style) { // Font if ($style instanceof Font) { $color = $style->getColor(); @@ -314,25 +275,25 @@ class RTF implements IWriter } // Search all fonts used - $_sections = $phpWord->getSections(); - $countSections = count($_sections); + $sections = $phpWord->getSections(); + $countSections = count($sections); if ($countSections > 0) { $pSection = 0; - foreach ($_sections as $section) { + foreach ($sections as $section) { $pSection++; - $_elements = $section->getElements(); + $elements = $section->getElements(); - foreach ($_elements as $element) { + foreach ($elements as $element) { if ($element instanceof Text) { - $fStyle = $element->getFontStyle(); + $fontStyle = $element->getFontStyle(); - if ($fStyle instanceof Font) { - if (in_array($fStyle->getColor(), $arrColors) == false) { - $arrColors[] = $fStyle->getColor(); + if ($fontStyle instanceof Font) { + if (in_array($fontStyle->getColor(), $arrColors) == false) { + $arrColors[] = $fontStyle->getColor(); } - if (in_array($fStyle->getFgColor(), $arrColors) == false) { - $arrColors[] = $fStyle->getFgColor(); + if (in_array($fontStyle->getFgColor(), $arrColors) == false) { + $arrColors[] = $fontStyle->getFgColor(); } } } @@ -342,198 +303,4 @@ class RTF implements IWriter return $arrColors; } - - /** - * Get content data - * - * @return string - */ - private function getDataContent() - { - $phpWord = $this->_document; - $sRTFBody = ''; - - $_sections = $phpWord->getSections(); - $countSections = count($_sections); - $pSection = 0; - - if ($countSections > 0) { - foreach ($_sections as $section) { - $pSection++; - $_elements = $section->getElements(); - foreach ($_elements as $element) { - if ($element instanceof Text) { - $sRTFBody .= $this->getDataContentText($element); - } elseif ($element instanceof TextBreak) { - $sRTFBody .= $this->getDataContentTextBreak(); - } elseif ($element instanceof TextRun) { - $sRTFBody .= $this->getDataContentTextRun($element); - } elseif ($element instanceof Link) { - $sRTFBody .= $this->getDataContentUnsupportedElement('Link'); - } elseif ($element instanceof Title) { - $sRTFBody .= $this->getDataContentUnsupportedElement('Title'); - } elseif ($element instanceof PageBreak) { - $sRTFBody .= $this->getDataContentUnsupportedElement('Page Break'); - } elseif ($element instanceof Table) { - $sRTFBody .= $this->getDataContentUnsupportedElement('Table'); - } elseif ($element instanceof ListItem) { - $sRTFBody .= $this->getDataContentUnsupportedElement('List Item'); - } elseif ($element instanceof Image) { - $sRTFBody .= $this->getDataContentUnsupportedElement('Image'); - } elseif ($element instanceof Object) { - $sRTFBody .= $this->getDataContentUnsupportedElement('Object'); - } elseif ($element instanceof TOC) { - $sRTFBody .= $this->getDataContentUnsupportedElement('TOC'); - } else { - $sRTFBody .= $this->getDataContentUnsupportedElement('Other'); - } - } - } - } - return $sRTFBody; - } - - /** - * Get text element content - * - * @param boolean $withoutP - * @return string - */ - private function getDataContentText(Text $text, $withoutP = false) - { - $sRTFText = ''; - - $styleFont = $text->getFontStyle(); - $SfIsObject = ($styleFont instanceof Font) ? true : false; - if (!$SfIsObject) { - $styleFont = Style::getStyle($styleFont); - } - - $styleParagraph = $text->getParagraphStyle(); - $SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - if (!$SpIsObject) { - $styleParagraph = Style::getStyle($styleParagraph); - } - - if ($styleParagraph && !$withoutP) { - if ($this->_lastParagraphStyle != $text->getParagraphStyle()) { - $sRTFText .= '\pard\nowidctlpar'; - if ($styleParagraph->getSpaceAfter() != null) { - $sRTFText .= '\sa' . $styleParagraph->getSpaceAfter(); - } - if ($styleParagraph->getAlign() != null) { - if ($styleParagraph->getAlign() == 'center') { - $sRTFText .= '\qc'; - } - } - $this->_lastParagraphStyle = $text->getParagraphStyle(); - } else { - $this->_lastParagraphStyle = ''; - } - } else { - $this->_lastParagraphStyle = ''; - } - - if ($styleFont instanceof Font) { - if ($styleFont->getColor() != null) { - $idxColor = array_search($styleFont->getColor(), $this->_colorTable); - if ($idxColor !== false) { - $sRTFText .= '\cf' . ($idxColor + 1); - } - } else { - $sRTFText .= '\cf0'; - } - if ($styleFont->getName() != null) { - $idxFont = array_search($styleFont->getName(), $this->_fontTable); - if ($idxFont !== false) { - $sRTFText .= '\f' . $idxFont; - } - } else { - $sRTFText .= '\f0'; - } - if ($styleFont->getBold()) { - $sRTFText .= '\b'; - } - if ($styleFont->getBold()) { - $sRTFText .= '\i'; - } - if ($styleFont->getSize()) { - $sRTFText .= '\fs' . ($styleFont->getSize() * 2); - } - } - if ($this->_lastParagraphStyle != '' || $styleFont) { - $sRTFText .= ' '; - } - $sRTFText .= $text->getText(); - - if ($styleFont instanceof Font) { - $sRTFText .= '\cf0'; - $sRTFText .= '\f0'; - - if ($styleFont->getBold()) { - $sRTFText .= '\b0'; - } - if ($styleFont->getItalic()) { - $sRTFText .= '\i0'; - } - if ($styleFont->getSize()) { - $sRTFText .= '\fs' . (PhpWord::DEFAULT_FONT_SIZE * 2); - } - } - - if (!$withoutP) { - $sRTFText .= '\par' . \PHP_EOL; - } - return $sRTFText; - } - - /** - * Get textrun content - * - * @return string - */ - private function getDataContentTextRun(TextRun $textrun) - { - $sRTFText = ''; - $elements = $textrun->getElements(); - if (count($elements) > 0) { - $sRTFText .= '\pard\nowidctlpar' . \PHP_EOL; - foreach ($elements as $element) { - if ($element instanceof Text) { - $sRTFText .= '{'; - $sRTFText .= $this->getDataContentText($element, true); - $sRTFText .= '}' . \PHP_EOL; - } - } - $sRTFText .= '\par' . \PHP_EOL; - } - return $sRTFText; - } - - /** - * Get text break content - * - * @return string - */ - private function getDataContentTextBreak() - { - $this->_lastParagraphStyle = ''; - - return '\par' . \PHP_EOL; - } - - /** - * Get unsupported element content - * - * @param string $element - */ - private function getDataContentUnsupportedElement($element) - { - $sRTFText = ''; - $sRTFText .= '\pard\nowidctlpar' . \PHP_EOL; - $sRTFText .= "{$element}"; - $sRTFText .= '\par' . \PHP_EOL; - - return $sRTFText; - } } diff --git a/src/PhpWord/Writer/RTF/Element/Element.php b/src/PhpWord/Writer/RTF/Element/Element.php new file mode 100644 index 00000000..9bb3b5d9 --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/Element.php @@ -0,0 +1,72 @@ +parentWriter = $parentWriter; + $this->element = $element; + $this->withoutP = $withoutP; + } + + /** + * Write element + * + * @return string + */ + public function write() + { + $rtfText = ''; + $elmName = str_replace('PhpOffice\\PhpWord\\Element\\', '', get_class($this->element)); + $elmWriterClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Element\\' . $elmName; + if (class_exists($elmWriterClass) === true) { + $elmWriter = new $elmWriterClass($this->parentWriter, $this->element, $this->withoutP); + $rtfText = $elmWriter->write(); + } + + return $rtfText; + } +} diff --git a/src/PhpWord/Writer/RTF/Element/Text.php b/src/PhpWord/Writer/RTF/Element/Text.php new file mode 100644 index 00000000..2ee110e0 --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/Text.php @@ -0,0 +1,111 @@ +element->getFontStyle(); + if (is_string($fontStyle)) { + $fontStyle = Style::getStyle($fontStyle); + } + + $paragraphStyle = $this->element->getParagraphStyle(); + if (is_string($paragraphStyle)) { + $paragraphStyle = Style::getStyle($paragraphStyle); + } + + if ($paragraphStyle && !$this->withoutP) { + if ($this->parentWriter->getLastParagraphStyle() != $this->element->getParagraphStyle()) { + $rtfText .= '\pard\nowidctlpar'; + if ($paragraphStyle->getSpaceAfter() != null) { + $rtfText .= '\sa' . $paragraphStyle->getSpaceAfter(); + } + if ($paragraphStyle->getAlign() != null) { + if ($paragraphStyle->getAlign() == 'center') { + $rtfText .= '\qc'; + } + } + $this->parentWriter->setLastParagraphStyle($this->element->getParagraphStyle()); + } else { + $this->parentWriter->setLastParagraphStyle(); + } + } else { + $this->parentWriter->setLastParagraphStyle(); + } + + if ($fontStyle instanceof Font) { + if ($fontStyle->getColor() != null) { + $idxColor = array_search($fontStyle->getColor(), $this->parentWriter->getColorTable()); + if ($idxColor !== false) { + $rtfText .= '\cf' . ($idxColor + 1); + } + } else { + $rtfText .= '\cf0'; + } + if ($fontStyle->getName() != null) { + $idxFont = array_search($fontStyle->getName(), $this->parentWriter->getFontTable()); + if ($idxFont !== false) { + $rtfText .= '\f' . $idxFont; + } + } else { + $rtfText .= '\f0'; + } + if ($fontStyle->getBold()) { + $rtfText .= '\b'; + } + if ($fontStyle->getItalic()) { + $rtfText .= '\i'; + } + if ($fontStyle->getSize()) { + $rtfText .= '\fs' . ($fontStyle->getSize() * 2); + } + } + if ($this->parentWriter->getLastParagraphStyle() != '' || $fontStyle) { + $rtfText .= ' '; + } + $rtfText .= $this->element->getText(); + + if ($fontStyle instanceof Font) { + $rtfText .= '\cf0'; + $rtfText .= '\f0'; + + if ($fontStyle->getBold()) { + $rtfText .= '\b0'; + } + if ($fontStyle->getItalic()) { + $rtfText .= '\i0'; + } + if ($fontStyle->getSize()) { + $rtfText .= '\fs' . (PhpWord::DEFAULT_FONT_SIZE * 2); + } + } + + if (!$this->withoutP) { + $rtfText .= '\par' . PHP_EOL; + } + return $rtfText; + } +} diff --git a/src/PhpWord/Writer/RTF/Element/TextBreak.php b/src/PhpWord/Writer/RTF/Element/TextBreak.php new file mode 100644 index 00000000..91ae706d --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/TextBreak.php @@ -0,0 +1,30 @@ +parentWriter->setLastParagraphStyle(); + + return '\par' . PHP_EOL; + } +} diff --git a/src/PhpWord/Writer/RTF/Element/TextRun.php b/src/PhpWord/Writer/RTF/Element/TextRun.php new file mode 100644 index 00000000..86c30f4b --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/TextRun.php @@ -0,0 +1,45 @@ +element->getElements(); + if (count($elements) > 0) { + $rtfText .= '\pard\nowidctlpar' . PHP_EOL; + foreach ($elements as $element) { + if ($element instanceof TextElement) { + $elementWriter = new Element($this->parentWriter, $element, true); + $rtfText .= '{'; + $rtfText .= $elementWriter->write(); + $rtfText .= '}' . PHP_EOL; + } + } + $rtfText .= '\par' . PHP_EOL; + } + + return $rtfText; + } +} diff --git a/src/PhpWord/Writer/RTF/Element/Title.php b/src/PhpWord/Writer/RTF/Element/Title.php new file mode 100644 index 00000000..61a40032 --- /dev/null +++ b/src/PhpWord/Writer/RTF/Element/Title.php @@ -0,0 +1,33 @@ +element->getText(); + $rtfText .= '\par' . PHP_EOL; + + return $rtfText; + } +} diff --git a/src/PhpWord/Writer/Word2007.php b/src/PhpWord/Writer/Word2007.php old mode 100755 new mode 100644 index fcd562ab..b87f1d24 --- a/src/PhpWord/Writer/Word2007.php +++ b/src/PhpWord/Writer/Word2007.php @@ -2,382 +2,228 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ namespace PhpOffice\PhpWord\Writer; -use PhpOffice\PhpWord\Exceptions\Exception; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Footnote; use PhpOffice\PhpWord\Media; -use PhpOffice\PhpWord\Writer\Word2007\ContentTypes; -use PhpOffice\PhpWord\Writer\Word2007\DocProps; -use PhpOffice\PhpWord\Writer\Word2007\Document; -use PhpOffice\PhpWord\Writer\Word2007\DocumentRels; -use PhpOffice\PhpWord\Writer\Word2007\Footer; -use PhpOffice\PhpWord\Writer\Word2007\Footnotes; -use PhpOffice\PhpWord\Writer\Word2007\FootnotesRels; -use PhpOffice\PhpWord\Writer\Word2007\Header; -use PhpOffice\PhpWord\Writer\Word2007\Rels; -use PhpOffice\PhpWord\Writer\Word2007\Styles; +use PhpOffice\PhpWord\Element\Section; +use PhpOffice\PhpWord\Exception\Exception; /** * Word2007 writer */ -class Word2007 implements IWriter +class Word2007 extends AbstractWriter implements WriterInterface { /** - * PHPWord object - * - * @var PhpOffice\PhpWord\PhpWord - */ - private $_document; - - /** - * Individual writers - * - * @var PhpOffice\PhpWord\Writer\Word2007\WriterPart - */ - private $_writerParts; - - /** - * Disk caching directory - * - * @var string - */ - private $_diskCachingDirectory; - - /** - * Use disk caching - * - * @var boolean - */ - private $_useDiskCaching = false; - - /** - * Types of images + * Content types values * * @var array */ - private $_imageTypes = array(); + private $cTypes = array('default' => array(), 'override' => array()); /** - * Types of objects + * Document relationship * * @var array */ - private $_objectTypes = array(); + private $docRels = array(); /** * Create new Word2007 writer * - * @param PhpOffice\PhpWord\PhpWord + * @param \PhpOffice\PhpWord\PhpWord */ public function __construct(PhpWord $phpWord = null) { - $this->_document = $phpWord; + // Assign PhpWord + $this->setPhpWord($phpWord); - $this->_diskCachingDirectory = './'; - - $this->_writerParts['contenttypes'] = new ContentTypes(); - $this->_writerParts['rels'] = new Rels(); - $this->_writerParts['docprops'] = new DocProps(); - $this->_writerParts['documentrels'] = new DocumentRels(); - $this->_writerParts['document'] = new Document(); - $this->_writerParts['styles'] = new Styles(); - $this->_writerParts['header'] = new Header(); - $this->_writerParts['footer'] = new Footer(); - $this->_writerParts['footnotes'] = new Footnotes(); - $this->_writerParts['footnotesrels'] = new FootnotesRels(); - - foreach ($this->_writerParts as $writer) { - $writer->setParentWriter($this); + // Create parts + $parts = array('ContentTypes', 'Rels', 'DocProps', 'Document', 'Styles', + 'Numbering', 'Settings', 'WebSettings', 'Header', 'Footer', 'Footnotes', + 'Endnotes', 'FontTable', 'Theme'); + foreach ($parts as $part) { + $partName = strtolower($part); + $partClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\' . $part; + if (class_exists($partClass)) { + $partObject = new $partClass(); + $partObject->setParentWriter($this); + $this->writerParts[$partName] = $partObject; + } } + + // Set package paths + $this->mediaPaths = array('image' => 'word/media/', 'object' => 'word/embeddings/'); } /** * Save document by name * - * @param string $pFilename + * @param string $filename */ - public function save($pFilename = null) + public function save($filename = null) { - if (!is_null($this->_document)) { + if (!is_null($this->phpWord)) { + $filename = $this->getTempFile($filename); + $objZip = $this->getZipArchive($filename); - // 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 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."); - } - } - - - $sectionElements = array(); - $_secElements = Media::getSectionMediaElements(); - foreach ($_secElements as $element) { // loop through section media elements - if ($element['type'] != 'hyperlink') { - $this->_addFileToPackage($objZip, $element); - } - $sectionElements[] = $element; - } - - $_hdrElements = Media::getHeaderMediaElements(); - foreach ($_hdrElements as $_headerFile => $_hdrMedia) { // loop through headers - if (count($_hdrMedia) > 0) { - $objZip->addFromString('word/_rels/' . $_headerFile . '.xml.rels', $this->getWriterPart('documentrels')->writeHeaderFooterRels($_hdrMedia)); - foreach ($_hdrMedia as $element) { // loop through header media elements - $this->_addFileToPackage($objZip, $element); - } - } - } - - $_ftrElements = Media::getFooterMediaElements(); - foreach ($_ftrElements as $_footerFile => $_ftrMedia) { // loop through footers - if (count($_ftrMedia) > 0) { - $objZip->addFromString('word/_rels/' . $_footerFile . '.xml.rels', $this->getWriterPart('documentrels')->writeHeaderFooterRels($_ftrMedia)); - foreach ($_ftrMedia as $element) { // loop through footers media elements - $this->_addFileToPackage($objZip, $element); - } - } - } - - $footnoteLinks = array(); - $_footnoteElements = Footnote::getFootnoteLinkElements(); - // loop through footnote link elements - foreach ($_footnoteElements as $element) { - $footnoteLinks[] = $element; - } - - $_cHdrs = 0; - $_cFtrs = 0; - $rID = Media::countSectionMediaElements() + 6; - $_sections = $this->_document->getSections(); - - $footers = array(); - foreach ($_sections as $section) { - $_headers = $section->getHeaders(); - foreach ($_headers as $index => &$_header) { - $_cHdrs++; - $_header->setRelationId(++$rID); - $_headerFile = 'header' . $_cHdrs . '.xml'; - $sectionElements[] = array('target' => $_headerFile, 'type' => 'header', 'rID' => $rID); - $objZip->addFromString('word/' . $_headerFile, $this->getWriterPart('header')->writeHeader($_header)); - } - - $_footer = $section->getFooter(); - $footers[++$_cFtrs] = $_footer; - if (!is_null($_footer)) { - $_footer->setRelationId(++$rID); - $_footerCount = $_footer->getFooterCount(); - $_footerFile = 'footer' . $_footerCount . '.xml'; - $sectionElements[] = array('target' => $_footerFile, 'type' => 'footer', 'rID' => $rID); - $objZip->addFromString('word/' . $_footerFile, $this->getWriterPart('footer')->writeFooter($_footer)); - } - } - - if (Footnote::countFootnoteElements() > 0) { - $_allFootnotesCollection = Footnote::getFootnoteElements(); - $_footnoteFile = 'footnotes.xml'; - $sectionElements[] = array('target'=>$_footnoteFile, 'type'=>'footnotes', 'rID'=>++$rID); - $objZip->addFromString('word/'.$_footnoteFile, $this->getWriterPart('footnotes')->writeFootnotes($_allFootnotesCollection)); - if (count($footnoteLinks) > 0) { - $objZip->addFromString('word/_rels/footnotes.xml.rels', $this->getWriterPart('footnotesrels')->writeFootnotesRels($footnoteLinks)); - } - } - - // build docx file - // Write dynamic files - $objZip->addFromString( - '[Content_Types].xml', - $this->getWriterPart('contenttypes')->writeContentTypes( - $this->_imageTypes, - $this->_objectTypes, - $_cHdrs, - $footers - ) + // Content types + $this->cTypes['default'] = array( + 'rels' => 'application/vnd.openxmlformats-package.relationships+xml', + 'xml' => 'application/xml', ); - $objZip->addFromString('_rels/.rels', $this->getWriterPart('rels')->writeRelationships($this->_document)); - $objZip->addFromString('docProps/app.xml', $this->getWriterPart('docprops')->writeDocPropsApp($this->_document)); - $objZip->addFromString('docProps/core.xml', $this->getWriterPart('docprops')->writeDocPropsCore($this->_document)); - $objZip->addFromString('word/document.xml', $this->getWriterPart('document')->writeDocument($this->_document)); - $objZip->addFromString('word/_rels/document.xml.rels', $this->getWriterPart('documentrels')->writeDocumentRels($sectionElements)); - $objZip->addFromString('word/styles.xml', $this->getWriterPart('styles')->writeStyles($this->_document)); - // Write static files - $objZip->addFile(__DIR__ . '/../_staticDocParts/numbering.xml', 'word/numbering.xml'); - $objZip->addFile(__DIR__ . '/../_staticDocParts/settings.xml', 'word/settings.xml'); - $objZip->addFile(__DIR__ . '/../_staticDocParts/theme1.xml', 'word/theme/theme1.xml'); - $objZip->addFile(__DIR__ . '/../_staticDocParts/webSettings.xml', 'word/webSettings.xml'); - $objZip->addFile(__DIR__ . '/../_staticDocParts/fontTable.xml', 'word/fontTable.xml'); + // Add section media files + $sectionMedia = Media::getElements('section'); + if (!empty($sectionMedia)) { + $this->addFilesToPackage($objZip, $sectionMedia); + $this->registerContentTypes($sectionMedia); + foreach ($sectionMedia as $element) { + $this->docRels[] = $element; + } + } + // Add header/footer media files & relations + $this->addHeaderFooterMedia($objZip, 'header'); + $this->addHeaderFooterMedia($objZip, 'footer'); + + // Add header/footer contents + $rId = Media::countElements('section') + 6; // @see Rels::writeDocRels for 6 first elements + $sections = $this->phpWord->getSections(); + foreach ($sections as $section) { + $this->addHeaderFooterContent($section, $objZip, 'header', $rId); + $this->addHeaderFooterContent($section, $objZip, 'footer', $rId); + } + + $this->addNotes($objZip, $rId, 'footnote'); + $this->addNotes($objZip, $rId, 'endnote'); + + // Write parts + $objZip->addFromString('[Content_Types].xml', $this->getWriterPart('contenttypes')->writeContentTypes($this->cTypes)); + $objZip->addFromString('_rels/.rels', $this->getWriterPart('rels')->writeMainRels()); + $objZip->addFromString('docProps/app.xml', $this->getWriterPart('docprops')->writeDocPropsApp($this->phpWord)); + $objZip->addFromString('docProps/core.xml', $this->getWriterPart('docprops')->writeDocPropsCore($this->phpWord)); + $objZip->addFromString('word/_rels/document.xml.rels', $this->getWriterPart('rels')->writeDocRels($this->docRels)); + $objZip->addFromString('word/document.xml', $this->getWriterPart('document')->writeDocument($this->phpWord)); + $objZip->addFromString('word/styles.xml', $this->getWriterPart('styles')->writeStyles($this->phpWord)); + $objZip->addFromString('word/numbering.xml', $this->getWriterPart('numbering')->writeNumbering()); + $objZip->addFromString('word/settings.xml', $this->getWriterPart('settings')->writeSettings()); + $objZip->addFromString('word/webSettings.xml', $this->getWriterPart('websettings')->writeWebSettings()); + $objZip->addFromString('word/fontTable.xml', $this->getWriterPart('fonttable')->write()); + $objZip->addFromString('word/theme/theme1.xml', $this->getWriterPart('theme')->write()); // Close file if ($objZip->close() === false) { - throw new Exception("Could not close zip file $pFilename."); + throw new Exception("Could not close zip file $filename."); } - // 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); - } + $this->cleanupTempFile(); } else { throw new Exception("PhpWord object unassigned."); } } /** - * Check content types - * - * @param string $src - */ - private function checkContentTypes($src) - { - $extension = null; - if (stripos(strrev($src), strrev('.php')) === 0) { - $extension = 'php'; - } else { - $imageType = exif_imagetype($src); - if ($imageType === \IMAGETYPE_JPEG) { - $extension = 'jpg'; - } elseif ($imageType === \IMAGETYPE_GIF) { - $extension = 'gif'; - } elseif ($imageType === \IMAGETYPE_PNG) { - $extension = 'png'; - } elseif ($imageType === \IMAGETYPE_BMP) { - $extension = 'bmp'; - } elseif ($imageType === \IMAGETYPE_TIFF_II || $imageType === \IMAGETYPE_TIFF_MM) { - $extension = 'tif'; - } - } - - if (isset($extension)) { - $imageData = getimagesize($src); - $imageType = image_type_to_mime_type($imageData[2]); - $imageExtension = str_replace('.', '', image_type_to_extension($imageData[2])); - if ($imageExtension === 'jpeg') { - $imageExtension = 'jpg'; - } - if (!in_array($imageType, $this->_imageTypes)) { - $this->_imageTypes[$imageExtension] = $imageType; - } - } else { - if (!in_array($extension, $this->_objectTypes)) { - $this->_objectTypes[] = $extension; - } - } - } - - /** - * Get writer part - * - * @param string $pPartName Writer part name - * @return \PhpOffice\PhpWord\Writer\ODText\WriterPart - */ - public function getWriterPart($pPartName = '') - { - if ($pPartName != '' && isset($this->_writerParts[strtolower($pPartName)])) { - return $this->_writerParts[strtolower($pPartName)]; - } else { - return null; - } - } - - /** - * Get use disk caching status - * - * @return boolean - */ - public function getUseDiskCaching() - { - return $this->_useDiskCaching; - } - - /** - * Set use disk caching status - * - * @param boolean $pValue - * @param string $pDirectory - */ - 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; - } - - /** - * Check content types + * Add header/footer media files * * @param mixed $objZip - * @param mixed $element + * @param string $docPart */ - private function _addFileToPackage($objZip, $element) + private function addHeaderFooterMedia($objZip, $docPart) { - if (isset($element['isMemImage']) && $element['isMemImage']) { - $image = call_user_func($element['createfunction'], $element['source']); - ob_start(); - call_user_func($element['imagefunction'], $image); - $imageContents = ob_get_contents(); - ob_end_clean(); - $objZip->addFromString('word/' . $element['target'], $imageContents); - imagedestroy($image); + $elements = Media::getElements($docPart); + if (!empty($elements)) { + foreach ($elements as $file => $media) { + if (count($media) > 0) { + if (!empty($media)) { + $this->addFilesToPackage($objZip, $media); + $this->registerContentTypes($media); + } + $relsFile = "word/_rels/{$file}.xml.rels"; + $objZip->addFromString($relsFile, $this->getWriterPart('rels')->writeMediaRels($media)); + } + } + } + } - $this->checkContentTypes($element['source']); - } else { - $objZip->addFile($element['source'], 'word/' . $element['target']); - $this->checkContentTypes($element['source']); + /** + * Add header/footer content + * + * @param mixed $objZip + * @param string $elmType + * @param integer $rId + */ + private function addHeaderFooterContent(Section &$section, $objZip, $elmType, &$rId) + { + $getFunction = $elmType == 'header' ? 'getHeaders' : 'getFooters'; + $writeFunction = $elmType == 'header' ? 'writeHeader' : 'writeFooter'; + $elmCount = ($section->getSectionId() - 1) * 3; + $elmObjects = $section->$getFunction(); + foreach ($elmObjects as &$elmObject) { + $elmCount++; + $elmObject->setRelationId(++$rId); + $elmFile = "{$elmType}{$elmCount}.xml"; + $objZip->addFromString("word/$elmFile", $this->getWriterPart($elmType)->$writeFunction($elmObject)); + $this->cTypes['override']["/word/$elmFile"] = $elmType; + $this->docRels[] = array('target' => $elmFile, 'type' => $elmType, 'rID' => $rId); + } + } + + /** + * Add footnotes/endnotes + * + * @param mixed $objZip + * @param integer $rId + * @param string $notesType + */ + private function addNotes($objZip, &$rId, $notesType = 'footnote') + { + $notesType = ($notesType == 'endnote') ? 'endnote' : 'footnote'; + $notesTypes = "{$notesType}s"; + $collection = 'PhpOffice\\PhpWord\\' . ucfirst($notesTypes); + $xmlFile = "{$notesTypes}.xml"; + $relsFile = "word/_rels/{$xmlFile}.rels"; + $xmlPath = "word/{$xmlFile}"; + + // Add footnotes media files, relations, and contents + if ($collection::countElements() > 0) { + $media = Media::getElements($notesType); + $this->addFilesToPackage($objZip, $media); + $this->registerContentTypes($media); + if (!empty($media)) { + $objZip->addFromString($relsFile, $this->getWriterPart('rels')->writeMediaRels($media)); + } + $elements = $collection::getElements(); + $objZip->addFromString($xmlPath, $this->getWriterPart($notesTypes)->write($elements)); + $this->cTypes['override']["/{$xmlPath}"] = $notesTypes; + $this->docRels[] = array('target' => $xmlFile, 'type' => $notesTypes, 'rID' => ++$rId); + } + } + + /** + * Register content types for each media + * + * @param array $media + */ + private function registerContentTypes($media) + { + foreach ($media as $medium) { + $mediumType = $medium['type']; + if ($mediumType == 'image') { + $extension = $medium['imageExtension']; + if (!array_key_exists($extension, $this->cTypes['default'])) { + $this->cTypes['default'][$extension] = $medium['imageType']; + } + } elseif ($mediumType == 'object') { + if (!array_key_exists('bin', $this->cTypes['default'])) { + $this->cTypes['default']['bin'] = 'application/vnd.openxmlformats-officedocument.oleObject'; + } + } } } } diff --git a/src/PhpWord/Writer/Word2007/Base.php b/src/PhpWord/Writer/Word2007/Base.php deleted file mode 100644 index d76d543d..00000000 --- a/src/PhpWord/Writer/Word2007/Base.php +++ /dev/null @@ -1,1231 +0,0 @@ -getFontStyle(); - - $SfIsObject = ($styleFont instanceof Font) ? true : false; - - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - - $styleParagraph = $text->getParagraphStyle(); - $SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - if ($SpIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$SpIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - - $strText = htmlspecialchars($text->getText()); - $strText = String::controlCharacterPHP2OOXML($strText); - - $xmlWriter->startElement('w:r'); - - if ($SfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$SfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:t'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); // needed because of drawing spaces before and after text - $xmlWriter->writeRaw($strText); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); // w:r - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p - } - } - - /** - * Write textrun element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section - */ - protected function _writeTextRun(XMLWriter $xmlWriter, TextRun $textrun) - { - $elements = $textrun->getElements(); - $styleParagraph = $textrun->getParagraphStyle(); - - $SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - $xmlWriter->startElement('w:p'); - - if ($SpIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$SpIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - if (count($elements) > 0) { - foreach ($elements as $element) { - if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element, true); - } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element, true); - } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element, true); - } elseif ($element instanceof Footnote) { - $this->_writeFootnoteReference($xmlWriter, $element, true); - } elseif ($element instanceof TextBreak) { - $xmlWriter->writeElement('w:br'); - } - } - } - - $xmlWriter->endElement(); - } - - /** - * Write paragraph style - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Style\Paragraph $style - * @param bool $withoutPPR - */ - protected function _writeParagraphStyle( - XMLWriter $xmlWriter, - Paragraph $style, - $withoutPPR = false - ) { - - $align = $style->getAlign(); - $spacing = $style->getSpacing(); - $spaceBefore = $style->getSpaceBefore(); - $spaceAfter = $style->getSpaceAfter(); - $indent = $style->getIndent(); - $hanging = $style->getHanging(); - $tabs = $style->getTabs(); - $widowControl = $style->getWidowControl(); - $keepNext = $style->getKeepNext(); - $keepLines = $style->getKeepLines(); - $pageBreakBefore = $style->getPageBreakBefore(); - - if (!is_null($align) || !is_null($spacing) || !is_null($spaceBefore) || - !is_null($spaceAfter) || !is_null($indent) || !is_null($hanging) || - !is_null($tabs) || !is_null($widowControl) || !is_null($keepNext) || - !is_null($keepLines) || !is_null($pageBreakBefore)) { - if (!$withoutPPR) { - $xmlWriter->startElement('w:pPr'); - } - - // Alignment - if (!is_null($align)) { - $xmlWriter->startElement('w:jc'); - $xmlWriter->writeAttribute('w:val', $align); - $xmlWriter->endElement(); - } - - // Indentation - if (!is_null($indent) || !is_null($hanging)) { - $xmlWriter->startElement('w:ind'); - $xmlWriter->writeAttribute('w:firstLine', 0); - if (!is_null($indent)) { - $xmlWriter->writeAttribute('w:left', $indent); - } - if (!is_null($hanging)) { - $xmlWriter->writeAttribute('w:hanging', $hanging); - } - $xmlWriter->endElement(); - } - - // Spacing - if (!is_null($spaceBefore) || !is_null($spaceAfter) || - !is_null($spacing)) { - $xmlWriter->startElement('w:spacing'); - if (!is_null($spaceBefore)) { - $xmlWriter->writeAttribute('w:before', $spaceBefore); - } - if (!is_null($spaceAfter)) { - $xmlWriter->writeAttribute('w:after', $spaceAfter); - } - if (!is_null($spacing)) { - $xmlWriter->writeAttribute('w:line', $spacing); - $xmlWriter->writeAttribute('w:lineRule', 'auto'); - } - $xmlWriter->endElement(); - } - - // Pagination - if (!$widowControl) { - $xmlWriter->startElement('w:widowControl'); - $xmlWriter->writeAttribute('w:val', '0'); - $xmlWriter->endElement(); - } - if ($keepNext) { - $xmlWriter->startElement('w:keepNext'); - $xmlWriter->writeAttribute('w:val', '1'); - $xmlWriter->endElement(); - } - if ($keepLines) { - $xmlWriter->startElement('w:keepLines'); - $xmlWriter->writeAttribute('w:val', '1'); - $xmlWriter->endElement(); - } - if ($pageBreakBefore) { - $xmlWriter->startElement('w:pageBreakBefore'); - $xmlWriter->writeAttribute('w:val', '1'); - $xmlWriter->endElement(); - } - - // Tabs - if (!is_null($tabs)) { - $tabs->toXml($xmlWriter); - } - - if (!$withoutPPR) { - $xmlWriter->endElement(); // w:pPr - } - } - } - - /** - * Write link element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Link $link - * @param boolean $withoutP - */ - protected function _writeLink(XMLWriter $xmlWriter, Link $link, $withoutP = false) - { - $rID = $link->getRelationId(); - $linkName = $link->getLinkName(); - if (is_null($linkName)) { - $linkName = $link->getLinkSrc(); - } - - $styleFont = $link->getFontStyle(); - $SfIsObject = ($styleFont instanceof Font) ? true : false; - - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - - $styleParagraph = $link->getParagraphStyle(); - $SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - if ($SpIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$SpIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - - $xmlWriter->startElement('w:hyperlink'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rID); - $xmlWriter->writeAttribute('w:history', '1'); - - $xmlWriter->startElement('w:r'); - if ($SfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$SfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:t'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); // needed because of drawing spaces before and after text - $xmlWriter->writeRaw($linkName); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p - } - } - - /** - * Write preserve text element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\TextRun $textrun - */ - protected function _writePreserveText(XMLWriter $xmlWriter, PreserveText $textrun) - { - $styleFont = $textrun->getFontStyle(); - $styleParagraph = $textrun->getParagraphStyle(); - - $SfIsObject = ($styleFont instanceof Font) ? true : false; - $SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - $arrText = $textrun->getText(); - if (!is_array($arrText)) { - $arrText = array($arrText); - } - - $xmlWriter->startElement('w:p'); - - if ($SpIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$SpIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - foreach ($arrText as $text) { - - if (substr($text, 0, 1) == '{') { - $text = substr($text, 1, -1); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'begin'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - - if ($SfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$SfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:instrText'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'separate'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } else { - $text = htmlspecialchars($text); - $text = String::controlCharacterPHP2OOXML($text); - - $xmlWriter->startElement('w:r'); - - if ($SfIsObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } elseif (!$SfIsObject && !is_null($styleFont)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:t'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw($text); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - - $xmlWriter->endElement(); // p - } - - /** - * Write footnote reference element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section - */ - protected function _writeTextStyle(XMLWriter $xmlWriter, Font $style) - { - $font = $style->getName(); - $bold = $style->getBold(); - $italic = $style->getItalic(); - $color = $style->getColor(); - $size = $style->getSize(); - $fgColor = $style->getFgColor(); - $strikethrough = $style->getStrikethrough(); - $underline = $style->getUnderline(); - $superscript = $style->getSuperScript(); - $subscript = $style->getSubScript(); - $hint = $style->getHint(); - - $xmlWriter->startElement('w:rPr'); - - // Font - if ($font != PhpWord::DEFAULT_FONT_NAME) { - $xmlWriter->startElement('w:rFonts'); - $xmlWriter->writeAttribute('w:ascii', $font); - $xmlWriter->writeAttribute('w:hAnsi', $font); - $xmlWriter->writeAttribute('w:eastAsia', $font); - $xmlWriter->writeAttribute('w:cs', $font); - //Font Content Type - if ($hint != PhpWord::DEFAULT_FONT_CONTENT_TYPE) { - $xmlWriter->writeAttribute('w:hint', $hint); - } - $xmlWriter->endElement(); - } - - - // Color - if ($color != PhpWord::DEFAULT_FONT_COLOR) { - $xmlWriter->startElement('w:color'); - $xmlWriter->writeAttribute('w:val', $color); - $xmlWriter->endElement(); - } - - // Size - if ($size != PhpWord::DEFAULT_FONT_SIZE) { - $xmlWriter->startElement('w:sz'); - $xmlWriter->writeAttribute('w:val', $size * 2); - $xmlWriter->endElement(); - $xmlWriter->startElement('w:szCs'); - $xmlWriter->writeAttribute('w:val', $size * 2); - $xmlWriter->endElement(); - } - - // Bold - if ($bold) { - $xmlWriter->writeElement('w:b', null); - } - - // Italic - if ($italic) { - $xmlWriter->writeElement('w:i', null); - $xmlWriter->writeElement('w:iCs', null); - } - - // Underline - if (!is_null($underline) && $underline != 'none') { - $xmlWriter->startElement('w:u'); - $xmlWriter->writeAttribute('w:val', $underline); - $xmlWriter->endElement(); - } - - // Strikethrough - if ($strikethrough) { - $xmlWriter->writeElement('w:strike', null); - } - - // Foreground-Color - if (!is_null($fgColor)) { - $xmlWriter->startElement('w:highlight'); - $xmlWriter->writeAttribute('w:val', $fgColor); - $xmlWriter->endElement(); - } - - // Superscript/subscript - if ($superscript || $subscript) { - $xmlWriter->startElement('w:vertAlign'); - $xmlWriter->writeAttribute('w:val', $superscript ? 'superscript' : 'subscript'); - $xmlWriter->endElement(); - } - - $xmlWriter->endElement(); - } - - /** - * Write text break element - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param \PhpOffice\PhpWord\Section\TextBreak $element - */ - protected function _writeTextBreak($xmlWriter, $element = null) - { - $hasStyle = false; - if (!is_null($element)) { - $fontStyle = $element->getFontStyle(); - $sfIsObject = ($fontStyle instanceof Font) ? true : false; - $paragraphStyle = $element->getParagraphStyle(); - $spIsObject = ($paragraphStyle instanceof Paragraph) ? true : false; - $hasStyle = !is_null($fontStyle) || !is_null($paragraphStyle); - } - if ($hasStyle) { - // Paragraph style - $xmlWriter->startElement('w:p'); - if ($spIsObject) { - $this->_writeParagraphStyle($xmlWriter, $paragraphStyle); - } elseif (!$spIsObject && !is_null($paragraphStyle)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $paragraphStyle); - $xmlWriter->endElement(); // w:pStyle - $xmlWriter->endElement(); // w:pPr - } - // Font style - if (!is_null($fontStyle)) { - $xmlWriter->startElement('w:pPr'); - if ($sfIsObject) { - $this->_writeTextStyle($xmlWriter, $fontStyle); - } elseif (!$sfIsObject && !is_null($fontStyle)) { - $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rStyle'); - $xmlWriter->writeAttribute('w:val', $fontStyle); - $xmlWriter->endElement(); // w:rStyle - $xmlWriter->endElement(); // w:rPr - } - $xmlWriter->endElement(); // w:pPr - } - $xmlWriter->endElement(); // w:p - } else { - // Null element. No paragraph nor font style - $xmlWriter->writeElement('w:p', null); - } - } - - /** - * Write footnote reference element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Table $table - */ - protected function _writeTable(XMLWriter $xmlWriter, Table $table) - { - $_rows = $table->getRows(); - $_cRows = count($_rows); - - if ($_cRows > 0) { - $xmlWriter->startElement('w:tbl'); - $tblStyle = $table->getStyle(); - $tblWidth = $table->getWidth(); - if ($tblStyle instanceof PhpOffice\PhpWord\Style\Table) { - $this->_writeTableStyle($xmlWriter, $tblStyle, false); - } else { - if (!empty($tblStyle)) { - $xmlWriter->startElement('w:tblPr'); - $xmlWriter->startElement('w:tblStyle'); - $xmlWriter->writeAttribute('w:val', $tblStyle); - $xmlWriter->endElement(); - if (!is_null($tblWidth)) { - $xmlWriter->startElement('w:tblW'); - $xmlWriter->writeAttribute('w:w', $tblWidth); - $xmlWriter->writeAttribute('w:type', 'pct'); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - } - - for ($i = 0; $i < $_cRows; $i++) { - $row = $_rows[$i]; - $height = $row->getHeight(); - $rowStyle = $row->getStyle(); - $tblHeader = $rowStyle->getTblHeader(); - $cantSplit = $rowStyle->getCantSplit(); - - $xmlWriter->startElement('w:tr'); - - if (!is_null($height) || !is_null($tblHeader) || !is_null($cantSplit)) { - $xmlWriter->startElement('w:trPr'); - if (!is_null($height)) { - $xmlWriter->startElement('w:trHeight'); - $xmlWriter->writeAttribute('w:val', $height); - $xmlWriter->endElement(); - } - if ($tblHeader) { - $xmlWriter->startElement('w:tblHeader'); - $xmlWriter->writeAttribute('w:val', '1'); - $xmlWriter->endElement(); - } - if ($cantSplit) { - $xmlWriter->startElement('w:cantSplit'); - $xmlWriter->writeAttribute('w:val', '1'); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - - foreach ($row->getCells() as $cell) { - $xmlWriter->startElement('w:tc'); - - $cellStyle = $cell->getStyle(); - $width = $cell->getWidth(); - - $xmlWriter->startElement('w:tcPr'); - $xmlWriter->startElement('w:tcW'); - $xmlWriter->writeAttribute('w:w', $width); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - - if ($cellStyle instanceof Cell) { - $this->_writeCellStyle($xmlWriter, $cellStyle); - } - - $xmlWriter->endElement(); - - $_elements = $cell->getElements(); - if (count($_elements) > 0) { - foreach ($_elements as $element) { - if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); - } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); - } elseif ($element instanceof ListItem) { - $this->_writeListItem($xmlWriter, $element); - } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element); - } elseif ($element instanceof Object) { - $this->_writeObject($xmlWriter, $element); - } elseif ($element instanceof PreserveText) { - $this->_writePreserveText($xmlWriter, $element); - } - } - } else { - $this->_writeTextBreak($xmlWriter); - } - - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - } - - /** - * Write table style - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Style\Table $style - * @param boolean $isFullStyle - */ - protected function _writeTableStyle( - XMLWriter $xmlWriter, - \PhpOffice\PhpWord\Style\Table $style, - $isFullStyle = true - ) { - $bgColor = $style->getBgColor(); - $brdCol = $style->getBorderColor(); - - $brdSz = $style->getBorderSize(); - $bTop = (!is_null($brdSz[0])) ? true : false; - $bLeft = (!is_null($brdSz[1])) ? true : false; - $bRight = (!is_null($brdSz[2])) ? true : false; - $bBottom = (!is_null($brdSz[3])) ? true : false; - $bInsH = (!is_null($brdSz[4])) ? true : false; - $bInsV = (!is_null($brdSz[5])) ? true : false; - $borders = ($bTop || $bLeft || $bRight || $bBottom || $bInsH || $bInsV) ? true : false; - - $cellMargin = $style->getCellMargin(); - $mTop = (!is_null($cellMargin[0])) ? true : false; - $mLeft = (!is_null($cellMargin[1])) ? true : false; - $mRight = (!is_null($cellMargin[2])) ? true : false; - $mBottom = (!is_null($cellMargin[3])) ? true : false; - $margins = ($mTop || $mLeft || $mRight || $mBottom) ? true : false; - - if ($margins || $borders) { - $xmlWriter->startElement('w:tblPr'); - if ($margins) { - $xmlWriter->startElement('w:tblCellMar'); - if ($mTop) { - echo $margins[0]; - $xmlWriter->startElement('w:top'); - $xmlWriter->writeAttribute('w:w', $cellMargin[0]); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - } - if ($mLeft) { - $xmlWriter->startElement('w:left'); - $xmlWriter->writeAttribute('w:w', $cellMargin[1]); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - } - if ($mRight) { - $xmlWriter->startElement('w:right'); - $xmlWriter->writeAttribute('w:w', $cellMargin[2]); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - } - if ($mBottom) { - $xmlWriter->startElement('w:bottom'); - $xmlWriter->writeAttribute('w:w', $cellMargin[3]); - $xmlWriter->writeAttribute('w:type', 'dxa'); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - if ($borders) { - $xmlWriter->startElement('w:tblBorders'); - if ($bTop) { - $xmlWriter->startElement('w:top'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[0]); - $xmlWriter->writeAttribute('w:color', $brdCol[0]); - $xmlWriter->endElement(); - } - if ($bLeft) { - $xmlWriter->startElement('w:left'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[1]); - $xmlWriter->writeAttribute('w:color', $brdCol[1]); - $xmlWriter->endElement(); - } - if ($bRight) { - $xmlWriter->startElement('w:right'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[2]); - $xmlWriter->writeAttribute('w:color', $brdCol[2]); - $xmlWriter->endElement(); - } - if ($bBottom) { - $xmlWriter->startElement('w:bottom'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[3]); - $xmlWriter->writeAttribute('w:color', $brdCol[3]); - $xmlWriter->endElement(); - } - if ($bInsH) { - $xmlWriter->startElement('w:insideH'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[4]); - $xmlWriter->writeAttribute('w:color', $brdCol[4]); - $xmlWriter->endElement(); - } - if ($bInsV) { - $xmlWriter->startElement('w:insideV'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[5]); - $xmlWriter->writeAttribute('w:color', $brdCol[5]); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); // w:tblPr - } - // Only write background color and first row for full style - if ($isFullStyle) { - // Background color - if (!is_null($bgColor)) { - $xmlWriter->startElement('w:tcPr'); - $xmlWriter->startElement('w:shd'); - $xmlWriter->writeAttribute('w:val', 'clear'); - $xmlWriter->writeAttribute('w:color', 'auto'); - $xmlWriter->writeAttribute('w:fill', $bgColor); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - // First Row - $firstRow = $style->getFirstRow(); - if (!is_null($firstRow)) { - $this->_writeRowStyle($xmlWriter, 'firstRow', $firstRow); - } - } - } - - /** - * Write row style - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param string $type - * @param PhpOffice\PhpWord\Style\Table $style - */ - protected function _writeRowStyle( - XMLWriter $xmlWriter, - $type, - \PhpOffice\PhpWord\Style\Table $style - ) { - $brdSz = $style->getBorderSize(); - $brdCol = $style->getBorderColor(); - $bgColor = $style->getBgColor(); - - $bTop = (!is_null($brdSz[0])) ? true : false; - $bLeft = (!is_null($brdSz[1])) ? true : false; - $bRight = (!is_null($brdSz[2])) ? true : false; - $bBottom = (!is_null($brdSz[3])) ? true : false; - $borders = ($bTop || $bLeft || $bRight || $bBottom) ? true : false; - - $xmlWriter->startElement('w:tblStylePr'); - $xmlWriter->writeAttribute('w:type', $type); - - $xmlWriter->startElement('w:tcPr'); - if (!is_null($bgColor)) { - $xmlWriter->startElement('w:shd'); - $xmlWriter->writeAttribute('w:val', 'clear'); - $xmlWriter->writeAttribute('w:color', 'auto'); - $xmlWriter->writeAttribute('w:fill', $bgColor); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:tcBorders'); - if ($bTop) { - $xmlWriter->startElement('w:top'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[0]); - $xmlWriter->writeAttribute('w:color', $brdCol[0]); - $xmlWriter->endElement(); - } - if ($bLeft) { - $xmlWriter->startElement('w:left'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[1]); - $xmlWriter->writeAttribute('w:color', $brdCol[1]); - $xmlWriter->endElement(); - } - if ($bRight) { - $xmlWriter->startElement('w:right'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[2]); - $xmlWriter->writeAttribute('w:color', $brdCol[2]); - $xmlWriter->endElement(); - } - if ($bBottom) { - $xmlWriter->startElement('w:bottom'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[3]); - $xmlWriter->writeAttribute('w:color', $brdCol[3]); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - } - - /** - * Write footnote reference element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Style\Cell $style - */ - protected function _writeCellStyle(XMLWriter $xmlWriter, Cell $style = null) - { - $bgColor = $style->getBgColor(); - $valign = $style->getVAlign(); - $textDir = $style->getTextDirection(); - $brdSz = $style->getBorderSize(); - $brdCol = $style->getBorderColor(); - - $bTop = (!is_null($brdSz[0])) ? true : false; - $bLeft = (!is_null($brdSz[1])) ? true : false; - $bRight = (!is_null($brdSz[2])) ? true : false; - $bBottom = (!is_null($brdSz[3])) ? true : false; - $borders = ($bTop || $bLeft || $bRight || $bBottom) ? true : false; - - $styles = (!is_null($bgColor) || !is_null($valign) || !is_null($textDir) || $borders) ? true : false; - - if ($styles) { - if (!is_null($textDir)) { - $xmlWriter->startElement('w:textDirection'); - $xmlWriter->writeAttribute('w:val', $textDir); - $xmlWriter->endElement(); - } - - if (!is_null($bgColor)) { - $xmlWriter->startElement('w:shd'); - $xmlWriter->writeAttribute('w:val', 'clear'); - $xmlWriter->writeAttribute('w:color', 'auto'); - $xmlWriter->writeAttribute('w:fill', $bgColor); - $xmlWriter->endElement(); - } - - if (!is_null($valign)) { - $xmlWriter->startElement('w:vAlign'); - $xmlWriter->writeAttribute('w:val', $valign); - $xmlWriter->endElement(); - } - - if ($borders) { - $_defaultColor = $style->getDefaultBorderColor(); - - $xmlWriter->startElement('w:tcBorders'); - if ($bTop) { - if (is_null($brdCol[0])) { - $brdCol[0] = $_defaultColor; - } - $xmlWriter->startElement('w:top'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[0]); - $xmlWriter->writeAttribute('w:color', $brdCol[0]); - $xmlWriter->endElement(); - } - - if ($bLeft) { - if (is_null($brdCol[1])) { - $brdCol[1] = $_defaultColor; - } - $xmlWriter->startElement('w:left'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[1]); - $xmlWriter->writeAttribute('w:color', $brdCol[1]); - $xmlWriter->endElement(); - } - - if ($bRight) { - if (is_null($brdCol[2])) { - $brdCol[2] = $_defaultColor; - } - $xmlWriter->startElement('w:right'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[2]); - $xmlWriter->writeAttribute('w:color', $brdCol[2]); - $xmlWriter->endElement(); - } - - if ($bBottom) { - if (is_null($brdCol[3])) { - $brdCol[3] = $_defaultColor; - } - $xmlWriter->startElement('w:bottom'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $brdSz[3]); - $xmlWriter->writeAttribute('w:color', $brdCol[3]); - $xmlWriter->endElement(); - } - - $xmlWriter->endElement(); - } - } - $gridSpan = $style->getGridSpan(); - if (!is_null($gridSpan)) { - $xmlWriter->startElement('w:gridSpan'); - $xmlWriter->writeAttribute('w:val', $gridSpan); - $xmlWriter->endElement(); - } - - $vMerge = $style->getVMerge(); - if (!is_null($vMerge)) { - $xmlWriter->startElement('w:vMerge'); - $xmlWriter->writeAttribute('w:val', $vMerge); - $xmlWriter->endElement(); - } - } - - /** - * Write image element - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param mixed $image - * @param boolean $withoutP - */ - protected function _writeImage(XMLWriter $xmlWriter, $image, $withoutP = false) - { - $rId = $image->getRelationId(); - - $style = $image->getStyle(); - $width = $style->getWidth(); - $height = $style->getHeight(); - $align = $style->getAlign(); - $marginTop = $style->getMarginTop(); - $marginLeft = $style->getMarginLeft(); - $wrappingStyle = $style->getWrappingStyle(); - - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - - if (!is_null($align)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:jc'); - $xmlWriter->writeAttribute('w:val', $align); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - } - - $xmlWriter->startElement('w:r'); - - $xmlWriter->startElement('w:pict'); - - $xmlWriter->startElement('v:shape'); - $xmlWriter->writeAttribute('type', '#_x0000_t75'); - - $imgStyle = ''; - if (null !== $width) { - $imgStyle .= 'width:' . $width . 'px;'; - } - if (null !== $height) { - $imgStyle .= 'height:' . $height . 'px;'; - } - if (null !== $marginTop) { - $imgStyle .= 'margin-top:' . $marginTop . 'in;'; - } - if (null !== $marginLeft) { - $imgStyle .= 'margin-left:' . $marginLeft . 'in;'; - } - - switch ($wrappingStyle) { - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND: - $imgStyle .= 'position:absolute;z-index:-251658752;'; - break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE: - $imgStyle .= 'position:absolute;z-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; - break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_TIGHT: - $imgStyle .= 'position:absolute;z-index:251659264;mso-wrap-edited:f;mso-position-horizontal:absolute;mso-position-vertical:absolute'; - break; - case \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_INFRONT: - $imgStyle .= 'position:absolute;zz-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; - break; - } - - $xmlWriter->writeAttribute('style', $imgStyle); - - $xmlWriter->startElement('v:imagedata'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rId); - $xmlWriter->writeAttribute('o:title', ''); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p - } - } - - /** - * Write footnote reference element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param mixed $image - */ - protected function _writeWatermark(XMLWriter $xmlWriter, $image) - { - $rId = $image->getRelationId(); - - $style = $image->getStyle(); - $width = $style->getWidth(); - $height = $style->getHeight(); - $marginLeft = $style->getMarginLeft(); - $marginTop = $style->getMarginTop(); - - $xmlWriter->startElement('w:p'); - - $xmlWriter->startElement('w:r'); - - $xmlWriter->startElement('w:pict'); - - $xmlWriter->startElement('v:shape'); - $xmlWriter->writeAttribute('type', '#_x0000_t75'); - - $strStyle = 'position:absolute;'; - $strStyle .= ' width:' . $width . 'px;'; - $strStyle .= ' height:' . $height . 'px;'; - if (!is_null($marginTop)) { - $strStyle .= ' margin-top:' . $marginTop . 'px;'; - } - if (!is_null($marginLeft)) { - $strStyle .= ' margin-left:' . $marginLeft . 'px;'; - } - - $xmlWriter->writeAttribute('style', $strStyle); - - $xmlWriter->startElement('v:imagedata'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rId); - $xmlWriter->writeAttribute('o:title', ''); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - } - - /** - * Write title element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Title $title - */ - protected function _writeTitle(XMLWriter $xmlWriter, Title $title) - { - $text = htmlspecialchars($title->getText()); - $text = String::controlCharacterPHP2OOXML($text); - $anchor = $title->getAnchor(); - $bookmarkId = $title->getBookmarkId(); - $style = $title->getStyle(); - - $xmlWriter->startElement('w:p'); - - if (!empty($style)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $style); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:bookmarkStart'); - $xmlWriter->writeAttribute('w:id', $bookmarkId); - $xmlWriter->writeAttribute('w:name', $anchor); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:t'); - $xmlWriter->writeRaw($text); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:bookmarkEnd'); - $xmlWriter->writeAttribute('w:id', $bookmarkId); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - } - - /** - * Write footnote element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Footnote $footnote - */ - protected function _writeFootnote(XMLWriter $xmlWriter, Footnote $footnote) - { - $xmlWriter->startElement('w:footnote'); - $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); - - $styleParagraph = $footnote->getParagraphStyle(); - $SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - $xmlWriter->startElement('w:p'); - - if ($SpIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph); - } elseif (!$SpIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $elements = $footnote->getElements(); - if (count($elements) > 0) { - foreach ($elements as $element) { - if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element, true); - } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element, true); - } - } - } - - $xmlWriter->endElement(); // w:p - $xmlWriter->endElement(); // w:footnote - } - - /** - * Write footnote reference element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Footnote $footnote - * @param boolean $withoutP - */ - protected function _writeFootnoteReference(XMLWriter $xmlWriter, Footnote $footnote, $withoutP = false) - { - if (!$withoutP) { - $xmlWriter->startElement('w:p'); - } - - $xmlWriter->startElement('w:r'); - - $xmlWriter->startElement('w:footnoteReference'); - $xmlWriter->writeAttribute('w:id', $footnote->getReferenceId()); - $xmlWriter->endElement(); // w:footnoteReference - - $xmlWriter->endElement(); // w:r - - if (!$withoutP) { - $xmlWriter->endElement(); // w:p - } - } -} diff --git a/src/PhpWord/Writer/Word2007/ContentTypes.php b/src/PhpWord/Writer/Word2007/ContentTypes.php deleted file mode 100755 index 5971d8a8..00000000 --- a/src/PhpWord/Writer/Word2007/ContentTypes.php +++ /dev/null @@ -1,240 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // Types - $xmlWriter->startElement('Types'); - $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types'); - - // Rels - $this->_writeDefaultContentType( - $xmlWriter, - 'rels', - 'application/vnd.openxmlformats-package.relationships+xml' - ); - - // XML - $this->_writeDefaultContentType( - $xmlWriter, - 'xml', - 'application/xml' - ); - - // Add media content-types - foreach ($_imageTypes as $key => $value) { - $this->_writeDefaultContentType($xmlWriter, $key, $value); - } - - // Add embedding content-types - if (count($_objectTypes) > 0) { - $this->_writeDefaultContentType( - $xmlWriter, - 'bin', - 'application/vnd.openxmlformats-officedocument.oleObject' - ); - } - - // DocProps - $this->_writeOverrideContentType( - $xmlWriter, - '/docProps/app.xml', - 'application/vnd.openxmlformats-officedocument.extended-properties+xml' - ); - - $this->_writeOverrideContentType( - $xmlWriter, - '/docProps/core.xml', - 'application/vnd.openxmlformats-package.core-properties+xml' - ); - - // Document - $this->_writeOverrideContentType( - $xmlWriter, - '/word/document.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml' - ); - - // Styles - $this->_writeOverrideContentType( - $xmlWriter, - '/word/styles.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml' - ); - - // Numbering - $this->_writeOverrideContentType( - $xmlWriter, - '/word/numbering.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml' - ); - - // Settings - $this->_writeOverrideContentType( - $xmlWriter, - '/word/settings.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml' - ); - - // Theme1 - $this->_writeOverrideContentType( - $xmlWriter, - '/word/theme/theme1.xml', - 'application/vnd.openxmlformats-officedocument.theme+xml' - ); - - // WebSettings - $this->_writeOverrideContentType( - $xmlWriter, - '/word/webSettings.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml' - ); - - // Font Table - $this->_writeOverrideContentType( - $xmlWriter, - '/word/fontTable.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml' - ); - - // Footnotes - $this->_writeOverrideContentType( - $xmlWriter, - '/word/footnotes.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml' - ); - - for ($i = 1; $i <= $_cHdrs; $i++) { - $this->_writeOverrideContentType( - $xmlWriter, - '/word/header' . $i . '.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml' - ); - } - - for ($i = 1; $i <= count($footers); $i++) { - if (!is_null($footers[$i])) { - $this->_writeOverrideContentType( - $xmlWriter, - '/word/footer' . $i . '.xml', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml' - ); - } - } - - - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } - - /** - * Get image mime type - * - * @param string $pFile Filename - * @return string Mime Type - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - private function _getImageMimeType($pFile = '') - { - if (file_exists($pFile)) { - $image = getimagesize($pFile); - return image_type_to_mime_type($image[2]); - } else { - throw new Exception("File $pFile does not exist"); - } - } - - /** - * Write Default XML element - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter XML Writer - * @param string $pPartname Part name - * @param string $pContentType Content type - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - private function _writeDefaultContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') - { - if ($pPartname != '' && $pContentType != '') { - // Write content type - $xmlWriter->startElement('Default'); - $xmlWriter->writeAttribute('Extension', $pPartname); - $xmlWriter->writeAttribute('ContentType', $pContentType); - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } - - /** - * Write Override XML element - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param string $pPartname Part name - * @param string $pContentType Content type - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - private function _writeOverrideContentType(XMLWriter $xmlWriter = null, $pPartname = '', $pContentType = '') - { - if ($pPartname != '' && $pContentType != '') { - // Write content type - $xmlWriter->startElement('Override'); - $xmlWriter->writeAttribute('PartName', $pPartname); - $xmlWriter->writeAttribute('ContentType', $pContentType); - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } -} diff --git a/src/PhpWord/Writer/Word2007/DocProps.php b/src/PhpWord/Writer/Word2007/DocProps.php deleted file mode 100644 index 9428a615..00000000 --- a/src/PhpWord/Writer/Word2007/DocProps.php +++ /dev/null @@ -1,195 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // Properties - $xmlWriter->startElement('Properties'); - $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties'); - $xmlWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); - - // Application - $xmlWriter->writeElement('Application', 'Microsoft Office Word'); - - // ScaleCrop - $xmlWriter->writeElement('ScaleCrop', 'false'); - - // HeadingPairs - $xmlWriter->startElement('HeadingPairs'); - - // Vector - $xmlWriter->startElement('vt:vector'); - $xmlWriter->writeAttribute('size', '4'); - $xmlWriter->writeAttribute('baseType', 'variant'); - - // Variant - $xmlWriter->startElement('vt:variant'); - $xmlWriter->writeElement('vt:lpstr', 'Theme'); - $xmlWriter->endElement(); - - // Variant - $xmlWriter->startElement('vt:variant'); - $xmlWriter->writeElement('vt:i4', '1'); - $xmlWriter->endElement(); - - // Variant - $xmlWriter->startElement('vt:variant'); - $xmlWriter->writeElement('vt:lpstr', 'Slide Titles'); - $xmlWriter->endElement(); - - // Variant - $xmlWriter->startElement('vt:variant'); - $xmlWriter->writeElement('vt:i4', '1'); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - // TitlesOfParts - $xmlWriter->startElement('TitlesOfParts'); - - // Vector - $xmlWriter->startElement('vt:vector'); - $xmlWriter->writeAttribute('size', '1'); - $xmlWriter->writeAttribute('baseType', 'lpstr'); - - $xmlWriter->writeElement('vt:lpstr', 'Office Theme'); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - // Company - $xmlWriter->writeElement('Company', $phpWord->getDocumentProperties()->getCompany()); - - // LinksUpToDate - $xmlWriter->writeElement('LinksUpToDate', 'false'); - - // SharedDoc - $xmlWriter->writeElement('SharedDoc', 'false'); - - // HyperlinksChanged - $xmlWriter->writeElement('HyperlinksChanged', 'false'); - - // AppVersion - $xmlWriter->writeElement('AppVersion', '12.0000'); - - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } - - - /** - * Write docProps/core.xml - * - * @param PhpOffice\PhpWord\PhpWord $phpWord - */ - public function writeDocPropsCore(PhpWord $phpWord = null) - { - // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // cp:coreProperties - $xmlWriter->startElement('cp:coreProperties'); - $xmlWriter->writeAttribute('xmlns:cp', 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties'); - $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); - $xmlWriter->writeAttribute('xmlns:dcterms', 'http://purl.org/dc/terms/'); - $xmlWriter->writeAttribute('xmlns:dcmitype', 'http://purl.org/dc/dcmitype/'); - $xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); - - // dc:creator - $xmlWriter->writeElement('dc:creator', $phpWord->getDocumentProperties()->getCreator()); - - // cp:lastModifiedBy - $xmlWriter->writeElement('cp:lastModifiedBy', $phpWord->getDocumentProperties()->getLastModifiedBy()); - - // dcterms:created - $xmlWriter->startElement('dcterms:created'); - $xmlWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); - $xmlWriter->writeRaw(date(DATE_W3C, $phpWord->getDocumentProperties()->getCreated())); - $xmlWriter->endElement(); - - // dcterms:modified - $xmlWriter->startElement('dcterms:modified'); - $xmlWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); - $xmlWriter->writeRaw(date(DATE_W3C, $phpWord->getDocumentProperties()->getModified())); - $xmlWriter->endElement(); - - // dc:title - $xmlWriter->writeElement('dc:title', $phpWord->getDocumentProperties()->getTitle()); - - // dc:description - $xmlWriter->writeElement('dc:description', $phpWord->getDocumentProperties()->getDescription()); - - // dc:subject - $xmlWriter->writeElement('dc:subject', $phpWord->getDocumentProperties()->getSubject()); - - // cp:keywords - $xmlWriter->writeElement('cp:keywords', $phpWord->getDocumentProperties()->getKeywords()); - - // cp:category - $xmlWriter->writeElement('cp:category', $phpWord->getDocumentProperties()->getCategory()); - - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } -} diff --git a/src/PhpWord/Writer/Word2007/Document.php b/src/PhpWord/Writer/Word2007/Document.php deleted file mode 100644 index 00f2b7fa..00000000 --- a/src/PhpWord/Writer/Word2007/Document.php +++ /dev/null @@ -1,544 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // w:document - $xmlWriter->startElement('w:document'); - - $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); - $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); - $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); - $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); - $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); - $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); - $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); - $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); - $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); - - $xmlWriter->startElement('w:body'); - - $_sections = $phpWord->getSections(); - $countSections = count($_sections); - $pSection = 0; - - if ($countSections > 0) { - foreach ($_sections as $section) { - $pSection++; - - $_elements = $section->getElements(); - - foreach ($_elements as $element) { - if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); - } elseif ($element instanceof Link) { - $this->_writeLink($xmlWriter, $element); - } elseif ($element instanceof Title) { - $this->_writeTitle($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); - } elseif ($element instanceof PageBreak) { - $this->_writePageBreak($xmlWriter); - } elseif ($element instanceof Table) { - $this->_writeTable($xmlWriter, $element); - } elseif ($element instanceof ListItem) { - $this->_writeListItem($xmlWriter, $element); - } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element); - } elseif ($element instanceof Object) { - $this->_writeObject($xmlWriter, $element); - } elseif ($element instanceof TOC) { - $this->_writeTOC($xmlWriter); - } elseif ($element instanceof Footnote) { - $this->_writeFootnoteReference($xmlWriter, $element); - } - } - - if ($pSection == $countSections) { - $this->_writeEndSection($xmlWriter, $section); - } else { - $this->_writeSection($xmlWriter, $section); - } - } - } - - $xmlWriter->endElement(); // End w:body - $xmlWriter->endElement(); // End w:document - - // Return - return $xmlWriter->getData(); - } - - /** - * Write begin section - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section - */ - private function _writeSection(XMLWriter $xmlWriter, Section $section) - { - $xmlWriter->startElement('w:p'); - $xmlWriter->startElement('w:pPr'); - $this->_writeEndSection($xmlWriter, $section, 3); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - /** - * Write end section - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section $section - */ - private function _writeEndSection(XMLWriter $xmlWriter, Section $section) - { - $settings = $section->getSettings(); - $_headers = $section->getHeaders(); - $_footer = $section->getFooter(); - $pgSzW = $settings->getPageSizeW(); - $pgSzH = $settings->getPageSizeH(); - $orientation = $settings->getOrientation(); - - $marginTop = $settings->getMarginTop(); - $marginLeft = $settings->getMarginLeft(); - $marginRight = $settings->getMarginRight(); - $marginBottom = $settings->getMarginBottom(); - - $headerHeight = $settings->getHeaderHeight(); - $footerHeight = $settings->getFooterHeight(); - - $borders = $settings->getBorderSize(); - - $colsNum = $settings->getColsNum(); - $colsSpace = $settings->getColsSpace(); - $breakType = $settings->getBreakType(); - - $xmlWriter->startElement('w:sectPr'); - - foreach ($_headers as &$_header) { - $rId = $_header->getRelationId(); - $xmlWriter->startElement('w:headerReference'); - $xmlWriter->writeAttribute('w:type', $_header->getType()); - $xmlWriter->writeAttribute('r:id', 'rId' . $rId); - $xmlWriter->endElement(); - } - - if ($section->hasDifferentFirstPage()) { - $xmlWriter->startElement('w:titlePg'); - $xmlWriter->endElement(); - } - - if (!is_null($breakType)) { - $xmlWriter->startElement('w:type'); - $xmlWriter->writeAttribute('w:val', $breakType); - $xmlWriter->endElement(); - } - - if (!is_null($_footer)) { - $rId = $_footer->getRelationId(); - $xmlWriter->startElement('w:footerReference'); - $xmlWriter->writeAttribute('w:type', 'default'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rId); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:pgSz'); - $xmlWriter->writeAttribute('w:w', $pgSzW); - $xmlWriter->writeAttribute('w:h', $pgSzH); - - if (!is_null($orientation) && strtolower($orientation) != 'portrait') { - $xmlWriter->writeAttribute('w:orient', $orientation); - } - - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:pgMar'); - $xmlWriter->writeAttribute('w:top', $marginTop); - $xmlWriter->writeAttribute('w:right', $marginRight); - $xmlWriter->writeAttribute('w:bottom', $marginBottom); - $xmlWriter->writeAttribute('w:left', $marginLeft); - $xmlWriter->writeAttribute('w:header', $headerHeight); - $xmlWriter->writeAttribute('w:footer', $footerHeight); - $xmlWriter->writeAttribute('w:gutter', '0'); - $xmlWriter->endElement(); - - - if (!is_null($borders[0]) || !is_null($borders[1]) || !is_null($borders[2]) || !is_null($borders[3])) { - $borderColor = $settings->getBorderColor(); - - $xmlWriter->startElement('w:pgBorders'); - $xmlWriter->writeAttribute('w:offsetFrom', 'page'); - - if (!is_null($borders[0])) { - $xmlWriter->startElement('w:top'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $borders[0]); - $xmlWriter->writeAttribute('w:space', '24'); - $xmlWriter->writeAttribute('w:color', $borderColor[0]); - $xmlWriter->endElement(); - } - - if (!is_null($borders[1])) { - $xmlWriter->startElement('w:left'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $borders[1]); - $xmlWriter->writeAttribute('w:space', '24'); - $xmlWriter->writeAttribute('w:color', $borderColor[1]); - $xmlWriter->endElement(); - } - - if (!is_null($borders[2])) { - $xmlWriter->startElement('w:right'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $borders[2]); - $xmlWriter->writeAttribute('w:space', '24'); - $xmlWriter->writeAttribute('w:color', $borderColor[2]); - $xmlWriter->endElement(); - } - - if (!is_null($borders[3])) { - $xmlWriter->startElement('w:bottom'); - $xmlWriter->writeAttribute('w:val', 'single'); - $xmlWriter->writeAttribute('w:sz', $borders[3]); - $xmlWriter->writeAttribute('w:space', '24'); - $xmlWriter->writeAttribute('w:color', $borderColor[3]); - $xmlWriter->endElement(); - } - $xmlWriter->endElement(); - } - - // Page numbering - if (null !== $settings->getPageNumberingStart()) { - $xmlWriter->startElement('w:pgNumType'); - $xmlWriter->writeAttribute('w:start', $section->getSettings()->getPageNumberingStart()); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:cols'); - $xmlWriter->writeAttribute('w:num', $colsNum); - $xmlWriter->writeAttribute('w:space', $colsSpace); - $xmlWriter->endElement(); - - - $xmlWriter->endElement(); - } - - /** - * Write page break element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - */ - private function _writePageBreak(XMLWriter $xmlWriter) - { - $xmlWriter->startElement('w:p'); - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:br'); - $xmlWriter->writeAttribute('w:type', 'page'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - /** - * Write list item element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\ListItem $listItem - */ - public function _writeListItem(XMLWriter $xmlWriter, ListItem $listItem) - { - $textObject = $listItem->getTextObject(); - $text = $textObject->getText(); - $styleParagraph = $textObject->getParagraphStyle(); - $SpIsObject = ($styleParagraph instanceof Paragraph) ? true : false; - - $depth = $listItem->getDepth(); - $listType = $listItem->getStyle()->getListType(); - - $xmlWriter->startElement('w:p'); - $xmlWriter->startElement('w:pPr'); - - if ($SpIsObject) { - $this->_writeParagraphStyle($xmlWriter, $styleParagraph, true); - } elseif (!$SpIsObject && !is_null($styleParagraph)) { - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleParagraph); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:numPr'); - - $xmlWriter->startElement('w:ilvl'); - $xmlWriter->writeAttribute('w:val', $depth); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:numId'); - $xmlWriter->writeAttribute('w:val', $listType); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $this->_writeText($xmlWriter, $textObject, true); - - $xmlWriter->endElement(); - } - - /** - * Write object element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param PhpOffice\PhpWord\Section\Object $object - */ - protected function _writeObject(XMLWriter $xmlWriter, Object $object) - { - $rIdObject = $object->getRelationId(); - $rIdImage = $object->getImageRelationId(); - $shapeId = md5($rIdObject . '_' . $rIdImage); - - $objectId = $object->getObjectId(); - - $style = $object->getStyle(); - $width = $style->getWidth(); - $height = $style->getHeight(); - $align = $style->getAlign(); - - - $xmlWriter->startElement('w:p'); - - if (!is_null($align)) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:jc'); - $xmlWriter->writeAttribute('w:val', $align); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:r'); - - $xmlWriter->startElement('w:object'); - $xmlWriter->writeAttribute('w:dxaOrig', '249'); - $xmlWriter->writeAttribute('w:dyaOrig', '160'); - - $xmlWriter->startElement('v:shape'); - $xmlWriter->writeAttribute('id', $shapeId); - $xmlWriter->writeAttribute('type', '#_x0000_t75'); - $xmlWriter->writeAttribute('style', 'width:104px;height:67px'); - $xmlWriter->writeAttribute('o:ole', ''); - - $xmlWriter->startElement('v:imagedata'); - $xmlWriter->writeAttribute('r:id', 'rId' . $rIdImage); - $xmlWriter->writeAttribute('o:title', ''); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->startElement('o:OLEObject'); - $xmlWriter->writeAttribute('Type', 'Embed'); - $xmlWriter->writeAttribute('ProgID', 'Package'); - $xmlWriter->writeAttribute('ShapeID', $shapeId); - $xmlWriter->writeAttribute('DrawAspect', 'Icon'); - $xmlWriter->writeAttribute('ObjectID', '_' . $objectId); - $xmlWriter->writeAttribute('r:id', 'rId' . $rIdObject); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); - - $xmlWriter->endElement(); // w:r - - $xmlWriter->endElement(); // w:p - } - - /** - * Write TOC element - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - */ - private function _writeTOC(XMLWriter $xmlWriter) - { - $titles = TOC::getTitles(); - $styleFont = TOC::getStyleFont(); - - $styleTOC = TOC::getStyleTOC(); - $fIndent = $styleTOC->getIndent(); - $tabLeader = $styleTOC->getTabLeader(); - $tabPos = $styleTOC->getTabPos(); - - $isObject = ($styleFont instanceof Font) ? true : false; - - for ($i = 0; $i < count($titles); $i++) { - $title = $titles[$i]; - $indent = ($title['depth'] - 1) * $fIndent; - - $xmlWriter->startElement('w:p'); - - $xmlWriter->startElement('w:pPr'); - - if ($isObject && !is_null($styleFont->getParagraphStyle())) { - $this->_writeParagraphStyle($xmlWriter, $styleFont->getParagraphStyle()); - } - - if ($indent > 0) { - $xmlWriter->startElement('w:ind'); - $xmlWriter->writeAttribute('w:left', $indent); - $xmlWriter->endElement(); - } - - if (!empty($styleFont) && !$isObject) { - $xmlWriter->startElement('w:pPr'); - $xmlWriter->startElement('w:pStyle'); - $xmlWriter->writeAttribute('w:val', $styleFont); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:tabs'); - $xmlWriter->startElement('w:tab'); - $xmlWriter->writeAttribute('w:val', 'right'); - if (!empty($tabLeader)) { - $xmlWriter->writeAttribute('w:leader', $tabLeader); - } - $xmlWriter->writeAttribute('w:pos', $tabPos); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); // w:pPr - - - if ($i == 0) { - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'begin'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:instrText'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw('TOC \o "1-9" \h \z \u'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'separate'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } - - $xmlWriter->startElement('w:hyperlink'); - $xmlWriter->writeAttribute('w:anchor', $title['anchor']); - $xmlWriter->writeAttribute('w:history', '1'); - - $xmlWriter->startElement('w:r'); - - if ($isObject) { - $this->_writeTextStyle($xmlWriter, $styleFont); - } - - $xmlWriter->startElement('w:t'); - $xmlWriter->writeRaw($title['text']); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->writeElement('w:tab', null); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'begin'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:instrText'); - $xmlWriter->writeAttribute('xml:space', 'preserve'); - $xmlWriter->writeRaw('PAGEREF ' . $title['anchor'] . ' \h'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - - $xmlWriter->endElement(); // w:hyperlink - - $xmlWriter->endElement(); // w:p - } - - $xmlWriter->startElement('w:p'); - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:fldChar'); - $xmlWriter->writeAttribute('w:fldCharType', 'end'); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - $xmlWriter->endElement(); - } -} diff --git a/src/PhpWord/Writer/Word2007/DocumentRels.php b/src/PhpWord/Writer/Word2007/DocumentRels.php deleted file mode 100755 index 0996db4e..00000000 --- a/src/PhpWord/Writer/Word2007/DocumentRels.php +++ /dev/null @@ -1,203 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // Relationships - $xmlWriter->startElement('Relationships'); - $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - - // Relationship word/document.xml - $this->_writeRelationship( - $xmlWriter, - 1, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles', - 'styles.xml' - ); - - // Relationship word/numbering.xml - $this->_writeRelationship( - $xmlWriter, - 2, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering', - 'numbering.xml' - ); - - // Relationship word/settings.xml - $this->_writeRelationship( - $xmlWriter, - 3, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings', - 'settings.xml' - ); - - // Relationship word/settings.xml - $this->_writeRelationship( - $xmlWriter, - 4, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme', - 'theme/theme1.xml' - ); - - // Relationship word/settings.xml - $this->_writeRelationship( - $xmlWriter, - 5, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings', - 'webSettings.xml' - ); - - // Relationship word/settings.xml - $this->_writeRelationship( - $xmlWriter, - 6, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable', - 'fontTable.xml' - ); - - // Relationships to Images / Embeddings / Headers / Footers - foreach ($_relsCollection as $relation) { - $relationType = $relation['type']; - $relationName = $relation['target']; - $relationId = $relation['rID']; - $targetMode = ($relationType == 'hyperlink') ? 'External' : ''; - - $this->_writeRelationship( - $xmlWriter, - $relationId, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, - $relationName, - $targetMode - ); - } - - - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } - - /** - * Write header footer rels - * - * @param array $_relsCollection - */ - public function writeHeaderFooterRels($_relsCollection) - { - // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // Relationships - $xmlWriter->startElement('Relationships'); - $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - - // Relationships to Images / Embeddings / Headers / Footers - foreach ($_relsCollection as $relation) { - $relationType = $relation['type']; - $relationName = $relation['target']; - $relationId = $relation['rID']; - - $this->_writeRelationship( - $xmlWriter, - $relationId, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, - $relationName - ); - } - - - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } - - /** - * Write individual rels entry - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param int $pId Relationship ID - * @param string $pType Relationship type - * @param string $pTarget Relationship target - * @param string $pTargetMode Relationship target mode - */ - private function _writeRelationship(XMLWriter $xmlWriter = null, $pId = 1, $pType = '', $pTarget = '', $pTargetMode = '') - { - if ($pType != '' && $pTarget != '') { - if (strpos($pId, 'rId') === false) { - $pId = 'rId' . $pId; - } - - // Write relationship - $xmlWriter->startElement('Relationship'); - $xmlWriter->writeAttribute('Id', $pId); - $xmlWriter->writeAttribute('Type', $pType); - $xmlWriter->writeAttribute('Target', $pTarget); - - if ($pTargetMode != '') { - $xmlWriter->writeAttribute('TargetMode', $pTargetMode); - } - - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } -} diff --git a/src/PhpWord/Writer/Word2007/Element/CheckBox.php b/src/PhpWord/Writer/Word2007/Element/CheckBox.php new file mode 100644 index 00000000..12b28cf9 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/CheckBox.php @@ -0,0 +1,96 @@ +element->getName()); + $name = String::controlCharacterPHP2OOXML($name); + $text = htmlspecialchars($this->element->getText()); + $text = String::controlCharacterPHP2OOXML($text); + $fontStyle = $this->element->getFontStyle(); + $paragraphStyle = $this->element->getParagraphStyle(); + + if (!$this->withoutP) { + $styleWriter = new ParagraphStyleWriter($this->xmlWriter, $paragraphStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:p'); + $styleWriter->write(); + } + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $this->xmlWriter->startElement('w:ffData'); + $this->xmlWriter->startElement('w:name'); + $this->xmlWriter->writeAttribute('w:val', $name); + $this->xmlWriter->endElement(); //w:name + $this->xmlWriter->writeAttribute('w:enabled', ''); + $this->xmlWriter->startElement('w:calcOnExit'); + $this->xmlWriter->writeAttribute('w:val', '0'); + $this->xmlWriter->endElement(); //w:calcOnExit + $this->xmlWriter->startElement('w:checkBox'); + $this->xmlWriter->writeAttribute('w:sizeAuto', ''); + $this->xmlWriter->startElement('w:default'); + $this->xmlWriter->writeAttribute('w:val', 0); + $this->xmlWriter->endElement(); //w:default + $this->xmlWriter->endElement(); //w:checkBox + $this->xmlWriter->endElement(); // w:ffData + $this->xmlWriter->endElement(); // w:fldChar + $this->xmlWriter->endElement(); // w:r + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:instrText'); + $this->xmlWriter->writeAttribute('xml:space', 'preserve'); + $this->xmlWriter->writeRaw(' FORMCHECKBOX '); + $this->xmlWriter->endElement();// w:instrText + $this->xmlWriter->endElement(); // w:r + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'seperate'); + $this->xmlWriter->endElement();// w:fldChar + $this->xmlWriter->endElement(); // w:r + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'end'); + $this->xmlWriter->endElement();// w:fldChar + $this->xmlWriter->endElement(); // w:r + + $styleWriter = new FontStyleWriter($this->xmlWriter, $fontStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:r'); + $styleWriter->write(); + $this->xmlWriter->startElement('w:t'); + $this->xmlWriter->writeAttribute('xml:space', 'preserve'); + $this->xmlWriter->writeRaw($text); + $this->xmlWriter->endElement(); // w:t + $this->xmlWriter->endElement(); // w:r + + if (!$this->withoutP) { + $this->xmlWriter->endElement(); // w:p + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Element.php b/src/PhpWord/Writer/Word2007/Element/Element.php new file mode 100644 index 00000000..9c91beb7 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Element.php @@ -0,0 +1,78 @@ +xmlWriter = $xmlWriter; + $this->parentWriter = $parentWriter; + $this->element = $element; + $this->withoutP = $withoutP; + } + + /** + * Write element + * + * @return string + */ + public function write() + { + $elmName = str_replace('PhpOffice\\PhpWord\\Element\\', '', get_class($this->element)); + $elmWriterClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elmName; + if (class_exists($elmWriterClass) === true) { + $elmWriter = new $elmWriterClass($this->xmlWriter, $this->parentWriter, $this->element, $this->withoutP); + $elmWriter->write(); + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Endnote.php b/src/PhpWord/Writer/Word2007/Element/Endnote.php new file mode 100644 index 00000000..fbdf7a75 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Endnote.php @@ -0,0 +1,27 @@ +referenceType = 'endnoteReference'; + parent::write(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php new file mode 100644 index 00000000..20360ebc --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -0,0 +1,27 @@ +referenceType = 'footnoteReference'; + parent::write(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Image.php b/src/PhpWord/Writer/Word2007/Element/Image.php new file mode 100644 index 00000000..e944b7af --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Image.php @@ -0,0 +1,147 @@ +element->getIsWatermark()) { + $this->writeWatermark(); + } else { + $this->writeImage(); + } + } + + /** + * Write image element + */ + private function writeImage() + { + $rId = $this->element->getRelationId() + ($this->element->isInSection() ? 6 : 0); + + $style = $this->element->getStyle(); + $width = $style->getWidth(); + $height = $style->getHeight(); + $align = $style->getAlign(); + $marginTop = $style->getMarginTop(); + $marginLeft = $style->getMarginLeft(); + $wrappingStyle = $style->getWrappingStyle(); + $w10wrapType = null; + $imgStyle = ''; + if (null !== $width) { + $imgStyle .= 'width:' . $width . 'px;'; + } + if (null !== $height) { + $imgStyle .= 'height:' . $height . 'px;'; + } + if (null !== $marginTop) { + $imgStyle .= 'margin-top:' . $marginTop . 'in;'; + } + if (null !== $marginLeft) { + $imgStyle .= 'margin-left:' . $marginLeft . 'in;'; + } + switch ($wrappingStyle) { + case ImageStyle::WRAPPING_STYLE_BEHIND: + $imgStyle .= 'position:absolute;z-index:-251658752;'; + break; + case ImageStyle::WRAPPING_STYLE_INFRONT: + $imgStyle .= 'position:absolute;z-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; + break; + case ImageStyle::WRAPPING_STYLE_SQUARE: + $imgStyle .= 'position:absolute;z-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; + $w10wrapType = 'square'; + break; + case ImageStyle::WRAPPING_STYLE_TIGHT: + $imgStyle .= 'position:absolute;z-index:251659264;mso-position-horizontal:absolute;mso-position-vertical:absolute;'; + $w10wrapType = 'tight'; + break; + } + + if (!$this->withoutP) { + $this->xmlWriter->startElement('w:p'); + if (!is_null($align)) { + $this->xmlWriter->startElement('w:pPr'); + $this->xmlWriter->startElement('w:jc'); + $this->xmlWriter->writeAttribute('w:val', $align); + $this->xmlWriter->endElement(); // w:jc + $this->xmlWriter->endElement(); // w:pPr + } + } + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:pict'); + $this->xmlWriter->startElement('v:shape'); + $this->xmlWriter->writeAttribute('type', '#_x0000_t75'); + $this->xmlWriter->writeAttribute('style', $imgStyle); + $this->xmlWriter->startElement('v:imagedata'); + $this->xmlWriter->writeAttribute('r:id', 'rId' . $rId); + $this->xmlWriter->writeAttribute('o:title', ''); + $this->xmlWriter->endElement(); // v:imagedata + if (!is_null($w10wrapType)) { + $this->xmlWriter->startElement('w10:wrap'); + $this->xmlWriter->writeAttribute('type', $w10wrapType); + $this->xmlWriter->endElement(); // w10:wrap + } + $this->xmlWriter->endElement(); // v:shape + $this->xmlWriter->endElement(); // w:pict + $this->xmlWriter->endElement(); // w:r + + if (!$this->withoutP) { + $this->xmlWriter->endElement(); // w:p + } + } + /** + * Write watermark element + */ + private function writeWatermark() + { + $rId = $this->element->getRelationId(); + + $style = $this->element->getStyle(); + $width = $style->getWidth(); + $height = $style->getHeight(); + $marginLeft = $style->getMarginLeft(); + $marginTop = $style->getMarginTop(); + $strStyle = 'position:absolute;'; + $strStyle .= ' width:' . $width . 'px;'; + $strStyle .= ' height:' . $height . 'px;'; + if (!is_null($marginTop)) { + $strStyle .= ' margin-top:' . $marginTop . 'px;'; + } + if (!is_null($marginLeft)) { + $strStyle .= ' margin-left:' . $marginLeft . 'px;'; + } + + $this->xmlWriter->startElement('w:p'); + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:pict'); + $this->xmlWriter->startElement('v:shape'); + $this->xmlWriter->writeAttribute('type', '#_x0000_t75'); + $this->xmlWriter->writeAttribute('style', $strStyle); + $this->xmlWriter->startElement('v:imagedata'); + $this->xmlWriter->writeAttribute('r:id', 'rId' . $rId); + $this->xmlWriter->writeAttribute('o:title', ''); + $this->xmlWriter->endElement(); // v:imagedata + $this->xmlWriter->endElement(); // v:shape + $this->xmlWriter->endElement(); // w:pict + $this->xmlWriter->endElement(); // w:r + $this->xmlWriter->endElement(); // w:p + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Link.php b/src/PhpWord/Writer/Word2007/Element/Link.php new file mode 100644 index 00000000..e9cdad91 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Link.php @@ -0,0 +1,57 @@ +element->getRelationId() + ($this->element->isInSection() ? 6 : 0); + $fontStyle = $this->element->getFontStyle(); + $paragraphStyle = $this->element->getParagraphStyle(); + + if (!$this->withoutP) { + $styleWriter = new ParagraphStyleWriter($this->xmlWriter, $paragraphStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:p'); + $styleWriter->write(); + } + + $styleWriter = new FontStyleWriter($this->xmlWriter, $fontStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:hyperlink'); + $this->xmlWriter->writeAttribute('r:id', 'rId' . $rId); + $this->xmlWriter->writeAttribute('w:history', '1'); + $this->xmlWriter->startElement('w:r'); + $styleWriter->write(); + $this->xmlWriter->startElement('w:t'); + $this->xmlWriter->writeAttribute('xml:space', 'preserve'); + $this->xmlWriter->writeRaw($this->element->getText()); + $this->xmlWriter->endElement(); // w:t + $this->xmlWriter->endElement(); // w:r + $this->xmlWriter->endElement(); // w:hyperlink + if (!$this->withoutP) { + $this->xmlWriter->endElement(); // w:p + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/ListItem.php b/src/PhpWord/Writer/Word2007/Element/ListItem.php new file mode 100644 index 00000000..d020fe6f --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/ListItem.php @@ -0,0 +1,54 @@ +element->getTextObject(); + $depth = $this->element->getDepth(); + $numId = $this->element->getStyle()->getNumId(); + $paragraphStyle = $textObject->getParagraphStyle(); + $styleWriter = new ParagraphStyleWriter($this->xmlWriter, $paragraphStyle); + $styleWriter->setWithoutPPR(true); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:p'); + + $this->xmlWriter->startElement('w:pPr'); + $styleWriter->write(); + $this->xmlWriter->startElement('w:numPr'); + $this->xmlWriter->startElement('w:ilvl'); + $this->xmlWriter->writeAttribute('w:val', $depth); + $this->xmlWriter->endElement(); // w:ilvl + $this->xmlWriter->startElement('w:numId'); + $this->xmlWriter->writeAttribute('w:val', $numId); + $this->xmlWriter->endElement(); // w:numId + $this->xmlWriter->endElement(); // w:numPr + $this->xmlWriter->endElement(); // w:pPr + + $elementWriter = new ElementWriter($this->xmlWriter, $this->parentWriter, $textObject, true); + $elementWriter->write(); + + $this->xmlWriter->endElement(); // w:p + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Note.php b/src/PhpWord/Writer/Word2007/Element/Note.php new file mode 100644 index 00000000..1ba73de8 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Note.php @@ -0,0 +1,48 @@ +withoutP) { + $this->xmlWriter->startElement('w:p'); + } + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:rPr'); + $this->xmlWriter->startElement('w:rStyle'); + $this->xmlWriter->writeAttribute('w:val', ucfirst($this->referenceType)); + $this->xmlWriter->endElement(); // w:rStyle + $this->xmlWriter->endElement(); // w:rPr + $this->xmlWriter->startElement("w:{$this->referenceType}"); + $this->xmlWriter->writeAttribute('w:id', $this->element->getRelationId()); + $this->xmlWriter->endElement(); // w:$referenceType + $this->xmlWriter->endElement(); // w:r + if (!$this->withoutP) { + $this->xmlWriter->endElement(); // w:p + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Object.php b/src/PhpWord/Writer/Word2007/Element/Object.php new file mode 100644 index 00000000..1a2dfa4a --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Object.php @@ -0,0 +1,69 @@ +element->getRelationId() + ($this->element->isInSection() ? 6 : 0); + $rIdImage = $this->element->getImageRelationId() + ($this->element->isInSection() ? 6 : 0); + $shapeId = md5($rIdObject . '_' . $rIdImage); + $objectId = $this->element->getRelationId() + 1325353440; + $style = $this->element->getStyle(); + $align = $style->getAlign(); + + if (!$this->withoutP) { + $this->xmlWriter->startElement('w:p'); + } + if (!is_null($align)) { + $this->xmlWriter->startElement('w:pPr'); + $this->xmlWriter->startElement('w:jc'); + $this->xmlWriter->writeAttribute('w:val', $align); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + } + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:object'); + $this->xmlWriter->writeAttribute('w:dxaOrig', '249'); + $this->xmlWriter->writeAttribute('w:dyaOrig', '160'); + $this->xmlWriter->startElement('v:shape'); + $this->xmlWriter->writeAttribute('id', $shapeId); + $this->xmlWriter->writeAttribute('type', '#_x0000_t75'); + $this->xmlWriter->writeAttribute('style', 'width:104px;height:67px'); + $this->xmlWriter->writeAttribute('o:ole', ''); + $this->xmlWriter->startElement('v:imagedata'); + $this->xmlWriter->writeAttribute('r:id', 'rId' . $rIdImage); + $this->xmlWriter->writeAttribute('o:title', ''); + $this->xmlWriter->endElement(); // v:imagedata + $this->xmlWriter->endElement(); // v:shape + $this->xmlWriter->startElement('o:OLEObject'); + $this->xmlWriter->writeAttribute('Type', 'Embed'); + $this->xmlWriter->writeAttribute('ProgID', 'Package'); + $this->xmlWriter->writeAttribute('ShapeID', $shapeId); + $this->xmlWriter->writeAttribute('DrawAspect', 'Icon'); + $this->xmlWriter->writeAttribute('ObjectID', '_' . $objectId); + $this->xmlWriter->writeAttribute('r:id', 'rId' . $rIdObject); + $this->xmlWriter->endElement(); // o:OLEObject + $this->xmlWriter->endElement(); // w:object + $this->xmlWriter->endElement(); // w:r + if (!$this->withoutP) { + $this->xmlWriter->endElement(); // w:p + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/PageBreak.php b/src/PhpWord/Writer/Word2007/Element/PageBreak.php new file mode 100644 index 00000000..a6cdd27f --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/PageBreak.php @@ -0,0 +1,32 @@ +xmlWriter->startElement('w:p'); + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:br'); + $this->xmlWriter->writeAttribute('w:type', 'page'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/PreserveText.php b/src/PhpWord/Writer/Word2007/Element/PreserveText.php new file mode 100644 index 00000000..72ff7f1b --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/PreserveText.php @@ -0,0 +1,90 @@ +element->getFontStyle(); + $paragraphStyle = $this->element->getParagraphStyle(); + $texts = $this->element->getText(); + if (!is_array($texts)) { + $texts = array($texts); + } + + $styleWriter = new ParagraphStyleWriter($this->xmlWriter, $paragraphStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:p'); + $styleWriter->write(); + + foreach ($texts as $text) { + if (substr($text, 0, 1) == '{') { + $text = substr($text, 1, -1); + $styleWriter = new FontStyleWriter($this->xmlWriter, $fontStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:r'); + $styleWriter->write(); + $this->xmlWriter->startElement('w:instrText'); + $this->xmlWriter->writeAttribute('xml:space', 'preserve'); + $this->xmlWriter->writeRaw($text); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'separate'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'end'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + } else { + $text = htmlspecialchars($text); + $text = String::controlCharacterPHP2OOXML($text); + $styleWriter = new FontStyleWriter($this->xmlWriter, $fontStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:r'); + $styleWriter->write(); + $this->xmlWriter->startElement('w:t'); + $this->xmlWriter->writeAttribute('xml:space', 'preserve'); + $this->xmlWriter->writeRaw($text); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + } + } + + $this->xmlWriter->endElement(); // p + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/TOC.php b/src/PhpWord/Writer/Word2007/Element/TOC.php new file mode 100644 index 00000000..5be287a3 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/TOC.php @@ -0,0 +1,154 @@ +element->getTitles(); + $fontStyle = $this->element->getStyleFont(); + + $tocStyle = $this->element->getStyleTOC(); + $fIndent = $tocStyle->getIndent(); + $tabLeader = $tocStyle->getTabLeader(); + $tabPos = $tocStyle->getTabPos(); + + $maxDepth = $this->element->getMaxDepth(); + $minDepth = $this->element->getMinDepth(); + + $isObject = ($fontStyle instanceof Font) ? true : false; + + for ($i = 0; $i < count($titles); $i++) { + $title = $titles[$i]; + $indent = ($title['depth'] - 1) * $fIndent; + + $this->xmlWriter->startElement('w:p'); + + $this->xmlWriter->startElement('w:pPr'); + + if ($isObject && !is_null($fontStyle->getParagraphStyle())) { + $styleWriter = new ParagraphStyleWriter($this->xmlWriter, $fontStyle->getParagraphStyle()); + $styleWriter->write(); + } + + if ($indent > 0) { + $this->xmlWriter->startElement('w:ind'); + $this->xmlWriter->writeAttribute('w:left', $indent); + $this->xmlWriter->endElement(); + } + + if (!empty($fontStyle) && !$isObject) { + $this->xmlWriter->startElement('w:pPr'); + $this->xmlWriter->startElement('w:pStyle'); + $this->xmlWriter->writeAttribute('w:val', $fontStyle); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + } + + $this->xmlWriter->startElement('w:tabs'); + $this->xmlWriter->startElement('w:tab'); + $this->xmlWriter->writeAttribute('w:val', 'right'); + if (!empty($tabLeader)) { + $this->xmlWriter->writeAttribute('w:leader', $tabLeader); + } + $this->xmlWriter->writeAttribute('w:pos', $tabPos); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->endElement(); // w:pPr + + + if ($i == 0) { + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:instrText'); + $this->xmlWriter->writeAttribute('xml:space', 'preserve'); + $this->xmlWriter->writeRaw('TOC \o "' . $minDepth . '-' . $maxDepth . '" \h \z \u'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'separate'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + } + + $this->xmlWriter->startElement('w:hyperlink'); + $this->xmlWriter->writeAttribute('w:anchor', $title['anchor']); + $this->xmlWriter->writeAttribute('w:history', '1'); + + $this->xmlWriter->startElement('w:r'); + + if ($isObject) { + $styleWriter = new FontStyleWriter($this->xmlWriter, $fontStyle); + $styleWriter->write(); + } + + $this->xmlWriter->startElement('w:t'); + $this->xmlWriter->writeRaw($title['text']); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->writeElement('w:tab', null); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'begin'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:instrText'); + $this->xmlWriter->writeAttribute('xml:space', 'preserve'); + $this->xmlWriter->writeRaw('PAGEREF ' . $title['anchor'] . ' \h'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'end'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->endElement(); // w:hyperlink + + $this->xmlWriter->endElement(); // w:p + } + + $this->xmlWriter->startElement('w:p'); + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'end'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Table.php b/src/PhpWord/Writer/Word2007/Element/Table.php new file mode 100644 index 00000000..c538561a --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Table.php @@ -0,0 +1,134 @@ +element->getRows(); + $rowCount = count($rows); + + if ($rowCount > 0) { + $this->xmlWriter->startElement('w:tbl'); + + // Table grid + $cellWidths = array(); + for ($i = 0; $i < $rowCount; $i++) { + $row = $rows[$i]; + $cells = $row->getCells(); + if (count($cells) <= count($cellWidths)) { + continue; + } + $cellWidths = array(); + foreach ($cells as $cell) { + $cellWidths[] = $cell->getWidth(); + } + } + $this->xmlWriter->startElement('w:tblGrid'); + foreach ($cellWidths as $width) { + $this->xmlWriter->startElement('w:gridCol'); + if (!is_null($width)) { + $this->xmlWriter->writeAttribute('w:w', $width); + $this->xmlWriter->writeAttribute('w:type', 'dxa'); + } + $this->xmlWriter->endElement(); + } + $this->xmlWriter->endElement(); // w:tblGrid + + // Table style + $tblStyle = $this->element->getStyle(); + $tblWidth = $this->element->getWidth(); + if ($tblStyle instanceof TableStyle) { + $styleWriter = new TableStyleWriter($this->xmlWriter, $tblStyle); + $styleWriter->setIsFullStyle(false); + $styleWriter->write(); + } else { + if (!empty($tblStyle)) { + $this->xmlWriter->startElement('w:tblPr'); + $this->xmlWriter->startElement('w:tblStyle'); + $this->xmlWriter->writeAttribute('w:val', $tblStyle); + $this->xmlWriter->endElement(); + if (!is_null($tblWidth)) { + $this->xmlWriter->startElement('w:tblW'); + $this->xmlWriter->writeAttribute('w:w', $tblWidth); + $this->xmlWriter->writeAttribute('w:type', 'pct'); + $this->xmlWriter->endElement(); + } + $this->xmlWriter->endElement(); + } + } + + // Table rows + for ($i = 0; $i < $rowCount; $i++) { + $row = $rows[$i]; + $height = $row->getHeight(); + $rowStyle = $row->getStyle(); + $tblHeader = $rowStyle->getTblHeader(); + $cantSplit = $rowStyle->getCantSplit(); + $exactHeight = $rowStyle->getExactHeight(); + + $this->xmlWriter->startElement('w:tr'); + if (!is_null($height) || !is_null($tblHeader) || !is_null($cantSplit)) { + $this->xmlWriter->startElement('w:trPr'); + if (!is_null($height)) { + $this->xmlWriter->startElement('w:trHeight'); + $this->xmlWriter->writeAttribute('w:val', $height); + $this->xmlWriter->writeAttribute('w:hRule', ($exactHeight ? 'exact' : 'atLeast')); + $this->xmlWriter->endElement(); + } + if ($tblHeader) { + $this->xmlWriter->startElement('w:tblHeader'); + $this->xmlWriter->writeAttribute('w:val', '1'); + $this->xmlWriter->endElement(); + } + if ($cantSplit) { + $this->xmlWriter->startElement('w:cantSplit'); + $this->xmlWriter->writeAttribute('w:val', '1'); + $this->xmlWriter->endElement(); + } + $this->xmlWriter->endElement(); + } + foreach ($row->getCells() as $cell) { + $cellStyle = $cell->getStyle(); + $width = $cell->getWidth(); + $this->xmlWriter->startElement('w:tc'); + $this->xmlWriter->startElement('w:tcPr'); + $this->xmlWriter->startElement('w:tcW'); + $this->xmlWriter->writeAttribute('w:w', $width); + $this->xmlWriter->writeAttribute('w:type', 'dxa'); + $this->xmlWriter->endElement(); // w:tcW + if ($cellStyle instanceof Cell) { + $styleWriter = new CellStyleWriter($this->xmlWriter, $cellStyle); + $styleWriter->write(); + } + $this->xmlWriter->endElement(); // w:tcPr + $this->parentWriter->writeContainerElements($this->xmlWriter, $cell); + $this->xmlWriter->endElement(); // w:tc + } + $this->xmlWriter->endElement(); // w:tr + } + $this->xmlWriter->endElement(); + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Text.php b/src/PhpWord/Writer/Word2007/Element/Text.php new file mode 100644 index 00000000..99ad4953 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Text.php @@ -0,0 +1,54 @@ +element->getFontStyle(); + $paragraphStyle = $this->element->getParagraphStyle(); + $text = htmlspecialchars($this->element->getText()); + $text = String::controlCharacterPHP2OOXML($text); + + if (!$this->withoutP) { + $styleWriter = new ParagraphStyleWriter($this->xmlWriter, $paragraphStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:p'); + $styleWriter->write(); + } + $styleWriter = new FontStyleWriter($this->xmlWriter, $fontStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:r'); + $styleWriter->write(); + $this->xmlWriter->startElement('w:t'); + $this->xmlWriter->writeAttribute('xml:space', 'preserve'); + $this->xmlWriter->writeRaw($text); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); // w:r + if (!$this->withoutP) { + $this->xmlWriter->endElement(); // w:p + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/TextBreak.php b/src/PhpWord/Writer/Word2007/Element/TextBreak.php new file mode 100644 index 00000000..008e1e12 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/TextBreak.php @@ -0,0 +1,58 @@ +withoutP) { + $hasStyle = false; + $fontStyle = null; + $paragraphStyle = null; + if (!is_null($this->element)) { + $fontStyle = $this->element->getFontStyle(); + $paragraphStyle = $this->element->getParagraphStyle(); + $hasStyle = !is_null($fontStyle) || !is_null($paragraphStyle); + } + if ($hasStyle) { + $styleWriter = new ParagraphStyleWriter($this->xmlWriter, $paragraphStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:p'); + $styleWriter->write(); + if (!is_null($fontStyle)) { + $styleWriter = new FontStyleWriter($this->xmlWriter, $fontStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:pPr'); + $styleWriter->write(); + $this->xmlWriter->endElement(); // w:pPr + } + $this->xmlWriter->endElement(); // w:p + } else { + $this->xmlWriter->writeElement('w:p'); + } + } else { + $this->xmlWriter->writeElement('w:br'); + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/TextRun.php b/src/PhpWord/Writer/Word2007/Element/TextRun.php new file mode 100644 index 00000000..f23ef693 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/TextRun.php @@ -0,0 +1,35 @@ +element->getParagraphStyle(); + $styleWriter = new ParagraphStyleWriter($this->xmlWriter, $paragraphStyle); + $styleWriter->setIsInline(true); + + $this->xmlWriter->startElement('w:p'); + $styleWriter->write(); + $this->parentWriter->writeContainerElements($this->xmlWriter, $this->element); + $this->xmlWriter->endElement(); // w:p + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Title.php b/src/PhpWord/Writer/Word2007/Element/Title.php new file mode 100644 index 00000000..5570921f --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Element/Title.php @@ -0,0 +1,65 @@ +element->getAnchor(); + $bookmarkId = $this->element->getBookmarkId(); + $style = $this->element->getStyle(); + $text = htmlspecialchars($this->element->getText()); + $text = String::controlCharacterPHP2OOXML($text); + + $this->xmlWriter->startElement('w:p'); + + if (!empty($style)) { + $this->xmlWriter->startElement('w:pPr'); + $this->xmlWriter->startElement('w:pStyle'); + $this->xmlWriter->writeAttribute('w:val', $style); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + } + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:fldChar'); + $this->xmlWriter->writeAttribute('w:fldCharType', 'end'); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:bookmarkStart'); + $this->xmlWriter->writeAttribute('w:id', $bookmarkId); + $this->xmlWriter->writeAttribute('w:name', $anchor); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->startElement('w:t'); + $this->xmlWriter->writeRaw($text); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + + $this->xmlWriter->startElement('w:bookmarkEnd'); + $this->xmlWriter->writeAttribute('w:id', $bookmarkId); + $this->xmlWriter->endElement(); + + $this->xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Footer.php b/src/PhpWord/Writer/Word2007/Footer.php deleted file mode 100644 index 0ae8b9ea..00000000 --- a/src/PhpWord/Writer/Word2007/Footer.php +++ /dev/null @@ -1,93 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - $xmlWriter->startElement('w:ftr'); - $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); - $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); - $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); - $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); - $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); - $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); - $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); - $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); - $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); - - $_elements = $footer->getElements(); - - foreach ($_elements as $element) { - if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); - } elseif ($element instanceof Table) { - $this->_writeTable($xmlWriter, $element); - } elseif ($element instanceof Image) { - $this->_writeImage($xmlWriter, $element); - } elseif ($element instanceof PreserveText) { - $this->_writePreserveText($xmlWriter, $element); - } - } - - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } -} diff --git a/src/PhpWord/Writer/Word2007/Footnotes.php b/src/PhpWord/Writer/Word2007/Footnotes.php deleted file mode 100644 index d1545639..00000000 --- a/src/PhpWord/Writer/Word2007/Footnotes.php +++ /dev/null @@ -1,92 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - $xmlWriter->startElement('w:footnotes'); - $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); - $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); - - // write separator and continuation separator - $xmlWriter->startElement('w:footnote'); - $xmlWriter->writeAttribute('w:id', 0); - $xmlWriter->writeAttribute('w:type', 'separator'); - $xmlWriter->startElement('w:p'); - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:separator'); - $xmlWriter->endElement(); // w:separator - $xmlWriter->endElement(); // w:r - $xmlWriter->endElement(); // w:p - $xmlWriter->endElement(); // w:footnote - - $xmlWriter->startElement('w:footnote'); - $xmlWriter->writeAttribute('w:id', 1); - $xmlWriter->writeAttribute('w:type', 'continuationSeparator'); - $xmlWriter->startElement('w:p'); - $xmlWriter->startElement('w:r'); - $xmlWriter->startElement('w:continuationSeparator'); - $xmlWriter->endElement(); // w:continuationSeparator - $xmlWriter->endElement(); // w:r - $xmlWriter->endElement(); // w:p - $xmlWriter->endElement(); // w:footnote - - foreach ($allFootnotesCollection as $footnote) { - if ($footnote instanceof Footnote) { - $this->_writeFootnote($xmlWriter, $footnote); - } - } - - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } -} diff --git a/src/PhpWord/Writer/Word2007/FootnotesRels.php b/src/PhpWord/Writer/Word2007/FootnotesRels.php deleted file mode 100644 index 9a9b53b0..00000000 --- a/src/PhpWord/Writer/Word2007/FootnotesRels.php +++ /dev/null @@ -1,105 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // Relationships - $xmlWriter->startElement('Relationships'); - $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - - // Relationships to Links - foreach ($_relsCollection as $relation) { - $relationType = $relation['type']; - $relationName = $relation['target']; - $relationId = $relation['rID']; - $targetMode = ($relationType == 'hyperlink') ? 'External' : ''; - - $this->_writeRelationship($xmlWriter, $relationId, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/' . $relationType, $relationName, $targetMode); - } - - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } - - /** - * Write individual rels entry - * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param int $pId Relationship ID - * @param string $pType Relationship type - * @param string $pTarget Relationship target - * @param string $pTargetMode Relationship target mode - */ - private function _writeRelationship(XMLWriter $xmlWriter = null, $pId = 1, $pType = '', $pTarget = '', $pTargetMode = '') - { - if ($pType != '' && $pTarget != '') { - if (strpos($pId, 'rId') === false) { - $pId = 'rId' . $pId; - } - - // Write relationship - $xmlWriter->startElement('Relationship'); - $xmlWriter->writeAttribute('Id', $pId); - $xmlWriter->writeAttribute('Type', $pType); - $xmlWriter->writeAttribute('Target', $pTarget); - - if ($pTargetMode != '') { - $xmlWriter->writeAttribute('TargetMode', $pTargetMode); - } - - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } -} diff --git a/src/PhpWord/Writer/Word2007/Header.php b/src/PhpWord/Writer/Word2007/Header.php deleted file mode 100644 index 9ca69196..00000000 --- a/src/PhpWord/Writer/Word2007/Header.php +++ /dev/null @@ -1,97 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - $xmlWriter->startElement('w:hdr'); - $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); - $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); - $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); - $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); - $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); - $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); - $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); - $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); - $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); - - - $_elements = $header->getElements(); - - foreach ($_elements as $element) { - if ($element instanceof Text) { - $this->_writeText($xmlWriter, $element); - } elseif ($element instanceof TextRun) { - $this->_writeTextRun($xmlWriter, $element); - } elseif ($element instanceof TextBreak) { - $this->_writeTextBreak($xmlWriter, $element); - } elseif ($element instanceof Table) { - $this->_writeTable($xmlWriter, $element); - } elseif ($element instanceof Image) { - if (!$element->getIsWatermark()) { - $this->_writeImage($xmlWriter, $element); - } else { - $this->_writeWatermark($xmlWriter, $element); - } - } elseif ($element instanceof PreserveText) { - $this->_writePreserveText($xmlWriter, $element); - } - } - - $xmlWriter->endElement(); - - // Return - return $xmlWriter->getData(); - } -} diff --git a/src/PhpWord/Writer/Word2007/Part/AbstractPart.php b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php new file mode 100644 index 00000000..afa84caf --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/AbstractPart.php @@ -0,0 +1,120 @@ +parentWriter = $pWriter; + } + + /** + * Get parent writer + * + * @return \PhpOffice\PhpWord\Writer\WriterInterface + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + public function getParentWriter() + { + if (!is_null($this->parentWriter)) { + return $this->parentWriter; + } else { + throw new Exception("No parent WriterInterface assigned."); + } + } + + /** + * Get XML Writer + * + * @return \PhpOffice\PhpWord\Shared\XMLWriter + */ + protected function getXmlWriter() + { + $useDiskCaching = false; + if (!is_null($this->parentWriter)) { + if ($this->parentWriter->getUseDiskCaching()) { + $useDiskCaching = true; + } + } + if ($useDiskCaching) { + return new XMLWriter(XMLWriter::STORAGE_DISK, $this->parentWriter->getDiskCachingDirectory()); + } else { + return new XMLWriter(XMLWriter::STORAGE_MEMORY); + } + } + + /** + * Write container elements + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\AbstractElement $container + */ + public function writeContainerElements(XMLWriter $xmlWriter, AbstractElement $container) + { + // Check allowed elements + $elmCommon = array('Text', 'Link', 'TextBreak', 'Image', 'Object'); + $elmMainCell = array_merge($elmCommon, array('TextRun', 'ListItem', 'CheckBox')); + $allowedElements = array( + 'Section' => array_merge($elmMainCell, array('Table', 'Footnote', 'Title', 'PageBreak', 'TOC')), + 'Header' => array_merge($elmMainCell, array('Table', 'PreserveText')), + 'Footer' => array_merge($elmMainCell, array('Table', 'PreserveText')), + 'Cell' => array_merge($elmMainCell, array('PreserveText', 'Footnote', 'Endnote')), + 'TextRun' => array_merge($elmCommon, array('Footnote', 'Endnote')), + 'Footnote' => $elmCommon, + 'Endnote' => $elmCommon, + ); + $containerName = get_class($container); + $containerName = substr($containerName, strrpos($containerName, '\\') + 1); + if (!array_key_exists($containerName, $allowedElements)) { + throw new Exception('Invalid container.'); + } + + // Loop through elements + $elements = $container->getElements(); + $withoutP = in_array($containerName, array('TextRun', 'Footnote', 'Endnote')) ? true : false; + if (count($elements) > 0) { + foreach ($elements as $element) { + if ($element instanceof AbstractElement) { + $elementWriter = new ElementWriter($xmlWriter, $this, $element, $withoutP); + $elementWriter->write(); + } + } + } else { + if ($containerName == 'Cell') { + $elementWriter = new ElementWriter($xmlWriter, $this, new TextBreak(), $withoutP); + $elementWriter->write(); + } + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/ContentTypes.php b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php new file mode 100644 index 00000000..00e05c76 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/ContentTypes.php @@ -0,0 +1,85 @@ + $OpenXMLPrefix . 'package.core-properties+xml', + '/docProps/app.xml' => $OpenXMLPrefix . 'officedocument.extended-properties+xml', + '/word/document.xml' => $WordMLPrefix . 'document.main+xml', + '/word/styles.xml' => $WordMLPrefix . 'styles+xml', + '/word/numbering.xml' => $WordMLPrefix . 'numbering+xml', + '/word/settings.xml' => $WordMLPrefix . 'settings+xml', + '/word/theme/theme1.xml' => $OpenXMLPrefix . 'officedocument.theme+xml', + '/word/webSettings.xml' => $WordMLPrefix . 'webSettings+xml', + '/word/fontTable.xml' => $WordMLPrefix . 'fontTable+xml', + ); + + $defaults = $contentTypes['default']; + if (!empty($contentTypes['override'])) { + foreach ($contentTypes['override'] as $key => $val) { + $overrides[$key] = $WordMLPrefix . $val . '+xml'; + } + } + + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('Types'); + $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/content-types'); + + $this->writeContentType($xmlWriter, $defaults, true); + $this->writeContentType($xmlWriter, $overrides, false); + + $xmlWriter->endElement(); // Types + + return $xmlWriter->getData(); + } + + /** + * Write content types element + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter XML Writer + * @param array $parts + * @param boolean $isDefault + * @throws \PhpOffice\PhpWord\Exception\Exception + */ + private function writeContentType(XMLWriter $xmlWriter, $parts, $isDefault) + { + foreach ($parts as $partName => $contentType) { + if ($partName != '' && $contentType != '') { + $partType = $isDefault ? 'Default' : 'Override'; + $partAttribute = $isDefault ? 'Extension' : 'PartName'; + $xmlWriter->startElement($partType); + $xmlWriter->writeAttribute($partAttribute, $partName); + $xmlWriter->writeAttribute('ContentType', $contentType); + $xmlWriter->endElement(); + } else { + throw new Exception("Invalid parameters passed."); + } + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/DocProps.php b/src/PhpWord/Writer/Word2007/Part/DocProps.php new file mode 100644 index 00000000..ade15c0a --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/DocProps.php @@ -0,0 +1,89 @@ +getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('Properties'); + $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties'); + $xmlWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'); + + $xmlWriter->writeElement('Application', 'PHPWord'); + $xmlWriter->writeElement('Company', $phpWord->getDocumentProperties()->getCompany()); + $xmlWriter->writeElement('Manager', $phpWord->getDocumentProperties()->getManager()); + + $xmlWriter->endElement(); // Properties + + return $xmlWriter->getData(); + } + + + /** + * Write docProps/core.xml + * + * @param \PhpOffice\PhpWord\PhpWord $phpWord + */ + public function writeDocPropsCore(PhpWord $phpWord = null) + { + if (is_null($phpWord)) { + throw new Exception("No PhpWord assigned."); + } + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('cp:coreProperties'); + $xmlWriter->writeAttribute('xmlns:cp', 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties'); + $xmlWriter->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/'); + $xmlWriter->writeAttribute('xmlns:dcterms', 'http://purl.org/dc/terms/'); + $xmlWriter->writeAttribute('xmlns:dcmitype', 'http://purl.org/dc/dcmitype/'); + $xmlWriter->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance'); + + $xmlWriter->writeElement('dc:creator', $phpWord->getDocumentProperties()->getCreator()); + $xmlWriter->writeElement('dc:title', $phpWord->getDocumentProperties()->getTitle()); + $xmlWriter->writeElement('dc:description', $phpWord->getDocumentProperties()->getDescription()); + $xmlWriter->writeElement('dc:subject', $phpWord->getDocumentProperties()->getSubject()); + $xmlWriter->writeElement('cp:keywords', $phpWord->getDocumentProperties()->getKeywords()); + $xmlWriter->writeElement('cp:category', $phpWord->getDocumentProperties()->getCategory()); + $xmlWriter->writeElement('cp:lastModifiedBy', $phpWord->getDocumentProperties()->getLastModifiedBy()); + + // dcterms:created + $xmlWriter->startElement('dcterms:created'); + $xmlWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); + $xmlWriter->writeRaw(date(DATE_W3C, $phpWord->getDocumentProperties()->getCreated())); + $xmlWriter->endElement(); + + // dcterms:modified + $xmlWriter->startElement('dcterms:modified'); + $xmlWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF'); + $xmlWriter->writeRaw(date(DATE_W3C, $phpWord->getDocumentProperties()->getModified())); + $xmlWriter->endElement(); + + $xmlWriter->endElement(); // cp:coreProperties + + return $xmlWriter->getData(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Document.php b/src/PhpWord/Writer/Word2007/Part/Document.php new file mode 100644 index 00000000..535784b8 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/Document.php @@ -0,0 +1,128 @@ +getXmlWriter(); + $sections = $phpWord->getSections(); + $sectionCount = count($sections); + $currentSection = 0; + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('w:document'); + $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); + $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); + $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); + $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); + + $xmlWriter->startElement('w:body'); + + + if ($sectionCount > 0) { + foreach ($sections as $section) { + $currentSection++; + $this->writeContainerElements($xmlWriter, $section); + if ($currentSection == $sectionCount) { + $this->writeSectionSettings($xmlWriter, $section); + } else { + $this->writeSection($xmlWriter, $section); + } + } + } + + $xmlWriter->endElement(); // w:body + $xmlWriter->endElement(); // w:document + + return $xmlWriter->getData(); + } + + /** + * Write begin section + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Section $section + */ + private function writeSection(XMLWriter $xmlWriter, Section $section) + { + $xmlWriter->startElement('w:p'); + $xmlWriter->startElement('w:pPr'); + $this->writeSectionSettings($xmlWriter, $section); + $xmlWriter->endElement(); + $xmlWriter->endElement(); + } + + /** + * Write end section + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Section $section + */ + private function writeSectionSettings(XMLWriter $xmlWriter, Section $section) + { + $xmlWriter->startElement('w:sectPr'); + + // Header reference + foreach ($section->getHeaders() as $header) { + $rId = $header->getRelationId(); + $xmlWriter->startElement('w:headerReference'); + $xmlWriter->writeAttribute('w:type', $header->getType()); + $xmlWriter->writeAttribute('r:id', 'rId' . $rId); + $xmlWriter->endElement(); + } + + // Footer reference + foreach ($section->getFooters() as $footer) { + $rId = $footer->getRelationId(); + $xmlWriter->startElement('w:footerReference'); + $xmlWriter->writeAttribute('w:type', $footer->getType()); + $xmlWriter->writeAttribute('r:id', 'rId' . $rId); + $xmlWriter->endElement(); + } + + // Different first page + if ($section->hasDifferentFirstPage()) { + $xmlWriter->startElement('w:titlePg'); + $xmlWriter->endElement(); + } + + // Section settings + $styleWriter = new SectionStyleWriter($xmlWriter, $section->getSettings()); + $styleWriter->write(); + + $xmlWriter->endElement(); // w:sectPr + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Endnotes.php b/src/PhpWord/Writer/Word2007/Part/Endnotes.php new file mode 100644 index 00000000..9cecf402 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/Endnotes.php @@ -0,0 +1,44 @@ + - \ No newline at end of file + +'; + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Footer.php b/src/PhpWord/Writer/Word2007/Part/Footer.php new file mode 100644 index 00000000..f31ece86 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/Footer.php @@ -0,0 +1,46 @@ +getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('w:ftr'); + $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); + $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); + $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); + $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); + + $this->writeContainerElements($xmlWriter, $footer); + + $xmlWriter->endElement(); // w:ftr + + return $xmlWriter->getData(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Footnotes.php b/src/PhpWord/Writer/Word2007/Part/Footnotes.php new file mode 100644 index 00000000..2356849e --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/Footnotes.php @@ -0,0 +1,144 @@ +getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement($this->rootNode); + $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); + $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); + $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); + $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); + + // Separator and continuation separator + $xmlWriter->startElement($this->elementNode); + $xmlWriter->writeAttribute('w:id', -1); + $xmlWriter->writeAttribute('w:type', 'separator'); + $xmlWriter->startElement('w:p'); + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:separator'); + $xmlWriter->endElement(); // w:separator + $xmlWriter->endElement(); // w:r + $xmlWriter->endElement(); // w:p + $xmlWriter->endElement(); // $this->elementNode + $xmlWriter->startElement($this->elementNode); + $xmlWriter->writeAttribute('w:id', 0); + $xmlWriter->writeAttribute('w:type', 'continuationSeparator'); + $xmlWriter->startElement('w:p'); + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:continuationSeparator'); + $xmlWriter->endElement(); // w:continuationSeparator + $xmlWriter->endElement(); // w:r + $xmlWriter->endElement(); // w:p + $xmlWriter->endElement(); // $this->elementNode + + // Content + foreach ($elements as $element) { + if ($element instanceof Footnote) { + $this->writeNote($xmlWriter, $element); + } + } + + $xmlWriter->endElement(); // $this->rootNode + + return $xmlWriter->getData(); + } + + /** + * Write note item + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Element\Footnote|\PhpOffice\PhpWord\Element\Endnote $element + */ + protected function writeNote(XMLWriter $xmlWriter, $element) + { + $xmlWriter->startElement($this->elementNode); + $xmlWriter->writeAttribute('w:id', $element->getRelationId()); + $xmlWriter->startElement('w:p'); + + // Paragraph style + $styleWriter = new ParagraphStyleWriter($xmlWriter, $element->getParagraphStyle()); + $styleWriter->setIsInline(true); + $styleWriter->write(); + + // Reference symbol + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rStyle'); + $xmlWriter->writeAttribute('w:val', $this->refStyle); + $xmlWriter->endElement(); // w:rStyle + $xmlWriter->endElement(); // w:rPr + $xmlWriter->writeElement($this->refNode); + $xmlWriter->endElement(); // w:r + + // Empty space after refence symbol + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:t'); + $xmlWriter->writeAttribute('xml:space', 'preserve'); + $xmlWriter->writeRaw(' '); + $xmlWriter->endElement(); // w:t + $xmlWriter->endElement(); // w:r + + $this->writeContainerElements($xmlWriter, $element); + + $xmlWriter->endElement(); // w:p + $xmlWriter->endElement(); // $this->elementNode + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Header.php b/src/PhpWord/Writer/Word2007/Part/Header.php new file mode 100644 index 00000000..d2af19da --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/Header.php @@ -0,0 +1,46 @@ +getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('w:hdr'); + $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); + $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); + $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); + $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); + + $this->writeContainerElements($xmlWriter, $header); + + $xmlWriter->endElement(); // w:hdr + + return $xmlWriter->getData(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Numbering.php b/src/PhpWord/Writer/Word2007/Part/Numbering.php new file mode 100644 index 00000000..ea1b699b --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/Numbering.php @@ -0,0 +1,177 @@ +getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('w:numbering'); + $xmlWriter->writeAttribute('xmlns:ve', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); + $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); + $xmlWriter->writeAttribute('xmlns:wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'); + $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:wne', 'http://schemas.microsoft.com/office/word/2006/wordml'); + + // Abstract numbering definitions + foreach ($styles as $style) { + if ($style instanceof NumberingStyle) { + $levels = $style->getLevels(); + + $xmlWriter->startElement('w:abstractNum'); + $xmlWriter->writeAttribute('w:abstractNumId', $style->getNumId()); + + $xmlWriter->startElement('w:nsid'); + $xmlWriter->writeAttribute('w:val', $this->getRandomHexNumber()); + $xmlWriter->endElement(); // w:nsid + + $xmlWriter->startElement('w:multiLevelType'); + $xmlWriter->writeAttribute('w:val', $style->getType()); + $xmlWriter->endElement(); // w:multiLevelType + + if (is_array($levels)) { + foreach ($levels as $levelNum => $levelObject) { + if ($levelObject instanceof NumberingLevel) { + $start = $levelObject->getStart(); + $format = $levelObject->getFormat(); + $restart = $levelObject->getRestart(); + $suffix = $levelObject->getSuffix(); + $text = $levelObject->getText(); + $align = $levelObject->getAlign(); + $tabPos = $levelObject->getTabPos(); + $left = $levelObject->getLeft(); + $hanging = $levelObject->getHanging(); + $font = $levelObject->getFont(); + $hint = $levelObject->getHint(); + + $xmlWriter->startElement('w:lvl'); + $xmlWriter->writeAttribute('w:ilvl', $levelNum); + + if (!is_null($start)) { + $xmlWriter->startElement('w:start'); + $xmlWriter->writeAttribute('w:val', $start); + $xmlWriter->endElement(); // w:start + } + if (!is_null($format)) { + $xmlWriter->startElement('w:numFmt'); + $xmlWriter->writeAttribute('w:val', $format); + $xmlWriter->endElement(); // w:numFmt + } + if (!is_null($restart)) { + $xmlWriter->startElement('w:lvlRestart'); + $xmlWriter->writeAttribute('w:val', $restart); + $xmlWriter->endElement(); // w:lvlRestart + } + if (!is_null($suffix)) { + $xmlWriter->startElement('w:suff'); + $xmlWriter->writeAttribute('w:val', $suffix); + $xmlWriter->endElement(); // w:suff + } + if (!is_null($text)) { + $xmlWriter->startElement('w:lvlText'); + $xmlWriter->writeAttribute('w:val', $text); + $xmlWriter->endElement(); // w:start + } + if (!is_null($align)) { + $xmlWriter->startElement('w:lvlJc'); + $xmlWriter->writeAttribute('w:val', $align); + $xmlWriter->endElement(); // w:lvlJc + } + if (!is_null($tabPos) || !is_null($left) || !is_null($hanging)) { + $xmlWriter->startElement('w:pPr'); + if (!is_null($tabPos)) { + $xmlWriter->startElement('w:tabs'); + $xmlWriter->startElement('w:tab'); + $xmlWriter->writeAttribute('w:val', 'num'); + $xmlWriter->writeAttribute('w:pos', $tabPos); + $xmlWriter->endElement(); // w:tab + $xmlWriter->endElement(); // w:tabs + } + if (!is_null($left) || !is_null($hanging)) { + $xmlWriter->startElement('w:ind'); + if (!is_null($left)) { + $xmlWriter->writeAttribute('w:left', $left); + } + if (!is_null($hanging)) { + $xmlWriter->writeAttribute('w:hanging', $hanging); + } + $xmlWriter->endElement(); // w:ind + } + $xmlWriter->endElement(); // w:pPr + } + if (!is_null($font) || !is_null($hint)) { + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:rFonts'); + if (!is_null($font)) { + $xmlWriter->writeAttribute('w:ascii', $font); + $xmlWriter->writeAttribute('w:hAnsi', $font); + $xmlWriter->writeAttribute('w:cs', $font); + } + if (!is_null($hint)) { + $xmlWriter->writeAttribute('w:hint', $hint); + } + $xmlWriter->endElement(); // w:rFonts + $xmlWriter->endElement(); // w:rPr + } + $xmlWriter->endElement(); // w:lvl + } + } + } + $xmlWriter->endElement(); // w:abstractNum + } + } + + // Numbering definition instances + foreach ($styles as $style) { + if ($style instanceof NumberingStyle) { + $xmlWriter->startElement('w:num'); + $xmlWriter->writeAttribute('w:numId', $style->getNumId()); + $xmlWriter->startElement('w:abstractNumId'); + $xmlWriter->writeAttribute('w:val', $style->getNumId()); + $xmlWriter->endElement(); // w:abstractNumId + $xmlWriter->endElement(); // w:num + } + } + + $xmlWriter->endElement(); // w:numbering + + return $xmlWriter->getData(); + } + + /** + * Get random hexadecimal number value + * + * @param int $length + * @return string + */ + private function getRandomHexNumber($length = 8) + { + return strtoupper(substr(md5(rand()), 0, $length)); + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Rels.php b/src/PhpWord/Writer/Word2007/Part/Rels.php new file mode 100644 index 00000000..8771b0f6 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/Rels.php @@ -0,0 +1,145 @@ + 'package/2006/relationships/metadata/core-properties', + 'docProps/app.xml' => 'officeDocument/2006/relationships/extended-properties', + 'word/document.xml' => 'officeDocument/2006/relationships/officeDocument', + ); + $xmlWriter = $this->getXmlWriter(); + $this->writeRels($xmlWriter, $xmlRels); + + return $xmlWriter->getData(); + } + + /** + * Write word/_rels/document.xml.rels + * + * @param array $mediaRels + */ + public function writeDocRels($mediaRels) + { + $xmlRels = array( + 'styles.xml' => 'officeDocument/2006/relationships/styles', + 'numbering.xml' => 'officeDocument/2006/relationships/numbering', + 'settings.xml' => 'officeDocument/2006/relationships/settings', + 'theme/theme1.xml' => 'officeDocument/2006/relationships/theme', + 'webSettings.xml' => 'officeDocument/2006/relationships/webSettings', + 'fontTable.xml' => 'officeDocument/2006/relationships/fontTable', + ); + $xmlWriter = $this->getXmlWriter(); + $this->writeRels($xmlWriter, $xmlRels, $mediaRels); + + return $xmlWriter->getData(); + } + + /** + * Write word/_rels/(header|footer|footnotes)*.xml.rels + * + * @param array $mediaRels + */ + public function writeMediaRels($mediaRels) + { + $xmlWriter = $this->getXmlWriter(); + $this->writeRels($xmlWriter, null, $mediaRels); + + return $xmlWriter->getData(); + } + + /** + * Write relationships + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param null|array $xmlRels + * @param null|array $mediaRels + * @param integer $relId + */ + private function writeRels(XMLWriter $xmlWriter, $xmlRels = null, $mediaRels = null, $relId = 1) + { + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('Relationships'); + $xmlWriter->writeAttribute('xmlns', self::RELS_BASE . 'package/2006/relationships'); + + // XML files relationships + if (is_array($xmlRels)) { + foreach ($xmlRels as $target => $type) { + $this->writeRel($xmlWriter, $relId++, $type, $target); + } + } + + // Media relationships + if (!is_null($mediaRels) && is_array($mediaRels)) { + $mapping = array('image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink'); + $targetPaths = array('image' => 'media/', 'object' => 'embeddings/'); + foreach ($mediaRels as $mediaRel) { + $mediaType = $mediaRel['type']; + $type = array_key_exists($mediaType, $mapping) ? $mapping[$mediaType] : $mediaType; + $target = array_key_exists($mediaType, $targetPaths) ? $targetPaths[$mediaType] : ''; + $target .= $mediaRel['target']; + $targetMode = ($type == 'hyperlink') ? 'External' : ''; + $this->writeRel($xmlWriter, $relId++, "officeDocument/2006/relationships/{$type}", $target, $targetMode); + } + } + + $xmlWriter->endElement(); // Relationships + } + + /** + * Write individual rels entry + * + * Format: + * + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param int $relId Relationship ID + * @param string $type Relationship type + * @param string $target Relationship target + * @param string $targetMode Relationship target mode + */ + private function writeRel(XMLWriter $xmlWriter, $relId, $type, $target, $targetMode = '') + { + if ($type != '' && $target != '') { + if (strpos($relId, 'rId') === false) { + $relId = 'rId' . $relId; + } + $xmlWriter->startElement('Relationship'); + $xmlWriter->writeAttribute('Id', $relId); + $xmlWriter->writeAttribute('Type', self::RELS_BASE . $type); + $xmlWriter->writeAttribute('Target', $target); + if ($targetMode != '') { + $xmlWriter->writeAttribute('TargetMode', $targetMode); + } + $xmlWriter->endElement(); + } else { + throw new Exception("Invalid parameters passed."); + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/Settings.php b/src/PhpWord/Writer/Word2007/Part/Settings.php new file mode 100644 index 00000000..81a59679 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/Settings.php @@ -0,0 +1,133 @@ + array('@attributes' => array('w:percent' => '100')), + 'w:embedSystemFonts' => '', + 'w:defaultTabStop' => array('@attributes' => array('w:val' => '708')), + 'w:hyphenationZone' => array('@attributes' => array('w:val' => '425')), + 'w:doNotHyphenateCaps' => '', + 'w:characterSpacingControl' => array('@attributes' => array('w:val' => 'doNotCompress')), + 'w:doNotValidateAgainstSchema' => '', + 'w:doNotDemarcateInvalidXml' => '', + 'w:compat' => array( + 'w:useNormalStyleForList' => '', + 'w:doNotUseIndentAsNumberingTabStop' => '', + 'w:useAltKinsokuLineBreakRules' => '', + 'w:allowSpaceOfSameStyleInTable' => '', + 'w:doNotSuppressIndentation' => '', + 'w:doNotAutofitConstrainedTables' => '', + 'w:autofitToFirstFixedWidthCell' => '', + 'w:underlineTabInNumList' => '', + 'w:displayHangulFixedWidth' => '', + 'w:splitPgBreakAndParaMark' => '', + 'w:doNotVertAlignCellWithSp' => '', + 'w:doNotBreakConstrainedForcedTable' => '', + 'w:doNotVertAlignInTxbx' => '', + 'w:useAnsiKerningPairs' => '', + 'w:cachedColBalance' => '', + ), + 'm:mathPr' => array( + 'm:mathFont' => array('@attributes' => array('m:val' => 'Cambria Math')), + 'm:brkBin' => array('@attributes' => array('m:val' => 'before')), + 'm:brkBinSub' => array('@attributes' => array('m:val' => '--')), + 'm:smallFrac' => array('@attributes' => array('m:val' => 'off')), + 'm:dispDef' => '', + 'm:lMargin' => array('@attributes' => array('m:val' => '0')), + 'm:rMargin' => array('@attributes' => array('m:val' => '0')), + 'm:defJc' => array('@attributes' => array('m:val' => 'centerGroup')), + 'm:wrapIndent' => array('@attributes' => array('m:val' => '1440')), + 'm:intLim' => array('@attributes' => array('m:val' => 'subSup')), + 'm:naryLim' => array('@attributes' => array('m:val' => 'undOvr')), + ), + 'w:uiCompat97To2003' => '', + 'w:themeFontLang' => array('@attributes' => array('w:val' => 'de-DE')), + 'w:clrSchemeMapping' => array( + '@attributes' => array( + 'w:bg1' => 'light1', + 'w:t1' => 'dark1', + 'w:bg2' => 'light2', + 'w:t2' => 'dark2', + 'w:accent1' => 'accent1', + 'w:accent2' => 'accent2', + 'w:accent3' => 'accent3', + 'w:accent4' => 'accent4', + 'w:accent5' => 'accent5', + 'w:accent6' => 'accent6', + 'w:hyperlink' => 'hyperlink', + 'w:followedHyperlink' => 'followedHyperlink', + ), + ), + 'w:doNotIncludeSubdocsInStats' => '', + 'w:doNotAutoCompressPictures' => '', + 'w:decimalSymbol' => array('@attributes' => array('w:val' => ',')), + 'w:listSeparator' => array('@attributes' => array('w:val' => ';')), + ); + + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('w:settings'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + $xmlWriter->writeAttribute('xmlns:m', 'http://schemas.openxmlformats.org/officeDocument/2006/math'); + $xmlWriter->writeAttribute('xmlns:sl', 'http://schemas.openxmlformats.org/schemaLibrary/2006/main'); + $xmlWriter->writeAttribute('xmlns:o', 'urn:schemas-microsoft-com:office:office'); + $xmlWriter->writeAttribute('xmlns:v', 'urn:schemas-microsoft-com:vml'); + $xmlWriter->writeAttribute('xmlns:w10', 'urn:schemas-microsoft-com:office:word'); + + foreach ($settings as $settingKey => $settingValue) { + $this->writeSetting($xmlWriter, $settingKey, $settingValue); + } + + $xmlWriter->endElement(); // w:settings + + return $xmlWriter->getData(); + } + + /** + * Write indivual setting, recursive to any child settings + * + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param string $settingKey + * @param array|string $settingValue + */ + protected function writeSetting($xmlWriter, $settingKey, $settingValue) + { + if ($settingValue == '') { + $xmlWriter->writeElement($settingKey); + } else { + $xmlWriter->startElement($settingKey); + foreach ($settingValue as $childKey => $childValue) { + if ($childKey == '@attributes') { + foreach ($childValue as $key => $val) { + $xmlWriter->writeAttribute($key, $val); + } + } else { + $this->writeSetting($xmlWriter, $childKey, $childValue); + } + } + $xmlWriter->endElement(); + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php similarity index 63% rename from src/PhpWord/Writer/Word2007/Styles.php rename to src/PhpWord/Writer/Word2007/Part/Styles.php index 799ff368..579ae8e5 100644 --- a/src/PhpWord/Writer/Word2007/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -2,115 +2,70 @@ /** * PHPWord * - * Copyright (c) 2014 PHPWord - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * @copyright Copyright (c) 2014 PHPWord - * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL - * @version 0.9.0 + * @link https://github.com/PHPOffice/PHPWord + * @copyright 2014 PHPWord + * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL */ -namespace PhpOffice\PhpWord\Writer\Word2007; +namespace PhpOffice\PhpWord\Writer\Word2007\Part; use PhpOffice\PhpWord\PhpWord; -use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style; +use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Paragraph; +use PhpOffice\PhpWord\Style\Table; +use PhpOffice\PhpWord\Writer\Word2007\Style\Font as FontStyleWriter; +use PhpOffice\PhpWord\Writer\Word2007\Style\Paragraph as ParagraphStyleWriter; +use PhpOffice\PhpWord\Writer\Word2007\Style\Table as TableStyleWriter; /** * Word2007 styles part writer + * + * @todo Do something with the numbering style introduced in 0.10.0 */ -class Styles extends Base +class Styles extends AbstractPart { - /** - * PHPWord object - * - * @var PhpWord - */ - private $_document; - /** * Write word/styles.xml * - * @param PhpOffice\PhpWord\PhpWord $phpWord + * @param \PhpOffice\PhpWord\PhpWord $phpWord */ public function writeStyles(PhpWord $phpWord = null) { - // Create XML writer - $xmlWriter = null; - if ($this->getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); + if (is_null($phpWord)) { + throw new Exception("No PhpWord assigned."); } + $xmlWriter = $this->getXmlWriter(); - $this->_document = $phpWord; - - // XML header $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - $xmlWriter->startElement('w:styles'); - $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); - // Write DocDefaults - $this->_writeDocDefaults($xmlWriter); - - // Write Style Definitions + // Write default styles $styles = Style::getStyles(); + $this->writeDefaultStyles($xmlWriter, $phpWord, $styles); - // Write normal paragraph style - $normalStyle = null; - if (array_key_exists('Normal', $styles)) { - $normalStyle = $styles['Normal']; - } - $xmlWriter->startElement('w:style'); - $xmlWriter->writeAttribute('w:type', 'paragraph'); - $xmlWriter->writeAttribute('w:default', '1'); - $xmlWriter->writeAttribute('w:styleId', 'Normal'); - $xmlWriter->startElement('w:name'); - $xmlWriter->writeAttribute('w:val', 'Normal'); - $xmlWriter->endElement(); - if (!is_null($normalStyle)) { - $this->_writeParagraphStyle($xmlWriter, $normalStyle); - } - $xmlWriter->endElement(); - - // Write other styles + // Write styles if (count($styles) > 0) { foreach ($styles as $styleName => $style) { if ($styleName == 'Normal') { continue; } - if ($style instanceof Font) { + // Font style + if ($style instanceof Font) { $paragraphStyle = $style->getParagraphStyle(); $styleType = $style->getStyleType(); - $type = ($styleType == 'title') ? 'paragraph' : 'character'; - if (!is_null($paragraphStyle)) { $type = 'paragraph'; } $xmlWriter->startElement('w:style'); $xmlWriter->writeAttribute('w:type', $type); - if ($styleType == 'title') { $arrStyle = explode('_', $styleName); $styleId = 'Heading' . $arrStyle[1]; @@ -122,33 +77,32 @@ class Styles extends Base $xmlWriter->writeAttribute('w:val', $styleLink); $xmlWriter->endElement(); } - $xmlWriter->startElement('w:name'); $xmlWriter->writeAttribute('w:val', $styleName); $xmlWriter->endElement(); - if (!is_null($paragraphStyle)) { // Point parent style to Normal $xmlWriter->startElement('w:basedOn'); $xmlWriter->writeAttribute('w:val', 'Normal'); $xmlWriter->endElement(); - $this->_writeParagraphStyle($xmlWriter, $paragraphStyle); + + $styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle); + $styleWriter->write(); } - $this->_writeTextStyle($xmlWriter, $style); - + $styleWriter = new FontStyleWriter($xmlWriter, $style); + $styleWriter->write(); $xmlWriter->endElement(); + // Paragraph style } elseif ($style instanceof Paragraph) { $xmlWriter->startElement('w:style'); $xmlWriter->writeAttribute('w:type', 'paragraph'); $xmlWriter->writeAttribute('w:customStyle', '1'); $xmlWriter->writeAttribute('w:styleId', $styleName); - $xmlWriter->startElement('w:name'); $xmlWriter->writeAttribute('w:val', $styleName); $xmlWriter->endElement(); - // Parent style $basedOn = $style->getBasedOn(); if (!is_null($basedOn)) { @@ -156,7 +110,6 @@ class Styles extends Base $xmlWriter->writeAttribute('w:val', $basedOn); $xmlWriter->endElement(); } - // Next paragraph style $next = $style->getNext(); if (!is_null($next)) { @@ -165,24 +118,25 @@ class Styles extends Base $xmlWriter->endElement(); } - $this->_writeParagraphStyle($xmlWriter, $style); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); + $styleWriter->write(); $xmlWriter->endElement(); - } elseif ($style instanceof \PhpOffice\PhpWord\Style\Table) { + // Table style + } elseif ($style instanceof Table) { $xmlWriter->startElement('w:style'); $xmlWriter->writeAttribute('w:type', 'table'); $xmlWriter->writeAttribute('w:customStyle', '1'); $xmlWriter->writeAttribute('w:styleId', $styleName); - $xmlWriter->startElement('w:name'); $xmlWriter->writeAttribute('w:val', $styleName); $xmlWriter->endElement(); - $xmlWriter->startElement('w:uiPriority'); $xmlWriter->writeAttribute('w:val', '99'); $xmlWriter->endElement(); - $this->_writeTableStyle($xmlWriter, $style); + $styleWriter = new TableStyleWriter($xmlWriter, $style); + $styleWriter->write(); $xmlWriter->endElement(); // w:style } @@ -191,41 +145,70 @@ class Styles extends Base $xmlWriter->endElement(); // w:styles - // Return return $xmlWriter->getData(); } /** - * Write document defaults + * Write default font and other default styles * - * @param PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter + * @param array $styles */ - private function _writeDocDefaults(XMLWriter $xmlWriter) + private function writeDefaultStyles(XMLWriter $xmlWriter, PhpWord $phpWord, $styles) { - $fontName = $this->_document->getDefaultFontName(); - $fontSize = $this->_document->getDefaultFontSize(); + $fontName = $phpWord->getDefaultFontName(); + $fontSize = $phpWord->getDefaultFontSize(); + // Default font $xmlWriter->startElement('w:docDefaults'); $xmlWriter->startElement('w:rPrDefault'); $xmlWriter->startElement('w:rPr'); - $xmlWriter->startElement('w:rFonts'); $xmlWriter->writeAttribute('w:ascii', $fontName); $xmlWriter->writeAttribute('w:hAnsi', $fontName); $xmlWriter->writeAttribute('w:eastAsia', $fontName); $xmlWriter->writeAttribute('w:cs', $fontName); - $xmlWriter->endElement(); - + $xmlWriter->endElement(); // w:rFonts $xmlWriter->startElement('w:sz'); $xmlWriter->writeAttribute('w:val', $fontSize * 2); - $xmlWriter->endElement(); - + $xmlWriter->endElement(); // w:sz $xmlWriter->startElement('w:szCs'); $xmlWriter->writeAttribute('w:val', $fontSize * 2); - $xmlWriter->endElement(); + $xmlWriter->endElement(); // w:szCs + $xmlWriter->endElement(); // w:rPr + $xmlWriter->endElement(); // w:rPrDefault + $xmlWriter->endElement(); // w:docDefaults - $xmlWriter->endElement(); - $xmlWriter->endElement(); - $xmlWriter->endElement(); + // Normal style + $xmlWriter->startElement('w:style'); + $xmlWriter->writeAttribute('w:type', 'paragraph'); + $xmlWriter->writeAttribute('w:default', '1'); + $xmlWriter->writeAttribute('w:styleId', 'Normal'); + $xmlWriter->startElement('w:name'); + $xmlWriter->writeAttribute('w:val', 'Normal'); + $xmlWriter->endElement(); // w:name + if (array_key_exists('Normal', $styles)) { + $styleWriter = new ParagraphStyleWriter($xmlWriter, $styles['Normal']); + $styleWriter->write(); + } + $xmlWriter->endElement(); // w:style + + // FootnoteReference style + if (!array_key_exists('FootnoteReference', $styles)) { + $xmlWriter->startElement('w:style'); + $xmlWriter->writeAttribute('w:type', 'character'); + $xmlWriter->writeAttribute('w:styleId', 'FootnoteReference'); + $xmlWriter->startElement('w:name'); + $xmlWriter->writeAttribute('w:val', 'Footnote Reference'); + $xmlWriter->endElement(); // w:name + $xmlWriter->writeElement('w:semiHidden'); + $xmlWriter->writeElement('w:unhideWhenUsed'); + $xmlWriter->startElement('w:rPr'); + $xmlWriter->startElement('w:vertAlign'); + $xmlWriter->writeAttribute('w:val', 'superscript'); + $xmlWriter->endElement(); // w:vertAlign + $xmlWriter->endElement(); // w:rPr + $xmlWriter->endElement(); // w:style + } } } diff --git a/src/PhpWord/_staticDocParts/theme1.xml b/src/PhpWord/Writer/Word2007/Part/Theme.php similarity index 93% rename from src/PhpWord/_staticDocParts/theme1.xml rename to src/PhpWord/Writer/Word2007/Part/Theme.php index 4fab507b..2e0b4c99 100644 --- a/src/PhpWord/_staticDocParts/theme1.xml +++ b/src/PhpWord/Writer/Word2007/Part/Theme.php @@ -1,2 +1,27 @@ - - \ No newline at end of file + +'; + } +} diff --git a/src/PhpWord/Writer/Word2007/Part/WebSettings.php b/src/PhpWord/Writer/Word2007/Part/WebSettings.php new file mode 100644 index 00000000..b1b5cc15 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Part/WebSettings.php @@ -0,0 +1,41 @@ + '', + ); + + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); + $xmlWriter->startElement('w:webSettings'); + $xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); + $xmlWriter->writeAttribute('xmlns:w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); + + foreach ($settings as $settingKey => $settingValue) { + $this->writeSetting($xmlWriter, $settingKey, $settingValue); + } + + $xmlWriter->endElement(); // w:settings + + return $xmlWriter->getData(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Rels.php b/src/PhpWord/Writer/Word2007/Rels.php deleted file mode 100755 index d816b24e..00000000 --- a/src/PhpWord/Writer/Word2007/Rels.php +++ /dev/null @@ -1,122 +0,0 @@ -getParentWriter()->getUseDiskCaching()) { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); - } else { - $xmlWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); - } - - // XML header - $xmlWriter->startDocument('1.0', 'UTF-8', 'yes'); - - // Relationships - $xmlWriter->startElement('Relationships'); - $xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships'); - - $relationId = 1; - - // Relationship word/document.xml - $this->_writeRelationship( - $xmlWriter, - $relationId, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument', - 'word/document.xml' - ); - - // Relationship docProps/core.xml - $this->_writeRelationship( - $xmlWriter, - ++$relationId, - 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties', - 'docProps/core.xml' - ); - - // Relationship docProps/app.xml - $this->_writeRelationship( - $xmlWriter, - ++$relationId, - 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties', - 'docProps/app.xml' - ); - - $xmlWriter->endElement(); - - return $xmlWriter->getData(); - } - - /** - * Write Override content type - * - * @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter - * @param int $pId Relationship ID. rId will be prepended! - * @param string $pType Relationship type - * @param string $pTarget Relationship target - * @param string $pTargetMode Relationship target mode - * @throws \PhpOffice\PhpWord\Exceptions\Exception - */ - private function _writeRelationship(XMLWriter $xmlWriter = null, $pId = 1, $pType = '', $pTarget = '', $pTargetMode = '') - { - if ($pType != '' && $pTarget != '') { - if (strpos($pId, 'rId') === false) { - $pId = 'rId' . $pId; - } - - // Write relationship - $xmlWriter->startElement('Relationship'); - $xmlWriter->writeAttribute('Id', $pId); - $xmlWriter->writeAttribute('Type', $pType); - $xmlWriter->writeAttribute('Target', $pTarget); - - if ($pTargetMode != '') { - $xmlWriter->writeAttribute('TargetMode', $pTargetMode); - } - - $xmlWriter->endElement(); - } else { - throw new Exception("Invalid parameters passed."); - } - } -} diff --git a/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php new file mode 100644 index 00000000..9b2d7ffd --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/AbstractStyle.php @@ -0,0 +1,68 @@ +xmlWriter = $xmlWriter; + $this->style = $style; + } + + /** + * Convert twip value + * + * @param int|float $value + * @param int|float $default + * @return int|float + */ + protected function convertTwip($value, $default = 0) + { + $unit = Settings::getMeasurementUnit(); + if ($unit == Settings::UNIT_TWIP || $value == $default) { + return $value; + } else { + return $value * $unit; + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php new file mode 100644 index 00000000..d33eed56 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -0,0 +1,87 @@ +style instanceof \PhpOffice\PhpWord\Style\Cell)) { + return; + } + + $brdSz = $this->style->getBorderSize(); + $brdCol = $this->style->getBorderColor(); + $hasBorders = false; + for ($i = 0; $i < 4; $i++) { + if (!is_null($brdSz[$i])) { + $hasBorders = true; + break; + } + } + + // Border + if ($hasBorders) { + $mbWriter = new MarginBorder($this->xmlWriter); + $mbWriter->setSizes($brdSz); + $mbWriter->setColors($brdCol); + $mbWriter->setAttributes(array('defaultColor' => CellStyle::DEFAULT_BORDER_COLOR)); + + $this->xmlWriter->startElement('w:tcBorders'); + $mbWriter->write(); + $this->xmlWriter->endElement(); + } + + // Text direction + if (!is_null($this->style->getTextDirection())) { + $this->xmlWriter->startElement('w:textDirection'); + $this->xmlWriter->writeAttribute('w:val', $this->style->getTextDirection()); + $this->xmlWriter->endElement(); + } + + // Shading + if (!is_null($this->style->getShading())) { + $styleWriter = new Shading($this->xmlWriter, $this->style->getShading()); + $styleWriter->write(); + } + + // Alignment + if (!is_null($this->style->getVAlign())) { + $this->xmlWriter->startElement('w:vAlign'); + $this->xmlWriter->writeAttribute('w:val', $this->style->getVAlign()); + $this->xmlWriter->endElement(); + } + + // Colspan + if (!is_null($this->style->getGridSpan())) { + $this->xmlWriter->startElement('w:gridSpan'); + $this->xmlWriter->writeAttribute('w:val', $this->style->getGridSpan()); + $this->xmlWriter->endElement(); + } + + // Row span + if (!is_null($this->style->getVMerge())) { + $this->xmlWriter->startElement('w:vMerge'); + $this->xmlWriter->writeAttribute('w:val', $this->style->getVMerge()); + $this->xmlWriter->endElement(); + } + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Font.php b/src/PhpWord/Writer/Word2007/Style/Font.php new file mode 100644 index 00000000..6ffc6a87 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Font.php @@ -0,0 +1,161 @@ +isInline && !is_null($this->style) && is_string($this->style); + if ($isStyleName) { + $this->xmlWriter->startElement('w:rPr'); + $this->xmlWriter->startElement('w:rStyle'); + $this->xmlWriter->writeAttribute('w:val', $this->style); + $this->xmlWriter->endElement(); + $this->xmlWriter->endElement(); + } else { + $this->writeStyle(); + } + } + + /** + * Write full style + */ + private function writeStyle() + { + if (!($this->style instanceof \PhpOffice\PhpWord\Style\Font)) { + return; + } + + $font = $this->style->getName(); + $color = $this->style->getColor(); + $size = $this->style->getSize(); + + $this->xmlWriter->startElement('w:rPr'); + + // Font name/family + if ($font != PhpWord::DEFAULT_FONT_NAME) { + $this->xmlWriter->startElement('w:rFonts'); + $this->xmlWriter->writeAttribute('w:ascii', $font); + $this->xmlWriter->writeAttribute('w:hAnsi', $font); + $this->xmlWriter->writeAttribute('w:eastAsia', $font); + $this->xmlWriter->writeAttribute('w:cs', $font); + //Font Content Type + if ($this->style->getHint() != PhpWord::DEFAULT_FONT_CONTENT_TYPE) { + $this->xmlWriter->writeAttribute('w:hint', $this->style->getHint()); + } + $this->xmlWriter->endElement(); + } + + // Color + if ($color != PhpWord::DEFAULT_FONT_COLOR) { + $this->xmlWriter->startElement('w:color'); + $this->xmlWriter->writeAttribute('w:val', $color); + $this->xmlWriter->endElement(); + } + + // Size + if ($size != PhpWord::DEFAULT_FONT_SIZE) { + $this->xmlWriter->startElement('w:sz'); + $this->xmlWriter->writeAttribute('w:val', $size * 2); + $this->xmlWriter->endElement(); + $this->xmlWriter->startElement('w:szCs'); + $this->xmlWriter->writeAttribute('w:val', $size * 2); + $this->xmlWriter->endElement(); + } + + // Bold + if ($this->style->getBold()) { + $this->xmlWriter->writeElement('w:b', null); + } + + // Italic + if ($this->style->getItalic()) { + $this->xmlWriter->writeElement('w:i', null); + $this->xmlWriter->writeElement('w:iCs', null); + } + + // Underline + if ($this->style->getUnderline() != 'none') { + $this->xmlWriter->startElement('w:u'); + $this->xmlWriter->writeAttribute('w:val', $this->style->getUnderline()); + $this->xmlWriter->endElement(); + } + + // Strikethrough + if ($this->style->getStrikethrough()) { + $this->xmlWriter->writeElement('w:strike', null); + } + + // Double strikethrough + if ($this->style->getDoubleStrikethrough()) { + $this->xmlWriter->writeElement('w:dstrike', null); + } + + // Foreground-Color + if (!is_null($this->style->getFgColor())) { + $this->xmlWriter->startElement('w:highlight'); + $this->xmlWriter->writeAttribute('w:val', $this->style->getFgColor()); + $this->xmlWriter->endElement(); + } + + // Background-Color + if (!is_null($this->style->getShading())) { + $styleWriter = new Shading($this->xmlWriter, $this->style->getShading()); + $styleWriter->write(); + } + + // Superscript/subscript + if ($this->style->getSuperScript() || $this->style->getSubScript()) { + $this->xmlWriter->startElement('w:vertAlign'); + $this->xmlWriter->writeAttribute('w:val', $this->style->getSuperScript() ? 'superscript' : 'subscript'); + $this->xmlWriter->endElement(); + } + + // Small caps + if ($this->style->getSmallCaps()) { + $this->xmlWriter->writeElement('w:smallCaps', null); + } + + // All caps + if ($this->style->getAllCaps()) { + $this->xmlWriter->writeElement('w:caps', null); + } + + $this->xmlWriter->endElement(); + } + + /** + * Set is inline + * + * @param bool $value + */ + public function setIsInline($value) + { + $this->isInline = $value; + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Indentation.php b/src/PhpWord/Writer/Word2007/Style/Indentation.php new file mode 100644 index 00000000..c31cdebf --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Indentation.php @@ -0,0 +1,39 @@ +style instanceof \PhpOffice\PhpWord\Style\Indentation)) { + return; + } + + $this->xmlWriter->startElement('w:ind'); + $this->xmlWriter->writeAttribute('w:left', $this->convertTwip($this->style->getLeft())); + $this->xmlWriter->writeAttribute('w:right', $this->convertTwip($this->style->getRight())); + if (!is_null($this->style->getFirstLine())) { + $this->xmlWriter->writeAttribute('w:firstLine', $this->convertTwip($this->style->getFirstLine())); + } + if (!is_null($this->style->getHanging())) { + $this->xmlWriter->writeAttribute('w:hanging', $this->convertTwip($this->style->getHanging())); + } + $this->xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/LineNumbering.php b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php new file mode 100644 index 00000000..6167e329 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/LineNumbering.php @@ -0,0 +1,37 @@ +style instanceof \PhpOffice\PhpWord\Style\LineNumbering)) { + return; + } + + $this->xmlWriter->startElement('w:lnNumType'); + $this->xmlWriter->writeAttribute('w:start', $this->style->getStart() - 1); + $this->xmlWriter->writeAttribute('w:countBy', $this->style->getIncrement()); + $this->xmlWriter->writeAttribute('w:distance', $this->style->getDistance()); + $this->xmlWriter->writeAttribute('w:restart', $this->style->getRestart()); + $this->xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/MarginBorder.php b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php new file mode 100644 index 00000000..ef6992db --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/MarginBorder.php @@ -0,0 +1,103 @@ +sizes) - 1; + + for ($i = 0; $i < $sizeCount; $i++) { + if (!is_null($this->sizes[$i])) { + $this->xmlWriter->startElement('w:' . $sides[$i]); + if (!empty($this->colors)) { + if (is_null($this->colors[$i]) && !empty($this->attributes)) { + if (array_key_exists('defaultColor', $this->attributes)) { + $this->colors[$i] = $this->attributes['defaultColor']; + } + } + $this->xmlWriter->writeAttribute('w:val', 'single'); + $this->xmlWriter->writeAttribute('w:sz', $this->sizes[$i]); + $this->xmlWriter->writeAttribute('w:color', $this->colors[$i]); + if (!empty($this->attributes)) { + if (array_key_exists('space', $this->attributes)) { + $this->xmlWriter->writeAttribute('w:space', $this->attributes['space']); + } + } + } else { + $this->xmlWriter->writeAttribute('w:w', $this->sizes[$i]); + $this->xmlWriter->writeAttribute('w:type', 'dxa'); + } + $this->xmlWriter->endElement(); + } + } + } + + /** + * Set sizes + * + * @param int[] $value + */ + public function setSizes($value) + { + $this->sizes = $value; + } + + /** + * Set colors + * + * @param string[] $value + */ + public function setColors($value) + { + $this->colors = $value; + } + + /** + * Set attributes + * + * @param array $value + */ + public function setAttributes($value) + { + $this->attributes = $value; + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Paragraph.php b/src/PhpWord/Writer/Word2007/Style/Paragraph.php new file mode 100644 index 00000000..b92e1714 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Paragraph.php @@ -0,0 +1,152 @@ +isInline && !is_null($this->style) && is_string($this->style); + if ($isStyleName) { + if (!$this->withoutPPR) { + $this->xmlWriter->startElement('w:pPr'); + } + $this->xmlWriter->startElement('w:pStyle'); + $this->xmlWriter->writeAttribute('w:val', $this->style); + $this->xmlWriter->endElement(); + if (!$this->withoutPPR) { + $this->xmlWriter->endElement(); + } + } else { + $this->writeStyle(); + } + } + + /** + * Write full style + */ + private function writeStyle() + { + if (!($this->style instanceof \PhpOffice\PhpWord\Style\Paragraph)) { + return; + } + + $widowControl = $this->style->getWidowControl(); + $keepNext = $this->style->getKeepNext(); + $keepLines = $this->style->getKeepLines(); + $pageBreakBefore = $this->style->getPageBreakBefore(); + + if (!$this->withoutPPR) { + $this->xmlWriter->startElement('w:pPr'); + } + + // Alignment + if (!is_null($this->style->getAlign())) { + $this->xmlWriter->startElement('w:jc'); + $this->xmlWriter->writeAttribute('w:val', $this->style->getAlign()); + $this->xmlWriter->endElement(); + } + + // Indentation + if (!is_null($this->style->getIndentation())) { + $styleWriter = new Indentation($this->xmlWriter, $this->style->getIndentation()); + $styleWriter->write(); + } + + // Spacing + if (!is_null($this->style->getSpace())) { + $styleWriter = new Spacing($this->xmlWriter, $this->style->getSpace()); + $styleWriter->write(); + } + + // Pagination + if (!$widowControl) { + $this->xmlWriter->startElement('w:widowControl'); + $this->xmlWriter->writeAttribute('w:val', '0'); + $this->xmlWriter->endElement(); + } + if ($keepNext) { + $this->xmlWriter->startElement('w:keepNext'); + $this->xmlWriter->writeAttribute('w:val', '1'); + $this->xmlWriter->endElement(); + } + if ($keepLines) { + $this->xmlWriter->startElement('w:keepLines'); + $this->xmlWriter->writeAttribute('w:val', '1'); + $this->xmlWriter->endElement(); + } + if ($pageBreakBefore) { + $this->xmlWriter->startElement('w:pageBreakBefore'); + $this->xmlWriter->writeAttribute('w:val', '1'); + $this->xmlWriter->endElement(); + } + + // Tabs + $tabs = $this->style->getTabs(); + if (!empty($tabs)) { + $this->xmlWriter->startElement("w:tabs"); + foreach ($tabs as $tab) { + $styleWriter = new Tab($this->xmlWriter, $tab); + $styleWriter->write(); + } + $this->xmlWriter->endElement(); + } + + if (!$this->withoutPPR) { + $this->xmlWriter->endElement(); // w:pPr + } + } + + /** + * Set without w:pPr + * + * @param bool $value + */ + public function setWithoutPPR($value) + { + $this->withoutPPR = $value; + } + + /** + * Set is inline + * + * @param bool $value + */ + public function setIsInline($value) + { + $this->isInline = $value; + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Section.php b/src/PhpWord/Writer/Word2007/Style/Section.php new file mode 100644 index 00000000..e00a3226 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Section.php @@ -0,0 +1,95 @@ +style instanceof \PhpOffice\PhpWord\Style\Section)) { + return; + } + + // Section break + if (!is_null($this->style->getBreakType())) { + $this->xmlWriter->startElement('w:type'); + $this->xmlWriter->writeAttribute('w:val', $this->style->getBreakType()); + $this->xmlWriter->endElement(); + } + + // Page size & orientation + $this->xmlWriter->startElement('w:pgSz'); + $this->xmlWriter->writeAttribute('w:orient', $this->style->getOrientation()); + $this->xmlWriter->writeAttribute('w:w', $this->style->getPageSizeW()); + $this->xmlWriter->writeAttribute('w:h', $this->style->getPageSizeH()); + $this->xmlWriter->endElement(); // w:pgSz + + // Margins + $this->xmlWriter->startElement('w:pgMar'); + $this->xmlWriter->writeAttribute('w:top', $this->convertTwip($this->style->getMarginTop(), SectionStyle::DEFAULT_MARGIN)); + $this->xmlWriter->writeAttribute('w:right', $this->convertTwip($this->style->getMarginRight(), SectionStyle::DEFAULT_MARGIN)); + $this->xmlWriter->writeAttribute('w:bottom', $this->convertTwip($this->style->getMarginBottom(), SectionStyle::DEFAULT_MARGIN)); + $this->xmlWriter->writeAttribute('w:left', $this->convertTwip($this->style->getMarginLeft(), SectionStyle::DEFAULT_MARGIN)); + $this->xmlWriter->writeAttribute('w:header', $this->convertTwip($this->style->getHeaderHeight(), SectionStyle::DEFAULT_HEADER_HEIGHT)); + $this->xmlWriter->writeAttribute('w:footer', $this->convertTwip($this->style->getFooterHeight(), SectionStyle::DEFAULT_FOOTER_HEIGHT)); + $this->xmlWriter->writeAttribute('w:gutter', $this->convertTwip($this->style->getGutter(), SectionStyle::DEFAULT_GUTTER)); + $this->xmlWriter->endElement(); + + // Borders + $borders = $this->style->getBorderSize(); + $hasBorders = false; + for ($i = 0; $i < 4; $i++) { + if (!is_null($borders[$i])) { + $hasBorders = true; + break; + } + } + if ($hasBorders) { + $styleWriter = new MarginBorder($this->xmlWriter); + $styleWriter->setSizes($borders); + $styleWriter->setColors($this->style->getBorderColor()); + $styleWriter->setAttributes(array('space' => '24')); + + $this->xmlWriter->startElement('w:pgBorders'); + $this->xmlWriter->writeAttribute('w:offsetFrom', 'page'); + $styleWriter->write(); + $this->xmlWriter->endElement(); + } + + // Page numbering + if (!is_null($this->style->getPageNumberingStart())) { + $this->xmlWriter->startElement('w:pgNumType'); + $this->xmlWriter->writeAttribute('w:start', $this->style->getPageNumberingStart()); + $this->xmlWriter->endElement(); + } + + // Columns + $this->xmlWriter->startElement('w:cols'); + $this->xmlWriter->writeAttribute('w:num', $this->style->getColsNum()); + $this->xmlWriter->writeAttribute('w:space', $this->convertTwip($this->style->getColsSpace(), SectionStyle::DEFAULT_COLUMN_SPACING)); + $this->xmlWriter->endElement(); + + // Line numbering + $styleWriter = new LineNumbering($this->xmlWriter, $this->style->getLineNumbering()); + $styleWriter->write(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Shading.php b/src/PhpWord/Writer/Word2007/Style/Shading.php new file mode 100644 index 00000000..3d831935 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Shading.php @@ -0,0 +1,34 @@ +style instanceof \PhpOffice\PhpWord\Style\Shading)) { + return; + } + + $this->xmlWriter->startElement('w:shd'); + $this->xmlWriter->writeAttribute('w:val', $this->style->getPattern()); + $this->xmlWriter->writeAttribute('w:color', $this->style->getColor()); + $this->xmlWriter->writeAttribute('w:fill', $this->style->getFill()); + $this->xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Spacing.php b/src/PhpWord/Writer/Word2007/Style/Spacing.php new file mode 100644 index 00000000..94f02a3c --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Spacing.php @@ -0,0 +1,41 @@ +style instanceof \PhpOffice\PhpWord\Style\Spacing)) { + return; + } + + $this->xmlWriter->startElement('w:spacing'); + if (!is_null($this->style->getBefore())) { + $this->xmlWriter->writeAttribute('w:before', $this->convertTwip($this->style->getBefore())); + } + if (!is_null($this->style->getAfter())) { + $this->xmlWriter->writeAttribute('w:after', $this->convertTwip($this->style->getAfter())); + } + if (!is_null($this->style->getLine())) { + $this->xmlWriter->writeAttribute('w:line', $this->style->getLine()); + $this->xmlWriter->writeAttribute('w:lineRule', $this->style->getRule()); + } + $this->xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Tab.php b/src/PhpWord/Writer/Word2007/Style/Tab.php new file mode 100644 index 00000000..403c6173 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Tab.php @@ -0,0 +1,34 @@ +style instanceof \PhpOffice\PhpWord\Style\Tab)) { + return; + } + + $this->xmlWriter->startElement("w:tab"); + $this->xmlWriter->writeAttribute("w:val", $this->style->getStopType()); + $this->xmlWriter->writeAttribute("w:leader", $this->style->getLeader()); + $this->xmlWriter->writeAttribute('w:pos', $this->convertTwip($this->style->getPosition())); + $this->xmlWriter->endElement(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Style/Table.php b/src/PhpWord/Writer/Word2007/Style/Table.php new file mode 100644 index 00000000..00bda8a4 --- /dev/null +++ b/src/PhpWord/Writer/Word2007/Style/Table.php @@ -0,0 +1,141 @@ +style instanceof \PhpOffice\PhpWord\Style\Table)) { + return; + } + + $brdCol = $this->style->getBorderColor(); + $brdSz = $this->style->getBorderSize(); + $cellMargin = $this->style->getCellMargin(); + + // If any of the borders/margins is set, process them + $hasBorders = false; + for ($i = 0; $i < 6; $i++) { + if (!is_null($brdSz[$i])) { + $hasBorders = true; + break; + } + } + $hasMargins = false; + for ($i = 0; $i < 4; $i++) { + if (!is_null($cellMargin[$i])) { + $hasMargins = true; + break; + } + } + if ($hasMargins || $hasBorders) { + $this->xmlWriter->startElement('w:tblPr'); + if ($hasMargins) { + $mbWriter = new MarginBorder($this->xmlWriter); + $mbWriter->setSizes($cellMargin); + + $this->xmlWriter->startElement('w:tblCellMar'); + $mbWriter->write(); + $this->xmlWriter->endElement(); // w:tblCellMar + } + if ($hasBorders) { + $mbWriter = new MarginBorder($this->xmlWriter); + $mbWriter->setSizes($brdSz); + $mbWriter->setColors($brdCol); + + $this->xmlWriter->startElement('w:tblBorders'); + $mbWriter->write(); + $this->xmlWriter->endElement(); // w:tblBorders + } + $this->xmlWriter->endElement(); // w:tblPr + } + // Only write background color and first row for full style + if ($this->isFullStyle) { + // Background color + if (!is_null($this->style->getShading())) { + $this->xmlWriter->startElement('w:tcPr'); + $styleWriter = new Shading($this->xmlWriter, $this->style->getShading()); + $styleWriter->write(); + $this->xmlWriter->endElement(); + } + // First Row + $firstRow = $this->style->getFirstRow(); + if ($firstRow instanceof \PhpOffice\PhpWord\Style\Table) { + $this->writeFirstRow($firstRow, 'firstRow'); + } + } + } + + /** + * Set is full style + * + * @param bool $value + */ + public function setIsFullStyle($value) + { + $this->isFullStyle = $value; + } + + /** + * Write row style + * + * @param string $type + */ + private function writeFirstRow(\PhpOffice\PhpWord\Style\Table $style, $type) + { + $this->xmlWriter->startElement('w:tblStylePr'); + $this->xmlWriter->writeAttribute('w:type', $type); + $this->xmlWriter->startElement('w:tcPr'); + if (!is_null($style->getShading())) { + $styleWriter = new Shading($this->xmlWriter, $style->getShading()); + $styleWriter->write(); + } + + // Borders + $brdSz = $style->getBorderSize(); + $brdCol = $style->getBorderColor(); + $hasBorders = false; + for ($i = 0; $i < 6; $i++) { + if (!is_null($brdSz[$i])) { + $hasBorders = true; + } + } + if ($hasBorders) { + $mbWriter = new MarginBorder($this->xmlWriter); + $mbWriter->setSizes($brdSz); + $mbWriter->setColors($brdCol); + + $this->xmlWriter->startElement('w:tcBorders'); + $mbWriter->write(); + $this->xmlWriter->endElement(); // w:tcBorders + } + + $this->xmlWriter->endElement(); // w:tcPr + $this->xmlWriter->endElement(); // w:tblStylePr + } +} diff --git a/src/PhpWord/Writer/Word2007/WriterPart.php b/src/PhpWord/Writer/Word2007/WriterPart.php deleted file mode 100755 index 01959437..00000000 --- a/src/PhpWord/Writer/Word2007/WriterPart.php +++ /dev/null @@ -1,66 +0,0 @@ -_parentWriter = $pWriter; - } - - /** - * Get parent writer - * - * @return IWriter - */ - public function getParentWriter() - { - if (!is_null($this->_parentWriter)) { - return $this->_parentWriter; - } else { - throw new Exception("No parent IWriter assigned."); - } - } -} diff --git a/src/PhpWord/Writer/WriterInterface.php b/src/PhpWord/Writer/WriterInterface.php new file mode 100644 index 00000000..2c225b2c --- /dev/null +++ b/src/PhpWord/Writer/WriterInterface.php @@ -0,0 +1,23 @@ + - \ No newline at end of file diff --git a/src/PhpWord/_staticDocParts/settings.xml b/src/PhpWord/_staticDocParts/settings.xml deleted file mode 100644 index 5eb22891..00000000 --- a/src/PhpWord/_staticDocParts/settings.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/PhpWord/_staticDocParts/webSettings.xml b/src/PhpWord/_staticDocParts/webSettings.xml deleted file mode 100644 index 72d28307..00000000 --- a/src/PhpWord/_staticDocParts/webSettings.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/src/PhpWord/_staticDocParts/_doc.png b/src/PhpWord/resources/doc.png similarity index 100% rename from src/PhpWord/_staticDocParts/_doc.png rename to src/PhpWord/resources/doc.png diff --git a/src/PhpWord/_staticDocParts/_ppt.png b/src/PhpWord/resources/ppt.png similarity index 100% rename from src/PhpWord/_staticDocParts/_ppt.png rename to src/PhpWord/resources/ppt.png diff --git a/src/PhpWord/_staticDocParts/_xls.png b/src/PhpWord/resources/xls.png similarity index 100% rename from src/PhpWord/_staticDocParts/_xls.png rename to src/PhpWord/resources/xls.png diff --git a/tests/PhpWord/Tests/AutoloaderTest.php b/tests/PhpWord/Tests/AutoloaderTest.php index 5657fe6b..2a021aeb 100644 --- a/tests/PhpWord/Tests/AutoloaderTest.php +++ b/tests/PhpWord/Tests/AutoloaderTest.php @@ -1,36 +1,55 @@ assertContains( array('PhpOffice\\PhpWord\\Autoloader', 'autoload'), - \spl_autoload_functions() + spl_autoload_functions() ); } + /** + * Autoload + */ public function testAutoload() { - $declared = \get_declared_classes(); - $declaredCount = \count($declared); + $declared = get_declared_classes(); + $declaredCount = count($declared); Autoloader::autoload('Foo'); $this->assertEquals( $declaredCount, - \count(get_declared_classes()), + count(get_declared_classes()), 'PhpOffice\\PhpWord\\Autoloader::autoload() is trying to load ' . 'classes outside of the PhpOffice\\PhpWord namespace' ); // TODO change this class to the main PhpWord class when it is namespaced - Autoloader::autoload('PhpOffice\\PhpWord\\Exceptions\\InvalidStyleException'); + Autoloader::autoload('PhpOffice\\PhpWord\\Exception\\InvalidStyleException'); $this->assertTrue( - \in_array('PhpOffice\\PhpWord\\Exceptions\\InvalidStyleException', \get_declared_classes()), + in_array('PhpOffice\\PhpWord\\Exception\\InvalidStyleException', get_declared_classes()), 'PhpOffice\\PhpWord\\Autoloader::autoload() failed to autoload the ' . - 'PhpOffice\\PhpWord\\Exceptions\\InvalidStyleException class' + 'PhpOffice\\PhpWord\\Exception\\InvalidStyleException class' ); } } diff --git a/tests/PhpWord/Tests/DocumentPropertiesTest.php b/tests/PhpWord/Tests/DocumentPropertiesTest.php index 220dd1ba..207eb195 100644 --- a/tests/PhpWord/Tests/DocumentPropertiesTest.php +++ b/tests/PhpWord/Tests/DocumentPropertiesTest.php @@ -1,14 +1,26 @@ assertEquals('AAA', $oProperties->getCreator()); } + /** + * Last modified by + */ public function testLastModifiedBy() { $oProperties = new DocumentProperties(); @@ -29,6 +44,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getLastModifiedBy()); } + /** + * Created + */ public function testCreated() { $oProperties = new DocumentProperties(); @@ -40,6 +58,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals($iTime, $oProperties->getCreated()); } + /** + * Modified + */ public function testModified() { $oProperties = new DocumentProperties(); @@ -51,6 +72,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals($iTime, $oProperties->getModified()); } + /** + * Title + */ public function testTitle() { $oProperties = new DocumentProperties(); @@ -61,6 +85,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getTitle()); } + /** + * Description + */ public function testDescription() { $oProperties = new DocumentProperties(); @@ -71,6 +98,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getDescription()); } + /** + * Subject + */ public function testSubject() { $oProperties = new DocumentProperties(); @@ -81,6 +111,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getSubject()); } + /** + * Keywords + */ public function testKeywords() { $oProperties = new DocumentProperties(); @@ -91,6 +124,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getKeywords()); } + /** + * Category + */ public function testCategory() { $oProperties = new DocumentProperties(); @@ -101,6 +137,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getCategory()); } + /** + * Company + */ public function testCompany() { $oProperties = new DocumentProperties(); @@ -111,6 +150,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getCompany()); } + /** + * Manager + */ public function testManager() { $oProperties = new DocumentProperties(); @@ -121,6 +163,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase $this->assertEquals('AAA', $oProperties->getManager()); } + /** + * Custom properties + */ public function testCustomProperty() { $oProperties = new DocumentProperties(); @@ -167,6 +212,9 @@ class DocumentPropertiesTest extends \PHPUnit_Framework_TestCase ), $oProperties->getCustomProperties()); } + /** + * Convert property + */ public function testConvertProperty() { $this->assertEquals('', DocumentProperties::convertProperty('a', 'empty')); diff --git a/tests/PhpWord/Tests/Element/AbstractElementTest.php b/tests/PhpWord/Tests/Element/AbstractElementTest.php new file mode 100644 index 00000000..8dbfb5b3 --- /dev/null +++ b/tests/PhpWord/Tests/Element/AbstractElementTest.php @@ -0,0 +1,39 @@ +getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); + $ival = rand(0, 100); + $stub->setElementIndex($ival); + $this->assertEquals($stub->getElementIndex(), $ival); + } + + /** + * Test set/get element unique Id + */ + public function testElementId() + { + $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Element\AbstractElement'); + $stub->setElementId(); + $this->assertEquals(strlen($stub->getElementId()), 6); + } +} diff --git a/tests/PhpWord/Tests/Section/Table/CellTest.php b/tests/PhpWord/Tests/Element/CellTest.php similarity index 55% rename from tests/PhpWord/Tests/Section/Table/CellTest.php rename to tests/PhpWord/Tests/Element/CellTest.php index 17ca8239..3a2c3342 100644 --- a/tests/PhpWord/Tests/Section/Table/CellTest.php +++ b/tests/PhpWord/Tests/Element/CellTest.php @@ -1,19 +1,38 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table\\Cell', $oCell); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $oCell); $this->assertEquals($oCell->getWidth(), null); } + /** + * New instance with array + */ public function testConstructWithStyleArray() { $iVal = rand(1, 1000); @@ -23,42 +42,46 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oCell->getWidth(), null); } - public function testConstructWithStyleString() - { - $iVal = rand(1, 1000); - $oCell = new Cell('section', $iVal, null, 'cellStyle'); - - $this->assertEquals($oCell->getStyle(), 'cellStyle'); - } - + /** + * Add text + */ public function testAddText() { $oCell = new Cell('section', 1); $element = $oCell->addText('text'); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); } + /** + * Add non-UTF8 + */ public function testAddTextNotUTF8() { $oCell = new Cell('section', 1); $element = $oCell->addText(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertEquals($element->getText(), 'ééé'); } + /** + * Add link + */ public function testAddLink() { $oCell = new Cell('section', 1); - $element = $oCell->addLink('http://www.google.fr', 'Nom'); + $element = $oCell->addLink(utf8_decode('ééé'), utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); } + /** + * Add text break + */ public function testAddTextBreak() { $oCell = new Cell('section', 1); @@ -67,57 +90,75 @@ class CellTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $oCell->getElements()); } + /** + * Add list item + */ public function testAddListItem() { $oCell = new Cell('section', 1); $element = $oCell->addListItem('text'); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\ListItem', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element); $this->assertEquals($element->getTextObject()->getText(), 'text'); } + /** + * Add list item non-UTF8 + */ public function testAddListItemNotUTF8() { $oCell = new Cell('section', 1); $element = $oCell->addListItem(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\ListItem', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItem', $element); $this->assertEquals($element->getTextObject()->getText(), 'ééé'); } + /** + * Add image section + */ public function testAddImageSection() { - $src = __DIR__ . "/../../_files/images/earth.jpg"; + $src = __DIR__ . "/../_files/images/earth.jpg"; $oCell = new Cell('section', 1); $element = $oCell->addImage($src); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } + /** + * Add image header + */ public function testAddImageHeader() { - $src = __DIR__ . "/../../_files/images/earth.jpg"; + $src = __DIR__ . "/../_files/images/earth.jpg"; $oCell = new Cell('header', 1); $element = $oCell->addImage($src); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } + /** + * Add image footer + */ public function testAddImageFooter() { - $src = __DIR__ . "/../../_files/images/earth.jpg"; + $src = __DIR__ . "/../_files/images/earth.jpg"; $oCell = new Cell('footer', 1); $element = $oCell->addImage($src); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } - public function testAddSectionImageByUrl() + /** + * Add image section by URL + */ + public function testAddImageSectionByUrl() { $oCell = new Cell('section', 1); $element = $oCell->addImage( @@ -125,10 +166,13 @@ class CellTest extends \PHPUnit_Framework_TestCase ); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } - public function testAddHeaderImageByUrl() + /** + * Add image header by URL + */ + public function testAddImageHeaderByUrl() { $oCell = new Cell('header', 1); $element = $oCell->addImage( @@ -136,10 +180,13 @@ class CellTest extends \PHPUnit_Framework_TestCase ); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } - public function testAddFooterImageByUrl() + /** + * Add image footer by URL + */ + public function testAddImageFooterByUrl() { $oCell = new Cell('footer', 1); $element = $oCell->addImage( @@ -147,47 +194,97 @@ class CellTest extends \PHPUnit_Framework_TestCase ); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } + /** + * Add object + */ public function testAddObjectXLS() { - $src = __DIR__ . "/../../_files/documents/sheet.xls"; + $src = __DIR__ . "/../_files/documents/sheet.xls"; $oCell = new Cell('section', 1); $element = $oCell->addObject($src); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Object', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $element); } + /** + * Test add object exception + * + * @expectedException \PhpOffice\PhpWord\Exception\InvalidObjectException + */ + public function testAddObjectException() + { + $src = __DIR__ . "/../_files/xsl/passthrough.xsl"; + $oCell = new Cell('section', 1); + $element = $oCell->addObject($src); + } + + /** + * Add preserve text + */ public function testAddPreserveText() { $oCell = new Cell('header', 1); $element = $oCell->addPreserveText('text'); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); } + /** + * Add preserve text non-UTF8 + */ public function testAddPreserveTextNotUTF8() { $oCell = new Cell('header', 1); $element = $oCell->addPreserveText(utf8_decode('ééé')); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); $this->assertEquals($element->getText(), array('ééé')); } + /** + * Add preserve text exception + * + * @expectedException \BadMethodCallException + */ + public function testAddPreserveTextException() + { + $oCell = new Cell('section', 1); + $element = $oCell->addPreserveText('text'); + } + + /** + * Add text run + */ public function testCreateTextRun() { $oCell = new Cell('section', 1); - $element = $oCell->createTextRun(); + $element = $oCell->addTextRun(); $this->assertCount(1, $oCell->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element); } + /** + * Add check box + */ + public function testAddCheckBox() + { + $oCell = new Cell('section', 1); + $element = $oCell->addCheckBox(utf8_decode('ééé'), utf8_decode('ééé')); + + $this->assertCount(1, $oCell->getElements()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $element); + } + + /** + * Get elements + */ public function testGetElements() { $oCell = new Cell('section', 1); diff --git a/tests/PhpWord/Tests/Element/CheckBoxTest.php b/tests/PhpWord/Tests/Element/CheckBoxTest.php new file mode 100644 index 00000000..e4611618 --- /dev/null +++ b/tests/PhpWord/Tests/Element/CheckBoxTest.php @@ -0,0 +1,79 @@ +assertInstanceOf('PhpOffice\\PhpWord\\Element\\CheckBox', $oCheckBox); + $this->assertEquals(null, $oCheckBox->getText()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oCheckBox->getFontStyle()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle()); + } + + /** + * Get name and text + */ + public function testCheckBox() + { + $oCheckBox = new CheckBox('chkBox', 'CheckBox'); + + $this->assertEquals($oCheckBox->getName(), 'chkBox'); + $this->assertEquals($oCheckBox->getText(), 'CheckBox'); + } + + /** + * Get font style + */ + public function testFont() + { + $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle'); + $this->assertEquals($oCheckBox->getFontStyle(), 'fontStyle'); + + $oCheckBox->setFontStyle(array('bold' => true, 'italic' => true, 'size' => 16)); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oCheckBox->getFontStyle()); + } + + /** + * Font style as object + */ + public function testFontObject() + { + $font = new Font(); + $oCheckBox = new CheckBox('chkBox', 'CheckBox', $font); + $this->assertEquals($oCheckBox->getFontStyle(), $font); + } + + /** + * Get paragraph style + */ + public function testParagraph() + { + $oCheckBox = new CheckBox('chkBox', 'CheckBox', 'fontStyle', 'paragraphStyle'); + $this->assertEquals($oCheckBox->getParagraphStyle(), 'paragraphStyle'); + + $oCheckBox->setParagraphStyle(array('align' => 'center', 'spaceAfter' => 100)); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oCheckBox->getParagraphStyle()); + } +} diff --git a/tests/PhpWord/Tests/Section/FooterTest.php b/tests/PhpWord/Tests/Element/FooterTest.php similarity index 62% rename from tests/PhpWord/Tests/Section/FooterTest.php rename to tests/PhpWord/Tests/Element/FooterTest.php index 2abb774e..d4201149 100644 --- a/tests/PhpWord/Tests/Section/FooterTest.php +++ b/tests/PhpWord/Tests/Element/FooterTest.php @@ -1,47 +1,63 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer', $oFooter); - $this->assertEquals($oFooter->getFooterCount(), $iVal); - } - - public function testRelationID() - { - $oFooter = new Footer(0); - - $iVal = rand(1, 1000); - $oFooter->setRelationId($iVal); - $this->assertEquals($oFooter->getRelationId(), $iVal); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footer', $oFooter); + $this->assertEquals($oFooter->getSectionId(), $iVal); } + /** + * Add text + */ public function testAddText() { $oFooter = new Footer(1); $element = $oFooter->addText('text'); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); } + /** + * Add text non-UTF8 + */ public function testAddTextNotUTF8() { $oFooter = new Footer(1); $element = $oFooter->addText(utf8_decode('ééé')); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertEquals($element->getText(), 'ééé'); } + /** + * Add text break + */ public function testAddTextBreak() { $oFooter = new Footer(1); @@ -51,24 +67,33 @@ class FooterTest extends \PHPUnit_Framework_TestCase $this->assertCount($iVal, $oFooter->getElements()); } + /** + * Add text run + */ public function testCreateTextRun() { $oFooter = new Footer(1); - $element = $oFooter->createTextRun(); + $element = $oFooter->addTextRun(); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element); } + /** + * Add table + */ public function testAddTable() { $oFooter = new Footer(1); $element = $oFooter->addTable(); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $element); } + /** + * Add image + */ public function testAddImage() { $src = __DIR__ . "/../_files/images/earth.jpg"; @@ -76,9 +101,12 @@ class FooterTest extends \PHPUnit_Framework_TestCase $element = $oFooter->addImage($src); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } + /** + * Add image by URL + */ public function testAddImageByUrl() { $oFooter = new Footer(1); @@ -87,32 +115,55 @@ class FooterTest extends \PHPUnit_Framework_TestCase ); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } + /** + * Add preserve text + */ public function testAddPreserveText() { $oFooter = new Footer(1); $element = $oFooter->addPreserveText('text'); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); } + /** + * Add preserve text non-UTF8 + */ public function testAddPreserveTextNotUTF8() { $oFooter = new Footer(1); $element = $oFooter->addPreserveText(utf8_decode('ééé')); $this->assertCount(1, $oFooter->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); $this->assertEquals($element->getText(), array('ééé')); } + /** + * Get elements + */ public function testGetElements() { $oFooter = new Footer(1); $this->assertInternalType('array', $oFooter->getElements()); } + + /** + * Set/get relation Id + */ + public function testRelationID() + { + $oFooter = new Footer(0); + + $iVal = rand(1, 1000); + $oFooter->setRelationId($iVal); + + $this->assertEquals($oFooter->getRelationId(), $iVal); + $this->assertEquals(Footer::AUTO, $oFooter->getType()); + } } diff --git a/tests/PhpWord/Tests/Section/FootnoteTest.php b/tests/PhpWord/Tests/Element/FootnoteTest.php similarity index 54% rename from tests/PhpWord/Tests/Section/FootnoteTest.php rename to tests/PhpWord/Tests/Element/FootnoteTest.php index 22b5087b..c2571afe 100644 --- a/tests/PhpWord/Tests/Section/FootnoteTest.php +++ b/tests/PhpWord/Tests/Element/FootnoteTest.php @@ -1,19 +1,38 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footnote', $oFootnote); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $oFootnote); $this->assertCount(0, $oFootnote->getElements()); $this->assertEquals($oFootnote->getParagraphStyle(), null); } + /** + * New instance with string parameter + */ public function testConstructString() { $oFootnote = new Footnote('pStyle'); @@ -21,6 +40,9 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oFootnote->getParagraphStyle(), 'pStyle'); } + /** + * New instance with array parameter + */ public function testConstructArray() { $oFootnote = new Footnote(array('spacing' => 100)); @@ -31,33 +53,56 @@ class FootnoteTest extends \PHPUnit_Framework_TestCase ); } + /** + * Add text element + */ public function testAddText() { $oFootnote = new Footnote(); $element = $oFootnote->addText('text'); $this->assertCount(1, $oFootnote->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); } + /** + * Add text break element + */ + public function testAddTextBreak() + { + $oFootnote = new Footnote(); + $oFootnote->addTextBreak(2); + + $this->assertCount(2, $oFootnote->getElements()); + } + + /** + * Add link element + */ public function testAddLink() { $oFootnote = new Footnote(); $element = $oFootnote->addLink('http://www.google.fr'); $this->assertCount(1, $oFootnote->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); } + /** + * Set/get reference Id + */ public function testReferenceId() { $oFootnote = new Footnote(); $iVal = rand(1, 1000); - $oFootnote->setReferenceId($iVal); - $this->assertEquals($oFootnote->getReferenceId(), $iVal); + $oFootnote->setRelationId($iVal); + $this->assertEquals($oFootnote->getRelationId(), $iVal); } + /** + * Get elements + */ public function testGetElements() { $oFootnote = new Footnote(); diff --git a/tests/PhpWord/Tests/Section/HeaderTest.php b/tests/PhpWord/Tests/Element/HeaderTest.php similarity index 62% rename from tests/PhpWord/Tests/Section/HeaderTest.php rename to tests/PhpWord/Tests/Element/HeaderTest.php index 4a568639..849dd220 100644 --- a/tests/PhpWord/Tests/Section/HeaderTest.php +++ b/tests/PhpWord/Tests/Element/HeaderTest.php @@ -1,40 +1,65 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Header', $oHeader); - $this->assertEquals($oHeader->getHeaderCount(), $iVal); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Header', $oHeader); + $this->assertEquals($oHeader->getSectionId(), $iVal); $this->assertEquals($oHeader->getType(), Header::AUTO); } + /** + * Add text + */ public function testAddText() { $oHeader = new Header(1); $element = $oHeader->addText('text'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oHeader->getElements()); $this->assertEquals($element->getText(), 'text'); } + /** + * Add text non-UTF8 + */ public function testAddTextNotUTF8() { $oHeader = new Header(1); $element = $oHeader->addText(utf8_decode('ééé')); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oHeader->getElements()); $this->assertEquals($element->getText(), 'ééé'); } + /** + * Add text break + */ public function testAddTextBreak() { $oHeader = new Header(1); @@ -42,6 +67,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $oHeader->getElements()); } + /** + * Add text break with params + */ public function testAddTextBreakWithParams() { $oHeader = new Header(1); @@ -50,22 +78,31 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertCount($iVal, $oHeader->getElements()); } + /** + * Add text run + */ public function testCreateTextRun() { $oHeader = new Header(1); - $element = $oHeader->createTextRun(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $element); + $element = $oHeader->addTextRun(); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $element); $this->assertCount(1, $oHeader->getElements()); } + /** + * Add table + */ public function testAddTable() { $oHeader = new Header(1); $element = $oHeader->addTable(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $element); $this->assertCount(1, $oHeader->getElements()); } + /** + * Add image + */ public function testAddImage() { $src = __DIR__ . "/../_files/images/earth.jpg"; @@ -73,9 +110,12 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $element = $oHeader->addImage($src); $this->assertCount(1, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } + /** + * Add image by URL + */ public function testAddImageByUrl() { $oHeader = new Header(1); @@ -84,28 +124,37 @@ class HeaderTest extends \PHPUnit_Framework_TestCase ); $this->assertCount(1, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } + /** + * Add preserve text + */ public function testAddPreserveText() { $oHeader = new Header(1); $element = $oHeader->addPreserveText('text'); $this->assertCount(1, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); } + /** + * Add preserve text non-UTF8 + */ public function testAddPreserveTextNotUTF8() { $oHeader = new Header(1); $element = $oHeader->addPreserveText(utf8_decode('ééé')); $this->assertCount(1, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $element); $this->assertEquals($element->getText(), array('ééé')); } + /** + * Add watermark + */ public function testAddWatermark() { $src = __DIR__ . "/../_files/images/earth.jpg"; @@ -113,9 +162,12 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $element = $oHeader->addWatermark($src); $this->assertCount(1, $oHeader->getElements()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); } + /** + * Get elements + */ public function testGetElements() { $oHeader = new Header(1); @@ -123,6 +175,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertInternalType('array', $oHeader->getElements()); } + /** + * Set/get relation Id + */ public function testRelationId() { $oHeader = new Header(1); @@ -132,6 +187,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oHeader->getRelationId(), $iVal); } + /** + * Reset type + */ public function testResetType() { $oHeader = new Header(1); @@ -141,6 +199,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oHeader->getType(), Header::AUTO); } + /** + * First page + */ public function testFirstPage() { $oHeader = new Header(1); @@ -149,6 +210,9 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oHeader->getType(), Header::FIRST); } + /** + * Even page + */ public function testEvenPage() { $oHeader = new Header(1); @@ -156,4 +220,27 @@ class HeaderTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oHeader->getType(), Header::EVEN); } + + /** + * Add footnote exception + * + * @expectedException BadMethodCallException + */ + public function testAddFootnoteException() + { + $header = new Header(1); + $header->addFootnote(); + } + + /** + * Set/get type + */ + public function testSetGetType() + { + $object = new Header(1); + $this->assertEquals(Header::AUTO, $object->getType()); + + $object->setType('ODD'); + $this->assertEquals(Header::AUTO, $object->getType()); + } } diff --git a/tests/PhpWord/Tests/Element/ImageTest.php b/tests/PhpWord/Tests/Element/ImageTest.php new file mode 100644 index 00000000..eb482398 --- /dev/null +++ b/tests/PhpWord/Tests/Element/ImageTest.php @@ -0,0 +1,143 @@ +assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $oImage); + $this->assertEquals($oImage->getSource(), $src); + $this->assertEquals($oImage->getMediaId(), md5($src)); + $this->assertEquals($oImage->getIsWatermark(), false); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); + } + + /** + * New instance with style + */ + public function testConstructWithStyle() + { + $src = __DIR__ . "/../_files/images/firefox.png"; + $oImage = new Image( + $src, + array('width' => 210, 'height' => 210, 'align' => 'center', + 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND) + ); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); + } + + /** + * Valid image types + */ + public function testImages() + { + $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), + ); + + 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()); + } + } + + /** + * Get style + */ + public function testStyle() + { + $oImage = new Image( + __DIR__ . "/../_files/images/earth.jpg", + array('height' => 210, 'align' => 'center') + ); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); + } + + /** + * Test invalid local image + * + * @expectedException \PhpOffice\PhpWord\Exception\InvalidImageException + */ + 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'); + } + + /** + * Get relation Id + */ + public function testRelationID() + { + $oImage = new Image(__DIR__ . "/../_files/images/earth.jpg", array('width' => 100)); + $iVal = rand(1, 1000); + $oImage->setRelationId($iVal); + $this->assertEquals($oImage->getRelationId(), $iVal); + } + + /** + * Test archived image + */ + public function testArchivedImage() + { + $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/Section/LinkTest.php b/tests/PhpWord/Tests/Element/LinkTest.php similarity index 58% rename from tests/PhpWord/Tests/Section/LinkTest.php rename to tests/PhpWord/Tests/Element/LinkTest.php index 3029b6fa..3840ede8 100644 --- a/tests/PhpWord/Tests/Section/LinkTest.php +++ b/tests/PhpWord/Tests/Element/LinkTest.php @@ -1,22 +1,42 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $oLink); - $this->assertEquals($oLink->getLinkSrc(), 'http://www.google.com'); - $this->assertEquals($oLink->getLinkName(), null); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink); + $this->assertEquals($oLink->getTarget(), 'http://www.google.com'); + $this->assertEquals($oLink->getText(), $oLink->getTarget()); $this->assertEquals($oLink->getFontStyle(), null); $this->assertEquals($oLink->getParagraphStyle(), null); } + /** + * Create new instance with array + */ public function testConstructWithParamsArray() { $oLink = new Link( @@ -26,13 +46,16 @@ class LinkTest extends \PHPUnit_Framework_TestCase array('marginLeft' => 600, 'marginRight' => 600, 'marginTop' => 600, 'marginBottom' => 600) ); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $oLink); - $this->assertEquals($oLink->getLinkSrc(), 'http://www.google.com'); - $this->assertEquals($oLink->getLinkName(), 'Search Engine'); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $oLink); + $this->assertEquals($oLink->getTarget(), 'http://www.google.com'); + $this->assertEquals($oLink->getText(), 'Search Engine'); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oLink->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oLink->getParagraphStyle()); } + /** + * Create new instance with style name string + */ public function testConstructWithParamsString() { $oLink = new Link('http://www.google.com', null, 'fontStyle', 'paragraphStyle'); @@ -41,6 +64,9 @@ class LinkTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oLink->getParagraphStyle(), 'paragraphStyle'); } + /** + * Set/get relation Id + */ public function testRelationId() { $oLink = new Link('http://www.google.com'); diff --git a/tests/PhpWord/Tests/Section/ListItemTest.php b/tests/PhpWord/Tests/Element/ListItemTest.php similarity index 59% rename from tests/PhpWord/Tests/Section/ListItemTest.php rename to tests/PhpWord/Tests/Element/ListItemTest.php index 2a95bb39..6526f571 100644 --- a/tests/PhpWord/Tests/Section/ListItemTest.php +++ b/tests/PhpWord/Tests/Element/ListItemTest.php @@ -1,17 +1,37 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $oListItem->getTextObject()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $oListItem->getTextObject()); } + /** + * Get style + */ public function testStyle() { $oListItem = new ListItem( @@ -28,6 +48,9 @@ class ListItemTest extends \PHPUnit_Framework_TestCase ); } + /** + * Get depth + */ public function testDepth() { $iVal = rand(1, 1000); diff --git a/tests/PhpWord/Tests/Section/ObjectTest.php b/tests/PhpWord/Tests/Element/ObjectTest.php similarity index 65% rename from tests/PhpWord/Tests/Section/ObjectTest.php rename to tests/PhpWord/Tests/Element/ObjectTest.php index fbf34228..0f5f191a 100644 --- a/tests/PhpWord/Tests/Section/ObjectTest.php +++ b/tests/PhpWord/Tests/Element/ObjectTest.php @@ -1,40 +1,66 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Object', $oObject); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); $this->assertEquals($oObject->getSource(), $src); } + /** + * Create new instance with non-supported files + */ public function testConstructWithNotSupportedFiles() { $src = __DIR__ . "/../_files/xsl/passthrough.xsl"; $oObject = new Object($src); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Object', $oObject); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); $this->assertEquals($oObject->getSource(), null); $this->assertEquals($oObject->getStyle(), null); } + /** + * Create with style + */ public function testConstructWithSupportedFilesAndStyle() { $src = __DIR__ . "/../_files/documents/sheet.xls"; $oObject = new Object($src, array('width' => '230px')); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Object', $oObject); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Object', $oObject); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oObject->getStyle()); $this->assertEquals($oObject->getSource(), $src); } + /** + * Set/get relation Id + */ public function testRelationId() { $src = __DIR__ . "/../_files/documents/sheet.xls"; @@ -45,6 +71,9 @@ class ObjectTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oObject->getRelationId(), $iVal); } + /** + * Set/get image relation Id + */ public function testImageRelationId() { $src = __DIR__ . "/../_files/documents/sheet.xls"; @@ -54,14 +83,4 @@ class ObjectTest extends \PHPUnit_Framework_TestCase $oObject->setImageRelationId($iVal); $this->assertEquals($oObject->getImageRelationId(), $iVal); } - - public function testObjectId() - { - $src = __DIR__ . "/../_files/documents/sheet.xls"; - $oObject = new Object($src); - - $iVal = rand(1, 1000); - $oObject->setObjectId($iVal); - $this->assertEquals($oObject->getObjectId(), $iVal); - } } diff --git a/tests/PhpWord/Tests/Element/PageBreakTest.php b/tests/PhpWord/Tests/Element/PageBreakTest.php new file mode 100644 index 00000000..0c6379f5 --- /dev/null +++ b/tests/PhpWord/Tests/Element/PageBreakTest.php @@ -0,0 +1,31 @@ +assertInstanceOf('PhpOffice\\PhpWord\\Element\\PageBreak', $oPageBreak); + } +} diff --git a/tests/PhpWord/Tests/Section/Footer/PreserveTextTest.php b/tests/PhpWord/Tests/Element/PreserveTextTest.php similarity index 67% rename from tests/PhpWord/Tests/Section/Footer/PreserveTextTest.php rename to tests/PhpWord/Tests/Element/PreserveTextTest.php index f9fb9aa9..16d4361d 100644 --- a/tests/PhpWord/Tests/Section/Footer/PreserveTextTest.php +++ b/tests/PhpWord/Tests/Element/PreserveTextTest.php @@ -1,20 +1,39 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footer\\PreserveText', $oPreserveText); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\PreserveText', $oPreserveText); $this->assertEquals($oPreserveText->getText(), null); $this->assertEquals($oPreserveText->getFontStyle(), null); $this->assertEquals($oPreserveText->getParagraphStyle(), null); } + /** + * Create new instance with style name + */ public function testConstructWithString() { $oPreserveText = new PreserveText('text', 'styleFont', 'styleParagraph'); @@ -23,6 +42,9 @@ class PreserveTextTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oPreserveText->getParagraphStyle(), 'styleParagraph'); } + /** + * Create new instance with array + */ public function testConstructWithArray() { $oPreserveText = new PreserveText( diff --git a/tests/PhpWord/Tests/Section/Table/RowTest.php b/tests/PhpWord/Tests/Element/RowTest.php similarity index 60% rename from tests/PhpWord/Tests/Section/Table/RowTest.php rename to tests/PhpWord/Tests/Element/RowTest.php index a19bf3c4..e232afa8 100644 --- a/tests/PhpWord/Tests/Section/Table/RowTest.php +++ b/tests/PhpWord/Tests/Element/RowTest.php @@ -1,22 +1,42 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table\\Row', $oRow); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $oRow); $this->assertEquals($oRow->getHeight(), null); $this->assertInternalType('array', $oRow->getCells()); $this->assertCount(0, $oRow->getCells()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle()); } + /** + * Create new instance with parameters + */ public function testConstructWithParams() { $iVal = rand(1, 1000); @@ -32,12 +52,15 @@ class RowTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Row', $oRow->getStyle()); } + /** + * Add cell + */ public function testAddCell() { $oRow = new Row('section', 1); $element = $oRow->addCell(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table\\Cell', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element); $this->assertCount(1, $oRow->getCells()); } } diff --git a/tests/PhpWord/Tests/Element/SectionTest.php b/tests/PhpWord/Tests/Element/SectionTest.php new file mode 100644 index 00000000..415e43ad --- /dev/null +++ b/tests/PhpWord/Tests/Element/SectionTest.php @@ -0,0 +1,168 @@ +assertAttributeEquals($oSection->getSettings(), 'settings', new Section(0)); + } + + /** + * Get elements + */ + public function testGetElements() + { + $oSection = new Section(0); + $this->assertAttributeEquals($oSection->getElements(), 'elements', new Section(0)); + } + + /** + * Get footer + */ + public function testGetFooters() + { + $oSection = new Section(0); + $this->assertAttributeEquals($oSection->getFooters(), 'footers', new Section(0)); + } + + /** + * Get headers + */ + public function testGetHeaders() + { + $oSection = new Section(0); + $this->assertAttributeEquals($oSection->getHeaders(), 'headers', new Section(0)); + } + + /** + * Set settings + */ + public function testSetSettings() + { + $expected = 'landscape'; + $object = new Section(0); + $object->setSettings(array('orientation' => $expected)); + $this->assertEquals($expected, $object->getSettings()->getOrientation()); + } + + /** + * Add elements + */ + public function testAddElements() + { + $objectSource = __DIR__ . "/../_files/documents/reader.docx"; + $imageSource = __DIR__ . "/../_files/images/PhpWord.png"; + $imageUrl = 'http://php.net//images/logos/php-med-trans-light.gif'; + + $section = new Section(0); + $section->addText(utf8_decode('ä')); + $section->addLink(utf8_decode('http://äää.com'), utf8_decode('ä')); + $section->addTextBreak(); + $section->addPageBreak(); + $section->addTable(); + $section->addListItem(utf8_decode('ä')); + $section->addObject($objectSource); + $section->addImage($imageSource); + $section->addTitle(utf8_decode('ä'), 1); + $section->addTextRun(); + $section->addFootnote(); + $section->addCheckBox(utf8_decode('chkä'), utf8_decode('Contentä')); + $section->addTOC(); + + $elementCollection = $section->getElements(); + $elementTypes = array('Text', 'Link', 'TextBreak', 'PageBreak', + 'Table', 'ListItem', 'Object', 'Image', + 'Title', 'TextRun', 'Footnote', 'CheckBox', 'TOC'); + $i = 0; + foreach ($elementTypes as $elementType) { + $this->assertInstanceOf("PhpOffice\\PhpWord\\Element\\{$elementType}", $elementCollection[$i]); + $i++; + } + } + + /** + * Test add object exception + * + * @expectedException \PhpOffice\PhpWord\Exception\InvalidObjectException + */ + public function testAddObjectException() + { + $source = __DIR__ . "/_files/xsl/passthrough.xsl"; + $section = new Section(0); + $section->addObject($source); + } + + /** + * Add title with predefined style + */ + public function testAddTitleWithStyle() + { + Style::addTitleStyle(1, array('size' => 14)); + $section = new Section(0); + $section->addTitle('Test', 1); + $elementCollection = $section->getElements(); + + $this->assertInstanceOf("PhpOffice\\PhpWord\\Element\\Title", $elementCollection[0]); + } + + /** + * Create header footer + */ + public function testCreateHeaderFooter() + { + $object = new Section(0); + $elements = array('Header', 'Footer'); + + foreach ($elements as $element) { + $method = "create{$element}"; + $this->assertInstanceOf("PhpOffice\\PhpWord\\Element\\{$element}", $object->$method()); + } + $this->assertFalse($object->hasDifferentFirstPage()); + } + + /** + * Add header has different first page + */ + public function testHasDifferentFirstPage() + { + $object = new Section(1); + $header = $object->addHeader(); + $header->setType(Header::FIRST); + $this->assertTrue($object->hasDifferentFirstPage()); + } + + /** + * Add header exception + * + * @expectedException Exception + * @expectedExceptionMesssage Invalid header/footer type. + */ + public function testAddHeaderException() + { + $object = new Section(1); + $header = $object->addHeader('ODD'); + } +} diff --git a/tests/PhpWord/Tests/Element/TOCTest.php b/tests/PhpWord/Tests/Element/TOCTest.php new file mode 100644 index 00000000..207f6969 --- /dev/null +++ b/tests/PhpWord/Tests/Element/TOCTest.php @@ -0,0 +1,80 @@ + 9062, + 'tabLeader' => \PhpOffice\PhpWord\Style\TOC::TABLEADER_DOT, + 'indent' => 200, + ); + $object = new TOC(array('_size' => 11), array('_tabPos' => $expected['tabPos'])); + $tocStyle = $object->getStyleTOC(); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\TOC', $tocStyle); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $object->getStyleFont()); + + foreach ($expected as $key => $value) { + $method = "get{$key}"; + $this->assertEquals($value, $tocStyle->$method()); + } + } + + /** + * Construct with named font style + */ + public function testConstructWithStyleName() + { + $object = new TOC('Font Style'); + $tocStyle = $object->getStyleTOC(); + + $this->assertEquals('Font Style', $object->getStyleFont()); + } + + /** + * Set/get minDepth and maxDepth + */ + public function testSetGetMinMaxDepth() + { + $toc = new TOC(); + $titles = array( + 'Heading 1' => 1, + 'Heading 2' => 2, + 'Heading 3' => 3, + 'Heading 4' => 4, + ); + foreach ($titles as $text => $depth) { + \PhpOffice\PhpWord\TOC::addTitle($text, $depth); + } + + $this->assertEquals(1, $toc->getMinDepth()); + $this->assertEquals(9, $toc->getMaxDepth()); + + $toc->setMinDepth(2); + $toc->setMaxDepth(3); + $toc->getTitles(); + + $this->assertEquals(2, $toc->getMinDepth()); + $this->assertEquals(3, $toc->getMaxDepth()); + } +} diff --git a/tests/PhpWord/Tests/Element/TableTest.php b/tests/PhpWord/Tests/Element/TableTest.php new file mode 100644 index 00000000..3fc51f98 --- /dev/null +++ b/tests/PhpWord/Tests/Element/TableTest.php @@ -0,0 +1,106 @@ +assertInstanceOf('PhpOffice\\PhpWord\\Element\\Table', $oTable); + $this->assertEquals($oTable->getStyle(), null); + $this->assertEquals($oTable->getWidth(), null); + $this->assertEquals($oTable->getRows(), array()); + $this->assertCount(0, $oTable->getRows()); + } + + /** + * Get style name + */ + public function testStyleText() + { + $oTable = new Table('section', 1, 'tableStyle'); + + $this->assertEquals($oTable->getStyle(), 'tableStyle'); + } + + /** + * Get style array + */ + public function testStyleArray() + { + $oTable = new Table('section', 1, array( + 'borderSize' => 6, + 'borderColor' => '006699', + 'cellMargin' => 80 + )); + + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $oTable->getStyle()); + } + + /** + * Set/get width + */ + public function testWidth() + { + $oTable = new Table('section', 1); + $iVal = rand(1, 1000); + $oTable->setWidth($iVal); + $this->assertEquals($oTable->getWidth(), $iVal); + } + + /** + * Add/get row + */ + public function testRow() + { + $oTable = new Table('section', 1); + $element = $oTable->addRow(); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Row', $element); + $this->assertCount(1, $oTable->getRows()); + } + + /** + * Add cell + */ + public function testCell() + { + $oTable = new Table('section', 1); + $oTable->addRow(); + $element = $oTable->addCell(); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Cell', $element); + } + + /** + * Add cell + */ + public function testCountColumns() + { + $oTable = new Table('section', 1); + $oTable->addRow(); + $element = $oTable->addCell(); + $this->assertEquals($oTable->countColumns(), 1); + $element = $oTable->addCell(); + $element = $oTable->addCell(); + $this->assertEquals($oTable->countColumns(), 3); + } +} diff --git a/tests/PhpWord/Tests/Section/TextBreakTest.php b/tests/PhpWord/Tests/Element/TextBreakTest.php similarity index 80% rename from tests/PhpWord/Tests/Section/TextBreakTest.php rename to tests/PhpWord/Tests/Element/TextBreakTest.php index 32410743..c228215f 100644 --- a/tests/PhpWord/Tests/Section/TextBreakTest.php +++ b/tests/PhpWord/Tests/Element/TextBreakTest.php @@ -1,12 +1,22 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $oTextRun); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); $this->assertCount(0, $oTextRun->getElements()); $this->assertEquals($oTextRun->getParagraphStyle(), null); } + /** + * New instance with string + */ public function testConstructString() { $oTextRun = new TextRun('pStyle'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $oTextRun); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); $this->assertCount(0, $oTextRun->getElements()); $this->assertEquals($oTextRun->getParagraphStyle(), 'pStyle'); } + /** + * New instance with array + */ public function testConstructArray() { $oTextRun = new TextRun(array('spacing' => 100)); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\TextRun', $oTextRun); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $oTextRun); $this->assertCount(0, $oTextRun->getElements()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oTextRun->getParagraphStyle()); } + /** + * Add text + */ public function testAddText() { $oTextRun = new TextRun(); $element = $oTextRun->addText('text'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oTextRun->getElements()); $this->assertEquals($element->getText(), 'text'); } + /** + * Add text non-UTF8 + */ public function testAddTextNotUTF8() { $oTextRun = new TextRun(); $element = $oTextRun->addText(utf8_decode('ééé')); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $element); $this->assertCount(1, $oTextRun->getElements()); $this->assertEquals($element->getText(), 'ééé'); } + /** + * Add link + */ public function testAddLink() { $oTextRun = new TextRun(); $element = $oTextRun->addLink('http://www.google.fr'); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oTextRun->getElements()); - $this->assertEquals($element->getLinkSrc(), 'http://www.google.fr'); + $this->assertEquals($element->getTarget(), 'http://www.google.fr'); } + /** + * Add link with name + */ public function testAddLinkWithName() { $oTextRun = new TextRun(); $element = $oTextRun->addLink('http://www.google.fr', utf8_decode('ééé')); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Link', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Link', $element); $this->assertCount(1, $oTextRun->getElements()); - $this->assertEquals($element->getLinkSrc(), 'http://www.google.fr'); - $this->assertEquals($element->getLinkName(), 'ééé'); + $this->assertEquals($element->getTarget(), 'http://www.google.fr'); + $this->assertEquals($element->getText(), 'ééé'); } + /** + * Add text break + */ + public function testAddTextBreak() + { + $oTextRun = new TextRun(); + $element = $oTextRun->addTextBreak(2); + + $this->assertCount(2, $oTextRun->getElements()); + } + + /** + * Add image + */ public function testAddImage() { $src = __DIR__ . "/../_files/images/earth.jpg"; @@ -80,16 +128,19 @@ class TextRunTest extends \PHPUnit_Framework_TestCase $oTextRun = new TextRun(); $element = $oTextRun->addImage($src); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Image', $element); $this->assertCount(1, $oTextRun->getElements()); } + /** + * Add footnote + */ public function testCreateFootnote() { $oTextRun = new TextRun(); - $element = $oTextRun->createFootnote(); + $element = $oTextRun->addFootnote(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Footnote', $element); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Footnote', $element); $this->assertCount(1, $oTextRun->getElements()); } } diff --git a/tests/PhpWord/Tests/Section/TextTest.php b/tests/PhpWord/Tests/Element/TextTest.php similarity index 60% rename from tests/PhpWord/Tests/Section/TextTest.php rename to tests/PhpWord/Tests/Element/TextTest.php index f17abc3f..953dfc8f 100644 --- a/tests/PhpWord/Tests/Section/TextTest.php +++ b/tests/PhpWord/Tests/Element/TextTest.php @@ -1,20 +1,40 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Text', $oText); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Text', $oText); $this->assertEquals(null, $oText->getText()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oText->getFontStyle()); $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle()); } + /** + * Get text + */ public function testText() { $oText = new Text('text'); @@ -22,6 +42,9 @@ class TextTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oText->getText(), 'text'); } + /** + * Get font style + */ public function testFont() { $oText = new Text('text', 'fontStyle'); @@ -31,6 +54,19 @@ class TextTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $oText->getFontStyle()); } + /** + * Get font style as object + */ + public function testFontObject() + { + $font = new Font(); + $oText = new Text('text', $font); + $this->assertEquals($oText->getFontStyle(), $font); + } + + /** + * Get paragraph style + */ public function testParagraph() { $oText = new Text('text', 'fontStyle', 'paragraphStyle'); diff --git a/tests/PhpWord/Tests/Section/TitleTest.php b/tests/PhpWord/Tests/Element/TitleTest.php similarity index 58% rename from tests/PhpWord/Tests/Section/TitleTest.php rename to tests/PhpWord/Tests/Element/TitleTest.php index 7c547c5e..6c472b0d 100644 --- a/tests/PhpWord/Tests/Section/TitleTest.php +++ b/tests/PhpWord/Tests/Element/TitleTest.php @@ -1,18 +1,38 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Title', $oTitle); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\Title', $oTitle); $this->assertEquals($oTitle->getText(), 'text'); } + /** + * Get style null + */ public function testStyleNull() { $oTitle = new Title('text'); @@ -20,6 +40,9 @@ class TitleTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTitle->getStyle(), null); } + /** + * Get style not null + */ public function testStyleNotNull() { $oTitle = new Title('text', 1, 'style'); @@ -27,6 +50,9 @@ class TitleTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTitle->getStyle(), 'style'); } + /** + * Get anchor + */ public function testAnchor() { $oTitle = new Title('text'); @@ -36,6 +62,9 @@ class TitleTest extends \PHPUnit_Framework_TestCase $this->assertEquals($oTitle->getAnchor(), $iVal); } + /** + * Get bookmark Id + */ public function testBookmarkID() { $oTitle = new Title('text'); diff --git a/tests/PhpWord/Tests/EndnotesTest.php b/tests/PhpWord/Tests/EndnotesTest.php new file mode 100644 index 00000000..a72e85f9 --- /dev/null +++ b/tests/PhpWord/Tests/EndnotesTest.php @@ -0,0 +1,39 @@ +assertEquals(1, $rId); + $this->assertEquals(1, count(Endnotes::getElements())); + $this->assertEquals($endnote2, Endnotes::getElement(1)); + $this->assertNull(Endnotes::getElement(2)); + + Endnotes::resetElements(); + $this->assertEquals(0, Endnotes::countElements()); + } +} diff --git a/tests/PhpWord/Tests/Exception/ExceptionTest.php b/tests/PhpWord/Tests/Exception/ExceptionTest.php new file mode 100644 index 00000000..04eb03e0 --- /dev/null +++ b/tests/PhpWord/Tests/Exception/ExceptionTest.php @@ -0,0 +1,32 @@ +assertEquals(1, $rId); + $this->assertEquals(1, count(Footnotes::getElements())); + $this->assertEquals($footnote2, Footnotes::getElement(1)); + $this->assertNull(Footnotes::getElement(2)); + + Footnotes::resetElements(); + $this->assertEquals(0, Footnotes::countElements()); + } +} diff --git a/tests/PhpWord/Tests/IOFactoryTest.php b/tests/PhpWord/Tests/IOFactoryTest.php index dafc19ea..405eabe0 100644 --- a/tests/PhpWord/Tests/IOFactoryTest.php +++ b/tests/PhpWord/Tests/IOFactoryTest.php @@ -1,19 +1,28 @@ assertInstanceOf( 'PhpOffice\\PhpWord\\Writer\\Word2007', @@ -22,18 +31,19 @@ final class IOFactoryTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::createWriter - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Create non-existing writer + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ - final public function testNonexistentWriterCanNotBeCreated() + public function testNonexistentWriterCanNotBeCreated() { IOFactory::createWriter(new PhpWord(), 'Word2006'); } /** - * @covers ::createReader + * Create existing reader */ - final public function testExistingReaderCanBeCreated() + public function testExistingReaderCanBeCreated() { $this->assertInstanceOf( 'PhpOffice\\PhpWord\\Reader\\Word2007', @@ -42,11 +52,24 @@ final class IOFactoryTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::createReader - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Create non-existing reader + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ - final public function testNonexistentReaderCanNotBeCreated() + public function testNonexistentReaderCanNotBeCreated() { IOFactory::createReader('Word2006'); } + + /** + * Load document + */ + public function testLoad() + { + $file = __DIR__ . "/_files/templates/blank.docx"; + $this->assertInstanceOf( + 'PhpOffice\\PhpWord\\PhpWord', + IOFactory::load($file) + ); + } } diff --git a/tests/PhpWord/Tests/MediaTest.php b/tests/PhpWord/Tests/MediaTest.php index 0bde5539..0b98bfd2 100644 --- a/tests/PhpWord/Tests/MediaTest.php +++ b/tests/PhpWord/Tests/MediaTest.php @@ -1,58 +1,112 @@ assertEquals(Media::getSectionMediaElements(), array()); - } - - public function testCountSectionMediaElementsWithNull() - { - $this->assertEquals(Media::countSectionMediaElements(), 0); - } - - public function testGetHeaderMediaElements() - { - $this->assertAttributeEquals( - Media::getHeaderMediaElements(), - '_headerMedia', - 'PhpOffice\\PhpWord\\Media' - ); - } - - public function testGetFooterMediaElements() - { - $this->assertAttributeEquals( - Media::getFooterMediaElements(), - '_footerMedia', - 'PhpOffice\\PhpWord\\Media' - ); + $this->assertEquals(Media::getElements('section'), array()); } /** - * Todo: add memory image to this test - * - * @covers \PhpOffice\PhpWord\Media::addSectionMediaElement + * Count section media elements + */ + public function testCountSectionMediaElementsWithNull() + { + $this->assertEquals(Media::countElements('section'), 0); + } + + /** + * Add section media element */ public function testAddSectionMediaElement() { - $section = new Section(0); - $section->addImage(__DIR__ . "/_files/images/mars_noext_jpg"); - $section->addImage(__DIR__ . "/_files/images/mars.jpg"); - $section->addImage(__DIR__ . "/_files/images/mario.gif"); - $section->addImage(__DIR__ . "/_files/images/firefox.png"); - $section->addImage(__DIR__ . "/_files/images/duke_nukem.bmp"); - $section->addImage(__DIR__ . "/_files/images/angela_merkel.tif"); + $local = __DIR__ . "/_files/images/mars.jpg"; + $object = __DIR__ . "/_files/documents/sheet.xls"; + $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; + Media::addElement('section', 'image', $local, new Image($local)); + Media::addElement('section', 'image', $local, new Image($local)); + Media::addElement('section', 'image', $remote, new Image($local)); + Media::addElement('section', 'object', $object); + Media::addElement('section', 'object', $object); - $elements = $section->getElements(); - $this->assertEquals(6, count($elements)); - foreach ($elements as $element) { - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $element); - } + $this->assertEquals(3, Media::countElements('section')); + } + + /** + * Add section link + */ + public function testAddSectionLinkElement() + { + $expected = Media::countElements('section') + 1; + $actual = Media::addElement('section', 'link', 'http://test.com'); + + $this->assertEquals($expected, $actual); + $this->assertEquals(1, Media::countElements('section', 'link')); + $this->assertEquals(1, count(Media::getElements('section', 'link'))); + } + + /** + * Add header media element + */ + public function testAddHeaderMediaElement() + { + $local = __DIR__ . "/_files/images/mars.jpg"; + $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; + Media::addElement('header1', 'image', $local, new Image($local)); + Media::addElement('header1', 'image', $local, new Image($local)); + Media::addElement('header1', 'image', $remote, new Image($remote)); + + $this->assertEquals(2, Media::countElements('header1')); + $this->assertEquals(2, count(Media::getElements('header1'))); + $this->assertEmpty(Media::getElements('header2')); + } + + /** + * Add footer media element and reset media + */ + public function testAddFooterMediaElement() + { + $local = __DIR__ . "/_files/images/mars.jpg"; + $remote = 'http://php.net/images/logos/php-med-trans-light.gif'; + Media::addElement('footer1', 'image', $local, new Image($local)); + Media::addElement('footer1', 'image', $local, new Image($local)); + Media::addElement('footer1', 'image', $remote, new Image($remote)); + + $this->assertEquals(2, Media::countElements('footer1')); + + Media::resetElements(); + $this->assertEquals(0, Media::countElements('footer1')); + } + + /** + * Add image element exception + * + * @expectedException Exception + * @expectedExceptionMessage Image object not assigned. + */ + public function testAddElementImageException() + { + Media::addElement('section', 'image', __DIR__ . "/_files/images/mars.jpg"); } } diff --git a/tests/PhpWord/Tests/PhpWordTest.php b/tests/PhpWord/Tests/PhpWordTest.php index bcabcfb3..8de6f808 100644 --- a/tests/PhpWord/Tests/PhpWordTest.php +++ b/tests/PhpWord/Tests/PhpWordTest.php @@ -1,22 +1,28 @@ assertEquals(new Section(1), $phpWord->createSection()); - $phpWord->createSection(); - $this->assertEquals(2, \count($phpWord->getSections())); + $this->assertEquals(new Section(1), $phpWord->addSection()); + $phpWord->addSection(); + $this->assertEquals(2, count($phpWord->getSections())); } /** - * @covers ::setDefaultFontName - * @covers ::getDefaultFontName + * Test set/get default font name */ public function testSetGetDefaultFontName() { @@ -66,8 +69,7 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::setDefaultFontSize - * @covers ::getDefaultFontSize + * Test set/get default font size */ public function testSetGetDefaultFontSize() { @@ -79,8 +81,7 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::setDefaultParagraphStyle - * @covers ::loadTemplate + * Test set default paragraph style */ public function testSetDefaultParagraphStyle() { @@ -90,10 +91,7 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::addParagraphStyle - * @covers ::addFontStyle - * @covers ::addTableStyle - * @covers ::addLinkStyle + * Test add styles */ public function testAddStyles() { @@ -114,7 +112,7 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::addTitleStyle + * Test add title style */ public function testAddTitleStyle() { @@ -126,7 +124,7 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::loadTemplate + * Test load template */ public function testLoadTemplate() { @@ -140,14 +138,15 @@ class PhpWordTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::loadTemplate - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Test load template exception + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testLoadTemplateException() { - $templateFqfn = \join( - \DIRECTORY_SEPARATOR, - array(\PHPWORD_TESTS_BASE_DIR, 'PhpWord', 'Tests', 'data', 'templates', 'blanks.docx') + $templateFqfn = join( + DIRECTORY_SEPARATOR, + array(PHPWORD_TESTS_BASE_DIR, 'PhpWord', 'Tests', '_files', 'templates', 'blanks.docx') ); $phpWord = new PhpWord(); $phpWord->loadTemplate($templateFqfn); diff --git a/tests/PhpWord/Tests/Reader/ODTextTest.php b/tests/PhpWord/Tests/Reader/ODTextTest.php new file mode 100644 index 00000000..6136b0c4 --- /dev/null +++ b/tests/PhpWord/Tests/Reader/ODTextTest.php @@ -0,0 +1,31 @@ +assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object); + } +} diff --git a/tests/PhpWord/Tests/Reader/Word2007Test.php b/tests/PhpWord/Tests/Reader/Word2007Test.php index f372a9e2..3a572f4d 100644 --- a/tests/PhpWord/Tests/Reader/Word2007Test.php +++ b/tests/PhpWord/Tests/Reader/Word2007Test.php @@ -1,9 +1,23 @@ assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $oImage); - $this->assertEquals($oImage->getSource(), $src); - $this->assertEquals($oImage->getMediaId(), md5($src)); - $this->assertEquals($oImage->getIsWatermark(), false); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); - } - - public function testConstructWithStyle() - { - $src = __DIR__ . "/../_files/images/firefox.png"; - $oImage = new Image( - $src, - array('width' => 210, 'height' => 210, 'align' => 'center', - 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_BEHIND) - ); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); - } - - /** - * @covers ::__construct - */ - public function testValidImageTypes() - { - 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"); - } - - /** - * @expectedException \PhpOffice\PhpWord\Exceptions\InvalidImageException - * @covers ::__construct - */ - public function testImageNotFound() - { - new Image(__DIR__ . "/../_files/images/thisisnotarealimage"); - } - - /** - * @expectedException \PhpOffice\PhpWord\Exceptions\UnsupportedImageTypeException - * @covers ::__construct - */ - public function testInvalidImageTypes() - { - new Image(__DIR__ . "/../_files/images/alexz-johnson.pcx"); - } - - public function testStyle() - { - $oImage = new Image( - __DIR__ . "/../_files/images/earth.jpg", - array('width' => 210, 'height' => 210, 'align' => 'center') - ); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle()); - } - - public function testRelationID() - { - $oImage = new Image(__DIR__ . "/../_files/images/earth.jpg"); - $iVal = rand(1, 1000); - $oImage->setRelationId($iVal); - $this->assertEquals($oImage->getRelationId(), $iVal); - } - - public function testWatermark() - { - $oImage = new Image(__DIR__ . "/../_files/images/earth.jpg"); - $oImage->setIsWatermark(true); - $this->assertEquals($oImage->getIsWatermark(), true); - } - public function testPNG() - { - $src = __DIR__ . "/../_files/images/firefox.png"; - $oImage = new Image($src); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\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'); - } - - public function testGIF() - { - $src = __DIR__ . "/../_files/images/mario.gif"; - $oImage = new Image($src); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\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'); - } - - public function testJPG() - { - $src = __DIR__ . "/../_files/images/earth.jpg"; - $oImage = new Image($src); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\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'); - } - - public function testBMP() - { - $oImage = new Image(__DIR__ . "/../_files/images/duke_nukem.bmp"); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Image', $oImage); - $this->assertEquals($oImage->getImageCreateFunction(), null); - $this->assertEquals($oImage->getImageFunction(), null); - $this->assertEquals($oImage->getImageExtension(), 'bmp'); - $this->assertEquals($oImage->getImageType(), 'image/bmp'); - } -} diff --git a/tests/PhpWord/Tests/Section/PageBreakTest.php b/tests/PhpWord/Tests/Section/PageBreakTest.php deleted file mode 100644 index 4bf414ad..00000000 --- a/tests/PhpWord/Tests/Section/PageBreakTest.php +++ /dev/null @@ -1,18 +0,0 @@ -assertInstanceOf('PhpOffice\\PhpWord\\Section\\PageBreak', $oPageBreak); - } -} diff --git a/tests/PhpWord/Tests/Section/TableTest.php b/tests/PhpWord/Tests/Section/TableTest.php deleted file mode 100644 index df00a232..00000000 --- a/tests/PhpWord/Tests/Section/TableTest.php +++ /dev/null @@ -1,60 +0,0 @@ -assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table', $oTable); - $this->assertEquals($oTable->getStyle(), null); - $this->assertEquals($oTable->getWidth(), null); - $this->assertEquals($oTable->getRows(), array()); - $this->assertCount(0, $oTable->getRows()); - } - - public function testStyleText() - { - $oTable = new Table('section', 1, 'tableStyle'); - - $this->assertEquals($oTable->getStyle(), 'tableStyle'); - } - - public function testStyleArray() - { - $oTable = new Table( - 'section', - 1, - array('borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80) - ); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Table', $oTable->getStyle()); - } - - public function testWidth() - { - $oTable = new Table('section', 1); - $iVal = rand(1, 1000); - $oTable->setWidth($iVal); - $this->assertEquals($oTable->getWidth(), $iVal); - } - - public function testRow() - { - $oTable = new Table('section', 1); - $element = $oTable->addRow(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table\\Row', $element); - $this->assertCount(1, $oTable->getRows()); - } - - public function testCell() - { - $oTable = new Table('section', 1); - $oTable->addRow(); - $element = $oTable->addCell(); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Table\\Cell', $element); - } -} diff --git a/tests/PhpWord/Tests/SectionTest.php b/tests/PhpWord/Tests/SectionTest.php deleted file mode 100644 index 629f8dde..00000000 --- a/tests/PhpWord/Tests/SectionTest.php +++ /dev/null @@ -1,120 +0,0 @@ -assertAttributeEquals($oSection->getSettings(), '_settings', new Section(0)); - } - - /** - * @covers ::getElements - */ - public function testGetElements() - { - $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getElements(), '_elementCollection', new Section(0)); - } - - /** - * @covers ::getFooter - */ - public function testGetFooter() - { - $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getFooter(), '_footer', new Section(0)); - } - - /** - * @covers ::getHeaders - */ - public function testGetHeaders() - { - $oSection = new Section(0); - $this->assertAttributeEquals($oSection->getHeaders(), '_headers', new Section(0)); - } - - /** - * @covers ::setSettings - */ - public function testSetSettings() - { - $expected = 'landscape'; - $object = new Section(0); - $object->setSettings(array('orientation' => $expected)); - $this->assertEquals($expected, $object->getSettings()->getOrientation()); - } - - /** - * @covers ::addText - * @covers ::addLink - * @covers ::addTextBreak - * @covers ::addPageBreak - * @covers ::addTable - * @covers ::addListItem - * @covers ::addObject - * @covers ::addImage - * @covers ::addTOC - * @covers ::addTitle - * @covers ::createTextRun - * @covers ::createFootnote - */ - public function testAddElements() - { - $objectSource = __DIR__ . "/_files/documents/sheet.xls"; - $imageSource = __DIR__ . "/_files/images/PhpWord.png"; - $imageUrl = 'http://php.net//images/logos/php-med-trans-light.gif'; - - $section = new Section(0); - $section->addText(utf8_decode('ä')); - $section->addLink(utf8_decode('http://äää.com'), utf8_decode('ä')); - $section->addTextBreak(); - $section->addPageBreak(); - $section->addTable(); - $section->addListItem(utf8_decode('ä')); - $section->addObject($objectSource); - $section->addImage($imageSource); - $section->addImage($imageUrl); - $section->addTOC(); - $section->addTitle(utf8_decode('ä'), 1); - $section->createTextRun(); - $section->createFootnote(); - - $elementCollection = $section->getElements(); - $elementType = 'Link'; - $this->assertInstanceOf("PhpOffice\\PhpWord\\Section\\{$elementType}", $elementCollection[1]); - // $elementTypes = array('Text', 'Link', 'TextBreak', 'PageBreak', - // 'Table', 'ListItem', 'Object', 'Image', 'Image', 'TOC', - // 'Title', 'TextRun'); - // $i = 0; - // foreach ($elementTypes as $elementType) { - // $this->assertInstanceOf("PhpOffice\\PhpWord\\Section\\{$elementType}", $elementCollection[$i]); - // $i++; - // } - } - - /** - * @covers ::createHeader - * @covers ::createFooter - */ - public function testCreateHeaderFooter() - { - $object = new Section(0); - $elements = array('Header', 'Footer'); - foreach ($elements as $element) { - $method = "create{$element}"; - $this->assertInstanceOf("PhpOffice\\PhpWord\\Section\\{$element}", $object->$method()); - } - } -} diff --git a/tests/PhpWord/Tests/SettingsTest.php b/tests/PhpWord/Tests/SettingsTest.php index e80679dd..64a09994 100644 --- a/tests/PhpWord/Tests/SettingsTest.php +++ b/tests/PhpWord/Tests/SettingsTest.php @@ -1,23 +1,65 @@ assertTrue(Settings::getCompatibility()); $this->assertTrue(Settings::setCompatibility(false)); $this->assertFalse(Settings::getCompatibility()); $this->assertFalse(Settings::setCompatibility('Non boolean')); } + + /** + * Test set/get zip class + */ + public function testSetGetZipClass() + { + $this->assertEquals(Settings::ZIPARCHIVE, Settings::getZipClass()); + $this->assertTrue(Settings::setZipClass(Settings::PCLZIP)); + $this->assertFalse(Settings::setZipClass('foo')); + } + + /** + * Test set/get PDF renderer + */ + 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')); + } + + /** + * Test set/get measurement unit + */ + public function testSetGetMeasurementUnit() + { + $this->assertEquals(Settings::UNIT_TWIP, Settings::getMeasurementUnit()); + $this->assertTrue(Settings::setMeasurementUnit(Settings::UNIT_INCH)); + $this->assertFalse(Settings::setMeasurementUnit('foo')); + } } diff --git a/tests/PhpWord/Tests/Shared/DrawingTest.php b/tests/PhpWord/Tests/Shared/DrawingTest.php index c9ccf515..713cebcd 100644 --- a/tests/PhpWord/Tests/Shared/DrawingTest.php +++ b/tests/PhpWord/Tests/Shared/DrawingTest.php @@ -1,9 +1,20 @@ assertTrue(String::isUTF8('')); @@ -16,12 +29,18 @@ class StringTest extends \PHPUnit_Framework_TestCase $this->assertFalse(String::isUTF8(utf8_decode('éééé'))); } + /** + * OOXML to PHP control character + */ public function testControlCharacterOOXML2PHP() { $this->assertEquals('', String::controlCharacterOOXML2PHP('')); $this->assertEquals(chr(0x08), String::controlCharacterOOXML2PHP('_x0008_')); } + /** + * PHP to OOXML control character + */ public function testControlCharacterPHP2OOXML() { $this->assertEquals('', String::controlCharacterPHP2OOXML('')); diff --git a/tests/PhpWord/Tests/Shared/XMLReaderTest.php b/tests/PhpWord/Tests/Shared/XMLReaderTest.php new file mode 100644 index 00000000..759bf580 --- /dev/null +++ b/tests/PhpWord/Tests/Shared/XMLReaderTest.php @@ -0,0 +1,54 @@ +assertFalse($object->getDomFromZip($filename, 'yadayadaya')); + } + + /** + * Test get elements returns empty + */ + public function testGetElementsReturnsEmpty() + { + $object = new XMLReader(); + $this->assertEquals(array(), $object->getElements('w:document')); + } + + /** + * Test get element returns null + */ + public function testGetElementReturnsNull() + { + $filename = __DIR__ . "/../_files/documents/reader.docx.zip"; + + $object = new XMLReader(); + $object->getDomFromZip($filename, '[Content_Types].xml'); + $element = $object->getElements('*')->item(0); + + $this->assertNull($object->getElement('yadayadaya', $element)); + } +} diff --git a/tests/PhpWord/Tests/Shared/ZipArchiveTest.php b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php new file mode 100644 index 00000000..2e45fcf8 --- /dev/null +++ b/tests/PhpWord/Tests/Shared/ZipArchiveTest.php @@ -0,0 +1,86 @@ + + */ + public function testAllMethods() + { + // 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"; + @mkdir($destination1); + @mkdir($destination2); + @mkdir($destination3); + + $object = new ZipArchive(); + $object->open($zipFile); + $object->addFile($existingFile, 'xls/new.xls'); + $object->addFromString('content/string.txt', 'Test'); + $object->close(); + + // 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); + $this->deleteDir($destination3); + @unlink($zipFile); + } + + /** + * 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/tests/PhpWord/Tests/Style/AbstractStyleTest.php b/tests/PhpWord/Tests/Style/AbstractStyleTest.php new file mode 100644 index 00000000..ae11c27c --- /dev/null +++ b/tests/PhpWord/Tests/Style/AbstractStyleTest.php @@ -0,0 +1,70 @@ +getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); + $stub->setStyleByArray(array('index' => 1)); + + $this->assertEquals(1, $stub->getIndex()); + } + + /** + * Test setBoolVal, setIntVal, setFloatVal, setEnumVal with normal value + */ + public function testSetValNormal() + { + $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); + + $this->assertEquals(true, self::callProtectedMethod($stub, 'setBoolVal', array(true, false))); + $this->assertEquals(12, self::callProtectedMethod($stub, 'setIntVal', array(12, 200))); + $this->assertEquals(871.1, self::callProtectedMethod($stub, 'setFloatVal', array(871.1, 2.1))); + $this->assertEquals('a', self::callProtectedMethod($stub, 'setEnumVal', array('a', array('a', 'b'), 'b'))); + } + + /** + * Test setBoolVal, setIntVal, setFloatVal, setEnumVal with default value + */ + public function testSetValDefault() + { + $stub = $this->getMockForAbstractClass('\PhpOffice\PhpWord\Style\AbstractStyle'); + + $this->assertEquals(false, self::callProtectedMethod($stub, 'setBoolVal', array('a', false))); + $this->assertEquals(200, self::callProtectedMethod($stub, 'setIntVal', array('foo', 200))); + $this->assertEquals(2.1, self::callProtectedMethod($stub, 'setFloatVal', array('foo', 2.1))); + $this->assertEquals('b', self::callProtectedMethod($stub, 'setEnumVal', array('z', array('a', 'b'), 'b'))); + } + + /** + * Helper function to call protected method + * + * @param mixed $object + * @param string $method + * @param array $args + */ + public static function callProtectedMethod($object, $method, array $args = array()) + { + $class = new \ReflectionClass(get_class($object)); + $method = $class->getMethod($method); + $method->setAccessible(true); + return $method->invokeArgs($object, $args); + } +} diff --git a/tests/PhpWord/Tests/Style/CellTest.php b/tests/PhpWord/Tests/Style/CellTest.php index bbdb6535..5e3d959d 100644 --- a/tests/PhpWord/Tests/Style/CellTest.php +++ b/tests/PhpWord/Tests/Style/CellTest.php @@ -1,9 +1,20 @@ assertEquals($default, $object->getDefaultBorderColor()); - - $object->setStyleValue('_defaultBorderColor', $value); - $this->assertEquals($value, $object->getDefaultBorderColor()); - - $object->setStyleValue('_borderColor', $value); + $object->setStyleValue('borderColor', $value); $expected = array($value, $value, $value, $value); $this->assertEquals($expected, $object->getBorderColor()); } @@ -67,7 +73,7 @@ class CellTest extends \PHPUnit_Framework_TestCase $value = 120; $expected = array($value, $value, $value, $value); - $object->setStyleValue('_borderSize', $value); + $object->setStyleValue('borderSize', $value); $this->assertEquals($expected, $object->getBorderSize()); } } diff --git a/tests/PhpWord/Tests/Style/FontTest.php b/tests/PhpWord/Tests/Style/FontTest.php index 4d2d2615..9185d646 100644 --- a/tests/PhpWord/Tests/Style/FontTest.php +++ b/tests/PhpWord/Tests/Style/FontTest.php @@ -1,4 +1,12 @@ false, 'color' => PhpWord::DEFAULT_FONT_COLOR, 'fgColor' => null, + 'bgColor' => null, + 'hint' => PhpWord::DEFAULT_FONT_CONTENT_TYPE, ); foreach ($attributes as $key => $default) { $get = "get{$key}"; - $object->setStyleValue("_$key", null); + $object->setStyleValue("$key", null); $this->assertEquals($default, $object->$get()); - $object->setStyleValue("_$key", ''); + $object->setStyleValue("$key", ''); $this->assertEquals($default, $object->$get()); } } @@ -67,23 +82,28 @@ class FontTest extends \PHPUnit_Framework_TestCase 'bold' => true, 'italic' => true, 'superScript' => true, - 'subScript' => true, + 'subScript' => false, 'underline' => Font::UNDERLINE_HEAVY, 'strikethrough' => true, 'color' => '999999', - 'fgColor' => '999999', + 'fgColor' => Font::FGCOLOR_YELLOW, + 'bgColor' => 'FFFF00', + 'hint' => 'eastAsia', ); + $object->setArrayStyle($attributes); foreach ($attributes as $key => $value) { $get = "get{$key}"; - $object->setStyleValue("_$key", $value); $this->assertEquals($value, $object->$get()); } } + /** + * Test set line height + */ public function testLineHeight() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); // Test style array $text = $section->addText('This is a test', array( @@ -110,4 +130,25 @@ class FontTest extends \PHPUnit_Framework_TestCase $this->assertEquals(720, $lineHeight); $this->assertEquals('auto', $lineRule); } + + /** + * Test line height floatval + */ + public function testLineHeightFloatval() + { + $object = new Font(null, array('align' => 'center')); + $object->setLineHeight('1.5pt'); + $this->assertEquals(1.5, $object->getLineHeight()); + } + + /** + * Test line height exception by using nonnumeric value + * + * @expectedException \PhpOffice\PhpWord\Exception\InvalidStyleException + */ + public function testLineHeightException() + { + $object = new Font(); + $object->setLineHeight('a'); + } } diff --git a/tests/PhpWord/Tests/Style/ImageTest.php b/tests/PhpWord/Tests/Style/ImageTest.php index b53cdc57..fd74d73c 100644 --- a/tests/PhpWord/Tests/Style/ImageTest.php +++ b/tests/PhpWord/Tests/Style/ImageTest.php @@ -1,9 +1,20 @@ 'left', 'marginTop' => 240, 'marginLeft' => 240, - 'wrappingStyle' => 'inline', + 'wrappingStyle' => 'inline' ); foreach ($properties as $key => $value) { $set = "set{$key}"; @@ -43,11 +54,11 @@ class ImageTest extends \PHPUnit_Framework_TestCase 'height' => 200, 'align' => 'left', 'marginTop' => 240, - 'marginLeft' => 240, + 'marginLeft' => 240 ); foreach ($properties as $key => $value) { $get = "get{$key}"; - $object->setStyleValue("_{$key}", $value); + $object->setStyleValue("{$key}", $value); $this->assertEquals($value, $object->$get()); } } diff --git a/tests/PhpWord/Tests/Style/ListItemTest.php b/tests/PhpWord/Tests/Style/ListItemTest.php index abdd6562..6eef720c 100644 --- a/tests/PhpWord/Tests/Style/ListItemTest.php +++ b/tests/PhpWord/Tests/Style/ListItemTest.php @@ -1,9 +1,20 @@ setStyleValue('_listType', $value); + $object->setStyleValue('listType', $value); $this->assertEquals($value, $object->getListType()); } @@ -42,4 +53,16 @@ class ListItemTest extends \PHPUnit_Framework_TestCase $object->setListType($value); $this->assertEquals($value, $object->getListType()); } + + /** + * Test set/get numbering style name + */ + public function testSetGetNumStyle() + { + $expected = 'List Name'; + + $object = new ListItem(); + $object->setNumStyle($expected); + $this->assertEquals($expected, $object->getNumStyle()); + } } diff --git a/tests/PhpWord/Tests/Style/NumberingLevelTest.php b/tests/PhpWord/Tests/Style/NumberingLevelTest.php new file mode 100644 index 00000000..f3e28a0e --- /dev/null +++ b/tests/PhpWord/Tests/Style/NumberingLevelTest.php @@ -0,0 +1,49 @@ + 1, + 'start' => 1, + 'format' => 'decimal', + 'restart' => 1, + 'suffix' => 'space', + 'text' => '%1.', + 'align' => 'left', + 'left' => 360, + 'hanging' => 360, + 'tabPos' => 360, + 'font' => 'Arial', + 'hint' => 'default', + ); + foreach ($attributes as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + $object->$set($value); + $this->assertEquals($value, $object->$get()); + } + } +} diff --git a/tests/PhpWord/Tests/Style/ParagraphTest.php b/tests/PhpWord/Tests/Style/ParagraphTest.php index 7c14ae71..690e34e1 100644 --- a/tests/PhpWord/Tests/Style/ParagraphTest.php +++ b/tests/PhpWord/Tests/Style/ParagraphTest.php @@ -1,4 +1,12 @@ null, 'widowControl' => true, 'keepNext' => false, 'keepLines' => false, @@ -32,9 +44,9 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase ); foreach ($attributes as $key => $default) { $get = "get{$key}"; - $object->setStyleValue("_$key", null); + $object->setStyleValue("$key", null); $this->assertEquals($default, $object->$get()); - $object->setStyleValue("_$key", ''); + $object->setStyleValue("$key", ''); $this->assertEquals($default, $object->$get()); } } @@ -62,7 +74,7 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase ); foreach ($attributes as $key => $value) { $get = "get{$key}"; - $object->setStyleValue("_$key", $value); + $object->setStyleValue("$key", $value); if ($key == 'align') { if ($value == 'justify') { $value = 'both'; @@ -83,13 +95,16 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase { $object = new Paragraph(); $object->setTabs(array(new Tab('left', 1550), new Tab('right', 5300))); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Tabs', $object->getTabs()); + $this->assertEquals(2, count($object->getTabs())); } + /** + * Line height + */ public function testLineHeight() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); // Test style array $text = $section->addText('This is a test', array(), array( @@ -126,4 +141,15 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase $object->setLineHeight('12.5pt'); $this->assertEquals(12.5, $object->getLineHeight()); } + + /** + * Test line height exception by using nonnumeric value + * + * @expectedException \PhpOffice\PhpWord\Exception\InvalidStyleException + */ + public function testLineHeightException() + { + $object = new Paragraph(); + $object->setLineHeight('a'); + } } diff --git a/tests/PhpWord/Tests/Style/RowTest.php b/tests/PhpWord/Tests/Style/RowTest.php index ca0cc559..ad193f80 100644 --- a/tests/PhpWord/Tests/Style/RowTest.php +++ b/tests/PhpWord/Tests/Style/RowTest.php @@ -1,23 +1,35 @@ true, 'cantSplit' => false, + 'exactHeight' => true, ); foreach ($properties as $key => $value) { // set/get @@ -30,8 +42,28 @@ class RowTest extends \PHPUnit_Framework_TestCase // setStyleValue $value = !$value; $expected = $value ? 1 : 0; - $object->setStyleValue("_{$key}", $value); + $object->setStyleValue("{$key}", $value); $this->assertEquals($expected, $object->$get()); } } + + /** + * Test properties with nonboolean values, which will return default value + */ + public function testNonBooleanValue() + { + $object = new Row(); + + $properties = array( + 'tblHeader' => 'a', + 'cantSplit' => 'b', + 'exactHeight' => 'c', + ); + foreach ($properties as $key => $value) { + $set = "set{$key}"; + $get = "get{$key}"; + $object->$set($value); + $this->assertFalse($object->$get()); + } + } } diff --git a/tests/PhpWord/Tests/Section/SettingsTest.php b/tests/PhpWord/Tests/Style/SectionTest.php similarity index 75% rename from tests/PhpWord/Tests/Section/SettingsTest.php rename to tests/PhpWord/Tests/Style/SectionTest.php index c8fcd637..a268c7fc 100644 --- a/tests/PhpWord/Tests/Section/SettingsTest.php +++ b/tests/PhpWord/Tests/Style/SectionTest.php @@ -1,8 +1,22 @@ setSettingValue('_orientation', 'landscape'); + $this->assertEquals('portrait', $oSettings->getOrientation()); + $this->assertEquals(11906, $oSettings->getPageSizeW()); + $this->assertEquals(16838, $oSettings->getPageSizeH()); + + $oSettings->setSettingValue('orientation', 'landscape'); $this->assertEquals('landscape', $oSettings->getOrientation()); $this->assertEquals(16838, $oSettings->getPageSizeW()); $this->assertEquals(11906, $oSettings->getPageSizeH()); - $oSettings->setSettingValue('_orientation', null); - $this->assertNull($oSettings->getOrientation()); - $this->assertEquals(11906, $oSettings->getPageSizeW()); - $this->assertEquals(16838, $oSettings->getPageSizeH()); - $iVal = rand(1, 1000); - $oSettings->setSettingValue('_borderSize', $iVal); + $oSettings->setSettingValue('borderSize', $iVal); $this->assertEquals(array($iVal, $iVal, $iVal, $iVal), $oSettings->getBorderSize()); $this->assertEquals($iVal, $oSettings->getBorderBottomSize()); $this->assertEquals($iVal, $oSettings->getBorderLeftSize()); $this->assertEquals($iVal, $oSettings->getBorderRightSize()); $this->assertEquals($iVal, $oSettings->getBorderTopSize()); - $oSettings->setSettingValue('_borderColor', 'FF00AA'); + $oSettings->setSettingValue('borderColor', 'FF00AA'); $this->assertEquals(array('FF00AA', 'FF00AA', 'FF00AA', 'FF00AA'), $oSettings->getBorderColor()); $this->assertEquals('FF00AA', $oSettings->getBorderBottomColor()); $this->assertEquals('FF00AA', $oSettings->getBorderLeftColor()); @@ -41,12 +53,22 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $iVal = rand(1, 1000); $oSettings->setSettingValue('headerHeight', $iVal); $this->assertEquals($iVal, $oSettings->getHeaderHeight()); + + $oSettings->setSettingValue('lineNumbering', array()); + $oSettings->setSettingValue('lineNumbering', array('start' => 1, 'increment' => 1, 'distance' => 240, 'restart' => 'newPage')); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\LineNumbering', $oSettings->getLineNumbering()); + + $oSettings->setSettingValue('lineNumbering', null); + $this->assertNull($oSettings->getLineNumbering()); } + /** + * Set/get margin + */ public function testMargin() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $iVal = rand(1, 1000); $oSettings->setMarginTop($iVal); @@ -65,10 +87,13 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals($iVal, $oSettings->getMarginRight()); } + /** + * Set/get landscape orientation + */ public function testOrientationLandscape() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $oSettings->setLandscape(); $this->assertEquals('landscape', $oSettings->getOrientation()); @@ -76,21 +101,27 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals(11906, $oSettings->getPageSizeH()); } + /** + * Set/get portrait orientation + */ public function testOrientationPortrait() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $oSettings->setPortrait(); - $this->assertNull($oSettings->getOrientation()); + $this->assertEquals('portrait', $oSettings->getOrientation()); $this->assertEquals(11906, $oSettings->getPageSizeW()); $this->assertEquals(16838, $oSettings->getPageSizeH()); } + /** + * Set/get border size + */ public function testBorderSize() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $iVal = rand(1, 1000); $oSettings->setBorderSize($iVal); @@ -117,10 +148,13 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals($iVal, $oSettings->getBorderTopSize()); } + /** + * Set/get border color + */ public function testBorderColor() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $oSettings->setBorderColor('FF00AA'); $this->assertEquals(array('FF00AA', 'FF00AA', 'FF00AA', 'FF00AA'), $oSettings->getBorderColor()); @@ -142,10 +176,13 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals('22FF33', $oSettings->getBorderTopColor()); } + /** + * Set/get page numbering start + */ public function testNumberingStart() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $this->assertNull($oSettings->getPageNumberingStart()); @@ -157,10 +194,12 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertNull($oSettings->getPageNumberingStart()); } + /** + * Set/get header height + */ public function testHeader() { - // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $this->assertEquals(720, $oSettings->getHeaderHeight()); @@ -172,10 +211,13 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals(720, $oSettings->getHeaderHeight()); } + /** + * Set/get footer height + */ public function testFooter() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $this->assertEquals(720, $oSettings->getFooterHeight()); @@ -187,10 +229,13 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals(720, $oSettings->getFooterHeight()); } + /** + * Set/get column number + */ public function testColumnsNum() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); // Default $this->assertEquals(1, $oSettings->getColsNum()); @@ -203,26 +248,32 @@ class SettingsTest extends \PHPUnit_Framework_TestCase $this->assertEquals(1, $oSettings->getColsNum()); } + /** + * Set/get column spacing + */ public function testColumnsSpace() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); // Default $this->assertEquals(720, $oSettings->getColsSpace()); $iVal = rand(1, 1000); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Settings', $oSettings->setColsSpace($iVal)); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $oSettings->setColsSpace($iVal)); $this->assertEquals($iVal, $oSettings->getColsSpace()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Section\\Settings', $oSettings->setColsSpace()); + $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Section', $oSettings->setColsSpace()); $this->assertEquals(720, $oSettings->getColsSpace()); } + /** + * Set/get break type + */ public function testBreakType() { // Section Settings - $oSettings = new Settings(); + $oSettings = new Section(); $this->assertNull($oSettings->getBreakType()); diff --git a/tests/PhpWord/Tests/Style/TOCTest.php b/tests/PhpWord/Tests/Style/TOCTest.php index b525a9c5..2c10de8d 100644 --- a/tests/PhpWord/Tests/Style/TOCTest.php +++ b/tests/PhpWord/Tests/Style/TOCTest.php @@ -1,10 +1,20 @@ assertEquals($value, $object->$get()); // setStyleValue - $object->setStyleValue("_{$key}", null); + $object->setStyleValue("{$key}", null); $this->assertEquals(null, $object->$get()); } } diff --git a/tests/PhpWord/Tests/Style/TableTest.php b/tests/PhpWord/Tests/Style/TableTest.php index 50bcc8ca..e5c3ab66 100644 --- a/tests/PhpWord/Tests/Style/TableTest.php +++ b/tests/PhpWord/Tests/Style/TableTest.php @@ -1,9 +1,19 @@ assertEquals($values, $object->getCellMargin()); } + + /** + * Set style value for various special value types + */ + public function testSetStyleValue() + { + $object = new Table(); + $object->setStyleValue('borderSize', 120); + $object->setStyleValue('cellMargin', 240); + $object->setStyleValue('borderColor', '999999'); + + $this->assertEquals( + array(120, 120, 120, 120, 120, 120), + $object->getBorderSize() + ); + $this->assertEquals( + array(240, 240, 240, 240), + $object->getCellMargin() + ); + $this->assertEquals( + array('999999', '999999', '999999', '999999', '999999', '999999'), + $object->getBorderColor() + ); + } } diff --git a/tests/PhpWord/Tests/Style/TabsTest.php b/tests/PhpWord/Tests/Style/TabsTest.php index 7ee387a9..26ee41d0 100644 --- a/tests/PhpWord/Tests/Style/TabsTest.php +++ b/tests/PhpWord/Tests/Style/TabsTest.php @@ -1,4 +1,12 @@ 'center'); - $font = array('italic' => true); + $font = array('italic' => true, '_bold' => true); $table = array('bgColor' => 'CCCCCC'); $styles = array('Paragraph' => 'Paragraph', 'Font' => 'Font', 'Link' => 'Font', 'Table' => 'Table', 'Heading_1' => 'Font', 'Normal' => 'Paragraph'); $elementCount = 6; + Style::addParagraphStyle('Paragraph', $paragraph); Style::addFontStyle('Font', $font); Style::addLinkStyle('Link', $font); @@ -36,5 +43,21 @@ class StyleTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf("PhpOffice\\PhpWord\\Style\\{$style}", Style::getStyle($name)); } $this->assertNull(Style::getStyle('Unknown')); + + Style::resetStyles(); + $this->assertEquals(0, count(Style::getStyles())); + + } + + /** + * Set default paragraph style + */ + public function testDefaultParagraphStyle() + { + $paragraph = array('align' => 'center'); + + Style::setDefaultParagraphStyle($paragraph); + + $this->assertInstanceOf("PhpOffice\\PhpWord\\Style\\Paragraph", Style::getStyle('Normal')); } } diff --git a/tests/PhpWord/Tests/TOCTest.php b/tests/PhpWord/Tests/TOCTest.php index 2c21af74..d0b73352 100644 --- a/tests/PhpWord/Tests/TOCTest.php +++ b/tests/PhpWord/Tests/TOCTest.php @@ -1,45 +1,28 @@ 9062, - 'tabLeader' => \PhpOffice\PhpWord\Style\TOC::TABLEADER_DOT, - 'indent' => 200, - ); - $object = new TOC(array('size' => 11), array('tabPos' => $expected['tabPos'])); - $tocStyle = $object->getStyleTOC(); - - $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\TOC', $tocStyle); - $this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Font', $object->getStyleFont()); - - foreach ($expected as $key => $value) { - $method = "get{$key}"; - $this->assertEquals($value, $tocStyle->$method()); - } - } - - /** - * @covers ::addTitle - * @covers ::getTitles + * Add and get title */ public function testAddAndGetTitle() { - // Prepare variables $titleCount = 3; $anchor = '_Toc' . (252634154 + $titleCount); $bookmark = $titleCount - 1; @@ -48,21 +31,23 @@ class TOCTest extends \PHPUnit_Framework_TestCase 'Heading 2' => 2, 'Heading 3' => 3, ); + $toc = new TOC(); - // @covers ::addTitle foreach ($titles as $text => $depth) { - $response = TOC::addTitle($text, $depth); + $response = $toc->addTitle($text, $depth); } $this->assertEquals($anchor, $response[0]); $this->assertEquals($bookmark, $response[1]); - // @covers ::getTitles $i = 0; - $savedTitles = TOC::getTitles(); + $savedTitles = $toc->getTitles(); foreach ($titles as $text => $depth) { $this->assertEquals($text, $savedTitles[$i]['text']); $this->assertEquals($depth, $savedTitles[$i]['depth']); $i++; } + + TOC::resetTitles(); + $this->assertEquals(0, count($toc->getTitles())); } } diff --git a/tests/PhpWord/Tests/TemplateTest.php b/tests/PhpWord/Tests/TemplateTest.php index c36ef408..f99ce294 100644 --- a/tests/PhpWord/Tests/TemplateTest.php +++ b/tests/PhpWord/Tests/TemplateTest.php @@ -1,16 +1,29 @@ assertEquals($expectedVar, $actualVar); $this->assertTrue($docFound); } + + /** + * Replace variables in header and footer + */ + public function testVariablesCanBeReplacedInHeaderAndFooter() + { + $template = __DIR__ . "/_files/templates/header-footer.docx"; + $expectedVar = array('documentContent', 'headerValue', 'footerValue'); + $docName = 'header-footer-test-result.docx'; + + $document = new Template($template); + $actualVar = $document->getVariables(); + $document->setValue('headerValue', 'Header Value'); + $document->setValue('documentContent', 'Document text.'); + $document->setValue('footerValue', 'Footer Value'); + $document->saveAs($docName); + $docFound = file_exists($docName); + unlink($docName); + + $this->assertEquals($expectedVar, $actualVar); + $this->assertTrue($docFound); + + } + + /** + * Clone and delete block + */ + public function testCloneDeleteBlock() + { + $template = __DIR__ . "/_files/templates/clone-delete-block.docx"; + $expectedVar = array('DELETEME', '/DELETEME', 'CLONEME', '/CLONEME'); + $docName = 'clone-delete-block-result.docx'; + + $document = new Template($template); + $actualVar = $document->getVariables(); + + $document->cloneBlock('CLONEME', 3); + $document->deleteBlock('DELETEME'); + + $document->saveAs($docName); + $docFound = file_exists($docName); + unlink($docName); + + $this->assertEquals($expectedVar, $actualVar); + $this->assertTrue($docFound); + } } diff --git a/tests/PhpWord/Tests/Writer/HTMLTest.php b/tests/PhpWord/Tests/Writer/HTMLTest.php new file mode 100644 index 00000000..265c4f6b --- /dev/null +++ b/tests/PhpWord/Tests/Writer/HTMLTest.php @@ -0,0 +1,110 @@ +assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord()); + } + + /** + * Construct with null + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @expectedExceptionMessage No PhpWord assigned. + */ + public function testConstructWithNull() + { + $object = new HTML(); + $object->getPhpWord(); + } + + /** + * Save + */ + public function testSave() + { + $localImage = __DIR__ . "/../_files/images/PhpWord.png"; + $archiveImage = 'zip://' . __DIR__ . '/../_files/documents/reader.docx#word/media/image1.jpeg'; + $gdImage = 'http://php.net/images/logos/php-med-trans-light.gif'; + $objectSrc = __DIR__ . "/../_files/documents/sheet.xls"; + $file = __DIR__ . "/../_files/temp.html"; + + $phpWord = new PhpWord(); + + $docProps = $phpWord->getDocumentProperties(); + $docProps->setTitle('HTML Test'); + + $phpWord->addFontStyle('Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000')); + $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); + $section = $phpWord->addSection(); + $section->addText('Test 1', 'Font', 'Paragraph'); + $section->addTextBreak(); + $section->addText('Test 2', array('name' => 'Tahoma', 'bold' => true, 'italic' => true, 'subscript' => true)); + $section->addLink('http://test.com'); + $section->addTitle('Test', 1); + $section->addPageBreak(); + $section->addListItem('Test'); + $section->addImage($localImage); + $section->addImage($archiveImage); + $section->addImage($gdImage); + $section->addObject($objectSrc); + $section->addFootnote(); + $section->addEndnote(); + + $section = $phpWord->addSection(); + + $textrun = $section->addTextRun(array('align' => 'center')); + $textrun->addText('Test 3'); + $textrun->addTextBreak(); + + $textrun = $section->addTextRun('Paragraph'); + $textrun->addLink('http://test.com'); + $textrun->addImage($localImage); + $textrun->addFootnote(); + $textrun->addEndnote(); + + $section = $phpWord->addSection(); + + $table = $section->addTable(); + $cell = $table->addRow()->addCell(); + $cell->addText('Test 1', array('superscript' => true, 'underline' => 'dash', 'strikethrough' => true)); + $cell->addTextRun(); + $cell->addLink('http://test.com'); + $cell->addTextBreak(); + $cell->addListItem('Test'); + $cell->addImage($localImage); + $cell->addObject($objectSrc); + $cell->addFootnote(); + $cell->addEndnote(); + $cell = $table->addRow()->addCell(); + + $writer = new HTML($phpWord); + $writer->save($file); + + $this->assertTrue(file_exists($file)); + + unlink($file); + } +} diff --git a/tests/PhpWord/Tests/Writer/ODText/ContentTest.php b/tests/PhpWord/Tests/Writer/ODText/ContentTest.php deleted file mode 100644 index 83f69fa7..00000000 --- a/tests/PhpWord/Tests/Writer/ODText/ContentTest.php +++ /dev/null @@ -1,55 +0,0 @@ - - */ - public function testWriteContent() - { - $imageSrc = __DIR__ . "/../../_files/images/PhpWord.png"; - $objectSrc = __DIR__ . "/../../_files/documents/sheet.xls"; - $expected = 'Expected'; - - $phpWord = new PhpWord(); - $phpWord->setDefaultFontName('Verdana'); - $phpWord->addFontStyle('Font', array('size' => 11)); - $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); - $section = $phpWord->createSection(); - $section->addText($expected); - $section->addText('Test font style', 'Font'); - $section->addText('Test paragraph style', null, 'Paragraph'); - $section->addTextBreak(); - $section->addLink('http://test.com', 'Test link'); - $section->addTitle('Test title', 1); - $section->addPageBreak(); - $section->addTable(); - $section->addListItem('Test list item'); - $section->addImage($imageSrc); - $section->addObject($objectSrc); - $section->addTOC(); - $textrun = $section->createTextRun(); - $textrun->addText('Test text run'); - $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); - - $element = "/office:document-content/office:body/office:text/text:p"; - $this->assertEquals($expected, $doc->getElement($element, 'content.xml')->nodeValue); - } -} diff --git a/tests/PhpWord/Tests/Writer/ODText/WriterPartTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/AbstractPartTest.php similarity index 53% rename from tests/PhpWord/Tests/Writer/ODText/WriterPartTest.php rename to tests/PhpWord/Tests/Writer/ODText/Part/AbstractPartTest.php index 5e184700..bde6b413 100644 --- a/tests/PhpWord/Tests/Writer/ODText/WriterPartTest.php +++ b/tests/PhpWord/Tests/Writer/ODText/Part/AbstractPartTest.php @@ -1,17 +1,23 @@ getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\ODText\\WriterPart' + 'PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart' ); $object->setParentWriter(new ODText()); $this->assertEquals( @@ -32,12 +38,12 @@ class WriterPartTest extends \PHPUnit_Framework_TestCase /** * covers ::getParentWriter * @expectedException Exception - * @expectedExceptionMessage No parent IWriter assigned. + * @expectedExceptionMessage No parent WriterInterface assigned. */ public function testSetGetParentWriterNull() { $object = $this->getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\ODText\\WriterPart' + 'PhpOffice\\PhpWord\\Writer\\ODText\\Part\\AbstractPart' ); $object->getParentWriter(); } diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php new file mode 100644 index 00000000..ebbfe470 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/ODText/Part/ContentTest.php @@ -0,0 +1,108 @@ +writeContent(); + } + + /** + * Test write content + */ + public function testWriteContent() + { + $imageSrc = __DIR__ . "/../../../_files/images/PhpWord.png"; + $objectSrc = __DIR__ . "/../../../_files/documents/sheet.xls"; + $expected = 'Expected'; + + $phpWord = new PhpWord(); + + $phpWord->setDefaultFontName('Verdana'); + $phpWord->addFontStyle('Font', array('size' => 11)); + $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); + + $section = $phpWord->addSection(); + $section->addText($expected); + $section->addText('Test font style', 'Font'); + $section->addText('Test paragraph style', null, 'Paragraph'); + $section->addLink('http://test.com', 'Test link'); + $section->addTitle('Test title', 1); + $section->addTextBreak(); + $section->addPageBreak(); + $section->addListItem('Test list item'); + $section->addImage($imageSrc); + $section->addObject($objectSrc); + $section->addTOC(); + + $textrun = $section->addTextRun(); + $textrun->addText('Test text run'); + + $table = $section->addTable(); + $cell = $table->addRow()->addCell(); + $cell = $table->addRow()->addCell(); + $cell->addText('Test'); + $cell->addLink('http://test.com', 'Test link'); + $cell->addTextBreak(); + $cell->addListItem('Test list item'); + $cell->addImage($imageSrc); + $cell->addObject($objectSrc); + $textrun = $cell->addTextRun(); + $textrun->addText('Test text run'); + + $footer = $section->addFooter(); + $footer->addPreserveText('{PAGE}'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $element = "/office:document-content/office:body/office:text/text:p"; + $this->assertEquals($expected, $doc->getElement($element, 'content.xml')->nodeValue); + } + + /** + * Test no paragraph style + */ + public function testWriteNoStyle() + { + $phpWord = new PhpWord(); + $phpWord->addFontStyle('Font', array('size' => 11)); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $element = "/office:document-content/office:automatic-styles/style:style"; + $this->assertTrue($doc->elementExists($element, 'content.xml')); + } +} diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/MetaTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/MetaTest.php new file mode 100644 index 00000000..fde04579 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/ODText/Part/MetaTest.php @@ -0,0 +1,32 @@ +writeMeta(); + } +} diff --git a/tests/PhpWord/Tests/Writer/ODText/Part/StylesTest.php b/tests/PhpWord/Tests/Writer/ODText/Part/StylesTest.php new file mode 100644 index 00000000..556bc804 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/ODText/Part/StylesTest.php @@ -0,0 +1,32 @@ +writeStyles(); + } +} diff --git a/tests/PhpWord/Tests/Writer/ODTextTest.php b/tests/PhpWord/Tests/Writer/ODTextTest.php index 030312e0..b02c3f9f 100644 --- a/tests/PhpWord/Tests/Writer/ODTextTest.php +++ b/tests/PhpWord/Tests/Writer/ODTextTest.php @@ -1,29 +1,36 @@ assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\HashTable', $object->getDrawingHashTable()); $this->assertEquals('./', $object->getDiskCachingDirectory()); foreach (array('Content', 'Manifest', 'Meta', 'Mimetype', 'Styles') as $part) { $this->assertInstanceOf( - "PhpOffice\\PhpWord\\Writer\\ODText\\{$part}", + "PhpOffice\\PhpWord\\Writer\\ODText\\Part\\{$part}", $object->getWriterPart($part) ); $this->assertInstanceOf( @@ -34,9 +41,10 @@ class ODTextTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::getPhpWord - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception - * @expectedExceptionMessage No PhpWord assigned. + * Construct with null + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @expectedExceptionMessage No PhpWord assigned. */ public function testConstructWithNull() { @@ -45,7 +53,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::save + * Save */ public function testSave() { @@ -56,7 +64,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test 1', 'Font'); $section->addTextBreak(); $section->addText('Test 2', null, 'Paragraph'); @@ -68,33 +76,35 @@ class ODTextTest extends \PHPUnit_Framework_TestCase $section->addImage($imageSrc); $section->addObject($objectSrc); $section->addTOC(); - $section = $phpWord->createSection(); - $textrun = $section->createTextRun(); + $section = $phpWord->addSection(); + $textrun = $section->addTextRun(); $textrun->addText('Test 3'); $writer = new ODText($phpWord); $writer->save($file); - $this->assertTrue(\file_exists($file)); + $this->assertTrue(file_exists($file)); unlink($file); } /** - * @covers ::save + * Save php output + * * @todo Haven't got any method to test this */ public function testSavePhpOutput() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test'); $writer = new ODText($phpWord); $writer->save('php://output'); } /** - * @covers ::save - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Save with no PhpWord object assigned + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception * @expectedExceptionMessage PhpWord object unassigned. */ public function testSaveException() @@ -104,7 +114,7 @@ class ODTextTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::getWriterPart + * Get writer part return null value */ public function testGetWriterPartNull() { @@ -113,26 +123,26 @@ class ODTextTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::setUseDiskCaching - * @covers ::getUseDiskCaching + * Set/get use disk caching */ public function testSetGetUseDiskCaching() { $object = new ODText(); - $object->setUseDiskCaching(true, \PHPWORD_TESTS_BASE_DIR); + $object->setUseDiskCaching(true, PHPWORD_TESTS_BASE_DIR); $this->assertTrue($object->getUseDiskCaching()); - $this->assertEquals(\PHPWORD_TESTS_BASE_DIR, $object->getDiskCachingDirectory()); + $this->assertEquals(PHPWORD_TESTS_BASE_DIR, $object->getDiskCachingDirectory()); } /** - * @covers ::setUseDiskCaching - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Use disk caching exception + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testSetUseDiskCachingException() { - $dir = \join( - \DIRECTORY_SEPARATOR, - array(\PHPWORD_TESTS_BASE_DIR, 'foo') + $dir = join( + DIRECTORY_SEPARATOR, + array(PHPWORD_TESTS_BASE_DIR, 'foo') ); $object = new ODText(); 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/RTFTest.php b/tests/PhpWord/Tests/Writer/RTFTest.php index 1c460a36..9cc7ed71 100644 --- a/tests/PhpWord/Tests/Writer/RTFTest.php +++ b/tests/PhpWord/Tests/Writer/RTFTest.php @@ -1,29 +1,37 @@ assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $object->getPhpWord()); - $this->assertInstanceOf('PhpOffice\\PhpWord\\HashTable', $object->getDrawingHashTable()); } /** - * covers ::__construct - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Construct with null + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception * @expectedExceptionMessage No PhpWord assigned. */ public function testConstructWithNull() @@ -33,32 +41,7 @@ class RTFTest extends \PHPUnit_Framework_TestCase } /** - * @covers ::save - * @todo Haven't got any method to test this - */ - public function testSavePhpOutput() - { - $phpWord = new PhpWord(); - $section = $phpWord->createSection(); - $section->addText('Test'); - $writer = new RTF($phpWord); - $writer->save('php://output'); - } - - /** - * @covers ::save - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception - * @expectedExceptionMessage PhpWord object unassigned. - */ - public function testSaveException() - { - $writer = new RTF(); - $writer->save(); - } - - /** - * @covers ::save - * @covers :: + * Save */ public function testSave() { @@ -67,12 +50,12 @@ class RTFTest extends \PHPUnit_Framework_TestCase $file = __DIR__ . "/../_files/temp.rtf"; $phpWord = new PhpWord(); - $phpWord->addFontStyle('Font', array('size' => 11)); + $phpWord->addFontStyle('Font', array('name' => 'Verdana', 'size' => 11, 'color' => 'FF0000', 'fgColor' => 'FF0000')); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); - $section = $phpWord->createSection(); - $section->addText('Test 1', 'Font'); + $section = $phpWord->addSection(); + $section->addText('Test 1', 'Font', 'Paragraph'); $section->addTextBreak(); - $section->addText('Test 2', null, 'Paragraph'); + $section->addText('Test 2', array('name' => 'Tahoma', 'bold' => true, 'italic' => true)); $section->addLink('http://test.com'); $section->addTitle('Test', 1); $section->addPageBreak(); @@ -81,15 +64,41 @@ class RTFTest extends \PHPUnit_Framework_TestCase $section->addImage($imageSrc); $section->addObject($objectSrc); $section->addTOC(); - $section = $phpWord->createSection(); - $textrun = $section->createTextRun(); + $section = $phpWord->addSection(); + $textrun = $section->addTextRun(); $textrun->addText('Test 3'); $textrun->addTextBreak(); $writer = new RTF($phpWord); $writer->save($file); - $this->assertTrue(\file_exists($file)); + $this->assertTrue(file_exists($file)); unlink($file); } + + /** + * Save + * + * @todo Haven't got any method to test this + */ + public function testSavePhpOutput() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Test'); + $writer = new RTF($phpWord); + $writer->save('php://output'); + } + + /** + * Save with no PhpWord object assigned + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @expectedExceptionMessage PhpWord object unassigned. + */ + public function testSaveException() + { + $writer = new RTF(); + $writer->save(); + } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php b/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php deleted file mode 100644 index 7c34d298..00000000 --- a/tests/PhpWord/Tests/Writer/Word2007/DocumentTest.php +++ /dev/null @@ -1,80 +0,0 @@ -createSection(); - $section->getSettings()->setPageNumberingStart(2); - - $doc = TestHelperDOCX::getDocument($phpWord); - $element = $doc->getElement('/w:document/w:body/w:sectPr/w:pgNumType'); - - $this->assertEquals(2, $element->getAttribute('w:start')); - } - - /** - * covers ::_writeTOC - * covers ::_writePageBreak - * covers ::_writeListItem - * covers ::_writeTitle - * covers ::_writeObject - */ - public function testElements() - { - $objectSrc = __DIR__ . "/../../_files/documents/sheet.xls"; - - $phpWord = new PhpWord(); - $phpWord->addTitleStyle(1, array('color' => '333333', 'bold'=>true)); - $phpWord->addTitleStyle(2, array('color'=>'666666')); - $section = $phpWord->createSection(); - $section->addTOC(); - $section->addPageBreak(); - $section->addTitle('Title 1', 1); - $section->addListItem('List Item 1', 0); - $section->addListItem('List Item 2', 0); - $section->addListItem('List Item 3', 0); - $section = $phpWord->createSection(); - $section->addTitle('Title 2', 2); - $section->addObject($objectSrc); - $doc = TestHelperDOCX::getDocument($phpWord); - - // TOC - $element = $doc->getElement('/w:document/w:body/w:p[1]/w:pPr/w:tabs/w:tab'); - $this->assertEquals('right', $element->getAttribute('w:val')); - $this->assertEquals('dot', $element->getAttribute('w:leader')); - $this->assertEquals(9062, $element->getAttribute('w:pos')); - - // Page break - $element = $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:br'); - $this->assertEquals('page', $element->getAttribute('w:type')); - - // Title - $element = $doc->getElement('/w:document/w:body/w:p[5]/w:pPr/w:pStyle'); - $this->assertEquals('Heading1', $element->getAttribute('w:val')); - - // List item - $element = $doc->getElement('/w:document/w:body/w:p[6]/w:pPr/w:numPr/w:numId'); - $this->assertEquals(3, $element->getAttribute('w:val')); - - // Object - $element = $doc->getElement('/w:document/w:body/w:p[11]/w:r/w:object/o:OLEObject'); - $this->assertEquals('Embed', $element->getAttribute('Type')); - } -} diff --git a/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php b/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php deleted file mode 100644 index 11557e69..00000000 --- a/tests/PhpWord/Tests/Writer/Word2007/FootnotesTest.php +++ /dev/null @@ -1,32 +0,0 @@ -createSection(); - $section->addText('Text'); - $footnote = $section->createFootnote(); - $footnote->addText('Footnote'); - $footnote->addLink('http://google.com'); - $doc = TestHelperDOCX::getDocument($phpWord); - - $this->assertTrue($doc->elementExists("/w:document/w:body/w:p/w:r/w:footnoteReference")); - } -} diff --git a/tests/PhpWord/Tests/Writer/Word2007/WriterPartTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/AbstractPartTest.php similarity index 50% rename from tests/PhpWord/Tests/Writer/Word2007/WriterPartTest.php rename to tests/PhpWord/Tests/Writer/Word2007/Part/AbstractPartTest.php index 69b19281..81786b14 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/WriterPartTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/AbstractPartTest.php @@ -1,18 +1,24 @@ getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\Word2007\\WriterPart' + 'PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\AbstractPart' ); $object->setParentWriter(new Word2007()); $this->assertEquals( @@ -33,12 +39,12 @@ class WriterPartTest extends \PHPUnit_Framework_TestCase /** * covers ::getParentWriter * @expectedException Exception - * @expectedExceptionMessage No parent IWriter assigned. + * @expectedExceptionMessage No parent WriterInterface assigned. */ public function testSetGetParentWriterNull() { $object = $this->getMockForAbstractClass( - 'PhpOffice\\PhpWord\\Writer\\Word2007\\WriterPart' + 'PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\AbstractPart' ); $object->getParentWriter(); } diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/DocPropsTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocPropsTest.php new file mode 100644 index 00000000..e6db4bf5 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocPropsTest.php @@ -0,0 +1,44 @@ +writeDocPropsApp(); + } + + /** + * Test write docProps/core.xml with no PhpWord + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @expectedExceptionMessage No PhpWord assigned. + */ + public function testWriteDocPropsCoreNoPhpWord() + { + $object = new DocProps(); + $object->writeDocPropsCore(); + } +} diff --git a/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php similarity index 51% rename from tests/PhpWord/Tests/Writer/Word2007/BaseTest.php rename to tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php index 31049be8..0cc4895d 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/BaseTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/DocumentTest.php @@ -1,14 +1,24 @@ writeDocument(); + } + + /** + * Write end section page numbering + */ + public function testWriteEndSectionPageNumbering() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $settings = $section->getSettings(); + $settings->setLandscape(); + $settings->setPageNumberingStart(2); + $settings->setBorderSize(240); + $settings->setBreakType('nextPage'); + + $doc = TestHelperDOCX::getDocument($phpWord); + $element = $doc->getElement('/w:document/w:body/w:sectPr/w:pgNumType'); + + $this->assertEquals(2, $element->getAttribute('w:start')); + } + + /** + * Write elements + */ + public function testElements() + { + $objectSrc = __DIR__ . "/../../../_files/documents/sheet.xls"; + + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(1, array('color' => '333333', 'bold'=>true)); + $phpWord->addTitleStyle(2, array('color'=>'666666')); + $section = $phpWord->addSection(); + $section->addTOC(); + $section->addPageBreak(); + $section->addTitle('Title 1', 1); + $section->addListItem('List Item 1', 0); + $section->addListItem('List Item 2', 0); + $section->addListItem('List Item 3', 0); + $section = $phpWord->addSection(); + $section->addTitle('Title 2', 2); + $section->addObject($objectSrc); + $doc = TestHelperDOCX::getDocument($phpWord); + + // TOC + $element = $doc->getElement('/w:document/w:body/w:p[1]/w:pPr/w:tabs/w:tab'); + $this->assertEquals('right', $element->getAttribute('w:val')); + $this->assertEquals('dot', $element->getAttribute('w:leader')); + $this->assertEquals(9062, $element->getAttribute('w:pos')); + + // Page break + $element = $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:br'); + $this->assertEquals('page', $element->getAttribute('w:type')); + + // Title + $element = $doc->getElement('/w:document/w:body/w:p[5]/w:pPr/w:pStyle'); + $this->assertEquals('Heading1', $element->getAttribute('w:val')); + + // List item + $element = $doc->getElement('/w:document/w:body/w:p[6]/w:pPr/w:numPr/w:numId'); + $this->assertEquals(3, $element->getAttribute('w:val')); + + // Object + $element = $doc->getElement('/w:document/w:body/w:p[11]/w:r/w:object/o:OLEObject'); + $this->assertEquals('Embed', $element->getAttribute('Type')); + } + + /** + * Write element with some styles + */ + public function testElementStyles() + { + $objectSrc = __DIR__ . "/../../../_files/documents/sheet.xls"; + + $phpWord = new PhpWord(); + $phpWord->addParagraphStyle('pStyle', array('align' => 'center')); // Style #1 + $phpWord->addFontStyle('fStyle', array('size' => '20', 'doubleStrikethrough' => true, 'allCaps' => true)); // Style #2 + $phpWord->addTitleStyle(1, array('color' => '333333', 'bold' => true)); // Style #3 + $fontStyle = new Font('text', array('align' => 'center')); + $section = $phpWord->addSection(); + $section->addListItem('List Item', 0, null, null, 'pStyle'); // Style #4 + $section->addObject($objectSrc, array('align' => 'center')); + $section->addTOC($fontStyle); + $section->addTitle('Title 1', 1); + $section->addTOC('fStyle'); + $doc = TestHelperDOCX::getDocument($phpWord); + + // List item + $element = $doc->getElement('/w:document/w:body/w:p[1]/w:pPr/w:numPr/w:numId'); + $this->assertEquals(4, $element->getAttribute('w:val')); + + // Object + $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:object/o:OLEObject'); + $this->assertEquals('Embed', $element->getAttribute('Type')); + + // TOC + $element = $doc->getElement('/w:document/w:body/w:p[3]/w:pPr/w:tabs/w:tab'); + $this->assertEquals('right', $element->getAttribute('w:val')); + $this->assertEquals('dot', $element->getAttribute('w:leader')); + $this->assertEquals(9062, $element->getAttribute('w:pos')); + } + + /** + * Test write text element */ public function testWriteText() { @@ -29,7 +150,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addFontStyle($rStyle, array('bold' => true)); $phpWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120)); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test', $rStyle, $pStyle); $doc = TestHelperDOCX::getDocument($phpWord); @@ -40,23 +161,24 @@ class BaseTest extends \PHPUnit_Framework_TestCase } /** - * covers ::_writeTextRun + * Test write textrun element */ public function testWriteTextRun() { $pStyle = 'pStyle'; $aStyle = array('align' => 'justify', 'spaceBefore' => 120, 'spaceAfter' => 120); - $imageSrc = __DIR__ . "/../../_files/images/earth.jpg"; + $imageSrc = __DIR__ . "/../../../_files/images/earth.jpg"; $phpWord = new PhpWord(); $phpWord->addParagraphStyle($pStyle, $aStyle); - $section = $phpWord->createSection('Test'); - $textrun = $section->createTextRun($pStyle); + $section = $phpWord->addSection('Test'); + $textrun = $section->addTextRun($pStyle); $textrun->addText('Test'); $textrun->addTextBreak(); - $textrun = $section->createTextRun($aStyle); + $textrun = $section->addTextRun($aStyle); $textrun->addLink('http://test.com'); - $textrun->addImage($imageSrc); + $textrun->addImage($imageSrc, array('align' => 'top')); + $textrun->addFootnote(); $doc = TestHelperDOCX::getDocument($phpWord); $parent = "/w:document/w:body/w:p"; @@ -64,15 +186,21 @@ class BaseTest extends \PHPUnit_Framework_TestCase } /** - * covers ::_writeLink + * Test write link element */ public function testWriteLink() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); + $fontStyleArray = array('bold' => true); + $fontStyleName = 'Font Style'; + $paragraphStyleArray = array('align' => 'center'); + $paragraphStyleName = 'Paragraph Style'; $expected = 'PhpWord'; $section->addLink('http://github.com/phpoffice/phpword', $expected); + $section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleArray, $paragraphStyleArray); + $section->addLink('http://github.com/phpoffice/phpword', 'Test', $fontStyleName, $paragraphStyleName); $doc = TestHelperDOCX::getDocument($phpWord); $element = $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t'); @@ -81,15 +209,21 @@ class BaseTest extends \PHPUnit_Framework_TestCase } /** - * covers ::_writePreserveText + * Test write preserve text element */ public function testWritePreserveText() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); - $footer = $section->createFooter(); + $section = $phpWord->addSection(); + $footer = $section->addFooter(); + $fontStyleArray = array('bold' => true); + $fontStyleName = 'Font'; + $paragraphStyleArray = array('align' => 'right'); + $paragraphStyleName = 'Paragraph'; - $footer->addPreserveText('{PAGE}'); + $footer->addPreserveText('Page {PAGE}'); + $footer->addPreserveText('{PAGE}', $fontStyleArray, $paragraphStyleArray); + $footer->addPreserveText('{PAGE}', $fontStyleName, $paragraphStyleName); $doc = TestHelperDOCX::getDocument($phpWord); $preserve = $doc->getElement("w:p/w:r[2]/w:instrText", 'word/footer1.xml'); @@ -99,7 +233,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase } /** - * covers ::_writeTextBreak + * Test write text break */ public function testWriteTextBreak() { @@ -111,7 +245,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase $phpWord = new PhpWord(); $phpWord->addFontStyle($fName, $fArray); $phpWord->addParagraphStyle($pName, $pArray); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addTextBreak(); $section->addTextBreak(1, $fArray, $pArray); $section->addTextBreak(1, $fName, $pName); @@ -124,30 +258,98 @@ class BaseTest extends \PHPUnit_Framework_TestCase } /** - * covers ::_writeParagraphStyle + * covers ::_writeImage */ - public function testWriteParagraphStyleAlign() + public function testWriteImage() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $styles = array('align' => 'left', 'width' => 40, 'height' => 40, 'marginTop' => -1, 'marginLeft' => -1); + $wraps = array('inline', 'behind', 'infront', 'square', 'tight'); + $section = $phpWord->addSection(); + foreach ($wraps as $wrap) { + $styles['wrappingStyle'] = $wrap; + $section->addImage(__DIR__ . "/../../../_files/images/earth.jpg", $styles); + } - $section->addText('This is my text', null, array('align' => 'right')); + $archiveFile = realpath(__DIR__ . '/../../../_files/documents/reader.docx'); + $imageFile = 'word/media/image1.jpeg'; + $source = 'zip://' . $archiveFile . '#' . $imageFile; + $section->addImage($source); $doc = TestHelperDOCX::getDocument($phpWord); - $element = $doc->getElement('/w:document/w:body/w:p/w:pPr/w:jc'); - $this->assertEquals('right', $element->getAttribute('w:val')); + // behind + $element = $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:pict/v:shape'); + $style = $element->getAttribute('style'); + $this->assertRegExp('/z\-index:\-[0-9]*/', $style); + + // square + $element = $doc->getElement('/w:document/w:body/w:p[4]/w:r/w:pict/v:shape/w10:wrap'); + $this->assertEquals('square', $element->getAttribute('type')); + } + + /** + * covers ::_writeWatermark + */ + public function testWriteWatermark() + { + $imageSrc = __DIR__ . "/../../../_files/images/earth.jpg"; + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $header = $section->addHeader(); + $header->addWatermark($imageSrc); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = $doc->getElement("/w:document/w:body/w:sectPr/w:headerReference"); + $this->assertStringStartsWith("rId", $element->getAttribute('r:id')); + } + + /** + * covers ::_writeTitle + */ + public function testWriteTitle() + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); + $phpWord->addSection()->addTitle('Test', 1); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = "/w:document/w:body/w:p/w:pPr/w:pStyle"; + $this->assertEquals('Heading1', $doc->getElementAttribute($element, 'w:val')); + $element = "/w:document/w:body/w:p/w:r/w:fldChar"; + $this->assertEquals('end', $doc->getElementAttribute($element, 'w:fldCharType')); + } + + /** + * covers ::_writeCheckbox + */ + public function testWriteCheckbox() + { + $rStyle = 'rStyle'; + $pStyle = 'pStyle'; + + $phpWord = new PhpWord(); + $phpWord->addFontStyle($rStyle, array('bold' => true)); + $phpWord->addParagraphStyle($pStyle, array('hanging' => 120, 'indent' => 120)); + $section = $phpWord->addSection(); + $section->addCheckbox('Check1', 'Test', $rStyle, $pStyle); + $doc = TestHelperDOCX::getDocument($phpWord); + + $element = '/w:document/w:body/w:p/w:r/w:fldChar/w:ffData/w:name'; + $this->assertEquals('Check1', $doc->getElementAttribute($element, 'w:val')); } /** * covers ::_writeParagraphStyle */ - public function testWriteParagraphStylePagination() + public function testWriteParagraphStyle() { // Create the doc $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $attributes = array( + 'align' => 'right', 'widowControl' => false, 'keepNext' => true, 'keepLines' => true, @@ -162,10 +364,13 @@ class BaseTest extends \PHPUnit_Framework_TestCase $i = 0; foreach ($attributes as $key => $value) { $i++; - $path = "/w:document/w:body/w:p[{$i}]/w:pPr/w:{$key}"; + $nodeName = ($key == 'align') ? 'jc' : $key; + $path = "/w:document/w:body/w:p[{$i}]/w:pPr/w:{$nodeName}"; + if ($key != 'align') { + $value = $value ? 1 : 0; + } $element = $doc->getElement($path); - $expected = $value ? 1 : 0; - $this->assertEquals($expected, $element->getAttribute('w:val')); + $this->assertEquals($value, $element->getAttribute('w:val')); } } @@ -184,8 +389,11 @@ class BaseTest extends \PHPUnit_Framework_TestCase $styles['superScript'] = true; $styles['color'] = 'FF0000'; $styles['fgColor'] = 'yellow'; + $styles['bgColor'] = 'FFFF00'; + $styles['hint'] = 'eastAsia'; + $styles['smallCaps'] = true; - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test', $styles); $doc = TestHelperDOCX::getDocument($phpWord); @@ -199,6 +407,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase $this->assertEquals('superscript', $doc->getElementAttribute("{$parent}/w:vertAlign", 'w:val')); $this->assertEquals($styles['color'], $doc->getElementAttribute("{$parent}/w:color", 'w:val')); $this->assertEquals($styles['fgColor'], $doc->getElementAttribute("{$parent}/w:highlight", 'w:val')); + $this->assertTrue($doc->elementExists("{$parent}/w:smallCaps")); } /** @@ -210,6 +419,10 @@ class BaseTest extends \PHPUnit_Framework_TestCase $tWidth = 120; $rHeight = 120; $cWidth = 120; + $imageSrc = __DIR__ . "/../../../_files/images/earth.jpg"; + $objectSrc = __DIR__ . "/../../../_files/documents/sheet.xls"; + + $tStyles["width"] = 50; $tStyles["cellMarginTop"] = 120; $tStyles["cellMarginRight"] = 120; $tStyles["cellMarginBottom"] = 120; @@ -227,8 +440,9 @@ class BaseTest extends \PHPUnit_Framework_TestCase $cStyles["borderBottomColor"] = 'FF0000'; $cStyles["borderLeftColor"] = 'FF0000'; $cStyles["borderRightColor"] = 'FF0000'; + $cStyles["vMerge"] = 'restart'; - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $table = $section->addTable($tStyles); $table->setWidth = 100; $table->addRow($rHeight, $rStyles); @@ -237,7 +451,9 @@ class BaseTest extends \PHPUnit_Framework_TestCase $cell->addTextBreak(); $cell->addLink('http://google.com'); $cell->addListItem('Test'); - $textrun = $cell->createTextRun(); + $cell->addImage($imageSrc); + $cell->addObject($objectSrc); + $textrun = $cell->addTextRun(); $textrun->addText('Test'); $doc = TestHelperDOCX::getDocument($phpWord); @@ -265,7 +481,7 @@ class BaseTest extends \PHPUnit_Framework_TestCase public function testWriteCellStyleCellGridSpan() { $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $table = $section->addTable(); @@ -287,60 +503,18 @@ class BaseTest extends \PHPUnit_Framework_TestCase } /** - * covers ::_writeImage + * Test write gutter and line numbering */ - public function testWriteImagePosition() + public function testWriteGutterAndLineNumbering() { - $phpWord = new PhpWord(); - $section = $phpWord->createSection(); - $section->addImage( - __DIR__ . "/../../_files/images/earth.jpg", - array( - 'marginTop' => -1, - 'marginLeft' => -1, - 'wrappingStyle' => 'behind' - ) - ); - - $doc = TestHelperDOCX::getDocument($phpWord); - $element = $doc->getElement('/w:document/w:body/w:p/w:r/w:pict/v:shape'); - - $style = $element->getAttribute('style'); - - $this->assertRegExp('/z\-index:\-[0-9]*/', $style); - $this->assertRegExp('/position:absolute;/', $style); - } - - /** - * covers ::_writeWatermark - */ - public function testWriteWatermark() - { - $imageSrc = __DIR__ . "/../../_files/images/earth.jpg"; + $pageMarginPath = '/w:document/w:body/w:sectPr/w:pgMar'; + $lineNumberingPath = '/w:document/w:body/w:sectPr/w:lnNumType'; $phpWord = new PhpWord(); - $section = $phpWord->createSection(); - $header = $section->createHeader(); - $header->addWatermark($imageSrc); + $section = $phpWord->addSection(array('gutter' => 240, 'lineNumbering' => array())); $doc = TestHelperDOCX::getDocument($phpWord); - $element = $doc->getElement("/w:document/w:body/w:sectPr/w:headerReference"); - $this->assertStringStartsWith("rId", $element->getAttribute('r:id')); - } - - /** - * covers ::_writeTitle - */ - public function testWriteTitle() - { - $phpWord = new PhpWord(); - $phpWord->addTitleStyle(1, array('bold' => true), array('spaceAfter' => 240)); - $phpWord->createSection()->addTitle('Test', 1); - $doc = TestHelperDOCX::getDocument($phpWord); - - $element = "/w:document/w:body/w:p/w:pPr/w:pStyle"; - $this->assertEquals('Heading1', $doc->getElementAttribute($element, 'w:val')); - $element = "/w:document/w:body/w:p/w:r/w:fldChar"; - $this->assertEquals('end', $doc->getElementAttribute($element, 'w:fldCharType')); + $this->assertEquals(240, $doc->getElement($pageMarginPath)->getAttribute('w:gutter')); + $this->assertTrue($doc->elementExists($lineNumberingPath)); } } diff --git a/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/FooterTest.php similarity index 57% rename from tests/PhpWord/Tests/Writer/Word2007/FooterTest.php rename to tests/PhpWord/Tests/Writer/Word2007/Part/FooterTest.php index 043f4713..513d4d2c 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/FooterTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/FooterTest.php @@ -1,30 +1,38 @@ addText(''); $container->addPreserveText(''); $container->addTextBreak(); - $container->createTextRun(); + $container->addTextRun(); $container->addTable()->addRow()->addCell()->addText(''); $container->addImage($imageSrc); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php new file mode 100644 index 00000000..3f9aaae7 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/FootnotesTest.php @@ -0,0 +1,49 @@ +addParagraphStyle('pStyle', array('align' => 'left')); + $section = $phpWord->addSection(); + $section->addText('Text'); + $footnote1 = $section->addFootnote('pStyle'); + $footnote1->addText('Footnote'); + $footnote1->addTextBreak(); + $footnote1->addLink('http://google.com'); + $footnote2 = $section->addEndnote(array('align' => 'left')); + $footnote2->addText('Endnote'); + $doc = TestHelperDOCX::getDocument($phpWord); + + $this->assertTrue($doc->elementExists("/w:document/w:body/w:p/w:r/w:footnoteReference")); + $this->assertTrue($doc->elementExists("/w:document/w:body/w:p/w:r/w:endnoteReference")); + } +} diff --git a/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/HeaderTest.php similarity index 61% rename from tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php rename to tests/PhpWord/Tests/Writer/Word2007/Part/HeaderTest.php index 59a45fc3..c3ca6b6b 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/HeaderTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/HeaderTest.php @@ -1,31 +1,36 @@ addText('Test'); $container->addPreserveText(''); $container->addTextBreak(); - $container->createTextRun(); + $container->addTextRun(); $container->addTable()->addRow()->addCell()->addText(''); $container->addImage($imageSrc); $container->addWatermark($imageSrc); diff --git a/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php new file mode 100644 index 00000000..8d76f016 --- /dev/null +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/NumberingTest.php @@ -0,0 +1,68 @@ +addNumberingStyle( + 'numStyle', + array( + 'type' => 'multilevel', + 'levels' => array( + array( + 'start' => 1, + 'format' => 'decimal', + 'restart' => 1, + 'suffix' => 'space', + 'text' => '%1.', + 'align' => 'left', + 'left' => 360, + 'hanging' => 360, + 'tabPos' => 360, + 'font' => 'Arial', + 'hint' => 'default', + ), + ) + ) + ); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $this->assertTrue($doc->elementExists('/w:numbering/w:abstractNum', $xmlFile)); + } +} diff --git a/tests/PhpWord/Tests/Writer/Word2007/StylesTest.php b/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php similarity index 75% rename from tests/PhpWord/Tests/Writer/Word2007/StylesTest.php rename to tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php index 81107f93..42c32bbc 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/StylesTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/Part/StylesTest.php @@ -1,10 +1,21 @@ writeStyles(); + } + /** * Test write styles */ diff --git a/tests/PhpWord/Tests/Writer/Word2007Test.php b/tests/PhpWord/Tests/Writer/Word2007Test.php index d6189557..74f3b1fd 100644 --- a/tests/PhpWord/Tests/Writer/Word2007Test.php +++ b/tests/PhpWord/Tests/Writer/Word2007Test.php @@ -1,4 +1,11 @@ 'ContentTypes', + 'Rels' => 'Rels', + 'DocProps' => 'DocProps', + 'Document' => 'Document', + 'Styles' => 'Styles', + 'Numbering' => 'Numbering', + 'Settings' => 'Settings', + 'WebSettings' => 'WebSettings', + 'Header' => 'Header', + 'Footer' => 'Footer', + 'Footnotes' => 'Footnotes', + 'Endnotes' => 'Footnotes', ); - foreach ($writerParts as $part) { + foreach ($writerParts as $part => $type) { $this->assertInstanceOf( - "PhpOffice\\PhpWord\\Writer\\Word2007\\{$part}", + "PhpOffice\\PhpWord\\Writer\\Word2007\\Part\\{$type}", $object->getWriterPart($part) ); $this->assertInstanceOf( @@ -48,30 +61,73 @@ class Word2007Test extends \PHPUnit_Framework_TestCase } /** - * @covers ::save + * Save */ public function testSave() { + $localImage = __DIR__ . '/../_files/images/earth.jpg'; + $remoteImage = 'http://php.net//images/logos/php-med-trans-light.gif'; $phpWord = new PhpWord(); $phpWord->addFontStyle('Font', array('size' => 11)); $phpWord->addParagraphStyle('Paragraph', array('align' => 'center')); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); $section->addText('Test 1', 'Font', 'Paragraph'); $section->addTextBreak(); $section->addText('Test 2'); - $section = $phpWord->createSection(); - $textrun = $section->createTextRun(); + $section = $phpWord->addSection(); + $textrun = $section->addTextRun(); $textrun->addText('Test 3'); + $footnote = $textrun->addFootnote(); + $footnote->addLink('http://test.com'); + $header = $section->addHeader(); + $header->addImage($localImage); + $footer = $section->addFooter(); + $footer->addImage($remoteImage); $writer = new Word2007($phpWord); $file = __DIR__ . "/../_files/temp.docx"; $writer->save($file); - $this->assertTrue(\file_exists($file)); + + $this->assertTrue(file_exists($file)); + unlink($file); } /** - * @covers ::checkContentTypes + * Save using disk caching + */ + public function testSaveUseDiskCaching() + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addText('Test'); + $footnote = $section->addFootnote(); + $footnote->addText('Test'); + + $writer = new Word2007($phpWord); + $writer->setUseDiskCaching(true); + $file = __DIR__ . "/../_files/temp.docx"; + $writer->save($file); + + $this->assertTrue(file_exists($file)); + + unlink($file); + } + + /** + * Save with no PhpWord object assigned + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception + * @expectedExceptionMessage PhpWord object unassigned. + */ + public function testSaveException() + { + $writer = new Word2007(); + $writer->save(); + } + + /** + * Check content types */ public function testCheckContentTypes() { @@ -84,7 +140,7 @@ class Word2007Test extends \PHPUnit_Framework_TestCase 'angela_merkel.tif' => '6.tif', ); $phpWord = new PhpWord(); - $section = $phpWord->createSection(); + $section = $phpWord->addSection(); foreach ($images as $source => $target) { $section->addImage(__DIR__ . "/../_files/images/{$source}"); } @@ -101,26 +157,39 @@ class Word2007Test extends \PHPUnit_Framework_TestCase } /** - * @covers ::setUseDiskCaching - * @covers ::getUseDiskCaching + * Get writer part return null value + */ + public function testGetWriterPartNull() + { + $object = new Word2007(); + $this->assertNull($object->getWriterPart()); + } + + /** + * Set/get use disk caching */ public function testSetGetUseDiskCaching() { - $object = new Word2007(); - $object->setUseDiskCaching(true, \PHPWORD_TESTS_BASE_DIR); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $object = new Word2007($phpWord); + $object->setUseDiskCaching(true, PHPWORD_TESTS_BASE_DIR); + $writer = new Word2007($phpWord); + $writer->save('php://output'); $this->assertTrue($object->getUseDiskCaching()); } /** - * @covers ::setUseDiskCaching - * @expectedException \PhpOffice\PhpWord\Exceptions\Exception + * Use disk caching exception + * + * @expectedException \PhpOffice\PhpWord\Exception\Exception */ public function testSetUseDiskCachingException() { - $dir = \join( - \DIRECTORY_SEPARATOR, - array(\PHPWORD_TESTS_BASE_DIR, 'foo') + $dir = join( + DIRECTORY_SEPARATOR, + array(PHPWORD_TESTS_BASE_DIR, 'foo') ); $object = new Word2007(); diff --git a/tests/PhpWord/Tests/_files/documents/reader.docx b/tests/PhpWord/Tests/_files/documents/reader.docx index e2ceeb64..5f37ef4b 100644 Binary files a/tests/PhpWord/Tests/_files/documents/reader.docx and b/tests/PhpWord/Tests/_files/documents/reader.docx differ diff --git a/tests/PhpWord/Tests/_files/documents/reader.odt b/tests/PhpWord/Tests/_files/documents/reader.odt new file mode 100644 index 00000000..9e18e619 Binary files /dev/null and b/tests/PhpWord/Tests/_files/documents/reader.odt differ diff --git a/tests/PhpWord/Tests/_files/images/angela_merkel.tif b/tests/PhpWord/Tests/_files/images/angela_merkel.tif index 236dedd1..50629970 100644 Binary files a/tests/PhpWord/Tests/_files/images/angela_merkel.tif and b/tests/PhpWord/Tests/_files/images/angela_merkel.tif differ diff --git a/tests/PhpWord/Tests/_files/images/duke_nukem.bmp b/tests/PhpWord/Tests/_files/images/duke_nukem.bmp index b78975d0..123b96f7 100644 Binary files a/tests/PhpWord/Tests/_files/images/duke_nukem.bmp and b/tests/PhpWord/Tests/_files/images/duke_nukem.bmp differ diff --git a/tests/PhpWord/Tests/_files/images/firefox.png b/tests/PhpWord/Tests/_files/images/firefox.png index 588afbfa..fb72cedd 100644 Binary files a/tests/PhpWord/Tests/_files/images/firefox.png and b/tests/PhpWord/Tests/_files/images/firefox.png differ diff --git a/tests/PhpWord/Tests/_files/templates/clone-delete-block.docx b/tests/PhpWord/Tests/_files/templates/clone-delete-block.docx new file mode 100644 index 00000000..049d5ca4 Binary files /dev/null and b/tests/PhpWord/Tests/_files/templates/clone-delete-block.docx differ diff --git a/tests/PhpWord/Tests/_files/templates/header-footer.docx b/tests/PhpWord/Tests/_files/templates/header-footer.docx new file mode 100644 index 00000000..647d5222 Binary files /dev/null and b/tests/PhpWord/Tests/_files/templates/header-footer.docx differ diff --git a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php index 97f84ac2..bea0d037 100644 --- a/tests/PhpWord/Tests/_includes/TestHelperDOCX.php +++ b/tests/PhpWord/Tests/_includes/TestHelperDOCX.php @@ -1,15 +1,32 @@