From b962897443e7ced5665f71f0e0b8de00dda42459 Mon Sep 17 00:00:00 2001 From: Owen Leibman Date: Fri, 3 Dec 2021 16:38:33 -0800 Subject: [PATCH] Mpdf With Very Many Styles Fix #2432. Probably for memory reasons, PhpSpreadsheet divides its data into chunks when writing to Mpdf. However, if the first chunk has so many styles that the `body` tag is not included in the chunk, Mpdf will not handle it correctly. Code is changed to ensure that the first chunk always contains the body tag. Because this error becomes evident only when opening the PDF file itself, it is difficult to write a test case. I have instead added a new sample file which meets the conditions which would have led to the error, and which can be examined to show that it is created correctly. --- samples/Pdf/21c_Pdf.php | 25 +++++++++++++++++++++++++ src/PhpSpreadsheet/Writer/Html.php | 4 +++- src/PhpSpreadsheet/Writer/Pdf/Mpdf.php | 9 +++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 samples/Pdf/21c_Pdf.php diff --git a/samples/Pdf/21c_Pdf.php b/samples/Pdf/21c_Pdf.php new file mode 100644 index 0000000000..6fe12664bd --- /dev/null +++ b/samples/Pdf/21c_Pdf.php @@ -0,0 +1,25 @@ +getActiveSheet(); +$counter = 0; +$helper->log('Populate spreadsheet'); +for ($row = 1; $row < 501; ++$row) { + $sheet->getCell("A$row")->setValue(++$counter); + // Add many styles by using slight variations of font color for each. + $sheet->getCell("A$row")->getStyle()->getFont()->getColor()->setRgb(sprintf('%06x', $counter)); + $sheet->getCell("B$row")->setValue(++$counter); + $sheet->getCell("C$row")->setValue(++$counter); +} + +$helper->log('Write to Mpdf'); +$writer = new Mpdf($spreadsheet); +$filename = $helper->getFileName('21c_Pdf_mpdf.xlsx', 'pdf'); +$writer->save($filename); +$helper->log("Saved $filename"); diff --git a/src/PhpSpreadsheet/Writer/Html.php b/src/PhpSpreadsheet/Writer/Html.php index a59ea1f931..9b69807486 100644 --- a/src/PhpSpreadsheet/Writer/Html.php +++ b/src/PhpSpreadsheet/Writer/Html.php @@ -356,6 +356,8 @@ private static function generateMeta($val, $desc) : ''; } + public const BODY_LINE = ' ' . PHP_EOL; + /** * Generate HTML header. * @@ -386,7 +388,7 @@ public function generateHTMLHeader($includeStyles = false) $html .= ' ' . PHP_EOL; $html .= '' . PHP_EOL; - $html .= ' ' . PHP_EOL; + $html .= self::BODY_LINE; return $html; } diff --git a/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php b/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php index 8d0eda91a7..e8a9ee7750 100644 --- a/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php +++ b/src/PhpSpreadsheet/Writer/Pdf/Mpdf.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Pdf; use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup; +use PhpOffice\PhpSpreadsheet\Writer\Html; use PhpOffice\PhpSpreadsheet\Writer\Pdf; class Mpdf extends Pdf @@ -82,6 +83,14 @@ public function save($filename, int $flags = 0): void $pdf->SetCreator($this->spreadsheet->getProperties()->getCreator()); $html = $this->generateHTMLAll(); + $bodyLocation = strpos($html, Html::BODY_LINE); + // Make sure first data presented to Mpdf includes body tag + // so that Mpdf doesn't parse it as content. Issue 2432. + if ($bodyLocation !== false) { + $bodyLocation += strlen(Html::BODY_LINE); + $pdf->WriteHTML(substr($html, 0, $bodyLocation)); + $html = substr($html, $bodyLocation); + } foreach (\array_chunk(\explode(PHP_EOL, $html), 1000) as $lines) { $pdf->WriteHTML(\implode(PHP_EOL, $lines)); }