dolibarr 25.0.0-alpha
onlineSign.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
3 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
4 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
5 * Copyright (C) 2026 Lenin Rivas <lenin.rivas777@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
26if (!defined('NOTOKENRENEWAL')) {
27 define('NOTOKENRENEWAL', '1'); // Disables token renewal
28}
29if (!defined('NOREQUIREHTML')) {
30 define('NOREQUIREHTML', '1');
31}
32if (!defined('NOREQUIREAJAX')) {
33 define('NOREQUIREAJAX', '1');
34}
35// Needed to create other objects with workflow
36/*if (!defined('NOREQUIRESOC')) {
37 define('NOREQUIRESOC', '1');
38}*/
39// Do not check anti CSRF attack test
40if (!defined('NOREQUIREMENU')) {
41 define('NOREQUIREMENU', '1');
42}
43// If there is no need to load and show top and left menu
44if (!defined("NOLOGIN")) {
45 define("NOLOGIN", '1');
46}
47if (!defined('NOIPCHECK')) {
48 define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip
49}
50if (!defined('NOBROWSERNOTIF')) {
51 define('NOBROWSERNOTIF', '1');
52}
53$entity = (!empty($_GET['entity']) ? (int) $_GET['entity'] : (!empty($_POST['entity']) ? (int) $_POST['entity'] : 1)); // Keep $_GET and $_POST here. GETPOST not yet defined.
54if (is_numeric($entity)) {
55 define("DOLENTITY", $entity);
56}
57include '../../main.inc.php';
58require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
67$action = GETPOST('action', 'aZ09');
68
69$signature = GETPOST('signaturebase64');
70// Match the filter the producer uses in newonlinesign.php:97 ('alpha').
71// Refs such as PR2601-0003 contain a dash, which aZ09 strips. After stripping
72// the dash, dol_verifyHash fails because the security key was built from the
73// full reference, so onlineSign answered 403 even on valid submissions (#31464).
74$ref = GETPOST('ref', 'alpha');
75$mode = GETPOST('mode', 'aZ09'); // 'proposal', ...
76$SECUREKEY = GETPOST("securekey"); // Secure key
77$online_sign_name = GETPOST("onlinesignname");
78
79$error = 0;
80$response = "";
81
82$type = $mode;
83
84global $dolibarr_main_instance_unique_id;
85$defaultsalt = substr(dol_hash('dolibarr'.$dolibarr_main_instance_unique_id, 'sha256'), 0, 32); // Fallback if no specific salt was set
86
87// Security check
88$securekeyseed = '';
89if ($type == 'proposal') {
90 $securekeyseed = getDolGlobalString('PROPOSAL_ONLINE_SIGNATURE_SECURITY_TOKEN', $defaultsalt);
91} elseif ($type == 'contract') {
92 $securekeyseed = getDolGlobalString('CONTRACT_ONLINE_SIGNATURE_SECURITY_TOKEN', $defaultsalt);
93} elseif ($type == 'fichinter') {
94 $securekeyseed = getDolGlobalString('FICHINTER_ONLINE_SIGNATURE_SECURITY_TOKEN', $defaultsalt);
95} else {
96 $securekeyseed = getDolGlobalString(strtoupper($type).'_ONLINE_SIGNATURE_SECURITY_TOKEN', $defaultsalt);
97}
98
99if (empty($SECUREKEY) || !dol_verifyHash($securekeyseed . $type . $ref . (!isModEnabled('multicompany') ? '' : $entity), $SECUREKEY, '0')) {
100 // Link may have expired because of a change into the keys used to forge the signature.
101 httponly_accessforbidden('Bad value for securitykey. Value provided ' . dol_escape_htmltag($SECUREKEY) . ' does not match expected value for ref=' . dol_escape_htmltag($ref), 403);
102}
103
104// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
105$hookmanager->initHooks(array('ajaxonlinesign'));
106
107
108/*
109 * Actions
110 */
111
112// None
113
114
115/*
116 * View
117 */
118
120
121if ($action == "importSignature") {
122 $issignatureok = (!empty($signature) && $signature[0] == "image/png;base64");
123 if ($issignatureok) {
124 $signature = $signature[1];
125 $data = base64_decode($signature);
126
127 if ($mode == "propale" || $mode == 'proposal') {
128 require_once DOL_DOCUMENT_ROOT . '/comm/propal/class/propal.class.php';
129 require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php';
130 require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
131 $object = new Propal($db);
132 $object->fetch(0, $ref);
133
134 if (getDolGlobalInt('PROPOSAL_ONLINESIGN_REFUSE_IF_VALIDITY_DATE_PASSED') && !empty($object->fin_validite)
135 && dol_get_first_hour($object->fin_validite) < dol_get_first_hour(dol_now())) {
136 // The proposal is no more valid. Tested before anything is written, and on
137 // calendar days: validity runs until the end of the due day.
138 $langs->load("errors");
139 print $langs->transnoentitiesnoconv("ErrorProposalValidityDatePassed", dol_print_date($object->fin_validite, 'day')); // Must be a print that is shown by a javascript alert().
140 $error++;
141 } elseif ($object->status != $object::STATUS_VALIDATED) {
142 // Protection so we can't sign a proposal that is no more with status validated.
143 // The same test exists on the UPDATE request below, but it runs after the signed PDF has been generated.
144 $langs->load("errors");
145 print $langs->transnoentitiesnoconv("ErrorCantSignDocument"); // Must be a print that is shown by a javascript alert().
146 $error++;
147 }
148
149 $upload_dir = !empty($conf->propal->multidir_output[$object->entity ?? $conf->entity]) ? $conf->propal->multidir_output[$object->entity ?? $conf->entity] : $conf->propal->dir_output;
150 $upload_dir .= '/' . dol_sanitizeFileName($object->ref) . '/';
151
152 $default_font_size = pdf_getPDFFontSize($langs); // Must be after pdf_getInstance
153 $default_font = pdf_getPDFFont($langs); // Must be after pdf_getInstance
154 $langs->loadLangs(array("main", "companies"));
155
156 $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S");
157 $filename = "signatures/" . $date . "_signature.png";
158 if (!$error && !is_dir($upload_dir . "signatures/")) {
159 if (!dol_mkdir($upload_dir . "signatures/")) {
160 $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/";
161 $error++;
162 }
163 }
164
165 if (!$error) {
166 $return = file_put_contents($upload_dir.$filename, $data);
167 if ($return === false) {
168 $error++;
169 $response = 'Error file_put_content: failed to create signature file.';
170 } else {
171 dolChmod($upload_dir.$filename);
172 }
173 }
174
175 if (!$error) {
176 // Defined modele of doc
177 $last_main_doc_file = $object->last_main_doc;
178 $directdownloadlink = $object->getLastMainDocLink('proposal'); // url to download the $object->last_main_doc
179
180 if (preg_match('/\.pdf/i', $last_main_doc_file)) {
181 $ref_pdf = pathinfo($last_main_doc_file, PATHINFO_FILENAME); // Retrieves the name of external or internal PDF
182 $ref_pdf = preg_replace('/_signed-(\d+)/', '', $ref_pdf);
183
184 $newpdffilename = $upload_dir . $ref_pdf . "_signed-" . $date . ".pdf";
185 $sourcefile = $upload_dir . $ref_pdf . ".pdf";
186
187 if (dol_is_file($sourcefile)) {
188 $parameters = array('sourcefile' => $sourcefile, 'newpdffilename' => $newpdffilename);
189 $reshook = $hookmanager->executeHooks('AddSignature', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
190 if ($reshook < 0) {
191 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
192 }
193
194 if (empty($reshook)) {
195 // We build the new PDF
196 $formatarray = pdf_getFormat();
197 $page_largeur = $formatarray['width'];
198 $page_hauteur = $formatarray['height'];
199 $format = array($page_largeur, $page_hauteur);
200
201 $pdf = pdf_getInstance($format);
202 if (class_exists('TCPDF')) {
203 $pdf->setPrintHeader(false);
204 $pdf->setPrintFooter(false);
205 }
206 $pdf->SetFont(pdf_getPDFFont($langs));
207
208 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
209 $pdf->SetCompression(false);
210 }
211
212 //$pdf->Open();
213 $pagecount = $pdf->setSourceFile($sourcefile); // original PDF
214
215 $param = array();
216 $param['online_sign_name'] = $online_sign_name;
217 $param['pathtoimage'] = $upload_dir . $filename;
218
219 $propalsignonspecificpage = getDolGlobalInt("PROPAL_SIGNATURE_ON_SPECIFIC_PAGE");
220
221 $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297);
222 for ($i = 1; $i < ($pagecount + 1); $i++) {
223 try {
224 $tppl = $pdf->importPage($i);
225 $s = $pdf->getTemplatesize($tppl);
226 $format = array($s['w'], $s['h']);
227 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L', $format);
228 $pdf->useTemplate($tppl);
229
230 if ($propalsignonspecificpage < 0) {
231 $propalsignonspecificpage = $pagecount - abs($propalsignonspecificpage);
232 }
233
234 if (empty($propalsignonspecificpage)) {
235 // Now we get the metadata keywords from the $sourcefile PDF (by parsing the binary PDF file) and use it to extract
236 // the page x in PAGESIGN=x into $propalsignonspecificpage
237 $keywords = pdfExtractMetadata($sourcefile, 'Keywords');
238 $reg = array();
239 if (preg_match('/PAGESIGN=(\d+)/', $keywords, $reg)) {
240 $propalsignonspecificpage = (int) $reg[1];
241 }
242 }
243
244 if (getDolGlobalString("PROPAL_SIGNATURE_ON_ALL_PAGES") || $propalsignonspecificpage == $i) {
245 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
246 // TODO Get position of box from PDF template
247
248 if (getDolGlobalString("PROPAL_SIGNATURE_XFORIMGSTART")) {
249 $param['xforimgstart'] = getDolGlobalString("PROPAL_SIGNATURE_XFORIMGSTART");
250 } else {
251 $param['xforimgstart'] = (empty($s['w']) ? 120 : round($s['w'] / 2) + 15);
252 }
253 if (getDolGlobalString("PROPAL_SIGNATURE_YFORIMGSTART")) {
254 $param['yforimgstart'] = getDolGlobalString("PROPAL_SIGNATURE_YFORIMGSTART");
255 } else {
256 $param['yforimgstart'] = (empty($s['h']) ? 240 : $s['h'] - 60);
257 }
258 if (getDolGlobalString("PROPAL_SIGNATURE_WFORIMG")) {
259 $param['wforimg'] = getDolGlobalString("PROPAL_SIGNATURE_WFORIMG");
260 } else {
261 $param['wforimg'] = $s['w'] - 20 - $param['xforimgstart'];
262 }
263
264 dolPrintSignatureImage($pdf, $langs, $param);
265 }
266 } catch (Exception $e) {
267 dol_syslog("Error when manipulating the PDF " . $sourcefile . " by onlineSign: " . $e->getMessage(), LOG_ERR);
268 $response = $e->getMessage();
269 $error++;
270 }
271 }
272
273 if (!getDolGlobalString("PROPAL_SIGNATURE_ON_ALL_PAGES") && !$propalsignonspecificpage) {
274 // We do not found specific instruction or page for the signature, so we add it now we are on the last page.
275 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
276 if (getDolGlobalString("PROPAL_SIGNATURE_XFORIMGSTART")) {
277 $param['xforimgstart'] = getDolGlobalString("PROPAL_SIGNATURE_XFORIMGSTART");
278 } else {
279 $param['xforimgstart'] = (empty($s['w']) ? 120 : round($s['w'] / 2) + 15);
280 }
281 if (getDolGlobalString("PROPAL_SIGNATURE_YFORIMGSTART")) {
282 $param['yforimgstart'] = getDolGlobalString("PROPAL_SIGNATURE_YFORIMGSTART");
283 } else {
284 $param['yforimgstart'] = (empty($s['h']) ? 240 : $s['h'] - 60);
285 }
286 if (getDolGlobalString("PROPAL_SIGNATURE_WFORIMG")) {
287 $param['wforimg'] = getDolGlobalString("PROPAL_SIGNATURE_WFORIMG");
288 } else {
289 $param['wforimg'] = $s['w'] - 20 - $param['xforimgstart'];
290 }
291
292 dolPrintSignatureImage($pdf, $langs, $param);
293 }
294
295 //$pdf->Close();
296 $pdf->Output($newpdffilename, "F");
297
298 // Index the new file and update the last_main_doc property of object.
299 $object->indexFile($newpdffilename, 1);
300 }
301 }
302 } elseif (preg_match('/\.odt/i', $last_main_doc_file)) {
303 // Adding signature on .ODT not yet supported
304 // TODO
305 } else {
306 // Document format not supported to insert online signature.
307 // We should just create an image file with the signature.
308 }
309 }
310
311 if (!$error) {
312 $db->begin();
313
314 $online_sign_ip = getUserRemoteIP();
315
316 $sql = "UPDATE " . MAIN_DB_PREFIX . "propal";
317 $sql .= " SET fk_statut = " . ((int) $object::STATUS_SIGNED) . ", note_private = '" . $db->escape($object->note_private) . "',";
318 $sql .= " date_signature = '" . $db->idate(dol_now()) . "',";
319 $sql .= " online_sign_ip = '" . $db->escape($online_sign_ip) . "'";
320 if ($online_sign_name) {
321 $sql .= ", online_sign_name = '" . $db->escape($online_sign_name) . "'";
322 }
323 $sql .= " WHERE rowid = " . ((int) $object->id);
324 $sql .= " AND fk_statut = ".((int) $object::STATUS_VALIDATED); // Protection so we can't sign a document that is no more with status validated.
325
326 dol_syslog(__FILE__, LOG_DEBUG);
327 $resql = $db->query($sql);
328 if (!$resql) {
329 $error++;
330 $response = "error sql";
331 } else {
332 $num = $db->affected_rows($resql);
333 if ($num <= 0) {
334 $error++;
335 $langs->load("errors");
336 //setEventMessages($langs->trans("ErrorCantSignDocument"), null, 'errors');
337 print $langs->transnoentitiesnoconv("ErrorCantSignDocument"); // Must be a print that is shown by ajavascript alert().
338 }
339 }
340
341 if (!$error) {
342 if (method_exists($object, 'call_trigger')) {
343 $object->context = array('closedfromonlinesignature' => 'closedfromonlinesignature');
344
345 $result = $object->call_trigger('PROPAL_CLOSE_SIGNED', $user);
346 if ($result < 0) {
347 $error++;
348 $response = "error in trigger " . $object->error;
349 } else {
350 $soc = new Societe($db);
351 $soc->id = $object->socid;
352 $result = $soc->setAsCustomer();
353 if ($result < 0) {
354 $error++;
355 $response = $db->lasterror();
356 } else {
357 $response = "success";
358 }
359 }
360 } else {
361 $response = "success";
362 }
363 }
364
365 if (!$error) {
366 $db->commit();
367 $response = "success";
368 setEventMessages("PropalSigned", null, 'mesgs');
369 } else {
370 $db->rollback();
371 }
372 }
373 } elseif ($mode == 'contract') {
374 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
375 require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php';
376 $object = new Contrat($db);
377 $object->fetch(0, $ref);
378
379 $upload_dir = !empty($conf->contract->multidir_output[$object->entity ?? $conf->entity]) ? $conf->contract->multidir_output[$object->entity ?? $conf->entity] : $conf->contrat->dir_output;
380 $upload_dir .= '/' . dol_sanitizeFileName($object->ref) . '/';
381
382 $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S");
383 $filename = "signatures/" . $date . "_signature.png";
384 if (!is_dir($upload_dir . "signatures/")) {
385 if (!dol_mkdir($upload_dir . "signatures/")) {
386 $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/";
387 $error++;
388 }
389 }
390
391 if (!$error) {
392 $return = file_put_contents($upload_dir . $filename, $data);
393 if ($return === false) {
394 $error++;
395 $response = 'Error file_put_content: failed to create signature file.';
396 } else {
397 dolChmod($upload_dir.$filename);
398 }
399 }
400
401 if (!$error) {
402 // Defined modele of doc
403 $last_main_doc_file = $object->last_main_doc;
404 $directdownloadlink = $object->getLastMainDocLink('contrat'); // url to download the $object->last_main_doc
405
406 if (preg_match('/\.pdf/i', $last_main_doc_file)) {
407 $ref_pdf = pathinfo($last_main_doc_file, PATHINFO_FILENAME); // Retrieves the name of external or internal PDF
408
409 $newpdffilename = $upload_dir . $ref_pdf . "_signed-" . $date . ".pdf";
410 $sourcefile = $upload_dir . $ref_pdf . ".pdf";
411
412 if (dol_is_file($sourcefile)) {
413 $parameters = array('sourcefile' => $sourcefile, 'newpdffilename' => $newpdffilename);
414 $reshook = $hookmanager->executeHooks('AddSignature', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
415 if ($reshook < 0) {
416 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
417 }
418
419 if (empty($reshook)) {
420 // We build the new PDF
421 $pdf = pdf_getInstance();
422 if (class_exists('TCPDF')) {
423 $pdf->setPrintHeader(false);
424 $pdf->setPrintFooter(false);
425 }
426 $pdf->SetFont(pdf_getPDFFont($langs));
427
428 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
429 $pdf->SetCompression(false);
430 }
431
432 //$pdf->Open();
433 $pagecount = $pdf->setSourceFile($sourcefile); // original PDF
434
435 $param = array();
436 $param['online_sign_name'] = $online_sign_name;
437 $param['pathtoimage'] = $upload_dir . $filename;
438
439 $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297);
440 for ($i = 1; $i < ($pagecount + 1); $i++) {
441 try {
442 $tppl = $pdf->importPage($i);
443 $s = $pdf->getTemplatesize($tppl);
444 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
445 $pdf->useTemplate($tppl);
446
447 if (getDolGlobalString("CONTRACT_SIGNATURE_ON_ALL_PAGES")) {
448 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
449 // TODO Get position of box from PDF template
450
451 if (getDolGlobalString("CONTRACT_SIGNATURE_XFORIMGSTART")) {
452 $param['xforimgstart'] = getDolGlobalString("CONTRACT_SIGNATURE_XFORIMGSTART");
453 } else {
454 $param['xforimgstart'] = (empty($s['w']) ? 110 : $s['w'] / 2 - 0);
455 }
456 if (getDolGlobalString("CONTRACT_SIGNATURE_YFORIMGSTART")) {
457 $param['yforimgstart'] = getDolGlobalString("CONTRACT_SIGNATURE_YFORIMGSTART");
458 } else {
459 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 62);
460 }
461 if (getDolGlobalString("CONTRACT_SIGNATURE_WFORIMG")) {
462 $param['wforimg'] = getDolGlobalString("CONTRACT_SIGNATURE_WFORIMG");
463 } else {
464 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16);
465 }
466
467 dolPrintSignatureImage($pdf, $langs, $param);
468 }
469 } catch (Exception $e) {
470 dol_syslog("Error when manipulating some PDF by onlineSign: " . $e->getMessage(), LOG_ERR);
471 $response = $e->getMessage();
472 $error++;
473 }
474 }
475
476 if (!getDolGlobalString("CONTRACT_SIGNATURE_ON_ALL_PAGES")) {
477 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
478 // TODO Get position of box from PDF template
479
480 $param['xforimgstart'] = (empty($s['w']) ? 110 : $s['w'] / 2 - 0);
481 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 62);
482 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16);
483
484 dolPrintSignatureImage($pdf, $langs, $param);
485 }
486
487 //$pdf->Close();
488 $pdf->Output($newpdffilename, "F");
489
490 // Index the new file and update the last_main_doc property of object.
491 $object->indexFile($newpdffilename, 1);
492 }
493 }
494 if (!$error) {
495 $response = "success";
496 }
497 } elseif (preg_match('/\.odt/i', $last_main_doc_file)) {
498 // Adding signature on .ODT not yet supported
499 // TODO
500 } else {
501 // Document format not supported to insert online signature.
502 // We should just create an image file with the signature.
503 }
504 $user = new User($db);
505 $object->setSignedStatus($user, Contrat::$SIGNED_STATUSES['STATUS_SIGNED_RECEIVER_ONLINE'], 0, 'CONTRACT_MODIFY');
506 }
507 } elseif ($mode == 'order') {
508 require_once DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php';
509 require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php';
510 $object = new Commande($db);
511 $object->fetch(0, $ref);
512
513 $upload_dir = !empty($conf->commande->multidir_output[$object->entity ?? $conf->entity]) ? $conf->commande->multidir_output[$object->entity ?? $conf->entity] : $conf->commande->dir_output;
514 $upload_dir .= '/' . dol_sanitizeFileName($object->ref) . '/';
515
516 $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S");
517 $filename = "signatures/" . $date . "_signature.png";
518 if (!is_dir($upload_dir . "signatures/")) {
519 if (!dol_mkdir($upload_dir . "signatures/")) {
520 $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/";
521 $error++;
522 }
523 }
524
525 if (!$error) {
526 $return = file_put_contents($upload_dir . $filename, $data);
527 if ($return === false) {
528 $error++;
529 $response = 'Error file_put_content: failed to create signature file.';
530 } else {
531 dolChmod($upload_dir.$filename);
532 }
533 }
534
535 if (!$error) {
536 // Defined modele of doc
537 $last_main_doc_file = $object->last_main_doc;
538 $directdownloadlink = $object->getLastMainDocLink('order'); // url to download the $object->last_main_doc
539
540 if (preg_match('/\.pdf/i', $last_main_doc_file)) {
541 $ref_pdf = pathinfo($last_main_doc_file, PATHINFO_FILENAME); // Retrieves the name of external or internal PDF
542 $ref_pdf = preg_replace('/_signed-(\d+)/', '', $ref_pdf);
543
544 $newpdffilename = $upload_dir . $ref_pdf . "_signed-" . $date . ".pdf";
545 $sourcefile = $upload_dir . $ref_pdf . ".pdf";
546
547 if (dol_is_file($sourcefile)) {
548 $parameters = array('sourcefile' => $sourcefile, 'newpdffilename' => $newpdffilename);
549 $reshook = $hookmanager->executeHooks('AddSignature', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
550 if ($reshook < 0) {
551 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
552 }
553
554 if (empty($reshook)) {
555 // We build the new PDF
556 $pdf = pdf_getInstance();
557 if (class_exists('TCPDF')) {
558 $pdf->setPrintHeader(false);
559 $pdf->setPrintFooter(false);
560 }
561 $pdf->SetFont(pdf_getPDFFont($langs));
562
563 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
564 $pdf->SetCompression(false);
565 }
566
567 //$pdf->Open();
568 $pagecount = $pdf->setSourceFile($sourcefile); // original PDF
569
570 $param = array();
571 $param['online_sign_name'] = $online_sign_name;
572 $param['pathtoimage'] = $upload_dir . $filename;
573
574 $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297);
575 for ($i = 1; $i < ($pagecount + 1); $i++) {
576 try {
577 $tppl = $pdf->importPage($i);
578 $s = $pdf->getTemplatesize($tppl);
579 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
580 $pdf->useTemplate($tppl);
581
582 if (getDolGlobalString("ORDER_SIGNATURE_ON_ALL_PAGES")) {
583 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
584 // TODO Get position of box from PDF template
585
586 if (getDolGlobalString("ORDER_SIGNATURE_XFORIMGSTART")) {
587 $param['xforimgstart'] = getDolGlobalString("ORDER_SIGNATURE_XFORIMGSTART");
588 } else {
589 $param['xforimgstart'] = (empty($s['w']) ? 120 : round($s['w'] / 2) + 15);
590 }
591 if (getDolGlobalString("ORDER_SIGNATURE_YFORIMGSTART")) {
592 $param['yforimgstart'] = getDolGlobalString("ORDER_SIGNATURE_YFORIMGSTART");
593 } else {
594 $param['yforimgstart'] = (empty($s['h']) ? 240 : $s['h'] - 60);
595 }
596 if (getDolGlobalString("ORDER_SIGNATURE_WFORIMG")) {
597 $param['wforimg'] = getDolGlobalString("ORDER_SIGNATURE_WFORIMG");
598 } else {
599 $param['wforimg'] = $s['w'] - 20 - $param['xforimgstart'];
600 }
601
602 dolPrintSignatureImage($pdf, $langs, $param);
603 }
604 } catch (Exception $e) {
605 dol_syslog("Error when manipulating some PDF by onlineSign: " . $e->getMessage(), LOG_ERR);
606 $response = $e->getMessage();
607 $error++;
608 }
609 }
610
611 if (!getDolGlobalString("ORDER_SIGNATURE_ON_ALL_PAGES")) {
612 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
613 // TODO Get position of box from PDF template
614
615 if (getDolGlobalString("ORDER_SIGNATURE_XFORIMGSTART")) {
616 $param['xforimgstart'] = getDolGlobalString("ORDER_SIGNATURE_XFORIMGSTART");
617 } else {
618 $param['xforimgstart'] = (empty($s['w']) ? 120 : round($s['w'] / 2) + 15);
619 }
620 if (getDolGlobalString("ORDER_SIGNATURE_YFORIMGSTART")) {
621 $param['yforimgstart'] = getDolGlobalString("ORDER_SIGNATURE_YFORIMGSTART");
622 } else {
623 $param['yforimgstart'] = (empty($s['h']) ? 240 : $s['h'] - 60);
624 }
625 if (getDolGlobalString("ORDER_SIGNATURE_WFORIMG")) {
626 $param['wforimg'] = getDolGlobalString("ORDER_SIGNATURE_WFORIMG");
627 } else {
628 $param['wforimg'] = $s['w'] - 20 - $param['xforimgstart'];
629 }
630
631 dolPrintSignatureImage($pdf, $langs, $param);
632 }
633
634 //$pdf->Close();
635 $pdf->Output($newpdffilename, "F");
636
637 // Index the new file and update the last_main_doc property of object.
638 $object->indexFile($newpdffilename, 1);
639 }
640 }
641 if (!$error) {
642 $response = "success";
643 }
644 } elseif (preg_match('/\.odt/i', $last_main_doc_file)) {
645 // Adding signature on .ODT not yet supported
646 // TODO
647 } else {
648 // Document format not supported to insert online signature.
649 // We should just create an image file with the signature.
650 }
651 if (!$error) {
652 $db->begin();
653
654 $online_sign_ip = getUserRemoteIP();
655
656 $sql = "UPDATE " . MAIN_DB_PREFIX . "commande";
657 $sql .= " SET fk_statut = " . ((int) $object::STATUS_VALIDATED) . ", note_private = '" . $db->escape($object->note_private) . "',";
658 $sql .= " date_signature = '" . $db->idate(dol_now()) . "',";
659 $sql .= " online_sign_ip = '" . $db->escape($online_sign_ip) . "'";
660 if ($online_sign_name) {
661 $sql .= ", online_sign_name = '" . $db->escape($online_sign_name) . "'";
662 }
663 $sql .= " WHERE rowid = " . ((int) $object->id);
664
665 dol_syslog(__FILE__, LOG_DEBUG);
666 $resql = $db->query($sql);
667 if (!$resql) {
668 $error++;
669 } else {
670 $num = $db->affected_rows($resql);
671 }
672
673 if (!$error) {
674 $user = new User($db);
675 $user->fetch($object->user_author_id);
676 $object->context = array('closedfromonlinesignature' => 'closedfromonlinesignature');
677 $result = $object->call_trigger('ORDER_CLOSE_SIGNED', $user);
678 if ($result < 0) {
679 $error++;
680 $response = "error in trigger " . $object->error;
681 } else {
682 $response = "success";
683 }
684 } else {
685 $error++;
686 $response = "error sql";
687 }
688
689 if (!$error) {
690 $db->commit();
691 $response = "success";
692 setEventMessages("OrderSigned", null, 'warnings');
693 } else {
694 $db->rollback();
695 }
696 }
697 }
698 } elseif ($mode == 'fichinter') {
699 require_once DOL_DOCUMENT_ROOT . '/fichinter/class/fichinter.class.php';
700 require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php';
701 $object = new Fichinter($db);
702 $object->fetch(0, $ref);
703
704 $upload_dir = !empty($conf->ficheinter->multidir_output[$object->entity ?? $conf->entity]) ? $conf->ficheinter->multidir_output[$object->entity ?? $conf->entity] : $conf->ficheinter->dir_output;
705 $upload_dir .= '/'.dol_sanitizeFileName($object->ref).'/';
706
707 $langs->loadLangs(array("main", "companies"));
708
709 $default_font_size = pdf_getPDFFontSize($langs); // Must be after pdf_getInstance
710 $default_font = pdf_getPDFFont($langs); // Must be
711
712 $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S");
713 $filename = "signatures/" . $date . "_signature.png";
714 if (!is_dir($upload_dir . "signatures/")) {
715 if (!dol_mkdir($upload_dir . "signatures/")) {
716 $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/";
717 $error++;
718 }
719 }
720
721 if (!$error) {
722 $return = file_put_contents($upload_dir . $filename, $data);
723 if ($return === false) {
724 $error++;
725 $response = 'Error file_put_content: failed to create signature file.';
726 } else {
727 dolChmod($upload_dir.$filename);
728 }
729 }
730
731 if (!$error) {
732 // Defined modele of doc
733 $last_main_doc_file = $object->last_main_doc;
734 $directdownloadlink = $object->getLastMainDocLink('fichinter'); // url to download the $object->last_main_doc
735
736 if (preg_match('/\.pdf/i', $last_main_doc_file)) {
737 $ref_pdf = pathinfo($last_main_doc_file, PATHINFO_FILENAME); // Retrieves the name of external or internal PDF
738
739 $newpdffilename = $upload_dir . $ref_pdf . "_signed-" . $date . ".pdf";
740 $sourcefile = $upload_dir . $ref_pdf . ".pdf";
741
742 if (dol_is_file($sourcefile)) {
743 $parameters = array('sourcefile' => $sourcefile, 'newpdffilename' => $newpdffilename);
744 $reshook = $hookmanager->executeHooks('AddSignature', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
745 if ($reshook < 0) {
746 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
747 }
748
749 if (empty($reshook)) {
750 // We build the new PDF
751 $pdf = pdf_getInstance();
752 if (class_exists('TCPDF')) {
753 $pdf->setPrintHeader(false);
754 $pdf->setPrintFooter(false);
755 }
756 $pdf->SetFont(pdf_getPDFFont($langs));
757
758 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
759 $pdf->SetCompression(false);
760 }
761
762 //$pdf->Open();
763 $pagecount = $pdf->setSourceFile($sourcefile); // original PDF
764
765 $param = array();
766 $param['online_sign_name'] = $online_sign_name;
767 $param['pathtoimage'] = $upload_dir . $filename;
768
769 $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297);
770 for ($i = 1; $i < ($pagecount + 1); $i++) {
771 try {
772 $tppl = $pdf->importPage($i);
773 $s = $pdf->getTemplatesize($tppl);
774 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
775 $pdf->useTemplate($tppl);
776
777 if (getDolGlobalString("FICHINTER_SIGNATURE_ON_ALL_PAGES")) {
778 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
779 // TODO Get position of box from PDF template
780
781 if (getDolGlobalString("FICHINTER_SIGNATURE_XFORIMGSTART")) {
782 $param['xforimgstart'] = getDolGlobalString("FICHINTER_SIGNATURE_XFORIMGSTART");
783 } else {
784 $param['xforimgstart'] = (empty($s['w']) ? 110 : round($s['w'] * 0.53));
785 }
786 if (getDolGlobalString("FICHINTER_SIGNATURE_YFORIMGSTART")) {
787 $param['yforimgstart'] = getDolGlobalString("FICHINTER_SIGNATURE_YFORIMGSTART");
788 } else {
789 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 60);
790 }
791 if (getDolGlobalString("FICHINTER_SIGNATURE_WFORIMG")) {
792 $param['wforimg'] = getDolGlobalString("FICHINTER_SIGNATURE_WFORIMG");
793 } else {
794 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16);
795 }
796
797 dolPrintSignatureImage($pdf, $langs, $param);
798 }
799 } catch (Exception $e) {
800 dol_syslog("Error when manipulating some PDF by onlineSign: " . $e->getMessage(), LOG_ERR);
801 $response = $e->getMessage();
802 $error++;
803 }
804 }
805
806 if (!getDolGlobalString("FICHINTER_SIGNATURE_ON_ALL_PAGES")) {
807 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
808 // TODO Get position of box from PDF template
809
810 $param['xforimgstart'] = (empty($s['w']) ? 110 : round($s['w'] * 0.53));
811 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 60);
812 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16);
813
814 dolPrintSignatureImage($pdf, $langs, $param);
815 }
816
817 //$pdf->Close();
818 $pdf->Output($newpdffilename, "F");
819
820 // Index the new file and update the last_main_doc property of object.
821 $object->indexFile($newpdffilename, 1);
822 }
823 }
824 if (!$error) {
825 $response = "success";
826 }
827 } elseif (preg_match('/\.odt/i', $last_main_doc_file)) {
828 // Adding signature on .ODT not yet supported
829 // TODO
830 } else {
831 // Document format not supported to insert online signature.
832 // We should just create an image file with the signature.
833 }
834 $user = new User($db);
835 $object->setSignedStatus($user, Fichinter::$SIGNED_STATUSES['STATUS_SIGNED_RECEIVER_ONLINE'], 0, 'FICHINTER_MODIFY');
836 }
837 } elseif ($mode == "societe_rib") {
838 $langs->load('withdrawals');
839 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
840 require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php';
841 $modelpath = "core/modules/bank/doc/";
842 $object = new CompanyBankAccount($db);
843 $object->fetch(0, $ref);
844 if (!empty($object->id)) {
845 $object->fetch_thirdparty();
846
847 $upload_dir = $conf->societe->multidir_output[$object->thirdparty->entity] . '/' . dol_sanitizeFileName((string) $object->thirdparty->id) . '/';
848
849 $default_font_size = pdf_getPDFFontSize($langs); // Must be after pdf_getInstance
850 $default_font = pdf_getPDFFont($langs); // Must be after pdf_getInstance
851 $langs->loadLangs(array("main", "companies"));
852
853 $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S");
854 $filename = "signatures/" . $date . "_signature.png";
855 if (!dol_is_dir($upload_dir . "signatures/")) {
856 if (!dol_mkdir($upload_dir . "signatures/")) {
857 $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/";
858 $error++;
859 }
860 }
861 if (!dol_is_writable($upload_dir . "signatures/")) {
862 $response = "Error directory " . $upload_dir . "signatures/ is not writable";
863 $error++;
864 }
865 if (!dol_is_writable(DOL_DATA_ROOT.'/admin/temp/')) { // This is used by TCPDF as working directory
866 $response = "Error directory " . DOL_DATA_ROOT."/admin/temp/ is not writable";
867 $error++;
868 }
869
870 if (!$error) {
871 $return = file_put_contents($upload_dir . $filename, $data);
872 if ($return === false) {
873 $error++;
874 $response = 'Error file_put_content: failed to create signature file.';
875 } else {
876 dolChmod($upload_dir.$filename);
877 }
878 }
879
880 if (!$error) {
881 // Defined modele of doc
882 $last_main_doc_file = $object->last_main_doc;
883 $last_modelpdf = $object->model_pdf;
884 $directdownloadlink = $object->getLastMainDocLink('company'); // url to download the $object->last_main_doc
885
886 if (preg_match('/\.pdf/i', $last_main_doc_file)) {
887 $sourcefile = '';
888 $newpdffilename = '';
889 if ($last_modelpdf == 'sepamandate') {
890 $newpdffilename = $upload_dir . $langs->transnoentitiesnoconv("SepaMandateShort") . ' ' . dol_sanitizeFileName($object->ref) . "-" . dol_sanitizeFileName($object->rum) . "_signed-" . $date . ".pdf";
891 $sourcefile = $upload_dir . $langs->transnoentitiesnoconv("SepaMandateShort") . ' ' . dol_sanitizeFileName($object->ref) . "-" . dol_sanitizeFileName($object->rum) . ".pdf";
892 } else {
893 // Fallback for setups using a non-default bank PDF model (eg. "ban"): take the last
894 // generated main document as source and append "_signed-<date>" before the extension.
895 // Without this the signed PDF is never built and the download link keeps pointing at
896 // the unsigned original.
897 $sourcefile = DOL_DATA_ROOT . '/' . $last_main_doc_file;
898 $newpdffilename = preg_replace('/\.pdf$/i', '_signed-' . $date . '.pdf', $sourcefile);
899 }
900 if (dol_is_file($sourcefile)) {
901 $parameters = array('sourcefile' => $sourcefile, 'newpdffilename' => $newpdffilename);
902 $reshook = $hookmanager->executeHooks('AddSignature', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
903 if ($reshook < 0) {
904 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
905 }
906
907 if (empty($reshook)) {
908 // We build the new PDF
909 $pdf = pdf_getInstance();
910 if (class_exists('TCPDF')) {
911 $pdf->setPrintHeader(false);
912 $pdf->setPrintFooter(false);
913 }
914 $pdf->SetFont(pdf_getPDFFont($langs));
915
916 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
917 $pdf->SetCompression(false);
918 }
919
920 //$pdf->Open();
921 $pagecount = $pdf->setSourceFile($sourcefile); // original PDF
922
923 $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297);
924 for ($i = 1; $i < ($pagecount + 1); $i++) {
925 try {
926 $tppl = $pdf->importPage($i);
927 $s = $pdf->getTemplatesize($tppl);
928 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
929 $pdf->useTemplate($tppl);
930 } catch (Exception $e) {
931 dol_syslog("Error when manipulating the PDF " . $sourcefile . " by onlineSign: " . $e->getMessage(), LOG_ERR);
932 $response = $e->getMessage();
933 $error++;
934 }
935 }
936
937
938 // Get position of box from PDF template
939 $file = '';
940 $classname = '';
941 $filefound = '';
942 $dirmodels = array('/');
943 if (is_array($conf->modules_parts['models'])) {
944 $dirmodels = array_merge($dirmodels, $conf->modules_parts['models']);
945 }
946 foreach ($dirmodels as $reldir) {
947 $file = "pdf_" . $last_modelpdf . ".modules.php";
948 // Check the template location
949 $file = dol_buildpath($reldir . $modelpath . $file, 0);
950 if (file_exists($file)) {
951 $filefound = $file;
952 $classname = 'pdf_' . $last_modelpdf;
953 break;
954 }
955 }
956
957 if ($filefound === '') {
958 $response = $langs->trans("Error") . ' Failed to load doc generator with modelpaths=' . $modelpath . ' - modele=' . $last_modelpdf;
959 dol_syslog($response, LOG_ERR);
960 $error++;
961 }
962
963 if (!$error && $classname !== '') {
964 // If PDF template class was found
965 require_once $file;
966
967 $objPDF = new $classname($db);
968
969 $pdf->SetFont($default_font, '', $default_font_size - 1);
970
971 $xForDate = $objPDF->marge_gauche;
972 $yForDate = $objPDF->page_hauteur - $objPDF->heightforinfotot - $objPDF->heightforfreetext - $objPDF->heightforfooter + 10;
973 $pdf->SetXY($xForDate, $yForDate);
974 $pdf->MultiCell(100, 4, dol_print_date(dol_now(), "daytext", false, $langs, true), 0, 'L');
975
976 $xforimgstart = $objPDF->xPosSignArea;
977 $yforimgstart = $yForDate - 5;
978 $wforimg = $s['w'] - 20 - $xforimgstart;
979
980 $param = array();
981 $param['online_sign_name'] = $online_sign_name;
982 $param['pathtoimage'] = $upload_dir . $filename;
983
984 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
985 // TODO Get position of box from PDF template
986
987 $param['xforimgstart'] = $xforimgstart;
988 $param['yforimgstart'] = $yforimgstart;
989 $param['wforimg'] = $wforimg;
990
991 dolPrintSignatureImage($pdf, $langs, $param);
992 }
993 //$pdf->Close();
994 $pdf->Output($newpdffilename, "F");
995
996 // Index the new file and update the last_main_doc property of object.
997 $object->indexFile($newpdffilename, 1);
998 }
999 }
1000 } elseif (preg_match('/\.odt/i', $last_main_doc_file)) {
1001 // Adding signature on .ODT not yet supported
1002 // TODO
1003 } else {
1004 // Document format not supported to insert online signature.
1005 // We should just create an image file with the signature.
1006 }
1007 }
1008 } else {
1009 $error++;
1010 $response = "cannot find BAN/RIB";
1011 }
1012
1013 if (!$error) {
1014 $db->begin();
1015
1016 $online_sign_ip = getUserRemoteIP();
1017
1018 $sql = "UPDATE " . MAIN_DB_PREFIX . $db->sanitize($object->table_element);
1019 $sql .= " SET ";
1020 $sql .= " date_signature = '" . $db->idate(dol_now()) . "',";
1021 $sql .= " online_sign_ip = '" . $db->escape($online_sign_ip) . "'";
1022 if ($online_sign_name) {
1023 $sql .= ", online_sign_name = '" . $db->escape($online_sign_name) . "'";
1024 }
1025 //$sql .= ", last_main_doc = '" . $db->escape($object->element'..') . "'";
1026
1027 $sql .= " WHERE rowid = " . ((int) $object->id);
1028
1029 dol_syslog(__FILE__, LOG_DEBUG);
1030 $resql = $db->query($sql);
1031 if (!$resql) {
1032 $error++;
1033 } else {
1034 $num = $db->affected_rows($resql);
1035 }
1036
1037 if (!$error) {
1038 $response = "success";
1039 } else {
1040 $error++;
1041 $response = "error sql";
1042 }
1043
1044 if (!$error) {
1045 $db->commit();
1046 $response = "success";
1047 setEventMessages(dol_ucfirst($mode)."Signed", null, 'warnings');
1048 } else {
1049 $db->rollback();
1050 }
1051 }
1052 } elseif ($mode == 'expedition') {
1053 require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php';
1054 require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php';
1055
1056 $object = new Expedition($db);
1057 $object->fetch(0, $ref);
1058
1059 $upload_dir = $conf->expedition->dir_output."/sending/";
1060 $upload_dir .= '/'.dol_sanitizeFileName($object->ref).'/';
1061
1062 $langs->loadLangs(array("main", "companies"));
1063
1064 $default_font_size = pdf_getPDFFontSize($langs); // Must be after pdf_getInstance
1065 $default_font = pdf_getPDFFont($langs); // Must be
1066
1067 $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S");
1068 $filename = "signatures/" . $date . "_signature.png";
1069 if (!is_dir($upload_dir . "signatures/")) {
1070 if (!dol_mkdir($upload_dir . "signatures/")) {
1071 $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/";
1072 $error++;
1073 }
1074 }
1075
1076 if (!$error) {
1077 $return = file_put_contents($upload_dir . $filename, $data);
1078 if ($return === false) {
1079 $error++;
1080 $response = 'Error file_put_content: failed to create signature file.';
1081 } else {
1082 dolChmod($upload_dir.$filename);
1083 }
1084 }
1085
1086 if (!$error) {
1087 $last_main_doc_file = $object->last_main_doc;
1088 // Defined modele of doc
1089 if (empty($last_main_doc_file) || !dol_is_file(DOL_DATA_ROOT.'/'.$object->last_main_doc)) {
1090 // It seems document has never been generated, or was generated and then deleted.
1091 // So we try to regenerate it with its default template.
1092 $defaulttemplate = ''; // We force the use an empty string instead of $object->model_pdf to be sure to use a "main" default template and not the last one used.
1093 $object->generateDocument($defaulttemplate, $langs);
1094 }
1095 $last_main_doc_file = $object->last_main_doc;
1096 $directdownloadlink = $object->getLastMainDocLink('expedition'); // url to download the $object->last_main_doc
1097
1098 if (preg_match('/\.pdf/i', $last_main_doc_file)) {
1099 $ref_pdf = pathinfo($last_main_doc_file, PATHINFO_FILENAME); // Retrieves the name of external or internal PDF
1100
1101 $newpdffilename = $upload_dir . $ref_pdf . "_signed-" . $date . ".pdf";
1102 $sourcefile = $upload_dir . $ref_pdf . ".pdf";
1103
1104 if (dol_is_file($sourcefile)) {
1105 $parameters = array('sourcefile' => $sourcefile, 'newpdffilename' => $newpdffilename);
1106 $reshook = $hookmanager->executeHooks('AddSignature', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1107 if ($reshook < 0) {
1108 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1109 }
1110
1111 if (empty($reshook)) {
1112 // We build the new PDF
1113 $pdf = pdf_getInstance();
1114 if (class_exists('TCPDF')) {
1115 $pdf->setPrintHeader(false);
1116 $pdf->setPrintFooter(false);
1117 }
1118 $pdf->SetFont(pdf_getPDFFont($langs));
1119
1120 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
1121 $pdf->SetCompression(false);
1122 }
1123
1124 //$pdf->Open();
1125 $pagecount = $pdf->setSourceFile($sourcefile); // original PDF
1126
1127 $param = array();
1128 $param['online_sign_name'] = $online_sign_name;
1129 $param['pathtoimage'] = $upload_dir . $filename;
1130
1131 $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297);
1132 for ($i = 1; $i < ($pagecount + 1); $i++) {
1133 try {
1134 $tppl = $pdf->importPage($i);
1135 $s = $pdf->getTemplatesize($tppl);
1136 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
1137 $pdf->useTemplate($tppl);
1138
1139 if (getDolGlobalString("SHIPMENT_SIGNATURE_ON_ALL_PAGES")) {
1140 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
1141 // TODO Get position of box from PDF template
1142
1143 $param['xforimgstart'] = (empty($s['w']) ? 110 : round($s['w'] * 0.53));
1144 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 60);
1145 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16);
1146
1147 dolPrintSignatureImage($pdf, $langs, $param);
1148 }
1149 } catch (Exception $e) {
1150 dol_syslog("Error when manipulating some PDF by onlineSign: " . $e->getMessage(), LOG_ERR);
1151 $response = $e->getMessage();
1152 $error++;
1153 }
1154 }
1155
1156 if (!getDolGlobalString("SHIPMENT_SIGNATURE_ON_ALL_PAGES")) {
1157 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
1158 // TODO Get position of box from PDF template
1159
1160 $param['xforimgstart'] = (empty($s['w']) ? 110 : round($s['w'] * 0.53));
1161 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 60);
1162 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16);
1163
1164 dolPrintSignatureImage($pdf, $langs, $param);
1165 }
1166
1167 //$pdf->Close();
1168 $pdf->Output($newpdffilename, "F");
1169
1170 // Index the new file and update the last_main_doc property of object.
1171 $object->indexFile($newpdffilename, 1);
1172 }
1173 }
1174 if (!$error) {
1175 $response = "success";
1176 }
1177 } elseif (preg_match('/\.odt/i', $last_main_doc_file)) {
1178 // Adding signature on .ODT not yet supported
1179 // TODO
1180 } else {
1181 // Document format not supported to insert online signature.
1182 // We should just create an image file with the signature.
1183 }
1184 }
1185 $user = new User($db);
1186 $object->setSignedStatus($user, Expedition::$SIGNED_STATUSES['STATUS_SIGNED_RECEIVER_ONLINE'], 0, 'SHIPPING_MODIFY');
1187 }
1188 } else {
1189 $error++;
1190 $response = 'error signature_not_found';
1191 }
1192}
1193
1194if ($error) {
1195 http_response_code(501);
1196}
1197
1198echo $response;
1199
1200
1209function dolPrintSignatureImage(TCPDF $pdf, $langs, $params)
1210{
1211 $default_font_size = pdf_getPDFFontSize($langs); // Must be after pdf_getInstance
1212 $default_font = pdf_getPDFFont($langs); // Must be
1213 $xforimgstart = $params['xforimgstart'];
1214 $yforimgstart = $params['yforimgstart'];
1215 $wforimg = $params['wforimg'];
1216
1217 $pdf->SetXY($xforimgstart, $yforimgstart + round($wforimg / 4) - 4);
1218 $pdf->SetFont($default_font, '', $default_font_size - 1);
1219 $pdf->SetTextColor(80, 80, 80);
1220 $pdf->MultiCell($wforimg, 4, $langs->transnoentities("Signature") . ': ' . dol_print_date(dol_now(), "day", false, $langs, true). ' - '.$params['online_sign_name'], 0, 'L');
1221 //$pdf->SetXY($xforimgstart, $yforimgstart + round($wforimg / 4));
1222 //$pdf->MultiCell($wforimg, 4, $langs->trans("Lastname") . ': ' . $online_sign_name, 0, 'L');
1223
1224 $pdf->Image($params['pathtoimage'], $xforimgstart, $yforimgstart, $wforimg, round($wforimg / 4));
1225
1226 return;
1227}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
Class to manage customers orders.
Class to manage bank accounts description of third parties.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage Dolibarr users.
dol_get_first_hour($date, $gm='tzserver')
Return GMT time for first hour of a given GMT date (it removes hours, min and second part)
Definition date.lib.php:676
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_is_writable($folderorfile)
Test if directory or filename is writable.
dol_is_file($pathoffile)
Return if path is a file.
dol_is_dir($folder)
Test if filename is a directory.
dol_now($mode='gmt')
Return date for now.
dol_ucfirst($string, $encoding="UTF-8")
Convert first character of the first word of a string to upper.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
dolChmod($filepath, $newmask='')
Change mod of a file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getUserRemoteIP($trusted=0)
Return the real IP of remote user.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Definition html.lib.php:181
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
dolPrintSignatureImage(TCPDF $pdf, $langs, $params)
Output the signature file into the PDF object.
pdf_getFormat($outputlangs=null, $mode='setup')
Return array with format properties of default PDF format.
Definition pdf.lib.php:87
pdf_getPDFFontSize($outputlangs)
Return font size to use for PDF generation.
Definition pdf.lib.php:296
pdfExtractMetadata($file, $field='Keywords')
Function to extract metadata from a PDF file by doing a binary parsing of the PDF file.
Definition pdf.lib.php:3324
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition pdf.lib.php:275
pdf_getInstance($format='', $metric='mm', $pagetype='P')
Return a PDF instance object.
Definition pdf.lib.php:129
httponly_accessforbidden($message='1', $http_response_code=403, $stringalreadysanitized=0)
Show a message to say access is forbidden and stop program.
dol_hash($chain, $type='0', $nosalt=0, $mode=0)
Returns a hash (non reversible encryption) of a string.
dol_verifyHash($chain, $hash, $type='0')
Compute a hash and compare it to the given one For backward compatibility reasons,...