Merge branch 'develop' into parse_drawings

This commit is contained in:
troosan 2018-07-14 03:30:11 +02:00 committed by GitHub
commit de83da2bbf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 1322 additions and 517 deletions

21
.gitattributes vendored Normal file
View File

@ -0,0 +1,21 @@
# build config
/.scrutinizer.yml export-ignore
/.travis.yml export-ignore
/php_cs.dist export-ignore
/phpmd.xml.dist export-ignore
/phpstan.neon export-ignore
/composer.lock export-ignore
# git files
/.gitignore export-ignore
/.gitattributes export-ignore
# project directories
/build export-ignore
/docs export-ignore
/samples export-ignore
# tests
/phpunit.xml.dist export-ignore
/tests export-ignore

View File

@ -19,7 +19,7 @@ tools:
config: config:
ruleset: phpmd.xml.dist ruleset: phpmd.xml.dist
external_code_coverage: external_code_coverage:
enabled: true enabled: false
timeout: 1200 timeout: 1200
php_cpd: true php_cpd: true
# php_sim: # Temporarily disabled to allow focus on things other than duplicates # php_sim: # Temporarily disabled to allow focus on things other than duplicates

View File

@ -37,7 +37,7 @@ before_script:
- composer self-update - composer self-update
- travis_wait composer install --prefer-source - travis_wait composer install --prefer-source
## PHPDocumentor ## PHPDocumentor
- mkdir -p build/docs ##- mkdir -p build/docs
- mkdir -p build/coverage - mkdir -p build/coverage
script: script:
@ -52,10 +52,8 @@ script:
## PHPLOC ## PHPLOC
- if [ -z "$COVERAGE" ]; then ./vendor/bin/phploc src/ ; fi - if [ -z "$COVERAGE" ]; then ./vendor/bin/phploc src/ ; fi
## PHPDocumentor ## PHPDocumentor
- if [ -z "$COVERAGE" ]; then ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" ; fi ##- if [ -z "$COVERAGE" ]; then ./vendor/bin/phpdoc -q -d ./src -t ./build/docs --ignore "*/src/PhpWord/Shared/*/*" --template="responsive-twig" ; fi
after_script: after_success:
## PHPDocumentor ## Coveralls
- bash .travis_shell_after_success.sh - if [ -n "$COVERAGE" ]; then travis_retry php vendor/bin/php-coveralls -v ; fi
## Scrutinizer
- if [ -n "$COVERAGE" ]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover build/logs/clover.xml ; fi

View File

@ -1,39 +0,0 @@
#!/bin/bash
echo "--DEBUG--"
echo "TRAVIS_REPO_SLUG: $TRAVIS_REPO_SLUG"
echo "TRAVIS_PHP_VERSION: $TRAVIS_PHP_VERSION"
echo "TRAVIS_PULL_REQUEST: $TRAVIS_PULL_REQUEST"
if [ "$TRAVIS_REPO_SLUG" == "PHPOffice/PHPWord" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_PHP_VERSION" == "5.6" ]; then
echo -e "Publishing PHPDoc...\n"
cp -R build/docs $HOME/docs-latest
cp -R build/coverage $HOME/coverage-latest
cd $HOME
git config --global user.email "travis@travis-ci.org"
git config --global user.name "travis-ci"
git clone --quiet --branch=gh-pages https://${GH_TOKEN}@github.com/PHPOffice/PHPWord gh-pages > /dev/null
cd gh-pages
echo "--DEBUG : Suppression"
git rm -rf ./docs/$TRAVIS_BRANCH
echo "--DEBUG : Dossier"
mkdir -p docs/$TRAVIS_BRANCH
mkdir -p coverage/$TRAVIS_BRANCH
echo "--DEBUG : Copie"
cp -Rf $HOME/docs-latest/* ./docs/$TRAVIS_BRANCH/
cp -Rf $HOME/coverage-latest/* ./coverage/$TRAVIS_BRANCH/
echo "--DEBUG : Git"
git add -f .
git commit -m "PHPDocumentor (Travis Build: $TRAVIS_BUILD_NUMBER - Branch: $TRAVIS_BRANCH)"
git push -fq origin gh-pages > /dev/null
echo -e "Published PHPDoc to gh-pages.\n"
fi

View File

@ -20,6 +20,11 @@ v0.15.0 (?? ??? 2018)
- Added support for Image text wrapping distance @troosan #1310 - Added support for Image text wrapping distance @troosan #1310
- Added parsing of CSS line-height and text-indent in HTML reader @troosan #1316 - Added parsing of CSS line-height and text-indent in HTML reader @troosan #1316
- Added the ability to enable gridlines and axislabels on charts @FrankMeyer #576 - Added the ability to enable gridlines and axislabels on charts @FrankMeyer #576
- Add support for table indent (tblInd) @Trainmaster #1343
- Added parsing of internal links in HTML reader @lalop #1336
- Several improvements to charts @JAEK-S #1332
- Add parsing of html image in base64 format @jgpATs2w #1382
- Added Support for Indentation & Tabs on RTF Writer. @smaug1985 #1405
### Fixed ### Fixed
- Fix reading of docx default style - @troosan #1238 - Fix reading of docx default style - @troosan #1238
@ -33,10 +38,15 @@ v0.15.0 (?? ??? 2018)
- Fix parsing of Heading and Title formating @troosan @gthomas2 #465 - Fix parsing of Heading and Title formating @troosan @gthomas2 #465
- Fix Dateformat typo, fix hours casing, add Month-Day-Year formats @ComputerTinker #591 - Fix Dateformat typo, fix hours casing, add Month-Day-Year formats @ComputerTinker #591
- Support reading of w:drawing for documents produced by word 2011+ @gthomas2 #464 #1324 - Support reading of w:drawing for documents produced by word 2011+ @gthomas2 #464 #1324
- Fix missing column width in ODText writer @potofcoffee #413
- Disable entity loader before parsing XML to avoid XXE injection @Tom4t0 #1427
### Changed ### Changed
- Remove zend-stdlib dependency @Trainmaster #1284 - Remove zend-stdlib dependency @Trainmaster #1284
- The default unit for `\PhpOffice\PhpWord\Style\Image` changed from `px` to `pt`.
### Miscelaneous
- Drop GitHub pages, switch to coveralls for code coverage analysis @czosel #1360
v0.14.0 (29 Dec 2017) v0.14.0 (29 Dec 2017)
---------------------- ----------------------

View File

@ -3,7 +3,7 @@
[![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) [![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword)
[![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord) [![Build Status](https://travis-ci.org/PHPOffice/PHPWord.svg?branch=master)](https://travis-ci.org/PHPOffice/PHPWord)
[![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?s=b5997ce59ac2816b4514f3a38de9900f6d492c1d)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) [![Code Quality](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/quality-score.png?s=b5997ce59ac2816b4514f3a38de9900f6d492c1d)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/)
[![Code Coverage](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/badges/coverage.png?s=742a98745725c562955440edc8d2c39d7ff5ae25)](https://scrutinizer-ci.com/g/PHPOffice/PHPWord/) [![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=develop)](https://coveralls.io/github/PHPOffice/PHPWord?branch=develop)
[![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads.png)](https://packagist.org/packages/phpoffice/phpword) [![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads.png)](https://packagist.org/packages/phpoffice/phpword)
[![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) [![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword)
[![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord) [![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord)

View File

@ -64,15 +64,17 @@
"phpoffice/common": "^0.2.9" "phpoffice/common": "^0.2.9"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.8.36 || ^5.0", "ext-zip": "*",
"phpdocumentor/phpdocumentor":"2.*", "ext-gd": "*",
"squizlabs/php_codesniffer": "^2.7", "phpunit/phpunit": "^4.8.36 || ^7.0",
"friendsofphp/php-cs-fixer": "^2.0", "squizlabs/php_codesniffer": "^2.9",
"friendsofphp/php-cs-fixer": "^2.2",
"phpmd/phpmd": "2.*", "phpmd/phpmd": "2.*",
"phploc/phploc": "2.* || 3.* || 4.*", "phploc/phploc": "2.* || 3.* || 4.*",
"dompdf/dompdf":"0.8.*", "dompdf/dompdf":"0.8.*",
"tecnickcom/tcpdf": "6.*", "tecnickcom/tcpdf": "6.*",
"mpdf/mpdf": "5.* || 6.* || 7.*" "mpdf/mpdf": "5.7.4 || 6.* || 7.*",
"php-coveralls/php-coveralls": "1.1.0 || ^2.0"
}, },
"suggest": { "suggest": {
"ext-zip": "Allows writing OOXML and ODF", "ext-zip": "Allows writing OOXML and ODF",

View File

@ -242,7 +242,7 @@ To add an image, use the ``addImage`` method to sections, headers, footers, text
$section->addImage($src, [$style]); $section->addImage($src, [$style]);
- ``$src``. String path to a local image, URL of a remote image or the image data, as a string. - ``$src``. String path to a local image, URL of a remote image or the image data, as a string. Warning: Do not pass user-generated strings here, as that would allow an attacker to read arbitrary files or perform server-side request forgery by passing file paths or URLs instead of image data.
- ``$style``. See :ref:`image-style`. - ``$style``. See :ref:`image-style`.
Examples: Examples:
@ -435,8 +435,8 @@ Available line style attributes:
- ``dash``. Line types: dash, rounddot, squaredot, dashdot, longdash, longdashdot, longdashdotdot. - ``dash``. Line types: dash, rounddot, squaredot, dashdot, longdash, longdashdot, longdashdotdot.
- ``beginArrow``. Start type of arrow: block, open, classic, diamond, oval. - ``beginArrow``. Start type of arrow: block, open, classic, diamond, oval.
- ``endArrow``. End type of arrow: block, open, classic, diamond, oval. - ``endArrow``. End type of arrow: block, open, classic, diamond, oval.
- ``width``. Line-object width in pt. - ``width``. Line-object width in *pt*.
- ``height``. Line-object height in pt. - ``height``. Line-object height in *pt*.
- ``flip``. Flip the line element: true, false. - ``flip``. Flip the line element: true, false.
Chart Chart

View File

@ -54,7 +54,5 @@ Example:
Using samples Using samples
------------- -------------
After installation, you can browse and use the samples that we've More examples are provided in the ``samples`` directory.
provided, either by command line or using browser. If you can access For an easy access to those samples launch ``php -S localhost:8000`` in the samples directory then browse to http://localhost:8000 to view the samples.
your PHPWord library folder using browser, point your browser to the
``samples`` folder, e.g. ``http://localhost/PhpWord/samples/``.

View File

@ -104,6 +104,7 @@ Available Table style options:
- ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'. - ``border(Top|Right|Bottom|Left)Color``. Border color, e.g. '9966CC'.
- ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*. - ``border(Top|Right|Bottom|Left)Size``. Border size in *twip*.
- ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in *twip*. - ``cellMargin(Top|Right|Bottom|Left)``. Cell margin in *twip*.
- ``indent``. Table indent from leading margin. Must be an instance of ``\PhpOffice\PhpWord\ComplexType\TblWidth``.
- ``width``. Table width in percent. - ``width``. Table width in percent.
- ``unit``. The unit to use for the width. One of ``\PhpOffice\PhpWord\SimpleType\TblWidth``. Defaults to *auto*. - ``unit``. The unit to use for the width. One of ``\PhpOffice\PhpWord\SimpleType\TblWidth``. Defaults to *auto*.
- ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants. - ``layout``. Table layout, either *fixed* or *autofit* See ``\PhpOffice\PhpWord\Style\Table`` for constants.
@ -149,10 +150,10 @@ Image
Available Image style options: Available Image style options:
- ``alignment``. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details. - ``alignment``. See ``\PhpOffice\PhpWord\SimpleType\Jc`` class for the details.
- ``height``. Height in pixels. - ``height``. Height in *pt*.
- ``marginLeft``. Left margin in inches, can be negative. - ``marginLeft``. Left margin in inches, can be negative.
- ``marginTop``. Top margin in inches, can be negative. - ``marginTop``. Top margin in inches, can be negative.
- ``width``. Width in pixels. - ``width``. Width in *pt*.
- ``wrappingStyle``. Wrapping style, *inline*, *square*, *tight*, *behind*, or *infront*. - ``wrappingStyle``. Wrapping style, *inline*, *square*, *tight*, *behind*, or *infront*.
- ``wrapDistanceTop``. Top text wrapping in pixels. - ``wrapDistanceTop``. Top text wrapping in pixels.
- ``wrapDistanceBottom``. Bottom text wrapping in pixels. - ``wrapDistanceBottom``. Bottom text wrapping in pixels.

View File

@ -1,7 +1,7 @@
includes: includes:
- vendor/phpstan/phpstan/conf/config.level1.neon - vendor/phpstan/phpstan/conf/config.level1.neon
parameters: parameters:
memory-limit: 200000 memory-limit: 20000000
autoload_directories: autoload_directories:
- tests - tests
autoload_files: autoload_files:

View File

@ -6,8 +6,7 @@
convertNoticesToExceptions="true" convertNoticesToExceptions="true"
convertWarningsToExceptions="true" convertWarningsToExceptions="true"
processIsolation="false" processIsolation="false"
stopOnFailure="false" stopOnFailure="false">
syntaxCheck="false">
<testsuites> <testsuites>
<testsuite name="PhpWord Test Suite"> <testsuite name="PhpWord Test Suite">
<directory>./tests/PhpWord</directory> <directory>./tests/PhpWord</directory>
@ -22,7 +21,7 @@
</whitelist> </whitelist>
</filter> </filter>
<logging> <logging>
<log type="coverage-html" target="./build/coverage" charset="UTF-8" highlight="true" /> <log type="coverage-html" target="./build/coverage" />
<log type="coverage-clover" target="./build/logs/clover.xml" /> <log type="coverage-clover" target="./build/logs/clover.xml" />
</logging> </logging>
</phpunit> </phpunit>

View File

@ -1,6 +1,5 @@
<?php <?php
use PhpOffice\PhpWord\Style\Font; use PhpOffice\PhpWord\Style\Font;
use PhpOffice\PhpWord\Style\Paragraph;
include_once 'Sample_Header.php'; include_once 'Sample_Header.php';

View File

@ -56,7 +56,7 @@ $templateProcessor->setValue('userPhone#3', '+1 428 889 775');
echo date('H:i:s'), ' Saving the result document...', EOL; echo date('H:i:s'), ' Saving the result document...', EOL;
$templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx'); $templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx');
echo getEndingNotes(array('Word2007' => 'docx')); echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_07_TemplateCloneRow.docx');
if (!CLI) { if (!CLI) {
include_once 'Sample_Footer.php'; include_once 'Sample_Footer.php';
} }

View File

@ -14,7 +14,7 @@ $templateProcessor->deleteBlock('DELETEME');
echo date('H:i:s'), ' Saving the result document...', EOL; echo date('H:i:s'), ' Saving the result document...', EOL;
$templateProcessor->saveAs('results/Sample_23_TemplateBlock.docx'); $templateProcessor->saveAs('results/Sample_23_TemplateBlock.docx');
echo getEndingNotes(array('Word2007' => 'docx')); echo getEndingNotes(array('Word2007' => 'docx'), 'results/Sample_23_TemplateBlock.docx');
if (!CLI) { if (!CLI) {
include_once 'Sample_Footer.php'; include_once 'Sample_Footer.php';
} }

View File

@ -11,7 +11,7 @@ $html = '<h1>Adding element via HTML</h1>';
$html .= '<p>Some well-formed HTML snippet needs to be used</p>'; $html .= '<p>Some well-formed HTML snippet needs to be used</p>';
$html .= '<p>With for example <strong>some<sup>1</sup> <em>inline</em> formatting</strong><sub>1</sub></p>'; $html .= '<p>With for example <strong>some<sup>1</sup> <em>inline</em> formatting</strong><sub>1</sub></p>';
$html .= '<p>A link to <a href="http://phpword.readthedocs.io/">Read the docs</a></p>'; $html .= '<p>A link to <a href="http://phpword.readthedocs.io/" style="text-decoration: underline">Read the docs</a></p>';
$html .= '<p lang="he-IL" style="text-align: right; direction: rtl">היי, זה פסקה מימין לשמאל</p>'; $html .= '<p lang="he-IL" style="text-align: right; direction: rtl">היי, זה פסקה מימין לשמאל</p>';

View File

@ -6,15 +6,20 @@ include_once 'Sample_Header.php';
// New Word document // New Word document
echo date('H:i:s'), ' Create new PhpWord object', EOL; echo date('H:i:s'), ' Create new PhpWord object', EOL;
$phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord = new \PhpOffice\PhpWord\PhpWord();
PhpOffice\PhpWord\Style::addTitleStyle(1, array('size' => 14));
// New section // New section
$section = $phpWord->addSection(); $section = $phpWord->addSection();
$section->addTitle('This page demos fields');
// Add Field elements // Add Field elements
// See Element/Field.php for all options // See Element/Field.php for all options
$section->addText('Date field:'); $section->addText('Date field:');
$section->addField('DATE', array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat')); $section->addField('DATE', array('dateformat' => 'dddd d MMMM yyyy H:mm:ss'), array('PreserveFormat'));
$section->addText('Style Ref field:');
$section->addField('STYLEREF', array('StyleIdentifier' => 'Heading 1'));
$section->addText('Page field:'); $section->addText('Page field:');
$section->addField('PAGE', array('format' => 'Arabic')); $section->addField('PAGE', array('format' => 'Arabic'));

View File

@ -16,8 +16,8 @@ $section = $phpWord->addSection();
$section->addTitle('2D charts', 1); $section->addTitle('2D charts', 1);
$section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous')); $section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous'));
$chartTypes = array('pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar'); $chartTypes = array('pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column');
$twoSeries = array('bar', 'column', 'line', 'area', 'scatter', 'radar'); $twoSeries = array('bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column');
$threeSeries = array('bar', 'line'); $threeSeries = array('bar', 'line');
$categories = array('A', 'B', 'C', 'D', 'E'); $categories = array('A', 'B', 'C', 'D', 'E');
$series1 = array(1, 3, 2, 5, 4); $series1 = array(1, 3, 2, 5, 4);

View File

@ -83,7 +83,7 @@ function write($phpWord, $filename, $writers)
$result .= EOL; $result .= EOL;
} }
$result .= getEndingNotes($writers); $result .= getEndingNotes($writers, $filename);
return $result; return $result;
} }
@ -92,10 +92,10 @@ function write($phpWord, $filename, $writers)
* Get ending notes * Get ending notes
* *
* @param array $writers * @param array $writers
* * @param mixed $filename
* @return string * @return string
*/ */
function getEndingNotes($writers) function getEndingNotes($writers, $filename)
{ {
$result = ''; $result = '';

View File

@ -11,5 +11,15 @@
<ul><li>Item 1</li><li>Item 2</li><ul><li>Item 2.1</li><li>Item 2.1</li></ul></ul> <ul><li>Item 1</li><li>Item 2</li><ul><li>Item 2.1</li><li>Item 2.1</li></ul></ul>
<p>Ordered (numbered) list:</p> <p>Ordered (numbered) list:</p>
<ol><li>Item 1</li><li>Item 2</li></ol> <ol><li>Item 1</li><li>Item 2</li></ol>
<p style="line-height:2">Double height</p>
<h2>Includes images</h2>
<img src="https://phpword.readthedocs.io/en/latest/_images/phpword.png" alt=""/>
<img src="https://localhost/gev/desarrollo/actividades/pruebas_14/5b064503587f7.jpeg" name="Imagen 12" align="bottom" width="208" height="183" border="0"/>
<img src="http://localhost/gev/desarrollo/actividades/pruebas_14/5b064503589db.png" name="Imagen 13" align="bottom" width="143" height="202" border="0"/>
<img src="http://localhost/gev/desarrollo/actividades/pruebas_14/5b0645035aac8.jpeg" name="Imagen 14" align="bottom" width="194" height="188" border="0"/>
</body> </body>
</html> </html>

0
samples/results/.gitignore vendored Normal file → Executable file
View File

View File

@ -0,0 +1,59 @@
<?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.
*
* @see https://github.com/PHPOffice/PHPWord
* @copyright 2010-2018 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\ComplexType;
use PhpOffice\PhpWord\SimpleType\TblWidth as TblWidthSimpleType;
/**
* @see http://www.datypic.com/sc/ooxml/t-w_CT_TblWidth.html
*/
final class TblWidth
{
/** @var string */
private $type;
/** @var int */
private $value;
/**
* @param int $value If omitted, then its value shall be assumed to be 0
* @param string $type If omitted, then its value shall be assumed to be dxa
*/
public function __construct($value = 0, $type = TblWidthSimpleType::TWIP)
{
$this->value = $value;
TblWidthSimpleType::validate($type);
$this->type = $type;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* @return int
*/
public function getValue()
{
return $this->value;
}
}

View File

@ -347,7 +347,7 @@ abstract class AbstractElement
* *
* @param \PhpOffice\PhpWord\Element\AbstractElement $container * @param \PhpOffice\PhpWord\Element\AbstractElement $container
*/ */
public function setParentContainer(AbstractElement $container) public function setParentContainer(self $container)
{ {
$this->parentContainer = substr(get_class($container), strrpos(get_class($container), '\\') + 1); $this->parentContainer = substr(get_class($container), strrpos(get_class($container), '\\') + 1);
$this->parent = $container; $this->parent = $container;

View File

@ -61,11 +61,12 @@ class Chart extends AbstractElement
* @param array $categories * @param array $categories
* @param array $values * @param array $values
* @param array $style * @param array $style
* @param null|mixed $seriesName
*/ */
public function __construct($type, $categories, $values, $style = null) public function __construct($type, $categories, $values, $style = null, $seriesName = null)
{ {
$this->setType($type); $this->setType($type);
$this->addSeries($categories, $values); $this->addSeries($categories, $values, $seriesName);
$this->style = $this->setNewStyle(new ChartStyle(), $style, true); $this->style = $this->setNewStyle(new ChartStyle(), $style, true);
} }
@ -86,7 +87,7 @@ class Chart extends AbstractElement
*/ */
public function setType($value) public function setType($value)
{ {
$enum = array('pie', 'doughnut', 'line', 'bar', 'column', 'area', 'radar', 'scatter'); $enum = array('pie', 'doughnut', 'line', 'bar', 'stacked_bar', 'percent_stacked_bar', 'column', 'stacked_column', 'percent_stacked_column', 'area', 'radar', 'scatter');
$this->type = $this->setEnumVal($value, $enum, 'pie'); $this->type = $this->setEnumVal($value, $enum, 'pie');
} }
@ -95,10 +96,15 @@ class Chart extends AbstractElement
* *
* @param array $categories * @param array $categories
* @param array $values * @param array $values
* @param null|mixed $name
*/ */
public function addSeries($categories, $values) public function addSeries($categories, $values, $name = null)
{ {
$this->series[] = array('categories' => $categories, 'values' => $values); $this->series[] = array(
'categories' => $categories,
'values' => $values,
'name' => $name,
);
} }
/** /**

View File

@ -78,6 +78,10 @@ class Field extends AbstractElement
'properties' => array(), 'properties' => array(),
'options' => array('PreserveFormat'), 'options' => array('PreserveFormat'),
), ),
'STYLEREF' => array(
'properties' => array('StyleIdentifier' => ''),
'options' => array('PreserveFormat'),
),
); );
/** /**

View File

@ -83,7 +83,7 @@ class OLEObject extends AbstractElement
$this->style = $this->setNewStyle(new ImageStyle(), $style, true); $this->style = $this->setNewStyle(new ImageStyle(), $style, true);
$this->icon = realpath(__DIR__ . "/../resources/{$ext}.png"); $this->icon = realpath(__DIR__ . "/../resources/{$ext}.png");
return $this; return;
} }
throw new InvalidObjectException(); throw new InvalidObjectException();

View File

@ -29,7 +29,7 @@ class PreserveText extends AbstractElement
/** /**
* Text content * Text content
* *
* @var string * @var string|array
*/ */
private $text; private $text;
@ -64,8 +64,6 @@ class PreserveText extends AbstractElement
if (isset($matches[0])) { if (isset($matches[0])) {
$this->text = $matches; $this->text = $matches;
} }
return $this;
} }
/** /**
@ -91,7 +89,7 @@ class PreserveText extends AbstractElement
/** /**
* Get Text content * Get Text content
* *
* @return string * @return string|array
*/ */
public function getText() public function getText()
{ {

View File

@ -135,18 +135,40 @@ class Table extends AbstractElement
public function countColumns() public function countColumns()
{ {
$columnCount = 0; $columnCount = 0;
if (is_array($this->rows)) {
$rowCount = count($this->rows); $rowCount = count($this->rows);
for ($i = 0; $i < $rowCount; $i++) { for ($i = 0; $i < $rowCount; $i++) {
/** @var \PhpOffice\PhpWord\Element\Row $row Type hint */ /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */
$row = $this->rows[$i]; $row = $this->rows[$i];
$cellCount = count($row->getCells()); $cellCount = count($row->getCells());
if ($columnCount < $cellCount) { if ($columnCount < $cellCount) {
$columnCount = $cellCount; $columnCount = $cellCount;
}
} }
} }
return $columnCount; return $columnCount;
} }
/**
* The first declared cell width for each column
*
* @return int[]
*/
public function findFirstDefinedCellWidths()
{
$cellWidths = array();
foreach ($this->rows as $row) {
$cells = $row->getCells();
if (count($cells) <= count($cellWidths)) {
continue;
}
$cellWidths = array();
foreach ($cells as $cell) {
$cellWidths[] = $cell->getWidth();
}
}
return $cellWidths;
}
} }

View File

@ -61,14 +61,12 @@ class Title extends AbstractElement
*/ */
public function __construct($text, $depth = 1) public function __construct($text, $depth = 1)
{ {
if (isset($text)) { if (is_string($text)) {
if (is_string($text)) { $this->text = CommonText::toUTF8($text);
$this->text = CommonText::toUTF8($text); } elseif ($text instanceof TextRun) {
} elseif ($text instanceof TextRun) { $this->text = $text;
$this->text = $text; } else {
} else { throw new \InvalidArgumentException('Invalid text, should be a string or a TextRun');
throw new \InvalidArgumentException('Invalid text, should be a string or a TextRun');
}
} }
$this->depth = $depth; $this->depth = $depth;
@ -76,8 +74,6 @@ class Title extends AbstractElement
if (array_key_exists($styleName, Style::getStyles())) { if (array_key_exists($styleName, Style::getStyles())) {
$this->style = str_replace('_', '', $styleName); $this->style = str_replace('_', '', $styleName);
} }
return $this;
} }
/** /**

View File

@ -17,7 +17,7 @@
namespace PhpOffice\PhpWord\Metadata; namespace PhpOffice\PhpWord\Metadata;
use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder; use PhpOffice\Common\Microsoft\PasswordEncoder;
use PhpOffice\PhpWord\SimpleType\DocProtect; use PhpOffice\PhpWord\SimpleType\DocProtect;
/** /**
@ -113,7 +113,7 @@ class Protection
/** /**
* Set password * Set password
* *
* @param $password * @param string $password
* @return self * @return self
*/ */
public function setPassword($password) public function setPassword($password)
@ -136,7 +136,7 @@ class Protection
/** /**
* Set count for hash iterations * Set count for hash iterations
* *
* @param $spinCount * @param int $spinCount
* @return self * @return self
*/ */
public function setSpinCount($spinCount) public function setSpinCount($spinCount)
@ -159,7 +159,7 @@ class Protection
/** /**
* Set algorithm * Set algorithm
* *
* @param $algorithm * @param string $algorithm
* @return self * @return self
*/ */
public function setAlgorithm($algorithm) public function setAlgorithm($algorithm)

View File

@ -35,10 +35,10 @@ use PhpOffice\PhpWord\Exception\Exception;
* @method int addChart(Element\Chart $chart) * @method int addChart(Element\Chart $chart)
* @method int addComment(Element\Comment $comment) * @method int addComment(Element\Comment $comment)
* *
* @method Style\Paragraph addParagraphStyle(string $styleName, array $styles) * @method Style\Paragraph addParagraphStyle(string $styleName, mixed $styles)
* @method Style\Font addFontStyle(string $styleName, mixed $fontStyle, mixed $paragraphStyle = null) * @method Style\Font addFontStyle(string $styleName, mixed $fontStyle, mixed $paragraphStyle = null)
* @method Style\Font addLinkStyle(string $styleName, mixed $styles) * @method Style\Font addLinkStyle(string $styleName, mixed $styles)
* @method Style\Font addTitleStyle(int $depth, mixed $fontStyle, mixed $paragraphStyle = null) * @method Style\Font addTitleStyle(mixed $depth, mixed $fontStyle, mixed $paragraphStyle = null)
* @method Style\Table addTableStyle(string $styleName, mixed $styleTable, mixed $styleFirstRow = null) * @method Style\Table addTableStyle(string $styleName, mixed $styleTable, mixed $styleFirstRow = null)
* @method Style\Numbering addNumberingStyle(string $styleName, mixed $styles) * @method Style\Numbering addNumberingStyle(string $styleName, mixed $styles)
*/ */

View File

@ -18,6 +18,7 @@
namespace PhpOffice\PhpWord\Reader\Word2007; namespace PhpOffice\PhpWord\Reader\Word2007;
use PhpOffice\Common\XMLReader; use PhpOffice\Common\XMLReader;
use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType;
use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\AbstractContainer;
use PhpOffice\PhpWord\Element\TextRun; use PhpOffice\PhpWord\Element\TextRun;
use PhpOffice\PhpWord\Element\TrackChange; use PhpOffice\PhpWord\Element\TrackChange;
@ -486,6 +487,11 @@ abstract class AbstractPart
if ($tablePositionNode !== null) { if ($tablePositionNode !== null) {
$style['position'] = $this->readTablePosition($xmlReader, $tablePositionNode); $style['position'] = $this->readTablePosition($xmlReader, $tablePositionNode);
} }
$indentNode = $xmlReader->getElement('w:tblInd', $styleNode);
if ($indentNode !== null) {
$style['indent'] = $this->readTableIndent($xmlReader, $indentNode);
}
} }
} }
@ -517,6 +523,24 @@ abstract class AbstractPart
return $this->readStyleDefs($xmlReader, $domNode, $styleDefs); return $this->readStyleDefs($xmlReader, $domNode, $styleDefs);
} }
/**
* Read w:tblInd
*
* @param \PhpOffice\Common\XMLReader $xmlReader
* @param \DOMElement $domNode
* @return TblWidthComplexType
*/
private function readTableIndent(XMLReader $xmlReader, \DOMElement $domNode)
{
$styleDefs = array(
'value' => array(self::READ_VALUE, '.', 'w:w'),
'type' => array(self::READ_VALUE, '.', 'w:type'),
);
$styleDefs = $this->readStyleDefs($xmlReader, $domNode, $styleDefs);
return new TblWidthComplexType((int) $styleDefs['value'], $styleDefs['type']);
}
/** /**
* Read w:tcPr * Read w:tcPr
* *

View File

@ -81,7 +81,7 @@ class Settings extends AbstractPart
* *
* @param XMLReader $xmlReader * @param XMLReader $xmlReader
* @param PhpWord $phpWord * @param PhpWord $phpWord
* @param \DOMNode $node * @param \DOMElement $node
*/ */
protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) protected function setThemeFontLang(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node)
{ {
@ -102,14 +102,16 @@ class Settings extends AbstractPart
* *
* @param XMLReader $xmlReader * @param XMLReader $xmlReader
* @param PhpWord $phpWord * @param PhpWord $phpWord
* @param \DOMNode $node * @param \DOMElement $node
*/ */
protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) protected function setDocumentProtection(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node)
{ {
$documentProtection = $phpWord->getSettings()->getDocumentProtection(); $documentProtection = $phpWord->getSettings()->getDocumentProtection();
$edit = $xmlReader->getAttribute('w:edit', $node); $edit = $xmlReader->getAttribute('w:edit', $node);
$documentProtection->setEditing($edit); if ($edit !== null) {
$documentProtection->setEditing($edit);
}
} }
/** /**
@ -117,7 +119,7 @@ class Settings extends AbstractPart
* *
* @param XMLReader $xmlReader * @param XMLReader $xmlReader
* @param PhpWord $phpWord * @param PhpWord $phpWord
* @param \DOMNode $node * @param \DOMElement $node
*/ */
protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) protected function setProofState(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node)
{ {
@ -139,7 +141,7 @@ class Settings extends AbstractPart
* *
* @param XMLReader $xmlReader * @param XMLReader $xmlReader
* @param PhpWord $phpWord * @param PhpWord $phpWord
* @param \DOMNode $node * @param \DOMElement $node
*/ */
protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) protected function setZoom(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node)
{ {
@ -156,7 +158,7 @@ class Settings extends AbstractPart
* *
* @param XMLReader $xmlReader * @param XMLReader $xmlReader
* @param PhpWord $phpWord * @param PhpWord $phpWord
* @param \DOMNode $node * @param \DOMElement $node
*/ */
protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node) protected function setRevisionView(XMLReader $xmlReader, PhpWord $phpWord, \DOMElement $node)
{ {

View File

@ -20,6 +20,7 @@ namespace PhpOffice\PhpWord\Shared;
use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\AbstractContainer;
use PhpOffice\PhpWord\Element\Row; use PhpOffice\PhpWord\Element\Row;
use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\Jc;
use PhpOffice\PhpWord\SimpleType\NumberFormat; use PhpOffice\PhpWord\SimpleType\NumberFormat;
@ -32,23 +33,30 @@ class Html
{ {
private static $listIndex = 0; private static $listIndex = 0;
private static $xpath; private static $xpath;
private static $options;
/** /**
* Add HTML parts. * Add HTML parts.
* *
* Note: $stylesheet parameter is removed to avoid PHPMD error for unused parameter * Note: $stylesheet parameter is removed to avoid PHPMD error for unused parameter
* Warning: Do not pass user-generated HTML here, as that would allow an attacker to read arbitrary
* files or perform server-side request forgery by passing local file paths or URLs in <img>.
* *
* @param \PhpOffice\PhpWord\Element\AbstractContainer $element Where the parts need to be added * @param \PhpOffice\PhpWord\Element\AbstractContainer $element Where the parts need to be added
* @param string $html The code to parse * @param string $html The code to parse
* @param bool $fullHTML If it's a full HTML, no need to add 'body' tag * @param bool $fullHTML If it's a full HTML, no need to add 'body' tag
* @param bool $preserveWhiteSpace If false, the whitespaces between nodes will be removed * @param bool $preserveWhiteSpace If false, the whitespaces between nodes will be removed
* @param array $options:
* + IMG_SRC_SEARCH: optional to speed up images loading from remote url when files can be found locally
* + IMG_SRC_REPLACE: optional to speed up images loading from remote url when files can be found locally
*/ */
public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true) public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true, $options = null)
{ {
/* /*
* @todo parse $stylesheet for default styles. Should result in an array based on id, class and element, * @todo parse $stylesheet for default styles. Should result in an array based on id, class and element,
* which could be applied when such an element occurs in the parseNode function. * which could be applied when such an element occurs in the parseNode function.
*/ */
self::$options = $options;
// Preprocess: remove all line ends, decode HTML entity, // Preprocess: remove all line ends, decode HTML entity,
// fix ampersand and angle brackets and add body tag for HTML fragments // fix ampersand and angle brackets and add body tag for HTML fragments
@ -63,10 +71,11 @@ class Html
} }
// Load DOM // Load DOM
libxml_disable_entity_loader(true);
$dom = new \DOMDocument(); $dom = new \DOMDocument();
$dom->preserveWhiteSpace = $preserveWhiteSpace; $dom->preserveWhiteSpace = $preserveWhiteSpace;
$dom->loadXML($html); $dom->loadXML($html);
self::$xpath = new \DOMXpath($dom); self::$xpath = new \DOMXPath($dom);
$node = $dom->getElementsByTagName('body'); $node = $dom->getElementsByTagName('body');
self::parseNode($node->item(0), $element); self::parseNode($node->item(0), $element);
@ -139,6 +148,7 @@ class Html
'sup' => array('Property', null, null, $styles, null, 'superScript', true), 'sup' => array('Property', null, null, $styles, null, 'superScript', true),
'sub' => array('Property', null, null, $styles, null, 'subScript', true), 'sub' => array('Property', null, null, $styles, null, 'subScript', true),
'span' => array('Span', $node, null, $styles, null, null, null), 'span' => array('Span', $node, null, $styles, null, null, null),
'font' => array('Span', $node, null, $styles, null, null, null),
'table' => array('Table', $node, $element, $styles, null, null, null), 'table' => array('Table', $node, $element, $styles, null, null, null),
'tr' => array('Row', $node, $element, $styles, null, null, null), 'tr' => array('Row', $node, $element, $styles, null, null, null),
'td' => array('Cell', $node, $element, $styles, null, null, null), 'td' => array('Cell', $node, $element, $styles, null, null, null),
@ -646,7 +656,52 @@ class Html
break; break;
} }
} }
$newElement = $element->addImage($src, $style); $originSrc = $src;
if (strpos($src, 'data:image') !== false) {
$tmpDir = Settings::getTempDir() . '/';
$match = array();
preg_match('/data:image\/(\w+);base64,(.+)/', $src, $match);
$src = $imgFile = $tmpDir . uniqid() . '.' . $match[1];
$ifp = fopen($imgFile, 'wb');
if ($ifp !== false) {
fwrite($ifp, base64_decode($match[2]));
fclose($ifp);
}
}
$src = urldecode($src);
if (!is_file($src)
&& !is_null(self::$options)
&& isset(self::$options['IMG_SRC_SEARCH'])
&& isset(self::$options['IMG_SRC_REPLACE'])) {
$src = str_replace(self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE'], $src);
}
if (!is_file($src)) {
if ($imgBlob = @file_get_contents($src)) {
$tmpDir = Settings::getTempDir() . '/';
$match = array();
preg_match('/.+\.(\w+)$/', $src, $match);
$src = $tmpDir . uniqid() . '.' . $match[1];
$ifp = fopen($src, 'wb');
if ($ifp !== false) {
fwrite($ifp, $imgBlob);
fclose($ifp);
}
}
}
if (is_file($src)) {
$newElement = $element->addImage($src, $style);
} else {
throw new \Exception("Could not load image $originSrc");
}
return $newElement; return $newElement;
} }
@ -719,7 +774,11 @@ class Html
break; break;
} }
} }
self::parseInlineStyle($node, $styles['font']); $styles['font'] = self::parseInlineStyle($node, $styles['font']);
if (strpos($target, '#') === 0) {
return $element->addLink(substr($target, 1), $node->textContent, $styles['font'], $styles['paragraph'], true);
}
return $element->addLink($target, $node->textContent, $styles['font'], $styles['paragraph']); return $element->addLink($target, $node->textContent, $styles['font'], $styles['paragraph']);
} }

