[TikiWiki-commits] [Git][tikiwiki/tiki][30.x] Pdflib fixes upstreamed from a 27 fork

"Jonny Bradley \(@jonnybradley\) via TikiWiki-cvs" <[email protected]>
Newsgroups gmane.comp.cms.tiki.cvs
Message-ID <69f211d18fdc2_3818f80810016f@gitlab-sidekiq-low-urgency-cpu-bound-v2-d59f77678-4lr4p.mail>

Jonny Bradley pushed to branch 30.x at Tiki Wiki CMS Groupware / Tiki


Commits:
16c2347b by Jonny Bradley at 2026-04-29T14:01:40+00:00
Pdflib fixes upstreamed from a 27 fork
---
* Pdflib fixes upstreamed from a 27 fork
---
* [FIX] mpdf: Seems feedback doesn't get shown in this context so use die() to at least show the error or exception

* phpstan - no idea why 'stan says "class Mpdf\MpdfException not found" - so try this?

* phpstan namespace fix take #2

* phpstan namespace fix

* [FIX] mpdf: Prevent the chunking to avoid the pcre.backtrace_limit error from splitting html tags in half
husky is so annoying!?
(could be improved to prevent <tags> being split from closing</tags> across page feeds)

* phpcs fix

* [FIX] mpdf: Various mPDF fixes
* [FIX] mpdf: Rename the `pcre.backtrack_limit` var to be more useful
* [FIX] mpdf: Keep the body classes so we can use css to target mPDF output using `body.tiki.tiki-print.print` (or just some of them), also insert the main inline `<style>` block in the `<head>` element rather than in the `body` (and don't remove `.tiki` from the css).
* [FIX] mpdf: Remove unnecessary processing of css - mPDF supports `<strong>` now and ignores @media statements.
bloody husky wasting my time!!!!!
[FIX] mpdf: More fixes for pdflib - `SetHTMLHeader` and `SetHTMLFooter` only set header and footer for ODD pages, so do them for EVEN as well, use `AddPageByArray` instead of `AddPage` (deprecated since mPDF 5ish) and reformat some silly long lines

See merge request tikiwiki/tiki!10096


(cherry picked from commit c77834859156f9db750c2a4cdb5a9a7a1cfacaa9)

d6ecbded [FIX] mpdf: Various mPDF fixes
34faec5e phpcs fix
185d25f3 [FIX] mpdf: Prevent the chunking to avoid the pcre.backtrace_limit error from...
09841047 phpstan namespace fix
aaed15df phpstan namespace fix take #2
9fc253b5 phpstan - no idea why 'stan says "class Mpdf\MpdfException not found" - so try this?
13107154 [FIX] mpdf: Seems feedback doesn't get shown in this context so use die() to...

Co-authored-by: Jonny Bradley <[email protected]>

See merge request tikiwiki/tiki!10101

- - - - -


2 changed files:

- lib/pdflib.php
- − themes/base_files/css/printqueries.css


Changes:

=====================================
lib/pdflib.php
=====================================
@@ -5,6 +5,7 @@
 // All Rights Reserved. See copyright.txt for details and a complete list of authors.
 // Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
 
+use Mpdf\Mpdf;
 use Tiki\Lib\Auth\Tokens;
 use Tiki\Lib\Theme\ThemeLib;
 
@@ -295,7 +296,19 @@ class PdfGenerator
             if ($pdfSettings['tocheading']) {
                 $tocpreHTML = htmlspecialchars("<h1>" . $pdfSettings['tocheading'] . "</h1>", ENT_QUOTES);
             }
-            $html = "<html><tocpagebreak toc-odd-footer-name=\"footer-without-pagination\"  toc-odd-footer-value=\"1\"" . $links . " toc-preHTML=\"" . $tocpreHTML . "\" toc-resetpagenum=\"1\" toc-suppress=\"on\" />" . $html . "</html>";
+            $html = <<<HTML
+<html>
+    <tocpagebreak
+        toc-odd-footer-name="footer-without-pagination"
+        toc-odd-footer-value="1"
+        $links
+        toc-preHTML="$tocpreHTML"
+        toc-resetpagenum="1"
+        toc-suppress="on"
+    />
+    $html
+</html>
+HTML;
         }
         $this->_parseHTML($html);
         $this->_getImages($html, $tempImgArr);
@@ -321,7 +334,7 @@ class PdfGenerator
             mkdir($mpdfConfig['tempDir'], 0770, true);
         }
 
-        $mpdf = new \Mpdf\Mpdf($mpdfConfig); // @phpstan-ignore class.notFound (depends on MPdf, installed through packages)
+        $mpdf = new Mpdf($mpdfConfig); // @phpstan-ignore class.notFound (depends on MPdf, installed through packages)
         $mpdf->curlAllowUnsafeSslRequests = ($prefs['print_pdf_mpdf_allow_unsafe_ssl_requests'] ?? 'y') === 'y';
 
         $basePath = $params['base_path'] ?? TIKI_PATH ;
@@ -372,7 +385,6 @@ class PdfGenerator
         $themecss = '';
         if ($pdfSettings['print_pdf_mpdf_printfriendly'] === 'y') {
             $printcss = file_get_contents('themes/base_files/css/printpdf.css'); // external css
-            $bodycss = 'tiki tiki-print'; //execluding theme css in case print friendly is set to yes.
         } else {
             //getting theme css
             $themeLib = TikiLib::lib('theme');
@@ -430,14 +442,8 @@ class PdfGenerator
             if ($themePath) {
                 $themecss .= file_get_contents($themePath);
             }
-
-            $themecss .= "\nb,strong{font-weight:bold !important;}";
-            // preserving theme styles by removing media print styles to print what is shown on screen
-            $themecss = str_replace(["media print", "color : fff"], ["media p","color : #fff"], $themecss);
-            //  for bootstrap print hidden, screen hidden styles on divs
-            $printcss = file_get_contents('themes/base_files/css/printqueries.css');
-            $bodycss = '';
         }
