nA)Bn{l?5
z8#e_1@k8v~X5@#X{uhDZVREHQS8C1-^lPtI;`_c4g{LesNdX1Ehe>bw-+V;Jp6?HG
zwJ1?QIGz&sr1o=|PQ*X8sK%810{=(_{v}uE$AYeWERAIiH;OReNR2*V)jEx!=?ln2
zGwfP7mrI2#kV^#FIU!k7o;rz3EYyx~h?NKo94>RzHpn?YuOSC*T9}}9TSx9Fqp`p@`0o9a2B%-^6?owPToiGg0y26IW^
zJ!00Ueo(hS!V1iufY7u0g_g-c=S&w%NDz5j?#CJUK}0s4m*C4eUrX6|P
z7#f}P(Wmxr=gHfM=fHY(jalweN|3Pn`FZq$*4)L|{EJZjh$}iNqBB7r5_TGm`kQ!{
zPd;cB1-&;*`VW_0k<%o}r<>Y@Z#!?;<;*UY-M#_yX5c%w5V$NeoF15bgLc#Z@Kl_|
z1l&8IEez1UN)GL(zcRM|rjz|AZ|ncLWWRUUAD^&~6(P_?0T7n1mloR1?NaBS_haSD
zGCB*%pf?grNk20hP`9*LY*~NH?7Ybke0!<*zS$qB!MYo>^%5oRADnR35?W^4bzM
zq^rA~4R^GSjHq^gL(1brmkiS34o-2l1TRNuu3hQ$5FraFjw4~cmGJkOus|FP!HbJ;%?{JE6IPvH0OIp`sOTUg^R
z@a`G|zo1vpim!jIIB*yKCl&H9Fbqr_`VaX3AV$8c=`NS;FI{9%n$LeT+up_BFoRU51fgXbGA>(0}ob+(qB5ult35&G`d;
zx7zNmio5j{zf|<_{ZR3HwZ&cdpP8e-z%Vc@(A>aZqtZX)(Om_9rds~4K=|=p1-}w6
z?`pZ5arjG*$CDpt@kjpQUHsjIgkShn>7Q5OpY(*g;JYD%Utm7XAK*Iygu5E@8bV-!hfM*V9cOi`@dZByYN4qp5NiThQGmoxIlN&e?E$SM=u!v
e{tN!sgXy^}Jan-5o^*@@^AQdPX4Ulj*8c%+K=Wn*
literal 0
HcmV?d00001
From 0ac841e338884e7cac15ea11ff9d623fb4013b1b Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Tue, 6 Feb 2024 16:13:40 -0800
Subject: [PATCH 02/24] Update Html.php
---
src/PhpWord/Shared/Html.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index 21d8404ddc..6f168164c6 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -109,7 +109,7 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit
$dom->loadXML($html);
static::$xpath = new DOMXPath($dom);
$node = $dom->getElementsByTagName('html');
- if (count($node) === 0) {
+ if (count($node) === 0 || $node->item(0) === null) {
$node = $dom->getElementsByTagName('body');
}
From 39fbabc5e81512078d9f15251d957701da56dca0 Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Thu, 9 May 2024 00:37:05 -0700
Subject: [PATCH 03/24] Load Html as Html Not Xml
Better from a technical standpoint.
Pre-processing much simplified.
Some post-processing added because loadHTML preserveWhiteSpace=false does not work well.
Not-UTF8 html can now be loaded.
No need to surround snippets with body tag.
---
src/PhpWord/Shared/Html.php | 69 +++++++++++++++---
.../PhpWordTests/Reader/Html/CharsetTest.php | 63 ++++++++++++++++
.../Reader/{ => Html}/HTMLTest.php | 4 +-
tests/PhpWordTests/Shared/HtmlTest.php | 40 +++++++---
.../_files/html/charset.ISO-8859-1.html | 17 +++++
.../_files/html/charset.ISO-8859-1.html4.html | 17 +++++
.../_files/html/charset.ISO-8859-2.html | 17 +++++
.../_files/html/charset.UTF-16.bebom.html | Bin 0 -> 604 bytes
.../_files/html/charset.UTF-16.lebom.html | Bin 0 -> 604 bytes
.../_files/html/charset.UTF-8.bom.html | 16 ++++
.../_files/html/charset.UTF-8.html | 17 +++++
.../_files/html/charset.gb18030.html | 9 +++
.../_files/html/charset.nocharset.html | 8 ++
.../_files/html/charset.unknown.html | 17 +++++
14 files changed, 270 insertions(+), 24 deletions(-)
create mode 100644 tests/PhpWordTests/Reader/Html/CharsetTest.php
rename tests/PhpWordTests/Reader/{ => Html}/HTMLTest.php (92%)
create mode 100644 tests/PhpWordTests/_files/html/charset.ISO-8859-1.html
create mode 100644 tests/PhpWordTests/_files/html/charset.ISO-8859-1.html4.html
create mode 100644 tests/PhpWordTests/_files/html/charset.ISO-8859-2.html
create mode 100644 tests/PhpWordTests/_files/html/charset.UTF-16.bebom.html
create mode 100644 tests/PhpWordTests/_files/html/charset.UTF-16.lebom.html
create mode 100644 tests/PhpWordTests/_files/html/charset.UTF-8.bom.html
create mode 100644 tests/PhpWordTests/_files/html/charset.UTF-8.html
create mode 100644 tests/PhpWordTests/_files/html/charset.gb18030.html
create mode 100644 tests/PhpWordTests/_files/html/charset.nocharset.html
create mode 100644 tests/PhpWordTests/_files/html/charset.unknown.html
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index 6f168164c6..9210aec19c 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -46,6 +46,8 @@ class Html
private const RGB_REGEXP = '/^\s*rgb\s*[(]\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*[)]\s*$/';
+ private const DECLARES_CHARSET = '/ charset=/i';
+
protected static $listIndex = 0;
protected static $xpath;
@@ -55,6 +57,9 @@ class Html
/** @var ?DocInfo */
protected static $docInfo;
+ /** @var bool */
+ private static $addbody = false;
+
/**
* @var Css
*/
@@ -88,16 +93,14 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit
}
}
- // Preprocess: remove all line ends, decode HTML entity,
- // fix ampersand and angle brackets and add body tag for HTML fragments
- $html = str_replace(["\n", "\r"], '', $html);
- $html = str_replace(['<', '>', '&', '"'], ['_lt_', '_gt_', '_amp_', '_quot_'], $html);
- $html = html_entity_decode($html, ENT_QUOTES, 'UTF-8');
- $html = str_replace('&', '&', $html);
- $html = str_replace(['_lt_', '_gt_', '_amp_', '_quot_'], ['<', '>', '&', '"'], $html);
-
- if (false === $fullHTML) {
- $html = '' . $html . '';
+ if (substr($html, 0, 2) === "\xfe\xff" || substr($html, 0, 2) === "\xff\xfe") {
+ $html = mb_convert_encoding($html, 'UTF-8', 'UTF-16');
+ }
+ if (substr($html, 0, 3) === "\xEF\xBB\xBF") {
+ $html = substr($html, 3);
+ }
+ if (self::$addbody && false === $fullHTML) {
+ $html = '' . $html . ''; // @codeCoverageIgnore
}
// Load DOM
@@ -105,8 +108,20 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit
$orignalLibEntityLoader = libxml_disable_entity_loader(true); // @codeCoverageIgnore
}
$dom = new DOMDocument();
+ $html = self::replaceNonAsciiIfNeeded($html);
$dom->preserveWhiteSpace = $preserveWhiteSpace;
- $dom->loadXML($html);
+
+ try {
+ $result = $dom->loadHTML($html);
+ $exceptionMessage = 'DOM loadHTML failed';
+ } catch (Exception $e) {
+ $result = false;
+ $exceptionMessage = $e->getMessage();
+ }
+ if ($result === false) {
+ throw new Exception($exceptionMessage);
+ }
+ self::removeAnnoyingWhitespaceTextNodes($dom);
static::$xpath = new DOMXPath($dom);
$node = $dom->getElementsByTagName('html');
if (count($node) === 0 || $node->item(0) === null) {
@@ -119,6 +134,38 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit
}
}
+ // https://www.php.net/manual/en/domdocument.loadhtml.php
+ private static function removeAnnoyingWhitespaceTextNodes(DOMNode $node): void
+ {
+ if ($node->hasChildNodes()) {
+ for ($i = $node->childNodes->length - 1; $i >= 0; --$i) {
+ self::removeAnnoyingWhitespaceTextNodes($node->childNodes->item($i));
+ }
+ }
+ if ($node->nodeType === XML_TEXT_NODE && !$node->hasChildNodes() && !$node->hasAttributes() && empty(trim($node->textContent))) {
+ $node->parentNode->removeChild($node);
+ }
+ }
+
+ private static function replaceNonAscii(array $matches): string
+ {
+ return '' . mb_ord($matches[0], 'UTF-8') . ';';
+ }
+
+ private static function replaceNonAsciiIfNeeded(string $convert): ?string
+ {
+ if (preg_match(self::DECLARES_CHARSET, $convert) !== 1) {
+ $lowend = "\u{80}";
+ $highend = "\u{10ffff}";
+ $regexp = "/[$lowend-$highend]/u";
+ /** @var callable $callback */
+ $callback = [self::class, 'replaceNonAscii'];
+ $convert = preg_replace_callback($regexp, $callback, $convert);
+ }
+
+ return $convert;
+ }
+
/**
* parse Inline style of a node.
*
diff --git a/tests/PhpWordTests/Reader/Html/CharsetTest.php b/tests/PhpWordTests/Reader/Html/CharsetTest.php
new file mode 100644
index 0000000000..60e80964a2
--- /dev/null
+++ b/tests/PhpWordTests/Reader/Html/CharsetTest.php
@@ -0,0 +1,63 @@
+expectException(Throwable::class);
+ $this->expectExceptionMessage('unknown encoding');
+ }
+ $directory = 'tests/PhpWordTests/_files/html';
+ $reader = new HTML();
+ $doc = $reader->load("$directory/$filename");
+ $sections = $doc->getSections();
+ self::assertCount(1, $sections);
+ $section = $sections[0];
+ $elements = $section->getElements();
+ $element = $elements[0];
+ self::assertInstanceOf(TextRun::class, $element);
+ self::assertSame($expectedResult, $element->getText());
+ }
+
+ public static function providerCharset(): array
+ {
+ return [
+ ['charset.ISO-8859-1.html', 'À1'],
+ ['charset.ISO-8859-1.html4.html', 'À1'],
+ ['charset.ISO-8859-2.html', 'Ŕ1'],
+ ['charset.nocharset.html', 'À1'],
+ ['charset.UTF-8.html', 'À1'],
+ ['charset.UTF-8.bom.html', 'À1'],
+ ['charset.UTF-16.bebom.html', 'À1'],
+ ['charset.UTF-16.lebom.html', 'À1'],
+ ['charset.gb18030.html', '电视机'],
+ ['charset.unknown.html', 'exception'],
+ ];
+ }
+}
diff --git a/tests/PhpWordTests/Reader/HTMLTest.php b/tests/PhpWordTests/Reader/Html/HTMLTest.php
similarity index 92%
rename from tests/PhpWordTests/Reader/HTMLTest.php
rename to tests/PhpWordTests/Reader/Html/HTMLTest.php
index f091e5a275..c0e150e495 100644
--- a/tests/PhpWordTests/Reader/HTMLTest.php
+++ b/tests/PhpWordTests/Reader/Html/HTMLTest.php
@@ -15,7 +15,7 @@
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
-namespace PhpOffice\PhpWordTests\Reader;
+namespace PhpOffice\PhpWordTests\Reader\Html;
use Exception;
use PhpOffice\PhpWord\IOFactory;
@@ -34,7 +34,7 @@ class HTMLTest extends \PHPUnit\Framework\TestCase
*/
public function testLoad(): void
{
- $filename = __DIR__ . '/../_files/documents/reader.html';
+ $filename = 'tests/PhpWordTests/_files/documents/reader.html';
$phpWord = IOFactory::load($filename, 'HTML');
self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord);
}
diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php
index 765d79f906..76e8273ec4 100644
--- a/tests/PhpWordTests/Shared/HtmlTest.php
+++ b/tests/PhpWordTests/Shared/HtmlTest.php
@@ -23,6 +23,7 @@
use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\TextRun;
use PhpOffice\PhpWord\PhpWord;
+use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\Html;
use PhpOffice\PhpWord\SimpleType\Jc;
use PhpOffice\PhpWord\SimpleType\LineSpacingRule;
@@ -52,6 +53,7 @@ protected function tearDown(): void
*/
public function testAddHtml(): void
{
+ Settings::setOutputEscapingEnabled(true);
$content = '';
// Default
@@ -80,16 +82,31 @@ public function testAddHtml(): void
// Other parts
$section = $phpWord->addSection();
$content = '';
+ $expectd = '';
$content .= '';
$content .= '';
$content .= '- Bullet
';
$content .= "'Single Quoted Text'";
+ $expectd .= "'Single Quoted Text'";
$content .= '"Double Quoted Text"';
- $content .= '& Ampersand';
+ $expectd .= '"Double Quoted Text"';
+ $content .= '& Ampersand';
+ $expectd .= '& Ampersand';
$content .= '<>“‘’«»‹›';
+ $expectd .= '<>“‘’«»‹›';
$content .= '&•°…™©®—';
+ $expectd .= '&•°…™©®—';
$content .= '– ²³¼½¾';
+ $expectd .= "–\u{a0} ²³¼½¾";
Html::addHtml($section, $content);
+ $elements = $section->getElements();
+ foreach ($elements as $element) {
+ if ($element instanceof Text) {
+ self::assertSame($expectd, $element->getText());
+
+ break;
+ }
+ }
}
/**
@@ -110,7 +127,7 @@ public function testParseFullHtml(): void
*/
public function testParseHtmlEntities(): void
{
- \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true);
+ Settings::setOutputEscapingEnabled(true);
$phpWord = new PhpWord();
$section = $phpWord->addSection();
Html::addHtml($section, 'text with entities <my text>');
@@ -138,13 +155,14 @@ public function testParseStyle(): void
Html::addHtml($section, $html);
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
- self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]'));
- self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r'));
- self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:t'));
- self::assertEquals('Calculator', $doc->getElement('/w:document/w:body/w:p[2]/w:r/w:t')->nodeValue);
- self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:rPr'));
- self::assertTrue($doc->elementExists('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz'));
- self::assertEquals('22.5', $doc->getElementAttribute('/w:document/w:body/w:p[2]/w:r/w:rPr/w:sz', 'w:val'));
+ $element = '/w:document/w:body/w:p';
+ self::assertTrue($doc->elementExists($element));
+ self::assertTrue($doc->elementExists("$element/w:r"));
+ self::assertTrue($doc->elementExists("$element/w:r/w:t"));
+ self::assertEquals('Calculator', $doc->getElement("$element/w:r/w:t")->nodeValue);
+ self::assertTrue($doc->elementExists("$element/w:r/w:rPr"));
+ self::assertTrue($doc->elementExists("$element/w:r/w:rPr/w:sz"));
+ self::assertEquals('22.5', $doc->getElementAttribute("$element/w:r/w:rPr/w:sz", 'w:val'));
}
public function testParseStyleTableClassName(): void
@@ -778,7 +796,7 @@ public function testParseListWithFormat(): void
{
$phpWord = new PhpWord();
$section = $phpWord->addSection();
- $html = preg_replace('/\s+/', ' ', '
+ $html = '
- Some text before
list item1 bold with text after bold
@@ -790,7 +808,7 @@ public function testParseListWithFormat(): void
list item2
-
');
+
';
Html::addHtml($section, $html, false, false);
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
diff --git a/tests/PhpWordTests/_files/html/charset.ISO-8859-1.html b/tests/PhpWordTests/_files/html/charset.ISO-8859-1.html
new file mode 100644
index 0000000000..fd27c975f3
--- /dev/null
+++ b/tests/PhpWordTests/_files/html/charset.ISO-8859-1.html
@@ -0,0 +1,17 @@
+
+
+
+
+ ISO-8859-1
+
+
+ 1
+
B1
+ 1
+ D1
+ 2
+ B2
+ C2
+ 2
+
+
diff --git a/tests/PhpWordTests/_files/html/charset.ISO-8859-1.html4.html b/tests/PhpWordTests/_files/html/charset.ISO-8859-1.html4.html
new file mode 100644
index 0000000000..8a14894517
--- /dev/null
+++ b/tests/PhpWordTests/_files/html/charset.ISO-8859-1.html4.html
@@ -0,0 +1,17 @@
+
+
+
+
+ ISO-8859-1 Html4 Doctype and Meta
+
+
+ 1
+ B1
+ 1
+ D1
+ 2
+ B2
+ C2
+ 2
+
+
diff --git a/tests/PhpWordTests/_files/html/charset.ISO-8859-2.html b/tests/PhpWordTests/_files/html/charset.ISO-8859-2.html
new file mode 100644
index 0000000000..c2b494ff99
--- /dev/null
+++ b/tests/PhpWordTests/_files/html/charset.ISO-8859-2.html
@@ -0,0 +1,17 @@
+
+
+
+
+ ISO-8859-2
+
+
+ 1
+ B1
+ 1
+ D1
+ 2
+ B2
+ C2
+ 2
+
+
diff --git a/tests/PhpWordTests/_files/html/charset.UTF-16.bebom.html b/tests/PhpWordTests/_files/html/charset.UTF-16.bebom.html
new file mode 100644
index 0000000000000000000000000000000000000000..6b29e7d2b011f7d8099fd407244dad7ef0d3121a
GIT binary patch
literal 604
zcmezOpFsf%Z5R|8Tp0WroEbtGA{hc0T!G>l3?&S?3^@#T3|vU+V4?~@nM8&>hI9s7
z26cv1AWI!XWhzib3YusMLnhGN9H0(6hESkwZVb8%h74v5HVpbeafBSQo%%qxU^6R;
zAs=XdC5jC&AHirFh614c0iYcq8$fJ?$uKoA8lu*T1hvmeQ0qd1+QSS+B)FG&waz4%
UdjYFjP$*&xcaS(NZ2-d<0BnUsYybcN
literal 0
HcmV?d00001
diff --git a/tests/PhpWordTests/_files/html/charset.UTF-16.lebom.html b/tests/PhpWordTests/_files/html/charset.UTF-16.lebom.html
new file mode 100644
index 0000000000000000000000000000000000000000..4ba47a81395d2f8076299b471e0357e1287ce1e3
GIT binary patch
literal 604
zcmezWPk{jfZ5R|8Tp0WroEbtGA{hc0T!G>l3?&S?3^@#T3|vrE3Jf-IQ3aq(B10ZS
zI)g2PIzuXurH-L86{sQwO|*m|6KHM@P=_5uD9|=H23-b21~Z_^`ap4n9I~DIKwGhy
zmBf$_G`|wX2AGdvv<*W6Q2qeW4v-BXHo|0>8W;^x>qLUu=On0gAwlh71|t&OOT1cV
U63o4TRV^qKv4uNG967}R0Iu{zYybcN
literal 0
HcmV?d00001
diff --git a/tests/PhpWordTests/_files/html/charset.UTF-8.bom.html b/tests/PhpWordTests/_files/html/charset.UTF-8.bom.html
new file mode 100644
index 0000000000..5a49399018
--- /dev/null
+++ b/tests/PhpWordTests/_files/html/charset.UTF-8.bom.html
@@ -0,0 +1,16 @@
+
+
+
+ UTF-8
+
+
+ À1
+ B1
+ ç1
+ D1
+ Ã2
+ B2
+ C2
+ Ð2
+
+
diff --git a/tests/PhpWordTests/_files/html/charset.UTF-8.html b/tests/PhpWordTests/_files/html/charset.UTF-8.html
new file mode 100644
index 0000000000..9ae5a8e343
--- /dev/null
+++ b/tests/PhpWordTests/_files/html/charset.UTF-8.html
@@ -0,0 +1,17 @@
+
+
+
+
+ UTF-8
+
+
+ À1
+ B1
+ ç1
+ D1
+ Ã2
+ B2
+ C2
+ Ð2
+
+
diff --git a/tests/PhpWordTests/_files/html/charset.gb18030.html b/tests/PhpWordTests/_files/html/charset.gb18030.html
new file mode 100644
index 0000000000..271a55fc54
--- /dev/null
+++ b/tests/PhpWordTests/_files/html/charset.gb18030.html
@@ -0,0 +1,9 @@
+
+
+
+gb18030
+
+
+ ӻ
+
+
diff --git a/tests/PhpWordTests/_files/html/charset.nocharset.html b/tests/PhpWordTests/_files/html/charset.nocharset.html
new file mode 100644
index 0000000000..d6829b2edc
--- /dev/null
+++ b/tests/PhpWordTests/_files/html/charset.nocharset.html
@@ -0,0 +1,8 @@
+ À1
+ B1
+ ç1
+ D1
+ Ã2
+ B2
+ C2
+ Ð2
diff --git a/tests/PhpWordTests/_files/html/charset.unknown.html b/tests/PhpWordTests/_files/html/charset.unknown.html
new file mode 100644
index 0000000000..189638a80f
--- /dev/null
+++ b/tests/PhpWordTests/_files/html/charset.unknown.html
@@ -0,0 +1,17 @@
+
+
+
+
+ UTF-8
+
+
+ À1
+ B1
+ ç1
+ D1
+ Ã2
+ B2
+ C2
+ Ð2
+
+
From cf1fd2a112419e72878b40a7589212f2dfd29c3c Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Thu, 9 May 2024 17:35:13 -0700
Subject: [PATCH 04/24] Permit Some Backwards Compatibility
It's debatable, but allow unescaped ampersand and unknown charset.
---
phpunit.xml.dist | 4 ++--
src/PhpWord/Shared/Html.php | 4 ++--
tests/PhpWordTests/Reader/Html/CharsetTest.php | 2 +-
tests/PhpWordTests/Shared/HtmlTest.php | 8 ++++----
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 6f1f5445ab..ff0c676fad 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -7,10 +7,10 @@
./src/PhpWord/Shared/PCLZip
-
+
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index 9210aec19c..2d68806f33 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -112,14 +112,14 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit
$dom->preserveWhiteSpace = $preserveWhiteSpace;
try {
- $result = $dom->loadHTML($html);
+ $result = $dom->loadHTML($html, LIBXML_NOWARNING | LIBXML_NOERROR);
$exceptionMessage = 'DOM loadHTML failed';
} catch (Exception $e) {
$result = false;
$exceptionMessage = $e->getMessage();
}
if ($result === false) {
- throw new Exception($exceptionMessage);
+ throw new Exception($exceptionMessage); // @codeCoverageIgnore
}
self::removeAnnoyingWhitespaceTextNodes($dom);
static::$xpath = new DOMXPath($dom);
diff --git a/tests/PhpWordTests/Reader/Html/CharsetTest.php b/tests/PhpWordTests/Reader/Html/CharsetTest.php
index 60e80964a2..4c73d70bb0 100644
--- a/tests/PhpWordTests/Reader/Html/CharsetTest.php
+++ b/tests/PhpWordTests/Reader/Html/CharsetTest.php
@@ -57,7 +57,7 @@ public static function providerCharset(): array
['charset.UTF-16.bebom.html', 'À1'],
['charset.UTF-16.lebom.html', 'À1'],
['charset.gb18030.html', '电视机'],
- ['charset.unknown.html', 'exception'],
+ 'loadhtml gives its best shot' => ['charset.unknown.html', "Ã\u{80}1"],
];
}
}
diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php
index 76e8273ec4..3fa4b5c1d0 100644
--- a/tests/PhpWordTests/Shared/HtmlTest.php
+++ b/tests/PhpWordTests/Shared/HtmlTest.php
@@ -90,14 +90,14 @@ public function testAddHtml(): void
$expectd .= "'Single Quoted Text'";
$content .= '"Double Quoted Text"';
$expectd .= '"Double Quoted Text"';
- $content .= '& Ampersand';
+ $content .= '& Ampersand';
$expectd .= '& Ampersand';
- $content .= '<>“‘’«»‹›';
- $expectd .= '<>“‘’«»‹›';
+ $content .= '<>“”‘’«»‹›';
+ $expectd .= '<>“”‘’«»‹›';
$content .= '&•°…™©®—';
$expectd .= '&•°…™©®—';
$content .= '– ²³¼½¾';
- $expectd .= "–\u{a0} ²³¼½¾";
+ $expectd .= "–\u{a0}\u{2003}\u{2002}²³¼½¾";
Html::addHtml($section, $content);
$elements = $section->getElements();
foreach ($elements as $element) {
From 2f799c2ba9be781106ac84545a58b58b2fc00f98 Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Fri, 16 Aug 2024 08:10:24 -0700
Subject: [PATCH 05/24] Phpstan False Positives
---
src/PhpWord/Shared/Html.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index d78338526a..2d96c375f7 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -180,7 +180,7 @@ protected static function parseInlineStyle($node, &$styles)
$attributes = $node->attributes; // get all the attributes(eg: id, class)
$bidi = false;
- $direction = isset($attributes['dir']) ? $attributes['dir']->value : '';
+ $direction = isset($attributes['dir']) ? $attributes['dir']->value : ''; // @phpstan-ignore-line
if ($direction === 'rtl') {
$bidi = $styles['bidi'] = $styles['rtl'] = true;
$styles['textDirection'] = TextDirection::RLTB;
@@ -550,7 +550,7 @@ protected static function parseTable($node, $element, &$styles)
$attributes = $node->attributes;
if ($attributes->getNamedItem('border') !== null && is_object($newElement->getStyle())) {
- $border = (int) $attributes->getNamedItem('border')->value;
+ $border = (int) $attributes->getNamedItem('border')->value; // @phpstan-ignore-line
$newElement->getStyle()->setBorderSize((int) Converter::pixelToTwip($border));
$newElement->getStyle()->setBorderStyle(($border === 0) ? 'none' : 'single');
}
From d9120c7f3782496d606ec087baa524ced709a51e Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Fri, 16 Aug 2024 08:39:59 -0700
Subject: [PATCH 06/24] Improve Resolution of Phpstan Problem
---
src/PhpWord/Shared/Html.php | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index 2d96c375f7..7fa9c6f36f 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -180,7 +180,8 @@ protected static function parseInlineStyle($node, &$styles)
$attributes = $node->attributes; // get all the attributes(eg: id, class)
$bidi = false;
- $direction = isset($attributes['dir']) ? $attributes['dir']->value : ''; // @phpstan-ignore-line
+ $attrDir = $attributes->getNamedItem('dir');
+ $direction = isset($attrDir) ? $attrDir->nodeValue : '';
if ($direction === 'rtl') {
$bidi = $styles['bidi'] = $styles['rtl'] = true;
$styles['textDirection'] = TextDirection::RLTB;
@@ -550,7 +551,7 @@ protected static function parseTable($node, $element, &$styles)
$attributes = $node->attributes;
if ($attributes->getNamedItem('border') !== null && is_object($newElement->getStyle())) {
- $border = (int) $attributes->getNamedItem('border')->value; // @phpstan-ignore-line
+ $border = (int) $attributes->getNamedItem('border')->nodeValue;
$newElement->getStyle()->setBorderSize((int) Converter::pixelToTwip($border));
$newElement->getStyle()->setBorderStyle(($border === 0) ? 'none' : 'single');
}
From 1093a3b3ad5295a71cd3d7dbb5ed56d4f5de69c6 Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Tue, 3 Sep 2024 23:34:34 -0700
Subject: [PATCH 07/24] Update Sample_45_RTLTitles.php
---
samples/Sample_45_RTLTitles.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/samples/Sample_45_RTLTitles.php b/samples/Sample_45_RTLTitles.php
index 83dd9b9872..e39510c97f 100644
--- a/samples/Sample_45_RTLTitles.php
+++ b/samples/Sample_45_RTLTitles.php
@@ -6,7 +6,7 @@
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\Html as SharedHtml;
-// Suggested by issue 2427.
+// Suggested by issue #2427.
echo date('H:i:s'), ' Create new PhpWord object', EOL;
$phpWord = new PhpWord();
Settings::setDefaultRtl(true);
From 74918d0909c8224b1a46a4dfbf1494f11e8dd5ed Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Tue, 3 Sep 2024 23:38:32 -0700
Subject: [PATCH 08/24] Update Sample_45_RTLTitles.php
---
samples/Sample_45_RTLTitles.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/samples/Sample_45_RTLTitles.php b/samples/Sample_45_RTLTitles.php
index e39510c97f..83dd9b9872 100644
--- a/samples/Sample_45_RTLTitles.php
+++ b/samples/Sample_45_RTLTitles.php
@@ -6,7 +6,7 @@
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\Html as SharedHtml;
-// Suggested by issue #2427.
+// Suggested by issue 2427.
echo date('H:i:s'), ' Create new PhpWord object', EOL;
$phpWord = new PhpWord();
Settings::setDefaultRtl(true);
From 28b1b08ee77462e87b0b69d364f1688d0e0eacd7 Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Wed, 4 Sep 2024 00:20:17 -0700
Subject: [PATCH 09/24] Update Sample_45_RTLTitles.php
---
samples/Sample_45_RTLTitles.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/samples/Sample_45_RTLTitles.php b/samples/Sample_45_RTLTitles.php
index 83dd9b9872..e39510c97f 100644
--- a/samples/Sample_45_RTLTitles.php
+++ b/samples/Sample_45_RTLTitles.php
@@ -6,7 +6,7 @@
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\Html as SharedHtml;
-// Suggested by issue 2427.
+// Suggested by issue #2427.
echo date('H:i:s'), ' Create new PhpWord object', EOL;
$phpWord = new PhpWord();
Settings::setDefaultRtl(true);
From 32a73505a08fd5c2136d4c128046e0585c4be5ab Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Thu, 9 Jan 2025 14:50:15 -0800
Subject: [PATCH 10/24] Update HTMLTest.php
---
tests/PhpWordTests/Reader/Html/HTMLTest.php | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/PhpWordTests/Reader/Html/HTMLTest.php b/tests/PhpWordTests/Reader/Html/HTMLTest.php
index c0e150e495..9b16662c08 100644
--- a/tests/PhpWordTests/Reader/Html/HTMLTest.php
+++ b/tests/PhpWordTests/Reader/Html/HTMLTest.php
@@ -1,4 +1,5 @@
Date: Thu, 9 Jan 2025 15:29:38 -0800
Subject: [PATCH 11/24] Move One Test to Avoid Merge Conflict
---
tests/PhpWordTests/Reader/{Html => }/HTMLTest.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
rename tests/PhpWordTests/Reader/{Html => }/HTMLTest.php (92%)
diff --git a/tests/PhpWordTests/Reader/Html/HTMLTest.php b/tests/PhpWordTests/Reader/HTMLTest.php
similarity index 92%
rename from tests/PhpWordTests/Reader/Html/HTMLTest.php
rename to tests/PhpWordTests/Reader/HTMLTest.php
index 9b16662c08..7a35a06f78 100644
--- a/tests/PhpWordTests/Reader/Html/HTMLTest.php
+++ b/tests/PhpWordTests/Reader/HTMLTest.php
@@ -16,7 +16,7 @@
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
-namespace PhpOffice\PhpWordTests\Reader\Html;
+namespace PhpOffice\PhpWordTests\Reader;
use Exception;
use PhpOffice\PhpWord\IOFactory;
@@ -35,7 +35,7 @@ class HTMLTest extends \PHPUnit\Framework\TestCase
*/
public function testLoad(): void
{
- $filename = 'tests/PhpWordTests/_files/documents/reader.html';
+ $filename = __DIR__ . '/../_files/documents/reader.html';
$phpWord = IOFactory::load($filename, 'HTML');
self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord);
}
From e9316c07c277036fb875b0f322e8da55533666ba Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Thu, 9 Jan 2025 15:48:25 -0800
Subject: [PATCH 12/24] Try to Correct Merge Conflicts in Writer/HTML/FontTest
---
tests/PhpWordTests/Writer/HTML/FontTest.php | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/tests/PhpWordTests/Writer/HTML/FontTest.php b/tests/PhpWordTests/Writer/HTML/FontTest.php
index 08a8fca6a4..20ab8d9920 100644
--- a/tests/PhpWordTests/Writer/HTML/FontTest.php
+++ b/tests/PhpWordTests/Writer/HTML/FontTest.php
@@ -1,4 +1,5 @@
Date: Thu, 9 Jan 2025 16:03:07 -0800
Subject: [PATCH 13/24] Trying FontTest One More Time Before Giving Up
---
tests/PhpWordTests/Writer/HTML/FontTest.php | 42 ++++++++++-----------
1 file changed, 21 insertions(+), 21 deletions(-)
diff --git a/tests/PhpWordTests/Writer/HTML/FontTest.php b/tests/PhpWordTests/Writer/HTML/FontTest.php
index 20ab8d9920..6416a44d2f 100644
--- a/tests/PhpWordTests/Writer/HTML/FontTest.php
+++ b/tests/PhpWordTests/Writer/HTML/FontTest.php
@@ -87,27 +87,27 @@ public function testFontNames1(): void
$style = Helper::getTextContent($xpath, '/html/head/style');
$prg = preg_match('/^body[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('body {font-family: \'Courier New\'; font-size: 12pt;}', $matches[0]);
$prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]);
$prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style2 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]);
$prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style3 {font-family: \'hack attempt'}; display:none\'; font-size: 10pt;}', $matches[0]);
$prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style4 {font-family: \'padmaa 1.1\'; font-size: 10pt; font-weight: bold;}', $matches[0]);
$prg = preg_match('/^[.]style5[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style5 {font-family: \'MingLiU-ExtB\'; font-size: 10pt; font-weight: bold;}', $matches[0]);
}
@@ -143,23 +143,23 @@ public function testFontNames2(): void
$style = Helper::getTextContent($xpath, '/html/head/style');
$prg = preg_match('/^body[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('body {font-family: \'Courier New\'; font-size: 12pt;}', $matches[0]);
$prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]);
- self::assertNotEmpty($matches);
$prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches);
- self::assertSame(1, $prg);
+ self::assertNotEmpty($matches);
+ self::assertNotFalse($prg);
self::assertEquals('.style2 {font-family: \'Arial\', sans-serif; font-size: 10pt;}', $matches[0]);
$prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style3 {font-family: \'DejaVu Sans Monospace\', monospace; font-size: 10pt;}', $matches[0]);
$prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style4 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]);
}
@@ -195,23 +195,23 @@ public function testFontNames3(): void
$style = Helper::getTextContent($xpath, '/html/head/style');
$prg = preg_match('/^body[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('body {font-family: \'Courier New\', monospace; font-size: 12pt;}', $matches[0]);
$prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]);
$prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style2 {font-family: \'Arial\', sans-serif; font-size: 10pt;}', $matches[0]);
$prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style3 {font-family: \'DejaVu Sans Monospace\', monospace; font-size: 10pt;}', $matches[0]);
$prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style4 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]);
}
@@ -242,19 +242,19 @@ public function testWhiteSpace(): void
self::assertEquals('body {font-family: \'Arial\'; font-size: 12pt; white-space: pre-wrap;}', $matches[0]);
$prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style1 {font-family: \'Courier New\'; font-size: 10pt; white-space: pre-wrap;}', $matches[0]);
$prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style2 {font-family: \'Courier New\'; font-size: 10pt;}', $matches[0]);
$prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style3 {font-family: \'Courier New\'; font-size: 10pt; white-space: normal;}', $matches[0]);
$prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches);
self::assertNotEmpty($matches);
- self::assertSame(1, $prg);
+ self::assertNotFalse($prg);
self::assertEquals('.style4 {font-family: \'Courier New\'; font-size: 10pt;}', $matches[0]);
}
From 8e6726c24a8e6a5db7c3dea0f6f3b17eb1064b5a Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Thu, 9 Jan 2025 16:55:59 -0800
Subject: [PATCH 14/24] Try to Catch Up
---
composer.json | 2 +-
src/PhpWord/Shared/Html.php | 4 ++--
src/PhpWord/SimpleType/TextDirection.php | 1 +
tests/PhpWordTests/Reader/Html/CharsetTest.php | 1 +
tests/PhpWordTests/Reader/Word2007/StyleTableTest.php | 1 +
tests/PhpWordTests/SettingsRtlTest.php | 1 +
tests/PhpWordTests/Shared/Html2402Test.php | 1 +
tests/PhpWordTests/Shared/HtmlFullTest.php | 1 +
tests/PhpWordTests/Shared/HtmlHeadingsTest.php | 1 +
tests/PhpWordTests/Shared/HtmlRtlTest.php | 5 +++--
tests/PhpWordTests/Shared/HtmlTest.php | 8 ++++----
tests/PhpWordTests/TemplateProcessorSectionTest.php | 1 +
tests/PhpWordTests/Writer/RTF/RichTextTitleTest.php | 1 +
13 files changed, 19 insertions(+), 9 deletions(-)
diff --git a/composer.json b/composer.json
index efebe941e7..2d06f890b3 100644
--- a/composer.json
+++ b/composer.json
@@ -122,7 +122,7 @@
"phpmd/phpmd": "^2.13",
"phpstan/phpstan": "^0.12.88 || ^1.0.0",
"phpstan/phpstan-phpunit": "^1.0 || ^2.0",
- "phpunit/phpunit": ">=7.0",
+ "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0 || ^10.0",
"symfony/process": "^4.4 || ^5.0",
"tecnickcom/tcpdf": "^6.5"
},
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index 7c2fcab0e6..81573cd83d 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -417,7 +417,7 @@ protected static function parseChildNodes($node, $element, $styles, $data): void
* @param AbstractContainer $element
* @param array &$styles
*
- * @return \PhpOffice\PhpWord\Element\PageBreak|\PhpOffice\PhpWord\Element\TextRun
+ * @return \PhpOffice\PhpWord\Element\PageBreak|TextRun
*/
protected static function parseParagraph($node, $element, &$styles)
{
@@ -590,7 +590,7 @@ protected static function parseRow($node, $element, &$styles)
* @param Table $element
* @param array &$styles
*
- * @return \PhpOffice\PhpWord\Element\Cell|\PhpOffice\PhpWord\Element\TextRun $element
+ * @return \PhpOffice\PhpWord\Element\Cell|TextRun $element
*/
protected static function parseCell($node, $element, &$styles)
{
diff --git a/src/PhpWord/SimpleType/TextDirection.php b/src/PhpWord/SimpleType/TextDirection.php
index 0797fa9294..ab1a045337 100644
--- a/src/PhpWord/SimpleType/TextDirection.php
+++ b/src/PhpWord/SimpleType/TextDirection.php
@@ -1,4 +1,5 @@
addSection([
- 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE,
+ 'orientation' => Style\Section::ORIENTATION_LANDSCAPE,
]);
// borders & backgrounds are here just for better visual comparison
@@ -548,7 +548,7 @@ public function testParseTableRowHeight(): void
{
$phpWord = new PhpWord();
$section = $phpWord->addSection([
- 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE,
+ 'orientation' => Style\Section::ORIENTATION_LANDSCAPE,
]);
$html = <<addSection([
- 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE,
+ 'orientation' => Style\Section::ORIENTATION_LANDSCAPE,
]);
// borders & backgrounds are here just for better visual comparison
@@ -670,7 +670,7 @@ public function testParseTableStyleAttributeInlineStyle(): void
{
$phpWord = new PhpWord();
$section = $phpWord->addSection([
- 'orientation' => \PhpOffice\PhpWord\Style\Section::ORIENTATION_LANDSCAPE,
+ 'orientation' => Style\Section::ORIENTATION_LANDSCAPE,
]);
$html = '
diff --git a/tests/PhpWordTests/TemplateProcessorSectionTest.php b/tests/PhpWordTests/TemplateProcessorSectionTest.php
index 0402d4fc66..a6e9d61163 100644
--- a/tests/PhpWordTests/TemplateProcessorSectionTest.php
+++ b/tests/PhpWordTests/TemplateProcessorSectionTest.php
@@ -1,4 +1,5 @@
Date: Sun, 12 Jan 2025 14:45:02 -0800
Subject: [PATCH 15/24] Experiment with Different Phpunit Xml Dists
---
.github/workflows/php.yml | 14 +++++++++++---
phpunit.7.8.xml.dist | 12 ++++++++++++
phpunit10.xml.dist | 20 ++++++++++++++++++++
3 files changed, 43 insertions(+), 3 deletions(-)
create mode 100644 phpunit.7.8.xml.dist
create mode 100644 phpunit10.xml.dist
diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml
index 0e2e9ea96d..b403e57d8a 100644
--- a/.github/workflows/php.yml
+++ b/.github/workflows/php.yml
@@ -83,11 +83,19 @@ jobs:
- name: Composer Install
run: composer install --ansi --prefer-dist --no-interaction --no-progress
- - name: Run phpunit
- if: matrix.php != '7.3'
+ - name: Run phpunit 7.1 7.2
+ if: matrix.php == '7.1' || matrix.php == '7.2'
+ run: ./vendor/bin/phpunit -c phpunit.7.8.xml.dist --no-coverage
+
+ - name: Run phpunit 7.4 8.0
+ if: matrix.php == '7.4' || matrix.php == '8.0'
run: ./vendor/bin/phpunit -c phpunit.xml.dist --no-coverage
- - name: Run phpunit
+ - name: Run phpunit 8.1 8.2 8.3 8.4
+ if: matrix.php == '8.1' || matrix.php == '8.2' || matrix.php == '8.3' || matrix.php == '8.4'
+ run: ./vendor/bin/phpunit -c phpunit10.xml.dist --no-coverage
+
+ - name: Run phpunit 7.3
if: matrix.php == '7.3'
run: ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/clover.xml
diff --git a/phpunit.7.8.xml.dist b/phpunit.7.8.xml.dist
new file mode 100644
index 0000000000..a8327fb286
--- /dev/null
+++ b/phpunit.7.8.xml.dist
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+ ./tests/PhpWordTests
+
+
+
+
diff --git a/phpunit10.xml.dist b/phpunit10.xml.dist
new file mode 100644
index 0000000000..b97fbee3fb
--- /dev/null
+++ b/phpunit10.xml.dist
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ ./tests/PhpWordTests
+
+
+
+
+
+ ./src
+
+
+ ./src/PhpWord/Shared/PCLZip
+
+
+
From 737cb3708a9be2bd0f13c42b15ca8d635baa2e7b Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Sun, 12 Jan 2025 14:53:38 -0800
Subject: [PATCH 16/24] Remove Logging from 7.8 Config
---
phpunit.7.8.xml.dist | 1 -
1 file changed, 1 deletion(-)
diff --git a/phpunit.7.8.xml.dist b/phpunit.7.8.xml.dist
index a8327fb286..22e77a0ea6 100644
--- a/phpunit.7.8.xml.dist
+++ b/phpunit.7.8.xml.dist
@@ -8,5 +8,4 @@
./tests/PhpWordTests
-
From 508464223d3b5dae4e9524fd2ab3768248b2b62f Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Sun, 12 Jan 2025 15:13:50 -0800
Subject: [PATCH 17/24] More Phpunit Tweaking
---
.github/workflows/php.yml | 4 ++--
phpunit.xml.dist | 22 +++++++++-------------
phpunit9.xml.dist | 24 ++++++++++++++++++++++++
3 files changed, 35 insertions(+), 15 deletions(-)
create mode 100644 phpunit9.xml.dist
diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml
index b403e57d8a..016120d913 100644
--- a/.github/workflows/php.yml
+++ b/.github/workflows/php.yml
@@ -89,7 +89,7 @@ jobs:
- name: Run phpunit 7.4 8.0
if: matrix.php == '7.4' || matrix.php == '8.0'
- run: ./vendor/bin/phpunit -c phpunit.xml.dist --no-coverage
+ run: ./vendor/bin/phpunit -c phpunit9.xml.dist --no-coverage
- name: Run phpunit 8.1 8.2 8.3 8.4
if: matrix.php == '8.1' || matrix.php == '8.2' || matrix.php == '8.3' || matrix.php == '8.4'
@@ -97,7 +97,7 @@ jobs:
- name: Run phpunit 7.3
if: matrix.php == '7.3'
- run: ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/clover.xml
+ run: ./vendor/bin/phpunit -c phpunit9.xml.dist --coverage-clover build/clover.xml
- name: Upload coverage results to Coveralls
if: matrix.php == '7.3'
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index ff0c676fad..b97fbee3fb 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,17 +1,5 @@
-
-
-
- ./src
-
-
- ./src/PhpWord/Shared/PCLZip
-
-
-
+
@@ -21,4 +9,12 @@
+
+
+ ./src
+
+
+ ./src/PhpWord/Shared/PCLZip
+
+
diff --git a/phpunit9.xml.dist b/phpunit9.xml.dist
new file mode 100644
index 0000000000..ff0c676fad
--- /dev/null
+++ b/phpunit9.xml.dist
@@ -0,0 +1,24 @@
+
+
+
+
+ ./src
+
+
+ ./src/PhpWord/Shared/PCLZip
+
+
+
+
+
+
+
+
+ ./tests/PhpWordTests
+
+
+
+
From d1a16fef6c785311810115213f68d4a04eaf4e3e Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Wed, 15 Jan 2025 15:43:15 -0800
Subject: [PATCH 18/24] Update HtmlTest.php
---
tests/PhpWordTests/Shared/HtmlTest.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php
index cf4d627c92..bc0899a8ac 100644
--- a/tests/PhpWordTests/Shared/HtmlTest.php
+++ b/tests/PhpWordTests/Shared/HtmlTest.php
@@ -28,9 +28,9 @@
use PhpOffice\PhpWord\Shared\Html;
use PhpOffice\PhpWord\SimpleType\Jc;
use PhpOffice\PhpWord\SimpleType\LineSpacingRule;
+use PhpOffice\PhpWord\SimpleType\TblWidth;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Style\Font;
-use PhpOffice\PhpWord\SimpleType\TblWidth;
use PhpOffice\PhpWord\Style\Paragraph;
use PhpOffice\PhpWordTests\AbstractWebServerEmbedded;
use PhpOffice\PhpWordTests\TestHelperDOCX;
From f82eb47f8f6327e8883a6d921ac3b73017d6b78b Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Thu, 30 Jan 2025 15:00:10 -0800
Subject: [PATCH 19/24] Eliminate JSON Dependency
JSON is used in exactly 2 places in the code and should not be used in either.
XMLWriter uses it to cast a float to string. Aside from being silly, this actually causes a problem in Shared/HtmlTest, where one of the results should be 4000 but is instead tested for 3999.9999... The error should have been immaterial (a simple cast will give the correct answer), but the test was wrong, insisting on an exact match for a floating point answer. It should use assertEqualsWithDelta. Next, the reason why JSON got it "wrong" was because the conversions in Shared/Converter use the wrong order of operations - multiplications should be performed before divisions to help avoid rounding problems, but Converter was doing the divisions first. All the conversions there are changed to multiply before dividing. Finally, Shared/Html checks for width units of points or pixels, but should check for inches and centimers as well.
Writer/Html outputs tracking properties as a JSON string for some unfathomable reason. It is changed to output each of the three (author, id, and date) as its own discrete property. Tests didn't actually confirm the value of the properties; they do now. Oh, yes, htmlspecialchars is needed for author and id, otherwise the html may wind up broken.
Some simple changes are made to TestHelperDOCX to avoid intermittent problems on Windows, and to make the code a little cleaner.
---
.gitignore | 3 +-
composer.json | 1 -
src/PhpWord/Shared/Converter.php | 24 +++++++--------
src/PhpWord/Shared/Html.php | 6 ++++
src/PhpWord/Shared/XMLWriter.php | 2 +-
src/PhpWord/Writer/HTML/Element/Text.php | 24 ++++++++-------
tests/PhpWordTests/Shared/HtmlTest.php | 7 +++--
tests/PhpWordTests/TestHelperDOCX.php | 24 +++++++++++----
.../PhpWordTests/Writer/HTML/ElementTest.php | 30 ++++++++++++++++++-
9 files changed, 86 insertions(+), 35 deletions(-)
diff --git a/.gitignore b/.gitignore
index 0b9d0608d0..3ebe0dc1a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,4 +24,5 @@ phpword.ini
/nbproject
/.php_cs.cache
/.phpunit.result.cache
-/public
\ No newline at end of file
+/.phpunit.cache
+/public
diff --git a/composer.json b/composer.json
index 2d06f890b3..9487640f2a 100644
--- a/composer.json
+++ b/composer.json
@@ -109,7 +109,6 @@
"php": "^7.1|^8.0",
"ext-dom": "*",
"ext-gd": "*",
- "ext-json": "*",
"ext-xml": "*",
"ext-zip": "*",
"phpoffice/math": "^0.2"
diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php
index 17d2e1a05d..82e11c0790 100644
--- a/src/PhpWord/Shared/Converter.php
+++ b/src/PhpWord/Shared/Converter.php
@@ -40,7 +40,7 @@ class Converter
*/
public static function cmToTwip($centimeter = 1)
{
- return $centimeter / self::INCH_TO_CM * self::INCH_TO_TWIP;
+ return $centimeter * self::INCH_TO_TWIP / self::INCH_TO_CM;
}
/**
@@ -64,7 +64,7 @@ public static function cmToInch($centimeter = 1)
*/
public static function cmToPixel($centimeter = 1)
{
- return $centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL;
+ return $centimeter * self::INCH_TO_PIXEL / self::INCH_TO_CM;
}
/**
@@ -76,7 +76,7 @@ public static function cmToPixel($centimeter = 1)
*/
public static function cmToPoint($centimeter = 1)
{
- return $centimeter / self::INCH_TO_CM * self::INCH_TO_POINT;
+ return $centimeter * self::INCH_TO_POINT / self::INCH_TO_CM;
}
/**
@@ -88,7 +88,7 @@ public static function cmToPoint($centimeter = 1)
*/
public static function cmToEmu($centimeter = 1)
{
- return round($centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU);
+ return round($centimeter * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU / self::INCH_TO_CM);
}
/**
@@ -160,7 +160,7 @@ public static function inchToEmu($inch = 1)
*/
public static function pixelToTwip($pixel = 1)
{
- return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_TWIP;
+ return $pixel * self::INCH_TO_TWIP / self::INCH_TO_PIXEL;
}
/**
@@ -172,7 +172,7 @@ public static function pixelToTwip($pixel = 1)
*/
public static function pixelToCm($pixel = 1)
{
- return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_CM;
+ return $pixel * self::INCH_TO_CM / self::INCH_TO_PIXEL;
}
/**
@@ -184,7 +184,7 @@ public static function pixelToCm($pixel = 1)
*/
public static function pixelToPoint($pixel = 1)
{
- return $pixel / self::INCH_TO_PIXEL * self::INCH_TO_POINT;
+ return $pixel * self::INCH_TO_POINT / self::INCH_TO_PIXEL;
}
/**
@@ -208,7 +208,7 @@ public static function pixelToEmu($pixel = 1)
*/
public static function pointToTwip($point = 1)
{
- return $point / self::INCH_TO_POINT * self::INCH_TO_TWIP;
+ return $point * self::INCH_TO_TWIP / self::INCH_TO_POINT;
}
/**
@@ -220,7 +220,7 @@ public static function pointToTwip($point = 1)
*/
public static function pointToPixel($point = 1)
{
- return $point / self::INCH_TO_POINT * self::INCH_TO_PIXEL;
+ return $point * self::INCH_TO_PIXEL / self::INCH_TO_POINT;
}
/**
@@ -232,7 +232,7 @@ public static function pointToPixel($point = 1)
*/
public static function pointToEmu($point = 1)
{
- return round($point / self::INCH_TO_POINT * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU);
+ return round($point * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU / self::INCH_TO_POINT);
}
/**
@@ -244,7 +244,7 @@ public static function pointToEmu($point = 1)
*/
public static function pointToCm($point = 1)
{
- return $point / self::INCH_TO_POINT * self::INCH_TO_CM;
+ return $point * self::INCH_TO_CM / self::INCH_TO_POINT;
}
/**
@@ -268,7 +268,7 @@ public static function emuToPixel($emu = 1)
*/
public static function picaToPoint($pica = 1)
{
- return $pica / self::INCH_TO_PICA * self::INCH_TO_POINT;
+ return $pica * self::INCH_TO_POINT / self::INCH_TO_PICA;
}
/**
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index 9b57f77adc..d1bf13d7f7 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -1477,6 +1477,12 @@ protected static function convertHtmlSize(string $size): float
if (false !== strpos($size, 'px')) {
return (float) str_replace('px', '', $size);
}
+ if (false !== strpos($size, 'cm')) {
+ return Converter::cmToPixel((float) str_replace('cm', '', $size));
+ }
+ if (false !== strpos($size, 'in')) {
+ return Converter::inchToPixel((float) str_replace('in', '', $size));
+ }
return (float) $size;
}
diff --git a/src/PhpWord/Shared/XMLWriter.php b/src/PhpWord/Shared/XMLWriter.php
index 8dc28e1184..8b267b694c 100644
--- a/src/PhpWord/Shared/XMLWriter.php
+++ b/src/PhpWord/Shared/XMLWriter.php
@@ -180,7 +180,7 @@ public function writeAttributeIf($condition, $attribute, $value): void
public function writeAttribute($name, $value)
{
if (is_float($value)) {
- $value = json_encode($value);
+ $value = (string) $value;
}
return parent::writeAttribute($name, $value ?? '');
diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php
index 312d3a19c2..c6363d1da4 100644
--- a/src/PhpWord/Writer/HTML/Element/Text.php
+++ b/src/PhpWord/Writer/HTML/Element/Text.php
@@ -163,20 +163,22 @@ private function writeTrackChangeOpening()
$content = '';
if (($changed->getChangeType() == TrackChange::INSERTED)) {
- $content .= 'getChangeType() == TrackChange::DELETED) {
- $content .= ' ['author' => $changed->getAuthor(), 'id' => $this->element->getElementId()]];
- if ($changed->getDate() != null) {
- $changedProp['changed']['date'] = $changed->getDate()->format('Y-m-d\TH:i:s\Z');
+ $author = htmlspecialchars($changed->getAuthor(), ENT_QUOTES);
+ $content .= " data-phpword-chg-author='$author'";
+ $elementId = htmlspecialchars($this->element->getElementId(), ENT_QUOTES);
+ $content .= " data-phpword-chg-id='$elementId'";
+ $date = $changed->getDate();
+ if ($date !== null) {
+ $dateout = $date->format('Y-m-d\TH:i:s\Z');
+ $content .= " data-phpword-chg-timestamp='$dateout'";
}
- $content .= json_encode($changedProp);
- $content .= '\' ';
- $content .= 'title="' . $changed->getAuthor();
- if ($changed->getDate() != null) {
- $dateUser = $changed->getDate()->format('Y-m-d H:i:s');
+ $content .= ' title="' . $author;
+ if ($date !== null) {
+ $dateUser = $date->format('Y-m-d H:i:s');
$content .= ' - ' . $dateUser;
}
$content .= '">';
diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php
index 142a93e5a5..5131d6ea44 100644
--- a/tests/PhpWordTests/Shared/HtmlTest.php
+++ b/tests/PhpWordTests/Shared/HtmlTest.php
@@ -256,7 +256,8 @@ public function testParseWidth(string $htmlSize, float $docxSize, string $docxUn
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblW';
self::assertTrue($doc->elementExists($xpath));
- self::assertEquals($docxSize, $doc->getElement($xpath)->getAttribute('w:w'));
+ $actual = (float) $doc->getElement($xpath)->getAttribute('w:w');
+ self::assertEqualsWithDelta($docxSize, $actual, 1.0e-12);
self::assertEquals($docxUnit, $doc->getElement($xpath)->getAttribute('w:type'));
}
@@ -1371,9 +1372,11 @@ public static function providerParseWidth(): array
return [
['auto', 5000, TblWidth::PERCENT],
['100%', 5000, TblWidth::PERCENT],
- ['200pt', 3999.999999999999, TblWidth::TWIP],
+ ['200pt', 4000, TblWidth::TWIP],
['300px', 4500, TblWidth::TWIP],
['400', 6000, TblWidth::TWIP],
+ ['2in', 2880, TblWidth::TWIP],
+ ['2.54cm', 1440, TblWidth::TWIP],
];
}
diff --git a/tests/PhpWordTests/TestHelperDOCX.php b/tests/PhpWordTests/TestHelperDOCX.php
index 2a6fbabae0..5ebe799cfc 100644
--- a/tests/PhpWordTests/TestHelperDOCX.php
+++ b/tests/PhpWordTests/TestHelperDOCX.php
@@ -47,13 +47,14 @@ class TestHelperDOCX
*/
public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007')
{
+ $tempdir = self::getTempDirPhpunit();
self::$file = tempnam(Settings::getTempDir(), 'PhpWord');
if (false === self::$file) {
throw new CreateTemporaryFileException();
}
- if (!is_dir(Settings::getTempDir() . '/PhpWord_Unit_Test/')) {
- mkdir(Settings::getTempDir() . '/PhpWord_Unit_Test/');
+ if (!is_dir($tempdir)) {
+ mkdir($tempdir);
}
$xmlWriter = IOFactory::createWriter($phpWord, $writerName);
@@ -62,11 +63,11 @@ public static function getDocument(PhpWord $phpWord, $writerName = 'Word2007')
$zip = new ZipArchive();
$res = $zip->open(self::$file);
if (true === $res) {
- $zip->extractTo(Settings::getTempDir() . '/PhpWord_Unit_Test/');
+ $zip->extractTo($tempdir);
$zip->close();
}
- $doc = new XmlDocument(Settings::getTempDir() . '/PhpWord_Unit_Test/');
+ $doc = new XmlDocument($tempdir);
if ($writerName === 'ODText') {
$doc->setDefaultFile('content.xml');
}
@@ -83,8 +84,9 @@ public static function clear(): void
unlink(self::$file);
self::$file = '';
}
- if (is_dir(Settings::getTempDir() . '/PhpWord_Unit_Test/')) {
- self::deleteDir(Settings::getTempDir() . '/PhpWord_Unit_Test/');
+ $tempdir = self::getTempDirPhpunit();
+ if (is_dir($tempdir)) {
+ self::deleteDir($tempdir);
}
}
@@ -117,4 +119,14 @@ public static function getFile()
{
return self::$file;
}
+
+ /**
+ * Get temporary directory for PhpUnit.
+ *
+ * @return string
+ */
+ private static function getTempDirPhpunit()
+ {
+ return Settings::getTempDir() . '/PhpWord_Unit_Test';
+ }
}
diff --git a/tests/PhpWordTests/Writer/HTML/ElementTest.php b/tests/PhpWordTests/Writer/HTML/ElementTest.php
index 3b2580381f..28e785a237 100644
--- a/tests/PhpWordTests/Writer/HTML/ElementTest.php
+++ b/tests/PhpWordTests/Writer/HTML/ElementTest.php
@@ -72,13 +72,41 @@ public function testWriteTrackChanges(): void
$text = $section->addText('my dummy text');
$text->setChangeInfo(TrackChange::INSERTED, 'author name');
$text2 = $section->addText('my other text');
- $text2->setTrackChange(new TrackChange(TrackChange::DELETED, 'another author', new DateTime()));
+ $deleteTime = new DateTime();
+ $deleteAuthor = "Spec O'char";
+ $deleteTrack = new TrackChange(TrackChange::DELETED, $deleteAuthor, $deleteTime);
+ $text2->setTrackChange($deleteTrack);
$dom = Helper::getAsHTML($phpWord);
$xpath = new DOMXPath($dom);
self::assertEquals(1, $xpath->query('/html/body/div/p[1]/ins')->length);
self::assertEquals(1, $xpath->query('/html/body/div/p[2]/del')->length);
+ $node = $xpath->query('/html/body/div/p[2]/del');
+ self::assertNotFalse($node);
+ $allAttributes = $node[0]->attributes;
+ self::assertCount(4, $allAttributes);
+ $node = $xpath->query('/html/body/div/p[2]/del');
+ self::assertNotFalse($node);
+
+ $attributes = $node[0]->attributes[0];
+ self::assertSame('data-phpword-chg-author', $attributes->name);
+ self::assertSame($deleteAuthor, $attributes->value);
+
+ $text2Id = $text2->getElementId();
+ $attributes = $node[0]->attributes[1];
+ self::assertSame('data-phpword-chg-id', $attributes->name);
+ self::assertSame($text2Id, $attributes->value);
+
+ $attributes = $node[0]->attributes[2];
+ self::assertSame('data-phpword-chg-timestamp', $attributes->name);
+ self::assertSame($deleteTime->format('Y-m-d\TH:i:s\Z'), $attributes->value);
+
+ $attributes = $node[0]->attributes[3];
+ self::assertSame('title', $attributes->name);
+ $expected = $deleteAuthor . ' - '
+ . $deleteTime->format('Y-m-d H:i:s');
+ self::assertSame($expected, $attributes->value);
}
/**
From 3ace7706180af59c7b10b3b0bab5a8615849c92a Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Thu, 30 Jan 2025 21:20:49 -0800
Subject: [PATCH 20/24] Improve Test Coverage
---
src/PhpWord/Shared/Html.php | 10 +-
src/PhpWord/Shared/HtmlColours.php | 5 -
tests/PhpWordTests/Shared/Html2Test.php | 140 ++++++++++++++++++++++++
3 files changed, 145 insertions(+), 10 deletions(-)
create mode 100644 tests/PhpWordTests/Shared/Html2Test.php
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index d1bf13d7f7..26bc83e3bb 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -36,6 +36,7 @@
use PhpOffice\PhpWord\SimpleType\NumberFormat;
use PhpOffice\PhpWord\SimpleType\TextDirection;
use PhpOffice\PhpWord\Style\Paragraph;
+use Throwable;
/**
* Common Html functions.
@@ -114,20 +115,20 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit
$dom->preserveWhiteSpace = $preserveWhiteSpace;
try {
- $result = $dom->loadHTML($html, LIBXML_NOWARNING | LIBXML_NOERROR);
+ $result = @$dom->loadHTML($html);
$exceptionMessage = 'DOM loadHTML failed';
- } catch (Exception $e) {
+ } catch (Throwable $e) {
$result = false;
$exceptionMessage = $e->getMessage();
}
if ($result === false) {
- throw new Exception($exceptionMessage); // @codeCoverageIgnore
+ throw new Exception($exceptionMessage);
}
self::removeAnnoyingWhitespaceTextNodes($dom);
static::$xpath = new DOMXPath($dom);
$node = $dom->getElementsByTagName('html');
if (count($node) === 0 || $node->item(0) === null) {
- $node = $dom->getElementsByTagName('body');
+ $node = $dom->getElementsByTagName('body'); // @codeCoverageIgnore
}
static::parseNode($node->item(0), $element);
@@ -1319,7 +1320,6 @@ protected static function mapListType($cssListType)
return NumberFormat::LOWER_ROMAN; // i, ii, iii, iv, ..
case 'I':
return NumberFormat::UPPER_ROMAN; // I, II, III, IV, ..
- case '1':
default:
return NumberFormat::DECIMAL; // 1, 2, 3, ..
}
diff --git a/src/PhpWord/Shared/HtmlColours.php b/src/PhpWord/Shared/HtmlColours.php
index 40bc0096c6..c50acfd5da 100644
--- a/src/PhpWord/Shared/HtmlColours.php
+++ b/src/PhpWord/Shared/HtmlColours.php
@@ -524,11 +524,6 @@ class HtmlColours
'yellowgreen' => '9acd32',
];
- public static function colourNameLookup(string $colorName): string
- {
- return self::COLOUR_MAP[$colorName] ?? '';
- }
-
public static function convertColour(string $colorName): string
{
$colorName = trim($colorName);
diff --git a/tests/PhpWordTests/Shared/Html2Test.php b/tests/PhpWordTests/Shared/Html2Test.php
new file mode 100644
index 0000000000..95866d4b07
--- /dev/null
+++ b/tests/PhpWordTests/Shared/Html2Test.php
@@ -0,0 +1,140 @@
+expectException(Exception::class);
+ $this->expectExceptionMessage('loadHTML');
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ Html::addHtml($section, '');
+ }
+
+ public function testCssOnIdElement(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $html = ''
+ . ''
+ . 'Id Test'
+ . ''
+ . ''
+ . 'test1.
'
+ . '';
+ Html::addHtml($section, $html);
+ $doc = TestHelperDOCX::getDocument($phpWord);
+ $marginPath = '/w:document/w:body/w:p/w:pPr/w:spacing';
+ self::assertSame('150', $doc->getElement($marginPath)->getAttribute('w:before'));
+ self::assertSame('150', $doc->getElement($marginPath)->getAttribute('w:after'));
+ $path = '/w:document/w:body/w:p/w:r';
+ self::assertSame('test1.', $doc->getElement($path)->nodeValue);
+ $boldPath = $path . '/w:rPr/w:b';
+ self::assertSame('1', $doc->getElement($boldPath)->getAttribute('w:val'));
+ }
+
+ public function testListTypes(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $html = '- Decimal number first
- second
'
+ . '- Lowercase first
- second
'
+ . '- Uppercase first
- second
'
+ . '- Lower roman first
- second
'
+ . '- Upper roman first
- second
';
+ Html::addHtml($section, $html);
+ $doc = TestHelperDOCX::getDocument($phpWord);
+
+ $item = 1;
+ $expected = '1';
+ $path = "/w:document/w:body/w:p[$item]";
+ self::assertSame('Decimal number first', $doc->getElement("$path/w:r")->nodeValue);
+ $numIdPath = $path . '/w:pPr/w:numPr/w:numId';
+ self::assertSame($expected, $doc->getElement($numIdPath)->getAttribute('w:val'));
+ ++$item;
+ $path = "/w:document/w:body/w:p[$item]";
+ $numIdPath = $path . '/w:pPr/w:numPr/w:numId';
+ self::assertSame($expected, $doc->getElement($numIdPath)->getAttribute('w:val'));
+
+ ++$item;
+ $expected = '2';
+ $path = "/w:document/w:body/w:p[$item]";
+ self::assertSame('Lowercase first', $doc->getElement("$path/w:r")->nodeValue);
+ $numIdPath = $path . '/w:pPr/w:numPr/w:numId';
+ self::assertSame($expected, $doc->getElement($numIdPath)->getAttribute('w:val'));
+ ++$item;
+ $path = "/w:document/w:body/w:p[$item]";
+ $numIdPath = $path . '/w:pPr/w:numPr/w:numId';
+ self::assertSame($expected, $doc->getElement($numIdPath)->getAttribute('w:val'));
+
+ ++$item;
+ $expected = '3';
+ $path = "/w:document/w:body/w:p[$item]";
+ self::assertSame('Uppercase first', $doc->getElement("$path/w:r")->nodeValue);
+ $numIdPath = $path . '/w:pPr/w:numPr/w:numId';
+ self::assertSame($expected, $doc->getElement($numIdPath)->getAttribute('w:val'));
+ ++$item;
+ $path = "/w:document/w:body/w:p[$item]";
+ $numIdPath = $path . '/w:pPr/w:numPr/w:numId';
+ self::assertSame($expected, $doc->getElement($numIdPath)->getAttribute('w:val'));
+
+ ++$item;
+ $expected = '4';
+ $path = "/w:document/w:body/w:p[$item]";
+ self::assertSame('Lower roman first', $doc->getElement("$path/w:r")->nodeValue);
+ $numIdPath = $path . '/w:pPr/w:numPr/w:numId';
+ self::assertSame($expected, $doc->getElement($numIdPath)->getAttribute('w:val'));
+ ++$item;
+ $path = "/w:document/w:body/w:p[$item]";
+ $numIdPath = $path . '/w:pPr/w:numPr/w:numId';
+ self::assertSame($expected, $doc->getElement($numIdPath)->getAttribute('w:val'));
+
+ ++$item;
+ $expected = '5';
+ $path = "/w:document/w:body/w:p[$item]";
+ self::assertSame('Upper roman first', $doc->getElement("$path/w:r")->nodeValue);
+ $numIdPath = $path . '/w:pPr/w:numPr/w:numId';
+ self::assertSame($expected, $doc->getElement($numIdPath)->getAttribute('w:val'));
+ ++$item;
+ $path = "/w:document/w:body/w:p[$item]";
+ $numIdPath = $path . '/w:pPr/w:numPr/w:numId';
+ self::assertSame($expected, $doc->getElement($numIdPath)->getAttribute('w:val'));
+ }
+}
From b1720b95ddac49ee56d9a2b7cde3a736ced484a9 Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Thu, 30 Jan 2025 22:18:41 -0800
Subject: [PATCH 21/24] A Bit More Coverage
---
tests/PhpWordTests/Shared/Html2Test.php | 64 +++++++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/tests/PhpWordTests/Shared/Html2Test.php b/tests/PhpWordTests/Shared/Html2Test.php
index 95866d4b07..64a71932dd 100644
--- a/tests/PhpWordTests/Shared/Html2Test.php
+++ b/tests/PhpWordTests/Shared/Html2Test.php
@@ -137,4 +137,68 @@ public function testListTypes(): void
$numIdPath = $path . '/w:pPr/w:numPr/w:numId';
self::assertSame($expected, $doc->getElement($numIdPath)->getAttribute('w:val'));
}
+
+ public function testPadding(): void
+ {
+ $phpWord = new PhpWord();
+ $section = $phpWord->addSection();
+ $html = ''
+ . ''
+ . '20 | '
+ . '20 30 | '
+ . '
'
+ . '20 30 40 | '
+ . '20 30 40 50 | '
+ . '
';
+ Html::addHtml($section, $html);
+ $doc = TestHelperDOCX::getDocument($phpWord);
+
+ $item = 1;
+ $td = 1;
+ $path = "/w:document/w:body/w:tbl/w:tr[$item]/w:tc[$td]";
+ self::assertSame('20', $doc->getElement("$path/w:p/w:r")->nodeValue);
+ $tcMarPath = $path . '/w:tcPr/w:tcMar';
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:top')->getAttribute('w:w'));
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:start')->getAttribute('w:w'));
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:bottom')->getAttribute('w:w'));
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:end')->getAttribute('w:w'));
+
+ ++$td;
+ $path = "/w:document/w:body/w:tbl/w:tr[$item]/w:tc[$td]";
+ self::assertSame('20 30', $doc->getElement("$path/w:p/w:r")->nodeValue);
+ $tcMarPath = $path . '/w:tcPr/w:tcMar';
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:top')->getAttribute('w:w'));
+ self::assertSame('450', $doc->getElement($tcMarPath . '/w:start')->getAttribute('w:w'));
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:bottom')->getAttribute('w:w'));
+ self::assertSame('450', $doc->getElement($tcMarPath . '/w:end')->getAttribute('w:w'));
+
+ $item = 1;
+ $td = 1;
+ $path = "/w:document/w:body/w:tbl/w:tr[$item]/w:tc[$td]";
+ self::assertSame('20', $doc->getElement("$path/w:p/w:r")->nodeValue);
+ $tcMarPath = $path . '/w:tcPr/w:tcMar';
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:top')->getAttribute('w:w'));
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:start')->getAttribute('w:w'));
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:bottom')->getAttribute('w:w'));
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:end')->getAttribute('w:w'));
+
+ ++$item;
+ $td = 1;
+ $path = "/w:document/w:body/w:tbl/w:tr[$item]/w:tc[$td]";
+ self::assertSame('20 30 40', $doc->getElement("$path/w:p/w:r")->nodeValue);
+ $tcMarPath = $path . '/w:tcPr/w:tcMar';
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:top')->getAttribute('w:w'));
+ self::assertSame('450', $doc->getElement($tcMarPath . '/w:start')->getAttribute('w:w'));
+ self::assertSame('600', $doc->getElement($tcMarPath . '/w:bottom')->getAttribute('w:w'));
+ self::assertSame('450', $doc->getElement($tcMarPath . '/w:end')->getAttribute('w:w'));
+
+ ++$td;
+ $path = "/w:document/w:body/w:tbl/w:tr[$item]/w:tc[$td]";
+ self::assertSame('20 30 40 50', $doc->getElement("$path/w:p/w:r")->nodeValue);
+ $tcMarPath = $path . '/w:tcPr/w:tcMar';
+ self::assertSame('300', $doc->getElement($tcMarPath . '/w:top')->getAttribute('w:w'));
+ self::assertSame('750', $doc->getElement($tcMarPath . '/w:start')->getAttribute('w:w'));
+ self::assertSame('600', $doc->getElement($tcMarPath . '/w:bottom')->getAttribute('w:w'));
+ self::assertSame('450', $doc->getElement($tcMarPath . '/w:end')->getAttribute('w:w'));
+ }
}
From 16904a2a0cea68176db99dbcc60c52e804b8212a Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Wed, 5 Feb 2025 22:24:41 -0800
Subject: [PATCH 22/24] Catch Up
---
src/PhpWord/Shared/Html.php | 8 ++++----
src/PhpWord/Writer/HTML/Element/Title.php | 15 +++++++++------
src/PhpWord/Writer/HTML/Part/Head.php | 1 +
tests/PhpWordTests/Shared/HtmlHeadingsTest.php | 9 ++++-----
tests/PhpWordTests/Shared/HtmlTest.php | 5 +++++
tests/PhpWordTests/Writer/HTML/PartTest.php | 12 +++++-------
6 files changed, 28 insertions(+), 22 deletions(-)
diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
index c574bd969d..9cc3abe5b7 100644
--- a/src/PhpWord/Shared/Html.php
+++ b/src/PhpWord/Shared/Html.php
@@ -470,10 +470,10 @@ protected static function parseInput($node, $element, &$styles): void
*/
protected static function parseHeading(DOMNode $node, AbstractContainer $element, array &$styles, string $headingStyle): TextRun
{
- self::parseInlineStyle($node, $styles['font']);
- // Create a TextRun to hold styles and text
- $styles['paragraph'] = $headingStyle;
- $textRun = new TextRun($styles['paragraph']);
+ $style = new Paragraph();
+ $style->setStyleName($headingStyle);
+ $style->setStyleByArray(self::parseInlineStyle($node, $styles['paragraph']));
+ $textRun = new TextRun($style);
// Create a title with level corresponding to number in heading style
// (Eg, Heading1 = 1)
diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php
index 1348a30a75..e759bfdcd6 100644
--- a/src/PhpWord/Writer/HTML/Element/Title.php
+++ b/src/PhpWord/Writer/HTML/Element/Title.php
@@ -19,9 +19,8 @@
namespace PhpOffice\PhpWord\Writer\HTML\Element;
use PhpOffice\PhpWord\Element\Title as PhpWordTitle;
-use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Writer\HTML;
-use PhpOffice\PhpWord\Writer\HTML\Style\Font;
+use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph;
/**
* TextRun element HTML writer.
@@ -44,17 +43,21 @@ public function write()
$tag = 'h' . $this->element->getDepth();
$text = $this->element->getText();
+ $paragraphStyle = null;
if (is_string($text)) {
$text = $this->parentWriter->escapeHTML($text);
} else {
+ $paragraphStyle = $text->getParagraphStyle();
$writer = new Container($this->parentWriter, $text);
$text = $writer->write();
}
$css = '';
- $style = Style::getStyle('Heading_' . $this->element->getDepth());
- if ($style !== null) {
- $styleWriter = new Font($style);
- $css = ' style="' . $styleWriter->write() . '"';
+ if (is_object($paragraphStyle)) {
+ $styleWriter = new Paragraph($paragraphStyle);
+ $write = $styleWriter->write();
+ if ($write !== '') {
+ $css = " style=\"$write\"";
+ }
}
$content = "<{$tag}{$css}>{$text}{$tag}>" . PHP_EOL;
diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php
index 0f295e58c3..f8af52ccb1 100644
--- a/src/PhpWord/Writer/HTML/Part/Head.php
+++ b/src/PhpWord/Writer/HTML/Part/Head.php
@@ -137,6 +137,7 @@ private function writeStyles(): string
$styleWriter = new FontStyleWriter($style);
if ($style->getStyleType() == 'title') {
$name = str_replace('Heading_', 'h', $name);
+ $css .= "{$name} {" . $styleWriter->write() . '}' . PHP_EOL;
$styleParagraph = $style->getParagraph();
$style = $styleParagraph;
} else {
diff --git a/tests/PhpWordTests/Shared/HtmlHeadingsTest.php b/tests/PhpWordTests/Shared/HtmlHeadingsTest.php
index 2f11386d04..8ecc95b773 100644
--- a/tests/PhpWordTests/Shared/HtmlHeadingsTest.php
+++ b/tests/PhpWordTests/Shared/HtmlHeadingsTest.php
@@ -40,7 +40,7 @@ public function testRoundTripHeadings(): void
$section = $originalDoc->addSection();
$expectedStrings = [];
$section->addTitle('Title 1', 1);
- $expectedStrings[] = 'Title 1
';
+ $expectedStrings[] = 'Title 1
';
for ($i = 2; $i <= 6; ++$i) {
$textRun = new TextRun();
$textRun->addText('Title ');
@@ -59,9 +59,8 @@ public function testRoundTripHeadings(): void
SharedHtml::addHtml($newSection, $content, true);
$newWriter = new HtmlWriter($newDoc);
$newContent = $newWriter->getContent();
- // Reader transforms Text to TextRun,
- // but result is functionally the same.
- $firstStringAsTextRun = 'Title 1
';
- self::assertSame($content, str_replace($firstStringAsTextRun, $expectedStrings[0], $newContent));
+
+ // This needs work
+ self::assertSame($newContent, str_replace('h1 {font-size: 20pt;}' . PHP_EOL, '', $content));
}
}
diff --git a/tests/PhpWordTests/Shared/HtmlTest.php b/tests/PhpWordTests/Shared/HtmlTest.php
index d50a5176d7..50f1e699a6 100644
--- a/tests/PhpWordTests/Shared/HtmlTest.php
+++ b/tests/PhpWordTests/Shared/HtmlTest.php
@@ -24,6 +24,7 @@
use PhpOffice\PhpWord\Element\Table;
use PhpOffice\PhpWord\Element\Text;
use PhpOffice\PhpWord\Element\TextRun;
+use PhpOffice\PhpWord\Element\Title;
use PhpOffice\PhpWord\PhpWord;
use PhpOffice\PhpWord\Settings;
use PhpOffice\PhpWord\Shared\Converter;
@@ -134,6 +135,8 @@ public function testParseHeader(): void
self::assertCount(1, $section->getElements());
$element = $section->getElement(0);
+ self::assertInstanceOf(Title::class, $element);
+ $element = $element->getText();
self::assertInstanceOf(TextRun::class, $element);
self::assertInstanceOf(Paragraph::class, $element->getParagraphStyle());
self::assertEquals('Heading1', $element->getParagraphStyle()->getStyleName());
@@ -155,6 +158,8 @@ public function testParseHeaderStyle(): void
self::assertCount(1, $section->getElements());
$element = $section->getElement(0);
+ self::assertInstanceOf(Title::class, $element);
+ $element = $element->getText();
self::assertInstanceOf(TextRun::class, $element);
self::assertInstanceOf(Paragraph::class, $element->getParagraphStyle());
self::assertEquals('Heading1', $element->getParagraphStyle()->getStyleName());
diff --git a/tests/PhpWordTests/Writer/HTML/PartTest.php b/tests/PhpWordTests/Writer/HTML/PartTest.php
index a9d91b9530..2ccb96a799 100644
--- a/tests/PhpWordTests/Writer/HTML/PartTest.php
+++ b/tests/PhpWordTests/Writer/HTML/PartTest.php
@@ -179,17 +179,15 @@ public function testTitleStyles(): void
$xpath = new DOMXPath($dom);
$style = Helper::getTextContent($xpath, '/html/head/style');
- //self::assertNotFalse(strpos($style, 'h1 {font-family: \'Calibri\'; font-weight: bold;}'));
+ self::assertNotFalse(strpos($style, 'h1 {font-family: \'Calibri\'; font-weight: bold;}'));
self::assertNotFalse(strpos($style, 'h1 {margin-top: 0.5pt; margin-bottom: 0.5pt;}'));
- //self::assertNotFalse(strpos($style, 'h2 {font-family: \'Times New Roman\'; font-style: italic;}'));
+ self::assertNotFalse(strpos($style, 'h2 {font-family: \'Times New Roman\'; font-style: italic;}'));
self::assertNotFalse(strpos($style, 'h2 {margin-top: 0.25pt; margin-bottom: 0.25pt;}'));
self::assertEquals(1, Helper::getLength($xpath, '/html/body/div/h1'));
self::assertEquals(2, Helper::getLength($xpath, '/html/body/div/h2'));
- // code for getNamedItem had been erroneous
- self::assertSame("font-family: 'Calibri'; font-weight: bold;", Helper::getNamedItem($xpath, '/html/body/div/h1', 'style')->textContent);
$html = Helper::getHtmlString($phpWord);
- self::assertStringContainsString('Header 1 #1
', $html);
- self::assertStringContainsString('Header 2 #1
', $html);
- self::assertStringContainsString('Header 2 #2
', $html);
+ self::assertStringContainsString('Header 1 #1
', $html);
+ self::assertStringContainsString('Header 2 #1
', $html);
+ self::assertStringContainsString('Header 2 #2
', $html);
}
}
From 92a4c5e1e45eb11ce5880671fd9a508a4bb2685f Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Thu, 6 Feb 2025 00:25:14 -0800
Subject: [PATCH 23/24] Html Writer Duplicate Header Styles in Style Tags
Nominally redundant, but makes things easier for Html Reader.
---
src/PhpWord/Writer/HTML/Element/Title.php | 19 +++++++++++++++----
.../PhpWordTests/Shared/HtmlHeadingsTest.php | 16 +++++++++++++---
tests/PhpWordTests/Writer/HTML/PartTest.php | 6 +++---
3 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php
index e759bfdcd6..43806a648c 100644
--- a/src/PhpWord/Writer/HTML/Element/Title.php
+++ b/src/PhpWord/Writer/HTML/Element/Title.php
@@ -19,7 +19,9 @@
namespace PhpOffice\PhpWord\Writer\HTML\Element;
use PhpOffice\PhpWord\Element\Title as PhpWordTitle;
+use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Writer\HTML;
+use PhpOffice\PhpWord\Writer\HTML\Style\Font;
use PhpOffice\PhpWord\Writer\HTML\Style\Paragraph;
/**
@@ -51,14 +53,23 @@ public function write()
$writer = new Container($this->parentWriter, $text);
$text = $writer->write();
}
- $css = '';
+ $write1 = $write2 = $write3 = '';
+ $style = Style::getStyle('Heading_' . $this->element->getDepth());
+ if ($style !== null) {
+ $styleWriter = new Font($style);
+ $write1 = $styleWriter->write();
+ }
if (is_object($paragraphStyle)) {
$styleWriter = new Paragraph($paragraphStyle);
- $write = $styleWriter->write();
- if ($write !== '') {
- $css = " style=\"$write\"";
+ $write3 = $styleWriter->write();
+ if ($write1 !== '' && $write3 !== '') {
+ $write2 = ' ';
}
}
+ $css = "$write1$write2$write3";
+ if ($css !== '') {
+ $css = " style=\"$css\"";
+ }
$content = "<{$tag}{$css}>{$text}{$tag}>" . PHP_EOL;
diff --git a/tests/PhpWordTests/Shared/HtmlHeadingsTest.php b/tests/PhpWordTests/Shared/HtmlHeadingsTest.php
index 8ecc95b773..331935fbae 100644
--- a/tests/PhpWordTests/Shared/HtmlHeadingsTest.php
+++ b/tests/PhpWordTests/Shared/HtmlHeadingsTest.php
@@ -40,7 +40,7 @@ public function testRoundTripHeadings(): void
$section = $originalDoc->addSection();
$expectedStrings = [];
$section->addTitle('Title 1', 1);
- $expectedStrings[] = 'Title 1
';
+ $expectedStrings[] = 'Title 1
';
for ($i = 2; $i <= 6; ++$i) {
$textRun = new TextRun();
$textRun->addText('Title ');
@@ -59,8 +59,18 @@ public function testRoundTripHeadings(): void
SharedHtml::addHtml($newSection, $content, true);
$newWriter = new HtmlWriter($newDoc);
$newContent = $newWriter->getContent();
+ // Reader does not yet support h1 declaration in css.
+ $content = str_replace('h1 {font-size: 20pt;}' . PHP_EOL, '', $content);
- // This needs work
- self::assertSame($newContent, str_replace('h1 {font-size: 20pt;}' . PHP_EOL, '', $content));
+ // Reader transforms Text to TextRun,
+ // but result is functionally the same.
+ self::assertSame(
+ $newContent,
+ str_replace(
+ 'Title 1
',
+ 'Title 1
',
+ $content
+ )
+ );
}
}
diff --git a/tests/PhpWordTests/Writer/HTML/PartTest.php b/tests/PhpWordTests/Writer/HTML/PartTest.php
index 2ccb96a799..0fe43c2350 100644
--- a/tests/PhpWordTests/Writer/HTML/PartTest.php
+++ b/tests/PhpWordTests/Writer/HTML/PartTest.php
@@ -186,8 +186,8 @@ public function testTitleStyles(): void
self::assertEquals(1, Helper::getLength($xpath, '/html/body/div/h1'));
self::assertEquals(2, Helper::getLength($xpath, '/html/body/div/h2'));
$html = Helper::getHtmlString($phpWord);
- self::assertStringContainsString('Header 1 #1
', $html);
- self::assertStringContainsString('Header 2 #1
', $html);
- self::assertStringContainsString('Header 2 #2
', $html);
+ self::assertStringContainsString('Header 1 #1
', $html);
+ self::assertStringContainsString('Header 2 #1
', $html);
+ self::assertStringContainsString('Header 2 #2
', $html);
}
}
From 60dbd8cd26e1abcb966c5977a155dc6ff591e62f Mon Sep 17 00:00:00 2001
From: oleibman <10341515+oleibman@users.noreply.github.com>
Date: Wed, 12 Feb 2025 13:11:27 -0800
Subject: [PATCH 24/24] Keep Up With 2533
---
src/PhpWord/Writer/HTML/Element/Title.php | 4 ++--
src/PhpWord/Writer/HTML/Part/Head.php | 1 -
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/PhpWord/Writer/HTML/Element/Title.php b/src/PhpWord/Writer/HTML/Element/Title.php
index 43806a648c..f3aeb395f4 100644
--- a/src/PhpWord/Writer/HTML/Element/Title.php
+++ b/src/PhpWord/Writer/HTML/Element/Title.php
@@ -18,7 +18,7 @@
namespace PhpOffice\PhpWord\Writer\HTML\Element;
-use PhpOffice\PhpWord\Element\Title as PhpWordTitle;
+use PhpOffice\PhpWord\Element\Title as ElementTitle;
use PhpOffice\PhpWord\Style;
use PhpOffice\PhpWord\Writer\HTML;
use PhpOffice\PhpWord\Writer\HTML\Style\Font;
@@ -38,7 +38,7 @@ class Title extends AbstractElement
*/
public function write()
{
- if (!$this->element instanceof PhpWordTitle) {
+ if (!$this->element instanceof ElementTitle) {
return '';
}
diff --git a/src/PhpWord/Writer/HTML/Part/Head.php b/src/PhpWord/Writer/HTML/Part/Head.php
index f8af52ccb1..4da526075d 100644
--- a/src/PhpWord/Writer/HTML/Part/Head.php
+++ b/src/PhpWord/Writer/HTML/Part/Head.php
@@ -101,7 +101,6 @@ private function writeStyles(): string
foreach ([
'body' => $bodyarray,
- //'*' => $astarray,
'a.NoteRef' => [
'text-decoration' => 'none',
],