View File

@ -1,235 +0,0 @@
<?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.
*
* @see https://github.com/PHPOffice/PHPWord
* @copyright 2010-2018 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Shared\Microsoft;
/**
* Password encoder for microsoft office applications
*/
class PasswordEncoder
{
const ALGORITHM_MD2 = 'MD2';
const ALGORITHM_MD4 = 'MD4';
const ALGORITHM_MD5 = 'MD5';
const ALGORITHM_SHA_1 = 'SHA-1';
const ALGORITHM_SHA_256 = 'SHA-256';
const ALGORITHM_SHA_384 = 'SHA-384';
const ALGORITHM_SHA_512 = 'SHA-512';
const ALGORITHM_RIPEMD = 'RIPEMD';
const ALGORITHM_RIPEMD_160 = 'RIPEMD-160';
const ALGORITHM_MAC = 'MAC';
const ALGORITHM_HMAC = 'HMAC';
/**
* Mapping between algorithm name and algorithm ID
*
* @var array
* @see https://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.writeprotection.cryptographicalgorithmsid(v=office.14).aspx
*/
private static $algorithmMapping = array(
self::ALGORITHM_MD2 => array(1, 'md2'),
self::ALGORITHM_MD4 => array(2, 'md4'),
self::ALGORITHM_MD5 => array(3, 'md5'),
self::ALGORITHM_SHA_1 => array(4, 'sha1'),
self::ALGORITHM_MAC => array(5, ''), // 'mac' -> not possible with hash()
self::ALGORITHM_RIPEMD => array(6, 'ripemd'),
self::ALGORITHM_RIPEMD_160 => array(7, 'ripemd160'),
self::ALGORITHM_HMAC => array(9, ''), //'hmac' -> not possible with hash()
self::ALGORITHM_SHA_256 => array(12, 'sha256'),
self::ALGORITHM_SHA_384 => array(13, 'sha384'),
self::ALGORITHM_SHA_512 => array(14, 'sha512'),
);
private static $initialCodeArray = array(
0xE1F0,
0x1D0F,
0xCC9C,
0x84C0,
0x110C,
0x0E10,
0xF1CE,
0x313E,
0x1872,
0xE139,
0xD40F,
0x84F9,
0x280C,
0xA96A,
0x4EC3,
);
private static $encryptionMatrix = array(
array(0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09),
array(0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF),
array(0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0),
array(0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40),
array(0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5),
array(0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A),
array(0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9),
array(0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0),
array(0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC),
array(0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10),
array(0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168),
array(0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C),
array(0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD),
array(0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC),
array(0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4),
);
private static $passwordMaxLength = 15;
/**
* Create a hashed password that MS Word will be able to work with
* @see https://blogs.msdn.microsoft.com/vsod/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0/
*
* @param string $password
* @param string $algorithmName
* @param string $salt
* @param int $spinCount
* @return string
*/
public static function hashPassword($password, $algorithmName = self::ALGORITHM_SHA_1, $salt = null, $spinCount = 10000)
{
$origEncoding = mb_internal_encoding();
mb_internal_encoding('UTF-8');
$password = mb_substr($password, 0, min(self::$passwordMaxLength, mb_strlen($password)));
// Get the single-byte values by iterating through the Unicode characters of the truncated password.
// For each character, if the low byte is not equal to 0, take it. Otherwise, take the high byte.
$passUtf8 = mb_convert_encoding($password, 'UCS-2LE', 'UTF-8');
$byteChars = array();
for ($i = 0; $i < mb_strlen($password); $i++) {
$byteChars[$i] = ord(substr($passUtf8, $i * 2, 1));
if ($byteChars[$i] == 0) {
$byteChars[$i] = ord(substr($passUtf8, $i * 2 + 1, 1));
}
}
// build low-order word and hig-order word and combine them
$combinedKey = self::buildCombinedKey($byteChars);
// build reversed hexadecimal string
$hex = str_pad(strtoupper(dechex($combinedKey & 0xFFFFFFFF)), 8, '0', \STR_PAD_LEFT);
$reversedHex = $hex[6] . $hex[7] . $hex[4] . $hex[5] . $hex[2] . $hex[3] . $hex[0] . $hex[1];
$generatedKey = mb_convert_encoding($reversedHex, 'UCS-2LE', 'UTF-8');
// Implementation Notes List:
// Word requires that the initial hash of the password with the salt not be considered in the count.
// The initial hash of salt + key is not included in the iteration count.
$algorithm = self::getAlgorithm($algorithmName);
$generatedKey = hash($algorithm, $salt . $generatedKey, true);
for ($i = 0; $i < $spinCount; $i++) {
$generatedKey = hash($algorithm, $generatedKey . pack('CCCC', $i, $i >> 8, $i >> 16, $i >> 24), true);
}
$generatedKey = base64_encode($generatedKey);
mb_internal_encoding($origEncoding);
return $generatedKey;
}
/**
* Get algorithm from self::$algorithmMapping
*
* @param string $algorithmName
* @return string
*/
private static function getAlgorithm($algorithmName)
{
$algorithm = self::$algorithmMapping[$algorithmName][1];
if ($algorithm == '') {
$algorithm = 'sha1';
}
return $algorithm;
}
/**
* Returns the algorithm ID
*
* @param string $algorithmName
* @return int
*/
public static function getAlgorithmId($algorithmName)
{
return self::$algorithmMapping[$algorithmName][0];
}
/**
* Build combined key from low-order word and high-order word
*
* @param array $byteChars byte array representation of password
* @return int
*/
private static function buildCombinedKey($byteChars)
{
$byteCharsLength = count($byteChars);
// Compute the high-order word
// Initialize from the initial code array (see above), depending on the passwords length.
$highOrderWord = self::$initialCodeArray[$byteCharsLength - 1];
// For each character in the password:
// For every bit in the character, starting with the least significant and progressing to (but excluding)
// the most significant, if the bit is set, XOR the keys high-order word with the corresponding word from
// the Encryption Matrix
for ($i = 0; $i < $byteCharsLength; $i++) {
$tmp = self::$passwordMaxLength - $byteCharsLength + $i;
$matrixRow = self::$encryptionMatrix[$tmp];
for ($intBit = 0; $intBit < 7; $intBit++) {
if (($byteChars[$i] & (0x0001 << $intBit)) != 0) {
$highOrderWord = ($highOrderWord ^ $matrixRow[$intBit]);
}
}
}
// Compute low-order word
// Initialize with 0
$lowOrderWord = 0;
// For each character in the password, going backwards
for ($i = $byteCharsLength - 1; $i >= 0; $i--) {
// low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR character
$lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteChars[$i]);
}
// Lastly, low-order word = (((low-order word SHR 14) AND 0x0001) OR (low-order word SHL 1) AND 0x7FFF)) XOR strPassword length XOR 0xCE4B.
$lowOrderWord = (((($lowOrderWord >> 14) & 0x0001) | (($lowOrderWord << 1) & 0x7FFF)) ^ $byteCharsLength ^ 0xCE4B);
// Combine the Low and High Order Word
return self::int32(($highOrderWord << 16) + $lowOrderWord);
}
/**
* Simulate behaviour of (signed) int32
*
* @codeCoverageIgnore
* @param int $value
* @return int
*/
private static function int32($value)
{
$value = ($value & 0xFFFFFFFF);
if ($value & 0x80000000) {
$value = -((~$value & 0xFFFFFFFF) + 1);
}
return $value;
}
}