+        $bodyClass = 'tiki tiki-print print';
 
         if (! empty($pdfSettings['coverpage_wiki'])) {
             $coverWikiPage = $pdfSettings['coverpage_wiki'];
@@ -482,7 +488,7 @@ class PdfGenerator
 
                 $coverHtml = '<div style="' . $coverStyle . '">' . $coverHtml . '</div>';
 
-                $coverMpdf = new \Mpdf\Mpdf($mpdfConfig); // @phpstan-ignore class.notFound (depends on MPdf, installed through packages)
+                $coverMpdf = new Mpdf($mpdfConfig); // @phpstan-ignore class.notFound (depends on MPdf, installed through packages)
                 $coverMpdf->SetHTMLHeader();
                 $coverMpdf->SetHTMLFooter();
                 $coverMpdf->AddPage(
@@ -530,8 +536,8 @@ class PdfGenerator
             '</style>';
 
         $cssStyles = str_replace(
-            [".tiki","opacity: 0;","page-break-inside: avoid;"],
-            ["","fill: #fff;opacity:0.3;stroke:black;","page-break-inside: auto;"],
+            ["opacity: 0;","page-break-inside: avoid;"],
+            ["fill: #fff;opacity:0.3;stroke:black;","page-break-inside: auto;"],
             $allCss
         );
         //PDF import templates will not work if background color is set, need to replace in css
@@ -613,7 +619,7 @@ class PdfGenerator
         }
         $pageNo = 1;
         $pagesTotal = 1;
-        $pdfLimit = ini_get('pcre.backtrack_limit');
+        $pcreBacktrackLimit = (int) ini_get('pcre.backtrack_limit');
         //end of coverpage generation
         foreach ($pdfPages as $pdfPage) {
             $resetPage = '';
@@ -716,12 +722,24 @@ class PdfGenerator
                     } elseif ($pdfPage['footer']) {
                         $footer = $pdfPage['footer'];
                     }
-                    //Add the header to the first page
                     $mpdf->SetHTMLHeader($this->processHeaderFooter($header, $params['page'] ?? ''), "O");
                     $mpdf->SetHTMLHeader($this->processHeaderFooter($header, $params['page'] ?? ''), "E");
-                    $mpdf->AddPage($pdfPage['orientation'], '', $resetPage, '', '', $pdfPage['margin_left'], $pdfPage['margin_right'], $pdfPage['margin_top'], $pdfPage['margin_bottom'], $pdfPage['margin_header'], $pdfPage['margin_footer'], '', '', '', '', '', '', '', '', '', $pdfPage['pagesize']);
+                    $mpdf->AddPageByArray(
+                        [
+                            'orientation'   => $pdfPage['orientation'],
+                            'resetpagenum'  => $resetPage,
+                            'margin-left'   => $pdfPage['margin_left'],
+                            'margin-right'  => $pdfPage['margin_right'],
+                            'margin-top'    => $pdfPage['margin_top'],
+                            'margin-bottom' => $pdfPage['margin_bottom'],
+                            //$pdfPage['margin_header'],
+                            //$pdfPage['margin_footer'],
+                            'sheet-size'    => $pdfPage['pagesize'],
+                        ]
+                    );
                     $mpdf->SetHTMLHeader($this->processHeaderFooter($header, $params['page'] ?? '')); //Add the header to other pages
                     $mpdf->SetHTMLFooter($this->processHeaderFooter($footer, $params['page'] ?? '', 'top')); //footer needs to be reset after page content is added
+                    $mpdf->SetHTMLFooter($this->processHeaderFooter($footer, $params['page'] ?? '', 'top'), 'E');
                     //checking watermark on page
                     $mpdf->SetWatermarkText($pdfPage['watermark']);
                     $mpdf->showWatermarkText = true;
@@ -750,20 +768,42 @@ class PdfGenerator
                     $pdfPage['pageContent'] = $this->getHtmlLayout($pdfPage['pageContent']);
                     $this->_getImages($pdfPage['pageContent'], $tempImgArr);
 
-                    $htmlChunk = '<html><body class="' . $bodycss . '" style="margin:0px;padding:0px;">' . $cssStyles;
+                    $htmlChunk = '<html><head>' . $cssStyles . '</head><body class="' . $bodyClass . '" style="margin:0;padding:0;">';
                     if ($prefs['print_pdf_mpdf_debug'] === 'y') {
                         $debugOutput .= $htmlChunk;
                     }
                     $mpdf->WriteHTML($htmlChunk);
-                    $pagesTotal += floor(strlen($pdfPage['pageContent']) / 3000);
+
                     //checking if page content is less than mPDF character limit, otherwise split it and loop to writeHTML
-                    for ($charLimit = 0; $charLimit <= strlen($pdfPage['pageContent']); $charLimit += $pdfLimit) {
-                        $content_slice = substr($pdfPage['pageContent'], $charLimit, $pdfLimit);
+                    $pageContentLength = strlen($pdfPage['pageContent']);
+                    $chunkStartPos = 0;
+                    while ($chunkStartPos <= $pageContentLength) {
+                        $content_slice = substr($pdfPage['pageContent'], $chunkStartPos, $pcreBacktrackLimit);
+                        if ($pageContentLength - $chunkStartPos > $pcreBacktrackLimit) {
+                            // more to come?
+                            $lastTagStart = strrpos($content_slice, '<');
+                            $lastTagEnd = strrpos($content_slice, '>');
+                            if ($lastTagStart > $lastTagEnd) {
+                                // truncate before the last unclosed tag, often a base64 data src image
+                                $newChunkStartPos = $chunkStartPos + $lastTagStart;
+                                $content_slice = substr($pdfPage['pageContent'], $chunkStartPos, $newChunkStartPos - $chunkStartPos);
+                                $chunkStartPos = $newChunkStartPos;
+                            } else {
+                                $chunkStartPos += $pcreBacktrackLimit;
+                            }
+                        } else {
+                            $chunkStartPos += $pcreBacktrackLimit;
+                        }
                         if ($content_slice) {
                             if ($prefs['print_pdf_mpdf_debug'] === 'y') {
                                 $debugOutput .= $content_slice;
                             }
-                            $mpdf->WriteHTML($content_slice);
+                            try {
+                                $mpdf->WriteHTML($content_slice);
+                            } catch (ErrorException $e) {
+                                \Feedback::error($e->getMessage());
+                                die($e->getMessage());
+                            }
                         }
                     }
                     $htmlChunk = '</body></html>';


=====================================
themes/base_files/css/printqueries.css deleted
=====================================
@@ -1,34 +0,0 @@
-@charset "utf-8";
-/* CSS Document */
-@media print {
-    .visible-print {
-        display: block !important;
-    }
-    table.visible-print {
-        display: table !important;
-    }
-    tr.visible-print {
-        display: table-row !important;
-    }
-    th.visible-print,
-    td.visible-print {
-        display: table-cell !important;
-    }
-    .visible-print-block {
-        display: block !important;
-    }
-    .visible-print-inline {
-        display: inline !important;
-    }
-    .visible-print-inline-block {
-        display: inline-block !important;
-    }
-    .hidden-print {
-        display: none !important;
-    }
-    .icon_copy_code {
-        display: none !important;
-    }
-}
-
-



View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/16c2347b859b81a3d188a56624020487452c9509

-- 
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/16c2347b859b81a3d188a56624020487452c9509
You're receiving this email because of your account on gitlab.com. Manage all notifications: https://gitlab.com/-/profile/notifications | Help: https://gitlab.com/help

_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.