Merge pull request #24330 from thomas-Ngr/develop_fix_odt_generation

Fix odt generation
This commit is contained in:
Laurent Destailleur 2023-03-26 15:23:54 +02:00 committed by GitHub
commit fa0528a5d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 435 additions and 32 deletions

View File

@ -18,6 +18,7 @@ class OdfException extends Exception
* @copyright 2010-2015 - Laurent Destailleur - eldy@users.sourceforge.net * @copyright 2010-2015 - Laurent Destailleur - eldy@users.sourceforge.net
* @copyright 2010 - Vikas Mahajan - http://vikasmahajan.wordpress.com * @copyright 2010 - Vikas Mahajan - http://vikasmahajan.wordpress.com
* @copyright 2012 - Stephen Larroque - lrq3000@gmail.com * @copyright 2012 - Stephen Larroque - lrq3000@gmail.com
* @copyright 2023 - Thomas Negre - contact@open-dsi.fr
* @license https://www.gnu.org/copyleft/gpl.html GPL License * @license https://www.gnu.org/copyleft/gpl.html GPL License
* @version 1.5.0 * @version 1.5.0
*/ */
@ -46,6 +47,9 @@ class Odf
public $userdefined=array(); public $userdefined=array();
const PIXEL_TO_CM = 0.026458333; const PIXEL_TO_CM = 0.026458333;
const FIND_TAGS_REGEX = '/<([A-Za-z0-9]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/';
const FIND_ENCODED_TAGS_REGEX = '/&lt;([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/&gt;)|(?:&gt;(.*)&lt;\/\1&gt;))/';
/** /**
* Class constructor * Class constructor
@ -161,12 +165,16 @@ class Odf
*/ */
public function convertVarToOdf($value, $encode = true, $charset = 'ISO-8859') public function convertVarToOdf($value, $encode = true, $charset = 'ISO-8859')
{ {
$value = $encode ? htmlspecialchars($value) : $value; $value = html_entity_decode($value, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401);
$value = ($charset == 'ISO-8859') ? utf8_encode($value) : $value;
// fix breaklines.
$value = preg_replace('/<br\s*\/?>/', "<br />", $value);
$convertedValue = $value; $convertedValue = $value;
// Check if the value includes html tags // Check if the value includes html tags
if ($this->_hasHtmlTag($value) === true) { if ($this->_hasHtmlTag($value) === true) {
$value = strip_tags($value, '<br><strong><b><i><em><u><s><sub><sup><span>');
// Default styles for strong/b, i/em, u, s, sub & sup // Default styles for strong/b, i/em, u, s, sub & sup
$automaticStyles = array( $automaticStyles = array(
'<style:style style:name="boldText" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>', '<style:style style:name="boldText" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold" /></style:style>',
@ -180,7 +188,7 @@ class Odf
$customStyles = array(); $customStyles = array();
$fontDeclarations = array(); $fontDeclarations = array();
$convertedValue = $this->_replaceHtmlWithOdtTag($this->_getDataFromHtml($value), $customStyles, $fontDeclarations); $convertedValue = $this->_replaceHtmlWithOdtTag($this->_getDataFromHtml($value), $customStyles, $fontDeclarations, $encode, $charset);
foreach ($customStyles as $key => $val) { foreach ($customStyles as $key => $val) {
array_push($automaticStyles, '<style:style style:name="customStyle' . $key . '" style:family="text">' . $val . '</style:style>'); array_push($automaticStyles, '<style:style style:name="customStyle' . $key . '" style:family="text">' . $val . '</style:style>');
@ -204,21 +212,23 @@ class Odf
} }
$this->contentXml = str_replace('</office:font-face-decls>', $fonts . '</office:font-face-decls>', $this->contentXml); $this->contentXml = str_replace('</office:font-face-decls>', $fonts . '</office:font-face-decls>', $this->contentXml);
} else { } else {
$convertedValue = preg_replace('/(\r\n|\r|\n)/i', "<text:line-break/>", $value); $convertedValue = $this->encode_chars($convertedValue, $encode, $charset);
$convertedValue = preg_replace('/(\r\n|\r|\n)/i', "<text:line-break/>", $convertedValue);
} }
return $convertedValue; return $convertedValue;
} }
/** /**
* Replaces html tags in with odt tags and returns an odt string * Replaces html tags in with odt tags and returns an odt string. Encodes and converts inner text.
*
* @param array $tags An array with html tags generated by the getDataFromHtml() function * @param array $tags An array with html tags generated by the getDataFromHtml() function
* @param array $customStyles An array of style defenitions that should be included inside the odt file * @param array $customStyles An array of style defenitions that should be included inside the odt file
* @param array $fontDeclarations An array of font declarations that should be included inside the odt file * @param array $fontDeclarations An array of font declarations that should be included inside the odt file
* @param bool $encode If true, special XML characters are encoded
* @param string $charset Charset. See encode_chars()
* @return string * @return string
*/ */
private function _replaceHtmlWithOdtTag($tags, &$customStyles, &$fontDeclarations) private function _replaceHtmlWithOdtTag($tags, &$customStyles, &$fontDeclarations, $encode = false, $charset = '')
{ {
if ($customStyles == null) $customStyles = array(); if ($customStyles == null) $customStyles = array();
if ($fontDeclarations == null) $fontDeclarations = array(); if ($fontDeclarations == null) $fontDeclarations = array();
@ -228,7 +238,8 @@ class Odf
foreach ((array) $tags as $tag) { foreach ((array) $tags as $tag) {
// Check if the current item is a tag or just plain text // Check if the current item is a tag or just plain text
if (isset($tag['text'])) { if (isset($tag['text'])) {
$odtResult .= $tag['text']; $text = $this->encode_chars($tag['text'], $encode, $charset);
$odtResult .= $text;
} elseif (isset($tag['name'])) { } elseif (isset($tag['name'])) {
switch ($tag['name']) { switch ($tag['name']) {
case 'br': case 'br':
@ -236,23 +247,23 @@ class Odf
break; break;
case 'strong': case 'strong':
case 'b': case 'b':
$odtResult .= '<text:span text:style-name="boldText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="boldText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . '</text:span>';
break; break;
case 'i': case 'i':
case 'em': case 'em':
$odtResult .= '<text:span text:style-name="italicText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="italicText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . '</text:span>';
break; break;
case 'u': case 'u':
$odtResult .= '<text:span text:style-name="underlineText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="underlineText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . '</text:span>';
break; break;
case 's': case 's':
$odtResult .= '<text:span text:style-name="strikethroughText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="strikethroughText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . '</text:span>';
break; break;
case 'sub': case 'sub':
$odtResult .= '<text:span text:style-name="subText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="subText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . '</text:span>';
break; break;
case 'sup': case 'sup':
$odtResult .= '<text:span text:style-name="supText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="supText">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . '</text:span>';
break; break;
case 'span': case 'span':
if (isset($tag['attributes']['style'])) { if (isset($tag['attributes']['style'])) {
@ -287,9 +298,9 @@ class Odf
} }
if (strlen($odtStyles) > 0) { if (strlen($odtStyles) > 0) {
// Generate a unique id for the style (using microtime and random because some CPUs are really fast...) // Generate a unique id for the style (using microtime and random because some CPUs are really fast...)
$key = floatval(str_replace('.', '', microtime(true)))+rand(0, 10); $key = floatval(str_replace('.', '', microtime(true))) + rand(0, 10);
$customStyles[$key] = $odtStyles; $customStyles[$key] = $odtStyles;
$odtResult .= '<text:span text:style-name="customStyle' . $key . '">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $tag['innerText']) . '</text:span>'; $odtResult .= '<text:span text:style-name="customStyle' . $key . '">' . ($tag['children'] != null ? $this->_replaceHtmlWithOdtTag($tag['children'], $customStyles, $fontDeclarations) : $this->encode_chars($tag['innerText'], $encode, $charset)) . '</text:span>';
} }
} }
break; break;
@ -302,6 +313,21 @@ class Odf
return $odtResult; return $odtResult;
} }
/**
* Correctly encode chars
* @param string $text The text to encode or not
* @param bool $encode If true, special XML characters are encoded
* @param string $charset Charset
* @return string The converted text
* @see self::convertVarToOdf()
*/
private function encode_chars($text, $encode = false, $charset = '')
{
$newtext = $encode ? htmlspecialchars($text, ENT_QUOTES | ENT_XML1) : $text;
$newtext = ($charset == 'ISO-8859') ? utf8_encode($newtext) : $newtext;
return $newtext;
}
/** /**
* Checks if the given text is a html string * Checks if the given text is a html string
* @param string $text The text to check * @param string $text The text to check
@ -309,7 +335,7 @@ class Odf
*/ */
private function _isHtmlTag($text) private function _isHtmlTag($text)
{ {
return preg_match('/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/', $text); return preg_match(self::FIND_TAGS_REGEX, $text);
} }
/** /**
@ -319,7 +345,7 @@ class Odf
*/ */
private function _hasHtmlTag($text) private function _hasHtmlTag($text)
{ {
$result = preg_match_all('/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/', $text); $result = preg_match_all(self::FIND_TAGS_REGEX, $text);
return is_numeric($result) && $result > 0; return is_numeric($result) && $result > 0;
} }
@ -334,9 +360,8 @@ class Odf
$tempHtml = $html; $tempHtml = $html;
while (strlen($tempHtml) > 0) { while (strlen($tempHtml) > 0) {
$matches = array();
// Check if the string includes a html tag // Check if the string includes a html tag
if (preg_match_all('/<([A-Za-z]+)(?:\s([A-Za-z]+(?:\-[A-Za-z]+)?(?:=(?:".*?")|(?:[0-9]+))))*(?:(?:\s\/>)|(?:>(.*)<\/\1>))/', $tempHtml, $matches)) { if (preg_match_all(self::FIND_TAGS_REGEX, $tempHtml, $matches)) {
$tagOffset = strpos($tempHtml, $matches[0][0]); $tagOffset = strpos($tempHtml, $matches[0][0]);
// Check if the string starts with the html tag // Check if the string starts with the html tag
if ($tagOffset > 0) { if ($tagOffset > 0) {
@ -348,13 +373,12 @@ class Odf
$tempHtml = substr($tempHtml, $tagOffset); $tempHtml = substr($tempHtml, $tagOffset);
} }
// Extract the attribute data from the html tag // Extract the attribute data from the html tag
$explodedAttributes = array();
preg_match_all('/([0-9A-Za-z]+(?:="[0-9A-Za-z\:\-\s\,\;\#]*")?)+/', $matches[2][0], $explodedAttributes); preg_match_all('/([0-9A-Za-z]+(?:="[0-9A-Za-z\:\-\s\,\;\#]*")?)+/', $matches[2][0], $explodedAttributes);
$explodedAttributes = array_filter($explodedAttributes[0]); $explodedAttributes = array_filter($explodedAttributes[0]);
$attributes = array(); $attributes = array();
// Store each attribute with its name in the $attributes array // Store each attribute with its name in the $attributes array
$explodedAttributesCount = count($explodedAttributes); $explodedAttributesCount = count($explodedAttributes);
for ($i=0; $i<$explodedAttributesCount; $i++) { for ($i = 0; $i < $explodedAttributesCount; $i++) {
$attribute = trim($explodedAttributes[$i]); $attribute = trim($explodedAttributes[$i]);
// Check if the attribute has a value (like style="") or has no value (like required) // Check if the attribute has a value (like style="") or has no value (like required)
if (strpos($attribute, '=') !== false) { if (strpos($attribute, '=') !== false) {
@ -368,7 +392,7 @@ class Odf
// Split the style properties and store them in an array // Split the style properties and store them in an array
$explodedStyles = explode(';', $attrValue); $explodedStyles = explode(';', $attrValue);
$explodedStylesCount = count($explodedStyles); $explodedStylesCount = count($explodedStyles);
for ($n=0; $n<$explodedStylesCount; $n++) { for ($n = 0; $n < $explodedStylesCount; $n++) {
$splitStyle = explode(':', $explodedStyles[$n]); $splitStyle = explode(':', $explodedStyles[$n]);
$attributes[$attrName][trim($splitStyle[0])] = trim($splitStyle[1]); $attributes[$attrName][trim($splitStyle[0])] = trim($splitStyle[1]);
} }

379
test/phpunit/ODFTest.php Normal file
View File

@ -0,0 +1,379 @@
<?php
/* Copyright (C) 2007-2017 Laurent Destailleur <eldy@users.sourceforge.net>
* Copyright (C) 2023 - Thomas Negre - contact@open-dsi.fr
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file test/unit/ODFTest.php
* \ingroup odf
* \brief PHPUnit test for odf class.
*/
global $conf,$user,$langs,$db;
//define('TEST_DB_FORCE_TYPE','mysql'); // This is to force using mysql driver
//require_once 'PHPUnit/Autoload.php';
require_once dirname(__FILE__).'/../../htdocs/master.inc.php';
require_once dirname(__FILE__).'/../../htdocs/includes/odtphp/odf.php';
if (empty($user->id)) {
print "Load permissions for admin user nb 1\n";
$user->fetch(1);
$user->getrights();
}
$conf->global->MAIN_DISABLE_ALL_MAILS=1;
$langs->load("main");
/**
* Class for PHPUnit tests
*
* @backupGlobals disabled
* @backupStaticAttributes enabled
* @remarks backupGlobals must be disabled to have db,conf,user and lang not erased.
*/
class ODFTest extends PHPUnit\Framework\TestCase
{
protected $savconf;
protected $savuser;
protected $savlangs;
protected $savdb;
/**
* Constructor
* We save global variables into local variables
*
* @return BOMTest
*/
public function __construct()
{
parent::__construct();
//$this->sharedFixture
global $conf,$user,$langs,$db;
$this->savconf=$conf;
$this->savuser=$user;
$this->savlangs=$langs;
$this->savdb=$db;
print __METHOD__." db->type=".$db->type." user->id=".$user->id;
//print " - db ".$db->db;
print "\n";
}
/**
* setUpBeforeClass
*
* @return void
*/
public static function setUpBeforeClass()
{
global $conf,$user,$langs,$db;
$db->begin(); // This is to have all actions inside a transaction even if test launched without suite.
print __METHOD__."\n";
}
/**
* tearDownAfterClass
*
* @return void
*/
public static function tearDownAfterClass()
{
global $conf,$user,$langs,$db;
$db->rollback();
print __METHOD__."\n";
}
/**
* Init phpunit tests
*
* @return void
*/
protected function setUp()
{
global $conf,$user,$langs,$db;
$conf=$this->savconf;
$user=$this->savuser;
$langs=$this->savlangs;
$db=$this->savdb;
print __METHOD__."\n";
}
/**
* End phpunit tests
*
* @return void
*/
protected function tearDown()
{
print __METHOD__."\n";
}
/**
* test ODF convertVarToOdf
*
* @return int
*/
public function testODFconvertVarToOdf()
{
global $conf,$user,$langs,$db;
$conf=$this->savconf;
$user=$this->savuser;
$langs=$this->savlangs;
$db=$this->savdb;
// we test using template_invoice, it does not matter, we just need a valid odt.
$filename = '../../htdocs/install/doctemplates/invoices/template_invoice.odt';
$config = [
'PATH_TO_TMP' => "/tmp",
'ZIP_PROXY' => "PclZipProxy",
'DELIMITER_LEFT' => "{",
'DELIMITER_RIGHT' => "}",
];
$to_test = [
/** No HTML **/
// Simple strings
1 => [
'to_convert' => 'Simple string',
'encode' => true,
'charset' => null,
'expected' => 'Simple string',
],
2 => [
'to_convert' => 'Simple string',
'encode' => false,
'charset' => null,
'expected' => 'Simple string',
],
3 => [
'to_convert' => "Simple string\nwith line break",
'encode' => true,
'charset' => null,
'expected' => "Simple string<text:line-break/>with line break",
],
4 => [
'to_convert' => "Simple string\nwith line break",
'encode' => false,
'charset' => null,
'expected' => "Simple string<text:line-break/>with line break",
],
// Special chars
5 => [
'to_convert' => 'One&two',
'encode' => true,
'charset' => null,
'expected' => 'One&amp;two',
],
6 => [
'to_convert' => 'One&two',
'encode' => false,
'charset' => null,
'expected' => 'One&two',
],
7 => [
'to_convert' => "/a&él'èàüöç€Ğ~<>",
'encode' => true,
'charset' => null,
'expected' => utf8_encode("/a&amp;él&apos;èàüöç€Ğ~&lt;&gt;"),
],
8 => [
'to_convert' => "/a&él'èàüöç€Ğ~<>",
'encode' => false,
'charset' => null,
'expected' => utf8_encode("/a&él'èàüöç€Ğ~<>"),
],
// special chars with non-default charset
9 => [
'to_convert' => "/a&él'èàüöç€Ğ~<>",
'encode' => true,
'charset' => 'UTF-16',
'expected' => "/a&amp;él&apos;èàüöç€Ğ~&lt;&gt;",
],
10 => [
'to_convert' => "/a&él'èàüöç€Ğ~<>",
'encode' => false,
'charset' => 'UTF-16', // When the charset differs from ISO-8859 string is not converted.
'expected' => "/a&él'èàüöç€Ğ~<>",
],
11 => [
'to_convert' => "Greater > than",
'encode' => true,
'charset' => null,
'expected' => utf8_encode("Greater &gt; than"),
],
12 => [
'to_convert' => "Greater > than",
'encode' => false,
'charset' => null,
'expected' => utf8_encode("Greater > than"),
],
13 => [
'to_convert' => "Smaller < than",
'encode' => true,
'charset' => null,
'expected' => utf8_encode("Smaller &lt; than"),
],
14 => [
'to_convert' => "Smaller < than",
'encode' => false,
'charset' => null,
'expected' => utf8_encode("Smaller < than"),
],
/** HTML **/
// break lines
15 => [
'to_convert' => "Break<br>line",
'encode' => true,
'charset' => null,
'expected' => utf8_encode("Break<text:line-break/>line"),
],
16 => [
'to_convert' => "Break<br>line",
'encode' => false,
'charset' => null,
'expected' => utf8_encode("Break<text:line-break/>line"),
],
17 => [
'to_convert' => "Break<br />line",
'encode' => true,
'charset' => null,
'expected' => utf8_encode("Break<text:line-break/>line"),
],
18 => [
'to_convert' => "Break<br />line",
'encode' => false,
'charset' => null,
'expected' => utf8_encode("Break<text:line-break/>line"),
],
// HTML tags
19 => [
'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>",
'encode' => false,
'charset' => 'UTF-8',
'expected' => 'text with <text:span text:style-name="boldText">strong, </text:span><text:span text:style-name="italicText">emphasis</text:span> and <text:span text:style-name="underlineText">underlined</text:span> words with <text:span text:style-name="italicText">it@lic sp&ciàlchärs éè l\'</text:span>',
],
20 => [
'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>",
'encode' => true,
'charset' => 'UTF-8',
'expected' => 'text with <text:span text:style-name="boldText">strong, </text:span><text:span text:style-name="italicText">emphasis</text:span> and <text:span text:style-name="underlineText">underlined</text:span> words with <text:span text:style-name="italicText">it@lic sp&amp;ciàlchärs éè l&apos;</text:span>',
],
21 => [
'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>",
'encode' => false,
'charset' => null,
'expected' => utf8_encode('text with <text:span text:style-name="boldText">strong, </text:span><text:span text:style-name="italicText">emphasis</text:span> and <text:span text:style-name="underlineText">underlined</text:span> words with <text:span text:style-name="italicText">it@lic sp&ciàlchärs éè l\'</text:span>'),
],
22 => [
'to_convert' => "text with <strong>strong, </strong><em>emphasis</em> and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>",
'encode' => true,
'charset' => null,
'expected' => utf8_encode('text with <text:span text:style-name="boldText">strong, </text:span><text:span text:style-name="italicText">emphasis</text:span> and <text:span text:style-name="underlineText">underlined</text:span> words with <text:span text:style-name="italicText">it@lic sp&amp;ciàlchärs éè l&apos;</text:span>'),
],
23 => [
'to_convert' => "text with <strong>intricated<u>tags</u></strong>",
'encode' => true,
'charset' => null,
'expected' => utf8_encode('text with <text:span text:style-name="boldText">intricated<text:span text:style-name="underlineText">tags</text:span></text:span>'),
],
// One can also pass html-encoded string to the method
24 => [
'to_convert' => 'One&amp;two',
'encode' => true,
'charset' => null,
'expected' => 'One&amp;two',
],
25 => [
'to_convert' => "text with &lt;strong&gt;strong, &lt;/strong&gt;&lt;em&gt;emphasis&lt;/em&gt; and &lt;u&gt;underlined&lt;/u&gt; words with &lt;i&gt;it@lic sp&amp;ciàlchärs éè l'&lt;/i&gt;",
'encode' => false,
'charset' => 'UTF-8',
'expected' => 'text with <text:span text:style-name="boldText">strong, </text:span><text:span text:style-name="italicText">emphasis</text:span> and <text:span text:style-name="underlineText">underlined</text:span> words with <text:span text:style-name="italicText">it@lic sp&ciàlchärs éè l\'</text:span>',
],
26 => [
'to_convert' => "text with &lt;strong&gt;strong, &lt;/strong&gt;&lt;em&gt;emphasis&lt;/em&gt; and &lt;u&gt;underlined&lt;/u&gt; words with &lt;i&gt;it@lic sp&amp;ciàlchärs éè l'&lt;/i&gt;",
'encode' => true,
'charset' => 'UTF-8',
'expected' => 'text with <text:span text:style-name="boldText">strong, </text:span><text:span text:style-name="italicText">emphasis</text:span> and <text:span text:style-name="underlineText">underlined</text:span> words with <text:span text:style-name="italicText">it@lic sp&amp;ciàlchärs éè l&apos;</text:span>',
],
27 => [
'to_convert' => "text with &lt;strong&gt;strong, &lt;/strong&gt;&lt;em&gt;emphasis&lt;/em&gt; and &lt;u&gt;underlined&lt;/u&gt; words with &lt;i&gt;it@lic sp&amp;ciàlchärs éè l'&lt;/i&gt;",
'encode' => false,
'charset' => null,
'expected' => utf8_encode('text with <text:span text:style-name="boldText">strong, </text:span><text:span text:style-name="italicText">emphasis</text:span> and <text:span text:style-name="underlineText">underlined</text:span> words with <text:span text:style-name="italicText">it@lic sp&ciàlchärs éè l\'</text:span>'),
],
28 => [
'to_convert' => "text with &lt;strong&gt;strong, &lt;/strong&gt;&lt;em&gt;emphasis&lt;/em&gt; and &lt;u&gt;underlined&lt;/u&gt; words with &lt;i&gt;it@lic sp&amp;ciàlchärs éè l'&lt;/i&gt;",
'encode' => true,
'charset' => null,
'expected' => utf8_encode('text with <text:span text:style-name="boldText">strong, </text:span><text:span text:style-name="italicText">emphasis</text:span> and <text:span text:style-name="underlineText">underlined</text:span> words with <text:span text:style-name="italicText">it@lic sp&amp;ciàlchärs éè l&apos;</text:span>'),
],
// // TODO custom styles are not tested for now : the custom style have a custom ID based on time. Not random, but hard to mock or predict. generated in _replaceHtmlWithOdtTag() case 'span'.
// [
// 'to_convert' => '123 <span style="color:#e74c3c">trucmachin > truc < troc > trac</span>bla bla',
// 'encode' => true,
// 'charset' => 'UTF-8',
// 'expected' => "123 <text:span text:style-name="customStyle1668592427018">trucmachin &gt; truc &lt; troc &gt; trac</text:span>bla bla'",
// ],
/* Tests that can evolve */
// Following tests reflect the current behavior. They may evolve if the method behavior changes.
// The method removes hyperlinks and tags that are not dealt with.
29 => [
'to_convert' => '123 <a href="/test.php">trucmachin > truc < troc > trac</a>bla bla',
'encode' => true,
'charset' => null,
'expected' => "123 trucmachin &gt; truc &lt; troc &gt; tracbla bla",
],
30 => [
'to_convert' => '123 <h3>Title</h3> bla',
'encode' => true,
'charset' => null,
'expected' => "123 Title bla",
],
// HTML should not take \n into account, but only <br />.
31 => [
'to_convert' => "text with <strong>strong text </strong>, a line\nbreak and <u>underlined</u> words with <i>it@lic sp&ciàlchärs éè l'</i>",
'encode' => false,
'charset' => 'UTF-8',
'expected' => 'text with <text:span text:style-name="boldText">strong text </text:span>, a line'."\n".'break and <text:span text:style-name="underlineText">underlined</text:span> words with <text:span text:style-name="italicText">it@lic sp&ciàlchärs éè l\'</text:span>',
],
];
$odf=new Odf($filename, array());
if (is_object($odf)) $result = 1; // Just to test
foreach ($to_test as $case) {
if ($case['charset'] !== null) {
$res = $odf->convertVarToOdf($case['to_convert'], $case['encode'], $case['charset']);
} else {
$res = $odf->convertVarToOdf($case['to_convert'], $case['encode']);
}
$this->assertEquals($res, $case['expected']);
}
print __METHOD__." result=".$result."\n";
return $result;
}
}