From 7e90a7999eb7e04687b2edfacf1721fb240cb2fc Mon Sep 17 00:00:00 2001 From: hpj <240088298@qq.com> Date: Wed, 10 Jan 2024 18:13:07 +0800 Subject: [PATCH 1/7] Add a method to TemplateProcessor for rendering HTML content. --- src/PhpWord/TemplateProcessor.php | 92 +++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 8aee40c546..0341a0efee 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -24,9 +24,11 @@ use PhpOffice\PhpWord\Exception\CopyFileException; use PhpOffice\PhpWord\Exception\CreateTemporaryFileException; use PhpOffice\PhpWord\Exception\Exception; +use PhpOffice\PhpWord\Shared\Html; use PhpOffice\PhpWord\Shared\Text; use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Shared\ZipArchive; +use PhpOffice\PhpWord\Writer\Word2007; use Throwable; use XSLTProcessor; @@ -315,6 +317,96 @@ public function setComplexBlock($search, Element\AbstractElement $complexType): $this->replaceXmlBlock($search, $xmlWriter->getData(), 'w:p'); } + /** + * @param string $search + * @param string $htmlContent + */ + public function setHtmlBlock($search,$htmlContent,$fullHtml=false): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section,$htmlContent,$fullHtml); + $zip = $this->zip(); + $obj = new Word2007($phpWord); + $refClass = new \ReflectionClass(Word2007::class); + $addFilesToPackage = $refClass->getMethod('addFilesToPackage'); + $addFilesToPackage->setAccessible(true); + $sectionMedia = Media::getElements('section'); + //add image to zip + if (!empty($sectionMedia)) { + //insert image to zip + $res = $addFilesToPackage->invoke($obj,$zip, $sectionMedia); + $registerContentTypes = $refClass->getMethod('registerContentTypes'); + $registerContentTypes->setAccessible(true); + $registerContentTypes->invoke($obj,$sectionMedia); + + $relationships = $refClass->getProperty('relationships'); + $relationships->setAccessible(true); + $tmpRelationships = []; + foreach ($sectionMedia as $element) { + $tmpRelationships[] = $element; + } + $relationships->setValue($obj,$tmpRelationships); + } + $documentWriterPart = $obj->getWriterPart("Document"); + $relsDocumentWriterPart = $obj->getWriterPart("RelsDocument"); + $documentXml = $documentWriterPart->write(); + $relsDocumentXml = $relsDocumentWriterPart->write(); + // Load the XML string into a SimpleXMLElement + $xml = simplexml_load_string($documentXml); + // Extract content between tags + $bodyContent = $xml->xpath('//w:body/*'); + // Output the extracted content + $documentBodyStr = ""; + foreach ($bodyContent as $element) { + $documentBodyStr .= $element->asXML(); + } + //replace html content r:id vaule avoid rid conflict + $rIdsElement = $xml->xpath('//*[@r:id]'); + $rIdValuesMap = []; + if ($rIdsElement){ + foreach ($rIdsElement as $idEle){ + $rid = (string)$idEle->attributes('r', true)->id; + $rIdValuesMap[$rid] = $rid; + } + } + if (!empty($rIdValuesMap )){ + foreach ($rIdValuesMap as $rid => $value){ + $replactVulue = $rid."-1"; + $rIdValuesMap[$rid] = $replactVulue; + $documentBodyStr = str_replace($rid,$replactVulue,$documentBodyStr); + } + } + //replace document.xml + $this->replaceXmlBlock($search, $documentBodyStr, 'w:p'); + + $xml = simplexml_load_string($relsDocumentXml); + // Register the namespace + $xml->registerXPathNamespace('ns', 'http://schemas.openxmlformats.org/package/2006/relationships'); + // Use XPath to find all Relationship nodes + $RelationshipXmls = $xml->xpath('//ns:Relationship'); + $RelationshipStr = ""; + foreach ($RelationshipXmls as $relationshipXml){ + $rid = (string)$relationshipXml->attributes(); + if (isset($rIdValuesMap[$rid])){ + $tmpStr = $relationshipXml->asXML(); + $tmpStr = str_replace($rid,$rIdValuesMap[$rid],$tmpStr); + $RelationshipStr .= $tmpStr; + } + } + //add relation to document.xml.rels + if ($RelationshipStr){ + $relsFileName = $this->getRelationsName($this->getMainPartName()); + $content = $this->tempDocumentRelations[$this->getMainPartName()]; + $endStr = ""; + $replaceValue = $RelationshipStr.$endStr; + $content = str_replace($endStr,$replaceValue,$content); + $this->tempDocumentRelations[$this->getMainPartName()] = $content ; + } + + } + + /** * @param mixed $search * @param mixed $replace From 15e5ad2338ac826f877309e9c44e13200ea65ca7 Mon Sep 17 00:00:00 2001 From: hpj <240088298@qq.com> Date: Wed, 10 Jan 2024 19:56:16 +0800 Subject: [PATCH 2/7] fix format --- src/PhpWord/TemplateProcessor.php | 57 +++++++++--------- tests/PhpWordTests/TemplateProcessorTest.php | 15 +++++ .../_files/templates/template_to_html.docx | Bin 0 -> 11182 bytes 3 files changed, 43 insertions(+), 29 deletions(-) create mode 100644 tests/PhpWordTests/_files/templates/template_to_html.docx diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 0341a0efee..797e377b3f 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -29,6 +29,7 @@ use PhpOffice\PhpWord\Shared\XMLWriter; use PhpOffice\PhpWord\Shared\ZipArchive; use PhpOffice\PhpWord\Writer\Word2007; +use ReflectionClass; use Throwable; use XSLTProcessor; @@ -321,24 +322,24 @@ public function setComplexBlock($search, Element\AbstractElement $complexType): * @param string $search * @param string $htmlContent */ - public function setHtmlBlock($search,$htmlContent,$fullHtml=false): void + public function setHtmlBlock($search, $htmlContent, $fullHtml = false): void { $phpWord = new PhpWord(); $section = $phpWord->addSection(); - Html::addHtml($section,$htmlContent,$fullHtml); + Html::addHtml($section, $htmlContent, $fullHtml); $zip = $this->zip(); $obj = new Word2007($phpWord); - $refClass = new \ReflectionClass(Word2007::class); + $refClass = new ReflectionClass(Word2007::class); $addFilesToPackage = $refClass->getMethod('addFilesToPackage'); $addFilesToPackage->setAccessible(true); $sectionMedia = Media::getElements('section'); //add image to zip if (!empty($sectionMedia)) { //insert image to zip - $res = $addFilesToPackage->invoke($obj,$zip, $sectionMedia); + $res = $addFilesToPackage->invoke($obj, $zip, $sectionMedia); $registerContentTypes = $refClass->getMethod('registerContentTypes'); $registerContentTypes->setAccessible(true); - $registerContentTypes->invoke($obj,$sectionMedia); + $registerContentTypes->invoke($obj, $sectionMedia); $relationships = $refClass->getProperty('relationships'); $relationships->setAccessible(true); @@ -346,10 +347,10 @@ public function setHtmlBlock($search,$htmlContent,$fullHtml=false): void foreach ($sectionMedia as $element) { $tmpRelationships[] = $element; } - $relationships->setValue($obj,$tmpRelationships); + $relationships->setValue($obj, $tmpRelationships); } - $documentWriterPart = $obj->getWriterPart("Document"); - $relsDocumentWriterPart = $obj->getWriterPart("RelsDocument"); + $documentWriterPart = $obj->getWriterPart('Document'); + $relsDocumentWriterPart = $obj->getWriterPart('RelsDocument'); $documentXml = $documentWriterPart->write(); $relsDocumentXml = $relsDocumentWriterPart->write(); // Load the XML string into a SimpleXMLElement @@ -357,24 +358,24 @@ public function setHtmlBlock($search,$htmlContent,$fullHtml=false): void // Extract content between tags $bodyContent = $xml->xpath('//w:body/*'); // Output the extracted content - $documentBodyStr = ""; + $documentBodyStr = ''; foreach ($bodyContent as $element) { $documentBodyStr .= $element->asXML(); } //replace html content r:id vaule avoid rid conflict - $rIdsElement = $xml->xpath('//*[@r:id]'); + $rIdsElement = $xml->xpath('//*[@r:id]'); $rIdValuesMap = []; - if ($rIdsElement){ - foreach ($rIdsElement as $idEle){ - $rid = (string)$idEle->attributes('r', true)->id; + if ($rIdsElement) { + foreach ($rIdsElement as $idEle) { + $rid = (string) $idEle->attributes('r', true)->id; $rIdValuesMap[$rid] = $rid; } } - if (!empty($rIdValuesMap )){ - foreach ($rIdValuesMap as $rid => $value){ - $replactVulue = $rid."-1"; + if (!empty($rIdValuesMap)) { + foreach ($rIdValuesMap as $rid => $value) { + $replactVulue = $rid . '-1'; $rIdValuesMap[$rid] = $replactVulue; - $documentBodyStr = str_replace($rid,$replactVulue,$documentBodyStr); + $documentBodyStr = str_replace($rid, $replactVulue, $documentBodyStr); } } //replace document.xml @@ -385,28 +386,26 @@ public function setHtmlBlock($search,$htmlContent,$fullHtml=false): void $xml->registerXPathNamespace('ns', 'http://schemas.openxmlformats.org/package/2006/relationships'); // Use XPath to find all Relationship nodes $RelationshipXmls = $xml->xpath('//ns:Relationship'); - $RelationshipStr = ""; - foreach ($RelationshipXmls as $relationshipXml){ - $rid = (string)$relationshipXml->attributes(); - if (isset($rIdValuesMap[$rid])){ + $RelationshipStr = ''; + foreach ($RelationshipXmls as $relationshipXml) { + $rid = (string) $relationshipXml->attributes(); + if (isset($rIdValuesMap[$rid])) { $tmpStr = $relationshipXml->asXML(); - $tmpStr = str_replace($rid,$rIdValuesMap[$rid],$tmpStr); + $tmpStr = str_replace($rid, $rIdValuesMap[$rid], $tmpStr); $RelationshipStr .= $tmpStr; } } //add relation to document.xml.rels - if ($RelationshipStr){ + if ($RelationshipStr) { $relsFileName = $this->getRelationsName($this->getMainPartName()); $content = $this->tempDocumentRelations[$this->getMainPartName()]; - $endStr = ""; - $replaceValue = $RelationshipStr.$endStr; - $content = str_replace($endStr,$replaceValue,$content); - $this->tempDocumentRelations[$this->getMainPartName()] = $content ; + $endStr = ''; + $replaceValue = $RelationshipStr . $endStr; + $content = str_replace($endStr, $replaceValue, $content); + $this->tempDocumentRelations[$this->getMainPartName()] = $content; } - } - /** * @param mixed $search * @param mixed $replace diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 49e88d1b5b..6ec1a3d106 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -1630,4 +1630,19 @@ public function testShouldMakeFieldsUpdateOnOpenWithCustomMacro(): void $templateProcessor->setUpdateFields(false); self::assertStringContainsString('', $templateProcessor->getSettingsPart()); } + + public function testSetHtml(): void + { + Settings::setOutputEscapingEnabled(true); + $content = '