View File

@ -39,7 +39,7 @@ class Style
* Add paragraph style * Add paragraph style
* *
* @param string $styleName * @param string $styleName
* @param array $styles * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styles
* @return \PhpOffice\PhpWord\Style\Paragraph * @return \PhpOffice\PhpWord\Style\Paragraph
*/ */
public static function addParagraphStyle($styleName, $styles) public static function addParagraphStyle($styleName, $styles)
@ -51,8 +51,8 @@ class Style
* Add font style * Add font style
* *
* @param string $styleName * @param string $styleName
* @param array $fontStyle * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $fontStyle
* @param array $paragraphStyle * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $paragraphStyle
* @return \PhpOffice\PhpWord\Style\Font * @return \PhpOffice\PhpWord\Style\Font
*/ */
public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = null) public static function addFontStyle($styleName, $fontStyle, $paragraphStyle = null)
@ -64,7 +64,7 @@ class Style
* Add link style * Add link style
* *
* @param string $styleName * @param string $styleName
* @param array $styles * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styles
* @return \PhpOffice\PhpWord\Style\Font * @return \PhpOffice\PhpWord\Style\Font
*/ */
public static function addLinkStyle($styleName, $styles) public static function addLinkStyle($styleName, $styles)
@ -76,7 +76,7 @@ class Style
* Add numbering style * Add numbering style
* *
* @param string $styleName * @param string $styleName
* @param array $styleValues * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styleValues
* @return \PhpOffice\PhpWord\Style\Numbering * @return \PhpOffice\PhpWord\Style\Numbering
* @since 0.10.0 * @since 0.10.0
*/ */
@ -88,14 +88,14 @@ class Style
/** /**
* Add title style * Add title style
* *
* @param int $depth * @param int|null $depth Provide null to set title font
* @param array $fontStyle * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $fontStyle
* @param array $paragraphStyle * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $paragraphStyle
* @return \PhpOffice\PhpWord\Style\Font * @return \PhpOffice\PhpWord\Style\Font
*/ */
public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null) public static function addTitleStyle($depth, $fontStyle, $paragraphStyle = null)
{ {
if ($depth == null) { if (empty($depth)) {
$styleName = 'Title'; $styleName = 'Title';
} else { } else {
$styleName = "Heading_{$depth}"; $styleName = "Heading_{$depth}";
@ -141,7 +141,7 @@ class Style
/** /**
* Set default paragraph style * Set default paragraph style
* *
* @param array $styles Paragraph style definition * @param array|\PhpOffice\PhpWord\Style\AbstractStyle $styles Paragraph style definition
* @return \PhpOffice\PhpWord\Style\Paragraph * @return \PhpOffice\PhpWord\Style\Paragraph
*/ */
public static function setDefaultParagraphStyle($styles) public static function setDefaultParagraphStyle($styles)

View File

@ -46,6 +46,60 @@ class Chart extends AbstractStyle
private $is3d = false; private $is3d = false;
/** /**
* A list of colors to use in the chart
*
* @var array
*/
private $colors = array();
/**
* A list of display options for data labels
*
* @var array
*/
private $dataLabelOptions = array(
'showVal' => true, // value
'showCatName' => true, // category name
'showLegendKey' => false, //show the cart legend
'showSerName' => false, // series name
'showPercent' => false,
'showLeaderLines' => false,
'showBubbleSize' => false,
);
/**
* A string that tells the writer where to write chart labels or to skip
* "nextTo" - sets labels next to the axis (bar graphs on the left) (default)
* "low" - labels on the left side of the graph
* "high" - labels on the right side of the graph
*
* @var string
*/
private $categoryLabelPosition = 'nextTo';
/**
* A string that tells the writer where to write chart labels or to skip
* "nextTo" - sets labels next to the axis (bar graphs on the bottom) (default)
* "low" - labels are below the graph
* "high" - labels above the graph
*
* @var string
*/
private $valueLabelPosition = 'nextTo';
/**
* @var string
*/
private $categoryAxisTitle;
/**
* @var string
*/
private $valueAxisTitle;
private $majorTickMarkPos = 'none';
/*
* Show labels for axis * Show labels for axis
* *
* @var bool * @var bool
@ -146,6 +200,28 @@ class Chart extends AbstractStyle
} }
/** /**
* Get the list of colors to use in a chart.
*
* @return array
*/
public function getColors()
{
return $this->colors;
}
/**
* Set the colors to use in a chart.
*
* @param array $value a list of colors to use in the chart
*/
public function setColors($value = array())
{
$this->colors = $value;
return $this;
}
/*
* Show labels for axis * Show labels for axis
* *
* @return bool * @return bool
@ -169,6 +245,31 @@ class Chart extends AbstractStyle
} }
/** /**
* get the list of options for data labels
*
* @return array
*/
public function getDataLabelOptions()
{
return $this->dataLabelOptions;
}
/**
* Set values for data label options.
* This will only change values for options defined in $this->dataLabelOptions, and cannot create new ones.
*
* @param array $values [description]
*/
public function setDataLabelOptions($values = array())
{
foreach (array_keys($this->dataLabelOptions) as $option) {
if (isset($values[$option])) {
$this->dataLabelOptions[$option] = $this->setBoolVal($values[$option], $this->dataLabelOptions[$option]);
}
}
}
/*
* Show Gridlines for Y-Axis * Show Gridlines for Y-Axis
* *
* @return bool * @return bool
@ -192,6 +293,117 @@ class Chart extends AbstractStyle
} }
/** /**
* Get the categoryLabelPosition setting
*
* @return string
*/
public function getCategoryLabelPosition()
{
return $this->categoryLabelPosition;
}
/**
* Set the categoryLabelPosition setting
* "none" - skips writing labels
* "nextTo" - sets labels next to the (bar graphs on the left)
* "low" - labels on the left side of the graph
* "high" - labels on the right side of the graph
*
* @param mixed $labelPosition
* @return self
*/
public function setCategoryLabelPosition($labelPosition)
{
$enum = array('nextTo', 'low', 'high');
$this->categoryLabelPosition = $this->setEnumVal($labelPosition, $enum, $this->categoryLabelPosition);
return $this;
}
/**
* Get the valueAxisLabelPosition setting
*
* @return string
*/
public function getValueLabelPosition()
{
return $this->valueLabelPosition;
}
/**
* Set the valueLabelPosition setting
* "none" - skips writing labels
* "nextTo" - sets labels next to the value
* "low" - sets labels are below the graph
* "high" - sets labels above the graph
*
* @param string
* @param mixed $labelPosition
*/
public function setValueLabelPosition($labelPosition)
{
$enum = array('nextTo', 'low', 'high');
$this->valueLabelPosition = $this->setEnumVal($labelPosition, $enum, $this->valueLabelPosition);
return $this;
}
/**
* Get the categoryAxisTitle
* @return string
*/
public function getCategoryAxisTitle()
{
return $this->categoryAxisTitle;
}
/**
* Set the title that appears on the category side of the chart
* @param string $axisTitle
*/
public function setCategoryAxisTitle($axisTitle)
{
$this->categoryAxisTitle = $axisTitle;
return $this;
}
/**
* Get the valueAxisTitle
* @return string
*/
public function getValueAxisTitle()
{
return $this->valueAxisTitle;
}
/**
* Set the title that appears on the value side of the chart
* @param string $axisTitle
*/
public function setValueAxisTitle($axisTitle)
{
$this->valueAxisTitle = $axisTitle;
return $this;
}
public function getMajorTickPosition()
{
return $this->majorTickMarkPos;
}
/**
* set the position for major tick marks
* @param string $position [description]
*/
public function setMajorTickPosition($position)
{
$enum = array('in', 'out', 'cross', 'none');
$this->majorTickMarkPos = $this->setEnumVal($position, $enum, $this->majorTickMarkPos);
}
/*
* Show Gridlines for X-Axis * Show Gridlines for X-Axis
* *
* @return bool * @return bool

View File

@ -264,7 +264,7 @@ class Font extends AbstractStyle
* Create new font style * Create new font style
* *
* @param string $type Type of font * @param string $type Type of font
* @param array $paragraph Paragraph styles definition * @param array|string|\PhpOffice\PhpWord\Style\AbstractStyle $paragraph Paragraph styles definition
*/ */
public function __construct($type = 'text', $paragraph = null) public function __construct($type = 'text', $paragraph = null)
{ {

View File

@ -47,6 +47,9 @@ final class Language extends AbstractStyle
const HE_IL = 'he-IL'; const HE_IL = 'he-IL';
const HE_IL_ID = 1037; const HE_IL_ID = 1037;
const IT_IT = 'it-IT';
const IT_IT_ID = 1040;
const JA_JP = 'ja-JP'; const JA_JP = 'ja-JP';
const JA_JP_ID = 1041; const JA_JP_ID = 1041;

View File

@ -17,6 +17,7 @@
namespace PhpOffice\PhpWord\Style; namespace PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType;
use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\Jc;
use PhpOffice\PhpWord\SimpleType\JcTable; use PhpOffice\PhpWord\SimpleType\JcTable;
use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\SimpleType\TblWidth;
@ -159,6 +160,16 @@ class Table extends Border
*/ */
private $position; private $position;
/** @var TblWidthComplexType|null */
private $indent;
/**
* The width of each column, computed based on the max cell width of each column
*
* @var int[]
*/
private $columnWidths;
/** /**
* Create new table style * Create new table style
* *
@ -724,4 +735,44 @@ class Table extends Border
return $this; return $this;
} }
/**
* @return TblWidthComplexType
*/
public function getIndent()
{
return $this->indent;
}
/**
* @param TblWidthComplexType $indent
* @return self
* @see http://www.datypic.com/sc/ooxml/e-w_tblInd-1.html
*/
public function setIndent(TblWidthComplexType $indent)
{
$this->indent = $indent;
return $this;
}
/**
* Get the columnWidths
*
* @return number[]
*/
public function getColumnWidths()
{
return $this->columnWidths;
}
/**
* The column widths
*
* @param int[] $value
*/
public function setColumnWidths(array $value = null)
{
$this->columnWidths = $value;
}
} }

View File

@ -113,6 +113,7 @@ class TemplateProcessor
*/ */
protected function transformSingleXml($xml, $xsltProcessor) protected function transformSingleXml($xml, $xsltProcessor)
{ {
libxml_disable_entity_loader(true);
$domDocument = new \DOMDocument(); $domDocument = new \DOMDocument();
if (false === $domDocument->loadXML($xml)) { if (false === $domDocument->loadXML($xml)) {
throw new Exception('Could not load the given XML document.'); throw new Exception('Could not load the given XML document.');

View File

@ -17,6 +17,10 @@
namespace PhpOffice\PhpWord\Writer\ODText\Element; namespace PhpOffice\PhpWord\Writer\ODText\Element;
use PhpOffice\Common\XMLWriter;
use PhpOffice\PhpWord\Element\Row as RowElement;
use PhpOffice\PhpWord\Element\Table as TableElement;
/** /**
* Table element writer * Table element writer
* *
@ -36,32 +40,59 @@ class Table extends AbstractElement
} }
$rows = $element->getRows(); $rows = $element->getRows();
$rowCount = count($rows); $rowCount = count($rows);
$colCount = $element->countColumns();
if ($rowCount > 0) { if ($rowCount > 0) {
$xmlWriter->startElement('table:table'); $xmlWriter->startElement('table:table');
$xmlWriter->writeAttribute('table:name', $element->getElementId()); $xmlWriter->writeAttribute('table:name', $element->getElementId());
$xmlWriter->writeAttribute('table:style', $element->getElementId()); $xmlWriter->writeAttribute('table:style', $element->getElementId());
$xmlWriter->startElement('table:table-column'); // Write columns
$xmlWriter->writeAttribute('table:number-columns-repeated', $colCount); $this->writeColumns($xmlWriter, $element);
$xmlWriter->endElement(); // table:table-column
// Write rows
foreach ($rows as $row) { foreach ($rows as $row) {
$xmlWriter->startElement('table:table-row'); $this->writeRow($xmlWriter, $row);
/** @var $row \PhpOffice\PhpWord\Element\Row Type hint */
foreach ($row->getCells() as $cell) {
$xmlWriter->startElement('table:table-cell');
$xmlWriter->writeAttribute('office:value-type', 'string');
$containerWriter = new Container($xmlWriter, $cell);
$containerWriter->write();
$xmlWriter->endElement(); // table:table-cell
}
$xmlWriter->endElement(); // table:table-row
} }
$xmlWriter->endElement(); // table:table $xmlWriter->endElement(); // table:table
} }
} }
/**
* Write column.
*
* @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param \PhpOffice\PhpWord\Element\Table $element
*/
private function writeColumns(XMLWriter $xmlWriter, TableElement $element)
{
$colCount = $element->countColumns();
for ($i = 0; $i < $colCount; $i++) {
$xmlWriter->startElement('table:table-column');
$xmlWriter->writeAttribute('table:style-name', $element->getElementId() . '.' . $i);
$xmlWriter->endElement();
}
}
/**
* Write row.
*
* @param \PhpOffice\Common\XMLWriter $xmlWriter
* @param \PhpOffice\PhpWord\Element\Row $row
*/
private function writeRow(XMLWriter $xmlWriter, RowElement $row)
{
$xmlWriter->startElement('table:table-row');
/** @var $row \PhpOffice\PhpWord\Element\Row Type hint */
foreach ($row->getCells() as $cell) {
$xmlWriter->startElement('table:table-cell');
$xmlWriter->writeAttribute('office:value-type', 'string');
$containerWriter = new Container($xmlWriter, $cell);
$containerWriter->write();
$xmlWriter->endElement(); // table:table-cell
}
$xmlWriter->endElement(); // table:table-row
}
} }

