Skip to content

Commit 54c4563

Browse files
authored
fix(pdf): clean HTML tables to fit PDF page width to avoid overflow (#52)
* fix(pdf): clean HTML tables to fit PDF page width to avoid overflow * fix * review
1 parent 71f0282 commit 54c4563

2 files changed

Lines changed: 65 additions & 34 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2424

2525
- GLPI 11 compatibility
2626

27+
### Fixed
28+
29+
- Fixed table formatting and border in PDF
30+
- Fixed table cell size in PDF generation
31+
2732
## [4.0.2] - 2025-09-30
2833

2934
- Fix missing images in exported Knowledge Base PDFs

inc/simplepdf.class.php

Lines changed: 60 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -32,36 +32,6 @@
3232

3333
use Glpi\RichText\RichText;
3434

35-
/**
36-
* -------------------------------------------------------------------------
37-
* LICENSE
38-
*
39-
* This file is part of PDF plugin for GLPI.
40-
*
41-
* PDF is free software: you can redistribute it and/or modify
42-
* it under the terms of the GNU Affero General Public License as published by
43-
* the Free Software Foundation, either version 3 of the License, or
44-
* (at your option) any later version.
45-
*
46-
* PDF is distributed in the hope that it will be useful,
47-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
48-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
49-
* GNU Affero General Public License for more details.
50-
*
51-
* You should have received a copy of the GNU Affero General Public License
52-
* along with Reports. If not, see <http://www.gnu.org/licenses/>.
53-
*
54-
* @author Nelly Mahu-Lasson, Remi Collet, Teclib
55-
* @copyright Copyright (c) 2009-2022 PDF plugin team
56-
* @license AGPL License 3.0 or (at your option) any later version
57-
* @link https://github.com/pluginsGLPI/pdf/
58-
* @link http://www.glpi-project.org/
59-
* @package pdf
60-
* @since 2009
61-
* http://www.gnu.org/licenses/agpl-3.0-standalone.html
62-
* --------------------------------------------------------------------------
63-
*/
64-
6535
//use TCPDF;
6636

6737
define('K_PATH_IMAGES', '');
@@ -376,11 +346,29 @@ public function displayText($name, $content = '', $minline = 3, $maxline = 100)
376346

377347
$this->setColumnsSize(100);
378348
$text = $name . ' ' . $content;
379-
$content = RichText::getEnhancedHtml($text);
380-
if (!preg_match("/<br\s?\/?>/", $content) && !preg_match('/<p>/', $content)) {
381-
$content = nl2br($content);
349+
$content = RichText::getEnhancedHtml($text, ['text_maxsize' => 0]);
350+
351+
// Split content by tables, keeping tables in the result
352+
$segments = preg_split('/(<table\b[^>]*>.*?<\/table>)/is', $content, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
353+
354+
// Process segments and rebuild content
355+
$formatted_content = '';
356+
foreach ($segments as $segment) {
357+
if (str_contains($segment, '<table')) {
358+
// Clean up table HTML for PDF rendering
359+
$segment = $this->cleanTableHtml($segment);
360+
$formatted_content .= $segment;
361+
} else {
362+
// Apply nl2br only to text segments
363+
if (!str_contains($segment, '<br') && !str_contains($segment, '<p>')) {
364+
$segment = nl2br($segment);
365+
}
366+
$formatted_content .= $segment;
367+
}
382368
}
383-
$this->displayInternal(240, 0.5, self::LEFT, $minline * 5, [$content]);
369+
370+
$this->displayInternal(240, 0.5, self::LEFT, $minline * 5, [$formatted_content]);
371+
384372
/* Restore */
385373
[$this->cols, $this->colsx, $this->colsw, $this->align, ] = $save;
386374
}
@@ -395,6 +383,44 @@ public function displaySpace($nb = 1)
395383
$this->pdf->Ln(4 * $nb);
396384
}
397385

386+
/**
387+
* Clean table HTML for proper PDF rendering
388+
* Removes problematic attributes and styles that cause tables to overflow
389+
*
390+
* @param string $html Table HTML code
391+
* @return string Cleaned HTML
392+
*/
393+
private function cleanTableHtml($html)
394+
{
395+
// Remove colgroup entirely (causes fixed widths)
396+
$html = preg_replace('/<colgroup\b[^>]*>.*?<\/colgroup>/is', '', $html);
397+
398+
// Remove table-layout:fixed style (prevents auto-sizing)
399+
$html = preg_replace('/table-layout\s*:\s*fixed\s*;?/i', '', $html);
400+
401+
// Remove width/height styles only from table elements (table, td, th, tr)
402+
$html = preg_replace('/(<(?:table|td|th|tr)\b[^>]*)\s+style\s*=\s*["\']([^"\']*)\bwidth\s*:\s*[^;"\'>]+;?([^"\']*)["\']/', '$1 style="$2$3"', $html);
403+
$html = preg_replace('/(<(?:table|td|th|tr)\b[^>]*)\s+style\s*=\s*["\']([^"\']*)\bheight\s*:\s*[^;"\'>]+;?([^"\']*)["\']/', '$1 style="$2$3"', $html);
404+
405+
// Remove width/height attributes only from table elements (table, td, th, tr)
406+
$html = preg_replace('/(<(?:table|td|th|tr)\b[^>]+)\s+width\s*=\s*["\']?[^"\'\s>]+["\']?/i', '$1', $html);
407+
$html = preg_replace('/(<(?:table|td|th|tr)\b[^>]+)\s+height\s*=\s*["\']?[^"\'\s>]+["\']?/i', '$1', $html);
408+
409+
// Clean up empty style attributes and double spaces
410+
$html = preg_replace('/\s+style\s*=\s*["\'][\s]*["\']/', '', $html);
411+
$html = preg_replace('/\s+/', ' ', $html);
412+
413+
// Add border to table if missing (for visibility)
414+
if (!preg_match('/border\s*=\s*["\']?[1-9]/i', $html)) {
415+
$html = preg_replace('/<table/i', '<table border="1"', $html, 1);
416+
}
417+
418+
// Force table to 100% width for PDF (do this LAST)
419+
$html = preg_replace('/<table([^>]*)>/i', '<table$1 style="width:100%">', $html, 1);
420+
421+
return $html;
422+
}
423+
398424
/**
399425
* Display an image
400426
*

0 commit comments

Comments
 (0)