Describe the bug and add attachments
This is a PhpWord bug: Html::addHtml() correctly decodes & → & from HTML, but when PhpWord writes the OOXML, it fails to re-escape & back to & inside <w:t> tags, so a broken file is created that Word can't open.
I fixed with the below:
//fix for phpword bug - PhpWord doesn't escape & in <w:t> content, so post-fix the generated XML
$zipFix = new ZipArchive();
if ($zipFix->open($tempFile) === true) {
$docXml = $zipFix->getFromName('word/document.xml');
// Fix bare & that PhpWord failed to escape (only unescaped ones, not & etc.)
$docXml = preg_replace('/&(?!amp;|lt;|gt;|quot;|apos;|#\d+;|#x[0-9a-fA-F]+;)/i', '&', $docXml);
$zipFix->addFromString('word/document.xml', $docXml);
$zipFix->close();
}
Expected behavior
Generate a file that can be opened by MS Word.
Steps to reproduce
$phpWord = new PhpWord();
$phpWord->setDefaultFontName('Times New Roman');
$phpWord->setDefaultFontSize(10);
$margins = [
'marginLeft' => 720,
'marginRight' => 720,
'marginTop' => 720,
'marginBottom' => 720,
];
$section = $phpWord->addSection($margins);
$footer = $section->addFooter();
$footer->addText('TEST', array('italic' => true));
$htmlTestStr = '
';
$htmlTestStr .= '
Prepared By / Record & Return To:
';
$htmlTestStr .= '
';
$htmlTestStr = str_ireplace('
', '
', $htmlTestStr);
// Escape bare ampersands that aren't already part of an HTML entity
$htmlTestStr = preg_replace('/&(?!amp;|lt;|gt;|quot;|apos;|#\d+;|#x[0-9a-fA-F]+;)/i', '&', $htmlTestStr);
//element,html,fullHTML,preserveWhiteSpace
Html::addHtml($section, $htmlTestStr, true, false);
$tempFile = tempnam(sys_get_temp_dir(), 'phpword');
$objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007');
$objWriter->save($tempFile);
//fix for phpword bug - PhpWord doesn't escape & in <w:t> content, so post-fix the generated XML
$zipFix = new ZipArchive();
if ($zipFix->open($tempFile) === true) {
$docXml = $zipFix->getFromName('word/document.xml');
// Fix bare & that PhpWord failed to escape (only unescaped ones, not & etc.)
$docXml = preg_replace('/&(?!amp;|lt;|gt;|quot;|apos;|#\d+;|#x[0-9a-fA-F]+;)/i', '&', $docXml);
$zipFix->addFromString('word/document.xml', $docXml);
$zipFix->close();
}
//Set download headers
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="test.docx"');
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($tempFile));
// Output file and delete the temp file
readfile($tempFile);
unlink($tempFile);
exit;
PHPWord version(s) where the bug happened
1.4
PHP version(s) where the bug happened
8.3
Priority
Describe the bug and add attachments
This is a PhpWord bug: Html::addHtml() correctly decodes & → & from HTML, but when PhpWord writes the OOXML, it fails to re-escape & back to & inside <w:t> tags, so a broken file is created that Word can't open.
I fixed with the below:
//fix for phpword bug - PhpWord doesn't escape & in <w:t> content, so post-fix the generated XML
$zipFix = new ZipArchive();
if ($zipFix->open($tempFile) === true) {
$docXml = $zipFix->getFromName('word/document.xml');
// Fix bare & that PhpWord failed to escape (only unescaped ones, not & etc.)
$docXml = preg_replace('/&(?!amp;|lt;|gt;|quot;|apos;|#\d+;|#x[0-9a-fA-F]+;)/i', '&', $docXml);
$zipFix->addFromString('word/document.xml', $docXml);
$zipFix->close();
}
Expected behavior
Generate a file that can be opened by MS Word.
Steps to reproduce
$htmlTestStr = '
'; $htmlTestStr .= 'Prepared By / Record & Return To:
', '
', $htmlTestStr); // Escape bare ampersands that aren't already part of an HTML entity $htmlTestStr = preg_replace('/&(?!amp;|lt;|gt;|quot;|apos;|#\d+;|#x[0-9a-fA-F]+;)/i', '&', $htmlTestStr); //element,html,fullHTML,preserveWhiteSpace Html::addHtml($section, $htmlTestStr, true, false); $tempFile = tempnam(sys_get_temp_dir(), 'phpword'); $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); $objWriter->save($tempFile);
//fix for phpword bug - PhpWord doesn't escape & in <w:t> content, so post-fix the generated XML
$zipFix = new ZipArchive();
if ($zipFix->open($tempFile) === true) {
$docXml = $zipFix->getFromName('word/document.xml');
// Fix bare & that PhpWord failed to escape (only unescaped ones, not & etc.)
$docXml = preg_replace('/&(?!amp;|lt;|gt;|quot;|apos;|#\d+;|#x[0-9a-fA-F]+;)/i', '&', $docXml);
$zipFix->addFromString('word/document.xml', $docXml);
$zipFix->close();
}
PHPWord version(s) where the bug happened
1.4
PHP version(s) where the bug happened
8.3
Priority