View File

@ -239,6 +239,7 @@ class Content extends AbstractPart
$style->setStyleName('fr' . $element->getMediaIndex()); $style->setStyleName('fr' . $element->getMediaIndex());
$this->autoStyles['Image'][] = $style; $this->autoStyles['Image'][] = $style;
} elseif ($element instanceof Table) { } elseif ($element instanceof Table) {
/** @var \PhpOffice\PhpWord\Style\Table $style */
$style = $element->getStyle(); $style = $element->getStyle();
if ($style === null) { if ($style === null) {
$style = new TableStyle(); $style = new TableStyle();
@ -246,6 +247,7 @@ class Content extends AbstractPart
$style = Style::getStyle($style); $style = Style::getStyle($style);
} }
$style->setStyleName($element->getElementId()); $style->setStyleName($element->getElementId());
$style->setColumnWidths($element->findFirstDefinedCellWidths());
$this->autoStyles['Table'][] = $style; $this->autoStyles['Table'][] = $style;
} }
} }

View File

@ -45,5 +45,19 @@ class Table extends AbstractStyle
$xmlWriter->writeAttribute('table:align', 'center'); $xmlWriter->writeAttribute('table:align', 'center');
$xmlWriter->endElement(); // style:table-properties $xmlWriter->endElement(); // style:table-properties
$xmlWriter->endElement(); // style:style $xmlWriter->endElement(); // style:style
$cellWidths = $style->getColumnWidths();
$countCellWidths = count($cellWidths);
for ($i = 0; $i < $countCellWidths; $i++) {
$width = $cellWidths[$i];
$xmlWriter->startElement('style:style');
$xmlWriter->writeAttribute('style:name', $style->getStyleName() . '.' . $i);
$xmlWriter->writeAttribute('style:family', 'table-column');
$xmlWriter->startElement('style:table-column-properties');
$xmlWriter->writeAttribute('style:column-width', number_format($width * 0.0017638889, 2, '.', '') . 'cm');
$xmlWriter->endElement(); // style:table-column-properties
$xmlWriter->endElement(); // style:style
}
} }
} }

