Merge branch 'develop' of https://github.com/PHPOffice/PHPWord.git into develop

This commit is contained in:
Bas-Jan 't Jong 2014-05-25 22:57:01 +02:00
commit 36080c14ca
88 changed files with 2071 additions and 1097 deletions

View File

@ -26,6 +26,10 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3; new r
- PDF Writer: Add TCPDF and mPDF as optional PDF renderer library - @ivanlanin
- ODT Writer: Enable title element and custom document properties - @ivanlanin
- ODT Reader: Ability to read standard and custom document properties - @ivanlanin
- Word2007 Writer: Enable the missing custom document properties writer - @ivanlanin
- Image: Enable "image float left" - @ivanlanin GH-244
- RTF Writer: Ability to write document properties - @ivanlanin
- RTF Writer: Ability to write image - @ivanlanin
### Bugfixes
@ -39,6 +43,7 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3; new r
- `Writer\Word2007\Part`: `Numbering::writeNumbering()`, `Settings::writeSettings()`, `WebSettings::writeWebSettings()`, `ContentTypes::writeContentTypes()`, `Styles::writeStyles()`, `Document::writeDocument()` all changed into `write()`
- `Writer\Word2007\Part\DocProps`: Split into `Writer\Word2007\Part\DocPropsCore` and `Writer\Word2007\Part\DocPropsApp`
- `Element\Title::getBookmarkId()` replaced by `Element\Title::getRelationId()`
- `Writer\HTML::writeDocument`: Replaced by `Writer\HTML::getContent`
### Miscellaneous
@ -54,6 +59,12 @@ This release marked the change of PHPWord license from LGPL 2.1 to LGPL 3; new r
- Style: Change behaviour of `set...` function of boolean properties; when none is defined, assumed true - @ivanlanin
- Shared: Unify PHP ZipArchive and PCLZip features into PhpWord ZipArchive - @ivanlanin
## 0.10.1 - 21 May 2014
This is a bugfix release for `php-zip` requirement in Composer.
- Change Composer requirements for php-zip from `require` to `suggest` - @bskrtich GH-246
## 0.10.0 - 4 May 2014
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.

View File

@ -1,189 +1,74 @@
# PHPWord License
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
PHPWord, a pure PHP library for reading and writing word processing documents
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Copyright (c) 2014 PHPWord
Preamble
This program 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 3 of the License, or
(at your option) any later version.
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
This program 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.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
## GNU LESSER GENERAL PUBLIC LICENSE
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
Version 3, 29 June 2007
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
0. Additional Definitions.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
The precise terms and conditions for copying, distribution and
modification follow.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
## GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
TERMS AND CONDITIONS
TERMS AND CONDITIONS
0. Definitions.
@ -732,3 +617,58 @@ reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

165
COPYING.LESSER Normal file
View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.

15
LICENSE Normal file
View File

@ -0,0 +1,15 @@
PHPWord, a pure PHP library for reading and writing word processing documents.
Copyright (c) 2010-2014 PHPWord.
PHPWord is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3 as published by
the Free Software Foundation.
PHPWord 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 version 3 for more details.
You should have received a copy of the GNU Lesser General Public License version 3
along with PHPWord. If not, see <http://www.gnu.org/licenses/>.

View File