+

+

HPJ LDAP(Lightweight Directory Access Protocol),轻量级目录访问协议,是一种在线目录访问协议,主要用于目录中资源的搜索和查询。如果在用户可控制的输入中没有对 LDAP 语法进行除去或引用,那么生成的 LDAP 查询可能会导致

'; + $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/template_to_html.docx'); + $templateProcessor->setHtmlBlock('html_content', $content); + $docName = 'html-to-template-test.docx'; + $templateProcessor->saveAs($docName); + $docFound = file_exists($docName); + unlink($docName); + self::assertTrue($docFound); + } } diff --git a/tests/PhpWordTests/_files/templates/template_to_html.docx b/tests/PhpWordTests/_files/templates/template_to_html.docx new file mode 100644 index 0000000000000000000000000000000000000000..dd2e6a8ebdea6a6404dde0035330b995b65e1bde GIT binary patch literal 11182 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 literal 0 HcmV?d00001 From 65c155cfa42d80b37584030abe3694e6445732b6 Mon Sep 17 00:00:00 2001 From: hpj <240088298@qq.com> Date: Wed, 10 Jan 2024 20:07:42 +0800 Subject: [PATCH 3/7] analyse code --- src/PhpWord/TemplateProcessor.php | 32 +++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 797e377b3f..6c278c854a 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -321,6 +321,7 @@ public function setComplexBlock($search, Element\AbstractElement $complexType): /** * @param string $search * @param string $htmlContent + * @param bool $fullHtml */ public function setHtmlBlock($search, $htmlContent, $fullHtml = false): void { @@ -356,12 +357,19 @@ public function setHtmlBlock($search, $htmlContent, $fullHtml = false): void // Load the XML string into a SimpleXMLElement $xml = simplexml_load_string($documentXml); // Extract content between tags + if ($xml === false){ + return; + } $bodyContent = $xml->xpath('//w:body/*'); // Output the extracted content $documentBodyStr = ''; - foreach ($bodyContent as $element) { - $documentBodyStr .= $element->asXML(); + if ($bodyContent) { + foreach ($bodyContent as $element) { + $documentBodyStr .= $element->asXML(); + } } + + //replace html content r:id vaule avoid rid conflict $rIdsElement = $xml->xpath('//*[@r:id]'); $rIdValuesMap = []; @@ -382,19 +390,27 @@ public function setHtmlBlock($search, $htmlContent, $fullHtml = false): void $this->replaceXmlBlock($search, $documentBodyStr, 'w:p'); $xml = simplexml_load_string($relsDocumentXml); + if ($xml === false){ + return; + } // Register the namespace $xml->registerXPathNamespace('ns', 'http://schemas.openxmlformats.org/package/2006/relationships'); // Use XPath to find all Relationship nodes $RelationshipXmls = $xml->xpath('//ns:Relationship'); $RelationshipStr = ''; - foreach ($RelationshipXmls as $relationshipXml) { - $rid = (string) $relationshipXml->attributes(); - if (isset($rIdValuesMap[$rid])) { - $tmpStr = $relationshipXml->asXML(); - $tmpStr = str_replace($rid, $rIdValuesMap[$rid], $tmpStr); - $RelationshipStr .= $tmpStr; + if ($RelationshipXmls){ + foreach ($RelationshipXmls as $relationshipXml) { + $rid = (string) $relationshipXml->attributes(); + if (isset($rIdValuesMap[$rid])) { + $tmpStr = $relationshipXml->asXML(); + if ($tmpStr!=false){ + $tmpStr = str_replace($rid, $rIdValuesMap[$rid], $tmpStr); + $RelationshipStr .= $tmpStr; + } + } } } + //add relation to document.xml.rels if ($RelationshipStr) { $relsFileName = $this->getRelationsName($this->getMainPartName()); From 6c0c8f8f47d5cead95789017aab6d3114846f5b6 Mon Sep 17 00:00:00 2001 From: hpj <240088298@qq.com> Date: Wed, 10 Jan 2024 20:09:15 +0800 Subject: [PATCH 4/7] analyse code --- src/PhpWord/TemplateProcessor.php | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index 6c278c854a..c312bb1af2 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -357,19 +357,18 @@ public function setHtmlBlock($search, $htmlContent, $fullHtml = false): void // Load the XML string into a SimpleXMLElement $xml = simplexml_load_string($documentXml); // Extract content between tags - if ($xml === false){ + if ($xml === false) { return; } $bodyContent = $xml->xpath('//w:body/*'); // Output the extracted content $documentBodyStr = ''; if ($bodyContent) { - foreach ($bodyContent as $element) { - $documentBodyStr .= $element->asXML(); - } + foreach ($bodyContent as $element) { + $documentBodyStr .= $element->asXML(); + } } - //replace html content r:id vaule avoid rid conflict $rIdsElement = $xml->xpath('//*[@r:id]'); $rIdValuesMap = []; @@ -390,7 +389,7 @@ public function setHtmlBlock($search, $htmlContent, $fullHtml = false): void $this->replaceXmlBlock($search, $documentBodyStr, 'w:p'); $xml = simplexml_load_string($relsDocumentXml); - if ($xml === false){ + if ($xml === false) { return; } // Register the namespace @@ -398,12 +397,12 @@ public function setHtmlBlock($search, $htmlContent, $fullHtml = false): void // Use XPath to find all Relationship nodes $RelationshipXmls = $xml->xpath('//ns:Relationship'); $RelationshipStr = ''; - if ($RelationshipXmls){ + if ($RelationshipXmls) { foreach ($RelationshipXmls as $relationshipXml) { $rid = (string) $relationshipXml->attributes(); if (isset($rIdValuesMap[$rid])) { $tmpStr = $relationshipXml->asXML(); - if ($tmpStr!=false){ + if ($tmpStr != false) { $tmpStr = str_replace($rid, $rIdValuesMap[$rid], $tmpStr); $RelationshipStr .= $tmpStr; } From 41ae4354323df2395874b4e9e2c7de6af1fe57af Mon Sep 17 00:00:00 2001 From: hpj <240088298@qq.com> Date: Sun, 14 Jan 2024 01:23:36 +0800 Subject: [PATCH 5/7] Optimize test cases and handle image loading failures --- src/PhpWord/TemplateProcessor.php | 14 ++++++++++++++ tests/PhpWordTests/TemplateProcessorTest.php | 6 ++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index c312bb1af2..a19ba363fc 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -327,6 +327,20 @@ public function setHtmlBlock($search, $htmlContent, $fullHtml = false): void { $phpWord = new PhpWord(); $section = $phpWord->addSection(); + //deal remote load Image + $pattern = '/]+src\s*=\s*["\']([^"\']+)["\'][^>]*>/i'; + preg_match_all($pattern, $htmlContent, $matches); + $imageSrcList = $matches[1]; + if (!empty($imageSrcList)) { + foreach ($imageSrcList as $imageSrc) { + try { + file_get_contents($imageSrc); + }catch (\Exception $e) { + $localImg = __DIR__.'/resources/doc.png'; + $htmlContent = str_replace($imageSrc, $localImg, $htmlContent); + } + } + } Html::addHtml($section, $htmlContent, $fullHtml); $zip = $this->zip(); $obj = new Word2007($phpWord); diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 6ec1a3d106..808956bc5d 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -1634,8 +1634,10 @@ public function testShouldMakeFieldsUpdateOnOpenWithCustomMacro(): void public function testSetHtml(): void { Settings::setOutputEscapingEnabled(true); - $content = '

-

+ $image1 = __DIR__.'/_files/images/earth.jpg'; + $image2 = __DIR__.'/_files/images/mars.jpg'; + $content = '

+

HPJ LDAP(Lightweight Directory Access Protocol),轻量级目录访问协议,是一种在线目录访问协议,主要用于目录中资源的搜索和查询。如果在用户可控制的输入中没有对 LDAP 语法进行除去或引用,那么生成的 LDAP 查询可能会导致

'; $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/template_to_html.docx'); $templateProcessor->setHtmlBlock('html_content', $content); From f410fca8672366239a52298a4e8bd42fb19d9b2f Mon Sep 17 00:00:00 2001 From: hpj <240088298@qq.com> Date: Sun, 14 Jan 2024 12:09:38 +0800 Subject: [PATCH 6/7] format --- src/PhpWord/TemplateProcessor.php | 6 +++--- tests/PhpWordTests/TemplateProcessorTest.php | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index a19ba363fc..b9d180e075 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -334,9 +334,9 @@ public function setHtmlBlock($search, $htmlContent, $fullHtml = false): void if (!empty($imageSrcList)) { foreach ($imageSrcList as $imageSrc) { try { - file_get_contents($imageSrc); - }catch (\Exception $e) { - $localImg = __DIR__.'/resources/doc.png'; + $content= file_get_contents($imageSrc); + } catch (\Exception $e) { + $localImg = __DIR__ . '/resources/doc.png'; $htmlContent = str_replace($imageSrc, $localImg, $htmlContent); } } diff --git a/tests/PhpWordTests/TemplateProcessorTest.php b/tests/PhpWordTests/TemplateProcessorTest.php index 808956bc5d..bea023c918 100644 --- a/tests/PhpWordTests/TemplateProcessorTest.php +++ b/tests/PhpWordTests/TemplateProcessorTest.php @@ -1634,10 +1634,10 @@ public function testShouldMakeFieldsUpdateOnOpenWithCustomMacro(): void public function testSetHtml(): void { Settings::setOutputEscapingEnabled(true); - $image1 = __DIR__.'/_files/images/earth.jpg'; - $image2 = __DIR__.'/_files/images/mars.jpg'; - $content = '

-

+ $image1 = __DIR__ . '/_files/images/earth.jpg'; + $image2 = __DIR__ . '/_files/images/mars.jpg'; + $content = '

+

HPJ LDAP(Lightweight Directory Access Protocol),轻量级目录访问协议,是一种在线目录访问协议,主要用于目录中资源的搜索和查询。如果在用户可控制的输入中没有对 LDAP 语法进行除去或引用,那么生成的 LDAP 查询可能会导致

'; $templateProcessor = new TemplateProcessor(__DIR__ . '/_files/templates/template_to_html.docx'); $templateProcessor->setHtmlBlock('html_content', $content); From aabbc3cbc0597f479fc087aade64ae1b74755f50 Mon Sep 17 00:00:00 2001 From: hpj <240088298@qq.com> Date: Sun, 14 Jan 2024 12:17:01 +0800 Subject: [PATCH 7/7] format --- src/PhpWord/TemplateProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php index b9d180e075..cc20c73543 100644 --- a/src/PhpWord/TemplateProcessor.php +++ b/src/PhpWord/TemplateProcessor.php @@ -334,7 +334,7 @@ public function setHtmlBlock($search, $htmlContent, $fullHtml = false): void if (!empty($imageSrcList)) { foreach ($imageSrcList as $imageSrc) { try { - $content= file_get_contents($imageSrc); + $content = file_get_contents($imageSrc); } catch (\Exception $e) { $localImg = __DIR__ . '/resources/doc.png'; $htmlContent = str_replace($imageSrc, $localImg, $htmlContent);