View File

@ -0,0 +1,45 @@
<?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.
*
* @see https://github.com/PHPOffice/PHPWord
* @copyright 2010-2018 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\RTF\Style;
/**
* RTF indentation style writer
*
* @since 0.11.0
*/
class Indentation extends AbstractStyle
{
/**
* Write style
*
* @return string
*/
public function write()
{
$style = $this->getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Indentation) {
return '';
}
$content = '\fi' . $style->getFirstLine();
$content .= '\li' . $style->getLeft();
$content .= '\ri' . $style->getRight();
return $content . ' ';
}
}

View File

@ -64,9 +64,49 @@ class Paragraph extends AbstractStyle
if (isset($alignments[$style->getAlignment()])) { if (isset($alignments[$style->getAlignment()])) {
$content .= $alignments[$style->getAlignment()]; $content .= $alignments[$style->getAlignment()];
} }
$content .= $this->writeIndentation($style->getIndentation());
$content .= $this->getValueIf($spaceBefore !== null, '\sb' . $spaceBefore); $content .= $this->getValueIf($spaceBefore !== null, '\sb' . $spaceBefore);
$content .= $this->getValueIf($spaceAfter !== null, '\sa' . $spaceAfter); $content .= $this->getValueIf($spaceAfter !== null, '\sa' . $spaceAfter);
$styles = $style->getStyleValues();
$content .= $this->writeTabs($styles['tabs']);
return $content;
}
/**
* Writes an \PhpOffice\PhpWord\Style\Indentation
*
* @param null|\PhpOffice\PhpWord\Style\Indentation $indent
* @return string
*/
private function writeIndentation($indent = null)
{
if (isset($indent) && $indent instanceof \PhpOffice\PhpWord\Style\Indentation) {
$writer = new Indentation($indent);
return $writer->write();
}
return '';
}
/**
* Writes tabs
*
* @param \PhpOffice\PhpWord\Style\Tab[] $tabs
* @return string
*/
private function writeTabs($tabs = null)
{
$content = '';
if (!empty($tabs)) {
foreach ($tabs as $tab) {
$styleWriter = new Tab($tab);
$content .= $styleWriter->write();
}
}
return $content; return $content;
} }

View File

@ -0,0 +1,49 @@
<?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.
*
* @see https://github.com/PHPOffice/PHPWord
* @copyright 2010-2018 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\RTF\Style;
/**
* Line numbering style writer
*
* @since 0.10.0
*/
class Tab extends AbstractStyle
{
/**
* Write style.
*/
public function write()
{
$style = $this->getStyle();
if (!$style instanceof \PhpOffice\PhpWord\Style\Tab) {
return;
}
$tabs = array(
\PhpOffice\PhpWord\Style\Tab::TAB_STOP_RIGHT => '\tqr',
\PhpOffice\PhpWord\Style\Tab::TAB_STOP_CENTER => '\tqc',
\PhpOffice\PhpWord\Style\Tab::TAB_STOP_DECIMAL => '\tqdec',
);
$content = '';
if (isset($tabs[$style->getType()])) {
$content .= $tabs[$style->getType()];
}
$content .= '\tx' . $style->getPosition();
return $content;
}
}

View File

@ -177,6 +177,9 @@ class Field extends Text
case 'macroname': case 'macroname':
$propertiesAndOptions .= $propval . ' '; $propertiesAndOptions .= $propval . ' ';
break; break;
default:
$propertiesAndOptions .= '"' . $propval . '" ';
break;
} }
} }

View File

@ -76,21 +76,7 @@ class Table extends AbstractElement
*/ */
private function writeColumns(XMLWriter $xmlWriter, TableElement $element) private function writeColumns(XMLWriter $xmlWriter, TableElement $element)
{ {
$rows = $element->getRows(); $cellWidths = $element->findFirstDefinedCellWidths();
$rowCount = count($rows);
$cellWidths = array();
for ($i = 0; $i < $rowCount; $i++) {
$row = $rows[$i];
$cells = $row->getCells();
if (count($cells) <= count($cellWidths)) {
continue;
}
$cellWidths = array();
foreach ($cells as $cell) {
$cellWidths[] = $cell->getWidth();
}
}
$xmlWriter->startElement('w:tblGrid'); $xmlWriter->startElement('w:tblGrid');
foreach ($cellWidths as $width) { foreach ($cellWidths as $width) {

View File

@ -47,6 +47,7 @@ class Title extends AbstractElement
$xmlWriter->endElement(); $xmlWriter->endElement();
} }
$bookmarkRId = null;
if ($element->getDepth() !== 0) { if ($element->getDepth() !== 0) {
$rId = $element->getRelationId(); $rId = $element->getRelationId();
$bookmarkRId = $element->getPhpWord()->addBookmark(); $bookmarkRId = $element->getPhpWord()->addBookmark();

View File

@ -41,14 +41,18 @@ class Chart extends AbstractPart
* @var array * @var array
*/ */
private $types = array( private $types = array(
'pie' => array('type' => 'pie', 'colors' => 1), 'pie' => array('type' => 'pie', 'colors' => 1),
'doughnut' => array('type' => 'doughnut', 'colors' => 1, 'hole' => 75, 'no3d' => true), 'doughnut' => array('type' => 'doughnut', 'colors' => 1, 'hole' => 75, 'no3d' => true),
'bar' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar'), 'bar' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar', 'grouping' => 'clustered'),
'column' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col'), 'stacked_bar' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar', 'grouping' => 'stacked'),
'line' => array('type' => 'line', 'colors' => 0, 'axes' => true), 'percent_stacked_bar' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar', 'grouping' => 'percentStacked'),
'area' => array('type' => 'area', 'colors' => 0, 'axes' => true), 'column' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'clustered'),
'radar' => array('type' => 'radar', 'colors' => 0, 'axes' => true, 'radar' => 'standard', 'no3d' => true), 'stacked_column' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'stacked'),
'scatter' => array('type' => 'scatter', 'colors' => 0, 'axes' => true, 'scatter' => 'marker', 'no3d' => true), 'percent_stacked_column' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col', 'grouping' => 'percentStacked'),
'line' => array('type' => 'line', 'colors' => 0, 'axes' => true),
'area' => array('type' => 'area', 'colors' => 0, 'axes' => true),
'radar' => array('type' => 'radar', 'colors' => 0, 'axes' => true, 'radar' => 'standard', 'no3d' => true),
'scatter' => array('type' => 'scatter', 'colors' => 0, 'axes' => true, 'scatter' => 'marker', 'no3d' => true),
); );
/** /**
@ -145,7 +149,7 @@ class Chart extends AbstractPart
} }
if (isset($this->options['bar'])) { if (isset($this->options['bar'])) {
$xmlWriter->writeElementBlock('c:barDir', 'val', $this->options['bar']); // bar|col $xmlWriter->writeElementBlock('c:barDir', 'val', $this->options['bar']); // bar|col
$xmlWriter->writeElementBlock('c:grouping', 'val', 'clustered'); // 3d; standard = percentStacked $xmlWriter->writeElementBlock('c:grouping', 'val', $this->options['grouping']); // 3d; standard = percentStacked
} }
if (isset($this->options['radar'])) { if (isset($this->options['radar'])) {
$xmlWriter->writeElementBlock('c:radarStyle', 'val', $this->options['radar']); $xmlWriter->writeElementBlock('c:radarStyle', 'val', $this->options['radar']);
@ -157,6 +161,8 @@ class Chart extends AbstractPart
// Series // Series
$this->writeSeries($xmlWriter, isset($this->options['scatter'])); $this->writeSeries($xmlWriter, isset($this->options['scatter']));
$xmlWriter->writeElementBlock('c:overlap', 'val', '100');
// Axes // Axes
if (isset($this->options['axes'])) { if (isset($this->options['axes'])) {
$xmlWriter->writeElementBlock('c:axId', 'val', 1); $xmlWriter->writeElementBlock('c:axId', 'val', 1);
@ -183,6 +189,8 @@ class Chart extends AbstractPart
private function writeSeries(XMLWriter $xmlWriter, $scatter = false) private function writeSeries(XMLWriter $xmlWriter, $scatter = false)
{ {
$series = $this->element->getSeries(); $series = $this->element->getSeries();
$style = $this->element->getStyle();
$colors = $style->getColors();
$index = 0; $index = 0;
foreach ($series as $seriesItem) { foreach ($series as $seriesItem) {
@ -194,6 +202,32 @@ class Chart extends AbstractPart
$xmlWriter->writeElementBlock('c:idx', 'val', $index); $xmlWriter->writeElementBlock('c:idx', 'val', $index);
$xmlWriter->writeElementBlock('c:order', 'val', $index); $xmlWriter->writeElementBlock('c:order', 'val', $index);
if (!is_null($seriesItem['name']) && $seriesItem['name'] != '') {
$xmlWriter->startElement('c:tx');
$xmlWriter->startElement('c:strRef');
$xmlWriter->startElement('c:strCache');
$xmlWriter->writeElementBlock('c:ptCount', 'val', 1);
$xmlWriter->startElement('c:pt');
$xmlWriter->writeAttribute('idx', 0);
$xmlWriter->startElement('c:v');
$xmlWriter->writeRaw($seriesItem['name']);
$xmlWriter->endElement(); // c:v
$xmlWriter->endElement(); // c:pt
$xmlWriter->endElement(); // c:strCache
$xmlWriter->endElement(); // c:strRef
$xmlWriter->endElement(); // c:tx
}
// The c:dLbls was added to make word charts look more like the reports in SurveyGizmo
// This section needs to be made configurable before a pull request is made
$xmlWriter->startElement('c:dLbls');
foreach ($style->getDataLabelOptions() as $option => $val) {
$xmlWriter->writeElementBlock("c:{$option}", 'val', (int) $val);
}
$xmlWriter->endElement(); // c:dLbls
if (isset($this->options['scatter'])) { if (isset($this->options['scatter'])) {
$this->writeShape($xmlWriter); $this->writeShape($xmlWriter);
} }
@ -204,6 +238,26 @@ class Chart extends AbstractPart
} else { } else {
$this->writeSeriesItem($xmlWriter, 'cat', $categories); $this->writeSeriesItem($xmlWriter, 'cat', $categories);
$this->writeSeriesItem($xmlWriter, 'val', $values); $this->writeSeriesItem($xmlWriter, 'val', $values);
// setting the chart colors was taken from https://github.com/PHPOffice/PHPWord/issues/494
if (is_array($colors) && count($colors)) {
// This is a workaround to make each series in a stack chart use a different color
if ($this->options['type'] == 'bar' && stristr($this->options['grouping'], 'stacked')) {
array_shift($colors);
}
$colorIndex = 0;
foreach ($colors as $color) {
$xmlWriter->startElement('c:dPt');
$xmlWriter->writeElementBlock('c:idx', 'val', $colorIndex);
$xmlWriter->startElement('c:spPr');
$xmlWriter->startElement('a:solidFill');
$xmlWriter->writeElementBlock('a:srgbClr', 'val', $color);
$xmlWriter->endElement(); // a:solidFill
$xmlWriter->endElement(); // c:spPr
$xmlWriter->endElement(); // c:dPt
$colorIndex++;
}
}
} }
$xmlWriter->endElement(); // c:ser $xmlWriter->endElement(); // c:ser
@ -230,14 +284,19 @@ class Chart extends AbstractPart
$xmlWriter->startElement($itemType); $xmlWriter->startElement($itemType);
$xmlWriter->startElement($itemLit); $xmlWriter->startElement($itemLit);
$xmlWriter->writeElementBlock('c:ptCount', 'val', count($values));
$index = 0; $index = 0;
foreach ($values as $value) { foreach ($values as $value) {
$xmlWriter->startElement('c:pt'); $xmlWriter->startElement('c:pt');
$xmlWriter->writeAttribute('idx', $index); $xmlWriter->writeAttribute('idx', $index);
$xmlWriter->startElement('c:v'); if (\PhpOffice\PhpWord\Settings::isOutputEscapingEnabled()) {
$xmlWriter->text($value); $xmlWriter->writeElement('c:v', $value);
$xmlWriter->endElement(); // c:v } else {
$xmlWriter->startElement('c:v');
$xmlWriter->writeRaw($value);
$xmlWriter->endElement(); // c:v
}
$xmlWriter->endElement(); // c:pt $xmlWriter->endElement(); // c:pt
$index++; $index++;
} }
@ -266,15 +325,33 @@ class Chart extends AbstractPart
$xmlWriter->writeElementBlock('c:axId', 'val', $axisId); $xmlWriter->writeElementBlock('c:axId', 'val', $axisId);
$xmlWriter->writeElementBlock('c:axPos', 'val', $axisPos); $xmlWriter->writeElementBlock('c:axPos', 'val', $axisPos);
$categoryAxisTitle = $style->getCategoryAxisTitle();
$valueAxisTitle = $style->getValueAxisTitle();
if ($axisType == 'c:catAx') {
if (!is_null($categoryAxisTitle)) {
$this->writeAxisTitle($xmlWriter, $categoryAxisTitle);
}
} elseif ($axisType == 'c:valAx') {
if (!is_null($valueAxisTitle)) {
$this->writeAxisTitle($xmlWriter, $valueAxisTitle);
}
}
$xmlWriter->writeElementBlock('c:crossAx', 'val', $axisCross); $xmlWriter->writeElementBlock('c:crossAx', 'val', $axisCross);
$xmlWriter->writeElementBlock('c:auto', 'val', 1); $xmlWriter->writeElementBlock('c:auto', 'val', 1);
if (isset($this->options['axes'])) { if (isset($this->options['axes'])) {
$xmlWriter->writeElementBlock('c:delete', 'val', 0); $xmlWriter->writeElementBlock('c:delete', 'val', 0);
$xmlWriter->writeElementBlock('c:majorTickMark', 'val', 'none'); $xmlWriter->writeElementBlock('c:majorTickMark', 'val', $style->getMajorTickPosition());
$xmlWriter->writeElementBlock('c:minorTickMark', 'val', 'none'); $xmlWriter->writeElementBlock('c:minorTickMark', 'val', 'none');
if ($style->showAxisLabels()) { if ($style->showAxisLabels()) {
$xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'nextTo'); if ($axisType == 'c:catAx') {
$xmlWriter->writeElementBlock('c:tickLblPos', 'val', $style->getCategoryLabelPosition());
} else {
$xmlWriter->writeElementBlock('c:tickLblPos', 'val', $style->getValueLabelPosition());
}
} else { } else {
$xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'none'); $xmlWriter->writeElementBlock('c:tickLblPos', 'val', 'none');
} }
@ -312,4 +389,30 @@ class Chart extends AbstractPart
$xmlWriter->endElement(); // a:ln $xmlWriter->endElement(); // a:ln
$xmlWriter->endElement(); // c:spPr $xmlWriter->endElement(); // c:spPr
} }
private function writeAxisTitle(XMLWriter $xmlWriter, $title)
{
$xmlWriter->startElement('c:title'); //start c:title
$xmlWriter->startElement('c:tx'); //start c:tx
$xmlWriter->startElement('c:rich'); // start c:rich
$xmlWriter->writeElement('a:bodyPr');
$xmlWriter->writeElement('a:lstStyle');
$xmlWriter->startElement('a:p');
$xmlWriter->startElement('a:pPr');
$xmlWriter->writeElement('a:defRPr');
$xmlWriter->endElement(); // end a:pPr
$xmlWriter->startElement('a:r');
$xmlWriter->writeElementBlock('a:rPr', 'lang', 'en-US');
$xmlWriter->startElement('a:t');
$xmlWriter->writeRaw($title);
$xmlWriter->endElement(); //end a:t
$xmlWriter->endElement(); // end a:r
$xmlWriter->endElement(); //end a:p
$xmlWriter->endElement(); //end c:rich
$xmlWriter->endElement(); // end c:tx
$xmlWriter->writeElementBlock('c:overlay', 'val', '0');
$xmlWriter->endElement(); // end c:title
}
} }

View File

@ -17,9 +17,9 @@
namespace PhpOffice\PhpWord\Writer\Word2007\Part; namespace PhpOffice\PhpWord\Writer\Word2007\Part;
use PhpOffice\Common\Microsoft\PasswordEncoder;
use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\ComplexType\ProofState;
use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\ComplexType\TrackChangesView;
use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder;
use PhpOffice\PhpWord\Style\Language; use PhpOffice\PhpWord\Style\Language;
/** /**

View File

@ -79,6 +79,7 @@ class Table extends AbstractStyle
$this->writeTblWidth($xmlWriter, 'w:tblW', $style->getUnit(), $style->getWidth()); $this->writeTblWidth($xmlWriter, 'w:tblW', $style->getUnit(), $style->getWidth());
$this->writeTblWidth($xmlWriter, 'w:tblCellSpacing', TblWidth::TWIP, $style->getCellSpacing()); $this->writeTblWidth($xmlWriter, 'w:tblCellSpacing', TblWidth::TWIP, $style->getCellSpacing());
$this->writeIndent($xmlWriter, $style);
$this->writeLayout($xmlWriter, $style->getLayout()); $this->writeLayout($xmlWriter, $style->getLayout());
// Position // Position
@ -216,4 +217,19 @@ class Table extends AbstractStyle
{ {
$this->width = $value; $this->width = $value;
} }
/**
* @param XMLWriter $xmlWriter
* @param TableStyle $style
*/
private function writeIndent(XMLWriter $xmlWriter, TableStyle $style)
{
$indent = $style->getIndent();
if ($indent === null) {
return;
}
$this->writeTblWidth($xmlWriter, 'w:tblInd', $indent->getType(), $indent->getValue());
}
} }