@ -9,7 +9,7 @@
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), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF.
PHPWord is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPWord/blob/develop/LICENSE.md). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/) and the [API Documentation](http://phpoffice.github.io/PHPWord/docs/develop/).
PHPWord is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPWord/blob/develop/COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading the [Developers' Documentation](http://phpword.readthedocs.org/) and the [API Documentation](http://phpoffice.github.io/PHPWord/docs/develop/).
## Features

View File

@ -44,11 +44,11 @@
"mpdf/mpdf": "5.*"
},
"suggest": {
"ext-zip": "Used to create docx files",
"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"
"ext-zip": "Used to write DOCX and ODT",
"ext-gd2": "Used to add images",
"ext-xmlwriter": "Used to write DOCX and ODT",
"ext-xsl": "Used to apply XSL style sheet to template part",
"dompdf/dompdf": "Used to write PDF"
},
"autoload": {
"psr-4": {

View File

@ -13,7 +13,7 @@ Applications <http://en.wikipedia.org/wiki/OpenDocument>`__
Format <http://en.wikipedia.org/wiki/Rich_Text_Format>`__ (RTF).
PHPWord is an open source project licensed under the terms of `LGPL
version 3 <https://github.com/PHPOffice/PHPWord/blob/develop/LICENSE.md>`__.
version 3 <https://github.com/PHPOffice/PHPWord/blob/develop/COPYING.LESSER>`__.
PHPWord is aimed to be a high quality software product by incorporating
`continuous integration <https://travis-ci.org/PHPOffice/PHPWord>`__ and
`unit testing <http://phpoffice.github.io/PHPWord/coverage/develop/>`__.
@ -61,7 +61,7 @@ Writers
+---------------------------+----------------------+--------+-------+-------+--------+-------+
| Features | | DOCX | ODT | RTF | HTML | PDF |
+===========================+======================+========+=======+=======+========+=======+
| **Document Properties** | Standard | ✓ | ✓ | | | |
| **Document Properties** | Standard | ✓ | ✓ | ✓ | ✓ | ✓ |
+---------------------------+----------------------+--------+-------+-------+--------+-------+
| | Custom | ✓ | ✓ | | | |
+---------------------------+----------------------+--------+-------+-------+--------+-------+
@ -83,7 +83,7 @@ Writers
+---------------------------+----------------------+--------+-------+-------+--------+-------+
| | Table | ✓ | ✓ | | ✓ | ✓ |
+---------------------------+----------------------+--------+-------+-------+--------+-------+
| | Image | ✓ | ✓ | | ✓ | |
| | Image | ✓ | ✓ | | ✓ | |
+---------------------------+----------------------+--------+-------+-------+--------+-------+
| | Object | ✓ | | | | |
+---------------------------+----------------------+--------+-------+-------+--------+-------+

View File

@ -2,3 +2,42 @@
Recipes
=======
Create float left image
-----------------------
Use absolute positioning relative to margin horizontally and to line
vertically.
.. code-block:: php
$imageStyle = array(
'width' => 40,
'height' => 40
'wrappingStyle' => 'square',
'positioning' => 'absolute',
'posHorizontalRel' => 'margin',
'posVerticalRel' => 'line',
);
$textrun->addImage('resources/_earth.jpg', $imageStyle);
$textrun->addText($lipsumText);
Download the produced file automatically
----------------------------------------
Use ``php://output`` as the filename.
.. code-block:: php
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->createSection();
$section->addText('Hello World!');
$file = 'HelloWorld.docx';
header("Content-Description: File Transfer");
header('Content-Disposition: attachment; filename="' . $file . '"');
header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
$xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
$xmlWriter->save("php://output");

View File

@ -40,6 +40,7 @@ Don't forget to change `code::` directive to `code-block::` in the resulting rst
- [RTF](#rtf)
- [HTML](#html)
- [PDF](#pdf)
- [Recipes](#recipes)
- [Frequently asked questions](#frequently-asked-questions)
- [References](#references)
@ -47,7 +48,7 @@ Don't forget to change `code::` directive to `code-block::` in the resulting rst
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).
PHPWord is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPWord/blob/develop/LICENSE.md). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading this Developers' Documentation and the [API Documentation](http://phpoffice.github.io/PHPWord/docs/develop/).
PHPWord is an open source project licensed under the terms of [LGPL version 3](https://github.com/PHPOffice/PHPWord/blob/develop/COPYING.LESSER). PHPWord is aimed to be a high quality software product by incorporating [continuous integration](https://travis-ci.org/PHPOffice/PHPWord) and [unit testing](http://phpoffice.github.io/PHPWord/coverage/develop/). You can learn more about PHPWord by reading this Developers' Documentation and the [API Documentation](http://phpoffice.github.io/PHPWord/docs/develop/).
## Features
@ -78,7 +79,7 @@ Below are the supported features for each file formats.
| Features | | DOCX | ODT | RTF | HTML | PDF |
|-------------------------|--------------------|------|-----|-----|------|-----|
| **Document Properties** | Standard | ✓ | ✓ | | | |
| **Document Properties** | Standard | ✓ | ✓ | ✓ | ✓ | |
| | Custom | ✓ | ✓ | | | |
| **Element Type** | Text | ✓ | ✓ | ✓ | ✓ | ✓ |
| | Text Run | ✓ | ✓ | ✓ | ✓ | ✓ |
@ -89,7 +90,7 @@ Below are the supported features for each file formats.
| | Page Break | ✓ | | ✓ | | |
| | List | ✓ | | | | |
| | Table | ✓ | ✓ | | ✓ | ✓ |
| | Image | ✓ | ✓ | | ✓ | |
| | Image | ✓ | ✓ | | ✓ | |
| | Object | ✓ | | | | |
| | Watermark | ✓ | | | | |
| | Table of Contents | ✓ | | | | |
@ -929,6 +930,44 @@ To be completed.
To be completed.
# Recipes
## Create float left image
Use absolute positioning relative to margin horizontally and to line vertically.
```php
$imageStyle = array(
'width' => 40,
'height' => 40
'wrappingStyle' => 'square',
'positioning' => 'absolute',
'posHorizontalRel' => 'margin',
'posVerticalRel' => 'line',
);
$textrun->addImage('resources/_earth.jpg', $imageStyle);
$textrun->addText($lipsumText);
```
## Download the produced file automatically
Use `php://output` as the filename.
```php
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->createSection();
$section->addText('Hello World!');
$file = 'HelloWorld.docx';
header("Content-Description: File Transfer");
header('Content-Disposition: attachment; filename="' . $file . '"');
header('Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document');
header('Content-Transfer-Encoding: binary');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Expires: 0');
$xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
$xmlWriter->save("php://output");
```
# Frequently asked questions
## Is this the same with PHPWord that I found in CodePlex?

View File

@ -40,6 +40,9 @@ $section->addImage(
'width' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(3),
'height' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(3),
'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE,
'posHorizontal' => \PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_RIGHT,
'posHorizontalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_PAGE,
'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_PAGE,
'marginLeft' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(15.5),
'marginTop' => \PhpOffice\PhpWord\Shared\Drawing::centimetersToPixels(1.55)
)

View File

@ -22,6 +22,7 @@ namespace PhpOffice\PhpWord;
*/
class Autoloader
{
/** @const string */
const NAMESPACE_PREFIX = 'PhpOffice\\PhpWord\\';
/**
@ -46,6 +47,7 @@ class Autoloader
$file = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, $prefixLength));
$file = realpath(__DIR__ . (empty($file) ? '' : DIRECTORY_SEPARATOR) . $file . '.php');
if (file_exists($file)) {
/** @noinspection PhpIncludeInspection Dynamic includes */
require_once $file;
}
}

View File

@ -22,7 +22,7 @@ namespace PhpOffice\PhpWord;
*/
class DocumentProperties
{
/** Constants */
/** @const string Property type constants */
const PROPERTY_TYPE_BOOLEAN = 'b';
const PROPERTY_TYPE_INTEGER = 'i';
const PROPERTY_TYPE_FLOAT = 'f';
@ -488,49 +488,23 @@ class DocumentProperties
*/
public static function convertProperty($propertyValue, $propertyType)
{
switch ($propertyType) {
case 'empty': // Empty
$conversion = self::getConversion($propertyType);
switch ($conversion) {
case 'empty': // Empty
return '';
case 'null': // Null
case 'null': // Null
return null;
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 'int': // Signed integer
return (int) $propertyValue;
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
case 'uint': // Unsigned integer
return abs((int) $propertyValue);
case 'r4': // 4-Byte Real Number
case 'r8': // 8-Byte Real Number
case 'decimal': // Decimal
case 'float': // Float
return (float) $propertyValue;
case 'date': // Date and Time
case 'filetime': // File Time
case 'date': // Date
return strtotime($propertyValue);
case 'bool': // Boolean
case 'bool': // Boolean
return ($propertyValue == 'true') ? true : false;
case 'lpstr': // LPSTR
case 'lpwstr': // LPWSTR
case 'bstr': // Basic String
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 $propertyValue;
}
return $propertyValue;
@ -569,10 +543,36 @@ class DocumentProperties
*/
private function setValue($value, $default)
{
if (is_null($value) || $value == '') {
if ($value === null || $value == '') {
$value = $default;
}
return $value;
}
/**
* Get conversion model depending on property type
*
* @param string $propertyType
* @return string
*/
private static function getConversion($propertyType)
{
$conversions = array(
'empty' => array('empty'),
'null' => array('null'),
'int' => array('i1', 'i2', 'i4', 'i8', 'int'),
'uint' => array('ui1', 'ui2', 'ui4', 'ui8', 'uint'),
'float' => array('r4', 'r8', 'decimal'),
'bool' => array('bool'),
'date' => array('date', 'filetime'),
);
foreach ($conversions as $conversion => $types) {
if (in_array($propertyType, $types)) {
return $conversion;
}
}
return 'string';
}
}

View File

@ -56,37 +56,24 @@ abstract class AbstractContainer extends AbstractElement
// Get arguments
$args = func_get_args();
$argsCount = func_num_args();
$withoutP = in_array($this->container, array('TextRun', 'Footnote', 'Endnote', 'ListItemRun'));
if ($withoutP && ($elementName == 'Text' || $elementName == 'PreserveText')) {
$args[3] = null;
$args[3] = null; // Remove paragraph style for texts in textrun
}
// Create element dynamically
// Create element using reflection
$reflection = new \ReflectionClass($elementClass);
$elementArgs = $args;
array_shift($elementArgs); // Shift an element off the beginning of array: the $elementName
/** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */
if ($argsCount == 2) { // TextRun, TextBox, Table, Footnote, Endnote
$element = new $elementClass($args[1]);
} elseif ($argsCount == 3) { // Object, TextBreak, Title
$element = new $elementClass($args[1], $args[2]);
} elseif ($argsCount == 4) { // PreserveText, Text, Image
$element = new $elementClass($args[1], $args[2], $args[3]);
} elseif ($argsCount == 5) { // CheckBox, Link, ListItemRun, TOC
$element = new $elementClass($args[1], $args[2], $args[3], $args[4]);
} elseif ($argsCount == 6) { // ListItem
$element = new $elementClass($args[1], $args[2], $args[3], $args[4], $args[5]);
} else { // Page Break
$element = new $elementClass();
}
$element = $reflection->newInstanceArgs($elementArgs);
// Set relation Id for media collection
$mediaContainer = $this->getMediaContainer();
if (in_array($elementName, array('Link', 'Image', 'Object'))) {
if ($elementName == 'Image') {
$rId = Media::addElement($mediaContainer, strtolower($elementName), $args[1], $element);
} else {
$rId = Media::addElement($mediaContainer, strtolower($elementName), $args[1]);
}
/** @var \PhpOffice\PhpWord\Element\Image $element Type hint */
$image = ($elementName == 'Image') ? $element : null;
$rId = Media::addElement($mediaContainer, strtolower($elementName), $args[1], $image);
$element->setRelationId($rId);
}
if ($elementName == 'Object') {

View File

@ -279,6 +279,77 @@ class Image extends AbstractElement
$this->mediaIndex = $value;
}
/**
* Get image string data
*
* @param bool $base64
* @return string|null
* @since 0.11.0
*/
public function getImageStringData($base64 = false)
{
$source = $this->source;
$actualSource = null;
$imageBinary = null;
$imageData = null;
$isTemp = false;
// Get actual source from archive image or other source
// Return null if not found
if ($this->sourceType == self::SOURCE_ARCHIVE) {
$source = substr($source, 6);
list($zipFilename, $imageFilename) = explode('#', $source);
$zip = new ZipArchive();
if ($zip->open($zipFilename) !== false) {
if ($zip->locateName($imageFilename)) {
$isTemp = true;
$zip->extractTo(sys_get_temp_dir(), $imageFilename);
$actualSource = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $imageFilename;
}
}
$zip->close();
} else {
$actualSource = $source;
}
// Can't find any case where $actualSource = null hasn't captured by
// preceding exceptions. Please uncomment when you find the case and
// put the case into Element\ImageTest.
// if ($actualSource === null) {
// return null;
// }
// Read image binary data and convert to hex/base64 string
if ($this->sourceType == self::SOURCE_GD) {
$imageResource = call_user_func($this->imageCreateFunc, $actualSource);
ob_start();
call_user_func($this->imageFunc, $imageResource);
$imageBinary = ob_get_contents();
ob_end_clean();
} else {
$fileHandle = fopen($actualSource, 'rb', false);
if ($fileHandle !== false) {
$imageBinary = fread($fileHandle, filesize($actualSource));
fclose($fileHandle);
}
}
if ($imageBinary !== null) {
if ($base64) {
$imageData = chunk_split(base64_encode($imageBinary));
} else {
$imageData = chunk_split(bin2hex($imageBinary));
}
}
// Delete temporary file if necessary
if ($isTemp === true) {
@unlink($actualSource);
}
return $imageData;
}
/**
* Check memory image, supported type, image functions, and proportional width/height
*

View File

@ -139,37 +139,53 @@ class Media
* Get media elements
*
* @param string $container section|headerx|footerx|footnote|endnote
* @param string $mediaType image|object|link
* @param string $type image|object|link
* @return array
* @since 0.10.0
*/
public static function getElements($container, $mediaType = null)
public static function getElements($container, $type = null)
{
$mediaElements = array();
$elements = 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;
$elements[$key] = $val;
}
}
return $elements;
} else {
if (!array_key_exists($container, self::$elements)) {
return $mediaElements;
return $elements;
}
foreach (self::$elements[$container] as $mediaKey => $mediaData) {
if (!is_null($mediaType)) {
if ($mediaType == $mediaData['type']) {
$mediaElements[$mediaKey] = $mediaData;
}
} else {
$mediaElements[$mediaKey] = $mediaData;
return self::getElementsByType($container, $type);
}
}
/**
* Get elements by media type
*
* @param string $container section|footnote|endnote
* @param string $type image|object|link
* @return array
* @since 0.11.0 Splitted from `getElements` to reduce complexity
*/
private static function getElementsByType($container, $type = null)
{
$elements = array();
foreach (self::$elements[$container] as $key => $data) {
if ($type !== null) {
if ($type == $data['type']) {
$elements[$key] = $data;
}
} else {
$elements[$key] = $data;
}
}
return $mediaElements;
return $elements;
}
/**

View File

@ -22,6 +22,7 @@ use PhpOffice\PhpWord\Exception\Exception;
/**
* Reader abstract class
*
* @since 0.8.0
* @codeCoverageIgnore Abstract class
*/
abstract class AbstractReader implements ReaderInterface

View File

@ -18,82 +18,13 @@
namespace PhpOffice\PhpWord\Reader\ODText;
use PhpOffice\PhpWord\Reader\Word2007\AbstractPart as Word2007AbstractPart;
use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Abstract part reader
*
* @since 0.10.0
* @codeCoverageIgnore Nothing in here yet
*/
abstract class AbstractPart extends Word2007AbstractPart
{
/**
* Read w:p (override)
*
* @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
* @param \DOMElement $domNode
* @param mixed $parent
* @param string $docPart
*
* @todo Get font style for preserve text
*/
protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart)
{
}
/**
* Read w:r (override)
*
* @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
* @param \DOMElement $domNode
* @param mixed $parent
* @param string $docPart
* @param mixed $paragraphStyle
*/
protected function readRun(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart, $paragraphStyle = null)
{
}
/**
* Read w:tbl (override)
*
* @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
* @param \DOMElement $domNode
* @param mixed $parent
* @param string $docPart
*/
protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart)
{
}
/**
* Read w:pPr (override)
*/
protected function readParagraphStyle(XMLReader $xmlReader, \DOMElement $domNode)
{
}
/**
* Read w:rPr (override)
*/
protected function readFontStyle(XMLReader $xmlReader, \DOMElement $domNode)
{
}
/**
* Read w:tblPr (override)
*/
protected function readTableStyle(XMLReader $xmlReader, \DOMElement $domNode)
{
}
/**
* Read style definition (override)
*
* @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
* @param \DOMElement $parentNode
* @param array $styleDefs
* @return array
*/
protected function readStyleDefs(XMLReader $xmlReader, \DOMElement $parentNode = null, $styleDefs = array())
{
}
}

View File

@ -19,6 +19,8 @@ namespace PhpOffice\PhpWord\Reader;
/**
* Reader interface
*
* @since 0.8.0
*/
interface ReaderInterface
{

View File

@ -24,6 +24,8 @@ use PhpOffice\PhpWord\Shared\XMLReader;
* Abstract part reader
*
* This class is inherited by ODText reader
*
* @since 0.10.0
*/
abstract class AbstractPart
{
@ -96,7 +98,7 @@ abstract class AbstractPart
*
* @todo Get font style for preserve text
*/
protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart)
protected function readParagraph(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart = 'document')
{
// Paragraph style
$paragraphStyle = null;
@ -246,7 +248,7 @@ abstract class AbstractPart
* @param mixed $parent
* @param string $docPart
*/
protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart)
protected function readTable(XMLReader $xmlReader, \DOMElement $domNode, &$parent, $docPart = 'document')
{
// Table style
$tblStyle = null;
@ -451,17 +453,9 @@ abstract class AbstractPart
$attribute = ($attribute === null) ? 'w:val' : $attribute;
$attributeValue = $xmlReader->getAttribute($attribute, $node);
// Assign style value based on conversion model
if ($method == self::READ_VALUE) {
$styles[$styleProp] = $attributeValue;
} elseif ($method == self::READ_SIZE) {
$styles[$styleProp] = $attributeValue / 2;
} elseif ($method == self::READ_TRUE) {
$styles[$styleProp] = true;
} elseif ($method == self::READ_FALSE) {
$styles[$styleProp] = false;
} elseif ($method == self::READ_EQUAL && $attributeValue == $expected) {
$styles[$styleProp] = true;
$styleValue = $this->readStyleDef($method, $attributeValue, $expected);
if ($styleValue !== null) {
$styles[$styleProp] = $styleValue;
}
}
}
@ -469,6 +463,31 @@ abstract class AbstractPart
return $styles;
}
/**
* Return style definition based on conversion method
*
* @param string $method
* @param mixed $attributeValue
* @param mixed $expected
* @return mixed
*/
private function readStyleDef($method, $attributeValue, $expected)
{
$style = $attributeValue;
if ($method == self::READ_SIZE) {
$style = $attributeValue / 2;
} elseif ($method == self::READ_TRUE) {
$style = true;
} elseif ($method == self::READ_FALSE) {
$style = false;
} elseif ($method == self::READ_EQUAL && $attributeValue == $expected) {
$style = true;
}
return $style;
}
/**
* Returns the target of image, object, or link as stored in ::readMainRels
*

View File

@ -19,6 +19,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007;
/**
* Extended properties reader
*
* @since 0.10.0
*/
class DocPropsApp extends DocPropsCore
{

View File

@ -22,6 +22,8 @@ use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Core properties reader
*
* @since 0.10.0
*/
class DocPropsCore extends AbstractPart
{

View File

@ -23,6 +23,8 @@ use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Custom properties reader
*
* @since 0.11.0
*/
class DocPropsCustom extends AbstractPart
{

View File

@ -19,12 +19,23 @@ namespace PhpOffice\PhpWord\Reader\Word2007;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Shared\XMLReader;
use PhpOffice\PhpWord\Element\Section;
/**
* Document reader
*
* @since 0.10.0
* @SuppressWarnings(PHPMD.UnusedPrivateMethod) For readWPNode
*/
class Document extends AbstractPart
{
/**
* PhpWord object
*
* @var \PhpOffice\PhpWord\PhpWord
*/
private $phpWord;
/**
* Read document.xml
*
@ -32,45 +43,18 @@ class Document extends AbstractPart
*/
public function read(PhpWord &$phpWord)
{
$this->phpWord = $phpWord;
$xmlReader = new XMLReader();
$xmlReader->getDomFromZip($this->docFile, $this->xmlFile);
$readMethods = array('w:p' => 'readWPNode', 'w:tbl' => 'readTable', 'w:sectPr' => 'readWSectPrNode');
$nodes = $xmlReader->getElements('w:body/*');
if ($nodes->length > 0) {
$section = $phpWord->addSection();
$section = $this->phpWord->addSection();
foreach ($nodes as $node) {
switch ($node->nodeName) {
case 'w:p': // Paragraph
// Page break
// @todo <w:lastRenderedPageBreak>
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);
$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);
$this->readHeaderFooter($settings, $section);
break;
if (array_key_exists($node->nodeName, $readMethods)) {
$readMethod = $readMethods[$node->nodeName];
$this->$readMethod($xmlReader, $node, $section);
}
}
}
@ -82,14 +66,16 @@ class Document extends AbstractPart
* @param array $settings
* @param \PhpOffice\PhpWord\Element\Section $section
*/
private function readHeaderFooter($settings, &$section)
private function readHeaderFooter($settings, Section &$section)
{
$readMethods = array('w:p' => 'readParagraph', 'w:tbl' => 'readTable');
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']);
$addMethod = "add{$hfType}";
$hfObject = $section->$addMethod($hfSetting['type']);
// Read header/footer content
$xmlReader = new XMLReader();
@ -97,15 +83,9 @@ class Document extends AbstractPart
$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;
if (array_key_exists($node->nodeName, $readMethods)) {
$readMethod = $readMethods[$node->nodeName];
$this->$readMethod($xmlReader, $node, $hfObject, $docPart);
}
}
}
@ -155,4 +135,47 @@ class Document extends AbstractPart
return $styles;
}
/**
* Read w:p node
*
* @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
* @param \DOMElement $node
* @param \PhpOffice\PhpWord\Element\Section $section
*
* @todo <w:lastRenderedPageBreak>
*/
private function readWPNode(XMLReader $xmlReader, \DOMElement $node, Section &$section)
{
// Page break
if ($xmlReader->getAttribute('w:type', $node, 'w:r/w:br') == 'page') {
$section->addPageBreak(); // PageBreak
}
// Paragraph
$this->readParagraph($xmlReader, $node, $section);
// Section properties
if ($xmlReader->elementExists('w:pPr/w:sectPr', $node)) {
$sectPrNode = $xmlReader->getElement('w:pPr/w:sectPr', $node);
if ($sectPrNode !== null) {
$this->readWSectPrNode($xmlReader, $sectPrNode, $section);
}
$section = $this->phpWord->addSection();
}
}
/**
* Read w:sectPr node
*
* @param \PhpOffice\PhpWord\Shared\XMLReader $xmlReader
* @param \DOMElement $node
* @param \PhpOffice\PhpWord\Element\Section $section
*/
private function readWSectPrNode(XMLReader $xmlReader, \DOMElement $node, Section &$section)
{
$settings = $this->readSectionStyle($xmlReader, $node);
$section->setSettings($settings);
$this->readHeaderFooter($settings, $section);
}
}

View File

@ -19,6 +19,8 @@ namespace PhpOffice\PhpWord\Reader\Word2007;
/**
* Endnotes reader
*
* @since 0.10.0
*/
class Endnotes extends Footnotes
{

View File

@ -22,6 +22,8 @@ use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Footnotes reader
*
* @since 0.10.0
*/
class Footnotes extends AbstractPart
{

View File

@ -22,6 +22,8 @@ use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Numbering reader
*
* @since 0.10.0
*/
class Numbering extends AbstractPart
{

View File

@ -22,6 +22,8 @@ use PhpOffice\PhpWord\Shared\XMLReader;
/**
* Styles reader
*
* @since 0.10.0
*/
class Styles extends AbstractPart
{

View File

@ -344,7 +344,7 @@ class Settings
// Parse config file
$config = array();
if ($configFile !== null) {
$config = parse_ini_file($configFile);
$config = @parse_ini_file($configFile);
if ($config === false) {
return $config;
}

View File

@ -88,12 +88,26 @@ class String
/**
* Returns unicode from UTF8 text
*
* The function is splitted to reduce cyclomatic complexity
*
* @param string $text UTF8 text
* @return string Unicode text
* @since 0.11.0
* @link http://www.randomchaos.com/documents/?source=php_and_unicode
*/
public static function toUnicode($text)
{
return self::unicodeToEntities(self::utf8ToUnicode($text));
}
/**
* Returns unicode array from UTF8 text
*
* @param string $text UTF8 text
* @return array
* @since 0.11.0
* @link http://www.randomchaos.com/documents/?source=php_and_unicode
*/
private static function utf8ToUnicode($text)
{
$unicode = array();
$values = array();
@ -122,8 +136,21 @@ class String
}
}
// Converts text with utf8 characters into rtf utf8 entites preserving ascii
return $unicode;
}
/**
* Returns entites from unicode array
*
* @param array $unicode
* @return string
* @since 0.11.0
* @link http://www.randomchaos.com/documents/?source=php_and_unicode
*/
private static function unicodeToEntities($unicode)
{
$entities = '';
foreach ($unicode as $value) {
if ($value != 65279) {
$entities .= $value > 127 ? '\uc0{\u' . $value . '}' : chr($value);

View File

@ -58,11 +58,6 @@ class XMLWriter
*/
public function __construct($tempLocation = self::STORAGE_MEMORY, $tempFolder = './')
{
// Define date format
if (!defined('DATE_W3C')) {
define('DATE_W3C', 'Y-m-d\TH:i:sP');
}
// Create internal XMLWriter
$this->xmlWriter = new \XMLWriter();
@ -73,9 +68,8 @@ class XMLWriter
// Create temporary filename
$this->tempFile = @tempnam($tempFolder, 'xml');
// Open storage
// Fallback to memory when temporary file cannot be used
if ($this->xmlWriter->openUri($this->tempFile) === false) {
// Fallback to memory...
$this->xmlWriter->openMemory();
}
}
@ -110,9 +104,16 @@ class XMLWriter
*
* @param mixed $function
* @param mixed $args
* @throws \BadMethodCallException
*/
public function __call($function, $args)
{
// Catch exception
if (method_exists($this->xmlWriter, $function) === false) {
throw new \BadMethodCallException("Method '{$function}' does not exists.");
}
// Run method
try {
@call_user_func_array(array($this->xmlWriter, $function), $args);
} catch (\Exception $ex) {

View File

@ -265,7 +265,7 @@ abstract class AbstractStyle
{
if ($value != null && trim($value) != '' && !empty($enum) && !in_array($value, $enum)) {
throw new \InvalidArgumentException('Invalid style value.');
} elseif (is_null($value) || trim($value) == '') {
} elseif ($value === null || trim($value) == '') {
$value = $default;
}

View File

@ -81,7 +81,7 @@ class Border extends AbstractStyle
/**
* Get border size
*
* @return int[]
* @return integer[]
*/
public function getBorderSize()
{

View File

@ -144,7 +144,7 @@ class Cell extends Border
*/
public function getBgColor()
{
if (!is_null($this->shading)) {
if ($this->shading !== null) {
return $this->shading->getFill();
} else {
return null;

View File

@ -540,7 +540,7 @@ class Font extends AbstractStyle
*/
public function getBgColor()
{
if (!is_null($this->shading)) {
if ($this->shading !== null) {
return $this->shading->getFill();
} else {
return null;

View File

@ -61,6 +61,7 @@ class Image extends AbstractStyle
const POSITION_RELATIVE_TO_PAGE = 'page';
const POSITION_RELATIVE_TO_COLUMN = 'column'; // horizontal only
const POSITION_RELATIVE_TO_CHAR = 'char'; // horizontal only
const POSITION_RELATIVE_TO_TEXT = 'text'; // vertical only
const POSITION_RELATIVE_TO_LINE = 'line'; // vertical only
const POSITION_RELATIVE_TO_LMARGIN = 'left-margin-area'; // horizontal only
const POSITION_RELATIVE_TO_RMARGIN = 'right-margin-area'; // horizontal only
@ -103,14 +104,14 @@ class Image extends AbstractStyle
*
* @var int
*/
private $marginTop;
private $marginTop = 0;
/**
* Margin Left
*
* @var int
*/
private $marginLeft;
private $marginLeft = 0;
/**
* Wrapping style
@ -247,9 +248,9 @@ class Image extends AbstractStyle
* @param int $value
* @return self
*/
public function setMarginTop($value = null)
public function setMarginTop($value = 0)
{
$this->marginTop = $value;
$this->marginTop = $this->setIntVal($value, 0);
return $this;
}
@ -270,9 +271,9 @@ class Image extends AbstractStyle
* @param int $value
* @return self
*/
public function setMarginLeft($value = null)
public function setMarginLeft($value = 0)
{
$this->marginLeft = $value;
$this->marginLeft = $this->setIntVal($value, 0);
return $this;
}
@ -352,7 +353,7 @@ class Image extends AbstractStyle
{
$enum = array(
self::POSITION_HORIZONTAL_LEFT, self::POSITION_HORIZONTAL_CENTER,
self::POSITION_HORIZONTAL_RIGHT,
self::POSITION_HORIZONTAL_RIGHT, self::POSITION_ABSOLUTE
);
$this->posHorizontal = $this->setEnumVal($alignment, $enum, $this->posHorizontal);
@ -381,7 +382,7 @@ class Image extends AbstractStyle
$enum = array(
self::POSITION_VERTICAL_TOP, self::POSITION_VERTICAL_CENTER,
self::POSITION_VERTICAL_BOTTOM, self::POSITION_VERTICAL_INSIDE,
self::POSITION_VERTICAL_OUTSIDE,
self::POSITION_VERTICAL_OUTSIDE, self::POSITION_ABSOLUTE
);
$this->posVertical = $this->setEnumVal($alignment, $enum, $this->posVertical);
@ -439,7 +440,7 @@ class Image extends AbstractStyle
{
$enum = array(
self::POSITION_RELATIVE_TO_MARGIN, self::POSITION_RELATIVE_TO_PAGE,
self::POSITION_RELATIVE_TO_LINE,
self::POSITION_RELATIVE_TO_TEXT, self::POSITION_RELATIVE_TO_LINE,
self::POSITION_RELATIVE_TO_TMARGIN, self::POSITION_RELATIVE_TO_BMARGIN,
self::POSITION_RELATIVE_TO_IMARGIN, self::POSITION_RELATIVE_TO_OMARGIN,
);

View File

@ -20,11 +20,12 @@ namespace PhpOffice\PhpWord\Style;
/**
* Line numbering style
*
* @link http://www.schemacentral.com/sc/ooxml/e-w_lnNumType-1.html
* @link http://www.schemacentral.com/sc/ooxml/t-w_CT_LineNumber.html
* @since 0.10.0
*/
class LineNumbering extends AbstractStyle
{
/** @const string Line numbering restart setting http://www.schemacentral.com/sc/ooxml/a-w_restart-1.html */
const LINE_NUMBERING_CONTINUOUS = 'continuous';
const LINE_NUMBERING_NEW_PAGE = 'newPage';
const LINE_NUMBERING_NEW_SECTION = 'newSection';

View File

@ -65,7 +65,7 @@ class ListItem extends AbstractStyle
*/
public function __construct($numStyle = null)
{
if (!is_null($numStyle)) {
if ($numStyle !== null) {
$this->setNumStyle($numStyle);
} else {
$this->setListType();
@ -149,7 +149,7 @@ class ListItem extends AbstractStyle
{
// Check if legacy style already registered in global Style collection
$numStyle = "PHPWordList{$this->listType}";
if (!is_null(Style::getStyle($numStyle))) {
if (Style::getStyle($numStyle) !== null) {
$this->setNumStyle($numStyle);
return;
}

View File

@ -171,7 +171,7 @@ class Paragraph extends AbstractStyle
*/
public function getSpaceBefore()
{
if (!is_null($this->spacing)) {
if ($this->spacing !== null) {
return $this->spacing->getBefore();
} else {
return null;
@ -196,7 +196,7 @@ class Paragraph extends AbstractStyle
*/
public function getSpaceAfter()
{
if (!is_null($this->spacing)) {
if ($this->spacing !== null) {
return $this->spacing->getAfter();
} else {
return null;
@ -221,7 +221,7 @@ class Paragraph extends AbstractStyle
*/
public function getSpacing()
{
if (!is_null($this->spacing)) {
if ($this->spacing !== null) {
return $this->spacing->getLine();
} else {
return null;
@ -278,7 +278,7 @@ class Paragraph extends AbstractStyle
*/
public function getIndent()
{
if (!is_null($this->indentation)) {
if ($this->indentation !== null) {
return $this->indentation->getLeft();
} else {
return null;
@ -303,7 +303,7 @@ class Paragraph extends AbstractStyle
*/
public function getHanging()
{
if (!is_null($this->indentation)) {
if ($this->indentation !== null) {
return $this->indentation->getHanging();
} else {
return null;

View File

@ -169,7 +169,7 @@ class Table extends Border
*/
public function getBgColor()
{
if (!is_null($this->shading)) {
if ($this->shading !== null) {
return $this->shading->getFill();
}
@ -192,7 +192,7 @@ class Table extends Border
/**
* Get TLRBHV Border Size
*
* @return int[]
* @return integer[]
*/
public function getBorderSize()
{

View File

@ -162,7 +162,7 @@ class TextBox extends Image
/**
* Get cell margin
*
* @return int[]
* @return integer[]
*/
public function getInnerMargin()
{
@ -179,7 +179,7 @@ class TextBox extends Image
$hasInnerMargins = false;
$margins = $this->getInnerMargin();
for ($i = 0; $i < count($margins); $i++) {
if (!is_null($margins[$i])) {
if ($margins[$i] !== null) {
$hasInnerMargins = true;
}
}

View File

@ -258,7 +258,7 @@ abstract class AbstractWriter implements WriterInterface
*
* @param string $filename
* @return \PhpOffice\PhpWord\Shared\ZipArchive
* @throws \PhpOffice\PhpWord\Exception\Exception
* @throws \Exception
*/
protected function getZipArchive($filename)
{
@ -271,13 +271,46 @@ abstract class AbstractWriter implements WriterInterface
$zip = new ZipArchive();
if ($zip->open($filename, ZipArchive::OVERWRITE) !== true) {
if ($zip->open($filename, ZipArchive::CREATE) !== true) {
throw new Exception("Could not open " . $filename . " for writing.");
throw new \Exception("Could not open '{$filename}' for writing.");
}
}
return $zip;
}
/**
* Open file for writing
*
* @param string $filename
* @return resource
* @throws \Exception
* @since 0.11.0
*/
protected function openFile($filename)
{
$filename = $this->getTempFile($filename);
$fileHandle = fopen($filename, 'w');
if ($fileHandle === false) {
throw new \Exception("Could not open '{$filename}' for writing.");
}
return $fileHandle;
}
/**
* Write content to file
*
* @param resource $fileHandle
* @param string $content
* @since 0.11.0
*/
protected function writeFile(&$fileHandle, $content)
{
fwrite($fileHandle, $content);
fclose($fileHandle);
$this->cleanupTempFile();
}
/**
* Add files to package
*

View File

@ -17,17 +17,7 @@
namespace PhpOffice\PhpWord\Writer;
use PhpOffice\PhpWord\Exception\Exception;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\Paragraph;
use PhpOffice\PhpWord\Writer\HTML\Element\Container;
use PhpOffice\PhpWord\Writer\HTML\Element\TextRun as TextRunWriter;
use PhpOffice\PhpWord\Writer\HTML\Style\Font as FontStyleWriter;
use PhpOffice\PhpWord\Writer\HTML\Style\Generic as GenericStyleWriter;
use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph as ParagraphStyleWriter;
/**
* HTML writer
@ -57,6 +47,17 @@ class HTML extends AbstractWriter implements WriterInterface
public function __construct(PhpWord $phpWord = null)
{
$this->setPhpWord($phpWord);
$this->parts = array('Head', 'Body');
foreach ($this->parts as $partName) {
$partClass = 'PhpOffice\\PhpWord\\Writer\\HTML\\Part\\' . $partName;
if (class_exists($partClass)) {
/** @var \PhpOffice\PhpWord\Writer\HTML\Part\AbstractPart $part Type hint */
$part = new $partClass();
$part->setParentWriter($this);
$this->writerParts[strtolower($partName)] = $part;
}
}
}
/**
@ -67,182 +68,26 @@ class HTML extends AbstractWriter implements WriterInterface
*/
public function save($filename = null)
{
$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();
}
/**
* Get phpWord data
*
* @return string
*/
public function writeDocument()
{
$content = '';
$content .= '<!DOCTYPE html>' . PHP_EOL;
$content .= '<!-- Generated by PHPWord -->' . PHP_EOL;
$content .= '<html>' . PHP_EOL;
$content .= '<head>' . PHP_EOL;
$content .= $this->writeHead();
$content .= '</head>' . PHP_EOL;
$content .= '<body>' . PHP_EOL;
$content .= $this->writeBody();
$content .= $this->writeNotes();
$content .= '</body>' . PHP_EOL;
$content .= '</html>' . PHP_EOL;
return $content;
}
/**
* Generate HTML header
*
* @return string
*/
private function writeHead()
{
$phpWord = $this->getPhpWord();
$properties = $phpWord->getDocumentProperties();
$propertiesMapping = array(
'creator' => 'author',
'title' => '',
'description' => '',
'subject' => '',
'keywords' => '',
'category' => '',
'company' => '',
'manager' => ''
);
$title = $properties->getTitle();
$title = ($title != '') ? $title : 'PHPWord';
$content = '';
$content .= '<meta charset="UTF-8" />' . PHP_EOL;
$content .= '<title>' . htmlspecialchars($title) . '</title>' . PHP_EOL;
foreach ($propertiesMapping as $key => $value) {
$value = ($value == '') ? $key : $value;
$method = "get" . $key;
if ($properties->$method() != '') {
$content .= '<meta name="' . $value . '" content="' .
htmlspecialchars($properties->$method()) . '" />' . PHP_EOL;
}
}
$content .= $this->writeStyles();
return $content;
$fileHandle = $this->openFile($filename);
$this->writeFile($fileHandle, $this->getContent());
}
/**
* Get content
*
* @return string
* @since 0.11.0
*/
private function writeBody()
public function getContent()
{
$phpWord = $this->getPhpWord();
$content = '';
$sections = $phpWord->getSections();
$countSections = count($sections);
if ($countSections > 0) {
foreach ($sections as $section) {
$writer = new Container($this, $section);
$content .= $writer->write();
}
}
return $content;
}
/**
* Get styles
*
* @return string
*/
private function writeStyles()
{
$css = '<style>' . PHP_EOL;
// Default styles
$defaultStyles = array(
'*' => array(
'font-family' => Settings::getDefaultFontName(),
'font-size' => Settings::getDefaultFontSize() . 'pt',
),
'a.NoteRef' => array(
'text-decoration' => 'none',
),
'hr' => array(
'height' => '1px',
'padding' => '0',
'margin' => '1em 0',
'border' => '0',
'border-top' => '1px solid #CCC',
),
);
foreach ($defaultStyles as $selector => $style) {
$styleWriter = new GenericStyleWriter($style);
$css .= $selector . ' {' . $styleWriter->write() . '}' . PHP_EOL;
}
// Custom styles
$customStyles = Style::getStyles();
if (is_array($customStyles)) {
foreach ($customStyles as $name => $style) {
if ($style instanceof Font) {
$styleWriter = new FontStyleWriter($style);
if ($style->getStyleType() == 'title') {
$name = str_replace('Heading_', 'h', $name);
} else {
$name = '.' . $name;
}
$css .= "{$name} {" . $styleWriter->write() . '}' . PHP_EOL;
} elseif ($style instanceof Paragraph) {
$styleWriter = new ParagraphStyleWriter($style);
$name = '.' . $name;
$css .= "{$name} {" . $styleWriter->write() . '}' . PHP_EOL;
}
}
}
$css .= '</style>' . PHP_EOL;
return $css;
}
/**
* Write footnote/endnote contents as textruns
*/
private function writeNotes()
{
$phpWord = $this->getPhpWord();
$content = PHP_EOL;
if (!empty($this->notes)) {
$content .= "<hr />" . PHP_EOL;
foreach ($this->notes as $noteId => $noteMark) {
list($noteType, $noteTypeId) = explode('-', $noteMark);
$method = 'get' . ($noteType == 'endnote' ? 'Endnotes' : 'Footnotes');
$collection = $phpWord->$method()->getItems();
if (array_key_exists($noteTypeId, $collection)) {
$element = $collection[$noteTypeId];
$noteAnchor = "<a name=\"note-{$noteId}\" />";
$noteAnchor .= "<a href=\"#{$noteMark}\" class=\"NoteRef\"><sup>{$noteId}</sup></a>";
$writer = new TextRunWriter($this, $element);
$writer->setOpeningText($noteAnchor);
$content .= $writer->write();
}
}
}
$content .= '<!DOCTYPE html>' . PHP_EOL;
$content .= '<!-- Generated by PHPWord -->' . PHP_EOL;
$content .= '<html>' . PHP_EOL;
$content .= $this->getWriterPart('Head')->write();
$content .= $this->getWriterPart('Body')->write();
$content .= '</html>' . PHP_EOL;
return $content;
}
@ -277,4 +122,16 @@ class HTML extends AbstractWriter implements WriterInterface
{
$this->notes[$noteId] = $noteMark;
}
/**
* Write document
*
* @return string
* @deprecated 0.11.0
* @codeCoverageIgnore
*/
public function writeDocument()
{
return $this->getContent();
}
}

View File

@ -18,7 +18,6 @@
namespace PhpOffice\PhpWord\Writer\HTML\Element;
use PhpOffice\PhpWord\Element\Image as ImageElement;
use PhpOffice\PhpWord\Shared\ZipArchive;
use PhpOffice\PhpWord\Writer\HTML\Style\Image as ImageStyleWriter;
/**
@ -43,10 +42,11 @@ class Image extends Text
$content = '';
if (!$parentWriter->isPdf()) {
$imageData = $this->getBase64ImageData($this->element);
if (!is_null($imageData)) {
$imageData = $this->element->getImageStringData(true);
if ($imageData !== null) {
$styleWriter = new ImageStyleWriter($this->element->getStyle());
$style = $styleWriter->write();
$imageData = 'data:' . $this->element->getImageType() . ';base64,' . $imageData;
$content .= $this->writeOpening();
$content .= "<img border=\"0\" style=\"{$style}\" src=\"{$imageData}\"/>";
@ -56,60 +56,4 @@ class Image extends Text
return $content;
}
/**
* Get Base64 image data
*
* @param \PhpOffice\PhpWord\Element\Image $element
* @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);
$zip = new ZipArchive();
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;
}
}

View File

@ -0,0 +1,68 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\HTML\Part;
use PhpOffice\PhpWord\Exception\Exception;
use PhpOffice\PhpWord\Writer\AbstractWriter;
/**
* Abstract HTML part writer
*
* @since 0.11.0
*/
abstract class AbstractPart
{
/**
* Parent writer
*
* @var \PhpOffice\PhpWord\Writer\AbstractWriter
*/
private $parentWriter;
/**
* Write part
*
* @return string
*/
abstract public function write();
/**
* Set parent writer
*
* @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer
*/
public function setParentWriter(AbstractWriter $writer = null)
{
$this->parentWriter = $writer;
}
/**
* Get parent writer
*
* @return \PhpOffice\PhpWord\Writer\AbstractWriter
* @throws \PhpOffice\PhpWord\Exception\Exception
*/
public function getParentWriter()
{
if ($this->parentWriter !== null) {
return $this->parentWriter;
} else {
throw new Exception('No parent WriterInterface assigned.');
}
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\HTML\Part;
use PhpOffice\PhpWord\Writer\HTML\Element\Container;
use PhpOffice\PhpWord\Writer\HTML\Element\TextRun as TextRunWriter;
/**
* RTF body part writer
*
* @since 0.11.0
*/
class Body extends AbstractPart
{
/**
* Write part
*
* @return string
*/
public function write()
{
$phpWord = $this->getParentWriter()->getPhpWord();
$content = '';
$content .= '<body>' . PHP_EOL;
$sections = $phpWord->getSections();
foreach ($sections as $section) {
$writer = new Container($this->getParentWriter(), $section);
$content .= $writer->write();
}
$content .= $this->writeNotes();
$content .= '</body>' . PHP_EOL;
return $content;
}
/**
* Write footnote/endnote contents as textruns
*
* @return string
*/
private function writeNotes()
{
/** @var \PhpOffice\PhpWord\Writer\HTML $parentWriter Type hint */
$parentWriter = $this->getParentWriter();
$phpWord = $parentWriter->getPhpWord();
$notes = $parentWriter->getNotes();
$content = '';
if (!empty($notes)) {
$content .= "<hr />" . PHP_EOL;
foreach ($notes as $noteId => $noteMark) {
list($noteType, $noteTypeId) = explode('-', $noteMark);
$method = 'get' . ($noteType == 'endnote' ? 'Endnotes' : 'Footnotes');
$collection = $phpWord->$method()->getItems();
if (array_key_exists($noteTypeId, $collection)) {
$element = $collection[$noteTypeId];
$noteAnchor = "<a name=\"note-{$noteId}\" />";
$noteAnchor .= "<a href=\"#{$noteMark}\" class=\"NoteRef\"><sup>{$noteId}</sup></a>";
$writer = new TextRunWriter($this->getParentWriter(), $element);
$writer->setOpeningText($noteAnchor);
$content .= $writer->write();
}
}
}
return $content;
}
}

View File

@ -0,0 +1,128 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\HTML\Part;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\Paragraph;
use PhpOffice\PhpWord\Writer\HTML\Style\Font as FontStyleWriter;
use PhpOffice\PhpWord\Writer\HTML\Style\Generic as GenericStyleWriter;
use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph as ParagraphStyleWriter;
/**
* RTF head part writer
*
* @since 0.11.0
*/
class Head extends AbstractPart
{
/**
* Write part
*
* @return string
*/
public function write()
{
$docProps = $this->getParentWriter()->getPhpWord()->getDocumentProperties();
$propertiesMapping = array(
'creator' => 'author',
'title' => '',
'description' => '',
'subject' => '',
'keywords' => '',
'category' => '',
'company' => '',
'manager' => ''
);
$title = $docProps->getTitle();
$title = ($title != '') ? $title : 'PHPWord';
$content = '';
$content .= '<head>' . PHP_EOL;
$content .= '<meta charset="UTF-8" />' . PHP_EOL;
$content .= '<title>' . htmlspecialchars($title) . '</title>' . PHP_EOL;
foreach ($propertiesMapping as $key => $value) {
$value = ($value == '') ? $key : $value;
$method = "get" . $key;
if ($docProps->$method() != '') {
$content .= '<meta name="' . $value . '" content="' .
htmlspecialchars($docProps->$method()) . '" />' . PHP_EOL;
}
}
$content .= $this->writeStyles();
$content .= '</head>' . PHP_EOL;
return $content;
}
/**
* Get styles
*
* @return string
*/
private function writeStyles()
{
$css = '<style>' . PHP_EOL;
// Default styles
$defaultStyles = array(
'*' => array(
'font-family' => Settings::getDefaultFontName(),
'font-size' => Settings::getDefaultFontSize() . 'pt',
),
'a.NoteRef' => array(
'text-decoration' => 'none',
),
'hr' => array(
'height' => '1px',
'padding' => '0',
'margin' => '1em 0',
'border' => '0',
'border-top' => '1px solid #CCC',
),
);
foreach ($defaultStyles as $selector => $style) {
$styleWriter = new GenericStyleWriter($style);
$css .= $selector . ' {' . $styleWriter->write() . '}' . PHP_EOL;
}
// Custom styles
$customStyles = Style::getStyles();
if (is_array($customStyles)) {
foreach ($customStyles as $name => $style) {
if ($style instanceof Font) {
$styleWriter = new FontStyleWriter($style);
if ($style->getStyleType() == 'title') {
$name = str_replace('Heading_', 'h', $name);
} else {
$name = '.' . $name;
}
$css .= "{$name} {" . $styleWriter->write() . '}' . PHP_EOL;
} elseif ($style instanceof Paragraph) {
$styleWriter = new ParagraphStyleWriter($style);
$name = '.' . $name;
$css .= "{$name} {" . $styleWriter->write() . '}' . PHP_EOL;
}
}
}
$css .= '</style>' . PHP_EOL;
return $css;
}
}

View File

@ -28,6 +28,11 @@ use PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart as Word2007AbstractPart;
*/
abstract class AbstractPart extends Word2007AbstractPart
{
/**
* @var string Date format
*/
protected $dateFormat = 'Y-m-d\TH:i:s.000';
/**
* Write common root attributes
*/

View File

@ -115,12 +115,14 @@ class Content extends AbstractPart
$xmlWriter->startElement('office:automatic-styles');
$this->writeTextStyles($xmlWriter);
foreach ($this->autoStyles as $element => $style) {
foreach ($this->autoStyles as $element => $styles) {
$writerClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Style\\' . $element;
foreach ($styles as $style) {
/** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */
$styleWriter = new $writerClass($xmlWriter, $style);
$styleWriter->write();
/** @var \PhpOffice\PhpWord\Writer\ODText\Style\AbstractStyle $styleWriter Type hint */
$styleWriter = new $writerClass($xmlWriter, $style);
$styleWriter->write();
}
}
$xmlWriter->endElement(); // office:automatic-styles

View File

@ -53,12 +53,12 @@ class Meta extends AbstractPart
$xmlWriter->writeElement('dc:subject', $docProps->getSubject());
$xmlWriter->writeElement('dc:description', $docProps->getDescription());
$xmlWriter->writeElement('dc:creator', $docProps->getLastModifiedBy());
$xmlWriter->writeElement('dc:date', gmdate('Y-m-d\TH:i:s.000', $docProps->getModified()));
$xmlWriter->writeElement('dc:date', gmdate($this->dateFormat, $docProps->getModified()));
// Extended properties
$xmlWriter->writeElement('meta:generator', 'PHPWord');
$xmlWriter->writeElement('meta:initial-creator', $docProps->getCreator());
$xmlWriter->writeElement('meta:creation-date', gmdate('Y-m-d\TH:i:s.000', $docProps->getCreated()));
$xmlWriter->writeElement('meta:creation-date', gmdate($this->dateFormat, $docProps->getCreated()));
$xmlWriter->writeElement('meta:keyword', $docProps->getKeywords());
// Category, company, and manager are put in meta namespace

View File

@ -65,13 +65,13 @@ class PDF
* @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
* @throws \PhpOffice\PhpWord\Exception\Exception
*/
public function __call($name, $arguments)
{
if ($this->renderer === null) {
throw new Exception("PDF Rendering library has not been defined.");
}
// Note: Commented because all exceptions should already be catched by `__construct`
// if ($this->renderer === null) {
// throw new Exception("PDF Rendering library has not been defined.");
// }
return call_user_func_array(array($this->renderer, $name), $arguments);
}

View File

@ -84,6 +84,7 @@ abstract class AbstractRenderer extends HTML
parent::__construct($phpWord);
$includeFile = Settings::getPdfRendererPath() . '/' . $this->includeFile;
if (file_exists($includeFile)) {
/** @noinspection PhpIncludeInspection Dynamic includes */
require_once $includeFile;
} else {
throw new Exception('Unable to load PDF Rendering library');

View File

@ -50,7 +50,7 @@ class DomPDF extends AbstractRenderer implements WriterInterface
// Create PDF
$pdf = new \DOMPDF();
$pdf->set_paper(strtolower($paperSize), $orientation);
$pdf->load_html($this->writeDocument());
$pdf->load_html($this->getContent());
$pdf->render();
// Write to file

View File

@ -61,7 +61,7 @@ class MPDF extends AbstractRenderer implements WriterInterface
$pdf->setKeywords($docProps->getKeywords());
$pdf->setCreator($docProps->getCreator());
$pdf->writeHTML($this->writeDocument());
$pdf->writeHTML($this->getContent());
// Write to file
fwrite($fileHandle, $pdf->output($filename, 'S'));

View File

@ -54,7 +54,7 @@ class TCPDF extends AbstractRenderer implements WriterInterface
$pdf->setPrintFooter(false);
$pdf->addPage();
$pdf->setFont($this->getFont());
$pdf->writeHTML($this->writeDocument());
$pdf->writeHTML($this->getContent());
// Write document properties
$phpWord = $this->getPhpWord();

View File

@ -17,13 +17,7 @@
namespace PhpOffice\PhpWord\Writer;
use PhpOffice\PhpWord\Exception\Exception;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\Drawing;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Writer\RTF\Element\Container;
/**
* RTF writer
@ -32,20 +26,6 @@ use PhpOffice\PhpWord\Writer\RTF\Element\Container;
*/
class RTF extends AbstractWriter implements WriterInterface
{
/**
* Color register
*
* @var array
*/
private $colorTable;
/**
* Font register
*
* @var array
*/
private $fontTable;
/**
* Last paragraph style
*
@ -54,39 +34,55 @@ class RTF extends AbstractWriter implements WriterInterface
private $lastParagraphStyle;
/**
* Create new RTF writer
* Create new instance
*
* @param \PhpOffice\PhpWord\PhpWord $phpWord
*/
public function __construct(PhpWord $phpWord = null)
{
$this->setPhpWord($phpWord);
$this->parts = array('Header', 'Document');
foreach ($this->parts as $partName) {
$partClass = get_class($this) . '\\Part\\' . $partName;
if (class_exists($partClass)) {
/** @var \PhpOffice\PhpWord\Writer\RTF\Part\AbstractPart $part Type hint */
$part = new $partClass();
$part->setParentWriter($this);
$this->writerParts[strtolower($partName)] = $part;
}
}
}
/**
* Save PhpWord to file
* Save content to file
*
* @param string $filename
* @throws \PhpOffice\PhpWord\Exception\Exception
*/
public function save($filename = null)
{
$filename = $this->getTempFile($filename);
$hFile = fopen($filename, 'w');
if ($hFile !== false) {
fwrite($hFile, $this->writeDocument());
fclose($hFile);
} else {
throw new Exception("Can't open file");
}
$this->cleanupTempFile();
$fileHandle = $this->openFile($filename);
$this->writeFile($fileHandle, $this->getContent());
}
/**
* Get color table
* Get content
*
* @return string
* @since 0.11.0
*/
public function getColorTable()
private function getContent()
{
return $this->colorTable;
$content = '';
$content .= '{';
$content .= '\rtf1' . PHP_EOL;
$content .= $this->getWriterPart('Header')->write();
$content .= $this->getWriterPart('Document')->write();
$content .= '}';
return $content;
}
/**
@ -94,7 +90,15 @@ class RTF extends AbstractWriter implements WriterInterface
*/
public function getFontTable()
{
return $this->fontTable;
return $this->getWriterPart('Header')->getFontTable();
}
/**
* Get color table
*/
public function getColorTable()
{
return $this->getWriterPart('Header')->getColorTable();
}
/**
@ -114,172 +118,4 @@ class RTF extends AbstractWriter implements WriterInterface
{
$this->lastParagraphStyle = $value;
}
/**
* Get all data
*
* @return string
*/
private function writeDocument()
{
$this->fontTable = $this->populateFontTable();
$this->colorTable = $this->populateColorTable();
// Set the default character set
$content = '{\rtf1';
$content .= '\ansi\ansicpg1252'; // Set the default font (the first one)
$content .= '\deff0'; // Set the default tab size (720 twips)
$content .= '\deftab720';
$content .= PHP_EOL;
// Set the font tbl group
$content .= '{\fonttbl';
foreach ($this->fontTable as $idx => $font) {
$content .= '{\f' . $idx . '\fnil\fcharset0 ' . $font . ';}';
}
$content .= '}' . PHP_EOL;
// Set the color tbl group
$content .= '{\colortbl ';
foreach ($this->colorTable as $color) {
$arrColor = Drawing::htmlToRGB($color);
$content .= ';\red' . $arrColor[0] . '\green' . $arrColor[1] . '\blue' . $arrColor[2] . '';
}
$content .= ';}' . PHP_EOL;
$content .= '{\*\generator PhpWord;}' . PHP_EOL; // Set the generator
$content .= '\viewkind4'; // Set the view mode of the document
$content .= '\uc1'; // Set the numberof bytes that follows a unicode character
$content .= '\pard'; // Resets to default paragraph properties.
$content .= '\nowidctlpar'; // No widow/orphan control
$content .= '\lang1036'; // Applies a language to a text run (1036 : French (France))
$content .= '\kerning1'; // Point size (in half-points) above which to kern character pairs
$content .= '\fs' . (Settings::getDefaultFontSize() * 2); // Set the font size in half-points
$content .= PHP_EOL;
// Body
$content .= $this->writeContent();
$content .= '}';
return $content;
}
/**
* Get content data
*
* @return string
*/
private function writeContent()
{
$content = '';
$sections = $this->getPhpWord()->getSections();
foreach ($sections as $section) {
$writer = new Container($this, $section);
$content .= $writer->write();
}
return $content;
}
/**
* Get all fonts
*
* @return array
*/
private function populateFontTable()
{
$phpWord = $this->getPhpWord();
$fontTable = array();
$fontTable[] = Settings::getDefaultFontName();
// Browse styles
$styles = Style::getStyles();
if (count($styles) > 0) {
foreach ($styles as $style) {
// Font
if ($style instanceof Font) {
if (in_array($style->getName(), $fontTable) == false) {
$fontTable[] = $style->getName();
}
}
}
}
// Search all fonts used
$sections = $phpWord->getSections();
$countSections = count($sections);
if ($countSections > 0) {
foreach ($sections as $section) {
$elements = $section->getElements();
foreach ($elements as $element) {
if (method_exists($element, 'getFontStyle')) {
$fontStyle = $element->getFontStyle();
if ($fontStyle instanceof Font) {
if (in_array($fontStyle->getName(), $fontTable) == false) {
$fontTable[] = $fontStyle->getName();
}
}
}
}
}
}
return $fontTable;
}
/**
* Get all colors
*
* @return array
*/
private function populateColorTable()
{
$phpWord = $this->getPhpWord();
$defaultFontColor = Settings::DEFAULT_FONT_COLOR;
$colorTable = array();
// Browse styles
$styles = Style::getStyles();
if (count($styles) > 0) {
foreach ($styles as $style) {
// Font
if ($style instanceof Font) {
$color = $style->getColor();
$fgcolor = $style->getFgColor();
if (!in_array($color, $colorTable) && $color != $defaultFontColor && !empty($color)) {
$colorTable[] = $color;
}
if (!in_array($fgcolor, $colorTable) && $fgcolor != $defaultFontColor && !empty($fgcolor)) {
$colorTable[] = $fgcolor;
}
}
}
}
// Search all fonts used
$sections = $phpWord->getSections();
$countSections = count($sections);
if ($countSections > 0) {
foreach ($sections as $section) {
$elements = $section->getElements();
foreach ($elements as $element) {
if (method_exists($element, 'getFontStyle')) {
$fontStyle = $element->getFontStyle();
if ($fontStyle instanceof Font) {
if (in_array($fontStyle->getColor(), $colorTable) == false) {
$colorTable[] = $fontStyle->getColor();
}
if (in_array($fontStyle->getFgColor(), $colorTable) == false) {
$colorTable[] = $fontStyle->getFgColor();
}
}
}
}
}
}
return $colorTable;
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\RTF\Element;
use PhpOffice\PhpWord\Element\Image as ImageElement;
use PhpOffice\PhpWord\Shared\Font;
/**
* Image element RTF writer
*
* @since 0.11.0
*/
class Image extends AbstractElement
{
/**
* Write element
*
* @return string
*/
public function write()
{
if (!$this->element instanceof ImageElement) {
return '';
}
$this->getStyles();
$style = $this->element->getStyle();
$content = '';
$content .= $this->writeOpening();
$content .= '{\*\shppict {\pict';
$content .= '\pngblip\picscalex100\picscaley100';
$content .= '\picwgoal' . round(Font::pixelSizeToTwips($style->getWidth()));
$content .= '\pichgoal' . round(Font::pixelSizeToTwips($style->getHeight()));
$content .= PHP_EOL;
$content .= $this->element->getImageStringData();
$content .= '}}';
$content .= $this->writeClosing();
return $content;
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\RTF\Part;
use PhpOffice\PhpWord\Writer\HTML\Part\AbstractPart as HTMLAbstractPart;
/**
* Abstract RTF part writer
*
* @since 0.11.0
*/
abstract class AbstractPart extends HTMLAbstractPart
{
}

View File

@ -0,0 +1,142 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\RTF\Part;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Writer\RTF\Element\Container;
/**
* RTF document part writer
*
* @since 0.11.0
*/
class Document extends AbstractPart
{
/**
* Write part
*
* @return string
*/
public function write()
{
$content = '';
$content .= $this->writeInfo();
$content .= $this->writeFormatting();
$content .= $this->writeSections();
return $content;
}
/**
* Write document information
*
* @return string
*/
private function writeInfo()
{
$docProps = $this->getParentWriter()->getPhpWord()->getDocumentProperties();
$properties = array('title', 'subject', 'category', 'keywords', 'comment',
'author', 'operator', 'creatim', 'revtim', 'company', 'manager');
$mapping = array('comment' => 'description', 'author' => 'creator', 'operator' => 'lastModifiedBy',
'creatim' => 'created', 'revtim' => 'modified');
$dateFields = array('creatim', 'revtim');
$content = '';
$content .= '{';
$content .= '\info';
foreach ($properties as $property) {
$method = 'get' . (array_key_exists($property, $mapping) ? $mapping[$property] : $property);
$value = $docProps->$method();
$value = in_array($property, $dateFields) ? $this->getDateValue($value) : $value;
$content .= "{\\{$property} {$value}}";
}
$content .= '}';
$content .= PHP_EOL;
return $content;
}
/**
* Write document formatting properties
*
* @return string
*/
private function writeFormatting()
{
$content = '';
$content .= '\deftab720'; // Set the default tab size (720 twips)
$content .= '\viewkind1'; // Set the view mode of the document
$content .= '\uc1'; // Set the numberof bytes that follows a unicode character
$content .= '\pard'; // Resets to default paragraph properties.
$content .= '\nowidctlpar'; // No widow/orphan control
$content .= '\lang1036'; // Applies a language to a text run (1036 : French (France))
$content .= '\kerning1'; // Point size (in half-points) above which to kern character pairs
$content .= '\fs' . (Settings::getDefaultFontSize() * 2); // Set the font size in half-points
$content .= PHP_EOL;
return $content;
}
/**
* Write sections
*
* @return string
*/
private function writeSections()
{
$content = '';
$sections = $this->getParentWriter()->getPhpWord()->getSections();
foreach ($sections as $section) {
$writer = new Container($this->getParentWriter(), $section);
$content .= $writer->write();
}
return $content;
}
/**
* Get date value
*
* The format of date value is `\yr?\mo?\dy?\hr?\min?\sec?`
*
* @param int $value
* @return string
*/
private function getDateValue($value)
{
$dateParts = array(
'Y' => 'yr',
'm' => 'mo',
'd' => 'dy',
'H' => 'hr',
'i' => 'min',
's' => 'sec',
);
$result = '';
foreach ($dateParts as $dateFormat => $controlWord) {
$result .= '\\' . $controlWord . date($dateFormat, $value);
}
return $result;
}
}

View File

@ -0,0 +1,227 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\RTF\Part;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\Drawing;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Style\Font;
/**
* RTF header part writer
*
* @since 0.11.0
*/
class Header extends AbstractPart
{
/**
* Font table
*
* @var array
*/
private $fontTable = array();
/**
* Color table
*
* @var array
*/
private $colorTable = array();
/**
* Get font table
*/
public function getFontTable()
{
return $this->fontTable;
}
/**
* Get color table
*/
public function getColorTable()
{
return $this->colorTable;
}
/**
* Write part
*
* @return string
*/
public function write()
{
$this->registerFont();
$content = '';
$content .= $this->writeCharset();
$content .= $this->writeDefaults();
$content .= $this->writeFontTable();
$content .= $this->writeColorTable();
$content .= $this->writeGenerator();
$content .= PHP_EOL;
return $content;
}
/**
* Write character set
*
* @return string
*/
private function writeCharset()
{
$content = '';
$content .= '\ansi';
$content .= '\ansicpg1252';
$content .= PHP_EOL;
return $content;
}
/**
* Write header defaults
*
* @return string
*/
private function writeDefaults()
{
$content = '';
$content .= '\deff0';
$content .= PHP_EOL;
return $content;
}
/**
* Write font table
*
* @return string
*/
private function writeFontTable()
{
$content = '';
$content .= '{';
$content .= '\fonttbl';
foreach ($this->fontTable as $index => $font) {
$content .= "{\\f{$index}\\fnil\\fcharset0{$font};}";
}
$content .= '}';
$content .= PHP_EOL;
return $content;
}
/**
* Write color table
*
* @return string
*/
private function writeColorTable()
{
$content = '';
$content .= '{';
$content .= '\colortbl';
foreach ($this->colorTable as $color) {
list($red, $green, $blue) = Drawing::htmlToRGB($color);
$content .= ";\\red{$red}\\green{$green}\\blue{$blue}";
}
$content .= '}';
$content .= PHP_EOL;
return $content;
}
/**
* Write
*
* @return string
*/
private function writeGenerator()
{
$content = '';
$content .= '{\*\generator PhpWord;}'; // Set the generator
$content .= PHP_EOL;
return $content;
}
/**
* Register all fonts and colors in both named and inline styles to appropriate header table
*/
private function registerFont()
{
$phpWord = $this->getParentWriter()->getPhpWord();
$this->fontTable[] = Settings::getDefaultFontName();
// Search named styles
$styles = Style::getStyles();
foreach ($styles as $style) {
$this->registerFontItems($style);
}
// Search inline styles
$sections = $phpWord->getSections();
foreach ($sections as $section) {
$elements = $section->getElements();
foreach ($elements as $element) {
if (method_exists($element, 'getFontStyle')) {
$style = $element->getFontStyle();
$this->registerFontItems($style);
}
}
}
}
/**
* Register fonts and colors
*
* @param \PhpOffice\PhpWord\Style\AbstractStyle $style
*/
private function registerFontItems($style)
{
$defaultFont = Settings::getDefaultFontName();
$defaultColor = Settings::DEFAULT_FONT_COLOR;
if ($style instanceof Font) {
$this->registerFontItem($this->fontTable, $style->getName(), $defaultFont);
$this->registerFontItem($this->colorTable, $style->getColor(), $defaultColor);
$this->registerFontItem($this->colorTable, $style->getFgColor(), $defaultColor);
}
}
/**
* Register individual font and color
*
* @param array $table
* @param string $value
* @param string $default
*/
private function registerFontItem(&$table, $value, $default)
{
if (in_array($value, $table) === false && $value !== null && $value != $default) {
$table[] = $value;
}
}
}

View File

@ -53,23 +53,24 @@ class Word2007 extends AbstractWriter implements WriterInterface
// Create parts
$this->parts = array(
'ContentTypes' => '[Content_Types].xml',
'Rels' => '_rels/.rels',
'DocPropsApp' => 'docProps/app.xml',
'DocPropsCore' => 'docProps/core.xml',
'RelsDocument' => 'word/_rels/document.xml.rels',
'Document' => 'word/document.xml',
'Styles' => 'word/styles.xml',
'Numbering' => 'word/numbering.xml',
'Settings' => 'word/settings.xml',
'WebSettings' => 'word/webSettings.xml',
'FontTable' => 'word/fontTable.xml',
'Theme' => 'word/theme/theme1.xml',
'RelsPart' => '',
'Header' => '',
'Footer' => '',
'Footnotes' => '',
'Endnotes' => '',
'ContentTypes' => '[Content_Types].xml',
'Rels' => '_rels/.rels',
'DocPropsApp' => 'docProps/app.xml',
'DocPropsCore' => 'docProps/core.xml',
'DocPropsCustom' => 'docProps/custom.xml',
'RelsDocument' => 'word/_rels/document.xml.rels',
'Document' => 'word/document.xml',
'Styles' => 'word/styles.xml',
'Numbering' => 'word/numbering.xml',
'Settings' => 'word/settings.xml',
'WebSettings' => 'word/webSettings.xml',
'FontTable' => 'word/fontTable.xml',
'Theme' => 'word/theme/theme1.xml',
'RelsPart' => '',
'Header' => '',
'Footer' => '',
'Footnotes' => '',
'Endnotes' => '',
);
foreach (array_keys($this->parts) as $partName) {
$partClass = get_class($this) . '\\Part\\' . $partName;

View File

@ -17,8 +17,10 @@
namespace PhpOffice\PhpWord\Writer\Word2007\Element;
use PhpOffice\PhpWord\Element\AbstractElement as Element;
use PhpOffice\PhpWord\Element\AbstractContainer as ContainerElement;
use PhpOffice\PhpWord\Element\TextBreak as TextBreakElement;
use PhpOffice\PhpWord\Shared\XMLWriter;
/**
* Container element writer (section, textrun, header, footnote, cell, etc.)
@ -51,36 +53,52 @@ class Container extends AbstractElement
$elements = $container->getElements();
$elementClass = '';
foreach ($elements as $element) {
$elementClass = substr(get_class($element), strrpos(get_class($element), '\\') + 1);
$writerClass = $this->namespace . '\\' . $elementClass;
// Check it's a page break. No need to write it, instead, flag containers' pageBreakBefore
// to be assigned to the next element
if ($elementClass == 'PageBreak') {
$this->setPageBreakBefore(true);
continue;
}
if (class_exists($writerClass)) {
// Get container's page break before and reset it
$pageBreakBefore = $this->hasPageBreakBefore();
$this->setPageBreakBefore(false);
/** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */
$writer = new $writerClass($xmlWriter, $element, $withoutP);
$writer->setPageBreakBefore($pageBreakBefore);
$writer->write();
}
$elementClass = $this->writeElement($xmlWriter, $element, $withoutP);
}
// Special case for Cell: They have to contain a w:p element at the end. The $elementClass contains
// the last element name. If it's empty string or Table, the last element is not w:p
if ($containerClass == 'Cell') {
if ($elementClass == '' || $elementClass == 'Table') {
$writerClass = $this->namespace . '\\TextBreak';
/** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */
$writer = new $writerClass($xmlWriter, new TextBreakElement(), $withoutP);
$writer->write();
}
// Special case for Cell: They have to contain a w:p element at the end.
// The $elementClass contains the last element name. If it's empty string
// or Table, the last element is not w:p
$writeLastTextBreak = ($containerClass == 'Cell') && ($elementClass == '' || $elementClass == 'Table');
if ($writeLastTextBreak) {
$writerClass = $this->namespace . '\\TextBreak';
/** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */
$writer = new $writerClass($xmlWriter, new TextBreakElement(), $withoutP);
$writer->write();
}
}
/**
* Write individual element
*
* @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param \PhpOffice\PhpWord\Element\AbstractElement $element
* @param bool $withoutP
* @return string
*/
private function writeElement(XMLWriter $xmlWriter, Element $element, $withoutP)
{
$elementClass = substr(get_class($element), strrpos(get_class($element), '\\') + 1);
$writerClass = $this->namespace . '\\' . $elementClass;
// Check it's a page break. No need to write it, instead, flag containers'
// pageBreakBefore to be assigned to the next element
if ($elementClass == 'PageBreak') {
$this->setPageBreakBefore(true);
return $elementClass;
}
if (class_exists($writerClass)) {
// Get container's page break before and reset it
$pageBreakBefore = $this->hasPageBreakBefore();
$this->setPageBreakBefore(false);
/** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */
$writer = new $writerClass($xmlWriter, $element, $withoutP);
$writer->setPageBreakBefore($pageBreakBefore);
$writer->write();
}
return $elementClass;
}
}

View File

@ -37,15 +37,13 @@ class TextBreak extends Text
if (!$this->withoutP) {
$hasStyle = $element->hasStyle();
$this->writeOpeningWP();
if ($hasStyle) {
$this->writeOpeningWP();
$xmlWriter->startElement('w:pPr');
$this->writeFontStyle();
$xmlWriter->endElement(); // w:pPr
$this->writeClosingWP();
} else {
$xmlWriter->writeElement('w:p');
}
$this->writeClosingWP();
} else {
$xmlWriter->writeElement('w:br');
}

View File

@ -33,6 +33,11 @@ abstract class AbstractPart
*/
protected $parentWriter;
/**
* @var string Date format
*/
protected $dateFormat = 'Y-m-d\TH:i:sP';
/**
* Write part
*

View File

@ -40,6 +40,7 @@ class ContentTypes extends AbstractPart
$overrides = array(
'/docProps/core.xml' => $openXMLPrefix . 'package.core-properties+xml',
'/docProps/app.xml' => $openXMLPrefix . 'officedocument.extended-properties+xml',
'/docProps/custom.xml' => $openXMLPrefix . 'officedocument.custom-properties+xml',
'/word/document.xml' => $wordMLPrefix . 'document.main+xml',
'/word/styles.xml' => $wordMLPrefix . 'styles+xml',
'/word/numbering.xml' => $wordMLPrefix . 'numbering+xml',

View File

@ -54,13 +54,13 @@ class DocPropsCore extends AbstractPart
// dcterms:created
$xmlWriter->startElement('dcterms:created');
$xmlWriter->writeAttribute('xsi:type', 'dcterms:W3CDTF');
$xmlWriter->writeRaw(date(DATE_W3C, $phpWord->getDocumentProperties()->getCreated()));
$xmlWriter->writeRaw(date($this->dateFormat, $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->writeRaw(date($this->dateFormat, $phpWord->getDocumentProperties()->getModified()));
$xmlWriter->endElement();
$xmlWriter->endElement(); // cp:coreProperties

View File

@ -0,0 +1,78 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\Word2007\Part;
/**
* Word2007 custom document properties part writer: docProps/custom.xml
*
* @since 0.11.0
*/
class DocPropsCustom extends AbstractPart
{
/**
* Write part
*
* @return string
*/
public function write()
{
$phpWord = $this->getParentWriter()->getPhpWord();
$xmlWriter = $this->getXmlWriter();
$xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
$xmlWriter->startElement('Properties');
$xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/officeDocument/2006/custom-properties');
$xmlWriter->writeAttribute('xmlns:vt', 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes');
$docProps = $phpWord->getDocumentProperties();
$properties = $docProps->getCustomProperties();
foreach ($properties as $key => $property) {
$propertyValue = $docProps->getCustomPropertyValue($property);
$propertyType = $docProps->getCustomPropertyType($property);
$xmlWriter->startElement('property');
$xmlWriter->writeAttribute('fmtid', '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}');
$xmlWriter->writeAttribute('pid', $key + 2);
$xmlWriter->writeAttribute('name', $property);
switch ($propertyType) {
case 'i':
$xmlWriter->writeElement('vt:i4', $propertyValue);
break;
case 'f':
$xmlWriter->writeElement('vt:r8', $propertyValue);
break;
case 'b':
$xmlWriter->writeElement('vt:bool', ($propertyValue) ? 'true' : 'false');
break;
case 'd':
$xmlWriter->startElement('vt:filetime');
$xmlWriter->writeRaw(date($this->dateFormat, $propertyValue));
$xmlWriter->endElement();
break;
default:
$xmlWriter->writeElement('vt:lpwstr', $propertyValue);
break;
}
$xmlWriter->endElement(); // property
}
$xmlWriter->endElement(); // Properties
return $xmlWriter->getData();
}
}

View File

@ -24,6 +24,8 @@ use PhpOffice\PhpWord\Style\NumberingLevel;
/**
* Word2007 numbering part writer: word/numbering.xml
*
* @since 0.10.0
*/
class Numbering extends AbstractPart
{
@ -97,12 +99,6 @@ class Numbering extends AbstractPart
*/
private function writeLevel(XMLWriter $xmlWriter, NumberingLevel $level)
{
$tabPos = $level->getTabPos();
$left = $level->getLeft();
$hanging = $level->getHanging();
$font = $level->getFont();
$hint = $level->getHint();
$xmlWriter->startElement('w:lvl');
$xmlWriter->writeAttribute('w:ilvl', $level->getLevel());
@ -124,48 +120,63 @@ class Numbering extends AbstractPart
}
}
// Paragraph styles
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
}
// Paragraph & font styles
$this->writeParagraph($xmlWriter, $level);
$this->writeFont($xmlWriter, $level);
// Font styles
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
}
/**
* Write level paragraph
*
* @since 0.11.0
* @todo Use paragraph style writer
*/
private function writeParagraph(XMLWriter $xmlWriter, NumberingLevel $level)
{
$tabPos = $level->getTabPos();
$left = $level->getLeft();
$hanging = $level->getHanging();
$xmlWriter->startElement('w:pPr');
$xmlWriter->startElement('w:tabs');
$xmlWriter->startElement('w:tab');
$xmlWriter->writeAttribute('w:val', 'num');
$xmlWriter->writeAttributeIf($tabPos !== null, 'w:pos', $tabPos);
$xmlWriter->endElement(); // w:tab
$xmlWriter->endElement(); // w:tabs
$xmlWriter->startElement('w:ind');
$xmlWriter->writeAttributeIf($left !== null, 'w:left', $left);
$xmlWriter->writeAttributeIf($hanging !== null, 'w:hanging', $hanging);
$xmlWriter->endElement(); // w:ind
$xmlWriter->endElement(); // w:pPr
}
/**
* Write level font
*
* @since 0.11.0
* @todo Use font style writer
*/
private function writeFont(XMLWriter $xmlWriter, NumberingLevel $level)
{
$font = $level->getFont();
$hint = $level->getHint();
$xmlWriter->startElement('w:rPr');
$xmlWriter->startElement('w:rFonts');
$xmlWriter->writeAttributeIf($font !== null, 'w:ascii', $font);
$xmlWriter->writeAttributeIf($font !== null, 'w:hAnsi', $font);
$xmlWriter->writeAttributeIf($font !== null, 'w:cs', $font);
$xmlWriter->writeAttributeIf($hint !== null, 'w:hint', $hint);
$xmlWriter->endElement(); // w:rFonts
$xmlWriter->endElement(); // w:rPr
}
/**
* Get random hexadecimal number value
*

View File

@ -35,9 +35,10 @@ class Rels extends AbstractPart
public function write()
{
$xmlRels = array(
'docProps/core.xml' => 'package/2006/relationships/metadata/core-properties',
'docProps/app.xml' => 'officeDocument/2006/relationships/extended-properties',
'word/document.xml' => 'officeDocument/2006/relationships/officeDocument',
'docProps/core.xml' => 'package/2006/relationships/metadata/core-properties',
'docProps/app.xml' => 'officeDocument/2006/relationships/extended-properties',
'docProps/custom.xml' => 'officeDocument/2006/relationships/custom-properties',
'word/document.xml' => 'officeDocument/2006/relationships/officeDocument',
);
$xmlWriter = $this->getXmlWriter();
$this->writeRels($xmlWriter, $xmlRels);
@ -49,43 +50,51 @@ class Rels extends AbstractPart
* Write relationships
*
* @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param null|array $xmlRels
* @param null|array $mediaRels
* @param integer $relId
* @param array $xmlRels
* @param array $mediaRels
* @param int $relId
*/
protected function writeRels(XMLWriter $xmlWriter, $xmlRels = null, $mediaRels = null, $relId = 1)
protected function writeRels(XMLWriter $xmlWriter, $xmlRels = array(), $mediaRels = array(), $relId = 1)
{
$xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
$xmlWriter->startElement('Relationships');
$xmlWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
// XML files relationships
if (is_array($xmlRels)) {
foreach ($xmlRels as $target => $type) {
$this->writeRel($xmlWriter, $relId++, $type, $target);
}
foreach ($xmlRels as $target => $type) {
$this->writeRel($xmlWriter, $relId++, $type, $target);
}
// Media relationships
if (is_array($mediaRels)) {
$typePrefix = 'officeDocument/2006/relationships/';
$typeMapping = 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, $typeMapping) ? $typeMapping[$mediaType] : $mediaType;
$target = array_key_exists($mediaType, $targetPaths) ? $targetPaths[$mediaType] : '';
$target .= $mediaRel['target'];
$targetMode = ($type == 'hyperlink') ? 'External' : '';
$this->writeRel($xmlWriter, $relId++, $typePrefix . $type, $target, $targetMode);
}
foreach ($mediaRels as $mediaRel) {
$this->writeMediaRel($xmlWriter, $relId++, $mediaRel);
}
$xmlWriter->endElement(); // Relationships
}
/**
* Write media relationships
*
* @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param int $relId
* @param array $mediaRel
*/
private function writeMediaRel(XMLWriter $xmlWriter, $relId, $mediaRel)
{
$typePrefix = 'officeDocument/2006/relationships/';
$typeMapping = array('image' => 'image', 'object' => 'oleObject', 'link' => 'hyperlink');
$targetMapping = array('image' => 'media/', 'object' => 'embeddings/');
$mediaType = $mediaRel['type'];
$type = array_key_exists($mediaType, $typeMapping) ? $typeMapping[$mediaType] : $mediaType;
$targetPrefix = array_key_exists($mediaType, $targetMapping) ? $targetMapping[$mediaType] : '';
$target = $mediaRel['target'];
$targetMode = ($type == 'hyperlink') ? 'External' : '';
$this->writeRel($xmlWriter, $relId, $typePrefix . $type, $targetPrefix . $target, $targetMode);
}
/**
* Write individual rels entry
*

View File

@ -39,7 +39,7 @@ class RelsPart extends Rels
public function write()
{
$xmlWriter = $this->getXmlWriter();
$this->writeRels($xmlWriter, null, $this->media);
$this->writeRels($xmlWriter, array(), $this->media);
return $xmlWriter->getData();
}

View File

@ -20,9 +20,9 @@ namespace PhpOffice\PhpWord\Writer\Word2007\Part;
use PhpOffice\PhpWord\Settings as PhpWordSettings;
use PhpOffice\PhpWord\Shared\XMLWriter;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\Paragraph;
use PhpOffice\PhpWord\Style\Table;
use PhpOffice\PhpWord\Style\Font as FontStyle;
use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle;
use PhpOffice\PhpWord\Style\Table as TableStyle;
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;
@ -31,6 +31,7 @@ use PhpOffice\PhpWord\Writer\Word2007\Style\Table as TableStyleWriter;
* Word2007 styles part writer: word/styles.xml
*
* @todo Do something with the numbering style introduced in 0.10.0
* @SuppressWarnings(PHPMD.UnusedPrivateMethod) For writeFontStyle, writeParagraphStyle, and writeTableStyle
*/
class Styles extends AbstractPart
{
@ -59,88 +60,11 @@ class Styles extends AbstractPart
continue;
}
// Font style
if ($style instanceof Font) {
$paragraphStyle = $style->getParagraph();
$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];
$styleName = 'heading ' . $arrStyle[1];
$styleLink = 'Heading' . $arrStyle[1] . 'Char';
$xmlWriter->writeAttribute('w:styleId', $styleId);
$xmlWriter->startElement('w:link');
$xmlWriter->writeAttribute('w:val', $styleLink);
$xmlWriter->endElement();
}
$xmlWriter->startElement('w:name');
$xmlWriter->writeAttribute('w:val', $styleName);
$xmlWriter->endElement();
// Parent style
$xmlWriter->writeElementIf(!is_null($paragraphStyle), 'w:basedOn', 'w:val', 'Normal');
// w:pPr
if (!is_null($paragraphStyle)) {
$styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle);
$styleWriter->write();
}
// w:rPr
$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();
$xmlWriter->writeElementIf(!is_null($basedOn), 'w:basedOn', 'w:val', $basedOn);
// Next paragraph style
$next = $style->getNext();
$xmlWriter->writeElementIf(!is_null($next), 'w:next', 'w:val', $next);
// w:pPr
$styleWriter = new ParagraphStyleWriter($xmlWriter, $style);
$styleWriter->write();
$xmlWriter->endElement();
// 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();
$styleWriter = new TableStyleWriter($xmlWriter, $style);
$styleWriter->write();
$xmlWriter->endElement(); // w:style
// Get style class and execute if the private method exists
$styleClass = substr(get_class($style), strrpos(get_class($style), '\\') + 1);
$method = "write{$styleClass}Style";
if (method_exists($this, $method)) {
$this->$method($xmlWriter, $styleName, $style);
}
}
}
@ -213,4 +137,115 @@ class Styles extends AbstractPart
$xmlWriter->endElement(); // w:style
}
}
/**
* Write font style
*
* @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param string $styleName
* @param \PhpOffice\PhpWord\Style\Font $style
*/
private function writeFontStyle(XMLWriter $xmlWriter, $styleName, FontStyle $style)
{
$paragraphStyle = $style->getParagraph();
$styleType = $style->getStyleType();
$type = ($styleType == 'title') ? 'paragraph' : 'character';
if (!is_null($paragraphStyle)) {
$type = 'paragraph';
}
$xmlWriter->startElement('w:style');
$xmlWriter->writeAttribute('w:type', $type);
// Heading style
if ($styleType == 'title') {
$arrStyle = explode('_', $styleName);
$styleId = 'Heading' . $arrStyle[1];
$styleName = 'heading ' . $arrStyle[1];
$styleLink = 'Heading' . $arrStyle[1] . 'Char';
$xmlWriter->writeAttribute('w:styleId', $styleId);
$xmlWriter->startElement('w:link');
$xmlWriter->writeAttribute('w:val', $styleLink);
$xmlWriter->endElement();
}
// Style name
$xmlWriter->startElement('w:name');
$xmlWriter->writeAttribute('w:val', $styleName);
$xmlWriter->endElement();
// Parent style
$xmlWriter->writeElementIf(!is_null($paragraphStyle), 'w:basedOn', 'w:val', 'Normal');
// w:pPr
if (!is_null($paragraphStyle)) {
$styleWriter = new ParagraphStyleWriter($xmlWriter, $paragraphStyle);
$styleWriter->write();
}
// w:rPr
$styleWriter = new FontStyleWriter($xmlWriter, $style);
$styleWriter->write();
$xmlWriter->endElement();
}
/**
* Write paragraph style
*
* @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param string $styleName
* @param \PhpOffice\PhpWord\Style\Paragraph $style
*/
private function writeParagraphStyle(XMLWriter $xmlWriter, $styleName, ParagraphStyle $style)
{
$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();
$xmlWriter->writeElementIf(!is_null($basedOn), 'w:basedOn', 'w:val', $basedOn);
// Next paragraph style
$next = $style->getNext();
$xmlWriter->writeElementIf(!is_null($next), 'w:next', 'w:val', $next);
// w:pPr
$styleWriter = new ParagraphStyleWriter($xmlWriter, $style);
$styleWriter->write();
$xmlWriter->endElement();
}
/**
* Write table style
*
* @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param string $styleName
* @param \PhpOffice\PhpWord\Style\Table $style
*/
private function writeTableStyle(XMLWriter $xmlWriter, $styleName, TableStyle $style)
{
$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();
$styleWriter = new TableStyleWriter($xmlWriter, $style);
$styleWriter->write();
$xmlWriter->endElement(); // w:style
}
}

View File

@ -65,16 +65,11 @@ class Image extends AbstractStyle
// Absolute/relative positioning
$positioning = $style->getPositioning();
$styleArray['position'] = $positioning;
if ($positioning == ImageStyle::POSITION_ABSOLUTE) {
$styleArray['mso-position-horizontal-relative'] = 'page';
$styleArray['mso-position-vertical-relative'] = 'page';
} elseif ($positioning == ImageStyle::POSITION_RELATIVE) {
if ($positioning !== null) {
$styleArray['mso-position-horizontal'] = $style->getPosHorizontal();
$styleArray['mso-position-vertical'] = $style->getPosVertical();
$styleArray['mso-position-horizontal-relative'] = $style->getPosHorizontalRel();
$styleArray['mso-position-vertical-relative'] = $style->getPosVerticalRel();
$styleArray['margin-left'] = 0;
$styleArray['margin-top'] = 0;
}
// Wrapping style

View File

@ -29,7 +29,7 @@ class MarginBorder extends AbstractStyle
/**
* Sizes
*
* @var int[]
* @var integer[]
*/
private $sizes = array();
@ -103,7 +103,7 @@ class MarginBorder extends AbstractStyle
/**
* Set sizes
*
* @param int[] $value
* @param integer[] $value
*/
public function setSizes($value)
{

View File

@ -38,6 +38,7 @@ class ImageTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($oImage->getSource(), $src);
$this->assertEquals($oImage->getMediaId(), md5($src));
$this->assertEquals($oImage->isWatermark(), false);
$this->assertEquals($oImage->getSourceType(), Image::SOURCE_LOCAL);
$this->assertInstanceOf('PhpOffice\\PhpWord\\Style\\Image', $oImage->getStyle());
}

View File

@ -51,6 +51,17 @@ class ListItemRunTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($oListItemRun->getParagraphStyle(), 'pStyle');
}
/**
* New instance with string
*/
public function testConstructListString()
{
$oListItemRun = new ListItemRun(0, 'numberingStyle');
$this->assertInstanceOf('PhpOffice\\PhpWord\\Element\\ListItemRun', $oListItemRun);
$this->assertCount(0, $oListItemRun->getElements());
}
/**
* New instance with array
*/

View File

@ -73,7 +73,7 @@ class SectionTest extends \PHPUnit_Framework_TestCase
{
$expected = 'landscape';
$object = new Section(0);
$object->setSettings(array('orientation' => $expected));
$object->setSettings(array('orientation' => $expected, 'foo' => null));
$this->assertEquals($expected, $object->getSettings()->getOrientation());
}

View File

@ -103,6 +103,14 @@ class SettingsTest extends \PHPUnit_Framework_TestCase
'defaultFontName' => 'Arial',
'defaultFontSize' => 10,
);
// Test default value
$this->assertEquals($expected, Settings::loadConfig());
// Test with valid file
$this->assertEquals($expected, Settings::loadConfig(__DIR__ . '/../../../phpword.ini.dist'));
// Test with invalid file
$this->assertEmpty(Settings::loadConfig(__DIR__ . '/../../../phpunit.xml.dist'));
}
}

View File

@ -54,4 +54,14 @@ class StringTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('', String::controlCharacterPHP2OOXML(''));
$this->assertEquals('_x0008_', String::controlCharacterPHP2OOXML(chr(0x08)));
}
/**
* Test unicode conversion
*/
public function testToUnicode()
{
$this->assertEquals('a', String::toUnicode('a'));
$this->assertEquals('\uc0{\u8364}', String::toUnicode('€'));
$this->assertEquals('\uc0{\u233}', String::toUnicode('é'));
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Tests\Shared;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\XMLWriter;
/**
* Test class for PhpOffice\PhpWord\Shared\XMLWriter
*/
class XMLWriterTest extends \PHPUnit_Framework_TestCase
{
/**
* Test method exception
*
* @expectedException \BadMethodCallException
* @expectedExceptionMessage Method 'foo' does not exists.
*/
public function testCallException()
{
Settings::setCompatibility(false);
$object = new XMLWriter();
$object->foo();
}
}

View File

@ -45,6 +45,7 @@ class AbstractStyleTest extends \PHPUnit_Framework_TestCase
$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(871.1, self::callProtectedMethod($stub, 'setFloatVal', array('871.1', 2.1)));
$this->assertEquals('a', self::callProtectedMethod($stub, 'setEnumVal', array('a', array('a', 'b'), 'b')));
}

View File

@ -52,7 +52,11 @@ class CellTest extends \PHPUnit_Framework_TestCase
foreach ($attributes as $key => $value) {
$set = "set{$key}";
$get = "get{$key}";
$this->assertNull($object->$get()); // Init with null value
$object->$set($value);
$this->assertEquals($value, $object->$get());
}
}

View File

@ -74,6 +74,7 @@ class FontTest extends \PHPUnit_Framework_TestCase
);
foreach ($attributes as $key => $default) {
$get = is_bool($default) ? "is{$key}" : "get{$key}";
$this->assertEquals($default, $object->$get());
$object->setStyleValue("$key", null);
$this->assertEquals($default, $object->$get());
$object->setStyleValue("$key", '');

View File

@ -96,6 +96,20 @@ class ParagraphTest extends \PHPUnit_Framework_TestCase
}
}
/**
* Test get null style value
*/
public function testGetNullStyleValue()
{
$object = new Paragraph();
$attributes = array('spacing', 'indent', 'hanging', 'spaceBefore', 'spaceAfter');
foreach ($attributes as $key) {
$get = "get{$key}";
$this->assertNull($object->$get());
}
}
/**
* Test tabs
*/

View File

@ -74,6 +74,9 @@ class TableTest extends \PHPUnit_Framework_TestCase
'cellMarginLeft' => 240,
'cellMarginRight' => 240,
'cellMarginBottom' => 240,
'align' => 'center',
'width' => 100,
'unit' => 'pct',
);
foreach ($attributes as $key => $value) {
$set = "set{$key}";
@ -146,6 +149,7 @@ class TableTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($value, $object->$get());
}
$this->assertEquals($values, $object->getCellMargin());
$this->assertTrue($object->hasMargin());
}
/**

View File

@ -92,8 +92,8 @@ class HTMLTest extends \PHPUnit_Framework_TestCase
$textrun = $section->addTextRun('Paragraph');
$textrun->addLink('http://test.com');
$textrun->addImage($localImage);
$textrun->addFootnote();
$textrun->addEndnote();
$textrun->addFootnote()->addText('Footnote');
$textrun->addEndnote()->addText('Endnote');
$section = $phpWord->addSection();

View File

@ -50,8 +50,9 @@ class ContentTest extends \PHPUnit_Framework_TestCase
$phpWord->setDefaultFontName('Verdana');
$phpWord->addFontStyle('Font', array('size' => 11));
$phpWord->addParagraphStyle('Paragraph', array('align' => 'center'));
$phpWord->addTableStyle('tblStyle', array('width' => 100));
$section = $phpWord->addSection();
$section = $phpWord->addSection(array('colsNum' => 2));
$section->addText($expected);
$section->addText('Test font style', 'Font');
$section->addText('Test paragraph style', null, 'Paragraph');
@ -60,14 +61,14 @@ class ContentTest extends \PHPUnit_Framework_TestCase
$section->addTextBreak();
$section->addPageBreak();
$section->addListItem('Test list item');
$section->addImage($imageSrc);
$section->addImage($imageSrc, array('width' => 50));
$section->addObject($objectSrc);
$section->addTOC();
$textrun = $section->addTextRun();
$textrun->addText('Test text run');
$table = $section->addTable();
$table = $section->addTable(array('width' => 50));
$cell = $table->addRow()->addCell();
$cell = $table->addRow()->addCell();
$cell->addText('Test');
@ -82,6 +83,8 @@ class ContentTest extends \PHPUnit_Framework_TestCase
$footer = $section->addFooter();
$footer->addPreserveText('{PAGE}');
$table = $section->addTable('tblStyle')->addRow()->addCell();
$doc = TestHelperDOCX::getDocument($phpWord, 'ODText');
$element = "/office:document-content/office:body/office:text/text:section/text:p";

View File

@ -28,7 +28,7 @@ class StyleTest extends \PHPUnit_Framework_TestCase
*/
public function testEmptyStyles()
{
$styles = array('Font', 'Paragraph');
$styles = array('Font', 'Paragraph', 'Image', 'Section', 'Table');
foreach ($styles as $style) {
$objectClass = 'PhpOffice\\PhpWord\\Writer\\ODText\\Style\\' . $style;
$xmlWriter = new XMLWriter();