Skip to content

Commit

Permalink
#483. Output escaping for RTF.
Browse files Browse the repository at this point in the history
  • Loading branch information
Roman Syroeshko committed Jul 8, 2016
1 parent 649da97 commit 3f1e0ac
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 31 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 "Table Alignment" element (see `\PhpOffice\PhpWord\Writer\Word2007\Element\TableAlignment`). - @RomanSyroeshko
- 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
- Improved error message for the case when `autoload.php` is not found. - @RomanSyroeshko #371
Expand Down
14 changes: 7 additions & 7 deletions src/PhpWord/Escaper/AbstractEscaper.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,22 @@
abstract class AbstractEscaper implements EscaperInterface
{
/**
* @param string $subject
* @param string $input
*
* @return string
*/
abstract protected function escapeSingleValue($subject);
abstract protected function escapeSingleValue($input);

public function escape($subject)
public function escape($input)
{
if (is_array($subject)) {
foreach ($subject as &$item) {
if (is_array($input)) {
foreach ($input as &$item) {
$item = $this->escapeSingleValue($item);
}
} else {
$subject = $this->escapeSingleValue($subject);
$input = $this->escapeSingleValue($input);
}

return $subject;
return $input;
}
}
4 changes: 2 additions & 2 deletions src/PhpWord/Escaper/EscaperInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
interface EscaperInterface
{
/**
* @param mixed $subject
* @param mixed $input
*
* @return mixed
*/
public function escape($subject);
public function escape($input);
}
4 changes: 2 additions & 2 deletions src/PhpWord/Escaper/RegExp.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ class RegExp extends AbstractEscaper
{
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';
}
}
88 changes: 88 additions & 0 deletions src/PhpWord/Escaper/Rtf.php
Original file line number Diff line number Diff line change
@@ -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:https://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:https://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;
}
}
4 changes: 2 additions & 2 deletions src/PhpWord/Escaper/Xml.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@
*/
class Xml extends AbstractEscaper
{
protected function escapeSingleValue($subject)
protected function escapeSingleValue($input)
{
// todo: omit encoding parameter after migration onto PHP 5.4
return htmlspecialchars($subject, ENT_QUOTES, 'UTF-8');
return htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
}
}
11 changes: 1 addition & 10 deletions src/PhpWord/Writer/HTML/Part/AbstractPart.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,11 @@
use Zend\Escaper\Escaper;

/**
* Abstract HTML part writer
*
* @since 0.11.0
*/
abstract class AbstractPart
{
/**
* Parent writer
*
* @var \PhpOffice\PhpWord\Writer\AbstractWriter
*/
private $parentWriter;
Expand All @@ -46,16 +42,13 @@ public function __construct()
}

/**
* Write part
*
* @return string
*/
abstract public function write();

/**
* Set parent writer.
*
* @param \PhpOffice\PhpWord\Writer\AbstractWriter $writer
*
* @return void
*/
public function setParentWriter(AbstractWriter $writer = null)
Expand All @@ -64,8 +57,6 @@ public function setParentWriter(AbstractWriter $writer = null)
}

/**
* Get parent writer
*
* @return \PhpOffice\PhpWord\Writer\AbstractWriter
*
* @throws \PhpOffice\PhpWord\Exception\Exception
Expand Down
17 changes: 16 additions & 1 deletion src/PhpWord/Writer/RTF/Element/AbstractElement.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@
namespace PhpOffice\PhpWord\Writer\RTF\Element;

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\Font as FontStyle;
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\RTF\Style\Font as FontStyleWriter;
use PhpOffice\PhpWord\Writer\RTF\Style\Paragraph as ParagraphStyleWriter;
Expand All @@ -46,6 +50,13 @@ abstract class AbstractElement extends HTMLAbstractElement
*/
private $paragraphStyle;

public function __construct(AbstractWriter $parentWriter, Element $element, $withoutP)
{
parent::__construct($parentWriter, $element, $withoutP);

$this->escaper = new Rtf();
}

/**
* Get font and paragraph styles.
*
Expand Down Expand Up @@ -112,7 +123,11 @@ protected function writeOpening()
*/
protected function writeText($text)
{
return CommonText::toUnicode($text);
if (Settings::isOutputEscapingEnabled()) {
return $this->escaper->escape($text);
} else {
return CommonText::toUnicode($text);
}
}

/**
Expand Down
51 changes: 47 additions & 4 deletions src/PhpWord/Writer/RTF/Part/AbstractPart.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,56 @@

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
*/
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.');
}
}
}
7 changes: 5 additions & 2 deletions src/PhpWord/Writer/RTF/Part/Document.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,11 @@ private function writeInfo()
$content .= '\info';
foreach ($properties as $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;
$content .= "{\\{$property} {$value}}";
}
Expand Down Expand Up @@ -105,7 +109,6 @@ private function writeFormatting()
*/
private function writeSections()
{

$content = '';

$sections = $this->getParentWriter()->getPhpWord()->getSections();
Expand Down
2 changes: 1 addition & 1 deletion src/PhpWord/Writer/RTF/Part/Header.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ private function writeGenerator()
{
$content = '';

$content .= '{\*\generator PhpWord;}'; // Set the generator
$content .= '{\*\generator PHPWord;}'; // Set the generator
$content .= PHP_EOL;

return $content;
Expand Down

0 comments on commit 3f1e0ac

Please sign in to comment.