View File

@ -126,4 +126,23 @@ class StyleTest extends AbstractTestReader
$fontStyle = $textRun->getElement(0)->getFontStyle(); $fontStyle = $textRun->getElement(0)->getFontStyle();
$this->assertEquals(15, $fontStyle->getPosition()); $this->assertEquals(15, $fontStyle->getPosition());
} }
public function testReadIndent()
{
$documentXml = '<w:tbl>
<w:tblPr>
<w:tblInd w:w="2160" w:type="dxa"/>
</w:tblPr>
</w:tbl>';
$phpWord = $this->getDocumentFromString(array('document' => $documentXml));
$elements = $phpWord->getSection(0)->getElements();
$this->assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]);
$this->assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle());
/** @var \PhpOffice\PhpWord\Style\Table $tableStyle */
$tableStyle = $elements[0]->getStyle();
$this->assertSame(TblWidth::TWIP, $tableStyle->getIndent()->getType());
$this->assertSame(2160, $tableStyle->getIndent()->getValue());
}
} }

File diff suppressed because one or more lines are too long

View File

@ -1,91 +0,0 @@
<?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.
*
* @see https://github.com/PHPOffice/PHPWord
* @copyright 2010-2018 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Shared;
use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder;
use PHPUnit\Framework\TestCase;
/**
* Test class for PhpOffice\PhpWord\Shared\Html
* @coversDefaultClass \PhpOffice\PhpWord\Shared\Html
*/
class PasswordEncoderTest extends \PHPUnit\Framework\TestCase
{
/**
* Test that a password can be hashed without specifying any additional parameters
*/
public function testEncodePassword()
{
//given
$password = 'test';
//when
$hashPassword = PasswordEncoder::hashPassword($password);
//then
TestCase::assertEquals('M795/MAlmGU8RIsY9Q9uDLHC7bk=', $hashPassword);
}
/**
* Test that a password can be hashed with a custom salt
*/
public function testEncodePasswordWithSalt()
{
//given
$password = 'test';
$salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA==');
//when
$hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_SHA_1, $salt);
//then
TestCase::assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword);
}
/**
* Test that the encoder falls back on SHA-1 if a non supported algorithm is given
*/
public function testDafaultsToSha1IfUnsupportedAlgorithm()
{
//given
$password = 'test';
$salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA==');
//when
$hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt);
//then
TestCase::assertEquals('QiDOcpia1YzSVJPiKPwWebl9p/0=', $hashPassword);
}
/**
* Test that the encoder falls back on SHA-1 if a non supported algorithm is given
*/
public function testEncodePasswordWithNullAsciiCodeInPassword()
{
//given
$password = 'test' . chr(0);
$salt = base64_decode('uq81pJRRGFIY5U+E9gt8tA==');
//when
$hashPassword = PasswordEncoder::hashPassword($password, PasswordEncoder::ALGORITHM_MAC, $salt, 1);
//then
TestCase::assertEquals('rDV9sgdDsztoCQlvRCb1lF2wxNg=', $hashPassword);
}
}

View File

@ -0,0 +1,188 @@
<?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.
*
* @see https://github.com/PHPOffice/PHPWord
* @copyright 2010-2017 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Style;
/**
* Test class for PhpOffice\PhpWord\Style\Chart
*
* @coversDefaultClass \PhpOffice\PhpWord\Style\Chart
* @runTestsInSeparateProcesses
*/
class ChartTest extends \PHPUnit\Framework\TestCase
{
/**
* Testing getter and setter for chart width
*/
public function testSetGetWidth()
{
$chart = new Chart();
$this->assertEquals($chart->getWidth(), 1000000);
$chart->setWidth(200);
$this->assertEquals($chart->getWidth(), 200);
}
/**
* Testing getter and setter for chart height
*/
public function testSetGetHeight()
{
$chart = new Chart();
$this->assertEquals($chart->getHeight(), 1000000);
$chart->setHeight(200);
$this->assertEquals($chart->getHeight(), 200);
}
/**
* Testing getter and setter for is3d
*/
public function testSetIs3d()
{
$chart = new Chart();
$this->assertEquals($chart->is3d(), false);
$chart->set3d(true);
$this->assertEquals($chart->is3d(), true);
}
/**
* Testing getter and setter for chart colors
*/
public function testSetGetColors()
{
$chart = new Chart();
$this->assertInternalType('array', $chart->getColors());
$this->assertEquals(count($chart->getColors()), 0);
$chart->setColors(array('FFFFFFFF', 'FF000000', 'FFFF0000'));
$this->assertEquals($chart->getColors(), array('FFFFFFFF', 'FF000000', 'FFFF0000'));
}
/**
* Testing getter and setter for dataLabelOptions
*/
public function testSetGetDataLabelOptions()
{
$chart = new Chart();
$originalDataLabelOptions = array(
'showVal' => true,
'showCatName' => true,
'showLegendKey' => false,
'showSerName' => false,
'showPercent' => false,
'showLeaderLines' => false,
'showBubbleSize' => false,
);
$this->assertEquals($chart->getDataLabelOptions(), $originalDataLabelOptions);
$changedDataLabelOptions = array(
'showVal' => false,
'showCatName' => false,
'showLegendKey' => true,
'showSerName' => true,
'showPercent' => true,
'showLeaderLines' => true,
'showBubbleSize' => true,
);
$chart->setDataLabelOptions(
array(
'showVal' => false,
'showCatName' => false,
'showLegendKey' => true,
'showSerName' => true,
'showPercent' => true,
'showLeaderLines' => true,
'showBubbleSize' => true,
)
);
$this->assertEquals($chart->getDataLabelOptions(), $changedDataLabelOptions);
}
/**
* Testing categoryLabelPosition getter and setter
*/
public function testSetGetCategoryLabelPosition()
{
$chart = new Chart();
$this->assertEquals($chart->getCategoryLabelPosition(), 'nextTo');
$chart->setCategoryLabelPosition('high');
$this->assertEquals($chart->getCategoryLabelPosition(), 'high');
}
/**
* Testing valueLabelPosition getter and setter
*/
public function testSetGetValueLabelPosition()
{
$chart = new Chart();
$this->assertEquals($chart->getValueLabelPosition(), 'nextTo');
$chart->setValueLabelPosition('low');
$this->assertEquals($chart->getValueLabelPosition(), 'low');
}
/**
* Testing categoryAxisTitle getter and setter
*/
public function testSetGetCategoryAxisTitle()
{
$chart = new Chart();
$chart->getCategoryAxisTitle();
$this->assertEquals($chart->getCategoryAxisTitle(), null);
$chart->setCategoryAxisTitle('Test Category Axis Title');
$this->assertEquals($chart->getCategoryAxisTitle(), 'Test Category Axis Title');
}
/**
* Testing valueAxisTitle getter and setter
*/
public function testSetGetValueAxisTitle()
{
$chart = new Chart();
$chart->getValueAxisTitle();
$this->assertEquals($chart->getValueAxisTitle(), null);
$chart->setValueAxisTitle('Test Value Axis Title');
$this->assertEquals($chart->getValueAxisTitle(), 'Test Value Axis Title');
}
}

View File

