[TikiWiki-commits] [Git][tikiwiki/tiki][29.x] [ENH] mpdf: Add debug output pref which saves the html sent to mPDF
"Jonny Bradley \(@jonnybradley\) via TikiWiki-cvs" <[email protected]>
| Newsgroups | gmane.comp.cms.tiki.cvs |
|---|---|
| Message-ID | <697a7886c042e_3b6d324c404a6@gitlab-sidekiq-low-urgency-cpu-bound-v2-96cd9b87c-xtmld.mail> |
Jonny Bradley pushed to branch 29.x at Tiki Wiki CMS Groupware / Tiki Commits: 5aec78ef by Jonny Bradley at 2026-01-28T20:50:17+00:00 [ENH] mpdf: Add debug output pref which saves the html sent to mPDF --- * [ENH] mpdf: Add debug output pref which saves the html sent to mPDF --- * [FIX] mpdf: Add a link to the debug output and make the warning clearer * [FIX] phpcs: Indentation fail #2 * [FIX] phpcs: Indentation fail * [FIX] mpdf: Don't add empty (whitespace) values to the css, and include the actual data for inline `url(data:...)` to avoid invalid css being sent to mPDF (also add a missing semicolon on the `opacity:0` replacement) * [FIX] mpdf: Don't add an unnecessary and incorrect `div.row` if not adding modules in `cols` within it * [ENH] mpdf: Add debug output pref which saves the html sent to mPDF in an html file (with a warning that this html file does not obey tiki permissions) See merge request tikiwiki/tiki!9320 (cherry picked from commit 53caad511811cd437967b29a8becff4b00028102) 46b6bc4e [ENH] mpdf: Add debug output pref which saves the html sent to mPDF in an html... bcd2ca0b [FIX] mpdf: Don't add an unnecessary and incorrect `div.row` if not adding... ce1d546d [FIX] mpdf: Don't add empty (whitespace) values to the css, and include the... 1a2a6fd8 [FIX] phpcs: Indentation fail ccc392cb [FIX] phpcs: Indentation fail #2 6ebe4074 [FIX] mpdf: Add a link to the debug output and make the warning clearer Co-authored-by: Jonny Bradley <[email protected]> See merge request tikiwiki/tiki!9430 - - - - - 3 changed files: - lib/pdflib.php - lib/prefs/print.php - templates/admin/include_print.tpl Changes: ===================================== lib/pdflib.php ===================================== @@ -527,13 +527,17 @@ class PdfGenerator $cssStyles = str_replace( [".tiki","opacity: 0;","page-break-inside: avoid;"], - ["","fill: #fff;opacity:0.3;stroke:black","page-break-inside: auto;"], + ["","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 $cssStyles = $this->replaceCssVariables($cssStyles); $cssStyles = $this->evaluateCalcExpressions($cssStyles); + if ($prefs['print_pdf_mpdf_debug'] === 'y') { + $debugOutput = ''; + } + if ( array_filter(array_column($pdfPages, 'pageContent'), function ($var) { return preg_match("/\bpdfinclude\b/i", $var); @@ -576,14 +580,28 @@ class PdfGenerator return date($matches[1]); }, $coverPage[$i]); } - $htm = '<body style="' . $coverPageBgColor . 'margin:0px;padding:0px"><div style="height:100%;background-image:url(' . $coverImage . ');background-size:cover;background-repeat: no-repeat;background-position: center;padding:20px;">'; - if (! empty($coverPage[0]) || ! empty($coverPage[1])) { - $htm .= '<div style="' . $coverPageBorder . 'height:95%;"> - <div style="text-align:' . $textAlign . ';margin-top:30%;' . $textColor . '"> - <div style="' . $textBgColor . $coverPageTextBorder . 'margin-bottom:10px;font-size:50px;">' . $coverPage[0] . '</div>' . $coverPage[1] . '</div></div>'; + $bodyStyle = "{$coverPageBgColor}margin:0px;padding:0px"; + $containerStyle = "height:100%;background-image:url({$coverImage});padding:20px;background-repeat:no-repeat;background-position:center;"; + $borderStyle = "{$coverPageBorder}height:95%;"; + $contentStyle = "text-align:{$textAlign};margin-top:30%;{$textColor}"; + $titleStyle = "{$textBgColor}{$coverPageTextBorder}margin-bottom:10px;font-size:50px;"; + + $htmlChunk = <<<HTML + <body style="$bodyStyle"> + <div style="$containerStyle"> + <div style="$borderStyle"> + <div style="$contentStyle"> + <div style="$titleStyle">{$coverPage[0]}</div> + {$coverPage[1]} + </div> + </div> + </div> + </body> + HTML; + if ($prefs['print_pdf_mpdf_debug'] === 'y') { + $debugOutput .= $htmlChunk; } - $htm .= '</div></body>'; - $mpdf->WriteHTML($htm); + $mpdf->WriteHTML($htmlChunk); } //Checking bookmark if (is_array($pdfSettings['autobookmarks'])) { @@ -674,7 +692,11 @@ class PdfGenerator } } } catch (Exception $e) { - $mpdf->WriteHTML("PDF not supported"); + $htmlChunk = "PDF not supported"; + if ($prefs['print_pdf_mpdf_debug'] === 'y') { + $debugOutput .= $htmlChunk; + } + $mpdf->WriteHTML($htmlChunk); } } unlink($tmpExtPDF); @@ -724,16 +746,27 @@ class PdfGenerator $pdfPage['pageContent'] = $this->getHtmlLayout($pdfPage['pageContent']); $this->_getImages($pdfPage['pageContent'], $tempImgArr); - $mpdf->WriteHTML('<html><body class="' . $bodycss . '" style="margin:0px;padding:0px;">' . $cssStyles); + $htmlChunk = '<html><body class="' . $bodycss . '" style="margin:0px;padding:0px;">' . $cssStyles; + 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); if ($content_slice) { + if ($prefs['print_pdf_mpdf_debug'] === 'y') { + $debugOutput .= $content_slice; + } $mpdf->WriteHTML($content_slice); } } - $mpdf->WriteHTML('</body></html>'); + $htmlChunk = '</body></html>'; + if ($prefs['print_pdf_mpdf_debug'] === 'y') { + $debugOutput .= $htmlChunk; + } + $mpdf->WriteHTML($htmlChunk); $pageNo++; $cssStyles = ''; //set to blank after added with first page } @@ -752,6 +785,11 @@ class PdfGenerator $this->clearTempImg($tempImgArr); $tempFile = fopen("temp/public/pdffile_" . session_id() . ".txt", "w"); fwrite($tempFile, ($pagesTotal * 30)); + + if ($prefs['print_pdf_mpdf_debug'] === 'y') { + file_put_contents('temp/mpdf_debug_output.html', $debugOutput); + } + return $mpdf->Output('', 'S'); // Return as a string } @@ -838,45 +876,50 @@ class PdfGenerator $htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '<div class="col-xs-12">' . $modules_to_print_contents['topbar_modules'] . '</div>'; } - $htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '<div class="row">'; + if (array_filter($modules_to_print_contents)) { + $htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '<div class="row">'; - if ($modules_to_print_contents['left_modules'] || $modules_to_print_contents['right_modules']) { - $sideColumn = 'col-xs-4'; + if ($modules_to_print_contents['left_modules'] || $modules_to_print_contents['right_modules']) { + $sideColumn = 'col-xs-4'; - if ($modules_to_print_contents['left_modules'] && $modules_to_print_contents['right_modules']) { - $sideColumn = 'col-xs-2'; - } + if ($modules_to_print_contents['left_modules'] && $modules_to_print_contents['right_modules']) { + $sideColumn = 'col-xs-2'; + } - if ($modules_to_print_contents['left_modules']) { - $htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '<div class="' . $sideColumn . '">' . $modules_to_print_contents['left_modules'] . '</div>'; - } + if ($modules_to_print_contents['left_modules']) { + $htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '<div class="' . $sideColumn . '">' + . $modules_to_print_contents['left_modules'] . '</div>'; + } - $htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '<div class="col-xs-8">'; + $htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '<div class="col-xs-8">'; - if ($modules_to_print_contents['pagetop_modules']) { - $htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '<div>' . $modules_to_print_contents['pagetop_modules'] . '</div>'; - } + if ($modules_to_print_contents['pagetop_modules']) { + $htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '<div>' . $modules_to_print_contents['pagetop_modules'] . '</div>'; + } - if ($modules_to_print_contents['pagebottom_modules']) { - $htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '<div>' . $modules_to_print_contents['pagebottom_modules'] . '</div>'; - } + if ($modules_to_print_contents['pagebottom_modules']) { + $htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '<div>' . $modules_to_print_contents['pagebottom_modules'] . '</div>'; + } - $htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '</div>'; + $htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '</div>'; - if ($modules_to_print_contents['right_modules']) { - $htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '<div class="' . $sideColumn . '">' . $modules_to_print_contents['right_modules'] . '</div>'; - } - } else { - if ($modules_to_print_contents['pagetop_modules']) { - $htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '<div class="col-xs-12">' . $modules_to_print_contents['pagetop_modules'] . '</div>'; - } - if ($modules_to_print_contents['pagebottom_modules']) { - $htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '<div class="col-xs-12">' . $modules_to_print_contents['pagebottom_modules'] . '</div>'; + if ($modules_to_print_contents['right_modules']) { + $htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '<div class="' . $sideColumn . '">' + . $modules_to_print_contents['right_modules'] . '</div>'; + } + } else { + if ($modules_to_print_contents['pagetop_modules']) { + $htmlLayout["staringPart"] = $htmlLayout["staringPart"] . '<div class="col-xs-12">' + . $modules_to_print_contents['pagetop_modules'] . '</div>'; + } + if ($modules_to_print_contents['pagebottom_modules']) { + $htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '<div class="col-xs-12">' + . $modules_to_print_contents['pagebottom_modules'] . '</div>'; + } } - } - - $htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '</div>'; + $htmlLayout["endingPart"] = $htmlLayout["endingPart"] . '</div>'; + } //check if Module contains navbar and force display (when printing nav is by default display none) if (str_contains($htmlLayout["staringPart"], '<nav') || str_contains($htmlLayout["endingPart"], '<nav')) { @@ -1655,16 +1698,19 @@ TEXT; private function runReplaceVars($css, $variables) { + // FIXME this pattern doesn't match multi-argument var calls + // e.g. "var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)))" + // from vendor_bundled/vendor/twbs/bootstrap/dist/css/bootstrap.css:1884 + return preg_replace_callback('/var\(--([a-zA-Z0-9-]+)(?:,\s*(.+?))?\)/', function ($matches) use ($variables) { $var_name = $matches[1]; $fallback = isset($matches[2]) ? $matches[2] : null; // Optional fallback value // Check if the variable exists - if (isset($variables[$var_name])) { - $value = $variables[$var_name]; - + $value = trim($variables[$var_name]); + if ($value) { // If the variable contains another `var()`, recursively resolve it - if (preg_match('/var\(--([a-zA-Z0-9-]+)\)/', $value)) { + if (preg_match('/var\(--([a-zA-Z0-9-]+)\)/U', $value)) { $value = $this->runReplaceVars($value, $variables); } return $value; // Return resolved value @@ -1695,6 +1741,15 @@ TEXT; // Create an associative array of variable names to their values $variables = array_combine($matches[1], $matches[2]); + // match again to find inline url data: values + preg_match_all('/--([a-zA-Z0-9-]+)\s*:\s*(url\(data:[^)]+\));/', $css, $matches); + // Reverse so the light variables are processed first? + $matches[1] = array_reverse($matches[1]); + $matches[2] = array_reverse($matches[2]); + + // Create an associative array of variable names to their values + $variables = array_merge($variables, array_combine($matches[1], $matches[2])); + // Replace all `var(--variable)` occurrences in the CSS $css = $this->runReplaceVars($css, $variables); ===================================== lib/prefs/print.php ===================================== @@ -323,6 +323,15 @@ function prefs_print_list() 'tags' => ['advanced'], 'default' => 'y', ], + 'print_pdf_mpdf_debug' => [ + 'name' => tra('Debug mPDF output'), + 'description' => tra('Saves a copy of the html sent to mPDF in the temp directory'), + 'warning' => tra('Does not respect permissions, do not use with production data.'), + 'view' => 'temp/mpdf_debug_output.html', + 'type' => 'flag', + 'tags' => ['advanced'], + 'default' => 'n', + ], 'print_wiki_authors' => [ 'name' => tra('Print wiki authors'), 'description' => tra('Include wiki page authors and date in print versions of wiki pages.'), ===================================== templates/admin/include_print.tpl ===================================== @@ -72,6 +72,7 @@ {preference name=print_pdf_mpdf_coverpage_settings} {preference name=print_pdf_mpdf_coverpage_image_settings} {preference name=print_pdf_mpdf_allow_unsafe_ssl_requests} + {preference name=print_pdf_mpdf_debug} </div> </fieldset> View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/5aec78efef58eff1ea42b4d4eda0a291aa6916f6 -- View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/5aec78efef58eff1ea42b4d4eda0a291aa6916f6 You're receiving this email because of your account on gitlab.com. _______________________________________________ TikiWiki-cvs mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs