dolibarr 21.0.0-alpha
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 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
10 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24 * or see https://www.gnu.org/
25 */
26
33// Enable this line to trace path when function is called.
34//print xdebug_print_function_stack('Functions2.lib was called');exit;
35
42function jsUnEscape($source)
43{
44 $decodedStr = "";
45 $pos = 0;
46 $len = strlen($source);
47 while ($pos < $len) {
48 $charAt = substr($source, $pos, 1);
49 if ($charAt == '%') {
50 $pos++;
51 $charAt = substr($source, $pos, 1);
52 if ($charAt == 'u') {
53 // we got a unicode character
54 $pos++;
55 $unicodeHexVal = substr($source, $pos, 4);
56 $unicode = hexdec($unicodeHexVal);
57 $entity = "&#".$unicode.';';
58 $decodedStr .= mb_convert_encoding($entity, 'UTF-8', 'ISO-8859-1');
59 $pos += 4;
60 } else {
61 // we have an escaped ascii character
62 $hexVal = substr($source, $pos, 2);
63 $decodedStr .= chr(hexdec($hexVal));
64 $pos += 2;
65 }
66 } else {
67 $decodedStr .= $charAt;
68 $pos++;
69 }
70 }
71 return dol_html_entity_decode($decodedStr, ENT_COMPAT | ENT_HTML5);
72}
73
74
84function dolGetModulesDirs($subdir = '')
85{
86 global $conf;
87
88 $modulesdir = array();
89
90 foreach ($conf->file->dol_document_root as $type => $dirroot) {
91 // Default core/modules dir
92 if ($type === 'main') {
93 $modulesdir[$dirroot.'/core/modules'.$subdir.'/'] = $dirroot.'/core/modules'.$subdir.'/';
94 }
95
96 // Scan dir from external modules
97 $handle = @opendir($dirroot);
98 if (is_resource($handle)) {
99 while (($file = readdir($handle)) !== false) {
100 if (preg_match('/disabled/', $file)) {
101 continue; // We discard module if it contains disabled into name.
102 }
103
104 if (substr($file, 0, 1) != '.' && is_dir($dirroot.'/'.$file) && strtoupper(substr($file, 0, 3)) != 'CVS' && $file != 'includes') {
105 if (is_dir($dirroot.'/'.$file.'/core/modules'.$subdir.'/')) {
106 $modulesdir[$dirroot.'/'.$file.'/core/modules'.$subdir.'/'] = $dirroot.'/'.$file.'/core/modules'.$subdir.'/';
107 }
108 }
109 }
110 closedir($handle);
111 }
112 }
113 return $modulesdir;
114}
115
116
123function dol_getDefaultFormat(Translate $outputlangs = null)
124{
125 global $langs;
126
127 $selected = 'EUA4';
128 if (!$outputlangs) {
129 $outputlangs = $langs;
130 }
131
132 if ($outputlangs->defaultlang == 'ca_CA') {
133 $selected = 'CAP4'; // Canada
134 }
135 if ($outputlangs->defaultlang == 'en_US') {
136 $selected = 'USLetter'; // US
137 }
138 return $selected;
139}
140
141
150function dol_print_object_info($object, $usetable = 0)
151{
152 global $langs, $db;
153
154 // Load translation files required by the page
155 $langs->loadLangs(array('other', 'admin'));
156
157 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
158
159 $deltadateforserver = getServerTimeZoneInt('now');
160 $deltadateforclient = ((int) $_SESSION['dol_tz'] + (int) $_SESSION['dol_dst']);
161 //$deltadateforcompany=((int) $_SESSION['dol_tz'] + (int) $_SESSION['dol_dst']);
162 $deltadateforuser = round($deltadateforclient - $deltadateforserver);
163 //print "x".$deltadateforserver." - ".$deltadateforclient." - ".$deltadateforuser;
164
165 if ($usetable) {
166 print '<table class="border tableforfield centpercent">';
167 }
168
169 // Import key
170 if (!empty($object->import_key)) {
171 if ($usetable) {
172 print '<tr><td class="titlefield">';
173 }
174 print $langs->trans("ImportedWithSet");
175 if ($usetable) {
176 print '</td><td>';
177 } else {
178 print ': ';
179 }
180 print $object->import_key;
181 if ($usetable) {
182 print '</td></tr>';
183 } else {
184 print '<br>';
185 }
186 }
187
188 // User creation (old method using already loaded object and not id is kept for backward compatibility)
189 if (!empty($object->user_creation) || !empty($object->user_creation_id)) {
190 if ($usetable) {
191 print '<tr><td class="titlefield">';
192 }
193 print $langs->trans("CreatedBy");
194 if ($usetable) {
195 print '</td><td>';
196 } else {
197 print ': ';
198 }
199 if (! empty($object->user_creation) && is_object($object->user_creation)) { // deprecated mode
200 if ($object->user_creation->id) {
201 print $object->user_creation->getNomUrl(-1, '', 0, 0, 0);
202 } else {
203 print $langs->trans("Unknown");
204 }
205 } else {
206 $userstatic = new User($db);
207 $userstatic->fetch($object->user_creation_id);
208 if ($userstatic->id) {
209 print $userstatic->getNomUrl(-1, '', 0, 0, 0);
210 } else {
211 print $langs->trans("Unknown");
212 }
213 }
214 if ($usetable) {
215 print '</td></tr>';
216 } else {
217 print '<br>';
218 }
219 }
220
221 // Date creation
222 if (!empty($object->date_creation)) {
223 if ($usetable) {
224 print '<tr><td class="titlefield">';
225 }
226 print $langs->trans("DateCreation");
227 if ($usetable) {
228 print '</td><td>';
229 } else {
230 print ': ';
231 }
232 print dol_print_date($object->date_creation, 'dayhour', 'tzserver');
233 if ($deltadateforuser) {
234 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>';
235 }
236 if ($usetable) {
237 print '</td></tr>';
238 } else {
239 print '<br>';
240 }
241 }
242
243 // User change (old method using already loaded object and not id is kept for backward compatibility)
244 if (!empty($object->user_modification) || !empty($object->user_modification_id)) {
245 if ($usetable) {
246 print '<tr><td class="titlefield">';
247 }
248 print $langs->trans("ModifiedBy");
249 if ($usetable) {
250 print '</td><td>';
251 } else {
252 print ': ';
253 }
254 if (is_object($object->user_modification)) {
255 if ($object->user_modification->id) {
256 print $object->user_modification->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_modification_id);
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 change
277 if (!empty($object->date_modification)) {
278 if ($usetable) {
279 print '<tr><td class="titlefield">';
280 }
281 print $langs->trans("DateLastModification");
282 if ($usetable) {
283 print '</td><td>';
284 } else {
285 print ': ';
286 }
287 print dol_print_date($object->date_modification, 'dayhour', 'tzserver');
288 if ($deltadateforuser) {
289 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>';
290 }
291 if ($usetable) {
292 print '</td></tr>';
293 } else {
294 print '<br>';
295 }
296 }
297
298 // User validation (old method using already loaded object and not id is kept for backward compatibility)
299 if (!empty($object->user_validation) || !empty($object->user_validation_id)) {
300 if ($usetable) {
301 print '<tr><td class="titlefield">';
302 }
303 print $langs->trans("ValidatedBy");
304 if ($usetable) {
305 print '</td><td>';
306 } else {
307 print ': ';
308 }
309 if (is_object($object->user_validation)) {
310 if ($object->user_validation->id) {
311 print $object->user_validation->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_validation_id ? $object->user_validation_id : $object->user_validation);
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 validation
332 if (!empty($object->date_validation)) {
333 if ($usetable) {
334 print '<tr><td class="titlefield">';
335 }
336 print $langs->trans("DateValidation");
337 if ($usetable) {
338 print '</td><td>';
339 } else {
340 print ': ';
341 }
342 print dol_print_date($object->date_validation, 'dayhour', 'tzserver');
343 if ($deltadateforuser) {
344 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>';
345 }
346 if ($usetable) {
347 print '</td></tr>';
348 } else {
349 print '<br>';
350 }
351 }
352
353 // User approve (old method using already loaded object and not id is kept for backward compatibility)
354 if (!empty($object->user_approve) || !empty($object->user_approve_id)) {
355 if ($usetable) {
356 print '<tr><td class="titlefield">';
357 }
358 print $langs->trans("ApprovedBy");
359 if ($usetable) {
360 print '</td><td>';
361 } else {
362 print ': ';
363 }
364 if (!empty($object->user_approve) && is_object($object->user_approve)) {
365 if ($object->user_approve->id) {
366 print $object->user_approve->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_approve_id ? $object->user_approve_id : $object->user_approve);
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 approve
387 if (!empty($object->date_approve) || !empty($object->date_approval)) {
388 if ($usetable) {
389 print '<tr><td class="titlefield">';
390 }
391 print $langs->trans("DateApprove");
392 if ($usetable) {
393 print '</td><td>';
394 } else {
395 print ': ';
396 }
397 print dol_print_date($object->date_approve ? $object->date_approve : $object->date_approval, 'dayhour', 'tzserver');
398 if ($deltadateforuser) {
399 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>';
400 }
401 if ($usetable) {
402 print '</td></tr>';
403 } else {
404 print '<br>';
405 }
406 }
407
408 // User approve
409 if (!empty($object->user_approve_id2)) {
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 $userstatic = new User($db);
420 $userstatic->fetch($object->user_approve_id2);
421 if ($userstatic->id) {
422 print $userstatic->getNomUrl(-1, '', 0, 0, 0);
423 } else {
424 print $langs->trans("Unknown");
425 }
426 if ($usetable) {
427 print '</td></tr>';
428 } else {
429 print '<br>';
430 }
431 }
432
433 // Date approve
434 if (!empty($object->date_approve2)) {
435 if ($usetable) {
436 print '<tr><td class="titlefield">';
437 }
438 print $langs->trans("DateApprove2");
439 if ($usetable) {
440 print '</td><td>';
441 } else {
442 print ': ';
443 }
444 print dol_print_date($object->date_approve2, 'dayhour', 'tzserver');
445 if ($deltadateforuser) {
446 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>';
447 }
448 if ($usetable) {
449 print '</td></tr>';
450 } else {
451 print '<br>';
452 }
453 }
454
455 // User signature
456 if (!empty($object->user_signature) || !empty($object->user_signature_id)) {
457 if ($usetable) {
458 print '<tr><td class="titlefield">';
459 }
460 print $langs->trans('SignedBy');
461 if ($usetable) {
462 print '</td><td>';
463 } else {
464 print ': ';
465 }
466 if (is_object($object->user_signature)) {
467 if ($object->user_signature->id) {
468 print $object->user_signature->getNomUrl(-1, '', 0, 0, 0);
469 } else {
470 print $langs->trans('Unknown');
471 }
472 } else {
473 $userstatic = new User($db);
474 $userstatic->fetch($object->user_signature_id ? $object->user_signature_id : $object->user_signature);
475 if ($userstatic->id) {
476 print $userstatic->getNomUrl(-1, '', 0, 0, 0);
477 } else {
478 print $langs->trans('Unknown');
479 }
480 }
481 if ($usetable) {
482 print '</td></tr>';
483 } else {
484 print '<br>';
485 }
486 }
487
488 // Date signature
489 if (!empty($object->date_signature)) {
490 if ($usetable) {
491 print '<tr><td class="titlefield">';
492 }
493 print $langs->trans('DateSigning');
494 if ($usetable) {
495 print '</td><td>';
496 } else {
497 print ': ';
498 }
499 print dol_print_date($object->date_signature, 'dayhour');
500 if ($deltadateforuser) {
501 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>';
502 }
503 if ($usetable) {
504 print '</td></tr>';
505 } else {
506 print '<br>';
507 }
508 }
509
510 // User close
511 if (!empty($object->user_closing_id)) {
512 if ($usetable) {
513 print '<tr><td class="titlefield">';
514 }
515 print $langs->trans("ClosedBy");
516 if ($usetable) {
517 print '</td><td>';
518 } else {
519 print ': ';
520 }
521 $userstatic = new User($db);
522 $userstatic->fetch($object->user_closing_id);
523 if ($userstatic->id) {
524 print $userstatic->getNomUrl(-1, '', 0, 0, 0);
525 } else {
526 print $langs->trans("Unknown");
527 }
528 if ($usetable) {
529 print '</td></tr>';
530 } else {
531 print '<br>';
532 }
533 }
534
535 // Date close
536 if (!empty($object->date_cloture) || !empty($object->date_closing)) {
537 if (isset($object->date_cloture) && !empty($object->date_cloture)) {
538 $object->date_closing = $object->date_cloture;
539 }
540 if ($usetable) {
541 print '<tr><td class="titlefield">';
542 }
543 print $langs->trans("DateClosing");
544 if ($usetable) {
545 print '</td><td>';
546 } else {
547 print ': ';
548 }
549 print dol_print_date($object->date_closing, 'dayhour', 'tzserver');
550 if ($deltadateforuser) {
551 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>';
552 }
553 if ($usetable) {
554 print '</td></tr>';
555 } else {
556 print '<br>';
557 }
558 }
559
560 // User conciliate
561 if (!empty($object->user_rappro) || !empty($object->user_rappro_id)) {
562 if ($usetable) {
563 print '<tr><td class="titlefield">';
564 }
565 print $langs->trans("ReconciledBy");
566 if ($usetable) {
567 print '</td><td>';
568 } else {
569 print ': ';
570 }
571 if (is_object($object->user_rappro)) {
572 if ($object->user_rappro->id) {
573 print $object->user_rappro->getNomUrl(-1, '', 0, 0, 0);
574 } else {
575 print $langs->trans("Unknown");
576 }
577 } else {
578 $userstatic = new User($db);
579 $userstatic->fetch($object->user_rappro_id ? $object->user_rappro_id : $object->user_rappro);
580 if ($userstatic->id) {
581 print $userstatic->getNomUrl(1, '', 0, 0, 0);
582 } else {
583 print $langs->trans("Unknown");
584 }
585 }
586 if ($usetable) {
587 print '</td></tr>';
588 } else {
589 print '<br>';
590 }
591 }
592
593 // Date conciliate
594 if (!empty($object->date_rappro)) {
595 if ($usetable) {
596 print '<tr><td class="titlefield">';
597 }
598 print $langs->trans("DateConciliating");
599 if ($usetable) {
600 print '</td><td>';
601 } else {
602 print ': ';
603 }
604 print dol_print_date($object->date_rappro, 'dayhour', 'tzserver');
605 if ($deltadateforuser) {
606 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>';
607 }
608 if ($usetable) {
609 print '</td></tr>';
610 } else {
611 print '<br>';
612 }
613 }
614
615 // Date send
616 if (!empty($object->date_envoi)) {
617 if ($usetable) {
618 print '<tr><td class="titlefield">';
619 }
620 print $langs->trans("DateLastSend");
621 if ($usetable) {
622 print '</td><td>';
623 } else {
624 print ': ';
625 }
626 print dol_print_date($object->date_envoi, 'dayhour', 'tzserver');
627 if ($deltadateforuser) {
628 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>';
629 }
630 if ($usetable) {
631 print '</td></tr>';
632 } else {
633 print '<br>';
634 }
635 }
636
637 if ($usetable) {
638 print '</table>';
639 }
640}
641
642
651function dolAddEmailTrackId($email, $trackingid)
652{
653 $tmp = explode('@', $email);
654 return $tmp[0].'+'.$trackingid.'@'.(isset($tmp[1]) ? $tmp[1] : '');
655}
656
663function isValidMailDomain($mail)
664{
665 list($user, $domain) = explode("@", $mail, 2);
666 return ($domain ? isValidMXRecord($domain) : 0);
667}
668
682function isValidUrl($url, $http = 0, $pass = 0, $port = 0, $path = 0, $query = 0, $anchor = 0)
683{
684 $ValidUrl = 0;
685 $urlregex = '';
686
687 // SCHEME
688 if ($http) {
689 $urlregex .= "^(http:\/\/|https:\/\/)";
690 }
691
692 // USER AND PASS
693 if ($pass) {
694 $urlregex .= "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)";
695 }
696
697 // HOSTNAME OR IP
698 //$urlregex .= "[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)*"; // x allowed (ex. http://localhost, http://routerlogin)
699 //$urlregex .= "[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)+"; // x.x
700 $urlregex .= "([a-z0-9+\$_\\\:-])+(\.[a-z0-9+\$_-][a-z0-9+\$_-]+)*"; // x ou x.xx (2 x ou plus)
701 //use only one of the above
702
703 // PORT
704 if ($port) {
705 $urlregex .= "(\:[0-9]{2,5})";
706 }
707 // PATH
708 if ($path) {
709 $urlregex .= "(\/([a-z0-9+\$_-]\.?)+)*\/";
710 }
711 // GET Query
712 if ($query) {
713 $urlregex .= "(\?[a-z+&\$_.-][a-z0-9;:@\/&%=+\$_.-]*)";
714 }
715 // ANCHOR
716 if ($anchor) {
717 $urlregex .= "(#[a-z_.-][a-z0-9+\$_.-]*)$";
718 }
719
720 // check
721 if (preg_match('/'.$urlregex.'/i', $url)) {
722 $ValidUrl = 1;
723 }
724 //print $urlregex.' - '.$url.' - '.$ValidUrl;
725
726 return $ValidUrl;
727}
728
735function isValidVATID($company)
736{
737 if ($company->isInEEC()) { // Syntax check rules for EEC countries
738 /* Disabled because some companies can have an address in Irland and a vat number in France.
739 $vatprefix = $company->country_code;
740 if ($vatprefix == 'GR') $vatprefix = '(EL|GR)';
741 elseif ($vatprefix == 'MC') $vatprefix = 'FR'; // Monaco is using french VAT numbers
742 else $vatprefix = preg_quote($vatprefix, '/');*/
743 $vatprefix = '[a-zA-Z][a-zA-Z]';
744 if (!preg_match('/^'.$vatprefix.'[a-zA-Z0-9\-\.]{5,14}$/i', str_replace(' ', '', $company->tva_intra))) {
745 return 0;
746 }
747 }
748
749 return 1;
750}
751
759function clean_url($url, $http = 1)
760{
761 // Fixed by Matelli (see http://matelli.fr/showcases/patch%73-dolibarr/fix-cleaning-url.html)
762 // To include the minus sign in a char class, we must not escape it but put it at the end of the class
763 // Also, there's no need of escape a dot sign in a class
764 $regs = array();
765 if (preg_match('/^(https?:[\\/]+)?([0-9A-Z.-]+\.[A-Z]{2,4})(:[0-9]+)?/i', $url, $regs)) {
766 $proto = $regs[1];
767 $domain = $regs[2];
768 $port = isset($regs[3]) ? $regs[3] : '';
769 //print $url." -> ".$proto." - ".$domain." - ".$port;
770 //$url = dol_string_nospecial(trim($url));
771 $url = trim($url);
772
773 // Si http: defini on supprime le http (Si https on ne supprime pas)
774 $newproto = $proto;
775 if ($http == 0) {
776 if (preg_match('/^http:[\\/]+/i', $url)) {
777 $url = preg_replace('/^http:[\\/]+/i', '', $url);
778 $newproto = '';
779 }
780 }
781
782 // On passe le nom de domaine en minuscule
783 $CleanUrl = preg_replace('/^'.preg_quote($proto.$domain, '/').'/i', $newproto.strtolower($domain), $url);
784
785 return $CleanUrl;
786 } else {
787 return $url;
788 }
789}
790
791
792
804function dolObfuscateEmail($mail, $replace = "*", $nbreplace = 8, $nbdisplaymail = 4, $nbdisplaydomain = 3, $displaytld = true)
805{
806 if (!isValidEmail($mail)) {
807 return '';
808 }
809 $tab = explode('@', $mail);
810 $tab2 = explode('.', $tab[1]);
811 $string_replace = '';
812 $mail_name = $tab[0];
813 $mail_domaine = $tab2[0];
814 $mail_tld = '';
815
816 $nbofelem = count($tab2);
817 for ($i = 1; $i < $nbofelem && $displaytld; $i++) {
818 $mail_tld .= '.'.$tab2[$i];
819 }
820
821 for ($i = 0; $i < $nbreplace; $i++) {
822 $string_replace .= $replace;
823 }
824
825 if (strlen($mail_name) > $nbdisplaymail) {
826 $mail_name = substr($mail_name, 0, $nbdisplaymail);
827 }
828
829 if (strlen($mail_domaine) > $nbdisplaydomain) {
830 $mail_domaine = substr($mail_domaine, strlen($mail_domaine) - $nbdisplaydomain);
831 }
832
833 return $mail_name.$string_replace.$mail_domaine.$mail_tld;
834}
835
836
846function array2tr($data, $troptions = '', $tdoptions = '')
847{
848 $text = '<tr '.$troptions.'>';
849 foreach ($data as $key => $item) {
850 $text .= '<td '.$tdoptions.'>'.$item.'</td>';
851 }
852 $text .= '</tr>';
853 return $text;
854}
855
866function array2table($data, $tableMarkup = 1, $tableoptions = '', $troptions = '', $tdoptions = '')
867{
868 $text = '';
869 if ($tableMarkup) {
870 $text = '<table '.$tableoptions.'>';
871 }
872 foreach ($data as $key => $item) {
873 if (is_array($item)) {
874 $text .= array2tr($item, $troptions, $tdoptions);
875 } else {
876 $text .= '<tr '.$troptions.'>';
877 $text .= '<td '.$tdoptions.'>'.$key.'</td>';
878 $text .= '<td '.$tdoptions.'>'.$item.'</td>';
879 $text .= '</tr>';
880 }
881 }
882 if ($tableMarkup) {
883 $text .= '</table>';
884 }
885 return $text;
886}
887
904function get_next_value($db, $mask, $table, $field, $where = '', $objsoc = '', $date = '', $mode = 'next', $bentityon = true, $objuser = null, $forceentity = null)
905{
906 global $user;
907
908 if (!is_object($objsoc)) {
909 $valueforccc = $objsoc;
910 } elseif ($table == "commande_fournisseur" || $table == "facture_fourn" || $table == "paiementfourn") {
911 $valueforccc = dol_string_unaccent($objsoc->code_fournisseur);
912 } else {
913 $valueforccc = dol_string_unaccent($objsoc->code_client);
914 }
915
916 $sharetable = $table;
917 if ($table == 'facture' || $table == 'invoice') {
918 $sharetable = 'invoicenumber'; // for getEntity function
919 }
920
921 // Clean parameters
922 if ($date == '') {
923 $date = dol_now(); // We use local year and month of PHP server to search numbers
924 }
925 // but we should use local year and month of user
926
927 // For debugging
928 //dol_syslog("mask=".$mask, LOG_DEBUG);
929 //include_once(DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php');
930 //$mask='FA{yy}{mm}-{0000@99}';
931 //$date=dol_mktime(12, 0, 0, 1, 1, 1900);
932 //$date=dol_stringtotime('20130101');
933
934 $hasglobalcounter = false;
935 $reg = array();
936 // Extract value for mask counter, mask raz and mask offset
937 if (preg_match('/\{(0+)([@\+][0-9\-\+\=]+)?([@\+][0-9\-\+\=]+)?\}/i', $mask, $reg)) {
938 $masktri = $reg[1].(!empty($reg[2]) ? $reg[2] : '').(!empty($reg[3]) ? $reg[3] : '');
939 $maskcounter = $reg[1];
940 $hasglobalcounter = true;
941 } else {
942 // setting some defaults so the rest of the code won't fail if there is a third party counter
943 $masktri = '00000';
944 $maskcounter = '00000';
945 }
946
947 $maskraz = -1;
948 $maskoffset = 0;
949 $resetEveryMonth = false;
950 if (dol_strlen($maskcounter) < 3 && !getDolGlobalString('MAIN_COUNTER_WITH_LESS_3_DIGITS')) {
951 return 'ErrorCounterMustHaveMoreThan3Digits';
952 }
953
954 // Extract value for third party mask counter
955 $regClientRef = array();
956 if (preg_match('/\{(c+)(0*)\}/i', $mask, $regClientRef)) {
957 $maskrefclient = $regClientRef[1].$regClientRef[2];
958 $maskrefclient_maskclientcode = $regClientRef[1];
959 $maskrefclient_maskcounter = $regClientRef[2];
960 $maskrefclient_maskoffset = 0; //default value of maskrefclient_counter offset
961 $maskrefclient_clientcode = substr($valueforccc, 0, dol_strlen($maskrefclient_maskclientcode)); //get n first characters of client code where n is length in mask
962 $maskrefclient_clientcode = str_pad($maskrefclient_clientcode, dol_strlen($maskrefclient_maskclientcode), "#", STR_PAD_RIGHT); //padding maskrefclient_clientcode for having exactly n characters in maskrefclient_clientcode
963 $maskrefclient_clientcode = dol_string_nospecial($maskrefclient_clientcode); //sanitize maskrefclient_clientcode for sql insert and sql select like
964 if (dol_strlen($maskrefclient_maskcounter) > 0 && dol_strlen($maskrefclient_maskcounter) < 3) {
965 return 'ErrorCounterMustHaveMoreThan3Digits';
966 }
967 } else {
968 $maskrefclient = '';
969 }
970
971 // fail if there is neither a global nor a third party counter
972 if (!$hasglobalcounter && ($maskrefclient_maskcounter == '')) {
973 return 'ErrorBadMask';
974 }
975
976 // Extract value for third party type
977 $regType = array();
978 if (preg_match('/\{(t+)\}/i', $mask, $regType)) {
979 $masktype = $regType[1];
980 $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)
981 $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
982 } else {
983 $masktype = '';
984 $masktype_value = '';
985 }
986
987 // Extract value for user
988 $regType = array();
989 if (preg_match('/\{(u+)\}/i', $mask, $regType)) {
990 $lastname = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
991 if (is_object($objuser)) {
992 $lastname = $objuser->lastname;
993 }
994
995 $maskuser = $regType[1];
996 $maskuser_value = substr($lastname, 0, dol_strlen($regType[1])); // get n first characters of user firstname (where n is length in mask)
997 $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
998 } else {
999 $maskuser = '';
1000 $maskuser_value = '';
1001 }
1002
1003 // Personalized field {XXX-1} à {XXX-9}
1004 $maskperso = array();
1005 $maskpersonew = array();
1006 $tmpmask = $mask;
1007 $regKey = array();
1008 while (preg_match('/\{([A-Z]+)\-([1-9])\}/', $tmpmask, $regKey)) {
1009 $maskperso[$regKey[1]] = '{'.$regKey[1].'-'.$regKey[2].'}';
1010 // @phan-suppress-next-line PhanParamSuspiciousOrder
1011 $maskpersonew[$regKey[1]] = str_pad('', (int) $regKey[2], '_', STR_PAD_RIGHT);
1012 $tmpmask = preg_replace('/\{'.$regKey[1].'\-'.$regKey[2].'\}/i', $maskpersonew[$regKey[1]], $tmpmask);
1013 }
1014
1015 if (strstr($mask, 'user_extra_')) {
1016 $start = "{user_extra_";
1017 $end = "\}";
1018 $extra = get_string_between($mask, "user_extra_", "}");
1019 if (!empty($user->array_options['options_'.$extra])) {
1020 $mask = preg_replace('#('.$start.')(.*?)('.$end.')#si', $user->array_options['options_'.$extra], $mask);
1021 }
1022 }
1023 $maskwithonlyymcode = $mask;
1024 $maskwithonlyymcode = preg_replace('/\{(0+)([@\+][0-9\-\+\=]+)?([@\+][0-9\-\+\=]+)?\}/i', $maskcounter, $maskwithonlyymcode);
1025 $maskwithonlyymcode = preg_replace('/\{dd\}/i', 'dd', $maskwithonlyymcode);
1026 $maskwithonlyymcode = preg_replace('/\{(c+)(0*)\}/i', $maskrefclient, $maskwithonlyymcode);
1027 $maskwithonlyymcode = preg_replace('/\{(t+)\}/i', $masktype_value, $maskwithonlyymcode);
1028 $maskwithonlyymcode = preg_replace('/\{(u+)\}/i', $maskuser_value, $maskwithonlyymcode);
1029 foreach ($maskperso as $key => $val) {
1030 $maskwithonlyymcode = preg_replace('/'.preg_quote($val, '/').'/i', $maskpersonew[$key], $maskwithonlyymcode);
1031 }
1032 $maskwithnocode = $maskwithonlyymcode;
1033 $maskwithnocode = preg_replace('/\{yyyy\}/i', 'yyyy', $maskwithnocode);
1034 $maskwithnocode = preg_replace('/\{yy\}/i', 'yy', $maskwithnocode);
1035 $maskwithnocode = preg_replace('/\{y\}/i', 'y', $maskwithnocode);
1036 $maskwithnocode = preg_replace('/\{mm\}/i', 'mm', $maskwithnocode);
1037 // Now maskwithnocode = 0000ddmmyyyyccc for example
1038 // and maskcounter = 0000 for example
1039 //print "maskwithonlyymcode=".$maskwithonlyymcode." maskwithnocode=".$maskwithnocode."\n<br>";
1040 //var_dump($reg);
1041
1042 // If an offset is asked
1043 if (!empty($reg[2]) && preg_match('/^\+/', $reg[2])) {
1044 $maskoffset = preg_replace('/^\+/', '', $reg[2]);
1045 }
1046 if (!empty($reg[3]) && preg_match('/^\+/', $reg[3])) {
1047 $maskoffset = preg_replace('/^\+/', '', $reg[3]);
1048 }
1049
1050 // Define $sqlwhere
1051 $sqlwhere = '';
1052 $yearoffset = 0; // Use year of current $date by default
1053 $yearoffsettype = false; // false: no reset, 0,-,=,+: reset at offset SOCIETE_FISCAL_MONTH_START, x=reset at offset x
1054
1055 // If a restore to zero after a month is asked we check if there is already a value for this year.
1056 if (!empty($reg[2]) && preg_match('/^@/', $reg[2])) {
1057 $yearoffsettype = preg_replace('/^@/', '', $reg[2]);
1058 }
1059 if (!empty($reg[3]) && preg_match('/^@/', $reg[3])) {
1060 $yearoffsettype = preg_replace('/^@/', '', $reg[3]);
1061 }
1062
1063 //print "yearoffset=".$yearoffset." yearoffsettype=".$yearoffsettype;
1064 if (is_numeric($yearoffsettype) && $yearoffsettype >= 1) {
1065 $maskraz = $yearoffsettype; // For backward compatibility
1066 } elseif ($yearoffsettype === '0' || (!empty($yearoffsettype) && !is_numeric($yearoffsettype) && getDolGlobalInt('SOCIETE_FISCAL_MONTH_START') > 1)) {
1067 $maskraz = getDolGlobalString('SOCIETE_FISCAL_MONTH_START');
1068 }
1069 //print "maskraz=".$maskraz; // -1=no reset
1070
1071 if ($maskraz > 0) { // A reset is required
1072 if ($maskraz == 99) {
1073 $maskraz = (int) date('m', $date);
1074 $resetEveryMonth = true;
1075 }
1076 if ($maskraz > 12) {
1077 return 'ErrorBadMaskBadRazMonth';
1078 }
1079
1080 // Define posy, posm and reg
1081 if ($maskraz > 1) { // if reset is not first month, we need month and year into mask
1082 if (preg_match('/^(.*)\{(y+)\}\{(m+)\}/i', $maskwithonlyymcode, $reg)) {
1083 $posy = 2;
1084 $posm = 3;
1085 } elseif (preg_match('/^(.*)\{(m+)\}\{(y+)\}/i', $maskwithonlyymcode, $reg)) {
1086 $posy = 3;
1087 $posm = 2;
1088 } else {
1089 return 'ErrorCantUseRazInStartedYearIfNoYearMonthInMask';
1090 }
1091
1092 if (dol_strlen($reg[$posy]) < 2) {
1093 return 'ErrorCantUseRazWithYearOnOneDigit';
1094 }
1095 } else { // if reset is for a specific month in year, we need year
1096 if (preg_match('/^(.*)\{(m+)\}\{(y+)\}/i', $maskwithonlyymcode, $reg)) {
1097 $posy = 3;
1098 $posm = 2;
1099 } elseif (preg_match('/^(.*)\{(y+)\}\{(m+)\}/i', $maskwithonlyymcode, $reg)) {
1100 $posy = 2;
1101 $posm = 3;
1102 } elseif (preg_match('/^(.*)\{(y+)\}/i', $maskwithonlyymcode, $reg)) {
1103 $posy = 2;
1104 $posm = 0;
1105 } else {
1106 return 'ErrorCantUseRazIfNoYearInMask';
1107 }
1108 }
1109 // Define length
1110 $yearlen = $posy ? dol_strlen($reg[$posy]) : 0;
1111 $monthlen = $posm ? dol_strlen($reg[$posm]) : 0;
1112 // Define pos
1113 $yearpos = (dol_strlen($reg[1]) + 1);
1114 $monthpos = ($yearpos + $yearlen);
1115 if ($posy == 3 && $posm == 2) { // if month is before year
1116 $monthpos = (dol_strlen($reg[1]) + 1);
1117 $yearpos = ($monthpos + $monthlen);
1118 }
1119 //print "xxx ".$maskwithonlyymcode." maskraz=".$maskraz." posy=".$posy." yearlen=".$yearlen." yearpos=".$yearpos." posm=".$posm." monthlen=".$monthlen." monthpos=".$monthpos." yearoffsettype=".$yearoffsettype." resetEveryMonth=".$resetEveryMonth."\n";
1120
1121 // Define $yearcomp and $monthcomp (that will be use in the select where to search max number)
1122 $monthcomp = $maskraz;
1123 $yearcomp = 0;
1124
1125 if (!empty($yearoffsettype) && !is_numeric($yearoffsettype) && $yearoffsettype != '=') { // $yearoffsettype is - or +
1126 $currentyear = (int) date("Y", $date);
1127 $fiscaldate = dol_mktime(0, 0, 0, $maskraz, 1, $currentyear);
1128 $newyeardate = dol_mktime(0, 0, 0, 1, 1, $currentyear);
1129 $nextnewyeardate = dol_mktime(0, 0, 0, 1, 1, $currentyear + 1);
1130 //echo 'currentyear='.$currentyear.' date='.dol_print_date($date, 'day').' fiscaldate='.dol_print_date($fiscaldate, 'day').'<br>';
1131
1132 // If after or equal of current fiscal date
1133 if ($date >= $fiscaldate) {
1134 // If before of next new year date
1135 if ($date < $nextnewyeardate && $yearoffsettype == '+') {
1136 $yearoffset = 1;
1137 }
1138 } elseif ($date >= $newyeardate && $yearoffsettype == '-') {
1139 // If after or equal of current new year date
1140 $yearoffset = -1;
1141 }
1142 } elseif ((int) date("m", $date) < $maskraz && empty($resetEveryMonth)) {
1143 // For backward compatibility
1144 $yearoffset = -1;
1145 } // If current month lower that month of return to zero, year is previous year
1146
1147 if ($yearlen == 4) {
1148 $yearcomp = sprintf("%04d", idate("Y", $date) + $yearoffset);
1149 } elseif ($yearlen == 2) {
1150 $yearcomp = sprintf("%02d", idate("y", $date) + $yearoffset);
1151 } elseif ($yearlen == 1) {
1152 $yearcomp = (int) substr(date('y', $date), 1, 1) + $yearoffset;
1153 }
1154 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)
1155 if ($yearlen == 4) {
1156 $yearcomp1 = sprintf("%04d", idate("Y", $date) + $yearoffset + 1);
1157 } elseif ($yearlen == 2) {
1158 $yearcomp1 = sprintf("%02d", idate("y", $date) + $yearoffset + 1);
1159 }
1160
1161 $sqlwhere .= "(";
1162 $sqlwhere .= " (SUBSTRING(".$field.", ".$yearpos.", ".$yearlen.") = '".$db->escape($yearcomp)."'";
1163 $sqlwhere .= " AND SUBSTRING(".$field.", ".$monthpos.", ".$monthlen.") >= '".str_pad($monthcomp, $monthlen, '0', STR_PAD_LEFT)."')";
1164 $sqlwhere .= " OR";
1165 $sqlwhere .= " (SUBSTRING(".$field.", ".$yearpos.", ".$yearlen.") = '".$db->escape($yearcomp1)."'";
1166 $sqlwhere .= " AND SUBSTRING(".$field.", ".$monthpos.", ".$monthlen.") < '".str_pad($monthcomp, $monthlen, '0', STR_PAD_LEFT)."') ";
1167 $sqlwhere .= ')';
1168 } elseif ($resetEveryMonth) {
1169 $sqlwhere .= "(SUBSTRING(".$field.", ".$yearpos.", ".$yearlen.") = '".$db->escape($yearcomp)."'";
1170 $sqlwhere .= " AND SUBSTRING(".$field.", ".$monthpos.", ".$monthlen.") = '".str_pad($monthcomp, $monthlen, '0', STR_PAD_LEFT)."')";
1171 } else { // reset is done on january
1172 $sqlwhere .= "(SUBSTRING(".$field.", ".$yearpos.", ".$yearlen.") = '".$db->escape($yearcomp)."')";
1173 }
1174 }
1175 //print "sqlwhere=".$sqlwhere." yearcomp=".$yearcomp."<br>\n"; // sqlwhere and yearcomp defined only if we ask a reset
1176 //print "masktri=".$masktri." maskcounter=".$maskcounter." maskraz=".$maskraz." maskoffset=".$maskoffset."<br>\n";
1177
1178 // Define $sqlstring
1179 if (function_exists('mb_strrpos')) {
1180 $posnumstart = mb_strrpos($maskwithnocode, $maskcounter, 0, 'UTF-8');
1181 } else {
1182 $posnumstart = strrpos($maskwithnocode, $maskcounter);
1183 } // Pos of counter in final string (from 0 to ...)
1184 if ($posnumstart < 0) {
1185 return 'ErrorBadMaskFailedToLocatePosOfSequence';
1186 }
1187 $sqlstring = "SUBSTRING(".$field.", ".($posnumstart + 1).", ".dol_strlen($maskcounter).")";
1188
1189 // Define $maskLike
1190 $maskLike = dol_string_nospecial($mask);
1191 $maskLike = str_replace("%", "_", $maskLike);
1192
1193 // Replace protected special codes with matching number of _ as wild card character
1194 $maskLike = preg_replace('/\{yyyy\}/i', '____', $maskLike);
1195 $maskLike = preg_replace('/\{yy\}/i', '__', $maskLike);
1196 $maskLike = preg_replace('/\{y\}/i', '_', $maskLike);
1197 $maskLike = preg_replace('/\{mm\}/i', '__', $maskLike);
1198 $maskLike = preg_replace('/\{dd\}/i', '__', $maskLike);
1199 // @phan-suppress-next-line PhanParamSuspiciousOrder
1200 $maskLike = str_replace(dol_string_nospecial('{'.$masktri.'}'), str_pad("", dol_strlen($maskcounter), "_"), $maskLike);
1201 if ($maskrefclient) {
1202 // @phan-suppress-next-line PhanParamSuspiciousOrder
1203 $maskLike = str_replace(dol_string_nospecial('{'.$maskrefclient.'}'), str_pad("", dol_strlen($maskrefclient), "_"), $maskLike);
1204 }
1205 if ($masktype) {
1206 $maskLike = str_replace(dol_string_nospecial('{'.$masktype.'}'), $masktype_value, $maskLike);
1207 }
1208 if ($maskuser) {
1209 $maskLike = str_replace(dol_string_nospecial('{'.$maskuser.'}'), $maskuser_value, $maskLike);
1210 }
1211 foreach ($maskperso as $key => $val) {
1212 $maskLike = str_replace(dol_string_nospecial($maskperso[$key]), $maskpersonew[$key], $maskLike);
1213 }
1214
1215 // Get counter in database
1216 $counter = 0;
1217 $sql = "SELECT MAX(".$sqlstring.") as val";
1218 $sql .= " FROM ".MAIN_DB_PREFIX.$table;
1219 $sql .= " WHERE ".$field." LIKE '".$db->escape($maskLike) . (getDolGlobalString('SEARCH_FOR_NEXT_VAL_ON_START_ONLY') ? "%" : "") . "'";
1220 $sql .= " AND ".$field." NOT LIKE '(PROV%)'";
1221
1222 // To ensure that all variables within the MAX() brackets are integers
1223 // This avoid bad detection of max when data are noised with non numeric values at the position of the numero
1224 if (getDolGlobalInt('MAIN_NUMBERING_FILTER_ON_INT_ONLY')) {
1225 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
1226 $sql .= " AND ". $db->regexpsql($sqlstring, '^[0-9]+$', 1);
1227 }
1228
1229 if ($bentityon) { // only if entity enable
1230 $sql .= " AND entity IN (".getEntity($sharetable).")";
1231 } elseif (!empty($forceentity)) {
1232 $sql .= " AND entity IN (".$db->sanitize($forceentity).")";
1233 }
1234 if ($where) {
1235 $sql .= $where;
1236 }
1237 if ($sqlwhere) {
1238 $sql .= " AND ".$sqlwhere;
1239 }
1240
1241 //print $sql.'<br>';
1242 dol_syslog("functions2::get_next_value mode=".$mode, LOG_DEBUG);
1243 $resql = $db->query($sql);
1244 if ($resql) {
1245 $obj = $db->fetch_object($resql);
1246 $counter = $obj->val;
1247 } else {
1248 dol_print_error($db);
1249 }
1250
1251 // Check if we must force counter to maskoffset
1252 if (empty($counter)) {
1253 $counter = $maskoffset;
1254 } elseif (preg_match('/[^0-9]/i', $counter)) {
1255 dol_syslog("Error, the last counter found is '".$counter."' so is not a numeric value. We will restart to 1.", LOG_ERR);
1256 $counter = 0;
1257 } elseif ($counter < $maskoffset && !getDolGlobalString('MAIN_NUMBERING_OFFSET_ONLY_FOR_FIRST')) {
1258 $counter = $maskoffset;
1259 }
1260
1261 if ($mode == 'last') { // We found value for counter = last counter value. Now need to get corresponding ref of invoice.
1262 $counterpadded = str_pad($counter, dol_strlen($maskcounter), "0", STR_PAD_LEFT);
1263
1264 // Define $maskLike
1265 $maskLike = dol_string_nospecial($mask);
1266 $maskLike = str_replace("%", "_", $maskLike);
1267 // Replace protected special codes with matching number of _ as wild card character
1268 $maskLike = preg_replace('/\{yyyy\}/i', '____', $maskLike);
1269 $maskLike = preg_replace('/\{yy\}/i', '__', $maskLike);
1270 $maskLike = preg_replace('/\{y\}/i', '_', $maskLike);
1271 $maskLike = preg_replace('/\{mm\}/i', '__', $maskLike);
1272 $maskLike = preg_replace('/\{dd\}/i', '__', $maskLike);
1273 $maskLike = str_replace(dol_string_nospecial('{'.$masktri.'}'), $counterpadded, $maskLike);
1274 if ($maskrefclient) {
1275 // @phan-suppress-next-line PhanParamSuspiciousOrder
1276 $maskLike = str_replace(dol_string_nospecial('{'.$maskrefclient.'}'), str_pad("", dol_strlen($maskrefclient), "_"), $maskLike);
1277 }
1278 if ($masktype) {
1279 $maskLike = str_replace(dol_string_nospecial('{'.$masktype.'}'), $masktype_value, $maskLike);
1280 }
1281 if ($maskuser) {
1282 $maskLike = str_replace(dol_string_nospecial('{'.$maskuser.'}'), $maskuser_value, $maskLike);
1283 }
1284
1285 $ref = '';
1286 $sql = "SELECT ".$field." as ref";
1287 $sql .= " FROM ".MAIN_DB_PREFIX.$table;
1288 $sql .= " WHERE ".$field." LIKE '".$db->escape($maskLike) . (getDolGlobalString('SEARCH_FOR_NEXT_VAL_ON_START_ONLY') ? "%" : "") . "'";
1289 $sql .= " AND ".$field." NOT LIKE '%PROV%'";
1290 if ($bentityon) { // only if entity enable
1291 $sql .= " AND entity IN (".getEntity($sharetable).")";
1292 } elseif (!empty($forceentity)) {
1293 $sql .= " AND entity IN (".$db->sanitize($forceentity).")";
1294 }
1295 if ($where) {
1296 $sql .= $where;
1297 }
1298 if ($sqlwhere) {
1299 $sql .= " AND ".$sqlwhere;
1300 }
1301
1302 dol_syslog("functions2::get_next_value mode=".$mode, LOG_DEBUG);
1303 $resql = $db->query($sql);
1304 if ($resql) {
1305 $obj = $db->fetch_object($resql);
1306 if ($obj) {
1307 $ref = $obj->ref;
1308 }
1309 } else {
1310 dol_print_error($db);
1311 }
1312
1313 $numFinal = $ref;
1314 } elseif ($mode == 'next') {
1315 $counter++;
1316 $maskrefclient_counter = 0;
1317
1318 // If value for $counter has a length higher than $maskcounter chars
1319 if ($counter >= pow(10, dol_strlen($maskcounter))) {
1320 $counter = 'ErrorMaxNumberReachForThisMask';
1321 }
1322
1323 if (!empty($maskrefclient_maskcounter)) {
1324 //print "maskrefclient_maskcounter=".$maskrefclient_maskcounter." maskwithnocode=".$maskwithnocode." maskrefclient=".$maskrefclient."\n<br>";
1325
1326 // Define $sqlstring
1327 $maskrefclient_posnumstart = strpos($maskwithnocode, $maskrefclient_maskcounter, strpos($maskwithnocode, $maskrefclient)); // Pos of counter in final string (from 0 to ...)
1328 if ($maskrefclient_posnumstart <= 0) {
1329 return 'ErrorBadMask';
1330 }
1331 $maskrefclient_sqlstring = 'SUBSTRING('.$field.', '.($maskrefclient_posnumstart + 1).', '.dol_strlen($maskrefclient_maskcounter).')';
1332 //print "x".$sqlstring;
1333
1334 // Define $maskrefclient_maskLike
1335 $maskrefclient_maskLike = dol_string_nospecial($mask);
1336 $maskrefclient_maskLike = str_replace("%", "_", $maskrefclient_maskLike);
1337 // Replace protected special codes with matching number of _ as wild card character
1338 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{yyyy}'), '____', $maskrefclient_maskLike);
1339 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{yy}'), '__', $maskrefclient_maskLike);
1340 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{y}'), '_', $maskrefclient_maskLike);
1341 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{mm}'), '__', $maskrefclient_maskLike);
1342 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{dd}'), '__', $maskrefclient_maskLike);
1343 // @phan-suppress-next-line PhanParamSuspiciousOrder
1344 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{'.$masktri.'}'), str_pad("", dol_strlen($maskcounter), "_"), $maskrefclient_maskLike);
1345 // @phan-suppress-next-line PhanParamSuspiciousOrder
1346 $maskrefclient_maskLike = str_replace(dol_string_nospecial('{'.$maskrefclient.'}'), $maskrefclient_clientcode.str_pad("", dol_strlen($maskrefclient_maskcounter), "_"), $maskrefclient_maskLike);
1347
1348 // Get counter in database
1349 $maskrefclient_sql = "SELECT MAX(".$maskrefclient_sqlstring.") as val";
1350 $maskrefclient_sql .= " FROM ".MAIN_DB_PREFIX.$table;
1351 //$sql.= " WHERE ".$field." not like '(%'";
1352 $maskrefclient_sql .= " WHERE ".$field." LIKE '".$db->escape($maskrefclient_maskLike) . (getDolGlobalString('SEARCH_FOR_NEXT_VAL_ON_START_ONLY') ? "%" : "") . "'";
1353 if ($bentityon) { // only if entity enable
1354 $maskrefclient_sql .= " AND entity IN (".getEntity($sharetable).")";
1355 } elseif (!empty($forceentity)) {
1356 $sql .= " AND entity IN (".$db->sanitize($forceentity).")";
1357 }
1358 if ($where) {
1359 $maskrefclient_sql .= $where; //use the same optional where as general mask
1360 }
1361 if ($sqlwhere) {
1362 $maskrefclient_sql .= ' AND '.$sqlwhere; //use the same sqlwhere as general mask
1363 }
1364 $maskrefclient_sql .= " AND (SUBSTRING(".$field.", ".(strpos($maskwithnocode, $maskrefclient) + 1).", ".dol_strlen($maskrefclient_maskclientcode).") = '".$db->escape($maskrefclient_clientcode)."')";
1365
1366 dol_syslog("functions2::get_next_value maskrefclient", LOG_DEBUG);
1367 $maskrefclient_resql = $db->query($maskrefclient_sql);
1368 if ($maskrefclient_resql) {
1369 $maskrefclient_obj = $db->fetch_object($maskrefclient_resql);
1370 $maskrefclient_counter = $maskrefclient_obj->val;
1371 } else {
1372 dol_print_error($db);
1373 }
1374
1375 if (empty($maskrefclient_counter) || preg_match('/[^0-9]/i', $maskrefclient_counter)) {
1376 $maskrefclient_counter = $maskrefclient_maskoffset;
1377 }
1378 $maskrefclient_counter++;
1379 }
1380
1381 // Build numFinal
1382 $numFinal = $mask;
1383
1384 // We replace special codes except refclient
1385 if (!empty($yearoffsettype) && !is_numeric($yearoffsettype) && $yearoffsettype != '=') { // yearoffsettype is - or +, so we don't want current year
1386 $numFinal = preg_replace('/\{yyyy\}/i', (string) ((int) date("Y", $date) + $yearoffset), $numFinal);
1387 $numFinal = preg_replace('/\{yy\}/i', (string) ((int) date("y", $date) + $yearoffset), $numFinal);
1388 $numFinal = preg_replace('/\{y\}/i', (string) ((int) substr((string) date("y", $date), 1, 1) + $yearoffset), $numFinal);
1389 } else { // we want yyyy to be current year
1390 $numFinal = preg_replace('/\{yyyy\}/i', date("Y", $date), $numFinal);
1391 $numFinal = preg_replace('/\{yy\}/i', date("y", $date), $numFinal);
1392 $numFinal = preg_replace('/\{y\}/i', substr(date("y", $date), 1, 1), $numFinal);
1393 }
1394 $numFinal = preg_replace('/\{mm\}/i', date("m", $date), $numFinal);
1395 $numFinal = preg_replace('/\{dd\}/i', date("d", $date), $numFinal);
1396
1397 // Now we replace the counter
1398 $maskbefore = '{'.$masktri.'}';
1399 $maskafter = str_pad($counter, dol_strlen($maskcounter), "0", STR_PAD_LEFT);
1400 //print 'x'.$numFinal.' - '.$maskbefore.' - '.$maskafter.'y';exit;
1401 $numFinal = str_replace($maskbefore, $maskafter, $numFinal);
1402
1403 // Now we replace the refclient
1404 if ($maskrefclient) {
1405 //print "maskrefclient=".$maskrefclient." maskrefclient_counter=".$maskrefclient_counter." maskwithonlyymcode=".$maskwithonlyymcode." maskwithnocode=".$maskwithnocode." maskrefclient_clientcode=".$maskrefclient_clientcode." maskrefclient_maskcounter=".$maskrefclient_maskcounter."\n<br>";exit;
1406 $maskrefclient_maskbefore = '{'.$maskrefclient.'}';
1407 $maskrefclient_maskafter = $maskrefclient_clientcode;
1408 if (dol_strlen($maskrefclient_maskcounter) > 0) {
1409 $maskrefclient_maskafter .= str_pad($maskrefclient_counter, dol_strlen($maskrefclient_maskcounter), "0", STR_PAD_LEFT);
1410 }
1411 $numFinal = str_replace($maskrefclient_maskbefore, $maskrefclient_maskafter, $numFinal);
1412 }
1413
1414 // Now we replace the type
1415 if ($masktype) {
1416 $masktype_maskbefore = '{'.$masktype.'}';
1417 $masktype_maskafter = $masktype_value;
1418 $numFinal = str_replace($masktype_maskbefore, $masktype_maskafter, $numFinal);
1419 }
1420
1421 // Now we replace the user
1422 if ($maskuser) {
1423 $maskuser_maskbefore = '{'.$maskuser.'}';
1424 $maskuser_maskafter = $maskuser_value;
1425 $numFinal = str_replace($maskuser_maskbefore, $maskuser_maskafter, $numFinal);
1426 }
1427 } else {
1428 $numFinal = "ErrorBadMode";
1429 dol_syslog("functions2::get_next_value ErrorBadMode '$mode'", LOG_ERR);
1430 }
1431
1432 dol_syslog("functions2::get_next_value return ".$numFinal, LOG_DEBUG);
1433 return $numFinal;
1434}
1435
1447function get_string_between($string, $start, $end)
1448{
1449 $ini = strpos($string, $start);
1450 if ($ini === false) {
1451 return '';
1452 }
1453 $ini += strlen($start);
1454 $endpos = strpos($string, $end, $ini);
1455 if ($endpos === false) {
1456 return '';
1457 }
1458 return substr($string, $ini, $endpos - $ini);
1459}
1460
1468function check_value($mask, $value)
1469{
1470 $result = 0;
1471
1472 $hasglobalcounter = false;
1473 // Extract value for mask counter, mask raz and mask offset
1474 $reg = array();
1475 if (preg_match('/\{(0+)([@\+][0-9]+)?([@\+][0-9]+)?\}/i', $mask, $reg)) {
1476 $masktri = $reg[1].(isset($reg[2]) ? $reg[2] : '').(isset($reg[3]) ? $reg[3] : '');
1477 $maskcounter = $reg[1];
1478 $hasglobalcounter = true;
1479 } else {
1480 // setting some defaults so the rest of the code won't fail if there is a third party counter
1481 $masktri = '00000';
1482 $maskcounter = '00000';
1483 }
1484 $maskraz = -1;
1485 $maskoffset = 0;
1486 if (dol_strlen($maskcounter) < 3) {
1487 return 'ErrorCounterMustHaveMoreThan3Digits';
1488 }
1489
1490 // Extract value for third party mask counter
1491 $regClientRef = array();
1492 if (preg_match('/\{(c+)(0*)\}/i', $mask, $regClientRef)) {
1493 $maskrefclient = $regClientRef[1].$regClientRef[2];
1494 $maskrefclient_maskclientcode = $regClientRef[1];
1495 $maskrefclient_maskcounter = $regClientRef[2];
1496 $maskrefclient_maskoffset = 0; //default value of maskrefclient_counter offset
1497 $maskrefclient_clientcode = substr('', 0, dol_strlen($maskrefclient_maskclientcode)); //get n first characters of client code to form maskrefclient_clientcode
1498 $maskrefclient_clientcode = str_pad($maskrefclient_clientcode, dol_strlen($maskrefclient_maskclientcode), "#", STR_PAD_RIGHT); //padding maskrefclient_clientcode for having exactly n characters in maskrefclient_clientcode
1499 $maskrefclient_clientcode = dol_string_nospecial($maskrefclient_clientcode); //sanitize maskrefclient_clientcode for sql insert and sql select like
1500 if (dol_strlen($maskrefclient_maskcounter) > 0 && dol_strlen($maskrefclient_maskcounter) < 3) {
1501 return 'ErrorCounterMustHaveMoreThan3Digits';
1502 }
1503 } else {
1504 $maskrefclient = '';
1505 }
1506
1507 // fail if there is neither a global nor a third party counter
1508 if (!$hasglobalcounter && ($maskrefclient_maskcounter == '')) {
1509 return 'ErrorBadMask';
1510 }
1511
1512 $maskwithonlyymcode = $mask;
1513 $maskwithonlyymcode = preg_replace('/\{(0+)([@\+][0-9]+)?([@\+][0-9]+)?\}/i', $maskcounter, $maskwithonlyymcode);
1514 $maskwithonlyymcode = preg_replace('/\{dd\}/i', 'dd', $maskwithonlyymcode);
1515 $maskwithonlyymcode = preg_replace('/\{(c+)(0*)\}/i', $maskrefclient, $maskwithonlyymcode);
1516 $maskwithnocode = $maskwithonlyymcode;
1517 $maskwithnocode = preg_replace('/\{yyyy\}/i', 'yyyy', $maskwithnocode);
1518 $maskwithnocode = preg_replace('/\{yy\}/i', 'yy', $maskwithnocode);
1519 $maskwithnocode = preg_replace('/\{y\}/i', 'y', $maskwithnocode);
1520 $maskwithnocode = preg_replace('/\{mm\}/i', 'mm', $maskwithnocode);
1521 // Now maskwithnocode = 0000ddmmyyyyccc for example
1522 // and maskcounter = 0000 for example
1523 //print "maskwithonlyymcode=".$maskwithonlyymcode." maskwithnocode=".$maskwithnocode."\n<br>";
1524
1525 // If an offset is asked
1526 if (!empty($reg[2]) && preg_match('/^\+/', $reg[2])) {
1527 $maskoffset = preg_replace('/^\+/', '', $reg[2]);
1528 }
1529 if (!empty($reg[3]) && preg_match('/^\+/', $reg[3])) {
1530 $maskoffset = preg_replace('/^\+/', '', $reg[3]);
1531 }
1532
1533 // Define $sqlwhere
1534
1535 // If a restore to zero after a month is asked we check if there is already a value for this year.
1536 if (!empty($reg[2]) && preg_match('/^@/', $reg[2])) {
1537 $maskraz = preg_replace('/^@/', '', $reg[2]);
1538 }
1539 if (!empty($reg[3]) && preg_match('/^@/', $reg[3])) {
1540 $maskraz = preg_replace('/^@/', '', $reg[3]);
1541 }
1542 if ($maskraz >= 0) {
1543 if ($maskraz == 99) {
1544 $maskraz = (int) date('m');
1545 $resetEveryMonth = true;
1546 }
1547 if ($maskraz > 12) {
1548 return 'ErrorBadMaskBadRazMonth';
1549 }
1550
1551 // Define reg
1552 if ($maskraz > 1 && !preg_match('/^(.*)\{(y+)\}\{(m+)\}/i', $maskwithonlyymcode, $reg)) {
1553 return 'ErrorCantUseRazInStartedYearIfNoYearMonthInMask';
1554 }
1555 if ($maskraz <= 1 && !preg_match('/^(.*)\{(y+)\}/i', $maskwithonlyymcode, $reg)) {
1556 return 'ErrorCantUseRazIfNoYearInMask';
1557 }
1558 //print "x".$maskwithonlyymcode." ".$maskraz;
1559 }
1560 //print "masktri=".$masktri." maskcounter=".$maskcounter." maskwithonlyymcode=".$maskwithonlyymcode." maskwithnocode=".$maskwithnocode." maskraz=".$maskraz." maskoffset=".$maskoffset."<br>\n";
1561
1562 if (function_exists('mb_strrpos')) {
1563 $posnumstart = mb_strrpos($maskwithnocode, $maskcounter, 0, 'UTF-8');
1564 } else {
1565 $posnumstart = strrpos($maskwithnocode, $maskcounter);
1566 } // Pos of counter in final string (from 0 to ...)
1567 if ($posnumstart < 0) {
1568 return 'ErrorBadMaskFailedToLocatePosOfSequence';
1569 }
1570
1571 // Check we have a number in $value at position ($posnumstart+1).', '.dol_strlen($maskcounter)
1572 // TODO
1573
1574 // Check length
1575 $len = dol_strlen($maskwithnocode);
1576 if (dol_strlen($value) != $len) {
1577 $result = -1;
1578 }
1579
1580 dol_syslog("functions2::check_value result=".$result, LOG_DEBUG);
1581 return $result;
1582}
1583
1592function binhex($bin, $pad = false, $upper = false)
1593{
1594 $last = dol_strlen($bin) - 1;
1595 $x = 0;
1596 for ($i = 0; $i <= $last; $i++) {
1597 $x += ($bin[$last - $i] ? 1 : 0) << $i;
1598 }
1599 $x = dechex($x);
1600 if ($pad) {
1601 while (dol_strlen($x) < intval(dol_strlen($bin)) / 4) {
1602 $x = "0$x";
1603 }
1604 }
1605 if ($upper) {
1606 $x = strtoupper($x);
1607 }
1608 return $x;
1609}
1610
1617function hexbin($hexa)
1618{
1619 $bin = '';
1620 $strLength = dol_strlen($hexa);
1621 for ($i = 0; $i < $strLength; $i++) {
1622 $bin .= str_pad(decbin(hexdec($hexa[$i])), 4, '0', STR_PAD_LEFT);
1623 }
1624 return $bin;
1625}
1626
1633function numero_semaine($time)
1634{
1635 $stime = dol_print_date($time, '%Y-%m-%d');
1636
1637 if (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+)\s?([0-9]+)?:?([0-9]+)?/i', $stime, $reg)) {
1638 // Date est au format 'YYYY-MM-DD' ou 'YYYY-MM-DD HH:MM:SS'
1639 $annee = (int) $reg[1];
1640 $mois = (int) $reg[2];
1641 $jour = (int) $reg[3];
1642 }
1643
1644 /*
1645 * Norme ISO-8601:
1646 * - Week 1 of the year contains Jan 4th, or contains the first Thursday of January.
1647 * - Most years have 52 weeks, but 53 weeks for years starting on a Thursday and bisectile years that start on a Wednesday.
1648 * - The first day of a week is Monday
1649 */
1650
1651 // Definition du Jeudi de la semaine
1652 if ((int) date("w", mktime(12, 0, 0, $mois, $jour, $annee)) == 0) { // Dimanche
1653 $jeudiSemaine = mktime(12, 0, 0, $mois, $jour, $annee) - 3 * 24 * 60 * 60;
1654 } elseif (date("w", mktime(12, 0, 0, $mois, $jour, $annee)) < 4) { // du Lundi au Mercredi
1655 $jeudiSemaine = mktime(12, 0, 0, $mois, $jour, $annee) + (4 - (int) date("w", mktime(12, 0, 0, $mois, $jour, $annee))) * 24 * 60 * 60;
1656 } elseif ((int) date("w", mktime(12, 0, 0, $mois, $jour, $annee)) > 4) { // du Vendredi au Samedi
1657 $jeudiSemaine = mktime(12, 0, 0, $mois, $jour, $annee) - ((int) date("w", mktime(12, 0, 0, $mois, $jour, $annee)) - 4) * 24 * 60 * 60;
1658 } else { // Jeudi
1659 $jeudiSemaine = mktime(12, 0, 0, $mois, $jour, $annee);
1660 }
1661
1662 // Definition du premier Jeudi de l'annee
1663 if ((int) date("w", mktime(12, 0, 0, 1, 1, (int) date("Y", $jeudiSemaine))) == 0) { // Dimanche
1664 $premierJeudiAnnee = mktime(12, 0, 0, 1, 1, (int) date("Y", $jeudiSemaine)) + 4 * 24 * 60 * 60;
1665 } elseif ((int) date("w", mktime(12, 0, 0, 1, 1, (int) date("Y", $jeudiSemaine))) < 4) { // du Lundi au Mercredi
1666 $premierJeudiAnnee = mktime(12, 0, 0, 1, 1, (int) date("Y", $jeudiSemaine)) + (4 - (int) date("w", mktime(12, 0, 0, 1, 1, (int) date("Y", $jeudiSemaine)))) * 24 * 60 * 60;
1667 } elseif ((int) date("w", mktime(12, 0, 0, 1, 1, (int) date("Y", $jeudiSemaine))) > 4) { // du Vendredi au Samedi
1668 $premierJeudiAnnee = mktime(12, 0, 0, 1, 1, (int) date("Y", $jeudiSemaine)) + (7 - ((int) date("w", mktime(12, 0, 0, 1, 1, (int) date("Y", $jeudiSemaine))) - 4)) * 24 * 60 * 60;
1669 } else { // Jeudi
1670 $premierJeudiAnnee = mktime(12, 0, 0, 1, 1, (int) date("Y", $jeudiSemaine));
1671 }
1672
1673 // Definition du numero de semaine: nb de jours entre "premier Jeudi de l'annee" et "Jeudi de la semaine";
1674 $numeroSemaine = (
1675 (
1676 (int) date("z", mktime(12, 0, 0, (int) date("m", $jeudiSemaine), (int) date("d", $jeudiSemaine), (int) date("Y", $jeudiSemaine)))
1677 -
1678 (int) date("z", mktime(12, 0, 0, (int) date("m", $premierJeudiAnnee), (int) date("d", $premierJeudiAnnee), (int) date("Y", $premierJeudiAnnee)))
1679 ) / 7
1680 ) + 1;
1681
1682 // Cas particulier de la semaine 53
1683 if ($numeroSemaine == 53) {
1684 // Les annees qui commencent un Jeudi et les annees bissextiles commencant un Mercredi en possedent 53
1685 if (
1686 ((int) date("w", mktime(12, 0, 0, 1, 1, (int) date("Y", $jeudiSemaine))) == 4)
1687 || (
1688 ((int) date("w", mktime(12, 0, 0, 1, 1, (int) date("Y", $jeudiSemaine))) == 3)
1689 && ((int) date("z", mktime(12, 0, 0, 12, 31, (int) date("Y", $jeudiSemaine))) == 365)
1690 )
1691 ) {
1692 $numeroSemaine = 53;
1693 } else {
1694 $numeroSemaine = 1;
1695 }
1696 }
1697
1698 //echo $jour."-".$mois."-".$annee." (".date("d-m-Y",$premierJeudiAnnee)." - ".date("d-m-Y",$jeudiSemaine).") -> ".$numeroSemaine."<BR>";
1699
1700 return sprintf("%02d", $numeroSemaine);
1701}
1702
1711function weight_convert($weight, &$from_unit, $to_unit)
1712{
1713 /* Pour convertire 320 gr en Kg appeler
1714 * $f = -3
1715 * weigh_convert(320, $f, 0) retournera 0.32
1716 *
1717 */
1718 $weight = is_numeric($weight) ? $weight : 0;
1719 while ($from_unit != $to_unit) {
1720 if ($from_unit > $to_unit) {
1721 $weight *= 10;
1722 $from_unit -= 1;
1723 $weight = weight_convert($weight, $from_unit, $to_unit);
1724 }
1725 if ($from_unit < $to_unit) {
1726 $weight /= 10;
1727 $from_unit += 1;
1728 $weight = weight_convert($weight, $from_unit, $to_unit);
1729 }
1730 }
1731
1732 return $weight;
1733}
1734
1746function dol_set_user_param($db, $conf, &$user, $tab)
1747{
1748 // Verification parameters
1749 if (count($tab) < 1) {
1750 return -1;
1751 }
1752
1753 $db->begin();
1754
1755 // We remove old parameters for all keys in $tab
1756 $sql = "DELETE FROM ".MAIN_DB_PREFIX."user_param";
1757 $sql .= " WHERE fk_user = ".((int) $user->id);
1758 $sql .= " AND entity = ".((int) $conf->entity);
1759 $sql .= " AND param in (";
1760 $i = 0;
1761 foreach ($tab as $key => $value) {
1762 if ($i > 0) {
1763 $sql .= ',';
1764 }
1765 $sql .= "'".$db->escape($key)."'";
1766 $i++;
1767 }
1768 $sql .= ")";
1769 dol_syslog("functions2.lib::dol_set_user_param", LOG_DEBUG);
1770
1771 $resql = $db->query($sql);
1772 if (!$resql) {
1773 dol_print_error($db);
1774 $db->rollback();
1775 return -1;
1776 }
1777
1778 foreach ($tab as $key => $value) {
1779 // Set new parameters
1780 $forcevalue = 0;
1781 if (is_array($value)) {
1782 if ($value["forcevalue"] == 1) {
1783 $forcevalue = 1;
1784 }
1785 $value = $value["value"];
1786 }
1787 if ($forcevalue == 1 || $value) {
1788 $sql = "INSERT INTO ".MAIN_DB_PREFIX."user_param(fk_user,entity,param,value)";
1789 $sql .= " VALUES (".((int) $user->id).",".((int) $conf->entity).",";
1790 $sql .= " '".$db->escape($key)."','".$db->escape($value)."')";
1791
1792 dol_syslog("functions2.lib::dol_set_user_param", LOG_DEBUG);
1793 $result = $db->query($sql);
1794 if (!$result) {
1795 dol_print_error($db);
1796 $db->rollback();
1797 return -1;
1798 }
1799 $user->conf->$key = $value;
1800 //print "key=".$key." user->conf->key=".$user->conf->$key;
1801 } else {
1802 unset($user->conf->$key);
1803 }
1804 }
1805
1806 $db->commit();
1807 return 1;
1808}
1809
1817function dol_print_reduction($reduction, $langs)
1818{
1819 $string = '';
1820 if ($reduction == 100) {
1821 $string = $langs->transnoentities("Offered");
1822 } else {
1823 $string = vatrate($reduction, true);
1824 }
1825
1826 return $string;
1827}
1828
1836function version_os($option = '')
1837{
1838 if ($option == 'smr') {
1839 $osversion = php_uname('s').' '.php_uname('m').' '.php_uname('r');
1840 } else {
1841 $osversion = php_uname();
1842 }
1843 return $osversion;
1844}
1845
1852function version_php()
1853{
1854 return phpversion();
1855}
1856
1862function version_db()
1863{
1864 global $db;
1865 if (is_object($db) && method_exists($db, 'getVersion')) {
1866 return $db->getVersion();
1867 }
1868 return '';
1869}
1870
1878{
1879 return DOL_VERSION;
1880}
1881
1888{
1889 return $_SERVER["SERVER_SOFTWARE"];
1890}
1891
1900function getListOfModels($db, $type, $maxfilenamelength = 0)
1901{
1902 global $conf, $langs;
1903 $liste = array();
1904 $found = 0;
1905 $dirtoscan = '';
1906
1907 $sql = "SELECT nom as id, nom as doc_template_name, libelle as label, description as description";
1908 $sql .= " FROM ".MAIN_DB_PREFIX."document_model";
1909 $sql .= " WHERE type = '".$db->escape($type)."'";
1910 $sql .= " AND entity IN (0,".$conf->entity.")";
1911 $sql .= " ORDER BY description DESC";
1912
1913 dol_syslog('/core/lib/function2.lib.php::getListOfModels', LOG_DEBUG);
1914 $resql_models = $db->query($sql);
1915 if ($resql_models) {
1916 $num = $db->num_rows($resql_models);
1917 $i = 0;
1918 while ($i < $num) {
1919 $found = 1;
1920
1921 $obj = $db->fetch_object($resql_models);
1922
1923 // If this generation module needs to scan a directory, then description field is filled
1924 // with the constant that contains list of directories to scan (COMPANY_ADDON_PDF_ODT_PATH, ...).
1925 if (!empty($obj->description)) { // A list of directories to scan is defined
1926 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1927
1928 $const = $obj->description;
1929 $dirtoscan = preg_replace('/[\r\n]+/', ',', trim(getDolGlobalString($const)));
1930
1931 $listoffiles = array();
1932
1933 // Now we add models found in directories scanned
1934 $listofdir = explode(',', $dirtoscan);
1935 foreach ($listofdir as $key => $tmpdir) {
1936 $tmpdir = trim($tmpdir);
1937 $tmpdir = preg_replace('/DOL_DATA_ROOT/', DOL_DATA_ROOT, $tmpdir);
1938 if (!$tmpdir) {
1939 unset($listofdir[$key]);
1940 continue;
1941 }
1942 if (is_dir($tmpdir)) {
1943 // all type of template is allowed
1944 $tmpfiles = dol_dir_list($tmpdir, 'files', 0, '', null, 'name', SORT_ASC, 0);
1945 if (count($tmpfiles)) {
1946 $listoffiles = array_merge($listoffiles, $tmpfiles);
1947 }
1948 }
1949 }
1950
1951 if (count($listoffiles)) {
1952 foreach ($listoffiles as $record) {
1953 $max = ($maxfilenamelength ? $maxfilenamelength : 28);
1954 $liste[$obj->id.':'.$record['fullname']] = dol_trunc($record['name'], $max, 'middle');
1955 }
1956 } else {
1957 $liste[0] = $obj->label.': '.$langs->trans("None");
1958 }
1959 } else {
1960 if ($type == 'member' && $obj->doc_template_name == 'standard') { // Special case, if member template, we add variant per format
1961 global $_Avery_Labels;
1962 include_once DOL_DOCUMENT_ROOT.'/core/lib/format_cards.lib.php';
1963 foreach ($_Avery_Labels as $key => $val) {
1964 $liste[$obj->id.':'.$key] = ($obj->label ? $obj->label : $obj->doc_template_name).' '.$val['name'];
1965 }
1966 } else {
1967 // Common usage
1968 $liste[$obj->id] = $obj->label ? $obj->label : $obj->doc_template_name;
1969 }
1970 }
1971 $i++;
1972 }
1973 } else {
1974 dol_print_error($db);
1975 return -1;
1976 }
1977
1978 if ($found) {
1979 return $liste;
1980 } else {
1981 return 0;
1982 }
1983}
1984
1992function is_ip($ip)
1993{
1994 // First we test if it is a valid IPv4
1995 if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
1996 // Then we test if it is a private range
1997 if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) {
1998 return 2;
1999 }
2000
2001 // Then we test if it is a reserved range
2002 if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE)) {
2003 return 0;
2004 }
2005
2006 return 1;
2007 }
2008
2009 return 0;
2010}
2011
2019function dol_buildlogin($lastname, $firstname)
2020{
2021 //$conf->global->MAIN_BUILD_LOGIN_RULE = 'f.lastname';
2022 $charforseparator = getDolGlobalString("MAIN_USER_SEPARATOR_CHAR_FOR_GENERATED_LOGIN", '.');
2023 if ($charforseparator == 'none') {
2024 $charforseparator = '';
2025 }
2026
2027 if (getDolGlobalString('MAIN_BUILD_LOGIN_RULE') == 'f.lastname') { // f.lastname
2028 $login = strtolower(dol_string_unaccent(dol_trunc($firstname, 1, 'right', 'UTF-8', 1)));
2029 $login .= ($login ? $charforseparator : '');
2030 $login .= strtolower(dol_string_unaccent($lastname));
2031 $login = dol_string_nospecial($login, ''); // For special names
2032 } else { // firstname.lastname
2033 $login = strtolower(dol_string_unaccent($firstname));
2034 $login .= ($login ? $charforseparator : '');
2035 $login .= strtolower(dol_string_unaccent($lastname));
2036 $login = dol_string_nospecial($login, ''); // For special names
2037 }
2038
2039 // TODO Add a hook to allow external modules to suggest new rules
2040
2041 return $login;
2042}
2043
2050{
2051 global $conf;
2052
2053 $params = array();
2054 $proxyuse = getDolGlobalString('MAIN_PROXY_USE');
2055 $proxyhost = (!$proxyuse ? false : $conf->global->MAIN_PROXY_HOST);
2056 $proxyport = (!$proxyuse ? false : $conf->global->MAIN_PROXY_PORT);
2057 $proxyuser = (!$proxyuse ? false : $conf->global->MAIN_PROXY_USER);
2058 $proxypass = (!$proxyuse ? false : $conf->global->MAIN_PROXY_PASS);
2059 $timeout = getDolGlobalInt('MAIN_USE_CONNECT_TIMEOUT', 10); // Connection timeout
2060 $response_timeout = getDolGlobalInt('MAIN_USE_RESPONSE_TIMEOUT', 30); // Response timeout
2061 //print extension_loaded('soap');
2062 if ($proxyuse) {
2063 $params = array('connection_timeout' => $timeout,
2064 'response_timeout' => $response_timeout,
2065 'proxy_use' => 1,
2066 'proxy_host' => $proxyhost,
2067 'proxy_port' => $proxyport,
2068 'proxy_login' => $proxyuser,
2069 'proxy_password' => $proxypass,
2070 'trace' => 1
2071 );
2072 } else {
2073 $params = array('connection_timeout' => $timeout,
2074 'response_timeout' => $response_timeout,
2075 'proxy_use' => 0,
2076 'proxy_host' => false,
2077 'proxy_port' => false,
2078 'proxy_login' => false,
2079 'proxy_password' => false,
2080 'trace' => 1
2081 );
2082 }
2083 return $params;
2084}
2085
2086
2096function dolGetElementUrl($objectid, $objecttype, $withpicto = 0, $option = '')
2097{
2098 global $db, $conf, $langs;
2099
2100 $ret = '';
2101 $regs = array();
2102
2103 // If we ask a resource form external module (instead of default path)
2104 if (preg_match('/^([^@]+)@([^@]+)$/i', $objecttype, $regs)) {
2105 $myobject = $regs[1];
2106 $module = $regs[2];
2107 } else {
2108 // Parse $objecttype (ex: project_task)
2109 $module = $myobject = $objecttype;
2110 if (preg_match('/^([^_]+)_([^_]+)/i', $objecttype, $regs)) {
2111 $module = $regs[1];
2112 $myobject = $regs[2];
2113 }
2114 }
2115
2116 // Generic case for $classpath
2117 $classpath = $module.'/class';
2118
2119 // Special cases, to work with non standard path
2120 if ($objecttype == 'facture' || $objecttype == 'invoice') {
2121 $langs->load('bills');
2122 $classpath = 'compta/facture/class';
2123 $module = 'facture';
2124 $myobject = 'facture';
2125 } elseif ($objecttype == 'commande' || $objecttype == 'order') {
2126 $langs->load('orders');
2127 $classpath = 'commande/class';
2128 $module = 'commande';
2129 $myobject = 'commande';
2130 } elseif ($objecttype == 'propal') {
2131 $langs->load('propal');
2132 $classpath = 'comm/propal/class';
2133 } elseif ($objecttype == 'supplier_proposal') {
2134 $langs->load('supplier_proposal');
2135 $classpath = 'supplier_proposal/class';
2136 } elseif ($objecttype == 'shipping') {
2137 $langs->load('sendings');
2138 $classpath = 'expedition/class';
2139 $myobject = 'expedition';
2140 $module = 'expedition_bon';
2141 } elseif ($objecttype == 'delivery') {
2142 $langs->load('deliveries');
2143 $classpath = 'delivery/class';
2144 $myobject = 'delivery';
2145 $module = 'delivery_note';
2146 } elseif ($objecttype == 'contract') {
2147 $langs->load('contracts');
2148 $classpath = 'contrat/class';
2149 $module = 'contrat';
2150 $myobject = 'contrat';
2151 } elseif ($objecttype == 'member') {
2152 $langs->load('members');
2153 $classpath = 'adherents/class';
2154 $module = 'adherent';
2155 $myobject = 'adherent';
2156 } elseif ($objecttype == 'cabinetmed_cons') {
2157 $classpath = 'cabinetmed/class';
2158 $module = 'cabinetmed';
2159 $myobject = 'cabinetmedcons';
2160 } elseif ($objecttype == 'fichinter') {
2161 $langs->load('interventions');
2162 $classpath = 'fichinter/class';
2163 $module = 'ficheinter';
2164 $myobject = 'fichinter';
2165 } elseif ($objecttype == 'project') {
2166 $langs->load('projects');
2167 $classpath = 'projet/class';
2168 $module = 'projet';
2169 } elseif ($objecttype == 'task') {
2170 $langs->load('projects');
2171 $classpath = 'projet/class';
2172 $module = 'projet';
2173 $myobject = 'task';
2174 } elseif ($objecttype == 'stock') {
2175 $classpath = 'product/stock/class';
2176 $module = 'stock';
2177 $myobject = 'stock';
2178 } elseif ($objecttype == 'inventory') {
2179 $classpath = 'product/inventory/class';
2180 $module = 'stock';
2181 $myobject = 'inventory';
2182 } elseif ($objecttype == 'mo') {
2183 $classpath = 'mrp/class';
2184 $module = 'mrp';
2185 $myobject = 'mo';
2186 } elseif ($objecttype == 'productlot') {
2187 $classpath = 'product/stock/class';
2188 $module = 'stock';
2189 $myobject = 'productlot';
2190 }
2191
2192 // Generic case for $classfile and $classname
2193 $classfile = strtolower($myobject);
2194 $classname = ucfirst($myobject);
2195 //print "objecttype=".$objecttype." module=".$module." subelement=".$subelement." classfile=".$classfile." classname=".$classname." classpath=".$classpath;
2196
2197 if ($objecttype == 'invoice_supplier') {
2198 $classfile = 'fournisseur.facture';
2199 $classname = 'FactureFournisseur';
2200 $classpath = 'fourn/class';
2201 $module = 'fournisseur';
2202 } elseif ($objecttype == 'order_supplier') {
2203 $classfile = 'fournisseur.commande';
2204 $classname = 'CommandeFournisseur';
2205 $classpath = 'fourn/class';
2206 $module = 'fournisseur';
2207 } elseif ($objecttype == 'supplier_proposal') {
2208 $classfile = 'supplier_proposal';
2209 $classname = 'SupplierProposal';
2210 $classpath = 'supplier_proposal/class';
2211 $module = 'supplier_proposal';
2212 } elseif ($objecttype == 'stock') {
2213 $classpath = 'product/stock/class';
2214 $classfile = 'entrepot';
2215 $classname = 'Entrepot';
2216 } elseif ($objecttype == 'facturerec') {
2217 $classpath = 'compta/facture/class';
2218 $classfile = 'facture-rec';
2219 $classname = 'FactureRec';
2220 $module = 'facture';
2221 } elseif ($objecttype == 'mailing') {
2222 $classpath = 'comm/mailing/class';
2223 $classfile = 'mailing';
2224 $classname = 'Mailing';
2225 }
2226
2227 if (isModEnabled($module)) {
2228 $res = dol_include_once('/'.$classpath.'/'.$classfile.'.class.php');
2229 if ($res) {
2230 if (class_exists($classname)) {
2231 $object = new $classname($db);
2232 $res = $object->fetch($objectid);
2233 if ($res > 0) {
2234 $ret = $object->getNomUrl($withpicto, $option);
2235 } elseif ($res == 0) {
2236 $ret = $langs->trans('Deleted');
2237 }
2238 unset($object);
2239 } else {
2240 dol_syslog("Class with classname ".$classname." is unknown even after the include", LOG_ERR);
2241 }
2242 }
2243 }
2244 return $ret;
2245}
2246
2247
2256function cleanCorruptedTree($db, $tabletocleantree, $fieldfkparent)
2257{
2258 $totalnb = 0;
2259 $listofid = array();
2260 $listofparentid = array();
2261
2262 // Get list of all id in array listofid and all parents in array listofparentid
2263 $sql = "SELECT rowid, ".$fieldfkparent." as parent_id FROM ".MAIN_DB_PREFIX.$tabletocleantree;
2264 $resql = $db->query($sql);
2265 if ($resql) {
2266 $num = $db->num_rows($resql);
2267 $i = 0;
2268 while ($i < $num) {
2269 $obj = $db->fetch_object($resql);
2270 $listofid[] = $obj->rowid;
2271 if ($obj->parent_id > 0) {
2272 $listofparentid[$obj->rowid] = $obj->parent_id;
2273 }
2274 $i++;
2275 }
2276 } else {
2277 dol_print_error($db);
2278 }
2279
2280 if (count($listofid)) {
2281 print 'Code requested to clean tree (may be to solve data corruption), so we check/clean orphelins and loops.'."<br>\n";
2282
2283 // Check loops on each other
2284 $sql = "UPDATE ".MAIN_DB_PREFIX.$tabletocleantree." SET ".$fieldfkparent." = 0 WHERE ".$fieldfkparent." = rowid"; // So we update only records linked to themself
2285 $resql = $db->query($sql);
2286 if ($resql) {
2287 $nb = $db->affected_rows($sql);
2288 if ($nb > 0) {
2289 print '<br>Some record that were parent of themself were cleaned.';
2290 }
2291
2292 $totalnb += $nb;
2293 }
2294 //else dol_print_error($db);
2295
2296 // Check other loops
2297 $listofidtoclean = array();
2298 foreach ($listofparentid as $id => $pid) {
2299 // Check depth
2300 //print 'Analyse record id='.$id.' with parent '.$pid.'<br>';
2301
2302 $cursor = $id;
2303 $arrayidparsed = array(); // We start from child $id
2304 while ($cursor > 0) {
2305 $arrayidparsed[$cursor] = 1;
2306 if ($arrayidparsed[$listofparentid[$cursor]]) { // We detect a loop. A record with a parent that was already into child
2307 print 'Found a loop between id '.$id.' - '.$cursor.'<br>';
2308 unset($arrayidparsed);
2309 $listofidtoclean[$cursor] = $id;
2310 break;
2311 }
2312 // @phpstan-ignore-next-line PHPStan thinks this line is never reached
2313 $cursor = $listofparentid[$cursor];
2314 }
2315
2316 if (count($listofidtoclean)) {
2317 break;
2318 }
2319 }
2320
2321 $sql = "UPDATE ".MAIN_DB_PREFIX.$db->sanitize($tabletocleantree);
2322 $sql .= " SET ".$db->sanitize($fieldfkparent)." = 0";
2323 $sql .= " WHERE rowid IN (".$db->sanitize(implode(',', $listofidtoclean)).")"; // So we update only records detected wrong
2324 $resql = $db->query($sql);
2325 if ($resql) {
2326 $nb = $db->affected_rows($sql);
2327 if ($nb > 0) {
2328 // Removed orphelins records
2329 print '<br>Some records were detected to have parent that is a child, we set them as root record for id: ';
2330 print implode(',', $listofidtoclean);
2331 }
2332
2333 $totalnb += $nb;
2334 }
2335 //else dol_print_error($db);
2336
2337 // Check and clean orphelins
2338 $sql = "UPDATE ".MAIN_DB_PREFIX.$db->sanitize($tabletocleantree);
2339 $sql .= " SET ".$db->sanitize($fieldfkparent)." = 0";
2340 $sql .= " WHERE ".$db->sanitize($fieldfkparent)." NOT IN (".$db->sanitize(implode(',', $listofid), 1).")"; // So we update only records linked to a non existing parent
2341 $resql = $db->query($sql);
2342 if ($resql) {
2343 $nb = $db->affected_rows($sql);
2344 if ($nb > 0) {
2345 // Removed orphelins records
2346 print '<br>Some orphelins were found and modified to be parent so records are visible again for id: ';
2347 print implode(',', $listofid);
2348 }
2349
2350 $totalnb += $nb;
2351 }
2352 //else dol_print_error($db);
2353
2354 print '<br>We fixed '.$totalnb.' record(s). Some records may still be corrupted. New check may be required.';
2355 return $totalnb;
2356 }
2357 return -1;
2358}
2359
2360
2370function colorArrayToHex($arraycolor, $colorifnotfound = '888888')
2371{
2372 if (!is_array($arraycolor)) {
2373 return $colorifnotfound;
2374 }
2375 if (empty($arraycolor)) {
2376 return $colorifnotfound;
2377 }
2378 return sprintf("%02s", dechex($arraycolor[0])).sprintf("%02s", dechex($arraycolor[1])).sprintf("%02s", dechex($arraycolor[2]));
2379}
2380
2391function colorStringToArray($stringcolor, $colorifnotfound = array(88, 88, 88))
2392{
2393 if (is_array($stringcolor)) {
2394 return $stringcolor; // If already into correct output format, we return as is
2395 }
2396 $reg = array();
2397 $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);
2398 if (!$tmp) {
2399 $tmp = explode(',', $stringcolor);
2400 if (count($tmp) < 3) {
2401 return $colorifnotfound;
2402 }
2403 return $tmp;
2404 }
2405 return array(hexdec($reg[1]), hexdec($reg[2]), hexdec($reg[3]));
2406}
2407
2413function colorValidateHex($color, $allow_white = true)
2414{
2415 if (!$allow_white && ($color === '#fff' || $color === '#ffffff')) {
2416 return false;
2417 }
2418
2419 if (preg_match('/^#[a-f0-9]{6}$/i', $color)) { //hex color is valid
2420 return true;
2421 }
2422 return false;
2423}
2424
2434function colorAgressiveness($hex, $ratio = -50, $brightness = 0)
2435{
2436 if (empty($ratio)) {
2437 $ratio = 0; // To avoid null
2438 }
2439
2440 // Steps should be between -255 and 255. Negative = darker, positive = lighter
2441 $ratio = max(-100, min(100, $ratio));
2442
2443 // Normalize into a six character long hex string
2444 $hex = str_replace('#', '', $hex);
2445 if (strlen($hex) == 3) {
2446 $hex = str_repeat(substr($hex, 0, 1), 2).str_repeat(substr($hex, 1, 1), 2).str_repeat(substr($hex, 2, 1), 2);
2447 }
2448
2449 // Split into three parts: R, G and B
2450 $color_parts = str_split($hex, 2);
2451 $return = '#';
2452
2453 foreach ($color_parts as $color) {
2454 $color = hexdec($color); // Convert to decimal
2455 if ($ratio > 0) { // We increase aggressivity
2456 if ($color > 127) {
2457 $color += ((255 - $color) * ($ratio / 100));
2458 }
2459 if ($color < 128) {
2460 $color -= ($color * ($ratio / 100));
2461 }
2462 } else { // We decrease aggressiveness
2463 if ($color > 128) {
2464 $color -= (($color - 128) * (abs($ratio) / 100));
2465 }
2466 if ($color < 127) {
2467 $color += ((128 - $color) * (abs($ratio) / 100));
2468 }
2469 }
2470 if ($brightness > 0) {
2471 $color = ($color * (100 + abs($brightness)) / 100);
2472 } else {
2473 $color = ($color * (100 - abs($brightness)) / 100);
2474 }
2475
2476 $color = max(0, min(255, $color)); // Adjust color to stay into valid range
2477 $return .= str_pad(dechex($color), 2, '0', STR_PAD_LEFT); // Make two char hex code
2478 }
2479
2480 //var_dump($hex.' '.$ratio.' -> '.$return);
2481 return $return;
2482}
2483
2490function colorAdjustBrightness($hex, $steps)
2491{
2492 // Steps should be between -255 and 255. Negative = darker, positive = lighter
2493 $steps = max(-255, min(255, $steps));
2494
2495 // Normalize into a six character long hex string
2496 $hex = str_replace('#', '', $hex);
2497 if (strlen($hex) == 3) {
2498 $hex = str_repeat(substr($hex, 0, 1), 2).str_repeat(substr($hex, 1, 1), 2).str_repeat(substr($hex, 2, 1), 2);
2499 }
2500
2501 // Split into three parts: R, G and B
2502 $color_parts = str_split($hex, 2);
2503 $return = '#';
2504
2505 foreach ($color_parts as $color) {
2506 $color = hexdec($color); // Convert to decimal
2507 $color = max(0, min(255, $color + $steps)); // Adjust color
2508 $return .= str_pad(dechex($color), 2, '0', STR_PAD_LEFT); // Make two char hex code
2509 }
2510
2511 return $return;
2512}
2513
2519function colorDarker($hex, $percent)
2520{
2521 $steps = intval(255 * $percent / 100) * -1;
2522 return colorAdjustBrightness($hex, $steps);
2523}
2524
2530function colorLighten($hex, $percent)
2531{
2532 $steps = intval(255 * $percent / 100);
2533 return colorAdjustBrightness($hex, $steps);
2534}
2535
2536
2543function colorHexToRgb($hex, $alpha = false, $returnArray = false)
2544{
2545 $string = '';
2546 $hex = str_replace('#', '', $hex);
2547 $length = strlen($hex);
2548 $rgb = array();
2549 $rgb['r'] = hexdec($length == 6 ? substr($hex, 0, 2) : ($length == 3 ? str_repeat(substr($hex, 0, 1), 2) : 0));
2550 $rgb['g'] = hexdec($length == 6 ? substr($hex, 2, 2) : ($length == 3 ? str_repeat(substr($hex, 1, 1), 2) : 0));
2551 $rgb['b'] = hexdec($length == 6 ? substr($hex, 4, 2) : ($length == 3 ? str_repeat(substr($hex, 2, 1), 2) : 0));
2552 if ($alpha !== false) {
2553 $rgb['a'] = (float) $alpha;
2554 $string = 'rgba('.implode(',', array_map('strval', $rgb)).')';
2555 } else {
2556 $string = 'rgb('.implode(',', array_map('strval', $rgb)).')';
2557 }
2558
2559 if ($returnArray) {
2560 return $rgb;
2561 } else {
2562 return $string;
2563 }
2564}
2565
2574function colorHexToHsl($hex, $alpha = false, $returnArray = false)
2575{
2576 $hex = str_replace('#', '', $hex);
2577 $red = hexdec(substr($hex, 0, 2)) / 255;
2578 $green = hexdec(substr($hex, 2, 2)) / 255;
2579 $blue = hexdec(substr($hex, 4, 2)) / 255;
2580
2581 $cmin = min($red, $green, $blue);
2582 $cmax = max($red, $green, $blue);
2583 $delta = $cmax - $cmin;
2584
2585 if ($delta == 0) {
2586 $hue = 0;
2587 } elseif ($cmax === $red) {
2588 $hue = (($green - $blue) / $delta);
2589 } elseif ($cmax === $green) {
2590 $hue = ($blue - $red) / $delta + 2;
2591 } else {
2592 $hue = ($red - $green) / $delta + 4;
2593 }
2594
2595 $hue = round($hue * 60);
2596 if ($hue < 0) {
2597 $hue += 360;
2598 }
2599
2600 $lightness = (($cmax + $cmin) / 2);
2601 $saturation = $delta === 0 ? 0 : ($delta / (1 - abs(2 * $lightness - 1)));
2602 if ($saturation < 0) {
2603 $saturation += 1;
2604 }
2605
2606 $lightness = round($lightness * 100);
2607 $saturation = round($saturation * 100);
2608
2609 if ($returnArray) {
2610 return array(
2611 'h' => $hue,
2612 'l' => $lightness,
2613 's' => $saturation,
2614 'a' => $alpha === false ? 1 : $alpha
2615 );
2616 } elseif ($alpha) {
2617 return 'hsla('.$hue.', '.$saturation.', '.$lightness.' / '.$alpha.')';
2618 } else {
2619 return 'hsl('.$hue.', '.$saturation.', '.$lightness.')';
2620 }
2621}
2622
2630function cartesianArray(array $input)
2631{
2632 // filter out empty values
2633 $input = array_filter($input);
2634
2635 $result = array(array());
2636
2637 foreach ($input as $key => $values) {
2638 $append = array();
2639
2640 foreach ($result as $product) {
2641 foreach ($values as $item) {
2642 $product[$key] = $item;
2643 $append[] = $product;
2644 }
2645 }
2646
2647 $result = $append;
2648 }
2649
2650 return $result;
2651}
2652
2653
2660function getModuleDirForApiClass($moduleobject)
2661{
2662 $moduledirforclass = $moduleobject;
2663 if ($moduledirforclass != 'api') {
2664 $moduledirforclass = preg_replace('/api$/i', '', $moduledirforclass);
2665 }
2666
2667 if ($moduleobject == 'contracts') {
2668 $moduledirforclass = 'contrat';
2669 } elseif (in_array($moduleobject, array('admin', 'login', 'setup', 'access', 'status', 'tools', 'documents'))) {
2670 $moduledirforclass = 'api';
2671 } elseif ($moduleobject == 'contact' || $moduleobject == 'contacts' || $moduleobject == 'customer' || $moduleobject == 'thirdparty' || $moduleobject == 'thirdparties') {
2672 $moduledirforclass = 'societe';
2673 } elseif ($moduleobject == 'propale' || $moduleobject == 'proposals') {
2674 $moduledirforclass = 'comm/propal';
2675 } elseif ($moduleobject == 'agenda' || $moduleobject == 'agendaevents') {
2676 $moduledirforclass = 'comm/action';
2677 } elseif ($moduleobject == 'adherent' || $moduleobject == 'members' || $moduleobject == 'memberstypes' || $moduleobject == 'subscriptions') {
2678 $moduledirforclass = 'adherents';
2679 } elseif ($moduleobject == 'don' || $moduleobject == 'donations') {
2680 $moduledirforclass = 'don';
2681 } elseif ($moduleobject == 'banque' || $moduleobject == 'bankaccounts') {
2682 $moduledirforclass = 'compta/bank';
2683 } elseif ($moduleobject == 'category' || $moduleobject == 'categorie') {
2684 $moduledirforclass = 'categories';
2685 } elseif ($moduleobject == 'order' || $moduleobject == 'orders') {
2686 $moduledirforclass = 'commande';
2687 } elseif ($moduleobject == 'shipments') {
2688 $moduledirforclass = 'expedition';
2689 } elseif ($moduleobject == 'multicurrencies') {
2690 $moduledirforclass = 'multicurrency';
2691 } elseif ($moduleobject == 'facture' || $moduleobject == 'invoice' || $moduleobject == 'invoices') {
2692 $moduledirforclass = 'compta/facture';
2693 } elseif ($moduleobject == 'project' || $moduleobject == 'projects' || $moduleobject == 'task' || $moduleobject == 'tasks') {
2694 $moduledirforclass = 'projet';
2695 } elseif ($moduleobject == 'stock' || $moduleobject == 'stockmovements' || $moduleobject == 'warehouses') {
2696 $moduledirforclass = 'product/stock';
2697 } elseif ($moduleobject == 'supplierproposals' || $moduleobject == 'supplierproposal' || $moduleobject == 'supplier_proposal') {
2698 $moduledirforclass = 'supplier_proposal';
2699 } elseif ($moduleobject == 'fournisseur' || $moduleobject == 'supplierinvoices' || $moduleobject == 'supplierorders') {
2700 $moduledirforclass = 'fourn';
2701 } elseif ($moduleobject == 'ficheinter' || $moduleobject == 'interventions') {
2702 $moduledirforclass = 'fichinter';
2703 } elseif ($moduleobject == 'mos') {
2704 $moduledirforclass = 'mrp';
2705 } elseif ($moduleobject == 'workstations') {
2706 $moduledirforclass = 'workstation';
2707 } elseif ($moduleobject == 'accounting') {
2708 $moduledirforclass = 'accountancy';
2709 } elseif (in_array($moduleobject, array('products', 'expensereports', 'users', 'tickets', 'boms', 'receptions', 'partnerships', 'recruitments'))) {
2710 $moduledirforclass = preg_replace('/s$/', '', $moduleobject);
2711 } elseif ($moduleobject == 'paymentsalaries') {
2712 $moduledirforclass = 'salaries';
2713 } elseif ($moduleobject == 'paymentexpensereports') {
2714 $moduledirforclass = 'expensereport';
2715 }
2716
2717 return $moduledirforclass;
2718}
2719
2727function randomColorPart($min = 0, $max = 255)
2728{
2729 return str_pad(dechex(mt_rand($min, $max)), 2, '0', STR_PAD_LEFT);
2730}
2731
2739function randomColor($min = 0, $max = 255)
2740{
2741 return randomColorPart($min, $max).randomColorPart($min, $max).randomColorPart($min, $max);
2742}
2743
2744
2745if (!function_exists('dolEscapeXML')) {
2752 function dolEscapeXML($string)
2753 {
2754 return strtr($string, array('\'' => '&apos;', '"' => '&quot;', '&' => '&amp;', '<' => '&lt;', '>' => '&gt;'));
2755 }
2756}
2757
2758
2766{
2767 global $dolibarr_main_url_root;
2768 // Define $urlwithroot
2769 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
2770 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
2771 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
2772 $notetoshow = preg_replace('/src="[a-zA-Z0-9_\/\-\.]*(viewimage\.php\?modulepart=medias[^"]*)"/', 'src="'.$urlwithroot.'/\1"', $notetoshow);
2773 return $notetoshow;
2774}
2775
2784function price2fec($amount)
2785{
2786 global $conf;
2787
2788 // Clean parameters
2789 if (empty($amount)) {
2790 $amount = 0; // To have a numeric value if amount not defined or = ''
2791 }
2792 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occurred when amount value = o (letter) instead 0 (number)
2793
2794 // Output decimal number by default
2795 $nbdecimal = (!getDolGlobalString('ACCOUNTING_FEC_DECIMAL_LENGTH') ? 2 : $conf->global->ACCOUNTING_FEC_DECIMAL_LENGTH);
2796
2797 // Output separators by default
2798 $dec = (!getDolGlobalString('ACCOUNTING_FEC_DECIMAL_SEPARATOR') ? ',' : $conf->global->ACCOUNTING_FEC_DECIMAL_SEPARATOR);
2799 $thousand = (!getDolGlobalString('ACCOUNTING_FEC_THOUSAND_SEPARATOR') ? '' : $conf->global->ACCOUNTING_FEC_THOUSAND_SEPARATOR);
2800
2801 // Format number
2802 $output = number_format($amount, $nbdecimal, $dec, $thousand);
2803
2804 return $output;
2805}
2806
2813function phpSyntaxError($code)
2814{
2815 if (!defined("CR")) {
2816 define("CR", "\r");
2817 }
2818 if (!defined("LF")) {
2819 define("LF", "\n");
2820 }
2821 if (!defined("CRLF")) {
2822 define("CRLF", "\r\n");
2823 }
2824
2825 $braces = 0;
2826 $inString = 0;
2827 foreach (token_get_all('<?php '.$code) as $token) {
2828 if (is_array($token)) {
2829 switch ($token[0]) {
2830 case T_CURLY_OPEN:
2831 case T_DOLLAR_OPEN_CURLY_BRACES:
2832 case T_START_HEREDOC:
2833 ++$inString;
2834 break;
2835 case T_END_HEREDOC:
2836 --$inString;
2837 break;
2838 }
2839 } elseif ($inString & 1) {
2840 switch ($token) {
2841 case '`':
2842 case '\'':
2843 case '"':
2844 --$inString;
2845 break;
2846 }
2847 } else {
2848 switch ($token) {
2849 case '`':
2850 case '\'':
2851 case '"':
2852 ++$inString;
2853 break;
2854 case '{':
2855 ++$braces;
2856 break;
2857 case '}':
2858 if ($inString) {
2859 --$inString;
2860 } else {
2861 --$braces;
2862 if ($braces < 0) {
2863 break 2;
2864 }
2865 }
2866 break;
2867 }
2868 }
2869 }
2870 $inString = @ini_set('log_errors', false);
2871 $token = @ini_set('display_errors', true);
2872 ob_start();
2873 $code = substr($code, strlen('<?php '));
2874 $braces || $code = "if(0){{$code}\n}";
2875 // @phan-suppress-next-line PhanPluginUnsafeEval
2876 if (eval($code) === false) {
2877 if ($braces) {
2878 $braces = PHP_INT_MAX;
2879 } else {
2880 false !== strpos($code, CR) && $code = strtr(str_replace(CRLF, LF, $code), CR, LF);
2881 $braces = substr_count($code, LF);
2882 }
2883 $code = ob_get_clean();
2884 $code = strip_tags($code);
2885 if (preg_match("'syntax error, (.+) in .+ on line (\d+)$'s", $code, $code)) {
2886 $code[2] = (int) $code[2];
2887 $code = $code[2] <= $braces
2888 ? array($code[1], $code[2])
2889 : array('unexpected $end'.substr($code[1], 14), $braces);
2890 } else {
2891 $code = array('syntax error', 0);
2892 }
2893 } else {
2894 ob_end_clean();
2895 $code = false;
2896 }
2897 @ini_set('display_errors', $token);
2898 @ini_set('log_errors', $inString);
2899 return $code;
2900}
2901
2902
2909{
2910 global $user;
2911
2912 // If $acceptlocallinktomedia is true, we can add link media files int email templates (we already can do this into HTML editor of an email).
2913 // 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:
2914 // $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
2915 // $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
2916 $acceptlocallinktomedia = getDolGlobalInt('MAIN_DISALLOW_MEDIAS_IN_EMAIL_TEMPLATES') ? 0 : 1;
2917 if ($acceptlocallinktomedia) {
2918 global $dolibarr_main_url_root;
2919 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
2920
2921 // Parse $newUrl
2922 $newUrlArray = parse_url($urlwithouturlroot);
2923 $hosttocheck = $newUrlArray['host'];
2924 $hosttocheck = str_replace(array('[', ']'), '', $hosttocheck); // Remove brackets of IPv6
2925
2926 if (function_exists('gethostbyname')) {
2927 $iptocheck = gethostbyname($hosttocheck);
2928 } else {
2929 $iptocheck = $hosttocheck;
2930 }
2931
2932 //var_dump($iptocheck.' '.$acceptlocallinktomedia);
2933 $allowParamName = 'MAIN_ALLOW_WYSIWYG_LOCAL_MEDIAS_ON_PRIVATE_NETWORK';
2934 $allowPrivateNetworkIP = getDolGlobalInt($allowParamName);
2935 if (!$allowPrivateNetworkIP && !filter_var($iptocheck, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
2936 // If ip of public url is a private network IP, we do not allow this.
2937 $acceptlocallinktomedia = 0;
2938 //dol_syslog("WYSIWYG Editor : local media not allowed (checked IP: {$iptocheck}). Use {$allowParamName} = 1 to allow local URL into WYSIWYG html content");
2939 }
2940
2941 if (preg_match('/http:/i', $urlwithouturlroot)) {
2942 // 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.
2943 $acceptlocallinktomedia = 0;
2944 // TODO Show a warning
2945 }
2946
2947 if (!empty($user->socid)) {
2948 $acceptlocallinktomedia = 0;
2949 }
2950 }
2951
2952 //return 1;
2953 return $acceptlocallinktomedia;
2954}
2955
2956
2964{
2965 $string = trim($string);
2966
2967 // If string does not start and end with parenthesis, we return $string as is.
2968 if (! preg_match('/^\‍(.*\‍)$/', $string)) {
2969 return $string;
2970 }
2971
2972 $nbofchars = dol_strlen($string);
2973 $i = 0;
2974 $g = 0;
2975 $countparenthesis = 0;
2976 while ($i < $nbofchars) {
2977 $char = dol_substr($string, $i, 1);
2978 if ($char == '(') {
2979 $countparenthesis++;
2980 } elseif ($char == ')') {
2981 $countparenthesis--;
2982 if ($countparenthesis <= 0) { // We reach the end of an independent group of parenthesis
2983 $g++;
2984 }
2985 }
2986 $i++;
2987 }
2988
2989 if ($g <= 1) {
2990 return preg_replace('/^\‍(/', '', preg_replace('/\‍)$/', '', $string));
2991 }
2992
2993 return $string;
2994}
2995
2996
3004{
3005 $arrayofcommonemoji = array(
3006 'misc' => array('2600', '26FF'), // Miscellaneous Symbols
3007 'ding' => array('2700', '27BF'), // Dingbats
3008 '????' => array('9989', '9989'), // Variation Selectors
3009 'vars' => array('FE00', 'FE0F'), // Variation Selectors
3010 'pict' => array('1F300', '1F5FF'), // Miscellaneous Symbols and Pictographs
3011 'emot' => array('1F600', '1F64F'), // Emoticons
3012 'tran' => array('1F680', '1F6FF'), // Transport and Map Symbols
3013 'flag' => array('1F1E0', '1F1FF'), // Flags (note: may be 1F1E6 instead of 1F1E0)
3014 'supp' => array('1F900', '1F9FF'), // Supplemental Symbols and Pictographs
3015 );
3016
3017 return $arrayofcommonemoji;
3018}
3019
3027function removeEmoji($text, $allowedemoji = 1)
3028{
3029 // $allowedemoji can be
3030 // 0=no emoji, 1=exclude the main known emojis (default), 2=keep only the main known (not implemented), 3=accept all
3031 // Note that to accept emoji in database, you must use utf8mb4, utf8mb3 is not enough.
3032
3033 if ($allowedemoji == 0) {
3034 // For a large removal:
3035 $text = preg_replace('/[\x{2600}-\x{FFFF}]/u', '', $text);
3036 $text = preg_replace('/[\x{10000}-\x{10FFFF}]/u', '', $text);
3037 }
3038
3039 // Delete emoji chars with a regex
3040 // See https://www.unicode.org/emoji/charts/full-emoji-list.html
3041 if ($allowedemoji == 1) {
3042 $arrayofcommonemoji = getArrayOfEmojiBis();
3043
3044 foreach ($arrayofcommonemoji as $key => $valarray) {
3045 $text = preg_replace('/[\x{'.$valarray[0].'}-\x{'.$valarray[1].'}]/u', '', $text);
3046 }
3047 }
3048
3049 if ($allowedemoji == 2) {
3050 // TODO Not yet implemented
3051 }
3052
3053 return $text;
3054}
$id
Definition account.php:39
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
Class to manage translations.
Class to manage Dolibarr users.
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:85
dol_dir_list($utf8_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:63
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...
getArrayOfEmojiBis()
Return array of Emojis for miscellaneous use.
colorHexToRgb($hex, $alpha=false, $returnArray=false)
get_string_between($string, $start, $end)
Get string from "$start" up to "$end".
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 directories that contain modules.
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 database tree (orphelins linked to a not existing parent), record linked to themself,...
colorArrayToHex($arraycolor, $colorifnotfound='888888')
Convert an array with RGB value into hex RGB value.
dol_print_reduction($reduction, $langs)
Returns formatted reduction.
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.
colorHexToHsl($hex, $alpha=false, $returnArray=false)
Color Hex to Hsl (used for style)
hexbin($hexa)
Convert an hexadecimal string into a binary string.
dol_set_user_param($db, $conf, &$user, $tab)
Save personal 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 information 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].
version_db()
Return DB version.
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...
removeEmoji($text, $allowedemoji=1)
Remove EMoji from email content.
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 information (by default a local PHP server timestamp) Rep...
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
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.
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 a Dolibarr global constant int value.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
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_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.