@ -17,7 +17,6 @@
namespace PhpOffice\PhpWord\Style; namespace PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\TestHelperDOCX; use PhpOffice\PhpWord\TestHelperDOCX;
/** /**

View File

@ -17,6 +17,7 @@
namespace PhpOffice\PhpWord\Style; namespace PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType;
use PhpOffice\PhpWord\SimpleType\JcTable; use PhpOffice\PhpWord\SimpleType\JcTable;
use PhpOffice\PhpWord\SimpleType\TblWidth; use PhpOffice\PhpWord\SimpleType\TblWidth;
@ -57,6 +58,7 @@ class TableTest extends \PHPUnit\Framework\TestCase
$this->assertNull($object->getBgColor()); $this->assertNull($object->getBgColor());
$this->assertEquals(Table::LAYOUT_AUTO, $object->getLayout()); $this->assertEquals(Table::LAYOUT_AUTO, $object->getLayout());
$this->assertEquals(TblWidth::AUTO, $object->getUnit()); $this->assertEquals(TblWidth::AUTO, $object->getUnit());
$this->assertNull($object->getIndent());
} }
/** /**
@ -208,4 +210,13 @@ class TableTest extends \PHPUnit\Framework\TestCase
$this->assertNotNull($object->getPosition()); $this->assertNotNull($object->getPosition());
$this->assertEquals(TablePosition::VANCHOR_PAGE, $object->getPosition()->getVertAnchor()); $this->assertEquals(TablePosition::VANCHOR_PAGE, $object->getPosition()->getVertAnchor());
} }
public function testIndent()
{
$indent = new TblWidthComplexType(100, TblWidth::TWIP);
$table = new Table(array('indent' => $indent));
$this->assertSame($indent, $table->getIndent());
}
} }

View File

@ -70,7 +70,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$text2->setTrackChange(new TrackChange(TrackChange::DELETED, 'another author', new \DateTime())); $text2->setTrackChange(new TrackChange(TrackChange::DELETED, 'another author', new \DateTime()));
$dom = $this->getAsHTML($phpWord); $dom = $this->getAsHTML($phpWord);
$xpath = new \DOMXpath($dom); $xpath = new \DOMXPath($dom);
$this->assertTrue($xpath->query('/html/body/p[1]/ins')->length == 1); $this->assertTrue($xpath->query('/html/body/p[1]/ins')->length == 1);
$this->assertTrue($xpath->query('/html/body/p[2]/del')->length == 1); $this->assertTrue($xpath->query('/html/body/p[2]/del')->length == 1);
@ -94,7 +94,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$cell22->addText('second cell'); $cell22->addText('second cell');
$dom = $this->getAsHTML($phpWord); $dom = $this->getAsHTML($phpWord);
$xpath = new \DOMXpath($dom); $xpath = new \DOMXPath($dom);
$this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 1); $this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 1);
$this->assertEquals('2', $xpath->query('/html/body/table/tr/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent); $this->assertEquals('2', $xpath->query('/html/body/table/tr/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent);
@ -123,7 +123,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$row3->addCell(500)->addText('third cell being spanned'); $row3->addCell(500)->addText('third cell being spanned');
$dom = $this->getAsHTML($phpWord); $dom = $this->getAsHTML($phpWord);
$xpath = new \DOMXpath($dom); $xpath = new \DOMXPath($dom);
$this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 2); $this->assertTrue($xpath->query('/html/body/table/tr[1]/td')->length == 2);
$this->assertEquals('3', $xpath->query('/html/body/table/tr[1]/td[1]')->item(0)->attributes->getNamedItem('rowspan')->textContent); $this->assertEquals('3', $xpath->query('/html/body/table/tr[1]/td[1]')->item(0)->attributes->getNamedItem('rowspan')->textContent);

View File

@ -17,7 +17,9 @@
namespace PhpOffice\PhpWord\Writer\RTF; namespace PhpOffice\PhpWord\Writer\RTF;
use PhpOffice\PhpWord\Writer\RTF;
use PhpOffice\PhpWord\Writer\RTF\Style\Border; use PhpOffice\PhpWord\Writer\RTF\Style\Border;
use PHPUnit\Framework\Assert;
/** /**
* Test class for PhpOffice\PhpWord\Writer\RTF\Style subnamespace * Test class for PhpOffice\PhpWord\Writer\RTF\Style subnamespace
@ -29,7 +31,7 @@ class StyleTest extends \PHPUnit\Framework\TestCase
*/ */
public function testEmptyStyles() public function testEmptyStyles()
{ {
$styles = array('Font', 'Paragraph', 'Section'); $styles = array('Font', 'Paragraph', 'Section', 'Tab', 'Indentation');
foreach ($styles as $style) { foreach ($styles as $style) {
$objectClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Style\\' . $style; $objectClass = 'PhpOffice\\PhpWord\\Writer\\RTF\\Style\\' . $style;
$object = new $objectClass(); $object = new $objectClass();
@ -55,4 +57,55 @@ class StyleTest extends \PHPUnit\Framework\TestCase
$this->assertEquals($expected, $content); $this->assertEquals($expected, $content);
} }
public function testIndentation()
{
$indentation = new \PhpOffice\PhpWord\Style\Indentation();
$indentation->setLeft(1);
$indentation->setRight(2);
$indentation->setFirstLine(3);
$indentWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Indentation($indentation);
$indentWriter->setParentWriter(new RTF());
$result = $indentWriter->write();
Assert::assertEquals('\fi3\li1\ri2 ', $result);
}
public function testRightTab()
{
$tabRight = new \PhpOffice\PhpWord\Style\Tab();
$tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_RIGHT);
$tabRight->setPosition(5);
$tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight);
$tabWriter->setParentWriter(new RTF());
$result = $tabWriter->write();
Assert::assertEquals('\tqr\tx5', $result);
}
public function testCenterTab()
{
$tabRight = new \PhpOffice\PhpWord\Style\Tab();
$tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_CENTER);
$tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight);
$tabWriter->setParentWriter(new RTF());
$result = $tabWriter->write();
Assert::assertEquals('\tqc\tx0', $result);
}
public function testDecimalTab()
{
$tabRight = new \PhpOffice\PhpWord\Style\Tab();
$tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_DECIMAL);
$tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight);
$tabWriter->setParentWriter(new RTF());
$result = $tabWriter->write();
Assert::assertEquals('\tqdec\tx0', $result);
}
} }

View File

@ -256,7 +256,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase
{ {
$phpWord = new PhpWord(); $phpWord = new PhpWord();
$section = $phpWord->addSection(); $section = $phpWord->addSection();
$style = array('width' => 1000000, 'height' => 1000000); $style = array('width' => 1000000, 'height' => 1000000, 'showAxisLabels' => true, 'showGridX' => true, 'showGridY' => true);
$chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar');
$categories = array('A', 'B', 'C', 'D', 'E'); $categories = array('A', 'B', 'C', 'D', 'E');
@ -288,6 +288,7 @@ class ElementTest extends \PHPUnit\Framework\TestCase
$section->addField('DATE', array(), array('LunarCalendar')); $section->addField('DATE', array(), array('LunarCalendar'));
$section->addField('DATE', array(), array('SakaEraCalendar')); $section->addField('DATE', array(), array('SakaEraCalendar'));
$section->addField('NUMPAGES', array('format' => 'roman', 'numformat' => '0,00'), array('SakaEraCalendar')); $section->addField('NUMPAGES', array('format' => 'roman', 'numformat' => '0,00'), array('SakaEraCalendar'));
$section->addField('STYLEREF', array('StyleIdentifier' => 'Heading 1'));
$doc = TestHelperDOCX::getDocument($phpWord); $doc = TestHelperDOCX::getDocument($phpWord);
$element = '/w:document/w:body/w:p/w:r/w:instrText'; $element = '/w:document/w:body/w:p/w:r/w:instrText';

View File

@ -17,11 +17,10 @@
namespace PhpOffice\PhpWord\Writer\Word2007\Part; namespace PhpOffice\PhpWord\Writer\Word2007\Part;
use PhpOffice\Common\Microsoft\PasswordEncoder;
use PhpOffice\PhpWord\ComplexType\ProofState; use PhpOffice\PhpWord\ComplexType\ProofState;
use PhpOffice\PhpWord\ComplexType\TrackChangesView; use PhpOffice\PhpWord\ComplexType\TrackChangesView;
use PhpOffice\PhpWord\PhpWord; use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\Microsoft\PasswordEncoder;
use PhpOffice\PhpWord\SimpleType\Zoom; use PhpOffice\PhpWord\SimpleType\Zoom;
use PhpOffice\PhpWord\Style\Language; use PhpOffice\PhpWord\Style\Language;
use PhpOffice\PhpWord\TestHelperDOCX; use PhpOffice\PhpWord\TestHelperDOCX;

View File

@ -43,7 +43,7 @@ class FontTest extends \PHPUnit\Framework\TestCase
$phpWord = new \PhpOffice\PhpWord\PhpWord(); $phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection(); $section = $phpWord->addSection();
$textrun = $section->addTextRun(); $textrun = $section->addTextRun();
$textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true)); $textrun->addText('سلام این یک پاراگراف راست به چپ است', array('rtl' => true, 'lang' => 'ar-DZ'));
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$file = 'word/document.xml'; $file = 'word/document.xml';

View File

@ -17,6 +17,8 @@
namespace PhpOffice\PhpWord\Writer\Word2007\Style; namespace PhpOffice\PhpWord\Writer\Word2007\Style;
use PhpOffice\PhpWord\ComplexType\TblWidth as TblWidthComplexType;
use PhpOffice\PhpWord\SimpleType\TblWidth;
use PhpOffice\PhpWord\Style\Table; use PhpOffice\PhpWord\Style\Table;
use PhpOffice\PhpWord\Style\TablePosition; use PhpOffice\PhpWord\Style\TablePosition;
use PhpOffice\PhpWord\TestHelperDOCX; use PhpOffice\PhpWord\TestHelperDOCX;
@ -75,7 +77,7 @@ class TableTest extends \PHPUnit\Framework\TestCase
$path = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing'; $path = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing';
$this->assertTrue($doc->elementExists($path)); $this->assertTrue($doc->elementExists($path));
$this->assertEquals(10.3, $doc->getElementAttribute($path, 'w:w')); $this->assertEquals(10.3, $doc->getElementAttribute($path, 'w:w'));
$this->assertEquals(\PhpOffice\PhpWord\SimpleType\TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); $this->assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type'));
} }
/** /**
@ -118,4 +120,25 @@ class TableTest extends \PHPUnit\Framework\TestCase
$this->assertEquals(TablePosition::YALIGN_TOP, $doc->getElementAttribute($path, 'w:tblpYSpec')); $this->assertEquals(TablePosition::YALIGN_TOP, $doc->getElementAttribute($path, 'w:tblpYSpec'));
$this->assertEquals(60, $doc->getElementAttribute($path, 'w:tblpY')); $this->assertEquals(60, $doc->getElementAttribute($path, 'w:tblpY'));
} }
public function testIndent()
{
$value = 100;
$type = TblWidth::TWIP;
$tableStyle = new Table();
$tableStyle->setIndent(new TblWidthComplexType($value, $type));
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
$table = $section->addTable($tableStyle);
$table->addRow();
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$path = '/w:document/w:body/w:tbl/w:tblPr/w:tblInd';
$this->assertTrue($doc->elementExists($path));
$this->assertSame($value, (int) $doc->getElementAttribute($path, 'w:w'));
$this->assertSame($type, $doc->getElementAttribute($path, 'w:type'));
}
} }

View File

@ -37,9 +37,9 @@ class XmlDocument
private $dom; private $dom;
/** /**
* DOMXpath object * DOMXPath object
* *
* @var \DOMXpath * @var \DOMXPath
*/ */
private $xpath; private $xpath;
@ -76,8 +76,10 @@ class XmlDocument
$this->file = $file; $this->file = $file;
$file = $this->path . '/' . $file; $file = $this->path . '/' . $file;
libxml_disable_entity_loader(false);
$this->dom = new \DOMDocument(); $this->dom = new \DOMDocument();
$this->dom->load($file); $this->dom->load($file);
libxml_disable_entity_loader(true);
return $this->dom; return $this->dom;
} }
@ -96,7 +98,7 @@ class XmlDocument
} }
if (null === $this->xpath) { if (null === $this->xpath) {
$this->xpath = new \DOMXpath($this->dom); $this->xpath = new \DOMXPath($this->dom);
$this->xpath->registerNamespace('w14', 'http://schemas.microsoft.com/office/word/2010/wordml'); $this->xpath->registerNamespace('w14', 'http://schemas.microsoft.com/office/word/2010/wordml');
} }