From bb3989c9a7b32ea03b045b6ccca1da1abece846c Mon Sep 17 00:00:00 2001 From: ldestailleur Date: Thu, 20 Mar 2025 12:01:18 +0100 Subject: [PATCH] NEW The signature is on the good page even if another module add pages --- htdocs/core/ajax/onlineSign.php | 19 +++++++++--- htdocs/core/lib/pdf.lib.php | 31 +++++++++++++++++++ .../modules/propale/doc/pdf_azur.modules.php | 4 +++ .../modules/propale/doc/pdf_cyan.modules.php | 4 +++ htdocs/public/onlinesign/newonlinesign.php | 4 ++- 5 files changed, 57 insertions(+), 5 deletions(-) diff --git a/htdocs/core/ajax/onlineSign.php b/htdocs/core/ajax/onlineSign.php index f24ed4e9b36..da25632abdb 100644 --- a/htdocs/core/ajax/onlineSign.php +++ b/htdocs/core/ajax/onlineSign.php @@ -152,6 +152,7 @@ if ($action == "importSignature") { if (preg_match('/\.pdf/i', $last_main_doc_file)) { $ref_pdf = pathinfo($last_main_doc_file, PATHINFO_FILENAME); // Retrieves the name of external or internal PDF + $ref_pdf = preg_replace('/_signed-(\d+)/', '', $ref_pdf); $newpdffilename = $upload_dir . $ref_pdf . "_signed-" . $date . ".pdf"; $sourcefile = $upload_dir . $ref_pdf . ".pdf"; @@ -183,6 +184,8 @@ if ($action == "importSignature") { $param['online_sign_name'] = $online_sign_name; $param['pathtoimage'] = $upload_dir . $filename; + $propalsignonspecificpage = getDolGlobalInt("PROPAL_SIGNATURE_ON_SPECIFIC_PAGE"); + $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297); for ($i = 1; $i < ($pagecount + 1); $i++) { try { @@ -190,11 +193,20 @@ if ($action == "importSignature") { $s = $pdf->getTemplatesize($tppl); $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L'); $pdf->useTemplate($tppl); - $propalsignonspecificpage = getDolGlobalInt("PROPAL_SIGNATURE_ON_SPECIFIC_PAGE"); if ($propalsignonspecificpage < 0) { $propalsignonspecificpage = $pagecount - abs($propalsignonspecificpage); } + if (empty($propalsignonspecificpage)) { + // Now we get the metadata keywords from the $sourcefile PDF (by parsing the binary PDF file) and use it to extract + // the page x in PAGESIGN=x into $propalsignonspecificpage + $keywords = pdfExtractMetadata($sourcefile, 'Keywords'); + $reg = array(); + if (preg_match('/PAGESIGN=(\d+)/', $keywords, $reg)) { + $propalsignonspecificpage = (int) $reg[1]; + } + } + if (getDolGlobalString("PROPAL_SIGNATURE_ON_ALL_PAGES") || $propalsignonspecificpage == $i) { // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF // TODO Get position of box from PDF template @@ -224,10 +236,9 @@ if ($action == "importSignature") { } } - if (!getDolGlobalString("PROPAL_SIGNATURE_ON_ALL_PAGES") && !getDolGlobalInt("PROPAL_SIGNATURE_ON_SPECIFIC_PAGE")) { + if (!getDolGlobalString("PROPAL_SIGNATURE_ON_ALL_PAGES") && !$propalsignonspecificpage) { + // We do not found specific instruction or page for the signature, so we add it now we are on the last page. // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF - // TODO Get position of box from PDF template - if (getDolGlobalString("PROPAL_SIGNATURE_XFORIMGSTART")) { $param['xforimgstart'] = getDolGlobalString("PROPAL_SIGNATURE_XFORIMGSTART"); } else { diff --git a/htdocs/core/lib/pdf.lib.php b/htdocs/core/lib/pdf.lib.php index 5a2ef75c572..40853f107f8 100644 --- a/htdocs/core/lib/pdf.lib.php +++ b/htdocs/core/lib/pdf.lib.php @@ -2783,3 +2783,34 @@ function pdfGetLineTotalDiscountAmount($object, $i, $outputlangs, $hidedetails = } return 0; } + +/** + * Function to extract metadata from a PDF file by doing a binary parsing of the PDF file + * + * @param string $file Path of file + * @param string $field Key to extract + * @return int|string + */ +function pdfExtractMetadata($file, $field = 'Keywords') +{ + if (!dol_is_file($file)) { + return "ERROR: FILE NOT FOUND OR NOT VALID"; + } + + // Get content of PDF file + $content = file_get_contents(dol_osencode($file)); + + // Use a regex to capture the metadata + if ($content) { + $matches = array(); + + // Remove non printablecaracters + $content = preg_replace('/[^(\x20-\x7F)]*/', '', $content); + if (preg_match('/\/' . preg_quote($field, '/') . '\s*\((.*?)\)/', $content, $matches)) { + return trim($matches[1]); + } + return "ERROR: NOT FOUND"; + } else { + return "ERROR: FAILED TO READ PDF"; + } +} diff --git a/htdocs/core/modules/propale/doc/pdf_azur.modules.php b/htdocs/core/modules/propale/doc/pdf_azur.modules.php index 6fd9c738929..978ade1f12e 100644 --- a/htdocs/core/modules/propale/doc/pdf_azur.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_azur.modules.php @@ -757,6 +757,10 @@ class pdf_azur extends ModelePDFPropales // Customer signature area if (!getDolGlobalString('PROPAL_DISABLE_SIGNATURE')) { $posy = $this->_signature_area($pdf, $object, $posy, $outputlangs); + + // Rewrite keywords to add a tag with the numero of page that contains the signature section + $keywords = $outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfCommercialProposalTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name); + $pdf->SetKeyWords($keywords." PAGESIGN=".$pdf->getPage()); } // Pied de page diff --git a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php index 8055b070c8a..0f090cf26a3 100644 --- a/htdocs/core/modules/propale/doc/pdf_cyan.modules.php +++ b/htdocs/core/modules/propale/doc/pdf_cyan.modules.php @@ -879,6 +879,10 @@ class pdf_cyan extends ModelePDFPropales // Customer signature area if (!getDolGlobalString('PROPAL_DISABLE_SIGNATURE')) { $posy = $this->drawSignatureArea($pdf, $object, $posy, $outputlangs); + + // Rewrite keywords to add a tag with the numero of page that contains the signature section + $keywords = $outputlangs->convToOutputCharset($object->ref)." ".$outputlangs->transnoentities("PdfCommercialProposalTitle")." ".$outputlangs->convToOutputCharset($object->thirdparty->name); + $pdf->SetKeyWords($keywords." PAGESIGN=".$pdf->getPage()); } // Add number of pages in footer diff --git a/htdocs/public/onlinesign/newonlinesign.php b/htdocs/public/onlinesign/newonlinesign.php index b1e96f623d2..2a7c46dee7e 100644 --- a/htdocs/public/onlinesign/newonlinesign.php +++ b/htdocs/public/onlinesign/newonlinesign.php @@ -420,6 +420,8 @@ if ($source == 'proposal') { $last_main_doc_file = $object->last_main_doc; if ($object->status == $object::STATUS_VALIDATED) { + $object->last_main_doc = preg_replace('/_signed-(\d+)/', '', $object->last_main_doc); // We want to be sure to not work on the signed version + if (empty($last_main_doc_file) || !dol_is_file(DOL_DATA_ROOT.'/'.$object->last_main_doc)) { // It seems document has never been generated, or was generated and then deleted. // So we try to regenerate it with its default template. @@ -448,7 +450,7 @@ if ($source == 'proposal') { $datefilesigned = dol_filemtime($last_main_doc_file); $datefilenotsigned = dol_filemtime($last_main_doc_file_not_signed); - if (empty($datefilenotsigned) || $datefilesigned > $datefilenotsigned) { + if (empty($datefilenotsigned) || $datefilesigned > $datefilenotsigned) { // If file signed is more recent $directdownloadlink = $object->getLastMainDocLink('proposal'); if ($directdownloadlink) { print '
';