From 1a950150a372403a6a6454bc65a2d35b2d3e31a2 Mon Sep 17 00:00:00 2001 From: Gowtham M Date: Tue, 12 May 2026 15:34:27 +0530 Subject: [PATCH] GWM : merge pdf --- app/Helpers/merge_pdf_helper.php | 85 +++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 8 deletions(-) diff --git a/app/Helpers/merge_pdf_helper.php b/app/Helpers/merge_pdf_helper.php index 4498b9f8..a192e33e 100644 --- a/app/Helpers/merge_pdf_helper.php +++ b/app/Helpers/merge_pdf_helper.php @@ -141,14 +141,8 @@ if (! function_exists('merge_ticket_pdfs')) { $src = $sourceFile['path']; try { if ($sourceFile['mime'] === 'application/pdf') { - $pageCount = $mpdf->setSourceFile($src); - for ($p = 1; $p <= $pageCount; $p++) { - $tplId = $mpdf->importPage($p); - $mpdf->AddPage(); - // adjustPageSize=true makes the output page match the imported page. - $mpdf->useTemplate($tplId, 0, 0, null, null, true); - $totalPages++; - } + $pageCount = merge_ticket_pdf_add_pdf_pages($mpdf, $src, $tempDir); + $totalPages += $pageCount; log_message('error', "merge_ticket_pdfs | added PDF | file={$src} | pages={$pageCount}"); } elseif (in_array($sourceFile['mime'], ['image/jpeg', 'image/png'], true)) { if (merge_ticket_pdf_add_image_page($mpdf, $src)) { @@ -226,6 +220,81 @@ if (! function_exists('merge_ticket_pdfs')) { } } +if (! function_exists('merge_ticket_pdf_add_pdf_pages')) { + /** + * Import PDF pages. If FPDI cannot import the source (commonly encrypted + * PDFs), normalize through Ghostscript and retry. + */ + function merge_ticket_pdf_add_pdf_pages(Mpdf $mpdf, string $pdfPath, string $tempDir): int + { + try { + return merge_ticket_pdf_import_pdf_pages($mpdf, $pdfPath); + } catch (\Throwable $e) { + log_message('error', "merge_ticket_pdfs | direct PDF import failed | file={$pdfPath} | " . $e->getMessage()); + + $normalizedPath = merge_ticket_pdf_normalize_with_ghostscript($pdfPath, $tempDir); + if ($normalizedPath === null) { + throw $e; + } + + try { + $pageCount = merge_ticket_pdf_import_pdf_pages($mpdf, $normalizedPath); + log_message('error', "merge_ticket_pdfs | Ghostscript normalized PDF imported | original={$pdfPath} | normalized={$normalizedPath} | pages={$pageCount}"); + @unlink($normalizedPath); + return $pageCount; + } catch (\Throwable $normalizedError) { + @unlink($normalizedPath); + throw $normalizedError; + } + } + } +} + +if (! function_exists('merge_ticket_pdf_import_pdf_pages')) { + function merge_ticket_pdf_import_pdf_pages(Mpdf $mpdf, string $pdfPath): int + { + $pageCount = $mpdf->setSourceFile($pdfPath); + for ($p = 1; $p <= $pageCount; $p++) { + $tplId = $mpdf->importPage($p); + $mpdf->AddPage(); + // adjustPageSize=true makes the output page match the imported page. + $mpdf->useTemplate($tplId, 0, 0, null, null, true); + } + + return $pageCount; + } +} + +if (! function_exists('merge_ticket_pdf_normalize_with_ghostscript')) { + function merge_ticket_pdf_normalize_with_ghostscript(string $pdfPath, string $tempDir): ?string + { + $ghostscript = is_executable('/usr/bin/gs') ? '/usr/bin/gs' : trim((string) @shell_exec('command -v gs 2>/dev/null')); + if ($ghostscript === '' || ! is_executable($ghostscript)) { + log_message('error', "merge_ticket_pdfs | Ghostscript not available for PDF normalization | file={$pdfPath}"); + return null; + } + + $normalizedPath = rtrim($tempDir, '/\\') . DIRECTORY_SEPARATOR . 'normalized_' . uniqid('', true) . '.pdf'; + $cmd = escapeshellarg($ghostscript) + . ' -q -dNOPAUSE -dBATCH -dSAFER -sDEVICE=pdfwrite -dCompatibilityLevel=1.4' + . ' -sOutputFile=' . escapeshellarg($normalizedPath) + . ' ' . escapeshellarg($pdfPath) + . ' 2>&1'; + + $output = []; + $exitCode = 1; + @exec($cmd, $output, $exitCode); + + if ($exitCode !== 0 || ! is_file($normalizedPath) || filesize($normalizedPath) <= 0) { + log_message('error', 'merge_ticket_pdfs | Ghostscript normalization failed | file=' . $pdfPath . ' | exit=' . $exitCode . ' | output=' . implode(' ', $output)); + @unlink($normalizedPath); + return null; + } + + return $normalizedPath; + } +} + if (! function_exists('merge_ticket_pdf_resolve_mime')) { /** * Resolve file type from stored MIME, filesystem MIME, and extension.