dolibarr 18.0.6
functions2.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2008-2011 Laurent Destailleur <eldy@users.sourceforge.net>
3 * Copyright (C) 2008-2012 Regis Houssin <regis.houssin@inodbox.com>
4 * Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr>
5 * Copyright (C) 2014-2016 Marcos García <marcosgdf@gmail.com>
6 * Copyright (C) 2015 Ferran Marcet <fmarcet@2byte.es>
7 * Copyright (C) 2015-2016 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
8 * Copyright (C) 2017 Juanjo Menent <jmenent@2byte.es>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 * or see https://www.gnu.org/
23 */
24
31// Enable this line to trace path when function is called.
32//print xdebug_print_function_stack('Functions2.lib was called');exit;
33
40function jsUnEscape($source)
41{
42 $decodedStr = "";
43 $pos = 0;
44 $len = strlen($source);
45 while ($pos < $len) {
46 $charAt = substr($source, $pos, 1);
47 if ($charAt == '%') {
48 $pos++;
49 $charAt = substr($source, $pos, 1);
50 if ($charAt == 'u') {
51 // we got a unicode character
52 $pos++;
53 $unicodeHexVal = substr($source, $pos, 4);
54 $unicode = hexdec($unicodeHexVal);
55 $entity = "&#".$unicode.';';
56 $decodedStr .= utf8_encode($entity);
57 $pos += 4;
58 } else {
59 // we have an escaped ascii character
60 $hexVal = substr($source, $pos, 2);
61 $decodedStr .= chr(hexdec($hexVal));
62 $pos += 2;
63 }
64 } else {
65 $decodedStr .= $charAt;
66 $pos++;
67 }
68 }
69 return dol_html_entity_decode($decodedStr, ENT_COMPAT | ENT_HTML5);
70}
71
72
80function dolGetModulesDirs($subdir = '')
81{
82 global $conf;
83
84 $modulesdir = array();
85
86 foreach ($conf->file->dol_document_root as $type => $dirroot) {
87 // Default core/modules dir
88 if ($type === 'main') {
89 $modulesdir[$dirroot.'/core/modules'.$subdir.'/'] = $dirroot.'/core/modules'.$subdir.'/';
90 }
91
92 // Scan dir from external modules
93 $handle = @opendir($dirroot);
94 if (is_resource($handle)) {
95 while (($file = readdir($handle)) !== false) {
96 if (preg_match('/disabled/', $file)) {
97 continue; // We discard module if it contains disabled into name.
98 }
99
100 if (is_dir($dirroot.'/'.$file) && substr($file, 0, 1) <> '.' && substr($file, 0, 3) <> 'CVS' && $file != 'includes') {
101 if (is_dir($dirroot.'/'.$file.'/core/modules'.$subdir.'/')) {
102 $modulesdir[$dirroot.'/'.$file.'/core/modules'.$subdir.'/'] = $dirroot.'/'.$file.'/core/modules'.$subdir.'/';
103 }
104 }
105 }
106 closedir($handle);
107 }
108 }
109 return $modulesdir;
110}
111
112
119function dol_getDefaultFormat(Translate $outputlangs = null)
120{
121 global $langs;
122
123 $selected = 'EUA4';
124 if (!$outputlangs) {
125 $outputlangs = $langs;
126 }
127
128 if ($outputlangs->defaultlang == 'ca_CA') {
129 $selected = 'CAP4'; // Canada
130 }
131 if ($outputlangs->defaultlang == 'en_US') {
132 $selected = 'USLetter'; // US
133 }
134 return $selected;
135}
136
145function dol_print_file($langs, $filename, $searchalt = 0)
146{
147 global $conf;
148
149 // Test if file is in lang directory
150 foreach ($langs->dir as $searchdir) {
151 $formfile = ($searchdir."/langs/".$langs->defaultlang."/".$filename);
152 dol_syslog('functions2::dol_print_file search file '.$formfile, LOG_DEBUG);
153 if (is_readable($formfile)) {
154 $content = file_get_contents($formfile);
155 $isutf8 = utf8_check($content);
156 if (!$isutf8 && $conf->file->character_set_client == 'UTF-8') {
157 print utf8_encode($content);
158 } elseif ($isutf8 && $conf->file->character_set_client == 'ISO-8859-1') {
159 print utf8_decode($content);
160 } else {
161 print $content;
162 }
163 return true;
164 } else {
165 dol_syslog('functions2::dol_print_file not found', LOG_DEBUG);
166 }
167
168 if ($searchalt) {
169 // Test si fichier dans repertoire de la langue alternative
170 if ($langs->defaultlang != "en_US") {
171 $formfilealt = $searchdir."/langs/en_US/".$filename;
172 } else {
173 $formfilealt = $searchdir."/langs/fr_FR/".$filename;
174 }
175 dol_syslog('functions2::dol_print_file search alt file '.$formfilealt, LOG_DEBUG);
176 //print 'getcwd='.getcwd().' htmlfilealt='.$formfilealt.' X '.file_exists(getcwd().'/'.$formfilealt);
177 if (is_readable($formfilealt)) {
178 $content = file_get_contents($formfilealt);
179 $isutf8 = utf8_check($content);
180 if (!$isutf8 && $conf->file->character_set_client == 'UTF-8') {
181 print mb_convert_encoding($content, 'UTF-8', 'ISO-8859-1');
182 } elseif ($isutf8 && $conf->file->character_set_client == 'ISO-8859-1') {
183 print mb_convert_encoding($content, 'ISO-8859-1', 'UTF-8');
184 } else {
185 print $content;
186 }
187 return true;
188 } else {
189 dol_syslog('functions2::dol_print_file not found', LOG_DEBUG);
190 }
191 }
192 }
193
194 return false;
195}
196
205function dol_print_object_info($object, $usetable = 0)
206{
207 global $langs, $db;
208
209 // Load translation files required by the page
210 $langs->loadLangs(array('other', 'admin'));
211
212 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
213
214 $deltadateforserver = getServerTimeZoneInt('now');
215 $deltadateforclient = ((int) $_SESSION['dol_tz'] + (int) $_SESSION['dol_dst']);
216 //$deltadateforcompany=((int) $_SESSION['dol_tz'] + (int) $_SESSION['dol_dst']);
217 $deltadateforuser = round($deltadateforclient - $deltadateforserver);
218 //print "x".$deltadateforserver." - ".$deltadateforclient." - ".$deltadateforuser;
219
220 if ($usetable) {
221 print '<table class="border tableforfield centpercent">';
222 }
223
224 // Import key
225 if (!empty($object->import_key)) {
226 if ($usetable) {
227 print '<tr><td class="titlefield">';
228 }
229 print $langs->trans("ImportedWithSet");
230 if ($usetable) {
231 print '</td><td>';
232 } else {
233 print ': ';
234 }
235 print $object->import_key;
236 if ($usetable) {
237 print '</td></tr>';
238 } else {
239 print '<br>';
240 }
241 }
242
243 // User creation (old method using already loaded object and not id is kept for backward compatibility)
244 if (!empty($object->user_creation) || !empty($object->user_creation_id)) {
245 if ($usetable) {
246 print '<tr><td class="titlefield">';
247 }
248 print $langs->trans("CreatedBy");
249 if ($usetable) {
250 print '</td><td>';
251 } else {
252 print ': ';
253 }
254 if (is_object($object->user_creation)) {
255 if ($object->user_creation->id) {
256 print $object->user_creation->getNomUrl(-1, '', 0, 0, 0);
257 } else {
258 print $langs->trans("Unknown");
259 }
260 } else {
261 $userstatic = new User($db);
262 $userstatic->fetch($object->user_creation_id ? $object->user_creation_id : $object->user_creation);
263 if ($userstatic->id) {
264 print $userstatic->getNomUrl(-1, '', 0, 0, 0);
265 } else {
266 print $langs->trans("Unknown");
267 }
268 }
269 if ($usetable) {
270 print '</td></tr>';
271 } else {
272 print '<br>';
273 }
274 }
275
276 // Date creation
277 if (!empty($object->date_creation)) {
278 if ($usetable) {
279 print '<tr><td class="titlefield">';
280 }
281 print $langs->trans("DateCreation");
282 if ($usetable) {
283 print '</td><td>';
284 } else {
285 print ': ';
286 }
287 print dol_print_date($object->date_creation, 'dayhour', 'tzserver');
288 if ($deltadateforuser) {
289 print ' <span class="opacitymedium">'.$langs->trans("CurrentHour").'</span> &nbsp; / &nbsp; '.dol_print_date($object->date_creation, "dayhour", "tzuserrel").' &nbsp;<span class="opacitymedium">'.$langs->trans("ClientHour").'</span>';
290 }
291 if ($usetable) {
292 print '</td></tr>';
293 } else {
294 print '<br>';
295 }
296 }
297
298 // User change (old method using already loaded object and not id is kept for backward compatibility)
299 if (!empty($object->user_modification) || !empty($object->user_modification_id)) {
300 if ($usetable) {
301 print '<tr><td class="titlefield">';
302 }
303 print $langs->trans("ModifiedBy");
304 if ($usetable) {
305 print '</td><td>';
306 } else {
307 print ': ';
308 }
309 if (is_object($object->user_modification)) {
310 if ($object->user_modification->id) {
311 print $object->user_modification->getNomUrl(-1, '', 0, 0, 0);
312 } else {
313 print $langs->trans("Unknown");
314 }
315 } else {
316 $userstatic = new User($db);
317 $userstatic->fetch($object->user_modification_id ? $object->user_modification_id : $object->user_modification);
318 if ($userstatic->id) {
319 print $userstatic->getNomUrl(-1, '', 0, 0, 0);
320 } else {
321 print $langs->trans("Unknown");
322 }
323 }
324 if ($usetable) {
325 print '</td></tr>';
326 } else {
327 print '<br>';
328 }
329 }
330
331 // Date change
332 if (!empty($object->date_modification)) {
333 if ($usetable) {
334 print '<tr><td class="titlefield">';
335 }
336 print $langs->trans("DateLastModification");
337 if ($usetable) {
338 print '</td><td>';
339 } else {
340 print ': ';
341 }
342 print dol_print_date($object->date_modification, 'dayhour', 'tzserver');
343 if ($deltadateforuser) {
344 print ' <span class="opacitymedium">'.$langs->trans("CurrentHour").'</span> &nbsp; / &nbsp; '.dol_print_date($object->date_modification, "dayhour", "tzuserrel").' &nbsp;<span class="opacitymedium">'.$langs->trans("ClientHour").'</span>';
345 }
346 if ($usetable) {
347 print '</td></tr>';
348 } else {
349 print '<br>';
350 }
351 }
352
353 // User validation (old method using already loaded object and not id is kept for backward compatibility)
354 if (!empty($object->user_validation) || !empty($object->user_validation_id)) {
355 if ($usetable) {
356 print '<tr><td class="titlefield">';
357 }
358 print $langs->trans("ValidatedBy");
359 if ($usetable) {
360 print '</td><td>';
361 } else {
362 print ': ';
363 }
364 if (is_object($object->user_validation)) {
365 if ($object->user_validation->id) {
366 print $object->user_validation->getNomUrl(-1, '', 0, 0, 0);
367 } else {
368 print $langs->trans("Unknown");
369 }
370 } else {
371 $userstatic = new User($db);
372 $userstatic->fetch($object->user_validation_id ? $object->user_validation_id : $object->user_validation);
373 if ($userstatic->id) {
374 print $userstatic->getNomUrl(-1, '', 0, 0, 0);
375 } else {
376 print $langs->trans("Unknown");
377 }
378 }
379 if ($usetable) {
380 print '</td></tr>';
381 } else {
382 print '<br>';
383 }
384 }
385
386 // Date validation
387 if (!empty($object->date_validation)) {
388 if ($usetable) {
389 print '<tr><td class="titlefield">';
390 }
391 print $langs->trans("DateValidation");
392 if ($usetable) {
393 print '</td><td>';
394 } else {
395 print ': ';
396 }
397 print dol_print_date($object->date_validation, 'dayhour', 'tzserver');
398 if ($deltadateforuser) {
399 print ' <span class="opacitymedium">'.$langs->trans("CurrentHour").'</span> &nbsp; / &nbsp; '.dol_print_date($object->date_validation, "dayhour", 'tzuserrel').' &nbsp;<span class="opacitymedium">'.$langs->trans("ClientHour").'</span>';
400 }
401 if ($usetable) {
402 print '</td></tr>';
403 } else {
404 print '<br>';
405 }
406 }
407
408 // User approve (old method using already loaded object and not id is kept for backward compatibility)
409 if (!empty($object->user_approve) || !empty($object->user_approve_id)) {
410 if ($usetable) {
411 print '<tr><td class="titlefield">';
412 }
413 print $langs->trans("ApprovedBy");
414 if ($usetable) {
415 print '</td><td>';
416 } else {
417 print ': ';
418 }
419 if (!empty($object->user_approve) && is_object($object->user_approve)) {
420 if ($object->user_approve->id) {
421 print $object->user_approve->getNomUrl(-1, '', 0, 0, 0);
422 } else {
423 print $langs->trans("Unknown");
424 }
425 } else {
426 $userstatic = new User($db);
427 $userstatic->fetch($object->user_approve_id ? $object->user_approve_id : $object->user_approve);
428 if ($userstatic->id) {
429 print $userstatic->getNomUrl(-1, '', 0, 0, 0);
430 } else {
431 print $langs->trans("Unknown");
432 }
433 }
434 if ($usetable) {
435 print '</td></tr>';
436 } else {
437 print '<br>';
438 }
439 }
440
441 // Date approve
442 if (!empty($object->date_approve) || !empty($object->date_approval)) {
443 if ($usetable) {
444 print '<tr><td class="titlefield">';
445 }
446 print $langs->trans("DateApprove");
447 if ($usetable) {
448 print '</td><td>';
449 } else {
450 print ': ';
451 }
452 print dol_print_date($object->date_approve ? $object->date_approve : $object->date_approval, 'dayhour', 'tzserver');
453 if ($deltadateforuser) {
454 print ' <span class="opacitymedium">'.$langs->trans("CurrentHour").'</span> &nbsp; / &nbsp; '.dol_print_date($object->date_approve, "dayhour", 'tzuserrel').' &nbsp;<span class="opacitymedium">'.$langs->trans("ClientHour").'</span>';
455 }
456 if ($usetable) {
457 print '</td></tr>';
458 } else {
459 print '<br>';
460 }
461 }
462
463 // User approve
464 if (!empty($object->user_approve_id2)) {
465 if ($usetable) {
466 print '<tr><td class="titlefield">';
467 }
468 print $langs->trans("ApprovedBy");
469 if ($usetable) {
470 print '</td><td>';
471 } else {
472 print ': ';
473 }
474 $userstatic = new User($db);
475 $userstatic->fetch($object->user_approve_id2);
476 if ($userstatic->id) {
477 print $userstatic->getNomUrl(-1, '', 0, 0, 0);
478 } else {
479 print $langs->trans("Unknown");
480 }
481 if ($usetable) {
482 print '</td></tr>';
483 } else {
484 print '<br>';
485 }
486 }
487
488 // Date approve
489 if (!empty($object->date_approve2)) {
490 if ($usetable) {
491 print '<tr><td class="titlefield">';
492 }
493 print $langs->trans("DateApprove2");
494 if ($usetable) {
495 print '</td><td>';
496 } else {
497 print ': ';
498 }
499 print dol_print_date($object->date_approve2, 'dayhour', 'tzserver');
500 if ($deltadateforuser) {
501 print ' <span class="opacitymedium">'.$langs->trans("CurrentHour").'</span> &nbsp; / &nbsp; '.dol_print_date($object->date_approve2, "dayhour", 'tzuserrel').' &nbsp;<span class="opacitymedium">'.$langs->trans("ClientHour").'</span>';
502 }
503 if ($usetable) {
504 print '</td></tr>';
505 } else {
506 print '<br>';
507 }
508 }
509
510 // User signature
511 if (!empty($object->user_signature) || !empty($object->user_signature_id)) {
512 if ($usetable) {
513 print '<tr><td class="titlefield">';
514 }
515 print $langs->trans('SignedBy');
516 if ($usetable) {
517 print '</td><td>';
518 } else {
519 print ': ';
520 }
521 if (is_object($object->user_signature)) {
522 if ($object->user_signature->id) {
523 print $object->user_signature->getNomUrl(-1, '', 0, 0, 0);
524 } else {
525 print $langs->trans('Unknown');
526 }
527 } else {
528 $userstatic = new User($db);
529 $userstatic->fetch($object->user_signature_id ? $object->user_signature_id : $object->user_signature);
530 if ($userstatic->id) {
531 print $userstatic->getNomUrl(-1, '', 0, 0, 0);
532 } else {
533 print $langs->trans('Unknown');
534 }
535 }
536 if ($usetable) {
537 print '</td></tr>';
538 } else {
539 print '<br>';
540 }
541 }
542
543 // Date signature
544 if (!empty($object->date_signature)) {
545 if ($usetable) {
546 print '<tr><td class="titlefield">';
547 }
548 print $langs->trans('DateSigning');
549 if ($usetable) {
550 print '</td><td>';
551 } else {
552 print ': ';
553 }
554 print dol_print_date($object->date_signature, 'dayhour');
555 if ($deltadateforuser) {
556 print ' <span class="opacitymedium">'.$langs->trans('CurrentHour').'</span> &nbsp; / &nbsp; '.dol_print_date($object->date_signature, 'dayhour', 'tzuserrel').' &nbsp;<span class="opacitymedium">'.$langs->trans('ClientHour').'</span>';
557 }
558 if ($usetable) {
559 print '</td></tr>';
560 } else {
561 print '<br>';
562 }
563 }
564
565 // User close
566 if (!empty($object->user_cloture) || !empty($object->user_closing) || !empty($object->user_closing_id)) {
567 if (isset($object->user_cloture) && !empty($object->user_cloture)) {
568 $object->user_closing = $object->user_cloture;
569 }
570 if ($usetable) {
571 print '<tr><td class="titlefield">';
572 }
573 print $langs->trans("ClosedBy");
574 if ($usetable) {
575 print '</td><td>';
576 } else {
577 print ': ';
578 }
579 if (is_object($object->user_closing)) {
580 if ($object->user_closing->id) {
581 print $object->user_closing->getNomUrl(-1, '', 0, 0, 0);
582 } else {
583 print $langs->trans("Unknown");
584 }
585 } else {
586 $userstatic = new User($db);
587 $userstatic->fetch($object->user_closing_id ? $object->user_closing_id : $object->user_closing);
588 if ($userstatic->id) {
589 print $userstatic->getNomUrl(-1, '', 0, 0, 0);
590 } else {
591 print $langs->trans("Unknown");
592 }
593 }
594 if ($usetable) {
595 print '</td></tr>';
596 } else {
597 print '<br>';
598 }
599 }
600
601 // Date close
602 if (!empty($object->date_cloture) || !empty($object->date_closing)) {
603 if (isset($object->date_cloture) && !empty($object->date_cloture)) {
604 $object->date_closing = $object->date_cloture;
605 }
606 if ($usetable) {
607 print '<tr><td class="titlefield">';
608 }
609 print $langs->trans("DateClosing");
610 if ($usetable) {
611 print '</td><td>';
612 } else {
613 print ': ';
614 }
615 print dol_print_date($object->date_closing, 'dayhour', 'tzserver');
616 if ($deltadateforuser) {
617 print ' <span class="opacitymedium">'.$langs->trans("CurrentHour").'</span> &nbsp; / &nbsp; '.dol_print_date($object->date_closing, "dayhour", 'tzuserrel').' &nbsp;<span class="opacitymedium">'.$langs->trans("ClientHour").'</span>';
618 }
619 if ($usetable) {
620 print '</td></tr>';
621 } else {
622 print '<br>';
623 }
624 }
625
626 // User conciliate
627 if (!empty($object->user_rappro) || !empty($object->user_rappro_id)) {
628 if ($usetable) {
629 print '<tr><td class="titlefield">';
630 }
631 print $langs->trans("ReconciledBy");
632 if ($usetable) {
633 print '</td><td>';
634 } else {
635 print ': ';
636 }
637 if (is_object($object->user_rappro)) {
638 if ($object->user_rappro->id) {
639 print $object->user_rappro->getNomUrl(-1, '', 0, 0, 0);
640 } else {
641 print $langs->trans("Unknown");
642 }
643 } else {
644 $userstatic = new User($db);
645 $userstatic->fetch($object->user_rappro_id ? $object->user_rappro_id : $object->user_rappro);
646 if ($userstatic->id) {
647 print $userstatic->getNomUrl(1, '', 0, 0, 0);
648 } else {
649 print $langs->trans("Unknown");
650 }
651 }
652 if ($usetable) {
653 print '</td></tr>';
654 } else {
655 print '<br>';
656 }
657 }
658
659 // Date conciliate
660 if (!empty($object->date_rappro)) {
661 if ($usetable) {
662 print '<tr><td class="titlefield">';
663 }
664 print $langs->trans("DateConciliating");
665 if ($usetable) {
666 print '</td><td>';
667 } else {
668 print ': ';
669 }
670 print dol_print_date($object->date_rappro, 'dayhour', 'tzserver');
671 if ($deltadateforuser) {
672 print ' <span class="opacitymedium">'.$langs->trans("CurrentHour").'</span> &nbsp; / &nbsp; '.dol_print_date($object->date_rappro, "dayhour", 'tzuserrel').' &nbsp;<span class="opacitymedium">'.$langs->trans("ClientHour").'</span>';
673 }
674 if ($usetable) {
675 print '</td></tr>';
676 } else {
677 print '<br>';
678 }
679 }
680
681 // Date send
682 if (!empty($object->date_envoi)) {
683 if ($usetable) {
684 print '<tr><td class="titlefield">';
685 }
686 print $langs->trans("DateLastSend");
687 if ($usetable) {
688 print '</td><td>';
689 } else {
690 print ': ';
691 }
692 print dol_print_date($object->date_envoi, 'dayhour', 'tzserver');
693 if ($deltadateforuser) {
694 print ' <span class="opacitymedium">'.$langs->trans("CurrentHour").'</span> &nbsp; / &nbsp; '.dol_print_date($object->date_envoi, "dayhour", 'tzuserrel').' &nbsp;<span class="opacitymedium">'.$langs->trans("ClientHour").'</span>';
695 }
696 if ($usetable) {
697 print '</td></tr>';
698 } else {
699 print '<br>';
700 }
701 }
702
703 if ($usetable) {
704 print '</table>';
705 }
706}
707
708
717function dolAddEmailTrackId($email, $trackingid)
718{
719 $tmp = explode('@', $email);
720 return $tmp[0].'+'.$trackingid.'@'.(isset($tmp[1]) ? $tmp[1] : '');
721}
722
729function isValidMailDomain($mail)
730{
731 list($user, $domain) = explode("@", $mail, 2);
732 return ($domain ? isValidMXRecord($domain) : 0);
733}
734
748function isValidUrl($url, $http = 0, $pass = 0, $port = 0, $path = 0, $query = 0, $anchor = 0)
749{
750 $ValidUrl = 0;
751 $urlregex = '';
752
753 // SCHEME
754 if ($http) {
755 $urlregex .= "^(http:\/\/|https:\/\/)";
756 }
757
758 // USER AND PASS
759 if ($pass) {
760 $urlregex .= "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)";
761 }
762
763 // HOSTNAME OR IP
764 //$urlregex .= "[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)*"; // x allowed (ex. http://localhost, http://routerlogin)
765 //$urlregex .= "[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)+"; // x.x
766 $urlregex .= "([a-z0-9+\$_\\\:-])+(\.[a-z0-9+\$_-][a-z0-9+\$_-]+)*"; // x ou x.xx (2 x ou plus)
767 //use only one of the above
768
769 // PORT
770 if ($port) {
771 $urlregex .= "(\:[0-9]{2,5})";
772 }
773 // PATH
774 if ($path) {
775 $urlregex .= "(\/([a-z0-9+\$_-]\.?)+)*\/";
776 }
777 // GET Query
778 if ($query) {
779 $urlregex .= "(\?[a-z+&\$_.-][a-z0-9;:@\/&%=+\$_.-]*)";
780 }
781 // ANCHOR
782 if ($anchor) {
783 $urlregex .= "(#[a-z_.-][a-z0-9+\$_.-]*)$";
784 }
785
786 // check
787 if (preg_match('/'.$urlregex.'/i', $url)) {
788 $ValidUrl = 1;
789 }
790 //print $urlregex.' - '.$url.' - '.$ValidUrl;
791
792 return $ValidUrl;
793}
794
801function isValidVATID($company)
802{
803 if ($company->isInEEC()) { // Syntax check rules for EEC countries
804 /* Disabled because some companies can have an address in Irland and a vat number in France.
805 $vatprefix = $company->country_code;
806 if ($vatprefix == 'GR') $vatprefix = '(EL|GR)';
807 elseif ($vatprefix == 'MC') $vatprefix = 'FR'; // Monaco is using french VAT numbers
808 else $vatprefix = preg_quote($vatprefix, '/');*/
809 $vatprefix = '[a-zA-Z][a-zA-Z]';
810 if (!preg_match('/^'.$vatprefix.'[a-zA-Z0-9\-\.]{5,14}$/i', str_replace(' ', '', $company->tva_intra))) {
811 return 0;
812 }
813 }
814
815 return 1;
816}
817
825function clean_url($url, $http = 1)
826{
827 // Fixed by Matelli (see http://matelli.fr/showcases/patchs-dolibarr/fix-cleaning-url.html)
828 // To include the minus sign in a char class, we must not escape it but put it at the end of the class
829 // Also, there's no need of escape a dot sign in a class
830 $regs = array();
831 if (preg_match('/^(https?:[\\/]+)?([0-9A-Z.-]+\.[A-Z]{2,4})(:[0-9]+)?/i', $url, $regs)) {
832 $proto = $regs[1];
833 $domain = $regs[2];
834 $port = isset($regs[3]) ? $regs[3] : '';
835 //print $url." -> ".$proto." - ".$domain." - ".$port;
836 //$url = dol_string_nospecial(trim($url));
837 $url = trim($url);
838
839 // Si http: defini on supprime le http (Si https on ne supprime pas)
840 $newproto = $proto;
841 if ($http == 0) {
842 if (preg_match('/^http:[\\/]+/i', $url)) {
843 $url = preg_replace('/^http:[\\/]+/i', '', $url);
844 $newproto = '';
845 }
846 }
847
848 // On passe le nom de domaine en minuscule
849 $CleanUrl = preg_replace('/^'.preg_quote($proto.$domain, '/').'/i', $newproto.strtolower($domain), $url);
850
851 return $CleanUrl;
852 } else {
853 return $url;
854 }
855}
856
857
858
870function dolObfuscateEmail($mail, $replace = "*", $nbreplace = 8, $nbdisplaymail = 4, $nbdisplaydomain = 3, $displaytld = true)
871{
872 if (!isValidEmail($mail)) {
873 return '';
874 }
875 $tab = explode('@', $mail);
876 $tab2 = explode('.', $tab[1]);
877 $string_replace = '';
878 $mail_name = $tab[0];
879 $mail_domaine = $tab2[0];
880 $mail_tld = '';
881
882 $nbofelem = count($tab2);
883 for ($i = 1; $i < $nbofelem && $displaytld; $i++) {
884 $mail_tld .= '.'.$tab2[$i];
885 }
886
887 for ($i = 0; $i < $nbreplace; $i++) {
888 $string_replace .= $replace;
889 }
890
891 if (strlen($mail_name) > $nbdisplaymail) {
892 $mail_name = substr($mail_name, 0, $nbdisplaymail);
893 }
894
895 if (strlen($mail_domaine) > $nbdisplaydomain) {
896 $mail_domaine = substr($mail_domaine, strlen($mail_domaine) - $nbdisplaydomain);
897 }
898
899 return $mail_name.$string_replace.$mail_domaine.$mail_tld;
900}
901
902
912function array2tr($data, $troptions = '', $tdoptions = '')
913{
914 $text = '<tr '.$troptions.'>';
915 foreach ($data as $key => $item) {
916 $text .= '<td '.$tdoptions.'>'.$item.'</td>';
917 }
918 $text .= '</tr>';
919 return $text;
920}
921
932function array2table($data, $tableMarkup = 1, $tableoptions = '', $troptions = '', $tdoptions = '')
933{
934 $text = '';
935 if ($tableMarkup) {
936 $text = '<table '.$tableoptions.'>';
937 }
938 foreach ($data as $key => $item) {
939 if (is_array($item)) {
940 $text .= array2tr($item, $troptions, $tdoptions);
941 } else {
942 $text .= '<tr '.$troptions.'>';
943 $text .= '<td '.$tdoptions.'>'.$key.'</td>';
944 $text .= '<td '.$tdoptions.'>'.$item.'</td>';
945 $text .= '</tr>';
946 }
947 }
948 if ($tableMarkup) {
949 $text .= '</table>';
950 }
951 return $text;
952}
953
970function get_next_value($db, $mask, $table, $field, $where = '', $objsoc = '', $date = '', $mode = 'next', $bentityon = true, $objuser = null, $forceentity = null)
971{
972 global $conf, $user;
973
974 if (!is_object($objsoc)) {
975 $valueforccc = $objsoc;
976 } elseif ($table == "commande_fournisseur" || $table == "facture_fourn" || $table == "paiementfourn") {
977 $valueforccc = dol_string_unaccent($objsoc->code_fournisseur);
978 } else {
979 $valueforccc = dol_string_unaccent($objsoc->code_client);
980 }
981
982 $sharetable = $table;
983 if ($table == 'facture' || $table == 'invoice') {
984 $sharetable = 'invoicenumber'; // for getEntity function
985 }
986
987 // Clean parameters
988 if ($date == '') {
989 $date = dol_now(); // We use local year and month of PHP server to search numbers
990 }
991 // but we should use local year and month of user
992
993 // For debugging
994 //dol_syslog("mask=".$mask, LOG_DEBUG);
995 //include_once(DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php');
996 //$mask='FA{yy}{mm}-{0000@99}';
997 //$date=dol_mktime(12, 0, 0, 1, 1, 1900);
998 //$date=dol_stringtotime('20130101');
999
1000 $hasglobalcounter = false;
1001 $reg = array();
1002 // Extract value for mask counter, mask raz and mask offset
1003 if (preg_match('/\{(0+)([@\+][0-9\-\+\=]+)?([@\+][0-9\-\+\=]+)?\}/i', $mask, $reg)) {
1004 $masktri = $reg[1].(!empty($reg[2]) ? $reg[2] : '').(!empty($reg[3]) ? $reg[3] : '');
1005 $maskcounter = $reg[1];
1006 $hasglobalcounter = true;
1007 } else {
1008 // setting some defaults so the rest of the code won't fail if there is a third party counter
1009 $masktri = '00000';
1010 $maskcounter = '00000';
1011 }
1012
1013 $maskraz = -1;
1014 $maskoffset = 0;
1015 $resetEveryMonth = false;
1016 if (dol_strlen($maskcounter) < 3 && empty($conf->global->MAIN_COUNTER_WITH_LESS_3_DIGITS)) {
1017 return 'ErrorCounterMustHaveMoreThan3Digits';
1018 }
1019
1020 // Extract value for third party mask counter
1021 $regClientRef = array();
1022 if (preg_match('/\{(c+)(0*)\}/i', $mask, $regClientRef)) {
1023 $maskrefclient = $regClientRef[1].$regClientRef[2];
1024 $maskrefclient_maskclientcode = $regClientRef[1];
1025 $maskrefclient_maskcounter = $regClientRef[2];
1026 $maskrefclient_maskoffset = 0; //default value of maskrefclient_counter offset
1027 $maskrefclient_clientcode = substr($valueforccc, 0, dol_strlen($maskrefclient_maskclientcode)); //get n first characters of client code where n is length in mask
1028 $maskrefclient_clientcode = str_pad($maskrefclient_clientcode, dol_strlen($maskrefclient_maskclientcode), "#", STR_PAD_RIGHT); //padding maskrefclient_clientcode for having exactly n characters in maskrefclient_clientcode
1029 $maskrefclient_clientcode = dol_string_nospecial($maskrefclient_clientcode); //sanitize maskrefclient_clientcode for sql insert and sql select like
1030 if (dol_strlen($maskrefclient_maskcounter) > 0 && dol_strlen($maskrefclient_maskcounter) < 3) {
1031 return 'ErrorCounterMustHaveMoreThan3Digits';
1032 }
1033 } else {
1034 $maskrefclient = '';
1035 }
1036
1037 // fail if there is neither a global nor a third party counter
1038 if (!$hasglobalcounter && ($maskrefclient_maskcounter == '')) {
1039 return 'ErrorBadMask';
1040 }
1041
1042 // Extract value for third party type
1043 $regType = array();
1044 if (preg_match('/\{(t+)\}/i', $mask, $regType)) {
1045 $masktype = $regType[1];
1046 $masktype_value = dol_substr(preg_replace('/^TE_/', '', $objsoc->typent_code), 0, dol_strlen($regType[1])); // get n first characters of thirdparty typent_code (where n is length in mask)
1047 $masktype_value = str_pad($masktype_value, dol_strlen($regType[1]), "#", STR_PAD_RIGHT); // we fill on right with # to have same number of char than into mask
1048 } else {
1049 $masktype = '';
1050 $masktype_value = '';
1051 }
1052
1053 // Extract value for user
1054 $regType = array();
1055 if (preg_match('/\{(u+)\}/i', $mask, $regType)) {
1056 $lastname = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
1057 if (is_object($objuser)) {
1058 $lastname = $objuser->lastname;
1059 }
1060
1061 $maskuser = $regType[1];
1062 $maskuser_value = substr($lastname, 0, dol_strlen($regType[1])); // get n first characters of user firstname (where n is length in mask)
1063 $maskuser_value = str_pad($maskuser_value, dol_strlen($regType[1]), "#", STR_PAD_RIGHT); // we fill on right with # to have same number of char than into mask
1064 } else {
1065 $maskuser = '';
1066 $maskuser_value = '';
1067 }
1068
1069 // Personalized field {XXX-1} à {XXX-9}
1070 $maskperso = array();
1071 $maskpersonew = array();
1072 $tmpmask = $mask;
1073 $regKey = array();
1074 while (preg_match('/\{([A-Z]+)\-([1-9])\}/', $tmpmask, $regKey)) {
1075 $maskperso[$regKey[1]] = '{'.$regKey[1].'-'.$regKey[2].'}';
1076 $maskpersonew[$regKey[1]] = str_pad('', $regKey[2], '_', STR_PAD_RIGHT);
1077 $tmpmask = preg_replace('/\{'.$regKey[1].'\-'.$regKey[2].'\}/i', $maskpersonew[$regKey[1]], $tmpmask);
1078 }
1079
1080 if (strstr($mask, 'user_extra_')) {
1081 $start = "{user_extra_";
1082 $end = "\}";
1083 $extra = get_string_between($mask, "user_extra_", "}");
1084 if (!empty($user->array_options['options_'.$extra])) {
1085 $mask = preg_replace('#('.$start.')(.*?)('.$end.')#si', $user->array_options['options_'.$extra], $mask);
1086 }
1087 }
1088 $maskwithonlyymcode = $mask;
1089 $maskwithonlyymcode = preg_replace('/\{(0+)([@\+][0-9\-\+\=]+)?([@\+][0-9\-\+\=]+)?\}/i', $maskcounter, $maskwithonlyymcode);
1090 $maskwithonlyymcode = preg_replace('/\{dd\}/i', 'dd', $maskwithonlyymcode);
1091 $maskwithonlyymcode = preg_replace('/\{(c+)(0*)\}/i', $maskrefclient, $maskwithonlyymcode);
1092 $maskwithonlyymcode = preg_replace('/\{(t+)\}/i', $masktype_value, $maskwithonlyymcode);
1093 $maskwithonlyymcode = preg_replace('/\{(u+)\}/i', $maskuser_value, $maskwithonlyymcode);
1094 foreach ($maskperso as $key => $val) {
1095 $maskwithonlyymcode = preg_replace('/'.preg_quote($val, '/').'/i', $maskpersonew[$key], $maskwithonlyymcode);
1096 }
1097 $maskwithnocode = $maskwithonlyymcode;
1098 $maskwithnocode = preg_replace('/\{yyyy\}/i', 'yyyy', $maskwithnocode);
1099 $maskwithnocode = preg_replace('/\{yy\}/i', 'yy', $maskwithnocode);
1100 $maskwithnocode = preg_replace('/\{y\}/i', 'y', $maskwithnocode);
1101 $maskwithnocode = preg_replace('/\{mm\}/i', 'mm', $maskwithnocode);
1102 // Now maskwithnocode = 0000ddmmyyyyccc for example
1103 // and maskcounter = 0000 for example
1104 //print "maskwithonlyymcode=".$maskwithonlyymcode." maskwithnocode=".$maskwithnocode."\n<br>";
1105 //var_dump($reg);
1106
1107 // If an offset is asked
1108 if (!empty($reg[2]) && preg_match('/^\+/', $reg[2])) {
1109 $maskoffset = preg_replace('/^\+/', '', $reg[2]);
1110 }
1111 if (!empty($reg[3]) && preg_match('/^\+/', $reg[3])) {
1112 $maskoffset = preg_replace('/^\+/', '', $reg[3]);
1113 }
1114
1115 // Define $sqlwhere
1116 $sqlwhere = '';
1117 $yearoffset = 0; // Use year of current $date by default
1118 $yearoffsettype = false; // false: no reset, 0,-,=,+: reset at offset SOCIETE_FISCAL_MONTH_START, x=reset at offset x
1119
1120 // If a restore to zero after a month is asked we check if there is already a value for this year.
1121 if (!empty($reg[2]) && preg_match('/^@/', $reg[2])) {
1122 $yearoffsettype = preg_replace('/^@/', '', $reg[2]);
1123 }
1124 if (!empty($reg[3]) && preg_match('/^@/', $reg[3])) {
1125 $yearoffsettype = preg_replace('/^@/', '', $reg[3]);
1126 }
1127
1128 //print "yearoffset=".$yearoffset." yearoffsettype=".$yearoffsettype;
1129 if (is_numeric($yearoffsettype) && $yearoffsettype >= 1) {
1130 $maskraz = $yearoffsettype; // For backward compatibility
1131 } elseif ($yearoffsettype === '0' || (!empty($yearoffsettype) && !is_numeric($yearoffsettype) && $conf->global->SOCIETE_FISCAL_MONTH_START > 1)) {
1132 $maskraz = $conf->global->SOCIETE_FISCAL_MONTH_START;
1133 }
1134 //print "maskraz=".$maskraz; // -1=no reset
1135
1136 if ($maskraz > 0) { // A reset is required
1137 if ($maskraz == 99) {
1138 $maskraz = date('m', $date);
1139 $resetEveryMonth = true;
1140 }
1141 if ($maskraz > 12) {
1142 return 'ErrorBadMaskBadRazMonth';
1143 }
1144
1145 // Define posy, posm and reg
1146 if ($maskraz > 1) { // if reset is not first month, we need month and year into mask
1147 if (preg_match('/^(.*)\{(y+)\}\{(m+)\}/i', $maskwithonlyymcode, $reg)) {
1148 $posy = 2;
1149 $posm = 3;
1150 } elseif (preg_match('/^(.*)\{(m+)\}\{(y+)\}/i', $maskwithonlyymcode, $reg)) {
1151 $posy = 3;
1152 $posm = 2;
1153 } else {
1154 return 'ErrorCantUseRazInStartedYearIfNoYearMonthInMask';
1155 }
1156
1157 if (dol_strlen($reg[$posy]) < 2) {
1158 return 'ErrorCantUseRazWithYearOnOneDigit';
1159 }
1160 } else // if reset is for a specific month in year, we need year
1161 {
1162 if (preg_match('/^(.*)\{(m+)\}\{(y+)\}/i', $maskwithonlyymcode, $reg)) {
1163 $posy = 3;
1164 $posm = 2;
1165 } elseif (preg_match('/^(.*)\{(y+)\}\{(m+)\}/i', $maskwithonlyymcode, $reg)) {
1166 $posy = 2;
1167 $posm = 3;
1168 } elseif (preg_match('/^(.*)\{(y+)\}/i', $maskwithonlyymcode, $reg)) {
1169 $posy = 2;
1170 $posm = 0;
1171 } else {
1172 return 'ErrorCantUseRazIfNoYearInMask';
1173 }
1174 }
1175 // Define length
1176 $yearlen = $posy ?dol_strlen($reg[$posy]) : 0;
1177 $monthlen = $posm ?dol_strlen($reg[$posm]) : 0;
1178 // Define pos
1179 $yearpos = (dol_strlen($reg[1]) + 1);
1180 $monthpos = ($yearpos + $yearlen);
1181 if ($posy == 3 && $posm == 2) { // if month is before year
1182 $monthpos = (dol_strlen($reg[1]) + 1);
1183 $yearpos = ($monthpos + $monthlen);
1184 }
1185 //print "xxx ".$maskwithonlyymcode." maskraz=".$maskraz." posy=".$posy." yearlen=".$yearlen." yearpos=".$yearpos." posm=".$posm." monthlen=".$monthlen." monthpos=".$monthpos." yearoffsettype=".$yearoffsettype." resetEveryMonth=".$resetEveryMonth."\n";
1186
1187 // Define $yearcomp and $monthcomp (that will be use in the select where to search max number)
1188 $monthcomp = $maskraz;
1189 $yearcomp = 0;
1190
1191 if (!empty($yearoffsettype) && !is_numeric($yearoffsettype) && $yearoffsettype != '=') { // $yearoffsettype is - or +
1192 $currentyear = date("Y", $date);
1193 $fiscaldate = dol_mktime('0', '0', '0', $maskraz, '1', $currentyear);
1194 $newyeardate = dol_mktime('0', '0', '0', '1', '1', $currentyear);
1195 $nextnewyeardate = dol_mktime('0', '0', '0', '1', '1', $currentyear + 1);
1196 //echo 'currentyear='.$currentyear.' date='.dol_print_date($date, 'day').' fiscaldate='.dol_print_date($fiscaldate, 'day').'<br>';
1197
1198 // If after or equal of current fiscal date
1199 if ($date >= $fiscaldate) {
1200 // If before of next new year date
1201 if ($date < $nextnewyeardate && $yearoffsettype == '+') {
1202 $yearoffset = 1;
1203 }
1204 } elseif ($date >= $newyeardate && $yearoffsettype == '-') {
1205 // If after or equal of current new year date
1206 $yearoffset = -1;
1207 }
1208 } elseif (date("m", $date) < $maskraz && empty($resetEveryMonth)) {
1209 // For backward compatibility
1210 $yearoffset = -1;
1211 } // If current month lower that month of return to zero, year is previous year
1212
1213 if ($yearlen == 4) {
1214 $yearcomp = sprintf("%04d", date("Y", $date) + $yearoffset);
1215 } elseif ($yearlen == 2) {
1216 $yearcomp = sprintf("%02d", date("y", $date) + $yearoffset);
1217 } elseif ($yearlen == 1) {
1218 $yearcomp = substr(date('y', $date), 1, 1) + $yearoffset;
1219 }
1220 if ($monthcomp > 1 && empty($resetEveryMonth)) { // Test with month is useless if monthcomp = 0 or 1 (0 is same as 1) (regis: $monthcomp can't equal 0)
1221 if ($yearlen == 4) {
1222 $yearcomp1 = sprintf("%04d", date("Y", $date) + $yearoffset + 1);
1223 } elseif ($yearlen == 2) {
1224 $yearcomp1 = sprintf("%02d", date("y", $date) + $yearoffset + 1);
1225 }
1226
1227 $sqlwhere .= "(";
1228 $sqlwhere .= " (SUBSTRING(".$field.", ".$yearpos.", ".$yearlen.") = '".$db->escape($yearcomp)."'";
1229 $sqlwhere .= " AND SUBSTRING(".$field.", ".$monthpos.", ".$monthlen.") >= '".str_pad($monthcomp, $monthlen, '0', STR_PAD_LEFT)."')";
1230 $sqlwhere .= " OR";
1231 $sqlwhere .= " (SUBSTRING(".$field.", ".$yearpos.", ".$yearlen.") = '".$db->escape($yearcomp1)."'";
1232 $sqlwhere .= " AND SUBSTRING(".$field.", ".$monthpos.", ".$monthlen.") < '".str_pad($monthcomp, $monthlen, '0', STR_PAD_LEFT)."') ";
1233 $sqlwhere .= ')';
1234 } elseif ($resetEveryMonth) {
1235 $sqlwhere .= "(SUBSTRING(".$field.", ".$yearpos.", ".$yearlen.") = '".$db->escape($yearcomp)."'";
1236 $sqlwhere .= " AND SUBSTRING(".$field.", ".$monthpos.", ".$monthlen.") = '".str_pad($monthcomp, $monthlen, '0', STR_PAD_LEFT)."')";
1237 } else { // reset is done on january
1238 $sqlwhere .= "(SUBSTRING(".$field.", ".$yearpos.", ".$yearlen.") = '".$db->escape($yearcomp)."')";
1239 }
1240 }
1241 //print "sqlwhere=".$sqlwhere." yearcomp=".$yearcomp."<br>\n"; // sqlwhere and yearcomp defined only if we ask a reset
1242 //print "masktri=".$masktri." maskcounter=".$maskcounter." maskraz=".$maskraz." maskoffset=".$maskoffset."<br>\n";
1243
1244 // Define $sqlstring
1245 if (function_exists('mb_strrpos')) {
1246 $posnumstart = mb_strrpos($maskwithnocode, $maskcounter, 0, 'UTF-8');
1247 } else {
1248 $posnumstart = strrpos($maskwithnocode, $maskcounter);
1249 } // Pos of counter in final string (from 0 to ...)
1250 if ($posnumstart < 0) {
1251 return 'ErrorBadMaskFailedToLocatePosOfSequence';
1252 }
1253 $sqlstring = "SUBSTRING(".$field.", ".($posnumstart + 1).", ".dol_strlen($maskcounter).")";
1254
1255 // Define $maskLike
1256 $maskLike = dol_string_nospecial($mask);
1257 $maskLike = str_replace("%", "_", $maskLike);
1258
1259 // Replace protected special codes with matching number of _ as wild card caracter
1260 $maskLike = preg_replace('/\{yyyy\}/i', '____', $maskLike);
1261 $maskLike = preg_replace('/\{yy\}/i', '__', $maskLike);
1262 $maskLike = preg_replace('/\{y\}/i', '_', $maskLike);
1263 $maskLike = preg_replace('/\{mm\}/i', '__', $maskLike);
1264 $maskLike = preg_replace('/\{dd\}/i', '__', $maskLike);
1265 $maskLike = str_replace(dol_string_nospecial('{'.$masktri.'}'), str_pad("", dol_strlen($maskcounter), "_"), $maskLike);
1266 if ($maskrefclient) {
1267 $maskLike = str_replace(dol_string_nospecial('{'.$maskrefclient.'}'), str_pad("", dol_strlen($maskrefclient), "_"), $maskLike);
1268 }
1269 if ($masktype) {
1270 $maskLike = str_replace(dol_string_nospecial('{'.$masktype.'}'), $masktype_value, $maskLike);
1271 }
1272 if ($maskuser) {
1273 $maskLike = str_replace(dol_string_nospecial('{'.$maskuser.'}'), $maskuser_value, $maskLike);
1274 }
1275 foreach ($maskperso as $key => $val) {
1276 $maskLike = str_replace(dol_string_nospecial($maskperso[$key]), $maskpersonew[$key], $maskLike);
1277 }
1278
1279 // Get counter in database
1280 $counter = 0;
1281 $sql = "SELECT MAX(".$sqlstring.") as val";
1282 $sql .= " FROM ".MAIN_DB_PREFIX.$table;
1283 $sql .= " WHERE ".$field." LIKE '".$db->escape($maskLike) . (!empty($conf->global->SEARCH_FOR_NEXT_VAL_ON_START_ONLY) ? "%" : "") . "'";
1284 $sql .= " AND ".$field." NOT LIKE '(PROV%)'";
1285
1286 // To ensure that all variables within the MAX() brackets are integers
1287 if (getDolGlobalInt('MAIN_NUMBERING_FILTER_ON_INT_ONLY')) {
1288 $sql .= " AND ". $db->regexpsql($sqlstring, '^[0-9]+$', true);
1289 }
1290
1291 if ($bentityon) { // only if entity enable
1292 $sql .= " AND entity IN (".getEntity($sharetable).")";
1293 } elseif (!empty($forceentity)) {
1294 $sql .= " AND entity IN (".$db->sanitize($forceentity).")";
1295 }
1296 if ($where) {
1297 $sql .= $where;
1298 }
1299 if ($sqlwhere) {
1300 $sql .= " AND ".$sqlwhere;
1301 }
1302
1303 //print $sql.'<br>';
1304 dol_syslog("functions2::get_next_value mode=".$mode, LOG_DEBUG);
1305 $resql = $db->query($sql);
1306 if ($resql) {
1307 $obj = $db->fetch_object($resql);
1308 $counter = $obj->val;
1309 } else {
1310 dol_print_error($db);
1311 }
1312
1313 // Check if we must force counter to maskoffset
1314 if (empty($counter)) {
1315 $counter = $maskoffset;
1316 } elseif (preg_match('/[^0-9]/i', $counter)) {
1317 dol_syslog("Error, the last counter found is '".$counter."' so is not a numeric value. We will restart to 1.", LOG_ERR);
1318 $counter = 0;
1319 } elseif ($counter < $maskoffset && empty($conf->global->MAIN_NUMBERING_OFFSET_ONLY_FOR_FIRST)) {
1320 $counter = $maskoffset;
1321 }
1322
1323 if ($mode == 'last') { // We found value for counter = last counter value. Now need to get corresponding ref of invoice.
1324 $counterpadded = str_pad($counter, dol_strlen($maskcounter), "0", STR_PAD_LEFT);
1325
1326 // Define $maskLike
1327 $maskLike = dol_string_nospecial($mask);
1328 $maskLike = str_replace("%", "_", $maskLike);
1329 // Replace protected special codes with matching number of _ as wild card caracter
1330 $maskLike = preg_replace('/\{yyyy\}/i', '____', $maskLike);
1331 $maskLike = preg_replace('/\{yy\}/i', '__', $maskLike);
1332 $maskLike = preg_replace('/\{y\}/i', '_', $maskLike);
1333 $maskLike = preg_replace('/\{mm\}/i', '__', $maskLike);
1334 $maskLike = preg_replace('/\{dd\}/i', '__', $maskLike);
1335 $maskLike = str_replace(dol_string_nospecial('{'.$masktri.'}'), $counterpadded, $maskLike);
1336 if ($maskrefclient) {
1337 $maskLike = str_replace(dol_string_nospecial('{'.$maskrefclient.'}'), str_pad("", dol_strlen($maskrefclient), "_"), $maskLike);
1338 }
1339 if ($masktype) {
1340 $maskLike = str_replace(dol_string_nospecial('{'.$masktype.'}'), $masktype_value, $maskLike);
1341 }
1342 if ($maskuser) {
1343 $maskLike = str_replace(dol_string_nospecial('{'.$maskuser.'}'), $maskuser_value, $maskLike);
1344 }
1345
1346 $ref = '';
1347 $sql = "SELECT ".$field." as ref";
1348 $sql .= " FROM ".MAIN_DB_PREFIX.$table;
1349 $sql .= " WHERE ".$field." LIKE '".$db->escape($maskLike) . (!empty($conf->global->SEARCH_FOR_NEXT_VAL_ON_START_ONLY) ? "%" : "") . "'";
1350 $sql .= " AND ".$field." NOT LIKE '%PROV%'";
1351 if ($bentityon) { // only if entity enable
1352 $sql .= " AND entity IN (".getEntity($sharetable).")";
1353 } elseif (!empty($forceentity)) {
1354 $sql .= " AND entity IN (".$db->sanitize($forceentity).")";
1355 }
1356 if ($where) {
1357 $sql .= $where;
1358 }
1359 if ($sqlwhere) {
1360 $sql .= " AND ".$sqlwhere;
1361 }
1362
1363 dol_syslog("functions2::get_next_value mode=".$mode, LOG_DEBUG);
1364 $resql = $db->query($sql);
1365 if ($resql) {
1366 $obj = $db->fetch_object($resql);
1367 if ($obj) {
1368 $ref = $obj->ref;
1369 }
1370 } else {
1371 dol_print_error($db);
1372 }
1373
1374 $numFinal = $ref;
1375 } elseif ($mode == 'next') {
1376 $counter++;
1377 $maskrefclient_counter = 0;
1378
1379 // If value for $counter has a length higher than $maskcounter chars
1380 if ($counter >= pow(10, dol_strlen($maskcounter))) {
1381 $counter = 'ErrorMaxNumberReachForThisMask';
1382 }
1383
1384 if (!empty($maskrefclient_maskcounter)) {
1385 //print "maskrefclient_maskcounter=".$maskrefclient_maskcounter." maskwithnocode=".$maskwithnocode." maskrefclient=".$maskrefclient."\n<br>";
1386
1387 // Define $sqlstring
1388 $maskrefclient_posnumstart = strpos($maskwithnocode, $maskrefclient_maskcounter, strpos($maskwithnocode, $maskrefclient)); // Pos of counter in final string (from 0 to ...)
1389 if ($maskrefclient_posnumstart <= 0) {
1390 return 'ErrorBadMask';
1391 }
1392 $maskrefclient_sqlstring = 'SUBSTRING('.$field.', '.($maskrefclient_posnumstart + 1).', '.dol_strlen($maskrefclient_maskcounter).')';
1393 //print "x".$sqlstring;
1394
1395 // Define $maskrefclient_maskLike
1396 $maskrefclient_maskLike = dol_string_nospecial($mask);
1397 $maskrefclient_maskLike = str_replace("%", "_", $maskrefclient_maskLike);
1398 // Replace protected special codes with matching number of _ as wild card caracter
1399 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{yyyy}'), '____', $maskrefclient_maskLike);
1400 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{yy}'), '__', $maskrefclient_maskLike);
1401 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{y}'), '_', $maskrefclient_maskLike);
1402 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{mm}'), '__', $maskrefclient_maskLike);
1403 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{dd}'), '__', $maskrefclient_maskLike);
1404 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{'.$masktri.'}'), str_pad("", dol_strlen($maskcounter), "_"), $maskrefclient_maskLike);
1405 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{'.$maskrefclient.'}'), $maskrefclient_clientcode.str_pad("", dol_strlen($maskrefclient_maskcounter), "_"), $maskrefclient_maskLike);
1406
1407 // Get counter in database
1408 $maskrefclient_sql = "SELECT MAX(".$maskrefclient_sqlstring.") as val";
1409 $maskrefclient_sql .= " FROM ".MAIN_DB_PREFIX.$table;
1410 //$sql.= " WHERE ".$field." not like '(%'";
1411 $maskrefclient_sql .= " WHERE ".$field." LIKE '".$db->escape($maskrefclient_maskLike) . (!empty($conf->global->SEARCH_FOR_NEXT_VAL_ON_START_ONLY) ? "%" : "") . "'";
1412 if ($bentityon) { // only if entity enable
1413 $maskrefclient_sql .= " AND entity IN (".getEntity($sharetable).")";
1414 } elseif (!empty($forceentity)) {
1415 $sql .= " AND entity IN (".$db->sanitize($forceentity).")";
1416 }
1417 if ($where) {
1418 $maskrefclient_sql .= $where; //use the same optional where as general mask
1419 }
1420 if ($sqlwhere) {
1421 $maskrefclient_sql .= ' AND '.$sqlwhere; //use the same sqlwhere as general mask
1422 }
1423 $maskrefclient_sql .= " AND (SUBSTRING(".$field.", ".(strpos($maskwithnocode, $maskrefclient) + 1).", ".dol_strlen($maskrefclient_maskclientcode).") = '".$db->escape($maskrefclient_clientcode)."')";
1424
1425 dol_syslog("functions2::get_next_value maskrefclient", LOG_DEBUG);
1426 $maskrefclient_resql = $db->query($maskrefclient_sql);
1427 if ($maskrefclient_resql) {
1428 $maskrefclient_obj = $db->fetch_object($maskrefclient_resql);
1429 $maskrefclient_counter = $maskrefclient_obj->val;
1430 } else {
1431 dol_print_error($db);
1432 }
1433
1434 if (empty($maskrefclient_counter) || preg_match('/[^0-9]/i', $maskrefclient_counter)) {
1435 $maskrefclient_counter = $maskrefclient_maskoffset;
1436 }
1437 $maskrefclient_counter++;
1438 }
1439
1440 // Build numFinal
1441 $numFinal = $mask;
1442
1443 // We replace special codes except refclient
1444 if (!empty($yearoffsettype) && !is_numeric($yearoffsettype) && $yearoffsettype != '=') { // yearoffsettype is - or +, so we don't want current year
1445 $numFinal = preg_replace('/\{yyyy\}/i', date("Y", $date) + $yearoffset, $numFinal);
1446 $numFinal = preg_replace('/\{yy\}/i', date("y", $date) + $yearoffset, $numFinal);
1447 $numFinal = preg_replace('/\{y\}/i', substr(date("y", $date), 1, 1) + $yearoffset, $numFinal);
1448 } else // we want yyyy to be current year
1449 {
1450 $numFinal = preg_replace('/\{yyyy\}/i', date("Y", $date), $numFinal);
1451 $numFinal = preg_replace('/\{yy\}/i', date("y", $date), $numFinal);
1452 $numFinal = preg_replace('/\{y\}/i', substr(date("y", $date), 1, 1), $numFinal);
1453 }
1454 $numFinal = preg_replace('/\{mm\}/i', date("m", $date), $numFinal);
1455 $numFinal = preg_replace('/\{dd\}/i', date("d", $date), $numFinal);
1456
1457 // Now we replace the counter
1458 $maskbefore = '{'.$masktri.'}';
1459 $maskafter = str_pad($counter, dol_strlen($maskcounter), "0", STR_PAD_LEFT);
1460 //print 'x'.$numFinal.' - '.$maskbefore.' - '.$maskafter.'y';exit;
1461 $numFinal = str_replace($maskbefore, $maskafter, $numFinal);
1462
1463 // Now we replace the refclient
1464 if ($maskrefclient) {
1465 //print "maskrefclient=".$maskrefclient." maskrefclient_counter=".$maskrefclient_counter." maskwithonlyymcode=".$maskwithonlyymcode." maskwithnocode=".$maskwithnocode." maskrefclient_clientcode=".$maskrefclient_clientcode." maskrefclient_maskcounter=".$maskrefclient_maskcounter."\n<br>";exit;
1466 $maskrefclient_maskbefore = '{'.$maskrefclient.'}';
1467 $maskrefclient_maskafter = $maskrefclient_clientcode;
1468 if (dol_strlen($maskrefclient_maskcounter) > 0) {
1469 $maskrefclient_maskafter .= str_pad($maskrefclient_counter, dol_strlen($maskrefclient_maskcounter), "0", STR_PAD_LEFT);
1470 }
1471 $numFinal = str_replace($maskrefclient_maskbefore, $maskrefclient_maskafter, $numFinal);
1472 }
1473
1474 // Now we replace the type
1475 if ($masktype) {
1476 $masktype_maskbefore = '{'.$masktype.'}';
1477 $masktype_maskafter = $masktype_value;
1478 $numFinal = str_replace($masktype_maskbefore, $masktype_maskafter, $numFinal);
1479 }
1480
1481 // Now we replace the user
1482 if ($maskuser) {
1483 $maskuser_maskbefore = '{'.$maskuser.'}';
1484 $maskuser_maskafter = $maskuser_value;
1485 $numFinal = str_replace($maskuser_maskbefore, $maskuser_maskafter, $numFinal);
1486 }
1487 }
1488
1489 dol_syslog("functions2::get_next_value return ".$numFinal, LOG_DEBUG);
1490 return $numFinal;
1491}
1492
1501function get_string_between($string, $start, $end)
1502{
1503 $string = " ".$string;
1504 $ini = strpos($string, $start);
1505 if ($ini == 0) {
1506 return "";
1507 }
1508 $ini += strlen($start);
1509 $len = strpos($string, $end, $ini) - $ini;
1510 return substr($string, $ini, $len);
1511}
1512
1520function check_value($mask, $value)
1521{
1522 $result = 0;
1523
1524 $hasglobalcounter = false;
1525 // Extract value for mask counter, mask raz and mask offset
1526 $reg = array();
1527 if (preg_match('/\{(0+)([@\+][0-9]+)?([@\+][0-9]+)?\}/i', $mask, $reg)) {
1528 $masktri = $reg[1].(isset($reg[2]) ? $reg[2] : '').(isset($reg[3]) ? $reg[3] : '');
1529 $maskcounter = $reg[1];
1530 $hasglobalcounter = true;
1531 } else {
1532 // setting some defaults so the rest of the code won't fail if there is a third party counter
1533 $masktri = '00000';
1534 $maskcounter = '00000';
1535 }
1536 $maskraz = -1;
1537 $maskoffset = 0;
1538 if (dol_strlen($maskcounter) < 3) {
1539 return 'ErrorCounterMustHaveMoreThan3Digits';
1540 }
1541
1542 // Extract value for third party mask counter
1543 $regClientRef = array();
1544 if (preg_match('/\{(c+)(0*)\}/i', $mask, $regClientRef)) {
1545 $maskrefclient = $regClientRef[1].$regClientRef[2];
1546 $maskrefclient_maskclientcode = $regClientRef[1];
1547 $maskrefclient_maskcounter = $regClientRef[2];
1548 $maskrefclient_maskoffset = 0; //default value of maskrefclient_counter offset
1549 $maskrefclient_clientcode = substr('', 0, dol_strlen($maskrefclient_maskclientcode)); //get n first characters of client code to form maskrefclient_clientcode
1550 $maskrefclient_clientcode = str_pad($maskrefclient_clientcode, dol_strlen($maskrefclient_maskclientcode), "#", STR_PAD_RIGHT); //padding maskrefclient_clientcode for having exactly n characters in maskrefclient_clientcode
1551 $maskrefclient_clientcode = dol_string_nospecial($maskrefclient_clientcode); //sanitize maskrefclient_clientcode for sql insert and sql select like
1552 if (dol_strlen($maskrefclient_maskcounter) > 0 && dol_strlen($maskrefclient_maskcounter) < 3) {
1553 return 'ErrorCounterMustHaveMoreThan3Digits';
1554 }
1555 } else {
1556 $maskrefclient = '';
1557 }
1558
1559 // fail if there is neither a global nor a third party counter
1560 if (!$hasglobalcounter && ($maskrefclient_maskcounter == '')) {
1561 return 'ErrorBadMask';
1562 }
1563
1564 $maskwithonlyymcode = $mask;
1565 $maskwithonlyymcode = preg_replace('/\{(0+)([@\+][0-9]+)?([@\+][0-9]+)?\}/i', $maskcounter, $maskwithonlyymcode);
1566 $maskwithonlyymcode = preg_replace('/\{dd\}/i', 'dd', $maskwithonlyymcode);
1567 $maskwithonlyymcode = preg_replace('/\{(c+)(0*)\}/i', $maskrefclient, $maskwithonlyymcode);
1568 $maskwithnocode = $maskwithonlyymcode;
1569 $maskwithnocode = preg_replace('/\{yyyy\}/i', 'yyyy', $maskwithnocode);
1570 $maskwithnocode = preg_replace('/\{yy\}/i', 'yy', $maskwithnocode);
1571 $maskwithnocode = preg_replace('/\{y\}/i', 'y', $maskwithnocode);
1572 $maskwithnocode = preg_replace('/\{mm\}/i', 'mm', $maskwithnocode);
1573 // Now maskwithnocode = 0000ddmmyyyyccc for example
1574 // and maskcounter = 0000 for example
1575 //print "maskwithonlyymcode=".$maskwithonlyymcode." maskwithnocode=".$maskwithnocode."\n<br>";
1576
1577 // If an offset is asked
1578 if (!empty($reg[2]) && preg_match('/^\+/', $reg[2])) {
1579 $maskoffset = preg_replace('/^\+/', '', $reg[2]);
1580 }
1581 if (!empty($reg[3]) && preg_match('/^\+/', $reg[3])) {
1582 $maskoffset = preg_replace('/^\+/', '', $reg[3]);
1583 }
1584
1585 // Define $sqlwhere
1586
1587 // If a restore to zero after a month is asked we check if there is already a value for this year.
1588 if (!empty($reg[2]) && preg_match('/^@/', $reg[2])) {
1589 $maskraz = preg_replace('/^@/', '', $reg[2]);
1590 }
1591 if (!empty($reg[3]) && preg_match('/^@/', $reg[3])) {
1592 $maskraz = preg_replace('/^@/', '', $reg[3]);
1593 }
1594 if ($maskraz >= 0) {
1595 if ($maskraz == 99) {
1596 $maskraz = date('m');
1597 $resetEveryMonth = true;
1598 }
1599 if ($maskraz > 12) {
1600 return 'ErrorBadMaskBadRazMonth';
1601 }
1602
1603 // Define reg
1604 if ($maskraz > 1 && !preg_match('/^(.*)\{(y+)\}\{(m+)\}/i', $maskwithonlyymcode, $reg)) {
1605 return 'ErrorCantUseRazInStartedYearIfNoYearMonthInMask';
1606 }
1607 if ($maskraz <= 1 && !preg_match('/^(.*)\{(y+)\}/i', $maskwithonlyymcode, $reg)) {
1608 return 'ErrorCantUseRazIfNoYearInMask';
1609 }
1610 //print "x".$maskwithonlyymcode." ".$maskraz;
1611 }
1612 //print "masktri=".$masktri." maskcounter=".$maskcounter." maskwithonlyymcode=".$maskwithonlyymcode." maskwithnocode=".$maskwithnocode." maskraz=".$maskraz." maskoffset=".$maskoffset."<br>\n";
1613
1614 if (function_exists('mb_strrpos')) {
1615 $posnumstart = mb_strrpos($maskwithnocode, $maskcounter, 0, 'UTF-8');
1616 } else {
1617 $posnumstart = strrpos($maskwithnocode, $maskcounter);
1618 } // Pos of counter in final string (from 0 to ...)
1619 if ($posnumstart < 0) {
1620 return 'ErrorBadMaskFailedToLocatePosOfSequence';
1621 }
1622
1623 // Check we have a number in $value at position ($posnumstart+1).', '.dol_strlen($maskcounter)
1624 // TODO
1625
1626 // Check length
1627 $len = dol_strlen($maskwithnocode);
1628 if (dol_strlen($value) != $len) {
1629 $result = -1;
1630 }
1631
1632 dol_syslog("functions2::check_value result=".$result, LOG_DEBUG);
1633 return $result;
1634}
1635
1644function binhex($bin, $pad = false, $upper = false)
1645{
1646 $last = dol_strlen($bin) - 1;
1647 for ($i = 0; $i <= $last; $i++) {
1648 $x += $bin[$last - $i] * pow(2, $i);
1649 }
1650 $x = dechex($x);
1651 if ($pad) {
1652 while (dol_strlen($x) < intval(dol_strlen($bin)) / 4) {
1653 $x = "0$x";
1654 }
1655 }
1656 if ($upper) {
1657 $x = strtoupper($x);
1658 }
1659 return $x;
1660}
1661
1668function hexbin($hexa)
1669{
1670 $bin = '';
1671 $strLength = dol_strlen($hexa);
1672 for ($i = 0; $i < $strLength; $i++) {
1673 $bin .= str_pad(decbin(hexdec($hexa[$i])), 4, '0', STR_PAD_LEFT);
1674 }
1675 return $bin;
1676}
1677
1684function numero_semaine($time)
1685{
1686 $stime = strftime('%Y-%m-%d', $time);
1687
1688 if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/i', $stime, $reg)) {
1689 // Date est au format 'YYYY-MM-DD' ou 'YYYY-MM-DD HH:MM:SS'
1690 $annee = $reg[1];
1691 $mois = $reg[2];
1692 $jour = $reg[3];
1693 }
1694
1695 /*
1696 * Norme ISO-8601:
1697 * - La semaine 1 de toute annee est celle qui contient le 4 janvier ou que la semaine 1 de toute annee est celle qui contient le 1er jeudi de janvier.
1698 * - La majorite des annees ont 52 semaines mais les annees qui commence un jeudi et les annees bissextiles commencant un mercredi en possede 53.
1699 * - Le 1er jour de la semaine est le Lundi
1700 */
1701
1702 // Definition du Jeudi de la semaine
1703 if (date("w", mktime(12, 0, 0, $mois, $jour, $annee)) == 0) { // Dimanche
1704 $jeudiSemaine = mktime(12, 0, 0, $mois, $jour, $annee) - 3 * 24 * 60 * 60;
1705 } elseif (date("w", mktime(12, 0, 0, $mois, $jour, $annee)) < 4) { // du Lundi au Mercredi
1706 $jeudiSemaine = mktime(12, 0, 0, $mois, $jour, $annee) + (4 - date("w", mktime(12, 0, 0, $mois, $jour, $annee))) * 24 * 60 * 60;
1707 } elseif (date("w", mktime(12, 0, 0, $mois, $jour, $annee)) > 4) { // du Vendredi au Samedi
1708 $jeudiSemaine = mktime(12, 0, 0, $mois, $jour, $annee) - (date("w", mktime(12, 0, 0, $mois, $jour, $annee)) - 4) * 24 * 60 * 60;
1709 } else { // Jeudi
1710 $jeudiSemaine = mktime(12, 0, 0, $mois, $jour, $annee);
1711 }
1712
1713 // Definition du premier Jeudi de l'annee
1714 if (date("w", mktime(12, 0, 0, 1, 1, date("Y", $jeudiSemaine))) == 0) { // Dimanche
1715 $premierJeudiAnnee = mktime(12, 0, 0, 1, 1, date("Y", $jeudiSemaine)) + 4 * 24 * 60 * 60;
1716 } elseif (date("w", mktime(12, 0, 0, 1, 1, date("Y", $jeudiSemaine))) < 4) { // du Lundi au Mercredi
1717 $premierJeudiAnnee = mktime(12, 0, 0, 1, 1, date("Y", $jeudiSemaine)) + (4 - date("w", mktime(12, 0, 0, 1, 1, date("Y", $jeudiSemaine)))) * 24 * 60 * 60;
1718 } elseif (date("w", mktime(12, 0, 0, 1, 1, date("Y", $jeudiSemaine))) > 4) { // du Vendredi au Samedi
1719 $premierJeudiAnnee = mktime(12, 0, 0, 1, 1, date("Y", $jeudiSemaine)) + (7 - (date("w", mktime(12, 0, 0, 1, 1, date("Y", $jeudiSemaine))) - 4)) * 24 * 60 * 60;
1720 } else // Jeudi
1721 {
1722 $premierJeudiAnnee = mktime(12, 0, 0, 1, 1, date("Y", $jeudiSemaine));
1723 }
1724
1725 // Definition du numero de semaine: nb de jours entre "premier Jeudi de l'annee" et "Jeudi de la semaine";
1726 $numeroSemaine = (
1727 (
1728 date("z", mktime(12, 0, 0, date("m", $jeudiSemaine), date("d", $jeudiSemaine), date("Y", $jeudiSemaine)))
1729 -
1730 date("z", mktime(12, 0, 0, date("m", $premierJeudiAnnee), date("d", $premierJeudiAnnee), date("Y", $premierJeudiAnnee)))
1731 ) / 7
1732 ) + 1;
1733
1734 // Cas particulier de la semaine 53
1735 if ($numeroSemaine == 53) {
1736 // Les annees qui commence un Jeudi et les annees bissextiles commencant un Mercredi en possede 53
1737 if (date("w", mktime(12, 0, 0, 1, 1, date("Y", $jeudiSemaine))) == 4 || (date("w", mktime(12, 0, 0, 1, 1, date("Y", $jeudiSemaine))) == 3 && date("z", mktime(12, 0, 0, 12, 31, date("Y", $jeudiSemaine))) == 365)) {
1738 $numeroSemaine = 53;
1739 } else {
1740 $numeroSemaine = 1;
1741 }
1742 }
1743
1744 //echo $jour."-".$mois."-".$annee." (".date("d-m-Y",$premierJeudiAnnee)." - ".date("d-m-Y",$jeudiSemaine).") -> ".$numeroSemaine."<BR>";
1745
1746 return sprintf("%02d", $numeroSemaine);
1747}
1748
1757function weight_convert($weight, &$from_unit, $to_unit)
1758{
1759 /* Pour convertire 320 gr en Kg appeler
1760 * $f = -3
1761 * weigh_convert(320, $f, 0) retournera 0.32
1762 *
1763 */
1764 $weight = is_numeric($weight) ? $weight : 0;
1765 while ($from_unit <> $to_unit) {
1766 if ($from_unit > $to_unit) {
1767 $weight = $weight * 10;
1768 $from_unit = $from_unit - 1;
1769 $weight = weight_convert($weight, $from_unit, $to_unit);
1770 }
1771 if ($from_unit < $to_unit) {
1772 $weight = $weight / 10;
1773 $from_unit = $from_unit + 1;
1774 $weight = weight_convert($weight, $from_unit, $to_unit);
1775 }
1776 }
1777
1778 return $weight;
1779}
1780
1792function dol_set_user_param($db, $conf, &$user, $tab)
1793{
1794 // Verification parametres
1795 if (count($tab) < 1) {
1796 return -1;
1797 }
1798
1799 $db->begin();
1800
1801 // We remove old parameters for all keys in $tab
1802 $sql = "DELETE FROM ".MAIN_DB_PREFIX."user_param";
1803 $sql .= " WHERE fk_user = ".((int) $user->id);
1804 $sql .= " AND entity = ".((int) $conf->entity);
1805 $sql .= " AND param in (";
1806 $i = 0;
1807 foreach ($tab as $key => $value) {
1808 if ($i > 0) {
1809 $sql .= ',';
1810 }
1811 $sql .= "'".$db->escape($key)."'";
1812 $i++;
1813 }
1814 $sql .= ")";
1815 dol_syslog("functions2.lib::dol_set_user_param", LOG_DEBUG);
1816
1817 $resql = $db->query($sql);
1818 if (!$resql) {
1819 dol_print_error($db);
1820 $db->rollback();
1821 return -1;
1822 }
1823
1824 foreach ($tab as $key => $value) {
1825 // Set new parameters
1826 if ($value) {
1827 $sql = "INSERT INTO ".MAIN_DB_PREFIX."user_param(fk_user,entity,param,value)";
1828 $sql .= " VALUES (".((int) $user->id).",".((int) $conf->entity).",";
1829 $sql .= " '".$db->escape($key)."','".$db->escape($value)."')";
1830
1831 dol_syslog("functions2.lib::dol_set_user_param", LOG_DEBUG);
1832 $result = $db->query($sql);
1833 if (!$result) {
1834 dol_print_error($db);
1835 $db->rollback();
1836 return -1;
1837 }
1838 $user->conf->$key = $value;
1839 //print "key=".$key." user->conf->key=".$user->conf->$key;
1840 } else {
1841 unset($user->conf->$key);
1842 }
1843 }
1844
1845 $db->commit();
1846 return 1;
1847}
1848
1856function dol_print_reduction($reduction, $langs)
1857{
1858 $string = '';
1859 if ($reduction == 100) {
1860 $string = $langs->transnoentities("Offered");
1861 } else {
1862 $string = vatrate($reduction, true);
1863 }
1864
1865 return $string;
1866}
1867
1875function version_os($option = '')
1876{
1877 if ($option == 'smr') {
1878 $osversion = php_uname('s').' '.php_uname('m').' '.php_uname('r');
1879 } else {
1880 $osversion = php_uname();
1881 }
1882 return $osversion;
1883}
1884
1891function version_php()
1892{
1893 return phpversion();
1894}
1895
1903{
1904 return DOL_VERSION;
1905}
1906
1913{
1914 return $_SERVER["SERVER_SOFTWARE"];
1915}
1916
1925function getListOfModels($db, $type, $maxfilenamelength = 0)
1926{
1927 global $conf, $langs;
1928 $liste = array();
1929 $found = 0;
1930 $dirtoscan = '';
1931
1932 $sql = "SELECT nom as id, nom as doc_template_name, libelle as label, description as description";
1933 $sql .= " FROM ".MAIN_DB_PREFIX."document_model";
1934 $sql .= " WHERE type = '".$db->escape($type)."'";
1935 $sql .= " AND entity IN (0,".$conf->entity.")";
1936 $sql .= " ORDER BY description DESC";
1937
1938 dol_syslog('/core/lib/function2.lib.php::getListOfModels', LOG_DEBUG);
1939 $resql_models = $db->query($sql);
1940 if ($resql_models) {
1941 $num = $db->num_rows($resql_models);
1942 $i = 0;
1943 while ($i < $num) {
1944 $found = 1;
1945
1946 $obj = $db->fetch_object($resql_models);
1947
1948 // If this generation module needs to scan a directory, then description field is filled
1949 // with the constant that contains list of directories to scan (COMPANY_ADDON_PDF_ODT_PATH, ...).
1950 if (!empty($obj->description)) { // A list of directories to scan is defined
1951 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1952
1953 $const = $obj->description;
1954 //irtoscan.=($dirtoscan?',':'').preg_replace('/[\r\n]+/',',',trim($conf->global->$const));
1955 $dirtoscan = preg_replace('/[\r\n]+/', ',', trim($conf->global->$const));
1956
1957 $listoffiles = array();
1958
1959 // Now we add models found in directories scanned
1960 $listofdir = explode(',', $dirtoscan);
1961 foreach ($listofdir as $key => $tmpdir) {
1962 $tmpdir = trim($tmpdir);
1963 $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
1964 if (!$tmpdir) {
1965 unset($listofdir[$key]);
1966 continue;
1967 }
1968 if (is_dir($tmpdir)) {
1969 // all type of template is allowed
1970 $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '', '', 'name', SORT_ASC, 0);
1971 if (count($tmpfiles)) {
1972 $listoffiles = array_merge($listoffiles, $tmpfiles);
1973 }
1974 }
1975 }
1976
1977 if (count($listoffiles)) {
1978 foreach ($listoffiles as $record) {
1979 $max = ($maxfilenamelength ? $maxfilenamelength : 28);
1980 $liste[$obj->id.':'.$record['fullname']] = dol_trunc($record['name'], $max, 'middle');
1981 }
1982 } else {
1983 $liste[0] = $obj->label.': '.$langs->trans("None");
1984 }
1985 } else {
1986 if ($type == 'member' && $obj->doc_template_name == 'standard') { // Special case, if member template, we add variant per format
1987 global $_Avery_Labels;
1988 include_once DOL_DOCUMENT_ROOT.'/core/lib/format_cards.lib.php';
1989 foreach ($_Avery_Labels as $key => $val) {
1990 $liste[$obj->id.':'.$key] = ($obj->label ? $obj->label : $obj->doc_template_name).' '.$val['name'];
1991 }
1992 } else {
1993 // Common usage
1994 $liste[$obj->id] = $obj->label ? $obj->label : $obj->doc_template_name;
1995 }
1996 }
1997 $i++;
1998 }
1999 } else {
2000 dol_print_error($db);
2001 return -1;
2002 }
2003
2004 if ($found) {
2005 return $liste;
2006 } else {
2007 return 0;
2008 }
2009}
2010
2018function is_ip($ip)
2019{
2020 // First we test if it is a valid IPv4
2021 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
2022 // Then we test if it is a private range
2023 if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) {
2024 return 2;
2025 }
2026
2027 // Then we test if it is a reserved range
2028 if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE)) {
2029 return 0;
2030 }
2031
2032 return 1;
2033 }
2034
2035 return 0;
2036}
2037
2045function dol_buildlogin($lastname, $firstname)
2046{
2047 global $conf;
2048
2049 //$conf->global->MAIN_BUILD_LOGIN_RULE = 'f.lastname';
2050 if (!empty($conf->global->MAIN_BUILD_LOGIN_RULE) && $conf->global->MAIN_BUILD_LOGIN_RULE == 'f.lastname') { // f.lastname
2051 $login = strtolower(dol_string_unaccent(dol_trunc($firstname, 1, 'right', 'UTF-8', 1)));
2052 $login .= ($login ? '.' : '');
2053 $login .= strtolower(dol_string_unaccent($lastname));
2054 $login = dol_string_nospecial($login, ''); // For special names
2055 } else { // firstname.lastname
2056 $login = strtolower(dol_string_unaccent($firstname));
2057 $login .= ($login ? '.' : '');
2058 $login .= strtolower(dol_string_unaccent($lastname));
2059 $login = dol_string_nospecial($login, ''); // For special names
2060 }
2061
2062 // TODO Add a hook to allow external modules to suggest new rules
2063
2064 return $login;
2065}
2066
2073{
2074 global $conf;
2075
2076 $params = array();
2077 $proxyuse = (empty($conf->global->MAIN_PROXY_USE) ?false:true);
2078 $proxyhost = (empty($conf->global->MAIN_PROXY_USE) ?false:$conf->global->MAIN_PROXY_HOST);
2079 $proxyport = (empty($conf->global->MAIN_PROXY_USE) ?false:$conf->global->MAIN_PROXY_PORT);
2080 $proxyuser = (empty($conf->global->MAIN_PROXY_USE) ?false:$conf->global->MAIN_PROXY_USER);
2081 $proxypass = (empty($conf->global->MAIN_PROXY_USE) ?false:$conf->global->MAIN_PROXY_PASS);
2082 $timeout = (empty($conf->global->MAIN_USE_CONNECT_TIMEOUT) ? 10 : $conf->global->MAIN_USE_CONNECT_TIMEOUT); // Connection timeout
2083 $response_timeout = (empty($conf->global->MAIN_USE_RESPONSE_TIMEOUT) ? 30 : $conf->global->MAIN_USE_RESPONSE_TIMEOUT); // Response timeout
2084 //print extension_loaded('soap');
2085 if ($proxyuse) {
2086 $params = array('connection_timeout'=>$timeout,
2087 'response_timeout'=>$response_timeout,
2088 'proxy_use' => 1,
2089 'proxy_host' => $proxyhost,
2090 'proxy_port' => $proxyport,
2091 'proxy_login' => $proxyuser,
2092 'proxy_password' => $proxypass,
2093 'trace' => 1
2094 );
2095 } else {
2096 $params = array('connection_timeout'=>$timeout,
2097 'response_timeout'=>$response_timeout,
2098 'proxy_use' => 0,
2099 'proxy_host' => false,
2100 'proxy_port' => false,
2101 'proxy_login' => false,
2102 'proxy_password' => false,
2103 'trace' => 1
2104 );
2105 }
2106 return $params;
2107}
2108
2109
2119function dolGetElementUrl($objectid, $objecttype, $withpicto = 0, $option = '')
2120{
2121 global $db, $conf, $langs;
2122
2123 $ret = '';
2124 $regs = array();
2125
2126 // If we ask a resource form external module (instead of default path)
2127 if (preg_match('/^([^@]+)@([^@]+)$/i', $objecttype, $regs)) {
2128 $myobject = $regs[1];
2129 $module = $regs[2];
2130 } else {
2131 // Parse $objecttype (ex: project_task)
2132 $module = $myobject = $objecttype;
2133 if (preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
2134 $module = $regs[1];
2135 $myobject = $regs[2];
2136 }
2137 }
2138
2139 // Generic case for $classpath
2140 $classpath = $module.'/class';
2141
2142 // Special cases, to work with non standard path
2143 if ($objecttype == 'facture' || $objecttype == 'invoice') {
2144 $langs->load('bills');
2145 $classpath = 'compta/facture/class';
2146 $module = 'facture';
2147 $myobject = 'facture';
2148 } elseif ($objecttype == 'commande' || $objecttype == 'order') {
2149 $langs->load('orders');
2150 $classpath = 'commande/class';
2151 $module = 'commande';
2152 $myobject = 'commande';
2153 } elseif ($objecttype == 'propal') {
2154 $langs->load('propal');
2155 $classpath = 'comm/propal/class';
2156 } elseif ($objecttype == 'supplier_proposal') {
2157 $langs->load('supplier_proposal');
2158 $classpath = 'supplier_proposal/class';
2159 } elseif ($objecttype == 'shipping') {
2160 $langs->load('sendings');
2161 $classpath = 'expedition/class';
2162 $myobject = 'expedition';
2163 $module = 'expedition_bon';
2164 } elseif ($objecttype == 'delivery') {
2165 $langs->load('deliveries');
2166 $classpath = 'delivery/class';
2167 $myobject = 'delivery';
2168 $module = 'delivery_note';
2169 } elseif ($objecttype == 'contract') {
2170 $langs->load('contracts');
2171 $classpath = 'contrat/class';
2172 $module = 'contrat';
2173 $myobject = 'contrat';
2174 } elseif ($objecttype == 'member') {
2175 $langs->load('members');
2176 $classpath = 'adherents/class';
2177 $module = 'adherent';
2178 $myobject = 'adherent';
2179 } elseif ($objecttype == 'cabinetmed_cons') {
2180 $classpath = 'cabinetmed/class';
2181 $module = 'cabinetmed';
2182 $myobject = 'cabinetmedcons';
2183 } elseif ($objecttype == 'fichinter') {
2184 $langs->load('interventions');
2185 $classpath = 'fichinter/class';
2186 $module = 'ficheinter';
2187 $myobject = 'fichinter';
2188 } elseif ($objecttype == 'project') {
2189 $langs->load('projects');
2190 $classpath = 'projet/class';
2191 $module = 'projet';
2192 } elseif ($objecttype == 'task') {
2193 $langs->load('projects');
2194 $classpath = 'projet/class';
2195 $module = 'projet';
2196 $myobject = 'task';
2197 } elseif ($objecttype == 'stock') {
2198 $classpath = 'product/stock/class';
2199 $module = 'stock';
2200 $myobject = 'stock';
2201 } elseif ($objecttype == 'inventory') {
2202 $classpath = 'product/inventory/class';
2203 $module = 'stock';
2204 $myobject = 'inventory';
2205 } elseif ($objecttype == 'mo') {
2206 $classpath = 'mrp/class';
2207 $module = 'mrp';
2208 $myobject = 'mo';
2209 } elseif ($objecttype == 'productlot') {
2210 $classpath = 'product/stock/class';
2211 $module = 'stock';
2212 $myobject = 'productlot';
2213 }
2214
2215 // Generic case for $classfile and $classname
2216 $classfile = strtolower($myobject);
2217 $classname = ucfirst($myobject);
2218 //print "objecttype=".$objecttype." module=".$module." subelement=".$subelement." classfile=".$classfile." classname=".$classname." classpath=".$classpath;
2219
2220 if ($objecttype == 'invoice_supplier') {
2221 $classfile = 'fournisseur.facture';
2222 $classname = 'FactureFournisseur';
2223 $classpath = 'fourn/class';
2224 $module = 'fournisseur';
2225 } elseif ($objecttype == 'order_supplier') {
2226 $classfile = 'fournisseur.commande';
2227 $classname = 'CommandeFournisseur';
2228 $classpath = 'fourn/class';
2229 $module = 'fournisseur';
2230 } elseif ($objecttype == 'supplier_proposal') {
2231 $classfile = 'supplier_proposal';
2232 $classname = 'SupplierProposal';
2233 $classpath = 'supplier_proposal/class';
2234 $module = 'supplier_proposal';
2235 } elseif ($objecttype == 'stock') {
2236 $classpath = 'product/stock/class';
2237 $classfile = 'entrepot';
2238 $classname = 'Entrepot';
2239 } elseif ($objecttype == 'facturerec') {
2240 $classpath = 'compta/facture/class';
2241 $classfile = 'facture-rec';
2242 $classname = 'FactureRec';
2243 $module = 'facture';
2244 } elseif ($objecttype == 'mailing') {
2245 $classpath = 'comm/mailing/class';
2246 $classfile = 'mailing';
2247 $classname = 'Mailing';
2248 }
2249
2250 if (isModEnabled($module)) {
2251 $res = dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
2252 if ($res) {
2253 if (class_exists($classname)) {
2254 $object = new $classname($db);
2255 $res = $object->fetch($objectid);
2256 if ($res > 0) {
2257 $ret = $object->getNomUrl($withpicto, $option);
2258 } elseif ($res == 0) {
2259 $ret = $langs->trans('Deleted');
2260 }
2261 unset($object);
2262 } else {
2263 dol_syslog("Class with classname ".$classname." is unknown even after the include", LOG_ERR);
2264 }
2265 }
2266 }
2267 return $ret;
2268}
2269
2270
2279function cleanCorruptedTree($db, $tabletocleantree, $fieldfkparent)
2280{
2281 $totalnb = 0;
2282 $listofid = array();
2283 $listofparentid = array();
2284
2285 // Get list of all id in array listofid and all parents in array listofparentid
2286 $sql = "SELECT rowid, ".$fieldfkparent." as parent_id FROM ".MAIN_DB_PREFIX.$tabletocleantree;
2287 $resql = $db->query($sql);
2288 if ($resql) {
2289 $num = $db->num_rows($resql);
2290 $i = 0;
2291 while ($i < $num) {
2292 $obj = $db->fetch_object($resql);
2293 $listofid[] = $obj->rowid;
2294 if ($obj->parent_id > 0) {
2295 $listofparentid[$obj->rowid] = $obj->parent_id;
2296 }
2297 $i++;
2298 }
2299 } else {
2300 dol_print_error($db);
2301 }
2302
2303 if (count($listofid)) {
2304 print 'Code requested to clean tree (may be to solve data corruption), so we check/clean orphelins and loops.'."<br>\n";
2305
2306 // Check loops on each other
2307 $sql = "UPDATE ".MAIN_DB_PREFIX.$tabletocleantree." SET ".$fieldfkparent." = 0 WHERE ".$fieldfkparent." = rowid"; // So we update only records linked to themself
2308 $resql = $db->query($sql);
2309 if ($resql) {
2310 $nb = $db->affected_rows($sql);
2311 if ($nb > 0) {
2312 print '<br>Some record that were parent of themself were cleaned.';
2313 }
2314
2315 $totalnb += $nb;
2316 }
2317 //else dol_print_error($db);
2318
2319 // Check other loops
2320 $listofidtoclean = array();
2321 foreach ($listofparentid as $id => $pid) {
2322 // Check depth
2323 //print 'Analyse record id='.$id.' with parent '.$pid.'<br>';
2324
2325 $cursor = $id;
2326 $arrayidparsed = array(); // We start from child $id
2327 while ($cursor > 0) {
2328 $arrayidparsed[$cursor] = 1;
2329 if ($arrayidparsed[$listofparentid[$cursor]]) { // We detect a loop. A record with a parent that was already into child
2330 print 'Found a loop between id '.$id.' - '.$cursor.'<br>';
2331 unset($arrayidparsed);
2332 $listofidtoclean[$cursor] = $id;
2333 break;
2334 }
2335 $cursor = $listofparentid[$cursor];
2336 }
2337
2338 if (count($listofidtoclean)) {
2339 break;
2340 }
2341 }
2342
2343 $sql = "UPDATE ".MAIN_DB_PREFIX.$tabletocleantree;
2344 $sql .= " SET ".$fieldfkparent." = 0";
2345 $sql .= " WHERE rowid IN (".$db->sanitize(join(',', $listofidtoclean)).")"; // So we update only records detected wrong
2346 $resql = $db->query($sql);
2347 if ($resql) {
2348 $nb = $db->affected_rows($sql);
2349 if ($nb > 0) {
2350 // Removed orphelins records
2351 print '<br>Some records were detected to have parent that is a child, we set them as root record for id: ';
2352 print join(',', $listofidtoclean);
2353 }
2354
2355 $totalnb += $nb;
2356 }
2357 //else dol_print_error($db);
2358
2359 // Check and clean orphelins
2360 $sql = "UPDATE ".MAIN_DB_PREFIX.$tabletocleantree;
2361 $sql .= " SET ".$fieldfkparent." = 0";
2362 $sql .= " WHERE ".$fieldfkparent." NOT IN (".$db->sanitize(join(',', $listofid), 1).")"; // So we update only records linked to a non existing parent
2363 $resql = $db->query($sql);
2364 if ($resql) {
2365 $nb = $db->affected_rows($sql);
2366 if ($nb > 0) {
2367 // Removed orphelins records
2368 print '<br>Some orphelins were found and modified to be parent so records are visible again for id: ';
2369 print join(',', $listofid);
2370 }
2371
2372 $totalnb += $nb;
2373 }
2374 //else dol_print_error($db);
2375
2376 print '<br>We fixed '.$totalnb.' record(s). Some records may still be corrupted. New check may be required.';
2377 return $totalnb;
2378 }
2379 return -1;
2380}
2381
2382
2392function colorArrayToHex($arraycolor, $colorifnotfound = '888888')
2393{
2394 if (!is_array($arraycolor)) {
2395 return $colorifnotfound;
2396 }
2397 if (empty($arraycolor)) {
2398 return $colorifnotfound;
2399 }
2400 return sprintf("%02s", dechex($arraycolor[0])).sprintf("%02s", dechex($arraycolor[1])).sprintf("%02s", dechex($arraycolor[2]));
2401}
2402
2413function colorStringToArray($stringcolor, $colorifnotfound = array(88, 88, 88))
2414{
2415 if (is_array($stringcolor)) {
2416 return $stringcolor; // If already into correct output format, we return as is
2417 }
2418 $reg = array();
2419 $tmp = preg_match('/^#?([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])$/', $stringcolor, $reg);
2420 if (!$tmp) {
2421 $tmp = explode(',', $stringcolor);
2422 if (count($tmp) < 3) {
2423 return $colorifnotfound;
2424 }
2425 return $tmp;
2426 }
2427 return array(hexdec($reg[1]), hexdec($reg[2]), hexdec($reg[3]));
2428}
2429
2435function colorValidateHex($color, $allow_white = true)
2436{
2437 if (!$allow_white && ($color === '#fff' || $color === '#ffffff')) {
2438 return false;
2439 }
2440
2441 if (preg_match('/^#[a-f0-9]{6}$/i', $color)) { //hex color is valid
2442 return true;
2443 }
2444 return false;
2445}
2446
2456function colorAgressiveness($hex, $ratio = -50, $brightness = 0)
2457{
2458 if (empty($ratio)) {
2459 $ratio = 0; // To avoid null
2460 }
2461
2462 // Steps should be between -255 and 255. Negative = darker, positive = lighter
2463 $ratio = max(-100, min(100, $ratio));
2464
2465 // Normalize into a six character long hex string
2466 $hex = str_replace('#', '', $hex);
2467 if (strlen($hex) == 3) {
2468 $hex = str_repeat(substr($hex, 0, 1), 2).str_repeat(substr($hex, 1, 1), 2).str_repeat(substr($hex, 2, 1), 2);
2469 }
2470
2471 // Split into three parts: R, G and B
2472 $color_parts = str_split($hex, 2);
2473 $return = '#';
2474
2475 foreach ($color_parts as $color) {
2476 $color = hexdec($color); // Convert to decimal
2477 if ($ratio > 0) { // We increase aggressivity
2478 if ($color > 127) {
2479 $color += ((255 - $color) * ($ratio / 100));
2480 }
2481 if ($color < 128) {
2482 $color -= ($color * ($ratio / 100));
2483 }
2484 } else // We decrease agressiveness
2485 {
2486 if ($color > 128) {
2487 $color -= (($color - 128) * (abs($ratio) / 100));
2488 }
2489 if ($color < 127) {
2490 $color += ((128 - $color) * (abs($ratio) / 100));
2491 }
2492 }
2493 if ($brightness > 0) {
2494 $color = ($color * (100 + abs($brightness)) / 100);
2495 } else {
2496 $color = ($color * (100 - abs($brightness)) / 100);
2497 }
2498
2499 $color = max(0, min(255, $color)); // Adjust color to stay into valid range
2500 $return .= str_pad(dechex($color), 2, '0', STR_PAD_LEFT); // Make two char hex code
2501 }
2502
2503 //var_dump($hex.' '.$ratio.' -> '.$return);
2504 return $return;
2505}
2506
2513function colorAdjustBrightness($hex, $steps)
2514{
2515 // Steps should be between -255 and 255. Negative = darker, positive = lighter
2516 $steps = max(-255, min(255, $steps));
2517
2518 // Normalize into a six character long hex string
2519 $hex = str_replace('#', '', $hex);
2520 if (strlen($hex) == 3) {
2521 $hex = str_repeat(substr($hex, 0, 1), 2).str_repeat(substr($hex, 1, 1), 2).str_repeat(substr($hex, 2, 1), 2);
2522 }
2523
2524 // Split into three parts: R, G and B
2525 $color_parts = str_split($hex, 2);
2526 $return = '#';
2527
2528 foreach ($color_parts as $color) {
2529 $color = hexdec($color); // Convert to decimal
2530 $color = max(0, min(255, $color + $steps)); // Adjust color
2531 $return .= str_pad(dechex($color), 2, '0', STR_PAD_LEFT); // Make two char hex code
2532 }
2533
2534 return $return;
2535}
2536
2542function colorDarker($hex, $percent)
2543{
2544 $steps = intval(255 * $percent / 100) * -1;
2545 return colorAdjustBrightness($hex, $steps);
2546}
2547
2553function colorLighten($hex, $percent)
2554{
2555 $steps = intval(255 * $percent / 100);
2556 return colorAdjustBrightness($hex, $steps);
2557}
2558
2559
2566function colorHexToRgb($hex, $alpha = false, $returnArray = false)
2567{
2568 $string = '';
2569 $hex = str_replace('#', '', $hex);
2570 $length = strlen($hex);
2571 $rgb = array();
2572 $rgb['r'] = hexdec($length == 6 ? substr($hex, 0, 2) : ($length == 3 ? str_repeat(substr($hex, 0, 1), 2) : 0));
2573 $rgb['g'] = hexdec($length == 6 ? substr($hex, 2, 2) : ($length == 3 ? str_repeat(substr($hex, 1, 1), 2) : 0));
2574 $rgb['b'] = hexdec($length == 6 ? substr($hex, 4, 2) : ($length == 3 ? str_repeat(substr($hex, 2, 1), 2) : 0));
2575 if ($alpha !== false) {
2576 $rgb['a'] = floatval($alpha);
2577 $string = 'rgba('.implode(',', $rgb).')';
2578 } else {
2579 $string = 'rgb('.implode(',', $rgb).')';
2580 }
2581
2582 if ($returnArray) {
2583 return $rgb;
2584 } else {
2585 return $string;
2586 }
2587}
2588
2589
2597function cartesianArray(array $input)
2598{
2599 // filter out empty values
2600 $input = array_filter($input);
2601
2602 $result = array(array());
2603
2604 foreach ($input as $key => $values) {
2605 $append = array();
2606
2607 foreach ($result as $product) {
2608 foreach ($values as $item) {
2609 $product[$key] = $item;
2610 $append[] = $product;
2611 }
2612 }
2613
2614 $result = $append;
2615 }
2616
2617 return $result;
2618}
2619
2620
2627function getModuleDirForApiClass($moduleobject)
2628{
2629 $moduledirforclass = $moduleobject;
2630 if ($moduledirforclass != 'api') {
2631 $moduledirforclass = preg_replace('/api$/i', '', $moduledirforclass);
2632 }
2633
2634 if ($moduleobject == 'contracts') {
2635 $moduledirforclass = 'contrat';
2636 } elseif (in_array($moduleobject, array('admin', 'login', 'setup', 'access', 'status', 'tools', 'documents'))) {
2637 $moduledirforclass = 'api';
2638 } elseif ($moduleobject == 'contact' || $moduleobject == 'contacts' || $moduleobject == 'customer' || $moduleobject == 'thirdparty' || $moduleobject == 'thirdparties') {
2639 $moduledirforclass = 'societe';
2640 } elseif ($moduleobject == 'propale' || $moduleobject == 'proposals') {
2641 $moduledirforclass = 'comm/propal';
2642 } elseif ($moduleobject == 'agenda' || $moduleobject == 'agendaevents') {
2643 $moduledirforclass = 'comm/action';
2644 } elseif ($moduleobject == 'adherent' || $moduleobject == 'members' || $moduleobject == 'memberstypes' || $moduleobject == 'subscriptions') {
2645 $moduledirforclass = 'adherents';
2646 } elseif ($moduleobject == 'don' || $moduleobject == 'donations') {
2647 $moduledirforclass = 'don';
2648 } elseif ($moduleobject == 'banque' || $moduleobject == 'bankaccounts') {
2649 $moduledirforclass = 'compta/bank';
2650 } elseif ($moduleobject == 'category' || $moduleobject == 'categorie') {
2651 $moduledirforclass = 'categories';
2652 } elseif ($moduleobject == 'order' || $moduleobject == 'orders') {
2653 $moduledirforclass = 'commande';
2654 } elseif ($moduleobject == 'shipments') {
2655 $moduledirforclass = 'expedition';
2656 } elseif ($moduleobject == 'multicurrencies') {
2657 $moduledirforclass = 'multicurrency';
2658 } elseif ($moduleobject == 'facture' || $moduleobject == 'invoice' || $moduleobject == 'invoices') {
2659 $moduledirforclass = 'compta/facture';
2660 } elseif ($moduleobject == 'project' || $moduleobject == 'projects' || $moduleobject == 'task' || $moduleobject == 'tasks') {
2661 $moduledirforclass = 'projet';
2662 } elseif ($moduleobject == 'stock' || $moduleobject == 'stockmovements' || $moduleobject == 'warehouses') {
2663 $moduledirforclass = 'product/stock';
2664 } elseif ($moduleobject == 'supplierproposals' || $moduleobject == 'supplierproposal' || $moduleobject == 'supplier_proposal') {
2665 $moduledirforclass = 'supplier_proposal';
2666 } elseif ($moduleobject == 'fournisseur' || $moduleobject == 'supplierinvoices' || $moduleobject == 'supplierorders') {
2667 $moduledirforclass = 'fourn';
2668 } elseif ($moduleobject == 'ficheinter' || $moduleobject == 'interventions') {
2669 $moduledirforclass = 'fichinter';
2670 } elseif ($moduleobject == 'mos') {
2671 $moduledirforclass = 'mrp';
2672 } elseif ($moduleobject == 'accounting') {
2673 $moduledirforclass = 'accountancy';
2674 } elseif (in_array($moduleobject, array('products', 'expensereports', 'users', 'tickets', 'boms', 'receptions'))) {
2675 $moduledirforclass = preg_replace('/s$/', '', $moduleobject);
2676 }
2677
2678 return $moduledirforclass;
2679}
2680
2688function randomColorPart($min = 0, $max = 255)
2689{
2690 return str_pad(dechex(mt_rand($min, $max)), 2, '0', STR_PAD_LEFT);
2691}
2692
2700function randomColor($min = 0, $max = 255)
2701{
2702 return randomColorPart($min, $max).randomColorPart($min, $max).randomColorPart($min, $max);
2703}
2704
2705
2706if (!function_exists('dolEscapeXML')) {
2713 function dolEscapeXML($string)
2714 {
2715 return strtr($string, array('\''=>'&apos;', '"'=>'&quot;', '&'=>'&amp;', '<'=>'&lt;', '>'=>'&gt;'));
2716 }
2717}
2718
2719
2727{
2728 global $dolibarr_main_url_root;
2729 // Define $urlwithroot
2730 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
2731 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
2732 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
2733 $notetoshow = preg_replace('/src="[a-zA-Z0-9_\/\-\.]*(viewimage\.php\?modulepart=medias[^"]*)"/', 'src="'.$urlwithroot.'/\1"', $notetoshow);
2734 return $notetoshow;
2735}
2736
2745function price2fec($amount)
2746{
2747 global $conf;
2748
2749 // Clean parameters
2750 if (empty($amount)) {
2751 $amount = 0; // To have a numeric value if amount not defined or = ''
2752 }
2753 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number)
2754
2755 // Output decimal number by default
2756 $nbdecimal = (empty($conf->global->ACCOUNTING_FEC_DECIMAL_LENGTH) ? 2 : $conf->global->ACCOUNTING_FEC_DECIMAL_LENGTH);
2757
2758 // Output separators by default
2759 $dec = (empty($conf->global->ACCOUNTING_FEC_DECIMAL_SEPARATOR) ? ',' : $conf->global->ACCOUNTING_FEC_DECIMAL_SEPARATOR);
2760 $thousand = (empty($conf->global->ACCOUNTING_FEC_THOUSAND_SEPARATOR) ? '' : $conf->global->ACCOUNTING_FEC_THOUSAND_SEPARATOR);
2761
2762 // Format number
2763 $output = number_format($amount, $nbdecimal, $dec, $thousand);
2764
2765 return $output;
2766}
2767
2774function phpSyntaxError($code)
2775{
2776 if (!defined("CR")) {
2777 define("CR", "\r");
2778 }
2779 if (!defined("LF")) {
2780 define("LF", "\n");
2781 }
2782 if (!defined("CRLF")) {
2783 define("CRLF", "\r\n");
2784 }
2785
2786 $braces = 0;
2787 $inString = 0;
2788 foreach (token_get_all('<?php '.$code) as $token) {
2789 if (is_array($token)) {
2790 switch ($token[0]) {
2791 case T_CURLY_OPEN:
2792 case T_DOLLAR_OPEN_CURLY_BRACES:
2793 case T_START_HEREDOC:
2794 ++$inString;
2795 break;
2796 case T_END_HEREDOC:
2797 --$inString;
2798 break;
2799 }
2800 } elseif ($inString & 1) {
2801 switch ($token) {
2802 case '`':
2803 case '\'':
2804 case '"':
2805 --$inString;
2806 break;
2807 }
2808 } else {
2809 switch ($token) {
2810 case '`':
2811 case '\'':
2812 case '"':
2813 ++$inString;
2814 break;
2815 case '{':
2816 ++$braces;
2817 break;
2818 case '}':
2819 if ($inString) {
2820 --$inString;
2821 } else {
2822 --$braces;
2823 if ($braces < 0) {
2824 break 2;
2825 }
2826 }
2827 break;
2828 }
2829 }
2830 }
2831 $inString = @ini_set('log_errors', false);
2832 $token = @ini_set('display_errors', true);
2833 ob_start();
2834 $code = substr($code, strlen('<?php '));
2835 $braces || $code = "if(0){{$code}\n}";
2836 if (eval($code) === false) {
2837 if ($braces) {
2838 $braces = PHP_INT_MAX;
2839 } else {
2840 false !== strpos($code, CR) && $code = strtr(str_replace(CRLF, LF, $code), CR, LF);
2841 $braces = substr_count($code, LF);
2842 }
2843 $code = ob_get_clean();
2844 $code = strip_tags($code);
2845 if (preg_match("'syntax error, (.+) in .+ on line (\d+)$'s", $code, $code)) {
2846 $code[2] = (int) $code[2];
2847 $code = $code[2] <= $braces
2848 ? array($code[1], $code[2])
2849 : array('unexpected $end'.substr($code[1], 14), $braces);
2850 } else {
2851 $code = array('syntax error', 0);
2852 }
2853 } else {
2854 ob_end_clean();
2855 $code = false;
2856 }
2857 @ini_set('display_errors', $token);
2858 @ini_set('log_errors', $inString);
2859 return $code;
2860}
2861
2862
2869{
2870 global $user;
2871
2872 // If $acceptlocallinktomedia is true, we can add link media files int email templates (we already can do this into HTML editor of an email).
2873 // Note that local link to a file into medias are replaced with a real link by email in CMailFile.class.php with value $urlwithroot defined like this:
2874 // $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
2875 // $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
2876 $acceptlocallinktomedia = getDolGlobalInt('MAIN_DISALLOW_MEDIAS_IN_EMAIL_TEMPLATES') ? 0 : 1;
2877 if ($acceptlocallinktomedia) {
2878 global $dolibarr_main_url_root;
2879 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
2880
2881 // Parse $newUrl
2882 $newUrlArray = parse_url($urlwithouturlroot);
2883 $hosttocheck = $newUrlArray['host'];
2884 $hosttocheck = str_replace(array('[', ']'), '', $hosttocheck); // Remove brackets of IPv6
2885
2886 if (function_exists('gethostbyname')) {
2887 $iptocheck = gethostbyname($hosttocheck);
2888 } else {
2889 $iptocheck = $hosttocheck;
2890 }
2891
2892 //var_dump($iptocheck.' '.$acceptlocallinktomedia);
2893 if (!filter_var($iptocheck, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
2894 // If ip of public url is a private network IP, we do not allow this.
2895 $acceptlocallinktomedia = 0;
2896 // TODO Show a warning
2897 }
2898
2899 if (preg_match('/http:/i', $urlwithouturlroot)) {
2900 // If public url is not a https, we do not allow to add medias link. It will generate security alerts when email will be sent.
2901 $acceptlocallinktomedia = 0;
2902 // TODO Show a warning
2903 }
2904
2905 if (!empty($user->socid)) {
2906 $acceptlocallinktomedia = 0;
2907 }
2908 }
2909
2910 //return 1;
2911 return $acceptlocallinktomedia;
2912}
2913
2914
2922{
2923 $string = trim($string);
2924
2925 // If string does not start and end with parenthesis, we return $string as is.
2926 if (! preg_match('/^\‍(.*\‍)$/', $string)) {
2927 return $string;
2928 }
2929
2930 $nbofchars = dol_strlen($string);
2931 $i = 0; $g = 0;
2932 $countparenthesis = 0;
2933 while ($i < $nbofchars) {
2934 $char = dol_substr($string, $i, 1);
2935 if ($char == '(') {
2936 $countparenthesis++;
2937 } elseif ($char == ')') {
2938 $countparenthesis--;
2939 if ($countparenthesis <= 0) { // We reach the end of an independent group of parenthesis
2940 $g++;
2941 }
2942 }
2943 $i++;
2944 }
2945
2946 if ($g <= 1) {
2947 return preg_replace('/^\‍(/', '', preg_replace('/\‍)$/', '', $string));
2948 }
2949
2950 return $string;
2951}
Class to manage translations.
Class to manage Dolibarr users.
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:83
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:62
array2table($data, $tableMarkup=1, $tableoptions='', $troptions='', $tdoptions='')
Return an html table from an array.
dol_buildlogin($lastname, $firstname)
Build a login from lastname, firstname.
if(!function_exists( 'dolEscapeXML')) convertBackOfficeMediasLinksToPublicLinks($notetoshow)
Convert links to local wrapper to medias files into a string into a public external URL readable on i...
colorHexToRgb($hex, $alpha=false, $returnArray=false)
get_string_between($string, $start, $end)
Get string between.
dolObfuscateEmail($mail, $replace="*", $nbreplace=8, $nbdisplaymail=4, $nbdisplaydomain=3, $displaytld=true)
Returns an email value with obfuscated parts.
version_webserver()
Return web server version.
getModuleDirForApiClass($moduleobject)
Get name of directory where the api_...class.php file is stored.
phpSyntaxError($code)
Check the syntax of some PHP code.
dolGetModulesDirs($subdir='')
Return list of modules directories.
array2tr($data, $troptions='', $tdoptions='')
Return lines of an html table from an array Used by array2table function only.
version_dolibarr()
Return Dolibarr version.
binhex($bin, $pad=false, $upper=false)
Convert a binary data to string that represent hexadecimal value.
colorAgressiveness($hex, $ratio=-50, $brightness=0)
Change color to make it less aggressive (ratio is negative) or more aggressive (ratio is positive)
removeGlobalParenthesis($string)
Remove first and last parenthesis but only if first is the opening and last the closing of the same g...
cartesianArray(array $input)
Applies the Cartesian product algorithm to an array Source: http://stackoverflow.com/a/15973172.
getSoapParams()
Return array to use for SoapClient constructor.
colorAdjustBrightness($hex, $steps)
cleanCorruptedTree($db, $tabletocleantree, $fieldfkparent)
Clean corrupted tree (orphelins linked to a not existing parent), record linked to themself and child...
colorArrayToHex($arraycolor, $colorifnotfound='888888')
Convert an array with RGB value into hex RGB value.
dol_print_reduction($reduction, $langs)
Returns formated reduction.
dol_print_file($langs, $filename, $searchalt=0)
Output content of a file $filename in version of current language (otherwise may use an alternate lan...
colorStringToArray($stringcolor, $colorifnotfound=array(88, 88, 88))
Convert a string RGB value ('FFFFFF', '255,255,255') into an array RGB array(255,255,...
acceptLocalLinktoMedia()
Check the syntax of some PHP code.
randomColor($min=0, $max=255)
Return hexadecimal color randomly.
is_ip($ip)
This function evaluates a string that should be a valid IPv4 Note: For ip 169.254....
check_value($mask, $value)
Check value.
weight_convert($weight, &$from_unit, $to_unit)
Convertit une masse d'une unite vers une autre unite.
clean_url($url, $http=1)
Clean an url string.
version_php()
Return PHP version.
hexbin($hexa)
Convert an hexadecimal string into a binary string.
dol_set_user_param($db, $conf, &$user, $tab)
Save personnal parameter.
numero_semaine($time)
Retourne le numero de la semaine par rapport a une date.
randomColorPart($min=0, $max=255)
Return 2 hexa code randomly.
colorDarker($hex, $percent)
dolGetElementUrl($objectid, $objecttype, $withpicto=0, $option='')
Return link url to an object.
getListOfModels($db, $type, $maxfilenamelength=0)
Return list of activated modules usable for document generation.
dol_print_object_info($object, $usetable=0)
Show informations on an object TODO Move this into html.formother.
get_next_value($db, $mask, $table, $field, $where='', $objsoc='', $date='', $mode='next', $bentityon=true, $objuser=null, $forceentity=null)
Return last or next value for a mask (according to area we should not reset)
isValidUrl($url, $http=0, $pass=0, $port=0, $path=0, $query=0, $anchor=0)
Url string validation <http[s]> :// [user[:pass]@] hostname [port] [/path] [?getquery] [anchor].
isValidMailDomain($mail)
Return true if email has a domain name that can be resolved to MX type.
dolAddEmailTrackId($email, $trackingid)
Return an email formatted to include a tracking id For example myemail@example.com becom myemail+trac...
colorLighten($hex, $percent)
isValidVATID($company)
Check if VAT numero is valid (check done on syntax only, no database or remote access)
version_os($option='')
Return OS version.
dol_getDefaultFormat(Translate $outputlangs=null)
Try to guess default paper format according to language into $langs.
price2fec($amount)
Function to format a value into a defined format for French administration (no thousand separator & d...
jsUnEscape($source)
Same function than javascript unescape() function but in PHP.
colorValidateHex($color, $allow_white=true)
dol_html_entity_decode($a, $b, $c='UTF-8', $keepsomeentities=0)
Replace html_entity_decode functions to manage errors.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
isValidMXRecord($domain)
Return if the domain name has a valid MX record.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
isValidEmail($address, $acceptsupervisorkey=0, $acceptuserkey=0)
Return true if email syntax is ok.
utf8_check($str)
Check if a string is in UTF8.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.