diff --git a/src/Spout/Common/Escaper/ODS.php b/src/Spout/Common/Escaper/ODS.php index 86caeb3..5e6b695 100644 --- a/src/Spout/Common/Escaper/ODS.php +++ b/src/Spout/Common/Escaper/ODS.php @@ -14,6 +14,31 @@ class ODS implements EscaperInterface { use Singleton; + /** @var string Regex pattern to detect control characters that need to be escaped */ + protected $escapableControlCharactersPattern; + + /** + * Initializes the singleton instance + */ + protected function init() + { + $this->escapableControlCharactersPattern = $this->getEscapableControlCharactersPattern(); + } + + /** + * @return string Regex pattern containing all escapable control characters + */ + protected function getEscapableControlCharactersPattern() + { + // control characters values are from 0 to 1F (hex values) in the ASCII table + // some characters should not be escaped though: "\t", "\r" and "\n". + return '[\x00-\x08' . + // skipping "\t" (0x9) and "\n" (0xA) + '\x0B-\x0C' . + // skipping "\r" (0xD) + '\x0E-\x1F]'; + } + /** * Escapes the given string to make it compatible with XLSX * @@ -22,7 +47,17 @@ class ODS implements EscaperInterface */ public function escape($string) { - return htmlspecialchars($string, ENT_QUOTES); + if (defined('ENT_DISALLOWED')) { + // 'ENT_DISALLOWED' ensures that invalid characters in the given document type are replaced. + // Otherwise characters like a vertical tab "\v" will make the XML document unreadable by the XML processor + // @link https://github.com/box/spout/issues/329 + return htmlspecialchars($string, ENT_QUOTES | ENT_DISALLOWED); + } else { + // We are on hhvm or any other engine that does not support ENT_DISALLOWED + $escapedString = htmlspecialchars($string, ENT_QUOTES); + $replacedString = preg_replace('/'.$this->escapableControlCharactersPattern.'/', '�', $escapedString); + return $replacedString; + } } /** diff --git a/tests/Spout/Common/Escaper/ODSTest.php b/tests/Spout/Common/Escaper/ODSTest.php new file mode 100644 index 0000000..fb5c960 --- /dev/null +++ b/tests/Spout/Common/Escaper/ODSTest.php @@ -0,0 +1,42 @@ +escape($stringToEscape); + + $this->assertEquals($expectedEscapedString, $escapedString, 'Incorrect escaped string'); + } +}