From 69373af48c46bbbc3b35c972b532edc5f528fe20 Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Sun, 7 Jun 2026 13:53:03 +0530 Subject: [PATCH] Fix: Add CKEditor special character sanitization for PDF generation Added sanitizeCKEditorSpecialChars() method to handle smart quotes, zero-width spaces, em/en dashes, and other special characters that can break mPDF. Removes invisible Unicode chars, replaces special punctuation with ASCII equivalents, cleans HTML comments. --- app/Controllers/Ipd_discharge.php | 54 +++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/app/Controllers/Ipd_discharge.php b/app/Controllers/Ipd_discharge.php index 2d3f56e..c4b2ba3 100644 --- a/app/Controllers/Ipd_discharge.php +++ b/app/Controllers/Ipd_discharge.php @@ -6290,6 +6290,9 @@ class Ipd_discharge extends BaseController $out = str_replace("\0", '', $html); $out = (string) preg_replace('/^\xEF\xBB\xBF/u', '', $out); + // Sanitize CKEditor special characters that can break mPDF + $out = $this->sanitizeCKEditorSpecialChars($out); + if ($stripNamedHeaderFooterWrappers) { // For body/template HTML, strip legacy named header/footer wrapper blocks. $out = (string) preg_replace('/]*>[\s\S]*?<\/htmlpageheader>/i', '', $out); @@ -6307,6 +6310,57 @@ class Ipd_discharge extends BaseController return $this->forceValidUtf8($out); } + private function sanitizeCKEditorSpecialChars(string $html): string + { + if ($html === '') { + return ''; + } + + // Remove zero-width spaces and other invisible characters + $html = str_replace([ + "\xE2\x80\x8B", // Zero-width space + "\xE2\x80\x8C", // Zero-width non-joiner + "\xE2\x80\x8D", // Zero-width joiner + "\xE2\x80\x8E", // Left-to-right mark + "\xE2\x80\x8F", // Right-to-left mark + "\xEF\xBB\xBF", // Zero-width no-break space (BOM) + ], '', $html); + + // Replace smart quotes and special punctuation with standard ASCII equivalents + $replacements = [ + // Smart quotes + "\xE2\x80\x9C" => '"', // Left double quote + "\xE2\x80\x9D" => '"', // Right double quote + "\xE2\x80\x98" => "'", // Left single quote + "\xE2\x80\x99" => "'", // Right single quote + "\xE2\x80\x9B" => "'", // Single high-reversed-9 quotation mark + + // Dashes + "\xE2\x80\x93" => '-', // En dash + "\xE2\x80\x94" => '-', // Em dash + "\xE2\x80\x95" => '-', // Horizontal bar + + // Ellipsis + "\xE2\x80\xA6" => '...', // Horizontal ellipsis + + // Spaces (keep non-breaking space as HTML entity) + "\xC2\xA0" => ' ', // Non-breaking space + ]; + + $html = str_replace(array_keys($replacements), array_values($replacements), $html); + + // Decode HTML entities to actual characters (mPDF handles UTF-8 better than entities) + $html = html_entity_decode($html, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + + // Remove or replace problematic HTML comments that might break parsing + $html = (string) preg_replace('//i', '', $html); + + // Clean up any malformed or nested comment blocks + $html = (string) preg_replace('//s', '', $html); + + return $html; + } + private function forceValidUtf8(string $text): string { if ($text === '') {