dolibarr 23.0.3
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-2025 Frédéric France <frederic.france@free.fr>
4 * Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
25if (!defined('NOTOKENRENEWAL')) {
26 define('NOTOKENRENEWAL', '1'); // Disables token renewal
27}
28if (!defined('NOREQUIREHTML')) {
29 define('NOREQUIREHTML', '1');
30}
31if (!defined('NOREQUIREAJAX')) {
32 define('NOREQUIREAJAX', '1');
33}
34// Needed to create other objects with workflow
35/*if (!defined('NOREQUIRESOC')) {
36 define('NOREQUIRESOC', '1');
37}*/
38// Do not check anti CSRF attack test
39if (!defined('NOREQUIREMENU')) {
40 define('NOREQUIREMENU', '1');
41}
42// If there is no need to load and show top and left menu
43if (!defined("NOLOGIN")) {
44 define("NOLOGIN", '1');
45}
46if (!defined('NOIPCHECK')) {
47 define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip
48}
49if (!defined('NOBROWSERNOTIF')) {
50 define('NOBROWSERNOTIF', '1');
51}
52$entity = (!empty($_GET['entity']) ? (int) $_GET['entity'] : (!empty($_POST['entity']) ? (int) $_POST['entity'] : 1)); // Keep $_GET and $_POST here. GETPOST not yet defined.
53if (is_numeric($entity)) {
54 define("DOLENTITY", $entity);
55}
56include '../../main.inc.php';
57require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php';
66$action = GETPOST('action', 'aZ09');
67
68$signature = GETPOST('signaturebase64');
69// Match the filter the producer uses in newonlinesign.php:97 ('alpha').
70// Refs such as PR2601-0003 contain a dash, which aZ09 strips. After stripping
71// the dash, dol_verifyHash fails because the security key was built from the
72// full reference, so onlineSign answered 403 even on valid submissions (#31464).
73$ref = GETPOST('ref', 'alpha');
74$mode = GETPOST('mode', 'aZ09'); // 'proposal', ...
75$SECUREKEY = GETPOST("securekey"); // Secure key
76$online_sign_name = GETPOST("onlinesignname");
77
78$error = 0;
79$response = "";
80
81$type = $mode;
82
83// Security check
84$securekeyseed = '';
85if ($type == 'proposal') {
86 $securekeyseed = getDolGlobalString('PROPOSAL_ONLINE_SIGNATURE_SECURITY_TOKEN');
87} elseif ($type == 'contract') {
88 $securekeyseed = getDolGlobalString('CONTRACT_ONLINE_SIGNATURE_SECURITY_TOKEN');
89} elseif ($type == 'fichinter') {
90 $securekeyseed = getDolGlobalString('FICHINTER_ONLINE_SIGNATURE_SECURITY_TOKEN');
91} else {
92 $securekeyseed = getDolGlobalString(strtoupper($type).'_ONLINE_SIGNATURE_SECURITY_TOKEN');
93}
94
95if (empty($SECUREKEY) || !dol_verifyHash($securekeyseed . $type . $ref . (!isModEnabled('multicompany') ? '' : $entity), $SECUREKEY, '0')) {
96 httponly_accessforbidden('Bad value for securitykey. Value provided ' . dol_escape_htmltag($SECUREKEY) . ' does not match expected value for ref=' . dol_escape_htmltag($ref), 403);
97}
98
99// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
100$hookmanager->initHooks(array('ajaxonlinesign'));
101
102
103/*
104 * Actions
105 */
106
107// None
108
109
110/*
111 * View
112 */
113
115
116if ($action == "importSignature") {
117 $issignatureok = (!empty($signature) && $signature[0] == "image/png;base64");
118 if ($issignatureok) {
119 $signature = $signature[1];
120 $data = base64_decode($signature);
121
122 if ($mode == "propale" || $mode == 'proposal') {
123 require_once DOL_DOCUMENT_ROOT . '/comm/propal/class/propal.class.php';
124 require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php';
125 $object = new Propal($db);
126 $object->fetch(0, $ref);
127
128 $upload_dir = !empty($conf->propal->multidir_output[$object->entity ?? $conf->entity]) ? $conf->propal->multidir_output[$object->entity ?? $conf->entity] : $conf->propal->dir_output;
129 $upload_dir .= '/' . dol_sanitizeFileName($object->ref) . '/';
130
131 $default_font_size = pdf_getPDFFontSize($langs); // Must be after pdf_getInstance
132 $default_font = pdf_getPDFFont($langs); // Must be after pdf_getInstance
133 $langs->loadLangs(array("main", "companies"));
134
135 $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S");
136 $filename = "signatures/" . $date . "_signature.png";
137 if (!is_dir($upload_dir . "signatures/")) {
138 if (!dol_mkdir($upload_dir . "signatures/")) {
139 $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/";
140 $error++;
141 }
142 }
143
144 if (!$error) {
145 $return = file_put_contents($upload_dir.$filename, $data);
146 if ($return === false) {
147 $error++;
148 $response = 'Error file_put_content: failed to create signature file.';
149 } else {
150 dolChmod($upload_dir.$filename);
151 }
152 }
153
154 if (!$error) {
155 // Defined modele of doc
156 $last_main_doc_file = $object->last_main_doc;
157 $directdownloadlink = $object->getLastMainDocLink('proposal'); // url to download the $object->last_main_doc
158
159 if (preg_match('/\.pdf/i', $last_main_doc_file)) {
160 $ref_pdf = pathinfo($last_main_doc_file, PATHINFO_FILENAME); // Retrieves the name of external or internal PDF
161 $ref_pdf = preg_replace('/_signed-(\d+)/', '', $ref_pdf);
162
163 $newpdffilename = $upload_dir . $ref_pdf . "_signed-" . $date . ".pdf";
164 $sourcefile = $upload_dir . $ref_pdf . ".pdf";
165
166 if (dol_is_file($sourcefile)) {
167 $parameters = array('sourcefile' => $sourcefile, 'newpdffilename' => $newpdffilename);
168 $reshook = $hookmanager->executeHooks('AddSignature', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
169 if ($reshook < 0) {
170 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
171 }
172
173 if (empty($reshook)) {
174 // We build the new PDF
175 $pdf = pdf_getInstance();
176 if (class_exists('TCPDF')) {
177 $pdf->setPrintHeader(false);
178 $pdf->setPrintFooter(false);
179 }
180 $pdf->SetFont(pdf_getPDFFont($langs));
181
182 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
183 $pdf->SetCompression(false);
184 }
185
186 //$pdf->Open();
187 $pagecount = $pdf->setSourceFile($sourcefile); // original PDF
188
189 $param = array();
190 $param['online_sign_name'] = $online_sign_name;
191 $param['pathtoimage'] = $upload_dir . $filename;
192
193 $propalsignonspecificpage = getDolGlobalInt("PROPAL_SIGNATURE_ON_SPECIFIC_PAGE");
194
195 $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297);
196 for ($i = 1; $i < ($pagecount + 1); $i++) {
197 try {
198 $tppl = $pdf->importPage($i);
199 $s = $pdf->getTemplatesize($tppl);
200 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
201 $pdf->useTemplate($tppl);
202 if ($propalsignonspecificpage < 0) {
203 $propalsignonspecificpage = $pagecount - abs($propalsignonspecificpage);
204 }
205
206 if (empty($propalsignonspecificpage)) {
207 // Now we get the metadata keywords from the $sourcefile PDF (by parsing the binary PDF file) and use it to extract
208 // the page x in PAGESIGN=x into $propalsignonspecificpage
209 $keywords = pdfExtractMetadata($sourcefile, 'Keywords');
210 $reg = array();
211 if (preg_match('/PAGESIGN=(\d+)/', $keywords, $reg)) {
212 $propalsignonspecificpage = (int) $reg[1];
213 }
214 }
215
216 if (getDolGlobalString("PROPAL_SIGNATURE_ON_ALL_PAGES") || $propalsignonspecificpage == $i) {
217 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
218 // TODO Get position of box from PDF template
219
220 if (getDolGlobalString("PROPAL_SIGNATURE_XFORIMGSTART")) {
221 $param['xforimgstart'] = getDolGlobalString("PROPAL_SIGNATURE_XFORIMGSTART");
222 } else {
223 $param['xforimgstart'] = (empty($s['w']) ? 120 : round($s['w'] / 2) + 15);
224 }
225 if (getDolGlobalString("PROPAL_SIGNATURE_YFORIMGSTART")) {
226 $param['yforimgstart'] = getDolGlobalString("PROPAL_SIGNATURE_YFORIMGSTART");
227 } else {
228 $param['yforimgstart'] = (empty($s['h']) ? 240 : $s['h'] - 60);
229 }
230 if (getDolGlobalString("PROPAL_SIGNATURE_WFORIMG")) {
231 $param['wforimg'] = getDolGlobalString("PROPAL_SIGNATURE_WFORIMG");
232 } else {
233 $param['wforimg'] = $s['w'] - 20 - $param['xforimgstart'];
234 }
235
236 dolPrintSignatureImage($pdf, $langs, $param);
237 }
238 } catch (Exception $e) {
239 dol_syslog("Error when manipulating the PDF " . $sourcefile . " by onlineSign: " . $e->getMessage(), LOG_ERR);
240 $response = $e->getMessage();
241 $error++;
242 }
243 }
244
245 if (!getDolGlobalString("PROPAL_SIGNATURE_ON_ALL_PAGES") && !$propalsignonspecificpage) {
246 // We do not found specific instruction or page for the signature, so we add it now we are on the last page.
247 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
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
267 //$pdf->Close();
268 $pdf->Output($newpdffilename, "F");
269
270 // Index the new file and update the last_main_doc property of object.
271 $object->indexFile($newpdffilename, 1);
272 }
273 }
274 } elseif (preg_match('/\.odt/i', $last_main_doc_file)) {
275 // Adding signature on .ODT not yet supported
276 // TODO
277 } else {
278 // Document format not supported to insert online signature.
279 // We should just create an image file with the signature.
280 }
281 }
282
283 if (!$error) {
284 $db->begin();
285
286 $online_sign_ip = getUserRemoteIP();
287
288 $sql = "UPDATE " . MAIN_DB_PREFIX . "propal";
289 $sql .= " SET fk_statut = " . ((int) $object::STATUS_SIGNED) . ", note_private = '" . $db->escape($object->note_private) . "',";
290 $sql .= " date_signature = '" . $db->idate(dol_now()) . "',";
291 $sql .= " online_sign_ip = '" . $db->escape($online_sign_ip) . "'";
292 if ($online_sign_name) {
293 $sql .= ", online_sign_name = '" . $db->escape($online_sign_name) . "'";
294 }
295 $sql .= " WHERE rowid = " . ((int) $object->id);
296
297 dol_syslog(__FILE__, LOG_DEBUG);
298 $resql = $db->query($sql);
299 if (!$resql) {
300 $error++;
301 } else {
302 $num = $db->affected_rows($resql);
303 }
304
305 if (!$error) {
306 if (method_exists($object, 'call_trigger')) {
307 //customer is not a user !?! so could we use same user as validation ?
308 $user = new User($db);
309 $user->fetch($object->user_validation_id);
310 $object->context = array('closedfromonlinesignature' => 'closedfromonlinesignature');
311 $result = $object->call_trigger('PROPAL_CLOSE_SIGNED', $user);
312 if ($result < 0) {
313 $error++;
314 $response = "error in trigger " . $object->error;
315 } else {
316 $soc = new Societe($db);
317 $soc->id = $object->socid;
318 $result = $soc->setAsCustomer();
319 if ($result < 0) {
320 $error++;
321 $response = $db->lasterror();
322 } else {
323 $response = "success";
324 }
325 }
326 } else {
327 $response = "success";
328 }
329 } else {
330 $error++;
331 $response = "error sql";
332 }
333
334 if (!$error) {
335 $db->commit();
336 $response = "success";
337 setEventMessages("PropalSigned", null, 'warnings');
338 } else {
339 $db->rollback();
340 }
341 }
342 } elseif ($mode == 'contract') {
343 require_once DOL_DOCUMENT_ROOT . '/contrat/class/contrat.class.php';
344 require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php';
345 $object = new Contrat($db);
346 $object->fetch(0, $ref);
347
348 $upload_dir = !empty($conf->contrat->multidir_output[$object->entity ?? $conf->entity]) ? $conf->contrat->multidir_output[$object->entity ?? $conf->entity] : $conf->contrat->dir_output;
349 $upload_dir .= '/' . dol_sanitizeFileName($object->ref) . '/';
350
351 $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S");
352 $filename = "signatures/" . $date . "_signature.png";
353 if (!is_dir($upload_dir . "signatures/")) {
354 if (!dol_mkdir($upload_dir . "signatures/")) {
355 $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/";
356 $error++;
357 }
358 }
359
360 if (!$error) {
361 $return = file_put_contents($upload_dir . $filename, $data);
362 if ($return === false) {
363 $error++;
364 $response = 'Error file_put_content: failed to create signature file.';
365 } else {
366 dolChmod($upload_dir.$filename);
367 }
368 }
369
370 if (!$error) {
371 // Defined modele of doc
372 $last_main_doc_file = $object->last_main_doc;
373 $directdownloadlink = $object->getLastMainDocLink('contrat'); // url to download the $object->last_main_doc
374
375 if (preg_match('/\.pdf/i', $last_main_doc_file)) {
376 $ref_pdf = pathinfo($last_main_doc_file, PATHINFO_FILENAME); // Retrieves the name of external or internal PDF
377
378 $newpdffilename = $upload_dir . $ref_pdf . "_signed-" . $date . ".pdf";
379 $sourcefile = $upload_dir . $ref_pdf . ".pdf";
380
381 if (dol_is_file($sourcefile)) {
382 $parameters = array('sourcefile' => $sourcefile, 'newpdffilename' => $newpdffilename);
383 $reshook = $hookmanager->executeHooks('AddSignature', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
384 if ($reshook < 0) {
385 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
386 }
387
388 if (empty($reshook)) {
389 // We build the new PDF
390 $pdf = pdf_getInstance();
391 if (class_exists('TCPDF')) {
392 $pdf->setPrintHeader(false);
393 $pdf->setPrintFooter(false);
394 }
395 $pdf->SetFont(pdf_getPDFFont($langs));
396
397 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
398 $pdf->SetCompression(false);
399 }
400
401 //$pdf->Open();
402 $pagecount = $pdf->setSourceFile($sourcefile); // original PDF
403
404 $param = array();
405 $param['online_sign_name'] = $online_sign_name;
406 $param['pathtoimage'] = $upload_dir . $filename;
407
408 $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297);
409 for ($i = 1; $i < ($pagecount + 1); $i++) {
410 try {
411 $tppl = $pdf->importPage($i);
412 $s = $pdf->getTemplatesize($tppl);
413 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
414 $pdf->useTemplate($tppl);
415
416 if (getDolGlobalString("CONTRACT_SIGNATURE_ON_ALL_PAGES")) {
417 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
418 // TODO Get position of box from PDF template
419
420 if (getDolGlobalString("CONTRACT_SIGNATURE_XFORIMGSTART")) {
421 $param['xforimgstart'] = getDolGlobalString("CONTRACT_SIGNATURE_XFORIMGSTART");
422 } else {
423 $param['xforimgstart'] = (empty($s['w']) ? 110 : $s['w'] / 2 - 0);
424 }
425 if (getDolGlobalString("CONTRACT_SIGNATURE_YFORIMGSTART")) {
426 $param['yforimgstart'] = getDolGlobalString("CONTRACT_SIGNATURE_YFORIMGSTART");
427 } else {
428 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 62);
429 }
430 if (getDolGlobalString("CONTRACT_SIGNATURE_WFORIMG")) {
431 $param['wforimg'] = getDolGlobalString("CONTRACT_SIGNATURE_WFORIMG");
432 } else {
433 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16);
434 }
435
436 dolPrintSignatureImage($pdf, $langs, $param);
437 }
438 } catch (Exception $e) {
439 dol_syslog("Error when manipulating some PDF by onlineSign: " . $e->getMessage(), LOG_ERR);
440 $response = $e->getMessage();
441 $error++;
442 }
443 }
444
445 if (!getDolGlobalString("CONTRACT_SIGNATURE_ON_ALL_PAGES")) {
446 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
447 // TODO Get position of box from PDF template
448
449 $param['xforimgstart'] = (empty($s['w']) ? 110 : $s['w'] / 2 - 0);
450 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 62);
451 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16);
452
453 dolPrintSignatureImage($pdf, $langs, $param);
454 }
455
456 //$pdf->Close();
457 $pdf->Output($newpdffilename, "F");
458
459 // Index the new file and update the last_main_doc property of object.
460 $object->indexFile($newpdffilename, 1);
461 }
462 }
463 if (!$error) {
464 $response = "success";
465 }
466 } elseif (preg_match('/\.odt/i', $last_main_doc_file)) {
467 // Adding signature on .ODT not yet supported
468 // TODO
469 } else {
470 // Document format not supported to insert online signature.
471 // We should just create an image file with the signature.
472 }
473 $user = new User($db);
474 $object->setSignedStatus($user, Contrat::$SIGNED_STATUSES['STATUS_SIGNED_RECEIVER_ONLINE'], 0, 'CONTRACT_MODIFY');
475 }
476 } elseif ($mode == 'fichinter') {
477 require_once DOL_DOCUMENT_ROOT . '/fichinter/class/fichinter.class.php';
478 require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php';
479 $object = new Fichinter($db);
480 $object->fetch(0, $ref);
481
482 $upload_dir = !empty($conf->ficheinter->multidir_output[$object->entity ?? $conf->entity]) ? $conf->ficheinter->multidir_output[$object->entity ?? $conf->entity] : $conf->ficheinter->dir_output;
483 $upload_dir .= '/'.dol_sanitizeFileName($object->ref).'/';
484
485 $langs->loadLangs(array("main", "companies"));
486
487 $default_font_size = pdf_getPDFFontSize($langs); // Must be after pdf_getInstance
488 $default_font = pdf_getPDFFont($langs); // Must be
489
490 $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S");
491 $filename = "signatures/" . $date . "_signature.png";
492 if (!is_dir($upload_dir . "signatures/")) {
493 if (!dol_mkdir($upload_dir . "signatures/")) {
494 $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/";
495 $error++;
496 }
497 }
498
499 if (!$error) {
500 $return = file_put_contents($upload_dir . $filename, $data);
501 if ($return === false) {
502 $error++;
503 $response = 'Error file_put_content: failed to create signature file.';
504 } else {
505 dolChmod($upload_dir.$filename);
506 }
507 }
508
509 if (!$error) {
510 // Defined modele of doc
511 $last_main_doc_file = $object->last_main_doc;
512 $directdownloadlink = $object->getLastMainDocLink('fichinter'); // url to download the $object->last_main_doc
513
514 if (preg_match('/\.pdf/i', $last_main_doc_file)) {
515 $ref_pdf = pathinfo($last_main_doc_file, PATHINFO_FILENAME); // Retrieves the name of external or internal PDF
516
517 $newpdffilename = $upload_dir . $ref_pdf . "_signed-" . $date . ".pdf";
518 $sourcefile = $upload_dir . $ref_pdf . ".pdf";
519
520 if (dol_is_file($sourcefile)) {
521 $parameters = array('sourcefile' => $sourcefile, 'newpdffilename' => $newpdffilename);
522 $reshook = $hookmanager->executeHooks('AddSignature', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
523 if ($reshook < 0) {
524 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
525 }
526
527 if (empty($reshook)) {
528 // We build the new PDF
529 $pdf = pdf_getInstance();
530 if (class_exists('TCPDF')) {
531 $pdf->setPrintHeader(false);
532 $pdf->setPrintFooter(false);
533 }
534 $pdf->SetFont(pdf_getPDFFont($langs));
535
536 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
537 $pdf->SetCompression(false);
538 }
539
540 //$pdf->Open();
541 $pagecount = $pdf->setSourceFile($sourcefile); // original PDF
542
543 $param = array();
544 $param['online_sign_name'] = $online_sign_name;
545 $param['pathtoimage'] = $upload_dir . $filename;
546
547 $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297);
548 for ($i = 1; $i < ($pagecount + 1); $i++) {
549 try {
550 $tppl = $pdf->importPage($i);
551 $s = $pdf->getTemplatesize($tppl);
552 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
553 $pdf->useTemplate($tppl);
554
555 if (getDolGlobalString("FICHINTER_SIGNATURE_ON_ALL_PAGES")) {
556 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
557 // TODO Get position of box from PDF template
558
559 if (getDolGlobalString("FICHINTER_SIGNATURE_XFORIMGSTART")) {
560 $param['xforimgstart'] = getDolGlobalString("FICHINTER_SIGNATURE_XFORIMGSTART");
561 } else {
562 $param['xforimgstart'] = (empty($s['w']) ? 110 : $s['w'] / 2 - 2);
563 }
564 if (getDolGlobalString("FICHINTER_SIGNATURE_YFORIMGSTART")) {
565 $param['yforimgstart'] = getDolGlobalString("FICHINTER_SIGNATURE_YFORIMGSTART");
566 } else {
567 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 38);
568 }
569 if (getDolGlobalString("FICHINTER_SIGNATURE_WFORIMG")) {
570 $param['wforimg'] = getDolGlobalString("FICHINTER_SIGNATURE_WFORIMG");
571 } else {
572 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 20);
573 }
574
575 dolPrintSignatureImage($pdf, $langs, $param);
576 }
577 } catch (Exception $e) {
578 dol_syslog("Error when manipulating some PDF by onlineSign: " . $e->getMessage(), LOG_ERR);
579 $response = $e->getMessage();
580 $error++;
581 }
582 }
583
584 if (!getDolGlobalString("FICHINTER_SIGNATURE_ON_ALL_PAGES")) {
585 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
586 // TODO Get position of box from PDF template
587
588 $param['xforimgstart'] = (empty($s['w']) ? 110 : $s['w'] / 2 - 2);
589 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 38);
590 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 20);
591
592 dolPrintSignatureImage($pdf, $langs, $param);
593 }
594
595 //$pdf->Close();
596 $pdf->Output($newpdffilename, "F");
597
598 // Index the new file and update the last_main_doc property of object.
599 $object->indexFile($newpdffilename, 1);
600 }
601 }
602 if (!$error) {
603 $response = "success";
604 }
605 } elseif (preg_match('/\.odt/i', $last_main_doc_file)) {
606 // Adding signature on .ODT not yet supported
607 // TODO
608 } else {
609 // Document format not supported to insert online signature.
610 // We should just create an image file with the signature.
611 }
612 $user = new User($db);
613 $object->setSignedStatus($user, Fichinter::$SIGNED_STATUSES['STATUS_SIGNED_RECEIVER_ONLINE'], 0, 'FICHINTER_MODIFY');
614 }
615 } elseif ($mode == "societe_rib") {
616 $langs->load('withdrawals');
617 require_once DOL_DOCUMENT_ROOT . '/societe/class/companybankaccount.class.php';
618 require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php';
619 $modelpath = "core/modules/bank/doc/";
620 $object = new CompanyBankAccount($db);
621 $object->fetch(0, $ref);
622 if (!empty($object->id)) {
623 $object->fetch_thirdparty();
624
625 $upload_dir = $conf->societe->multidir_output[$object->thirdparty->entity] . '/' . dol_sanitizeFileName((string) $object->thirdparty->id) . '/';
626
627 $default_font_size = pdf_getPDFFontSize($langs); // Must be after pdf_getInstance
628 $default_font = pdf_getPDFFont($langs); // Must be after pdf_getInstance
629 $langs->loadLangs(array("main", "companies"));
630
631 $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S");
632 $filename = "signatures/" . $date . "_signature.png";
633 if (!dol_is_dir($upload_dir . "signatures/")) {
634 if (!dol_mkdir($upload_dir . "signatures/")) {
635 $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/";
636 $error++;
637 }
638 }
639 if (!dol_is_writable($upload_dir . "signatures/")) {
640 $response = "Error directory " . $upload_dir . "signatures/ is not writable";
641 $error++;
642 }
643 if (!dol_is_writable(DOL_DATA_ROOT.'/admin/temp/')) { // This is used by TCPDF as working directory
644 $response = "Error directory " . DOL_DATA_ROOT."/admin/temp/ is not writable";
645 $error++;
646 }
647
648 if (!$error) {
649 $return = file_put_contents($upload_dir . $filename, $data);
650 if ($return === false) {
651 $error++;
652 $response = 'Error file_put_content: failed to create signature file.';
653 } else {
654 dolChmod($upload_dir.$filename);
655 }
656 }
657
658 if (!$error) {
659 // Defined modele of doc
660 $last_main_doc_file = $object->last_main_doc;
661 $last_modelpdf = $object->model_pdf;
662 $directdownloadlink = $object->getLastMainDocLink('company'); // url to download the $object->last_main_doc
663
664 if (preg_match('/\.pdf/i', $last_main_doc_file)) {
665 $sourcefile = '';
666 $newpdffilename = '';
667 if ($last_modelpdf == 'sepamandate') {
668 $newpdffilename = $upload_dir . $langs->transnoentitiesnoconv("SepaMandateShort") . ' ' . dol_sanitizeFileName($object->ref) . "-" . dol_sanitizeFileName($object->rum) . "_signed-" . $date . ".pdf";
669 $sourcefile = $upload_dir . $langs->transnoentitiesnoconv("SepaMandateShort") . ' ' . dol_sanitizeFileName($object->ref) . "-" . dol_sanitizeFileName($object->rum) . ".pdf";
670 } else {
671 // Fallback for setups using a non-default bank PDF model (eg. "ban"): take the last
672 // generated main document as source and append "_signed-<date>" before the extension.
673 // Without this the signed PDF is never built and the download link keeps pointing at
674 // the unsigned original.
675 $sourcefile = DOL_DATA_ROOT . '/' . $last_main_doc_file;
676 $newpdffilename = preg_replace('/\.pdf$/i', '_signed-' . $date . '.pdf', $sourcefile);
677 }
678 if (dol_is_file($sourcefile)) {
679 $parameters = array('sourcefile' => $sourcefile, 'newpdffilename' => $newpdffilename);
680 $reshook = $hookmanager->executeHooks('AddSignature', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
681 if ($reshook < 0) {
682 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
683 }
684
685 if (empty($reshook)) {
686 // We build the new PDF
687 $pdf = pdf_getInstance();
688 if (class_exists('TCPDF')) {
689 $pdf->setPrintHeader(false);
690 $pdf->setPrintFooter(false);
691 }
692 $pdf->SetFont(pdf_getPDFFont($langs));
693
694 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
695 $pdf->SetCompression(false);
696 }
697
698 //$pdf->Open();
699 $pagecount = $pdf->setSourceFile($sourcefile); // original PDF
700
701 $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297);
702 for ($i = 1; $i < ($pagecount + 1); $i++) {
703 try {
704 $tppl = $pdf->importPage($i);
705 $s = $pdf->getTemplatesize($tppl);
706 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
707 $pdf->useTemplate($tppl);
708 } catch (Exception $e) {
709 dol_syslog("Error when manipulating the PDF " . $sourcefile . " by onlineSign: " . $e->getMessage(), LOG_ERR);
710 $response = $e->getMessage();
711 $error++;
712 }
713 }
714
715
716 // Get position of box from PDF template
717 $file = '';
718 $classname = '';
719 $filefound = '';
720 $dirmodels = array('/');
721 if (is_array($conf->modules_parts['models'])) {
722 $dirmodels = array_merge($dirmodels, $conf->modules_parts['models']);
723 }
724 foreach ($dirmodels as $reldir) {
725 $file = "pdf_" . $last_modelpdf . ".modules.php";
726 // On vérifie l'emplacement du modele
727 $file = dol_buildpath($reldir . $modelpath . $file, 0);
728 if (file_exists($file)) {
729 $filefound = $file;
730 $classname = 'pdf_' . $last_modelpdf;
731 break;
732 }
733 }
734
735 if ($filefound === '') {
736 $response = $langs->trans("Error") . ' Failed to load doc generator with modelpaths=' . $modelpath . ' - modele=' . $last_modelpdf;
737 dol_syslog($response, LOG_ERR);
738 $error++;
739 }
740
741 if (!$error && $classname !== '') {
742 // If PDF template class was found
743 require_once $file;
744
745 $objPDF = new $classname($db);
746
747 $pdf->SetFont($default_font, '', $default_font_size - 1);
748
749 $xForDate = $objPDF->marge_gauche;
750 $yForDate = $objPDF->page_hauteur - $objPDF->heightforinfotot - $objPDF->heightforfreetext - $objPDF->heightforfooter + 10;
751 $pdf->SetXY($xForDate, $yForDate);
752 $pdf->MultiCell(100, 4, dol_print_date(dol_now(), "daytext", false, $langs, true), 0, 'L');
753
754 $xforimgstart = $objPDF->xPosSignArea;
755 $yforimgstart = $yForDate - 5;
756 $wforimg = $s['w'] - 20 - $xforimgstart;
757
758 $param = array();
759 $param['online_sign_name'] = $online_sign_name;
760 $param['pathtoimage'] = $upload_dir . $filename;
761
762 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
763 // TODO Get position of box from PDF template
764
765 $param['xforimgstart'] = $xforimgstart;
766 $param['yforimgstart'] = $yforimgstart;
767 $param['wforimg'] = $wforimg;
768
769 dolPrintSignatureImage($pdf, $langs, $param);
770 }
771 //$pdf->Close();
772 $pdf->Output($newpdffilename, "F");
773
774 // Index the new file and update the last_main_doc property of object.
775 $object->indexFile($newpdffilename, 1);
776 }
777 }
778 } elseif (preg_match('/\.odt/i', $last_main_doc_file)) {
779 // Adding signature on .ODT not yet supported
780 // TODO
781 } else {
782 // Document format not supported to insert online signature.
783 // We should just create an image file with the signature.
784 }
785 }
786 } else {
787 $error++;
788 $response = "cannot find BAN/RIB";
789 }
790
791 if (!$error) {
792 $db->begin();
793
794 $online_sign_ip = getUserRemoteIP();
795
796 $sql = "UPDATE " . MAIN_DB_PREFIX . $object->table_element;
797 $sql .= " SET ";
798 $sql .= " date_signature = '" . $db->idate(dol_now()) . "',";
799 $sql .= " online_sign_ip = '" . $db->escape($online_sign_ip) . "'";
800 if ($online_sign_name) {
801 $sql .= ", online_sign_name = '" . $db->escape($online_sign_name) . "'";
802 }
803 //$sql .= ", last_main_doc = '" . $db->escape($object->element'..') . "'";
804
805 $sql .= " WHERE rowid = " . ((int) $object->id);
806
807 dol_syslog(__FILE__, LOG_DEBUG);
808 $resql = $db->query($sql);
809 if (!$resql) {
810 $error++;
811 } else {
812 $num = $db->affected_rows($resql);
813 }
814
815 if (!$error) {
816 $response = "success";
817 } else {
818 $error++;
819 $response = "error sql";
820 }
821
822 if (!$error) {
823 $db->commit();
824 $response = "success";
825 setEventMessages(dol_ucfirst($mode)."Signed", null, 'warnings');
826 } else {
827 $db->rollback();
828 }
829 }
830 } elseif ($mode == 'expedition') {
831 require_once DOL_DOCUMENT_ROOT . '/expedition/class/expedition.class.php';
832 require_once DOL_DOCUMENT_ROOT . '/core/lib/pdf.lib.php';
833
834 $object = new Expedition($db);
835 $object->fetch(0, $ref);
836
837 $upload_dir = $conf->expedition->dir_output."/sending/";
838 $upload_dir .= '/'.dol_sanitizeFileName($object->ref).'/';
839
840 $langs->loadLangs(array("main", "companies"));
841
842 $default_font_size = pdf_getPDFFontSize($langs); // Must be after pdf_getInstance
843 $default_font = pdf_getPDFFont($langs); // Must be
844
845 $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S");
846 $filename = "signatures/" . $date . "_signature.png";
847 if (!is_dir($upload_dir . "signatures/")) {
848 if (!dol_mkdir($upload_dir . "signatures/")) {
849 $response = "Error mkdir. Failed to create dir " . $upload_dir . "signatures/";
850 $error++;
851 }
852 }
853
854 if (!$error) {
855 $return = file_put_contents($upload_dir . $filename, $data);
856 if ($return === false) {
857 $error++;
858 $response = 'Error file_put_content: failed to create signature file.';
859 } else {
860 dolChmod($upload_dir.$filename);
861 }
862 }
863
864 if (!$error) {
865 $last_main_doc_file = $object->last_main_doc;
866 // Defined modele of doc
867 if (empty($last_main_doc_file) || !dol_is_file(DOL_DATA_ROOT.'/'.$object->last_main_doc)) {
868 // It seems document has never been generated, or was generated and then deleted.
869 // So we try to regenerate it with its default template.
870 $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.
871 $object->generateDocument($defaulttemplate, $langs);
872 }
873 $last_main_doc_file = $object->last_main_doc;
874 $directdownloadlink = $object->getLastMainDocLink('expedition'); // url to download the $object->last_main_doc
875
876 if (preg_match('/\.pdf/i', $last_main_doc_file)) {
877 $ref_pdf = pathinfo($last_main_doc_file, PATHINFO_FILENAME); // Retrieves the name of external or internal PDF
878
879 $newpdffilename = $upload_dir . $ref_pdf . "_signed-" . $date . ".pdf";
880 $sourcefile = $upload_dir . $ref_pdf . ".pdf";
881
882 if (dol_is_file($sourcefile)) {
883 $parameters = array('sourcefile' => $sourcefile, 'newpdffilename' => $newpdffilename);
884 $reshook = $hookmanager->executeHooks('AddSignature', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
885 if ($reshook < 0) {
886 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
887 }
888
889 if (empty($reshook)) {
890 // We build the new PDF
891 $pdf = pdf_getInstance();
892 if (class_exists('TCPDF')) {
893 $pdf->setPrintHeader(false);
894 $pdf->setPrintFooter(false);
895 }
896 $pdf->SetFont(pdf_getPDFFont($langs));
897
898 if (getDolGlobalString('MAIN_DISABLE_PDF_COMPRESSION')) {
899 $pdf->SetCompression(false);
900 }
901
902 //$pdf->Open();
903 $pagecount = $pdf->setSourceFile($sourcefile); // original PDF
904
905 $param = array();
906 $param['online_sign_name'] = $online_sign_name;
907 $param['pathtoimage'] = $upload_dir . $filename;
908
909 $s = array(); // Array with size of each page. Example array(w'=>210, 'h'=>297);
910 for ($i = 1; $i < ($pagecount + 1); $i++) {
911 try {
912 $tppl = $pdf->importPage($i);
913 $s = $pdf->getTemplatesize($tppl);
914 $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
915 $pdf->useTemplate($tppl);
916
917 if (getDolGlobalString("SHIPMENT_SIGNATURE_ON_ALL_PAGES")) {
918 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
919 // TODO Get position of box from PDF template
920
921 $param['xforimgstart'] = 111;
922 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 60);
923 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16);
924
925 dolPrintSignatureImage($pdf, $langs, $param);
926 }
927 } catch (Exception $e) {
928 dol_syslog("Error when manipulating some PDF by onlineSign: " . $e->getMessage(), LOG_ERR);
929 $response = $e->getMessage();
930 $error++;
931 }
932 }
933
934 if (!getDolGlobalString("SHIPMENT_SIGNATURE_ON_ALL_PAGES")) {
935 // A signature image file is 720 x 180 (ratio 1/4) but we use only the size into PDF
936 // TODO Get position of box from PDF template
937
938 $param['xforimgstart'] = 111;
939 $param['yforimgstart'] = (empty($s['h']) ? 250 : $s['h'] - 60);
940 $param['wforimg'] = $s['w'] - ($param['xforimgstart'] + 16);
941
942 dolPrintSignatureImage($pdf, $langs, $param);
943 }
944
945 //$pdf->Close();
946 $pdf->Output($newpdffilename, "F");
947
948 // Index the new file and update the last_main_doc property of object.
949 $object->indexFile($newpdffilename, 1);
950 }
951 }
952 if (!$error) {
953 $response = "success";
954 }
955 } elseif (preg_match('/\.odt/i', $last_main_doc_file)) {
956 // Adding signature on .ODT not yet supported
957 // TODO
958 } else {
959 // Document format not supported to insert online signature.
960 // We should just create an image file with the signature.
961 }
962 }
963 $user = new User($db);
964 $object->setSignedStatus($user, Expedition::$SIGNED_STATUSES['STATUS_SIGNED_RECEIVER_ONLINE'], 0, 'SHIPPING_MODIFY');
965 }
966 } else {
967 $error++;
968 $response = 'error signature_not_found';
969 }
970}
971
972if ($error) {
973 http_response_code(501);
974}
975
976echo $response;
977
978
987function dolPrintSignatureImage(TCPDF $pdf, $langs, $params)
988{
989 $default_font_size = pdf_getPDFFontSize($langs); // Must be after pdf_getInstance
990 $default_font = pdf_getPDFFont($langs); // Must be
991 $xforimgstart = $params['xforimgstart'];
992 $yforimgstart = $params['yforimgstart'];
993 $wforimg = $params['wforimg'];
994
995 $pdf->SetXY($xforimgstart, $yforimgstart + round($wforimg / 4) - 4);
996 $pdf->SetFont($default_font, '', $default_font_size - 1);
997 $pdf->SetTextColor(80, 80, 80);
998 $pdf->MultiCell($wforimg, 4, $langs->transnoentities("Signature") . ': ' . dol_print_date(dol_now(), "day", false, $langs, true). ' - '.$params['online_sign_name'], 0, 'L');
999 //$pdf->SetXY($xforimgstart, $yforimgstart + round($wforimg / 4));
1000 //$pdf->MultiCell($wforimg, 4, $langs->trans("Lastname") . ': ' . $online_sign_name, 0, 'L');
1001
1002 $pdf->Image($params['pathtoimage'], $xforimgstart, $yforimgstart, $wforimg, round($wforimg / 4));
1003
1004 return;
1005}
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
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_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.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
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)
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)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
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_getPDFFontSize($outputlangs)
Return font size to use for PDF generation.
Definition pdf.lib.php:289
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:2936
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition pdf.lib.php:268
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_verifyHash($chain, $hash, $type='0')
Compute a hash and compare it to the given one For backward compatibility reasons,...