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