#483. Output escaping for RTF.
This commit is contained in:
parent
649da97a42
commit
3f1e0ac4a7
|
|
@ -13,6 +13,7 @@ Place announcement text here.
|
||||||
- Introduced writer for the "Paragraph Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment`). - @RomanSyroeshko
|
- Introduced writer for the "Paragraph Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\ParagraphAlignment`). - @RomanSyroeshko
|
||||||
- Introduced writer for the "Table Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment`). - @RomanSyroeshko
|
- Introduced writer for the "Table Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment`). - @RomanSyroeshko
|
||||||
- Supported indexed arrays in arguments of `TemplateProcessor::setValue()`. - @RomanSyroeshko #618
|
- Supported indexed arrays in arguments of `TemplateProcessor::setValue()`. - @RomanSyroeshko #618
|
||||||
|
- Introduced automatic output escaping for OOXML, ODF, HTML, and RTF. To turn the feature on use `phpword.ini` or `\PhpOffice\PhpWord\Settings`. - @RomanSyroeshko #483
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371
|
- Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371
|
||||||
|
|
|
||||||
|
|
@ -25,22 +25,22 @@ namespace PhpOffice\PhpWord\Escaper;
|
||||||
abstract class AbstractEscaper implements EscaperInterface
|
abstract class AbstractEscaper implements EscaperInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param string $subject
|
* @param string $input
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
abstract protected function escapeSingleValue($subject);
|
abstract protected function escapeSingleValue($input);
|
||||||
|
|
||||||
public function escape($subject)
|
public function escape($input)
|
||||||
{
|
{
|
||||||
if (is_array($subject)) {
|
if (is_array($input)) {
|
||||||
foreach ($subject as &$item) {
|
foreach ($input as &$item) {
|
||||||
$item = $this->escapeSingleValue($item);
|
$item = $this->escapeSingleValue($item);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$subject = $this->escapeSingleValue($subject);
|
$input = $this->escapeSingleValue($input);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $subject;
|
return $input;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,9 @@ namespace PhpOffice\PhpWord\Escaper;
|
||||||
interface EscaperInterface
|
interface EscaperInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @param mixed $subject
|
* @param mixed $input
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function escape($subject);
|
public function escape($input);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ class RegExp extends AbstractEscaper
|
||||||
{
|
{
|
||||||
const REG_EXP_DELIMITER = '/';
|
const REG_EXP_DELIMITER = '/';
|
||||||
|
|
||||||
protected function escapeSingleValue($subject)
|
protected function escapeSingleValue($input)
|
||||||
{
|
{
|
||||||
return self::REG_EXP_DELIMITER . preg_quote($subject, self::REG_EXP_DELIMITER) . self::REG_EXP_DELIMITER . 'u';
|
return self::REG_EXP_DELIMITER . preg_quote($input, self::REG_EXP_DELIMITER) . self::REG_EXP_DELIMITER . 'u';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
|
* word processing documents.
|
||||||
|
*
|
||||||
|
* PHPWord is free software distributed under the terms of the GNU Lesser
|
||||||
|
* General Public License version 3 as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please read the LICENSE
|
||||||
|
* file that was distributed with this source code. For the full list of
|
||||||
|
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
|
||||||
|
*
|
||||||
|
* @link https://github.com/PHPOffice/PHPWord
|
||||||
|
* @copyright 2010-2016 PHPWord contributors
|
||||||
|
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace PhpOffice\PhpWord\Escaper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @since 0.13.0
|
||||||
|
*
|
||||||
|
* @codeCoverageIgnore
|
||||||
|
*/
|
||||||
|
class Rtf extends AbstractEscaper
|
||||||
|
{
|
||||||
|
protected function escapeAsciiCharacter($code) {
|
||||||
|
if (20 > $code || $code >= 80) {
|
||||||
|
return '{\u' . $code . '}';
|
||||||
|
} else {
|
||||||
|
return chr($code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function escapeMultibyteCharacter($code) {
|
||||||
|
return '\uc0{\u' . $code . '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see http://www.randomchaos.com/documents/?source=php_and_unicode
|
||||||
|
*/
|
||||||
|
protected function escapeSingleValue($input)
|
||||||
|
{
|
||||||
|
$escapedValue = '';
|
||||||
|
|
||||||
|
$numberOfBytes = 1;
|
||||||
|
$bytes = array();
|
||||||
|
for ($i = 0; $i < strlen($input); ++$i) {
|
||||||
|
$character = $input[$i];
|
||||||
|
$asciiCode = ord($character);
|
||||||
|
|
||||||
|
if ($asciiCode < 128) {
|
||||||
|
$escapedValue .= $this->escapeAsciiCharacter($asciiCode);
|
||||||
|
} else {
|
||||||
|
if (0 == count($bytes)) {
|
||||||
|
if ($asciiCode < 224) {
|
||||||
|
$numberOfBytes = 2;
|
||||||
|
} else if ($asciiCode < 240) {
|
||||||
|
$numberOfBytes = 3;
|
||||||
|
} else if ($asciiCode < 248) {
|
||||||
|
$numberOfBytes = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$bytes[] = $asciiCode;
|
||||||
|
|
||||||
|
if ($numberOfBytes == count($bytes)) {
|
||||||
|
if (4 == $numberOfBytes) {
|
||||||
|
$multibyteCode = ($bytes[0] % 8) * 262144 + ($bytes[1] % 64) * 4096 + ($bytes[2] % 64) * 64 + ($bytes[3] % 64);
|
||||||
|
} elseif (3 == $numberOfBytes) {
|
||||||
|
$multibyteCode = ($bytes[0] % 16) * 4096 + ($bytes[1] % 64) * 64 + ($bytes[2] % 64);
|
||||||
|
} else {
|
||||||
|
$multibyteCode = ($bytes[0] % 32) * 64 + ($bytes[1] % 64);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (65279 != $multibyteCode) {
|
||||||
|
$escapedValue .= $multibyteCode < 128 ? $this->escapeAsciiCharacter($multibyteCode) : $this->escapeMultibyteCharacter($multibyteCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
$numberOfBytes = 1;
|
||||||
|
$bytes = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $escapedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,9 +24,9 @@ namespace PhpOffice\PhpWord\Escaper;
|
||||||
*/
|
*/
|
||||||
class Xml extends AbstractEscaper
|
class Xml extends AbstractEscaper
|
||||||
{
|
{
|
||||||
protected function escapeSingleValue($subject)
|
protected function escapeSingleValue($input)
|
||||||
{
|
{
|
||||||
// todo: omit encoding parameter after migration onto PHP 5.4
|
// todo: omit encoding parameter after migration onto PHP 5.4
|
||||||
return htmlspecialchars($subject, ENT_QUOTES, 'UTF-8');
|
return htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,15 +22,11 @@ use PhpOffice\PhpWord\Writer\AbstractWriter;
|
||||||
use Zend\Escaper\Escaper;
|
use Zend\Escaper\Escaper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract HTML part writer
|
|
||||||
*
|
|
||||||
* @since 0.11.0
|
* @since 0.11.0
|
||||||
*/
|
*/
|
||||||
abstract class AbstractPart
|
abstract class AbstractPart
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Parent writer
|
|
||||||
*
|
|
||||||
* @var \PhpOffice\PhpWord\Writer\AbstractWriter
|
* @var \PhpOffice\PhpWord\Writer\AbstractWriter
|
||||||
*/
|
*/
|
||||||
private $parentWriter;
|
private $parentWriter;
|
||||||
|
|
@ -46,16 +42,13 @@ abstract class AbstractPart
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write part
|
|
||||||
*
|
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
abstract public function write();
|
abstract public function write();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set parent writer.
|
|
||||||
*
|
|
||||||
* @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer
|
* @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer
|
||||||
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setParentWriter(AbstractWriter $writer = null)
|
public function setParentWriter(AbstractWriter $writer = null)
|
||||||
|
|
@ -64,8 +57,6 @@ abstract class AbstractPart
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get parent writer
|
|
||||||
*
|
|
||||||
* @return \PhpOffice\PhpWord\Writer\AbstractWriter
|
* @return \PhpOffice\PhpWord\Writer\AbstractWriter
|
||||||
*
|
*
|
||||||
* @throws \PhpOffice\PhpWord\Exception\Exception
|
* @throws \PhpOffice\PhpWord\Exception\Exception
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,13 @@
|
||||||
namespace PhpOffice\PhpWord\Writer\RTF\Element;
|
namespace PhpOffice\PhpWord\Writer\RTF\Element;
|
||||||
|
|
||||||
use PhpOffice\Common\Text as CommonText;
|
use PhpOffice\Common\Text as CommonText;
|
||||||
|
use PhpOffice\PhpWord\Element\AbstractElement as Element;
|
||||||
|
use PhpOffice\PhpWord\Escaper\Rtf;
|
||||||
|
use PhpOffice\PhpWord\Settings;
|
||||||
use PhpOffice\PhpWord\Style;
|
use PhpOffice\PhpWord\Style;
|
||||||
use PhpOffice\PhpWord\Style\Font as FontStyle;
|
use PhpOffice\PhpWord\Style\Font as FontStyle;
|
||||||
use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle;
|
use PhpOffice\PhpWord\Style\Paragraph as ParagraphStyle;
|
||||||
|
use PhpOffice\PhpWord\Writer\AbstractWriter;
|
||||||
use PhpOffice\PhpWord\Writer\HTML\Element\AbstractElement as HTMLAbstractElement;
|
use PhpOffice\PhpWord\Writer\HTML\Element\AbstractElement as HTMLAbstractElement;
|
||||||
use PhpOffice\PhpWord\Writer\RTF\Style\Font as FontStyleWriter;
|
use PhpOffice\PhpWord\Writer\RTF\Style\Font as FontStyleWriter;
|
||||||
use PhpOffice\PhpWord\Writer\RTF\Style\Paragraph as ParagraphStyleWriter;
|
use PhpOffice\PhpWord\Writer\RTF\Style\Paragraph as ParagraphStyleWriter;
|
||||||
|
|
@ -46,6 +50,13 @@ abstract class AbstractElement extends HTMLAbstractElement
|
||||||
*/
|
*/
|
||||||
private $paragraphStyle;
|
private $paragraphStyle;
|
||||||
|
|
||||||
|
public function __construct(AbstractWriter $parentWriter, Element $element, $withoutP)
|
||||||
|
{
|
||||||
|
parent::__construct($parentWriter, $element, $withoutP);
|
||||||
|
|
||||||
|
$this->escaper = new Rtf();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get font and paragraph styles.
|
* Get font and paragraph styles.
|
||||||
*
|
*
|
||||||
|
|
@ -112,7 +123,11 @@ abstract class AbstractElement extends HTMLAbstractElement
|
||||||
*/
|
*/
|
||||||
protected function writeText($text)
|
protected function writeText($text)
|
||||||
{
|
{
|
||||||
return CommonText::toUnicode($text);
|
if (Settings::isOutputEscapingEnabled()) {
|
||||||
|
return $this->escaper->escape($text);
|
||||||
|
} else {
|
||||||
|
return CommonText::toUnicode($text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,56 @@
|
||||||
|
|
||||||
namespace PhpOffice\PhpWord\Writer\RTF\Part;
|
namespace PhpOffice\PhpWord\Writer\RTF\Part;
|
||||||
|
|
||||||
use PhpOffice\PhpWord\Writer\HTML\Part\AbstractPart as HTMLAbstractPart;
|
use PhpOffice\PhpWord\Escaper\Rtf;
|
||||||
|
use PhpOffice\PhpWord\Exception\Exception;
|
||||||
|
use PhpOffice\PhpWord\Writer\AbstractWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract RTF part writer
|
|
||||||
*
|
|
||||||
* @since 0.11.0
|
* @since 0.11.0
|
||||||
*/
|
*/
|
||||||
abstract class AbstractPart extends HTMLAbstractPart
|
abstract class AbstractPart
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* @var \PhpOffice\PhpWord\Writer\AbstractWriter
|
||||||
|
*/
|
||||||
|
private $parentWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \PhpOffice\PhpWord\Escaper\EscaperInterface
|
||||||
|
*/
|
||||||
|
protected $escaper;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->escaper = new Rtf();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract public function write();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setParentWriter(AbstractWriter $writer = null)
|
||||||
|
{
|
||||||
|
$this->parentWriter = $writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \PhpOffice\PhpWord\Writer\AbstractWriter
|
||||||
|
*
|
||||||
|
* @throws \PhpOffice\PhpWord\Exception\Exception
|
||||||
|
*/
|
||||||
|
public function getParentWriter()
|
||||||
|
{
|
||||||
|
if ($this->parentWriter !== null) {
|
||||||
|
return $this->parentWriter;
|
||||||
|
} else {
|
||||||
|
throw new Exception('No parent WriterInterface assigned.');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,11 @@ class Document extends AbstractPart
|
||||||
$content .= '\info';
|
$content .= '\info';
|
||||||
foreach ($properties as $property) {
|
foreach ($properties as $property) {
|
||||||
$method = 'get' . (isset($mapping[$property]) ? $mapping[$property] : $property);
|
$method = 'get' . (isset($mapping[$property]) ? $mapping[$property] : $property);
|
||||||
$value = $docProps->$method();
|
if (!in_array($property, $dateFields) && Settings::isOutputEscapingEnabled()) {
|
||||||
|
$value = $this->escaper->escape($docProps->$method());
|
||||||
|
} else {
|
||||||
|
$value = $docProps->$method();
|
||||||
|
}
|
||||||
$value = in_array($property, $dateFields) ? $this->getDateValue($value) : $value;
|
$value = in_array($property, $dateFields) ? $this->getDateValue($value) : $value;
|
||||||
$content .= "{\\{$property} {$value}}";
|
$content .= "{\\{$property} {$value}}";
|
||||||
}
|
}
|
||||||
|
|
@ -105,7 +109,6 @@ class Document extends AbstractPart
|
||||||
*/
|
*/
|
||||||
private function writeSections()
|
private function writeSections()
|
||||||
{
|
{
|
||||||
|
|
||||||
$content = '';
|
$content = '';
|
||||||
|
|
||||||
$sections = $this->getParentWriter()->getPhpWord()->getSections();
|
$sections = $this->getParentWriter()->getPhpWord()->getSections();
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ class Header extends AbstractPart
|
||||||
{
|
{
|
||||||
$content = '';
|
$content = '';
|
||||||
|
|
||||||
$content .= '{\*\generator PhpWord;}'; // Set the generator
|
$content .= '{\*\generator PHPWord;}'; // Set the generator
|
||||||
$content .= PHP_EOL;
|
$content .= PHP_EOL;
|
||||||
|
|
||||||
return $content;
|
return $content;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue