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