dolibarr 19.0.3
functions.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2000-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2003 Jean-Louis Bergamo <jlb@j1b.org>
4 * Copyright (C) 2004-2022 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
7 * Copyright (C) 2004 Christophe Combelles <ccomb@free.fr>
8 * Copyright (C) 2005-2019 Regis Houssin <regis.houssin@inodbox.com>
9 * Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr>
10 * Copyright (C) 2010-2018 Juanjo Menent <jmenent@2byte.es>
11 * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
12 * Copyright (C) 2013-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
13 * Copyright (C) 2014 Cédric GROSS <c.gross@kreiz-it.fr>
14 * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
15 * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
16 * Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
17 * Copyright (C) 2019-2023 Thibault Foucart <support@ptibogxiv.net>
18 * Copyright (C) 2020 Open-Dsi <support@open-dsi.fr>
19 * Copyright (C) 2021 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
20 * Copyright (C) 2022 Anthony Berton <anthony.berton@bb2a.fr>
21 * Copyright (C) 2022 Ferran Marcet <fmarcet@2byte.es>
22 * Copyright (C) 2022 Charlene Benke <charlene@patas-monkey.com>
23 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 3 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program. If not, see <https://www.gnu.org/licenses/>.
37 * or see https://www.gnu.org/
38 */
39
46include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
47
48// Function for better PHP x compatibility
49if (!function_exists('utf8_encode')) {
56 function utf8_encode($elements)
57 {
58 return mb_convert_encoding($elements, 'UTF-8', 'ISO-8859-1');
59 }
60}
61
62if (!function_exists('utf8_decode')) {
69 function utf8_decode($elements)
70 {
71 return mb_convert_encoding($elements, 'ISO-8859-1', 'UTF-8');
72 }
73}
74if (!function_exists('str_starts_with')) {
82 function str_starts_with($haystack, $needle)
83 {
84 return (string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0;
85 }
86}
87if (!function_exists('str_ends_with')) {
95 function str_ends_with($haystack, $needle)
96 {
97 return $needle !== '' && substr($haystack, -strlen($needle)) === (string) $needle;
98 }
99}
100if (!function_exists('str_contains')) {
108 function str_contains($haystack, $needle)
109 {
110 return $needle !== '' && mb_strpos($haystack, $needle) !== false;
111 }
112}
113
114
123function getMultidirOutput($object, $module = '')
124{
125 global $conf;
126
127 if (!is_object($object) && empty($module)) {
128 return null;
129 }
130 if (empty($module) && !empty($object->element)) {
131 $module = $object->element;
132 }
133 // Special case for backward compatibility
134 if ($module == 'fichinter') {
135 $module = 'ficheinter';
136 }
137 if (isset($conf->$module) && property_exists($conf->$module, 'multidir_output')) {
138 return $conf->$module->multidir_output[(empty($object->entity) ? $conf->entity : $object->entity)];
139 } else {
140 return 'error-diroutput-not-defined-for-this-object='.$module;
141 }
142}
143
151function getDolGlobalString($key, $default = '')
152{
153 global $conf;
154 return (string) (isset($conf->global->$key) ? $conf->global->$key : $default);
155}
156
165function getDolGlobalInt($key, $default = 0)
166{
167 global $conf;
168 return (int) (isset($conf->global->$key) ? $conf->global->$key : $default);
169}
170
179function getDolUserString($key, $default = '', $tmpuser = null)
180{
181 if (empty($tmpuser)) {
182 global $user;
183 $tmpuser = $user;
184 }
185
186 return (string) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
187}
188
197function getDolUserInt($key, $default = 0, $tmpuser = null)
198{
199 if (empty($tmpuser)) {
200 global $user;
201 $tmpuser = $user;
202 }
203
204 return (int) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
205}
206
213function isModEnabled($module)
214{
215 global $conf;
216
217 // Fix special cases
218 $arrayconv = array(
219 'bank' => 'banque',
220 'category' => 'categorie',
221 'contract' => 'contrat',
222 'project' => 'projet',
223 'delivery_note' => 'expedition'
224 );
225 if (!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD')) {
226 $arrayconv['supplier_order'] = 'fournisseur';
227 $arrayconv['supplier_invoice'] = 'fournisseur';
228 }
229 if (!empty($arrayconv[$module])) {
230 $module = $arrayconv[$module];
231 }
232
233 return !empty($conf->modules[$module]);
234 //return !empty($conf->$module->enabled);
235}
236
248function getDoliDBInstance($type, $host, $user, $pass, $name, $port)
249{
250 require_once DOL_DOCUMENT_ROOT."/core/db/".$type.'.class.php';
251
252 $class = 'DoliDB'.ucfirst($type);
253 $dolidb = new $class($type, $host, $user, $pass, $name, $port);
254 return $dolidb;
255}
256
274function getEntity($element, $shared = 1, $currentobject = null)
275{
276 global $conf, $mc, $hookmanager, $object, $action, $db;
277
278 if (!is_object($hookmanager)) {
279 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
280 $hookmanager = new HookManager($db);
281 }
282
283 // fix different element names (France to English)
284 switch ($element) {
285 case 'projet':
286 $element = 'project';
287 break;
288 case 'contrat':
289 $element = 'contract';
290 break; // "/contrat/class/contrat.class.php"
291 case 'order_supplier':
292 $element = 'supplier_order';
293 break; // "/fourn/class/fournisseur.commande.class.php"
294 case 'invoice_supplier':
295 $element = 'supplier_invoice';
296 break; // "/fourn/class/fournisseur.facture.class.php"
297 }
298
299 if (is_object($mc)) {
300 $out = $mc->getEntity($element, $shared, $currentobject);
301 } else {
302 $out = '';
303 $addzero = array('user', 'usergroup', 'cronjob', 'c_email_templates', 'email_template', 'default_values', 'overwrite_trans');
304 if (in_array($element, $addzero)) {
305 $out .= '0,';
306 }
307 $out .= ((int) $conf->entity);
308 }
309
310 // Manipulate entities to query on the fly
311 $parameters = array(
312 'element' => $element,
313 'shared' => $shared,
314 'object' => $object,
315 'currentobject' => $currentobject,
316 'out' => $out
317 );
318 $reshook = $hookmanager->executeHooks('hookGetEntity', $parameters, $currentobject, $action); // Note that $action and $object may have been modified by some hooks
319
320 if (is_numeric($reshook)) {
321 if ($reshook == 0 && !empty($hookmanager->resPrint)) {
322 $out .= ','.$hookmanager->resPrint; // add
323 } elseif ($reshook == 1) {
324 $out = $hookmanager->resPrint; // replace
325 }
326 }
327
328 return $out;
329}
330
337function setEntity($currentobject)
338{
339 global $conf, $mc;
340
341 if (is_object($mc) && method_exists($mc, 'setEntity')) {
342 return $mc->setEntity($currentobject);
343 } else {
344 return ((is_object($currentobject) && $currentobject->id > 0 && $currentobject->entity > 0) ? $currentobject->entity : $conf->entity);
345 }
346}
347
354function isASecretKey($keyname)
355{
356 return preg_match('/(_pass|password|_pw|_key|securekey|serverkey|secret\d?|p12key|exportkey|_PW_[a-z]+|token)$/i', $keyname);
357}
358
359
366function num2Alpha($n)
367{
368 for ($r = ""; $n >= 0; $n = intval($n / 26) - 1) {
369 $r = chr($n % 26 + 0x41) . $r;
370 }
371 return $r;
372}
373
374
391function getBrowserInfo($user_agent)
392{
393 include_once DOL_DOCUMENT_ROOT.'/includes/mobiledetect/mobiledetectlib/Mobile_Detect.php';
394
395 $name = 'unknown';
396 $version = '';
397 $os = 'unknown';
398 $phone = '';
399
400 $user_agent = substr($user_agent, 0, 512); // Avoid to process too large user agent
401
402 $detectmobile = new Mobile_Detect(null, $user_agent);
403 $tablet = $detectmobile->isTablet();
404
405 if ($detectmobile->isMobile()) {
406 $phone = 'unknown';
407
408 // If phone/smartphone, we set phone os name.
409 if ($detectmobile->is('AndroidOS')) {
410 $os = $phone = 'android';
411 } elseif ($detectmobile->is('BlackBerryOS')) {
412 $os = $phone = 'blackberry';
413 } elseif ($detectmobile->is('iOS')) {
414 $os = 'ios';
415 $phone = 'iphone';
416 } elseif ($detectmobile->is('PalmOS')) {
417 $os = $phone = 'palm';
418 } elseif ($detectmobile->is('SymbianOS')) {
419 $os = 'symbian';
420 } elseif ($detectmobile->is('webOS')) {
421 $os = 'webos';
422 } elseif ($detectmobile->is('MaemoOS')) {
423 $os = 'maemo';
424 } elseif ($detectmobile->is('WindowsMobileOS') || $detectmobile->is('WindowsPhoneOS')) {
425 $os = 'windows';
426 }
427 }
428
429 // OS
430 if (preg_match('/linux/i', $user_agent)) {
431 $os = 'linux';
432 } elseif (preg_match('/macintosh/i', $user_agent)) {
433 $os = 'macintosh';
434 } elseif (preg_match('/windows/i', $user_agent)) {
435 $os = 'windows';
436 }
437
438 // Name
439 $reg = array();
440 if (preg_match('/firefox(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
441 $name = 'firefox';
442 $version = empty($reg[2]) ? '' : $reg[2];
443 } elseif (preg_match('/edge(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
444 $name = 'edge';
445 $version = empty($reg[2]) ? '' : $reg[2];
446 } elseif (preg_match('/chrome(\/|\s)([\d\.]+)/i', $user_agent, $reg)) {
447 $name = 'chrome';
448 $version = empty($reg[2]) ? '' : $reg[2];
449 } elseif (preg_match('/chrome/i', $user_agent, $reg)) {
450 // we can have 'chrome (Mozilla...) chrome x.y' in one string
451 $name = 'chrome';
452 } elseif (preg_match('/iceweasel/i', $user_agent)) {
453 $name = 'iceweasel';
454 } elseif (preg_match('/epiphany/i', $user_agent)) {
455 $name = 'epiphany';
456 } elseif (preg_match('/safari(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
457 $name = 'safari';
458 $version = empty($reg[2]) ? '' : $reg[2];
459 } elseif (preg_match('/opera(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
460 // Safari is often present in string for mobile but its not.
461 $name = 'opera';
462 $version = empty($reg[2]) ? '' : $reg[2];
463 } elseif (preg_match('/(MSIE\s([0-9]+\.[0-9]))|.*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
464 $name = 'ie';
465 $version = end($reg);
466 } elseif (preg_match('/(Windows NT\s([0-9]+\.[0-9])).*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
467 // MS products at end
468 $name = 'ie';
469 $version = end($reg);
470 } elseif (preg_match('/l[iy]n(x|ks)(\‍(|\/|\s)*([\d\.]+)/i', $user_agent, $reg)) {
471 // MS products at end
472 $name = 'lynxlinks';
473 $version = empty($reg[3]) ? '' : $reg[3];
474 }
475
476 if ($tablet) {
477 $layout = 'tablet';
478 } elseif ($phone) {
479 $layout = 'phone';
480 } else {
481 $layout = 'classic';
482 }
483
484 return array(
485 'browsername' => $name,
486 'browserversion' => $version,
487 'browseros' => $os,
488 'browserua' => $user_agent,
489 'layout' => $layout, // tablet, phone, classic
490 'phone' => $phone, // deprecated
491 'tablet' => $tablet // deprecated
492 );
493}
494
500function dol_shutdown()
501{
502 global $db;
503 $disconnectdone = false;
504 $depth = 0;
505 if (is_object($db) && !empty($db->connected)) {
506 $depth = $db->transaction_opened;
507 $disconnectdone = $db->close();
508 }
509 dol_syslog("--- End access to ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]).(($disconnectdone && $depth) ? ' (Warn: db disconnection forced, transaction depth was '.$depth.')' : ''), (($disconnectdone && $depth) ? LOG_WARNING : LOG_INFO));
510}
511
521function GETPOSTISSET($paramname)
522{
523 $isset = false;
524
525 $relativepathstring = $_SERVER["PHP_SELF"];
526 // Clean $relativepathstring
527 if (constant('DOL_URL_ROOT')) {
528 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
529 }
530 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
531 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
532 //var_dump($relativepathstring);
533 //var_dump($user->default_values);
534
535 // Code for search criteria persistence.
536 // Retrieve values if restore_lastsearch_values
537 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
538 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
539 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
540 if (is_array($tmp)) {
541 foreach ($tmp as $key => $val) {
542 if ($key == $paramname) { // We are on the requested parameter
543 $isset = true;
544 break;
545 }
546 }
547 }
548 }
549 // If there is saved contextpage, limit, page or mode
550 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
551 $isset = true;
552 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
553 $isset = true;
554 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
555 $isset = true;
556 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
557 $isset = true;
558 }
559 } else {
560 $isset = (isset($_POST[$paramname]) || isset($_GET[$paramname])); // We must keep $_POST and $_GET here
561 }
562
563 return $isset;
564}
565
574function GETPOSTISARRAY($paramname, $method = 0)
575{
576 // for $method test need return the same $val as GETPOST
577 if (empty($method)) {
578 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
579 } elseif ($method == 1) {
580 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
581 } elseif ($method == 2) {
582 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
583 } elseif ($method == 3) {
584 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
585 } else {
586 $val = 'BadFirstParameterForGETPOST';
587 }
588
589 return is_array($val);
590}
591
621function GETPOST($paramname, $check = 'alphanohtml', $method = 0, $filter = null, $options = null, $noreplace = 0)
622{
623 global $mysoc, $user, $conf;
624
625 if (empty($paramname)) {
626 return 'BadFirstParameterForGETPOST';
627 }
628 if (empty($check)) {
629 dol_syslog("Deprecated use of GETPOST, called with 1st param = ".$paramname." and a 2nd param that is '', when calling page ".$_SERVER["PHP_SELF"], LOG_WARNING);
630 // Enable this line to know who call the GETPOST with '' $check parameter.
631 //var_dump(debug_backtrace()[0]);
632 }
633
634 if (empty($method)) {
635 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
636 } elseif ($method == 1) {
637 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
638 } elseif ($method == 2) {
639 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
640 } elseif ($method == 3) {
641 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
642 } else {
643 return 'BadThirdParameterForGETPOST';
644 }
645
646 if (empty($method) || $method == 3 || $method == 4) {
647 $relativepathstring = (empty($_SERVER["PHP_SELF"]) ? '' : $_SERVER["PHP_SELF"]);
648 // Clean $relativepathstring
649 if (constant('DOL_URL_ROOT')) {
650 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
651 }
652 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
653 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
654 //var_dump($relativepathstring);
655 //var_dump($user->default_values);
656
657 // Code for search criteria persistence.
658 // Retrieve saved values if restore_lastsearch_values is set
659 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
660 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
661 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
662 if (is_array($tmp)) {
663 foreach ($tmp as $key => $val) {
664 if ($key == $paramname) { // We are on the requested parameter
665 $out = $val;
666 break;
667 }
668 }
669 }
670 }
671 // If there is saved contextpage, page or limit
672 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
673 $out = $_SESSION['lastsearch_contextpage_'.$relativepathstring];
674 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
675 $out = $_SESSION['lastsearch_limit_'.$relativepathstring];
676 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
677 $out = $_SESSION['lastsearch_page_'.$relativepathstring];
678 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
679 $out = $_SESSION['lastsearch_mode_'.$relativepathstring];
680 }
681 } elseif (!isset($_GET['sortfield'])) {
682 // Else, retrieve default values if we are not doing a sort
683 // If we did a click on a field to sort, we do no apply default values. Same if option MAIN_ENABLE_DEFAULT_VALUES is not set
684 if (!empty($_GET['action']) && $_GET['action'] == 'create' && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
685 // Search default value from $object->field
686 global $object;
687 if (is_object($object) && isset($object->fields[$paramname]['default'])) {
688 $out = $object->fields[$paramname]['default'];
689 }
690 }
691 if (getDolGlobalString('MAIN_ENABLE_DEFAULT_VALUES')) {
692 if (!empty($_GET['action']) && (preg_match('/^create/', $_GET['action']) || preg_match('/^presend/', $_GET['action'])) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
693 // Now search in setup to overwrite default values
694 if (!empty($user->default_values)) { // $user->default_values defined from menu 'Setup - Default values'
695 if (isset($user->default_values[$relativepathstring]['createform'])) {
696 foreach ($user->default_values[$relativepathstring]['createform'] as $defkey => $defval) {
697 $qualified = 0;
698 if ($defkey != '_noquery_') {
699 $tmpqueryarraytohave = explode('&', $defkey);
700 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
701 $foundintru = 0;
702 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
703 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
704 $foundintru = 1;
705 }
706 }
707 if (!$foundintru) {
708 $qualified = 1;
709 }
710 //var_dump($defkey.'-'.$qualified);
711 } else {
712 $qualified = 1;
713 }
714
715 if ($qualified) {
716 if (isset($user->default_values[$relativepathstring]['createform'][$defkey][$paramname])) {
717 $out = $user->default_values[$relativepathstring]['createform'][$defkey][$paramname];
718 break;
719 }
720 }
721 }
722 }
723 }
724 } elseif (!empty($paramname) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
725 // Management of default search_filters and sort order
726 if (!empty($user->default_values)) {
727 // $user->default_values defined from menu 'Setup - Default values'
728 //var_dump($user->default_values[$relativepathstring]);
729 if ($paramname == 'sortfield' || $paramname == 'sortorder') {
730 // Sorted on which fields ? ASC or DESC ?
731 if (isset($user->default_values[$relativepathstring]['sortorder'])) {
732 // Even if paramname is sortfield, data are stored into ['sortorder...']
733 foreach ($user->default_values[$relativepathstring]['sortorder'] as $defkey => $defval) {
734 $qualified = 0;
735 if ($defkey != '_noquery_') {
736 $tmpqueryarraytohave = explode('&', $defkey);
737 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
738 $foundintru = 0;
739 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
740 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
741 $foundintru = 1;
742 }
743 }
744 if (!$foundintru) {
745 $qualified = 1;
746 }
747 //var_dump($defkey.'-'.$qualified);
748 } else {
749 $qualified = 1;
750 }
751
752 if ($qualified) {
753 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
754 foreach ($user->default_values[$relativepathstring]['sortorder'][$defkey] as $key => $val) {
755 if ($out) {
756 $out .= ', ';
757 }
758 if ($paramname == 'sortfield') {
759 $out .= dol_string_nospecial($key, '', $forbidden_chars_to_replace);
760 }
761 if ($paramname == 'sortorder') {
762 $out .= dol_string_nospecial($val, '', $forbidden_chars_to_replace);
763 }
764 }
765 //break; // No break for sortfield and sortorder so we can cumulate fields (is it realy usefull ?)
766 }
767 }
768 }
769 } elseif (isset($user->default_values[$relativepathstring]['filters'])) {
770 foreach ($user->default_values[$relativepathstring]['filters'] as $defkey => $defval) { // $defkey is a querystring like 'a=b&c=d', $defval is key of user
771 if (!empty($_GET['disabledefaultvalues'])) { // If set of default values has been disabled by a request parameter
772 continue;
773 }
774 $qualified = 0;
775 if ($defkey != '_noquery_') {
776 $tmpqueryarraytohave = explode('&', $defkey);
777 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
778 $foundintru = 0;
779 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
780 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
781 $foundintru = 1;
782 }
783 }
784 if (!$foundintru) {
785 $qualified = 1;
786 }
787 //var_dump($defkey.'-'.$qualified);
788 } else {
789 $qualified = 1;
790 }
791
792 if ($qualified && isset($user->default_values[$relativepathstring]['filters'][$defkey][$paramname])) {
793 // We must keep $_POST and $_GET here
794 if (isset($_POST['sall']) || isset($_POST['search_all']) || isset($_GET['sall']) || isset($_GET['search_all'])) {
795 // We made a search from quick search menu, do we still use default filter ?
796 if (!getDolGlobalString('MAIN_DISABLE_DEFAULT_FILTER_FOR_QUICK_SEARCH')) {
797 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
798 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
799 }
800 } else {
801 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
802 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
803 }
804 break;
805 }
806 }
807 }
808 }
809 }
810 }
811 }
812 }
813
814 // Substitution variables for GETPOST (used to get final url with variable parameters or final default value, when using variable parameters __XXX__ in the GET URL)
815 // Example of variables: __DAY__, __MONTH__, __YEAR__, __MYCOMPANY_COUNTRY_ID__, __USER_ID__, ...
816 // We do this only if var is a GET. If it is a POST, may be we want to post the text with vars as the setup text.
817 if (!is_array($out) && empty($_POST[$paramname]) && empty($noreplace)) {
818 $reg = array();
819 $maxloop = 20;
820 $loopnb = 0; // Protection against infinite loop
821 while (preg_match('/__([A-Z0-9]+_?[A-Z0-9]+)__/i', $out, $reg) && ($loopnb < $maxloop)) { // Detect '__ABCDEF__' as key 'ABCDEF' and '__ABC_DEF__' as key 'ABC_DEF'. Detection is also correct when 2 vars are side by side.
822 $loopnb++;
823 $newout = '';
824
825 if ($reg[1] == 'DAY') {
826 $tmp = dol_getdate(dol_now(), true);
827 $newout = $tmp['mday'];
828 } elseif ($reg[1] == 'MONTH') {
829 $tmp = dol_getdate(dol_now(), true);
830 $newout = $tmp['mon'];
831 } elseif ($reg[1] == 'YEAR') {
832 $tmp = dol_getdate(dol_now(), true);
833 $newout = $tmp['year'];
834 } elseif ($reg[1] == 'PREVIOUS_DAY') {
835 $tmp = dol_getdate(dol_now(), true);
836 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
837 $newout = $tmp2['day'];
838 } elseif ($reg[1] == 'PREVIOUS_MONTH') {
839 $tmp = dol_getdate(dol_now(), true);
840 $tmp2 = dol_get_prev_month($tmp['mon'], $tmp['year']);
841 $newout = $tmp2['month'];
842 } elseif ($reg[1] == 'PREVIOUS_YEAR') {
843 $tmp = dol_getdate(dol_now(), true);
844 $newout = ($tmp['year'] - 1);
845 } elseif ($reg[1] == 'NEXT_DAY') {
846 $tmp = dol_getdate(dol_now(), true);
847 $tmp2 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
848 $newout = $tmp2['day'];
849 } elseif ($reg[1] == 'NEXT_MONTH') {
850 $tmp = dol_getdate(dol_now(), true);
851 $tmp2 = dol_get_next_month($tmp['mon'], $tmp['year']);
852 $newout = $tmp2['month'];
853 } elseif ($reg[1] == 'NEXT_YEAR') {
854 $tmp = dol_getdate(dol_now(), true);
855 $newout = ($tmp['year'] + 1);
856 } elseif ($reg[1] == 'MYCOMPANY_COUNTRY_ID' || $reg[1] == 'MYCOUNTRY_ID' || $reg[1] == 'MYCOUNTRYID') {
857 $newout = $mysoc->country_id;
858 } elseif ($reg[1] == 'USER_ID' || $reg[1] == 'USERID') {
859 $newout = $user->id;
860 } elseif ($reg[1] == 'USER_SUPERVISOR_ID' || $reg[1] == 'SUPERVISOR_ID' || $reg[1] == 'SUPERVISORID') {
861 $newout = $user->fk_user;
862 } elseif ($reg[1] == 'ENTITY_ID' || $reg[1] == 'ENTITYID') {
863 $newout = $conf->entity;
864 } else {
865 $newout = ''; // Key not found, we replace with empty string
866 }
867 //var_dump('__'.$reg[1].'__ -> '.$newout);
868 $out = preg_replace('/__'.preg_quote($reg[1], '/').'__/', $newout, $out);
869 }
870 }
871
872 // Check type of variable and make sanitization according to this
873 if (preg_match('/^array/', $check)) { // If 'array' or 'array:restricthtml' or 'array:aZ09' or 'array:intcomma'
874 if (!is_array($out) || empty($out)) {
875 $out = array();
876 } else {
877 $tmparray = explode(':', $check);
878 if (!empty($tmparray[1])) {
879 $tmpcheck = $tmparray[1];
880 } else {
881 $tmpcheck = 'alphanohtml';
882 }
883 foreach ($out as $outkey => $outval) {
884 $out[$outkey] = sanitizeVal($outval, $tmpcheck, $filter, $options);
885 }
886 }
887 } else {
888 // If field name is 'search_xxx' then we force the add of space after each < and > (when following char is numeric) because it means
889 // we use the < or > to make a search on a numeric value to do higher or lower so we can add a space to break html tags
890 if (strpos($paramname, 'search_') === 0) {
891 $out = preg_replace('/([<>])([-+]?\d)/', '\1 \2', $out);
892 }
893
894 $out = sanitizeVal($out, $check, $filter, $options);
895 }
896
897 // Sanitizing for special parameters.
898 // Note: There is no reason to allow the backtopage, backtolist or backtourl parameter to contains an external URL. Only relative URLs are allowed.
899 if ($paramname == 'backtopage' || $paramname == 'backtolist' || $paramname == 'backtourl') {
900 $out = str_replace('\\', '/', $out); // Can be before the loop because only 1 char is replaced. No risk to get it after other replacements.
901 $out = str_replace(array(':', ';', '@', "\t", ' '), '', $out); // Can be before the loop because only 1 char is replaced. No risk to retreive it after other replacements.
902 do {
903 $oldstringtoclean = $out;
904 $out = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $out);
905 $out = preg_replace(array('/^[^\?]*%/'), '', $out); // We remove any % chars before the ?. Example in url: '/product/stock/card.php?action=create&backtopage=%2Fdolibarr_dev%2Fhtdocs%2Fpro%25duct%2Fcard.php%3Fid%3Dabc'
906 $out = preg_replace(array('/^[a-z]*\/\s*\/+/i'), '', $out); // We remove schema*// to remove external URL
907 } while ($oldstringtoclean != $out);
908 }
909
910 // Code for search criteria persistence.
911 // Save data into session if key start with 'search_' or is 'smonth', 'syear', 'month', 'year'
912 if (empty($method) || $method == 3 || $method == 4) {
913 if (preg_match('/^search_/', $paramname) || in_array($paramname, array('sortorder', 'sortfield'))) {
914 //var_dump($paramname.' - '.$out.' '.$user->default_values[$relativepathstring]['filters'][$paramname]);
915
916 // We save search key only if $out not empty that means:
917 // - posted value not empty, or
918 // - if posted value is empty and a default value exists that is not empty (it means we did a filter to an empty value when default was not).
919
920 if ($out != '' && isset($user)) {// $out = '0' or 'abc', it is a search criteria to keep
921 $user->lastsearch_values_tmp[$relativepathstring][$paramname] = $out;
922 }
923 }
924 }
925
926 return $out;
927}
928
938function GETPOSTINT($paramname, $method = 0)
939{
940 return (int) GETPOST($paramname, 'int', $method, null, null, 0);
941}
942
943
954function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
955{
956 return sanitizeVal($out, $check, $filter, $options);
957}
958
968function sanitizeVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
969{
970 // TODO : use class "Validate" to perform tests (and add missing tests) if needed for factorize
971 // Check is done after replacement
972 switch ($check) {
973 case 'none':
974 break;
975 case 'int': // Check param is a numeric value (integer but also float or hexadecimal)
976 if (!is_numeric($out)) {
977 $out = '';
978 }
979 break;
980 case 'intcomma':
981 if (is_array($out)) {
982 $out = implode(',', $out);
983 }
984 if (preg_match('/[^0-9,-]+/i', $out)) {
985 $out = '';
986 }
987 break;
988 case 'san_alpha':
989 $out = filter_var($out, FILTER_SANITIZE_STRING);
990 break;
991 case 'email':
992 $out = filter_var($out, FILTER_SANITIZE_EMAIL);
993 break;
994 case 'aZ':
995 if (!is_array($out)) {
996 $out = trim($out);
997 if (preg_match('/[^a-z]+/i', $out)) {
998 $out = '';
999 }
1000 }
1001 break;
1002 case 'aZ09':
1003 if (!is_array($out)) {
1004 $out = trim($out);
1005 if (preg_match('/[^a-z0-9_\-\.]+/i', $out)) {
1006 $out = '';
1007 }
1008 }
1009 break;
1010 case 'aZ09arobase': // great to sanitize $objecttype parameter
1011 if (!is_array($out)) {
1012 $out = trim($out);
1013 if (preg_match('/[^a-z0-9_\-\.@]+/i', $out)) {
1014 $out = '';
1015 }
1016 }
1017 break;
1018 case 'aZ09comma': // great to sanitize $sortfield or $sortorder params that can be 't.abc,t.def_gh'
1019 if (!is_array($out)) {
1020 $out = trim($out);
1021 if (preg_match('/[^a-z0-9_\-\.,]+/i', $out)) {
1022 $out = '';
1023 }
1024 }
1025 break;
1026 case 'alpha': // No html and no ../ and "
1027 case 'alphanohtml': // Recommended for most scalar parameters and search parameters
1028 if (!is_array($out)) {
1029 $out = trim($out);
1030 do {
1031 $oldstringtoclean = $out;
1032 // Remove html tags
1033 $out = dol_string_nohtmltag($out, 0);
1034 // Remove also other dangerous string sequences
1035 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1036 // '../' or '..\' is dangerous because it allows dir transversals
1037 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1038 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1039 } while ($oldstringtoclean != $out);
1040 // keep lines feed
1041 }
1042 break;
1043 case 'alphawithlgt': // No " and no ../ but we keep balanced < > tags with no special chars inside. Can be used for email string like "Name <email>". Less secured than 'alphanohtml'
1044 if (!is_array($out)) {
1045 $out = trim($out);
1046 do {
1047 $oldstringtoclean = $out;
1048 // Remove html tags
1049 $out = dol_html_entity_decode($out, ENT_COMPAT | ENT_HTML5, 'UTF-8');
1050 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1051 // '../' or '..\' is dangerous because it allows dir transversals
1052 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1053 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1054 } while ($oldstringtoclean != $out);
1055 }
1056 break;
1057 case 'nohtml': // No html
1058 $out = dol_string_nohtmltag($out, 0);
1059 break;
1060 case 'restricthtmlnolink':
1061 case 'restricthtml': // Recommended for most html textarea
1062 case 'restricthtmlallowclass':
1063 case 'restricthtmlallowunvalid':
1064 $out = dol_htmlwithnojs($out, 1, $check);
1065 break;
1066 case 'custom':
1067 if (!empty($out)) {
1068 if (empty($filter)) {
1069 return 'BadParameterForGETPOST - Param 3 of sanitizeVal()';
1070 }
1071 /*if (empty($options)) {
1072 return 'BadParameterForGETPOST - Param 4 of sanitizeVal()';
1073 }*/
1074 $out = filter_var($out, $filter, $options);
1075 }
1076 break;
1077 default:
1078 dol_syslog("Error, you call sanitizeVal() with a bad value for the check type. Data can't be sanitized.", LOG_ERR);
1079 break;
1080 }
1081
1082 return $out;
1083}
1084
1085
1086if (!function_exists('dol_getprefix')) {
1096 function dol_getprefix($mode = '')
1097 {
1098 // If prefix is for email (we need to have $conf already loaded for this case)
1099 if ($mode == 'email') {
1100 global $conf;
1101
1102 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID')) { // If MAIL_PREFIX_FOR_EMAIL_ID is set
1103 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID') != 'SERVER_NAME') {
1104 return $conf->global->MAIL_PREFIX_FOR_EMAIL_ID;
1105 } elseif (isset($_SERVER["SERVER_NAME"])) { // If MAIL_PREFIX_FOR_EMAIL_ID is set to 'SERVER_NAME'
1106 return $_SERVER["SERVER_NAME"];
1107 }
1108 }
1109
1110 // The recommended value if MAIL_PREFIX_FOR_EMAIL_ID is not defined (may be not defined for old versions)
1111 if (!empty($conf->file->instance_unique_id)) {
1112 return sha1('dolibarr'.$conf->file->instance_unique_id);
1113 }
1114
1115 // For backward compatibility when instance_unique_id is not set
1116 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1117 }
1118
1119 // If prefix is for session (no need to have $conf loaded)
1120 global $dolibarr_main_instance_unique_id, $dolibarr_main_cookie_cryptkey; // This is loaded by filefunc.inc.php
1121 $tmp_instance_unique_id = empty($dolibarr_main_instance_unique_id) ? (empty($dolibarr_main_cookie_cryptkey) ? '' : $dolibarr_main_cookie_cryptkey) : $dolibarr_main_instance_unique_id; // Unique id of instance
1122
1123 // The recommended value (may be not defined for old versions)
1124 if (!empty($tmp_instance_unique_id)) {
1125 return sha1('dolibarr'.$tmp_instance_unique_id);
1126 }
1127
1128 // For backward compatibility when instance_unique_id is not set
1129 if (isset($_SERVER["SERVER_NAME"]) && isset($_SERVER["DOCUMENT_ROOT"])) {
1130 return sha1($_SERVER["SERVER_NAME"].$_SERVER["DOCUMENT_ROOT"].DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1131 } else {
1132 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1133 }
1134 }
1135}
1136
1147function dol_include_once($relpath, $classname = '')
1148{
1149 global $conf, $langs, $user, $mysoc; // Do not remove this. They must be defined for files we include. Other globals var must be retrieved with $GLOBALS['var']
1150
1151 $fullpath = dol_buildpath($relpath);
1152
1153 if (!file_exists($fullpath)) {
1154 dol_syslog('functions::dol_include_once Tried to load unexisting file: '.$relpath, LOG_WARNING);
1155 return false;
1156 }
1157
1158 if (!empty($classname) && !class_exists($classname)) {
1159 return include $fullpath;
1160 } else {
1161 return include_once $fullpath;
1162 }
1163}
1164
1165
1176function dol_buildpath($path, $type = 0, $returnemptyifnotfound = 0)
1177{
1178 global $conf;
1179
1180 $path = preg_replace('/^\//', '', $path);
1181
1182 if (empty($type)) { // For a filesystem path
1183 $res = DOL_DOCUMENT_ROOT.'/'.$path; // Standard default path
1184 if (is_array($conf->file->dol_document_root)) {
1185 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array("main"=>"/home/main/htdocs", "alt0"=>"/home/dirmod/htdocs", ...)
1186 if ($key == 'main') {
1187 continue;
1188 }
1189 // if (@file_exists($dirroot.'/'.$path)) {
1190 if (@file_exists($dirroot.'/'.$path)) { // avoid [php:warn]
1191 $res = $dirroot.'/'.$path;
1192 return $res;
1193 }
1194 }
1195 }
1196 if ($returnemptyifnotfound) {
1197 // Not found into alternate dir
1198 if ($returnemptyifnotfound == 1 || !file_exists($res)) {
1199 return '';
1200 }
1201 }
1202 } else {
1203 // For an url path
1204 // We try to get local path of file on filesystem from url
1205 // Note that trying to know if a file on disk exist by forging path on disk from url
1206 // works only for some web server and some setup. This is bugged when
1207 // using proxy, rewriting, virtual path, etc...
1208 $res = '';
1209 if ($type == 1) {
1210 $res = DOL_URL_ROOT.'/'.$path; // Standard value
1211 }
1212 if ($type == 2) {
1213 $res = DOL_MAIN_URL_ROOT.'/'.$path; // Standard value
1214 }
1215 if ($type == 3) {
1216 $res = DOL_URL_ROOT.'/'.$path;
1217 }
1218
1219 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array(["main"]=>"/home/main/htdocs", ["alt0"]=>"/home/dirmod/htdocs", ...)
1220 if ($key == 'main') {
1221 if ($type == 3) {
1222 /*global $dolibarr_main_url_root;*/
1223
1224 // Define $urlwithroot
1225 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1226 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1227 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1228
1229 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).'/'.$path; // Test on start with http is for old conf syntax
1230 }
1231 continue;
1232 }
1233 $regs = array();
1234 preg_match('/^([^\?]+(\.css\.php|\.css|\.js\.php|\.js|\.png|\.jpg|\.php)?)/i', $path, $regs); // Take part before '?'
1235 if (!empty($regs[1])) {
1236 //print $key.'-'.$dirroot.'/'.$path.'-'.$conf->file->dol_url_root[$type].'<br>'."\n";
1237 //if (file_exists($dirroot.'/'.$regs[1])) {
1238 if (@file_exists($dirroot.'/'.$regs[1])) { // avoid [php:warn]
1239 if ($type == 1) {
1240 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1241 }
1242 if ($type == 2) {
1243 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_MAIN_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1244 }
1245 if ($type == 3) {
1246 /*global $dolibarr_main_url_root;*/
1247
1248 // Define $urlwithroot
1249 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1250 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1251 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1252
1253 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).$conf->file->dol_url_root[$key].'/'.$path; // Test on start with http is for old conf syntax
1254 }
1255 break;
1256 }
1257 }
1258 }
1259 }
1260
1261 return $res;
1262}
1263
1275function dol_clone($object, $native = 0)
1276{
1277 if ($native == 0) {
1278 // deprecated method, use the method with native = 2 instead
1279 $tmpsavdb = null;
1280 if (isset($object->db) && isset($object->db->db) && is_object($object->db->db) && get_class($object->db->db) == 'PgSql\Connection') {
1281 $tmpsavdb = $object->db;
1282 unset($object->db); // Such property can not be serialized with pgsl (when object->db->db = 'PgSql\Connection')
1283 }
1284
1285 $myclone = unserialize(serialize($object)); // serialize then unserialize is a hack to be sure to have a new object for all fields
1286
1287 if (!empty($tmpsavdb)) {
1288 $object->db = $tmpsavdb;
1289 }
1290 } elseif ($native == 2) {
1291 // recommended method to have a full isolated cloned object
1292 $myclone = new stdClass();
1293 $tmparray = get_object_vars($object); // return only public properties
1294
1295 if (is_array($tmparray)) {
1296 foreach ($tmparray as $propertykey => $propertyval) {
1297 if (is_scalar($propertyval) || is_array($propertyval)) {
1298 $myclone->$propertykey = $propertyval;
1299 }
1300 }
1301 }
1302 } else {
1303 $myclone = clone $object; // PHP clone is a shallow copy only, not a real clone, so properties of references will keep the reference (refering to the same target/variable)
1304 }
1305
1306 return $myclone;
1307}
1308
1318function dol_size($size, $type = '')
1319{
1320 global $conf;
1321 if (empty($conf->dol_optimize_smallscreen)) {
1322 return $size;
1323 }
1324 if ($type == 'width' && $size > 250) {
1325 return 250;
1326 } else {
1327 return 10;
1328 }
1329}
1330
1331
1343function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1)
1344{
1345 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1346 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1347 // Char '/' and '\' are file delimiters.
1348 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1349 $filesystem_forbidden_chars = array('<', '>', '/', '\\', '?', '*', '|', '"', ':', '°', '$', ';', '`');
1350 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1351 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1352 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1353 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1354 $tmp = str_replace('..', '', $tmp);
1355 return $tmp;
1356}
1357
1369function dol_sanitizePathName($str, $newstr = '_', $unaccent = 1)
1370{
1371 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1372 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1373 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1374 $filesystem_forbidden_chars = array('<', '>', '?', '*', '|', '"', '°', '$', ';', '`');
1375 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1376 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1377 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1378 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1379 $tmp = str_replace('..', '', $tmp);
1380 return $tmp;
1381}
1382
1390function dol_sanitizeUrl($stringtoclean, $type = 1)
1391{
1392 // We clean string because some hacks try to obfuscate evil strings by inserting non printable chars. Example: 'java(ascci09)scr(ascii00)ipt' is processed like 'javascript' (whatever is place of evil ascii char)
1393 // We should use dol_string_nounprintableascii but function may not be yet loaded/available
1394 $stringtoclean = preg_replace('/[\x00-\x1F\x7F]/u', '', $stringtoclean); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1395 // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: on<!-- -->error=alert(1)
1396 $stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
1397
1398 $stringtoclean = str_replace('\\', '/', $stringtoclean);
1399 if ($type == 1) {
1400 // removing : should disable links to external url like http:aaa)
1401 // removing ';' should disable "named" html entities encode into an url (we should not have this into an url)
1402 $stringtoclean = str_replace(array(':', ';', '@'), '', $stringtoclean);
1403 }
1404
1405 do {
1406 $oldstringtoclean = $stringtoclean;
1407 // removing '&colon' should disable links to external url like http:aaa)
1408 // removing '&#' should disable "numeric" html entities encode into an url (we should not have this into an url)
1409 $stringtoclean = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $stringtoclean);
1410 } while ($oldstringtoclean != $stringtoclean);
1411
1412 if ($type == 1) {
1413 // removing '//' should disable links to external url like //aaa or http//)
1414 $stringtoclean = preg_replace(array('/^[a-z]*\/\/+/i'), '', $stringtoclean);
1415 }
1416
1417 return $stringtoclean;
1418}
1419
1426function dol_sanitizeEmail($stringtoclean)
1427{
1428 do {
1429 $oldstringtoclean = $stringtoclean;
1430 $stringtoclean = str_ireplace(array('"', ':', '[', ']',"\n", "\r", '\\', '\/'), '', $stringtoclean);
1431 } while ($oldstringtoclean != $stringtoclean);
1432
1433 return $stringtoclean;
1434}
1435
1445{
1446 global $conf;
1447
1448 if (is_null($str)) {
1449 return '';
1450 }
1451
1452 if (utf8_check($str)) {
1453 if (extension_loaded('intl') && getDolGlobalString('MAIN_UNACCENT_USE_TRANSLITERATOR')) {
1454 $transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: NFC;', Transliterator::FORWARD);
1455 return $transliterator->transliterate($str);
1456 }
1457 // See http://www.utf8-chartable.de/
1458 $string = rawurlencode($str);
1459 $replacements = array(
1460 '%C3%80' => 'A', '%C3%81' => 'A', '%C3%82' => 'A', '%C3%83' => 'A', '%C3%84' => 'A', '%C3%85' => 'A',
1461 '%C3%87' => 'C',
1462 '%C3%88' => 'E', '%C3%89' => 'E', '%C3%8A' => 'E', '%C3%8B' => 'E',
1463 '%C3%8C' => 'I', '%C3%8D' => 'I', '%C3%8E' => 'I', '%C3%8F' => 'I',
1464 '%C3%91' => 'N',
1465 '%C3%92' => 'O', '%C3%93' => 'O', '%C3%94' => 'O', '%C3%95' => 'O', '%C3%96' => 'O',
1466 '%C5%A0' => 'S',
1467 '%C3%99' => 'U', '%C3%9A' => 'U', '%C3%9B' => 'U', '%C3%9C' => 'U',
1468 '%C3%9D' => 'Y', '%C5%B8' => 'y',
1469 '%C3%A0' => 'a', '%C3%A1' => 'a', '%C3%A2' => 'a', '%C3%A3' => 'a', '%C3%A4' => 'a', '%C3%A5' => 'a',
1470 '%C3%A7' => 'c',
1471 '%C3%A8' => 'e', '%C3%A9' => 'e', '%C3%AA' => 'e', '%C3%AB' => 'e',
1472 '%C3%AC' => 'i', '%C3%AD' => 'i', '%C3%AE' => 'i', '%C3%AF' => 'i',
1473 '%C3%B1' => 'n',
1474 '%C3%B2' => 'o', '%C3%B3' => 'o', '%C3%B4' => 'o', '%C3%B5' => 'o', '%C3%B6' => 'o',
1475 '%C5%A1' => 's',
1476 '%C3%B9' => 'u', '%C3%BA' => 'u', '%C3%BB' => 'u', '%C3%BC' => 'u',
1477 '%C3%BD' => 'y', '%C3%BF' => 'y'
1478 );
1479 $string = strtr($string, $replacements);
1480 return rawurldecode($string);
1481 } else {
1482 // See http://www.ascii-code.com/
1483 $string = strtr(
1484 $str,
1485 "\xC0\xC1\xC2\xC3\xC4\xC5\xC7
1486 \xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1
1487 \xD2\xD3\xD4\xD5\xD8\xD9\xDA\xDB\xDD
1488 \xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB
1489 \xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF8
1490 \xF9\xFA\xFB\xFC\xFD\xFF",
1491 "AAAAAAC
1492 EEEEIIIIDN
1493 OOOOOUUUY
1494 aaaaaaceeee
1495 iiiidnooooo
1496 uuuuyy"
1497 );
1498 $string = strtr($string, array("\xC4"=>"Ae", "\xC6"=>"AE", "\xD6"=>"Oe", "\xDC"=>"Ue", "\xDE"=>"TH", "\xDF"=>"ss", "\xE4"=>"ae", "\xE6"=>"ae", "\xF6"=>"oe", "\xFC"=>"ue", "\xFE"=>"th"));
1499 return $string;
1500 }
1501}
1502
1516function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '', $badcharstoremove = '', $keepspaces = 0)
1517{
1518 $forbidden_chars_to_replace = array("'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=", '°', '$', ';'); // more complete than dol_sanitizeFileName
1519 if (empty($keepspaces)) {
1520 $forbidden_chars_to_replace[] = " ";
1521 }
1522 $forbidden_chars_to_remove = array();
1523 //$forbidden_chars_to_remove=array("(",")");
1524
1525 if (is_array($badcharstoreplace)) {
1526 $forbidden_chars_to_replace = $badcharstoreplace;
1527 }
1528 if (is_array($badcharstoremove)) {
1529 $forbidden_chars_to_remove = $badcharstoremove;
1530 }
1531
1532 return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str));
1533}
1534
1535
1549function dol_string_nounprintableascii($str, $removetabcrlf = 1)
1550{
1551 if ($removetabcrlf) {
1552 return preg_replace('/[\x00-\x1F\x7F]/u', '', $str); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1553 } else {
1554 return preg_replace('/[\x00-\x08\x11-\x12\x14-\x1F\x7F]/u', '', $str); // /u operator should make UTF8 valid characters being ignored so are not included into the replace
1555 }
1556}
1557
1566function dol_escape_js($stringtoescape, $mode = 0, $noescapebackslashn = 0)
1567{
1568 if (is_null($stringtoescape)) {
1569 return '';
1570 }
1571
1572 // escape quotes and backslashes, newlines, etc.
1573 $substitjs = array("&#039;"=>"\\'", "\r"=>'\\r');
1574 //$substitjs['</']='<\/'; // We removed this. Should be useless.
1575 if (empty($noescapebackslashn)) {
1576 $substitjs["\n"] = '\\n';
1577 $substitjs['\\'] = '\\\\';
1578 }
1579 if (empty($mode)) {
1580 $substitjs["'"] = "\\'";
1581 $substitjs['"'] = "\\'";
1582 } elseif ($mode == 1) {
1583 $substitjs["'"] = "\\'";
1584 } elseif ($mode == 2) {
1585 $substitjs['"'] = '\\"';
1586 } elseif ($mode == 3) {
1587 $substitjs["'"] = "\\'";
1588 $substitjs['"'] = "\\\"";
1589 }
1590 return strtr($stringtoescape, $substitjs);
1591}
1592
1599function dol_escape_json($stringtoescape)
1600{
1601 return str_replace('"', '\"', $stringtoescape);
1602}
1603
1611function dol_escape_php($stringtoescape, $stringforquotes = 2)
1612{
1613 if (is_null($stringtoescape)) {
1614 return '';
1615 }
1616
1617 if ($stringforquotes == 2) {
1618 return str_replace('"', "'", $stringtoescape);
1619 }
1620 if ($stringforquotes == 1) {
1621 return str_replace("'", "\'", str_replace('"', "'", $stringtoescape));
1622 }
1623
1624 return 'Bad parameter for stringforquotes in dol_escape_php';
1625}
1626
1633function dol_escape_xml($stringtoescape)
1634{
1635 return $stringtoescape;
1636}
1637
1645function dolPrintLabel($s)
1646{
1648}
1649
1658function dolPrintHTML($s, $allowiframe = 0)
1659{
1660 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, 'common', 0, 1);
1661}
1662
1670{
1671 // The dol_htmlentitiesbr will convert simple text into html
1672 // The dol_escape_htmltag will escape html chars.
1673 return dol_escape_htmltag(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 0, 0, 0, array('br', 'b', 'font', 'span')), 1, -1, '', 0, 1);
1674}
1675
1684function dolPrintHTMLForTextArea($s, $allowiframe = 0)
1685{
1686 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, '', 0, 1);
1687}
1688
1696{
1697 return htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
1698}
1699
1700
1717function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapetags = '', $escapeonlyhtmltags = 0, $cleanalsojavascript = 0)
1718{
1719 if ($noescapetags == 'common') {
1720 $noescapetags = 'html,body,a,b,em,hr,i,u,ul,li,br,div,img,font,p,span,strong,table,tr,td,th,tbody,h1,h2,h3,h4,h5,h6,h7,h8,h9';
1721 // Add also html5 tags
1722 $noescapetags .= ',header,footer,nav,section,menu,menuitem';
1723 }
1724 if ($cleanalsojavascript) {
1725 $stringtoescape = dol_string_onlythesehtmltags($stringtoescape, 0, 0, $cleanalsojavascript, 0, array(), 0);
1726 }
1727
1728 // escape quotes and backslashes, newlines, etc.
1729 if ($escapeonlyhtmltags) {
1730 $tmp = htmlspecialchars_decode((string) $stringtoescape, ENT_COMPAT);
1731 } else {
1732 $tmp = html_entity_decode((string) $stringtoescape, ENT_COMPAT, 'UTF-8');
1733 }
1734 if (!$keepb) {
1735 $tmp = strtr($tmp, array("<b>"=>'', '</b>'=>'', '<strong>'=>'', '</strong>'=>''));
1736 }
1737 if (!$keepn) {
1738 $tmp = strtr($tmp, array("\r"=>'\\r', "\n"=>'\\n'));
1739 } elseif ($keepn == -1) {
1740 $tmp = strtr($tmp, array("\r"=>'', "\n"=>''));
1741 }
1742
1743 if ($escapeonlyhtmltags) {
1744 return htmlspecialchars($tmp, ENT_COMPAT, 'UTF-8');
1745 } else {
1746 // Escape tags to keep
1747 $tmparrayoftags = array();
1748 if ($noescapetags) {
1749 $tmparrayoftags = explode(',', $noescapetags);
1750 }
1751 if (count($tmparrayoftags)) {
1752 // TODO Does not works yet when there is attributes into tag
1753 foreach ($tmparrayoftags as $tagtoreplace) {
1754 $tmp = str_ireplace('<'.$tagtoreplace.'>', '__BEGINTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1755 $tmp = str_ireplace('</'.$tagtoreplace.'>', '__ENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1756 $tmp = str_ireplace('<'.$tagtoreplace.' />', '__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1757 }
1758 }
1759
1760 $result = htmlentities($tmp, ENT_COMPAT, 'UTF-8');
1761
1762 if (count($tmparrayoftags)) {
1763 foreach ($tmparrayoftags as $tagtoreplace) {
1764 $result = str_ireplace('__BEGINTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.'>', $result);
1765 $result = str_ireplace('__ENDTAGTOREPLACE'.$tagtoreplace.'__', '</'.$tagtoreplace.'>', $result);
1766 $result = str_ireplace('__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.' />', $result);
1767 }
1768 }
1769
1770 return $result;
1771 }
1772}
1773
1781function dol_strtolower($string, $encoding = "UTF-8")
1782{
1783 if (function_exists('mb_strtolower')) {
1784 return mb_strtolower($string, $encoding);
1785 } else {
1786 return strtolower($string);
1787 }
1788}
1789
1798function dol_strtoupper($string, $encoding = "UTF-8")
1799{
1800 if (function_exists('mb_strtoupper')) {
1801 return mb_strtoupper($string, $encoding);
1802 } else {
1803 return strtoupper($string);
1804 }
1805}
1806
1815function dol_ucfirst($string, $encoding = "UTF-8")
1816{
1817 if (function_exists('mb_substr')) {
1818 return mb_strtoupper(mb_substr($string, 0, 1, $encoding), $encoding).mb_substr($string, 1, null, $encoding);
1819 } else {
1820 return ucfirst($string);
1821 }
1822}
1823
1832function dol_ucwords($string, $encoding = "UTF-8")
1833{
1834 if (function_exists('mb_convert_case')) {
1835 return mb_convert_case($string, MB_CASE_TITLE, $encoding);
1836 } else {
1837 return ucwords($string);
1838 }
1839}
1840
1862function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = '', $restricttologhandler = '', $logcontext = null)
1863{
1864 global $conf, $user, $debugbar;
1865
1866 // If syslog module enabled
1867 if (!isModEnabled('syslog')) {
1868 return;
1869 }
1870
1871 // Check if we are into execution of code of a website
1872 if (defined('USEEXTERNALSERVER') && !defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) {
1873 global $website, $websitekey;
1874 if (is_object($website) && !empty($website->ref)) {
1875 $suffixinfilename .= '_website_'.$website->ref;
1876 } elseif (!empty($websitekey)) {
1877 $suffixinfilename .= '_website_'.$websitekey;
1878 }
1879 }
1880
1881 // Check if we have a forced suffix
1882 if (defined('USESUFFIXINLOG')) {
1883 $suffixinfilename .= constant('USESUFFIXINLOG');
1884 }
1885
1886 if ($ident < 0) {
1887 foreach ($conf->loghandlers as $loghandlerinstance) {
1888 $loghandlerinstance->setIdent($ident);
1889 }
1890 }
1891
1892 if (!empty($message)) {
1893 // Test log level
1894 $logLevels = array(LOG_EMERG=>'EMERG', LOG_ALERT=>'ALERT', LOG_CRIT=>'CRITICAL', LOG_ERR=>'ERR', LOG_WARNING=>'WARN', LOG_NOTICE=>'NOTICE', LOG_INFO=>'INFO', LOG_DEBUG=>'DEBUG');
1895 if (!array_key_exists($level, $logLevels)) {
1896 throw new Exception('Incorrect log level');
1897 }
1898 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
1899 return;
1900 }
1901
1902 if (!getDolGlobalString('MAIN_SHOW_PASSWORD_INTO_LOG')) {
1903 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
1904 }
1905
1906 // If adding log inside HTML page is required
1907 if ((!empty($_REQUEST['logtohtml']) && getDolGlobalString('MAIN_ENABLE_LOG_TO_HTML'))
1908 || (is_object($user) && $user->hasRight('debugbar', 'read') && is_object($debugbar))) {
1909 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".$logLevels[$level]." ".$message;
1910 }
1911
1912 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
1913 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
1914 if (getDolGlobalString('MAIN_ENABLE_LOG_INLINE_HTML') && !empty($_GET["log"])) {
1915 print "\n\n<!-- Log start\n";
1916 print dol_escape_htmltag($message)."\n";
1917 print "Log end -->\n";
1918 }
1919
1920 $data = array(
1921 'message' => $message,
1922 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
1923 'level' => $level,
1924 'user' => ((is_object($user) && $user->id) ? $user->login : false),
1925 'ip' => false
1926 );
1927
1928 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
1929 if (!empty($remoteip)) {
1930 $data['ip'] = $remoteip;
1931 // This is when server run behind a reverse proxy
1932 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
1933 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
1934 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
1935 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
1936 }
1937 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
1938 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
1939 $data['ip'] = $_SERVER['SERVER_ADDR'];
1940 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
1941 // This is when PHP session is ran outside a web server, like from Windows command line (Not always defined, but useful if OS defined it).
1942 $data['ip'] = $_SERVER['COMPUTERNAME'].(empty($_SERVER['USERNAME']) ? '' : '@'.$_SERVER['USERNAME']);
1943 } elseif (!empty($_SERVER['LOGNAME'])) {
1944 // This is when PHP session is ran outside a web server, like from Linux command line (Not always defined, but usefull if OS defined it).
1945 $data['ip'] = '???@'.$_SERVER['LOGNAME'];
1946 }
1947
1948 // Loop on each log handler and send output
1949 foreach ($conf->loghandlers as $loghandlerinstance) {
1950 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
1951 continue;
1952 }
1953 $loghandlerinstance->export($data, $suffixinfilename);
1954 }
1955 unset($data);
1956 }
1957
1958 if ($ident > 0) {
1959 foreach ($conf->loghandlers as $loghandlerinstance) {
1960 $loghandlerinstance->setIdent($ident);
1961 }
1962 }
1963}
1964
1981function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
1982{
1983 global $conf;
1984
1985 if (strpos($url, '?') > 0) {
1986 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1987 } else {
1988 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1989 }
1990
1991 $out = '';
1992
1993 $backtopagejsfieldsid = '';
1994 $backtopagejsfieldslabel = '';
1995 if ($backtopagejsfields) {
1996 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
1997 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
1998 $backtopagejsfields = $name.":".$backtopagejsfields;
1999 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
2000 } else {
2001 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
2002 }
2003 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
2004 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
2005 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
2006 }
2007
2008 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
2009 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
2010 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
2011 if (empty($conf->use_javascript_ajax)) {
2012 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
2013 } elseif ($jsonopen) {
2014 $out .= ' href="#" onclick="'.$jsonopen.'"';
2015 } else {
2016 $out .= ' href="#"';
2017 }
2018 $out .= '>'.$buttonstring.'</a>';
2019
2020 if (!empty($conf->use_javascript_ajax)) {
2021 // Add code to open url using the popup. Add also hidden field to retreive the returned variables
2022 $out .= '<!-- code to open popup and variables to retreive returned variables -->';
2023 $out .= '<div id="idfordialog'.$name.'" class="hidden">div for dialog</div>';
2024 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">div for returned id</div>';
2025 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">div for returned label</div>';
2026 $out .= '<!-- Add js code to open dialog popup on dialog -->';
2027 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
2028 jQuery(document).ready(function () {
2029 jQuery(".button_'.$name.'").click(function () {
2030 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
2031 var $tmpdialog = $(\'#idfordialog'.$name.'\');
2032 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
2033 $tmpdialog.dialog({
2034 autoOpen: false,
2035 modal: true,
2036 height: (window.innerHeight - 150),
2037 width: \'80%\',
2038 title: \''.dol_escape_js($label).'\',
2039 open: function (event, ui) {
2040 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
2041 },
2042 close: function (event, ui) {
2043 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
2044 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
2045 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
2046 if (returnedid != "" && returnedid != "div for returned id") {
2047 jQuery("#'.(empty($backtopagejsfieldsid) ? "none" : $backtopagejsfieldsid).'").val(returnedid);
2048 }
2049 if (returnedlabel != "" && returnedlabel != "div for returned label") {
2050 jQuery("#'.(empty($backtopagejsfieldslabel) ? "none" : $backtopagejsfieldslabel).'").val(returnedlabel);
2051 }
2052 }
2053 });
2054
2055 $tmpdialog.dialog(\'open\');
2056 return false;
2057 });
2058 });
2059 </script>';
2060 }
2061 return $out;
2062}
2063
2080function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2081{
2082 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2083}
2084
2101function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2102{
2103 global $conf, $langs, $hookmanager;
2104
2105 // Show title
2106 $showtitle = 1;
2107 if (!empty($conf->dol_optimize_smallscreen)) {
2108 $showtitle = 0;
2109 }
2110
2111 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2112
2113 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2114 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2115 }
2116
2117 // Show right part
2118 if ($morehtmlright) {
2119 $out .= '<div class="inline-block floatright tabsElem">'.$morehtmlright.'</div>'; // Output right area first so when space is missing, text is in front of tabs and not under.
2120 }
2121
2122 // Show title
2123 if (!empty($title) && $showtitle && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2124 $limittitle = 30;
2125 $out .= '<a class="tabTitle">';
2126 if ($picto) {
2127 $noprefix = $pictoisfullpath;
2128 if (strpos($picto, 'fontawesome_') !== false) {
2129 $noprefix = 1;
2130 }
2131 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2132 }
2133 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2134 $out .= '</a>';
2135 }
2136
2137 // Show tabs
2138
2139 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2140 $maxkey = -1;
2141 if (is_array($links) && !empty($links)) {
2142 $keys = array_keys($links);
2143 if (count($keys)) {
2144 $maxkey = max($keys);
2145 }
2146 }
2147
2148 // Show tabs
2149 // if =0 we don't use the feature
2150 if (empty($limittoshow)) {
2151 $limittoshow = (!getDolGlobalString('MAIN_MAXTABS_IN_CARD') ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2152 }
2153 if (!empty($conf->dol_optimize_smallscreen)) {
2154 $limittoshow = 2;
2155 }
2156
2157 $displaytab = 0;
2158 $nbintab = 0;
2159 $popuptab = 0;
2160 $outmore = '';
2161 for ($i = 0; $i <= $maxkey; $i++) {
2162 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2163 // If active tab is already present
2164 if ($i >= $limittoshow) {
2165 $limittoshow--;
2166 }
2167 }
2168 }
2169
2170 for ($i = 0; $i <= $maxkey; $i++) {
2171 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2172 $isactive = true;
2173 } else {
2174 $isactive = false;
2175 }
2176
2177 if ($i < $limittoshow || $isactive) {
2178 // Output entry with a visible tab
2179 $out .= '<div class="inline-block tabsElem'.($isactive ? ' tabsElemActive' : '').((!$isactive && getDolGlobalString('MAIN_HIDE_INACTIVETAB_ON_PRINT')) ? ' hideonprint' : '').'"><!-- id tab = '.(empty($links[$i][2]) ? '' : dol_escape_htmltag($links[$i][2])).' -->';
2180
2181 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2182 if (!empty($links[$i][0])) {
2183 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2184 } else {
2185 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2186 }
2187 } elseif (!empty($links[$i][1])) {
2188 //print "x $i $active ".$links[$i][2]." z";
2189 $out .= '<div class="tab tab'.($isactive ? 'active' : 'unactive').'" style="margin: 0 !important">';
2190 if (!empty($links[$i][0])) {
2191 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2192 $out .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="tab inline-block valignmiddle'.($morecss ? ' '.$morecss : '').(!empty($links[$i][5]) ? ' '.$links[$i][5] : '').'" href="'.$links[$i][0].'" title="'.dol_escape_htmltag($titletoshow).'">';
2193 }
2194 $out .= $links[$i][1];
2195 if (!empty($links[$i][0])) {
2196 $out .= '</a>'."\n";
2197 }
2198 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2199 $out .= '</div>';
2200 }
2201
2202 $out .= '</div>';
2203 } else {
2204 // Add entry into the combo popup with the other tabs
2205 if (!$popuptab) {
2206 $popuptab = 1;
2207 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2208 }
2209 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2210 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2211 if (!empty($links[$i][0])) {
2212 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2213 } else {
2214 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2215 }
2216 } elseif (!empty($links[$i][1])) {
2217 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2218 $outmore .= preg_replace('/([a-z])\|([a-z])/i', '\\1 | \\2', $links[$i][1]); // Replace x|y with x | y to allow wrap on long composed texts.
2219 $outmore .= '</a>'."\n";
2220 }
2221 $outmore .= '</div>';
2222
2223 $nbintab++;
2224 }
2225 $displaytab = $i;
2226 }
2227 if ($popuptab) {
2228 $outmore .= '</div>';
2229 }
2230
2231 if ($popuptab) { // If there is some tabs not shown
2232 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2233 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2234 $widthofpopup = 200;
2235
2236 $tabsname = $moretabssuffix;
2237 if (empty($tabsname)) {
2238 $tabsname = str_replace("@", "", $picto);
2239 }
2240 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2241 $out .= '<div class="tab valignmiddle"><a href="#" class="tab moretab inline-block tabunactive valignmiddle"><span class="hideonsmartphone">'.$langs->trans("More").'</span>... ('.$nbintab.')</a></div>'; // Do not use "reposition" class in the "More".
2242 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2243 $out .= $outmore;
2244 $out .= '</div>';
2245 $out .= '<div></div>';
2246 $out .= "</div>\n";
2247
2248 $out .= '<script nonce="'.getNonce().'">';
2249 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2250 var x = this.offsetLeft, y = this.offsetTop;
2251 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2252 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2253 $('#moretabsList".$tabsname."').css('".$right."','8px');
2254 }
2255 $('#moretabsList".$tabsname."').css('".$left."','auto');
2256 });
2257 ";
2258 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2259 $out .= "</script>";
2260 }
2261
2262 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2263 $out .= "</div>\n";
2264 }
2265
2266 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2267 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom'))).'">'."\n";
2268 }
2269 if (!empty($dragdropfile)) {
2270 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2271 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2272 }
2273 $parameters = array('tabname' => $active, 'out' => $out);
2274 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2275 if ($reshook > 0) {
2276 $out = $hookmanager->resPrint;
2277 }
2278
2279 return $out;
2280}
2281
2289function dol_fiche_end($notab = 0)
2290{
2291 print dol_get_fiche_end($notab);
2292}
2293
2300function dol_get_fiche_end($notab = 0)
2301{
2302 if (!$notab || $notab == -1) {
2303 return "\n</div>\n";
2304 } else {
2305 return '';
2306 }
2307}
2308
2328function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2329{
2330 global $conf, $form, $user, $langs, $hookmanager, $action;
2331
2332 $error = 0;
2333
2334 $maxvisiblephotos = 1;
2335 $showimage = 1;
2336 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2337 $showbarcode = empty($conf->barcode->enabled) ? 0 : (empty($object->barcode) ? 0 : 1);
2338 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2339 $showbarcode = 0;
2340 }
2341 $modulepart = 'unknown';
2342
2343 if ($object->element == 'societe' || $object->element == 'contact' || $object->element == 'product' || $object->element == 'ticket') {
2344 $modulepart = $object->element;
2345 } elseif ($object->element == 'member') {
2346 $modulepart = 'memberphoto';
2347 } elseif ($object->element == 'user') {
2348 $modulepart = 'userphoto';
2349 }
2350
2351 if (class_exists("Imagick")) {
2352 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2353 $modulepart = $object->element;
2354 } elseif ($object->element == 'fichinter') {
2355 $modulepart = 'ficheinter';
2356 } elseif ($object->element == 'contrat') {
2357 $modulepart = 'contract';
2358 } elseif ($object->element == 'order_supplier') {
2359 $modulepart = 'supplier_order';
2360 } elseif ($object->element == 'invoice_supplier') {
2361 $modulepart = 'supplier_invoice';
2362 }
2363 }
2364
2365 if ($object->element == 'product') {
2366 $width = 80;
2367 $cssclass = 'photowithmargin photoref';
2368 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2369 $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : 5);
2370 if ($conf->browser->layout == 'phone') {
2371 $maxvisiblephotos = 1;
2372 }
2373 if ($showimage) {
2374 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$object->show_photos('product', $conf->product->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, 0, $width, 0, '').'</div>';
2375 } else {
2376 if (getDolGlobalString('PRODUCT_NODISPLAYIFNOPHOTO')) {
2377 $nophoto = '';
2378 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2379 } else { // Show no photo link
2380 $nophoto = '/public/theme/common/nophoto.png';
2381 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" title="'.dol_escape_htmltag($langs->trans("UploadAnImageToSeeAPhotoHere", $langs->transnoentitiesnoconv("Documents"))).'" alt="No photo"'.($width ? ' style="width: '.$width.'px"' : '').' src="'.DOL_URL_ROOT.$nophoto.'"></div>';
2382 }
2383 }
2384 } elseif ($object->element == 'ticket') {
2385 $width = 80;
2386 $cssclass = 'photoref';
2387 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2388 $maxvisiblephotos = (isset($conf->global->TICKET_MAX_VISIBLE_PHOTO) ? $conf->global->TICKET_MAX_VISIBLE_PHOTO : 2);
2389 if ($conf->browser->layout == 'phone') {
2390 $maxvisiblephotos = 1;
2391 }
2392
2393 if ($showimage) {
2394 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2395 if ($object->nbphoto > 0) {
2396 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2397 } else {
2398 $showimage = 0;
2399 }
2400 }
2401 if (!$showimage) {
2402 if (getDolGlobalString('TICKET_NODISPLAYIFNOPHOTO')) {
2403 $nophoto = '';
2404 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2405 } else { // Show no photo link
2406 $nophoto = img_picto('No photo', 'object_ticket');
2407 $morehtmlleft .= '<!-- No photo to show -->';
2408 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2409 $morehtmlleft .= $nophoto;
2410 $morehtmlleft .= '</div></div>';
2411 }
2412 }
2413 } else {
2414 if ($showimage) {
2415 if ($modulepart != 'unknown') {
2416 $phototoshow = '';
2417 // Check if a preview file is available
2418 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2419 $objectref = dol_sanitizeFileName($object->ref);
2420 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2421 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2422 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2423 $subdir .= ((!empty($subdir) && !preg_match('/\/$/', $subdir)) ? '/' : '').$objectref; // the objectref dir is not included into get_exdir when used with level=2, so we add it at end
2424 } else {
2425 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2426 }
2427 if (empty($subdir)) {
2428 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2429 }
2430
2431 $filepath = $dir_output.$subdir."/";
2432
2433 $filepdf = $filepath.$objectref.".pdf";
2434 $relativepath = $subdir.'/'.$objectref.'.pdf';
2435
2436 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2437 $fileimage = $filepdf.'_preview.png';
2438 $relativepathimage = $relativepath.'_preview.png';
2439
2440 $pdfexists = file_exists($filepdf);
2441
2442 // If PDF file exists
2443 if ($pdfexists) {
2444 // Conversion du PDF en image png si fichier png non existant
2445 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2446 if (!getDolGlobalString('MAIN_DISABLE_PDF_THUMBS')) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2447 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2448 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2449 if ($ret < 0) {
2450 $error++;
2451 }
2452 }
2453 }
2454 }
2455
2456 if ($pdfexists && !$error) {
2457 $heightforphotref = 80;
2458 if (!empty($conf->dol_optimize_smallscreen)) {
2459 $heightforphotref = 60;
2460 }
2461 // If the preview file is found
2462 if (file_exists($fileimage)) {
2463 $phototoshow = '<div class="photoref">';
2464 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2465 $phototoshow .= '</div>';
2466 }
2467 }
2468 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo'
2469 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2470 }
2471
2472 if ($phototoshow) {
2473 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2474 $morehtmlleft .= $phototoshow;
2475 $morehtmlleft .= '</div>';
2476 }
2477 }
2478
2479 if (empty($phototoshow)) { // Show No photo link (picto of object)
2480 if ($object->element == 'action') {
2481 $width = 80;
2482 $cssclass = 'photorefcenter';
2483 $nophoto = img_picto('No photo', 'title_agenda');
2484 } else {
2485 $width = 14;
2486 $cssclass = 'photorefcenter';
2487 $picto = $object->picto;
2488 $prefix = 'object_';
2489 if ($object->element == 'project' && !$object->public) {
2490 $picto = 'project'; // instead of projectpub
2491 }
2492 if (strpos($picto, 'fontawesome_') !== false) {
2493 $prefix = '';
2494 }
2495 $nophoto = img_picto('No photo', $prefix.$picto);
2496 }
2497 $morehtmlleft .= '<!-- No photo to show -->';
2498 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2499 $morehtmlleft .= $nophoto;
2500 $morehtmlleft .= '</div></div>';
2501 }
2502 }
2503 }
2504
2505 // Show barcode
2506 if ($showbarcode) {
2507 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2508 }
2509
2510 if ($object->element == 'societe') {
2511 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2512 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2513 } else {
2514 $morehtmlstatus .= $object->getLibStatut(6);
2515 }
2516 } elseif ($object->element == 'product') {
2517 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2518 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2519 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2520 } else {
2521 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2522 }
2523 $morehtmlstatus .= ' &nbsp; ';
2524 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2525 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2526 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2527 } else {
2528 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2529 }
2530 } elseif (in_array($object->element, array('salary'))) {
2531 $tmptxt = $object->getLibStatut(6, $object->alreadypaid);
2532 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2533 $tmptxt = $object->getLibStatut(5, $object->alreadypaid);
2534 }
2535 $morehtmlstatus .= $tmptxt;
2536 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier', 'chargesociales', 'loan', 'tva'))) { // TODO Move this to use ->alreadypaid
2537 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2538 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2539 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2540 }
2541 $morehtmlstatus .= $tmptxt;
2542 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2543 if ($object->statut == 0) {
2544 $morehtmlstatus .= $object->getLibStatut(5);
2545 } else {
2546 $morehtmlstatus .= $object->getLibStatut(4);
2547 }
2548 } elseif ($object->element == 'facturerec') {
2549 if ($object->frequency == 0) {
2550 $morehtmlstatus .= $object->getLibStatut(2);
2551 } else {
2552 $morehtmlstatus .= $object->getLibStatut(5);
2553 }
2554 } elseif ($object->element == 'project_task') {
2555 $object->fk_statut = 1;
2556 if ($object->progress > 0) {
2557 $object->fk_statut = 2;
2558 }
2559 if ($object->progress >= 100) {
2560 $object->fk_statut = 3;
2561 }
2562 $tmptxt = $object->getLibStatut(5);
2563 $morehtmlstatus .= $tmptxt; // No status on task
2564 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2565 $tmptxt = $object->getLibStatut(6);
2566 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2567 $tmptxt = $object->getLibStatut(5);
2568 }
2569 $morehtmlstatus .= $tmptxt;
2570 }
2571
2572 // Add if object was dispatched "into accountancy"
2573 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2574 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2575 if (method_exists($object, 'getVentilExportCompta')) {
2576 $accounted = $object->getVentilExportCompta();
2577 $langs->load("accountancy");
2578 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2579 }
2580 }
2581
2582 // Add alias for thirdparty
2583 if (!empty($object->name_alias)) {
2584 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
2585 }
2586
2587 // Add label
2588 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
2589 if (!empty($object->label)) {
2590 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
2591 }
2592 }
2593
2594 // Show address and email
2595 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
2596 $moreaddress = $object->getBannerAddress('refaddress', $object); // address, email, url, social networks
2597 if ($moreaddress) {
2598 $morehtmlref .= '<div class="refidno refaddress">';
2599 $morehtmlref .= $moreaddress;
2600 $morehtmlref .= '</div>';
2601 }
2602 }
2603 if (getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && (getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') == '1' || preg_match('/'.preg_quote($object->element, '/').'/i', $conf->global->MAIN_SHOW_TECHNICAL_ID)) && !empty($object->id)) {
2604 $morehtmlref .= '<div style="clear: both;"></div>';
2605 $morehtmlref .= '<div class="refidno opacitymedium">';
2606 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
2607 $morehtmlref .= '</div>';
2608 }
2609
2610 $parameters=array('morehtmlref'=>$morehtmlref);
2611 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
2612 if ($reshook < 0) {
2613 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2614 } elseif (empty($reshook)) {
2615 $morehtmlref .= $hookmanager->resPrint;
2616 } elseif ($reshook > 0) {
2617 $morehtmlref = $hookmanager->resPrint;
2618 }
2619
2620 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
2621 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
2622 print '</div>';
2623 print '<div class="underrefbanner clearboth"></div>';
2624}
2625
2635function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
2636{
2637 global $langs;
2638 $ret = '';
2639 if ($fieldrequired) {
2640 $ret .= '<span class="fieldrequired">';
2641 }
2642 $ret .= '<label for="'.$fieldkey.'">';
2643 $ret .= $langs->trans($langkey);
2644 $ret .= '</label>';
2645 if ($fieldrequired) {
2646 $ret .= '</span>';
2647 }
2648 return $ret;
2649}
2650
2658function dol_bc($var, $moreclass = '')
2659{
2660 global $bc;
2661 $ret = ' '.$bc[$var];
2662 if ($moreclass) {
2663 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
2664 }
2665 return $ret;
2666}
2667
2681function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = '', $mode = 0, $extralangcode = '')
2682{
2683 global $conf, $langs, $hookmanager;
2684
2685 $ret = '';
2686 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
2687
2688 // See format of addresses on https://en.wikipedia.org/wiki/Address
2689 // Address
2690 if (empty($mode)) {
2691 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
2692 }
2693 // Zip/Town/State
2694 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || getDolGlobalString('MAIN_FORCE_STATE_INTO_ADDRESS')) {
2695 // US: title firstname name \n address lines \n town, state, zip \n country
2696 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2697 $ret .= (($ret && $town) ? $sep : '').$town;
2698
2699 if (!empty($object->state)) {
2700 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
2701 }
2702 if (!empty($object->zip)) {
2703 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
2704 }
2705 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
2706 // UK: title firstname name \n address lines \n town state \n zip \n country
2707 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2708 $ret .= ($ret ? $sep : '').$town;
2709 if (!empty($object->state)) {
2710 $ret .= ($ret ? ", " : '').$object->state;
2711 }
2712 if (!empty($object->zip)) {
2713 $ret .= ($ret ? $sep : '').$object->zip;
2714 }
2715 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
2716 // ES: title firstname name \n address lines \n zip town \n state \n country
2717 $ret .= ($ret ? $sep : '').$object->zip;
2718 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2719 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2720 if (!empty($object->state)) {
2721 $ret .= $sep.$object->state;
2722 }
2723 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
2724 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
2725 // See https://www.sljfaq.org/afaq/addresses.html
2726 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2727 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
2728 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
2729 // IT: title firstname name\n address lines \n zip town state_code \n country
2730 $ret .= ($ret ? $sep : '').$object->zip;
2731 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2732 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2733 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
2734 } else {
2735 // Other: title firstname name \n address lines \n zip town[, state] \n country
2736 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2737 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
2738 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
2739 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
2740 $ret .= ($ret ? ", " : '').$object->state;
2741 }
2742 }
2743
2744 if (!is_object($outputlangs)) {
2745 $outputlangs = $langs;
2746 }
2747 if ($withcountry) {
2748 $langs->load("dict");
2749 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
2750 }
2751 if ($hookmanager) {
2752 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
2753 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
2754 if ($reshook > 0) {
2755 $ret = '';
2756 }
2757 $ret .= $hookmanager->resPrint;
2758 }
2759
2760 return $ret;
2761}
2762
2763
2764
2773function dol_strftime($fmt, $ts = false, $is_gmt = false)
2774{
2775 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
2776 return ($is_gmt) ? @gmstrftime($fmt, $ts) : @strftime($fmt, $ts);
2777 } else {
2778 return 'Error date into a not supported range';
2779 }
2780}
2781
2803function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = '', $encodetooutput = false)
2804{
2805 global $conf, $langs;
2806
2807 // If date undefined or "", we return ""
2808 if (dol_strlen($time) == 0) {
2809 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
2810 }
2811
2812 if ($tzoutput === 'auto') {
2813 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
2814 }
2815
2816 // Clean parameters
2817 $to_gmt = false;
2818 $offsettz = $offsetdst = 0;
2819 if ($tzoutput) {
2820 $to_gmt = true; // For backward compatibility
2821 if (is_string($tzoutput)) {
2822 if ($tzoutput == 'tzserver') {
2823 $to_gmt = false;
2824 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
2825 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
2826 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
2827 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
2828 $to_gmt = true;
2829 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
2830
2831 if (class_exists('DateTimeZone')) {
2832 $user_date_tz = new DateTimeZone($offsettzstring);
2833 $user_dt = new DateTime();
2834 $user_dt->setTimezone($user_date_tz);
2835 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
2836 $offsettz = $user_dt->getOffset(); // should include dst ?
2837 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
2838 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
2839 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
2840 }
2841 }
2842 }
2843 }
2844 if (!is_object($outputlangs)) {
2845 $outputlangs = $langs;
2846 }
2847 if (!$format) {
2848 $format = 'daytextshort';
2849 }
2850
2851 // Do we have to reduce the length of date (year on 2 chars) to save space.
2852 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
2853 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour', 'dayhoursec'))) ? 1 : 0; // Test on original $format param.
2854 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
2855 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
2856 if ($formatwithoutreduce != $format) {
2857 $format = $formatwithoutreduce;
2858 $reduceformat = 1;
2859 } // so format 'dayreduceformat' is processed like day
2860
2861 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
2862 // TODO Add format daysmallyear and dayhoursmallyear
2863 if ($format == 'day') {
2864 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
2865 } elseif ($format == 'hour') {
2866 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
2867 } elseif ($format == 'hourduration') {
2868 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
2869 } elseif ($format == 'daytext') {
2870 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
2871 } elseif ($format == 'daytextshort') {
2872 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
2873 } elseif ($format == 'dayhour') {
2874 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
2875 } elseif ($format == 'dayhoursec') {
2876 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
2877 } elseif ($format == 'dayhourtext') {
2878 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
2879 } elseif ($format == 'dayhourtextshort') {
2880 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
2881 } elseif ($format == 'dayhourlog') {
2882 // Format not sensitive to language
2883 $format = '%Y%m%d%H%M%S';
2884 } elseif ($format == 'dayhourlogsmall') {
2885 // Format not sensitive to language
2886 $format = '%y%m%d%H%M';
2887 } elseif ($format == 'dayhourldap') {
2888 $format = '%Y%m%d%H%M%SZ';
2889 } elseif ($format == 'dayhourxcard') {
2890 $format = '%Y%m%dT%H%M%SZ';
2891 } elseif ($format == 'dayxcard') {
2892 $format = '%Y%m%d';
2893 } elseif ($format == 'dayrfc') {
2894 $format = '%Y-%m-%d'; // DATE_RFC3339
2895 } elseif ($format == 'dayhourrfc') {
2896 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
2897 } elseif ($format == 'standard') {
2898 $format = '%Y-%m-%d %H:%M:%S';
2899 }
2900
2901 if ($reduceformat) {
2902 $format = str_replace('%Y', '%y', $format);
2903 $format = str_replace('yyyy', 'yy', $format);
2904 }
2905
2906 // Clean format
2907 if (preg_match('/%b/i', $format)) { // There is some text to translate
2908 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2909 $format = str_replace('%b', '__b__', $format);
2910 $format = str_replace('%B', '__B__', $format);
2911 }
2912 if (preg_match('/%a/i', $format)) { // There is some text to translate
2913 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2914 $format = str_replace('%a', '__a__', $format);
2915 $format = str_replace('%A', '__A__', $format);
2916 }
2917
2918 // Analyze date
2919 $reg = array();
2920 if (preg_match('/^([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])$/i', $time, $reg)) { // Deprecated. Ex: 1970-01-01, 1970-01-01 01:00:00, 19700101010000
2921 dol_print_error('', "Functions.lib::dol_print_date function called with a bad value from page ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]));
2922 return '';
2923 } elseif (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?/i', $time, $reg)) { // Still available to solve problems in extrafields of type date
2924 // This part of code should not be used anymore.
2925 dol_syslog("Functions.lib::dol_print_date function called with a bad value from page ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]), LOG_WARNING);
2926 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
2927 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
2928 $syear = (!empty($reg[1]) ? $reg[1] : '');
2929 $smonth = (!empty($reg[2]) ? $reg[2] : '');
2930 $sday = (!empty($reg[3]) ? $reg[3] : '');
2931 $shour = (!empty($reg[4]) ? $reg[4] : '');
2932 $smin = (!empty($reg[5]) ? $reg[5] : '');
2933 $ssec = (!empty($reg[6]) ? $reg[6] : '');
2934
2935 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
2936
2937 if ($to_gmt) {
2938 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2939 } else {
2940 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2941 }
2942 $dtts = new DateTime();
2943 $dtts->setTimestamp($time);
2944 $dtts->setTimezone($tzo);
2945 $newformat = str_replace(
2946 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2947 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2948 $format
2949 );
2950 $ret = $dtts->format($newformat);
2951 $ret = str_replace(
2952 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2953 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2954 $ret
2955 );
2956 } else {
2957 // Date is a timestamps
2958 if ($time < 100000000000) { // Protection against bad date values
2959 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2960
2961 if ($to_gmt) {
2962 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2963 } else {
2964 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2965 }
2966 $dtts = new DateTime();
2967 $dtts->setTimestamp($timetouse);
2968 $dtts->setTimezone($tzo);
2969 $newformat = str_replace(
2970 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2971 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2972 $format
2973 );
2974 $ret = $dtts->format($newformat);
2975 $ret = str_replace(
2976 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2977 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2978 $ret
2979 );
2980 //var_dump($ret);exit;
2981 } else {
2982 $ret = 'Bad value '.$time.' for date';
2983 }
2984 }
2985
2986 if (preg_match('/__b__/i', $format)) {
2987 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2988
2989 if ($to_gmt) {
2990 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2991 } else {
2992 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2993 }
2994 $dtts = new DateTime();
2995 $dtts->setTimestamp($timetouse);
2996 $dtts->setTimezone($tzo);
2997 $month = $dtts->format("m");
2998 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
2999 if ($encodetooutput) {
3000 $monthtext = $outputlangs->transnoentities('Month'.$month);
3001 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
3002 } else {
3003 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
3004 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
3005 }
3006 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
3007 $ret = str_replace('__b__', $monthtextshort, $ret);
3008 $ret = str_replace('__B__', $monthtext, $ret);
3009 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
3010 //return $ret;
3011 }
3012 if (preg_match('/__a__/i', $format)) {
3013 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
3014 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
3015
3016 if ($to_gmt) {
3017 $tzo = new DateTimeZone('UTC');
3018 } else {
3019 $tzo = new DateTimeZone(date_default_timezone_get());
3020 }
3021 $dtts = new DateTime();
3022 $dtts->setTimestamp($timetouse);
3023 $dtts->setTimezone($tzo);
3024 $w = $dtts->format("w");
3025 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
3026
3027 $ret = str_replace('__A__', $dayweek, $ret);
3028 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
3029 }
3030
3031 return $ret;
3032}
3033
3034
3055function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
3056{
3057 if ($timestamp === '') {
3058 return array();
3059 }
3060
3061 $datetimeobj = new DateTime();
3062 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
3063 if ($forcetimezone) {
3064 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
3065 }
3066 $arrayinfo = array(
3067 'year'=>((int) date_format($datetimeobj, 'Y')),
3068 'mon'=>((int) date_format($datetimeobj, 'm')),
3069 'mday'=>((int) date_format($datetimeobj, 'd')),
3070 'wday'=>((int) date_format($datetimeobj, 'w')),
3071 'yday'=>((int) date_format($datetimeobj, 'z')),
3072 'hours'=>((int) date_format($datetimeobj, 'H')),
3073 'minutes'=>((int) date_format($datetimeobj, 'i')),
3074 'seconds'=>((int) date_format($datetimeobj, 's')),
3075 '0'=>$timestamp
3076 );
3077
3078 return $arrayinfo;
3079}
3080
3102function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3103{
3104 global $conf;
3105 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3106
3107 if ($gm === 'auto') {
3108 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3109 }
3110 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3111
3112 // Clean parameters
3113 if ($hour == -1 || empty($hour)) {
3114 $hour = 0;
3115 }
3116 if ($minute == -1 || empty($minute)) {
3117 $minute = 0;
3118 }
3119 if ($second == -1 || empty($second)) {
3120 $second = 0;
3121 }
3122
3123 // Check parameters
3124 if ($check) {
3125 if (!$month || !$day) {
3126 return '';
3127 }
3128 if ($day > 31) {
3129 return '';
3130 }
3131 if ($month > 12) {
3132 return '';
3133 }
3134 if ($hour < 0 || $hour > 24) {
3135 return '';
3136 }
3137 if ($minute < 0 || $minute > 60) {
3138 return '';
3139 }
3140 if ($second < 0 || $second > 60) {
3141 return '';
3142 }
3143 }
3144
3145 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3146 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3147 $localtz = new DateTimeZone($default_timezone);
3148 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3149 // We use dol_tz_string first because it is more reliable.
3150 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3151 try {
3152 $localtz = new DateTimeZone($default_timezone);
3153 } catch (Exception $e) {
3154 dol_syslog("Warning dol_tz_string contains an invalid value ".$_SESSION["dol_tz_string"], LOG_WARNING);
3155 $default_timezone = @date_default_timezone_get();
3156 }
3157 } elseif (strrpos($gm, "tz,") !== false) {
3158 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3159 try {
3160 $localtz = new DateTimeZone($timezone);
3161 } catch (Exception $e) {
3162 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3163 }
3164 }
3165
3166 if (empty($localtz)) {
3167 $localtz = new DateTimeZone('UTC');
3168 }
3169 //var_dump($localtz);
3170 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3171 $dt = new DateTime('now', $localtz);
3172 $dt->setDate((int) $year, (int) $month, (int) $day);
3173 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3174 $date = $dt->getTimestamp(); // should include daylight saving time
3175 //var_dump($date);
3176 return $date;
3177}
3178
3179
3190function dol_now($mode = 'auto')
3191{
3192 $ret = 0;
3193
3194 if ($mode === 'auto') {
3195 $mode = 'gmt';
3196 }
3197
3198 if ($mode == 'gmt') {
3199 $ret = time(); // Time for now at greenwich.
3200 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3201 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3202 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3203 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3204 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3205 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3206 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3207 // $ret=dol_now('gmt')+($tzsecond*3600);
3208 //}
3209 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3210 // Time for now with user timezone added
3211 //print 'time: '.time();
3212 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3213 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3214 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3215 }
3216
3217 return $ret;
3218}
3219
3220
3229function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3230{
3231 global $conf, $langs;
3232 $level = 1024;
3233
3234 if (!empty($conf->dol_optimize_smallscreen)) {
3235 $shortunit = 1;
3236 }
3237
3238 // Set value text
3239 if (empty($shortvalue) || $size < ($level * 10)) {
3240 $ret = $size;
3241 $textunitshort = $langs->trans("b");
3242 $textunitlong = $langs->trans("Bytes");
3243 } else {
3244 $ret = round($size / $level, 0);
3245 $textunitshort = $langs->trans("Kb");
3246 $textunitlong = $langs->trans("KiloBytes");
3247 }
3248 // Use long or short text unit
3249 if (empty($shortunit)) {
3250 $ret .= ' '.$textunitlong;
3251 } else {
3252 $ret .= ' '.$textunitshort;
3253 }
3254
3255 return $ret;
3256}
3257
3268function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = '')
3269{
3270 global $langs;
3271
3272 if (empty($url)) {
3273 return '';
3274 }
3275
3276 $linkstart = '<a href="';
3277 if (!preg_match('/^http/i', $url)) {
3278 $linkstart .= 'http://';
3279 }
3280 $linkstart .= $url;
3281 $linkstart .= '"';
3282 if ($target) {
3283 $linkstart .= ' target="'.$target.'"';
3284 }
3285 $linkstart .= ' title="'.$langs->trans("URL").': '.$url.'"';
3286 $linkstart .= '>';
3287
3288 $link = '';
3289 if (!preg_match('/^http/i', $url)) {
3290 $link .= 'http://';
3291 }
3292 $link .= dol_trunc($url, $max);
3293
3294 $linkend = '</a>';
3295
3296 if ($morecss == 'float') { // deprecated
3297 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto($langs->trans("Url"), 'globe', 'class="paddingrightonly"') : '').$link.'</div>';
3298 } else {
3299 return $linkstart.'<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto('', 'globe', 'class="paddingrightonly"') : '').$link.'</span>'.$linkend;
3300 }
3301}
3302
3315function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3316{
3317 global $user, $langs, $hookmanager;
3318
3319 //global $conf; $conf->global->AGENDA_ADDACTIONFOREMAIL = 1;
3320 //$showinvalid = 1; $email = 'rrrrr';
3321
3322 $newemail = dol_escape_htmltag($email);
3323
3324 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && $withpicto) {
3325 $withpicto = 0;
3326 }
3327
3328 if (empty($email)) {
3329 return '&nbsp;';
3330 }
3331
3332 if (!empty($addlink)) {
3333 $newemail = '<a class="paddingrightonly" style="text-overflow: ellipsis;" href="';
3334 if (!preg_match('/^mailto:/i', $email)) {
3335 $newemail .= 'mailto:';
3336 }
3337 $newemail .= $email;
3338 $newemail .= '">';
3339
3340 $newemail .= ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '');
3341
3342 $newemail .= dol_trunc($email, $max);
3343 $newemail .= '</a>';
3344 if ($showinvalid && !isValidEmail($email)) {
3345 $langs->load("errors");
3346 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email), '', 'paddingrightonly');
3347 }
3348
3349 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3350 $type = 'AC_EMAIL';
3351 $linktoaddaction = '';
3352 if (getDolGlobalString('AGENDA_ADDACTIONFOREMAIL')) {
3353 $linktoaddaction = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.urlencode($type).'&amp;contactid='.((int) $cid).'&amp;socid='.((int) $socid).'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3354 }
3355 if ($linktoaddaction) {
3356 $newemail = '<div>'.$newemail.' '.$linktoaddaction.'</div>';
3357 }
3358 }
3359 } else {
3360 $newemail = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3361
3362 if ($showinvalid && !isValidEmail($email)) {
3363 $langs->load("errors");
3364 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3365 }
3366 }
3367
3368 //$rep = '<div class="nospan" style="margin-right: 10px">';
3369 //$rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3370 //$rep .= '</div>';
3371 $rep = $newemail;
3372
3373 if ($hookmanager) {
3374 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3375
3376 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3377 if ($reshook > 0) {
3378 $rep = '';
3379 }
3380 $rep .= $hookmanager->resPrint;
3381 }
3382
3383 return $rep;
3384}
3385
3392{
3393 global $conf, $db;
3394
3395 $socialnetworks = array();
3396 // Enable caching of array
3397 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3398 $cachekey = 'socialnetworks_' . $conf->entity;
3399 $dataretrieved = dol_getcache($cachekey);
3400 if (!is_null($dataretrieved)) {
3401 $socialnetworks = $dataretrieved;
3402 } else {
3403 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3404 $sql .= " WHERE entity=".$conf->entity;
3405 $resql = $db->query($sql);
3406 if ($resql) {
3407 while ($obj = $db->fetch_object($resql)) {
3408 $socialnetworks[$obj->code] = array(
3409 'rowid' => $obj->rowid,
3410 'label' => $obj->label,
3411 'url' => $obj->url,
3412 'icon' => $obj->icon,
3413 'active' => $obj->active,
3414 );
3415 }
3416 }
3417 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3418 }
3419
3420 return $socialnetworks;
3421}
3422
3433function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3434{
3435 global $conf, $user, $langs;
3436
3437 $htmllink = $value;
3438
3439 if (empty($value)) {
3440 return '&nbsp;';
3441 }
3442
3443 if (!empty($type)) {
3444 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3445 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3446 $htmllink .= '<span class="fab pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3447 if ($type == 'skype') {
3448 $htmllink .= dol_escape_htmltag($value);
3449 $htmllink .= '&nbsp; <a href="skype:';
3450 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3451 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3452 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3453 $htmllink .= '</a><a href="skype:';
3454 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3455 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3456 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3457 $htmllink .= '</a>';
3458 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3459 $addlink = 'AC_SKYPE';
3460 $link = '';
3461 if (getDolGlobalString('AGENDA_ADDACTIONFORSKYPE')) {
3462 $link = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.$addlink.'&amp;contactid='.$cid.'&amp;socid='.$socid.'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3463 }
3464 $htmllink .= ($link ? ' '.$link : '');
3465 }
3466 } else {
3467 $networkconstname = 'MAIN_INFO_SOCIETE_'.strtoupper($type).'_URL';
3468 if (getDolGlobalString($networkconstname)) {
3469 $link = str_replace('{socialid}', $value, getDolGlobalString($networkconstname));
3470 if (preg_match('/^https?:\/\//i', $link)) {
3471 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3472 } else {
3473 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3474 }
3475 } elseif (!empty($dictsocialnetworks[$type]['url'])) {
3476 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3477 if ($tmpvirginurl) {
3478 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3479 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3480
3481 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3482 if ($tmpvirginurl3) {
3483 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3484 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3485 }
3486
3487 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3488 if ($tmpvirginurl2) {
3489 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3490 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3491 }
3492 }
3493 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3494 if (preg_match('/^https?:\/\//i', $link)) {
3495 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3496 } else {
3497 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3498 }
3499 } else {
3500 $htmllink .= dol_escape_htmltag($value);
3501 }
3502 }
3503 $htmllink .= '</div>';
3504 } else {
3505 $langs->load("errors");
3506 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3507 }
3508 return $htmllink;
3509}
3510
3520function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1)
3521{
3522 global $mysoc;
3523
3524 if (empty($profID) || empty($profIDtype)) {
3525 return '';
3526 }
3527 if (empty($countrycode)) {
3528 $countrycode = $mysoc->country_code;
3529 }
3530 $newProfID = $profID;
3531 $id = substr($profIDtype, -1);
3532 $ret = '';
3533 if (strtoupper($countrycode) == 'FR') {
3534 // France
3535 // (see https://www.economie.gouv.fr/entreprises/numeros-identification-entreprise)
3536
3537 if ($id == 1 && dol_strlen($newProfID) == 9) {
3538 // SIREN (ex: 123 123 123)
3539 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3);
3540 }
3541 if ($id == 2 && dol_strlen($newProfID) == 14) {
3542 // SIRET (ex: 123 123 123 12345)
3543 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3).' '.substr($newProfID, 9, 5);
3544 }
3545 if ($id == 3 && dol_strlen($newProfID) == 5) {
3546 // NAF/APE (ex: 69.20Z)
3547 $newProfID = substr($newProfID, 0, 2).'.'.substr($newProfID, 2, 3);
3548 }
3549 if ($profIDtype === 'VAT' && dol_strlen($newProfID) == 13) {
3550 // TVA intracommunautaire (ex: FR12 123 123 123)
3551 $newProfID = substr($newProfID, 0, 4).' '.substr($newProfID, 4, 3).' '.substr($newProfID, 7, 3).' '.substr($newProfID, 10, 3);
3552 }
3553 }
3554 if (!empty($addcpButton)) {
3555 $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3556 } else {
3557 $ret = $newProfID;
3558 }
3559 return $ret;
3560}
3561
3576function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0)
3577{
3578 global $conf, $user, $langs, $mysoc, $hookmanager;
3579
3580 // Clean phone parameter
3581 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
3582 if (empty($phone)) {
3583 return '';
3584 }
3585 if (getDolGlobalString('MAIN_PHONE_SEPAR')) {
3586 $separ = $conf->global->MAIN_PHONE_SEPAR;
3587 }
3588 if (empty($countrycode) && is_object($mysoc)) {
3589 $countrycode = $mysoc->country_code;
3590 }
3591
3592 // Short format for small screens
3593 if ($conf->dol_optimize_smallscreen) {
3594 $separ = '';
3595 }
3596
3597 $newphone = $phone;
3598 if (strtoupper($countrycode) == "FR") {
3599 // France
3600 if (dol_strlen($phone) == 10) {
3601 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 2).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3602 } elseif (dol_strlen($phone) == 7) {
3603 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
3604 } elseif (dol_strlen($phone) == 9) {
3605 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
3606 } elseif (dol_strlen($phone) == 11) {
3607 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3608 } elseif (dol_strlen($phone) == 12) {
3609 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3610 } elseif (dol_strlen($phone) == 13) {
3611 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 2);
3612 }
3613 } elseif (strtoupper($countrycode) == "CA") {
3614 if (dol_strlen($phone) == 10) {
3615 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
3616 }
3617 } elseif (strtoupper($countrycode) == "PT") {//Portugal
3618 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
3619 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3620 }
3621 } elseif (strtoupper($countrycode) == "SR") {//Suriname
3622 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
3623 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
3624 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
3625 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
3626 }
3627 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
3628 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
3629 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
3630 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
3631 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
3632 }
3633 } elseif (strtoupper($countrycode) == "ES") {//Espagne
3634 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
3635 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3636 }
3637 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
3638 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
3639 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3640 }
3641 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
3642 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
3643 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3644 }
3645 } elseif (strtoupper($countrycode) == "TR") {//Turquie
3646 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
3647 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3648 }
3649 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
3650 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
3651 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3652 }
3653 } elseif (strtoupper($countrycode) == "MX") {//Mexique
3654 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
3655 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3656 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
3657 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3658 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
3659 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3660 }
3661 } elseif (strtoupper($countrycode) == "ML") {//Mali
3662 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
3663 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3664 }
3665 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
3666 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
3667 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3668 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
3669 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 3);
3670 }
3671 } elseif (strtoupper($countrycode) == "MU") {
3672 //Maurice
3673 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
3674 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3675 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
3676 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3677 }
3678 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
3679 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
3680 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3681 }
3682 } elseif (strtoupper($countrycode) == "SY") {//Syrie
3683 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
3684 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3685 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
3686 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 3);
3687 }
3688 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
3689 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
3690 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3691 } elseif (dol_strlen($phone) == 13) {//ex: +971_ABC_DEF_GHI
3692 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3693 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
3694 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
3695 }
3696 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
3697 if (dol_strlen($phone) == 13) {//ex: +213_ABC_DEF_GHI
3698 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3699 }
3700 } elseif (strtoupper($countrycode) == "BE") {//Belgique
3701 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
3702 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3703 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
3704 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3705 }
3706 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
3707 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
3708 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3709 }
3710 } elseif (strtoupper($countrycode) == "CO") {//Colombie
3711 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
3712 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3713 }
3714 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
3715 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
3716 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 1).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3717 }
3718 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
3719 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
3720 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3721 }
3722 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
3723 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
3724 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 2);
3725 }
3726 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
3727 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
3728 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3729 }
3730 } elseif (strtoupper($countrycode) == "CH") {//Suisse
3731 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
3732 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3733 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
3734 $newphone = $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 4);
3735 }
3736 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
3737 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
3738 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3739 }
3740 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
3741 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
3742 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3743 }
3744 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
3745 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
3746 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3747 }
3748 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
3749 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
3750 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3751 }
3752 } elseif (strtoupper($countrycode) == "IT") {//Italie
3753 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
3754 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3755 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
3756 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3757 }
3758 } elseif (strtoupper($countrycode) == "AU") {
3759 //Australie
3760 if (dol_strlen($phone) == 12) {
3761 //ex: +61_A_BCDE_FGHI
3762 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
3763 }
3764 } elseif (strtoupper($countrycode) == "LU") {
3765 // Luxembourg
3766 if (dol_strlen($phone) == 10) {// fixe 6 chiffres +352_AA_BB_CC
3767 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3768 } elseif (dol_strlen($phone) == 11) {// fixe 7 chiffres +352_AA_BB_CC_D
3769 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 1);
3770 } elseif (dol_strlen($phone) == 12) {// fixe 8 chiffres +352_AA_BB_CC_DD
3771 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3772 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
3773 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3774 }
3775 }
3776
3777 $newphoneastart = $newphoneaend = '';
3778 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
3779 if ($addlink == 'tel' || $conf->browser->layout == 'phone' || (isModEnabled('clicktodial') && getDolGlobalString('CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS'))) { // If phone or option for, we use link of phone
3780 $newphoneastart = '<a href="tel:'.$phone.'">';
3781 $newphoneaend .= '</a>';
3782 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
3783 if (empty($user->clicktodial_loaded)) {
3784 $user->fetch_clicktodial();
3785 }
3786
3787 // Define urlmask
3788 $urlmask = getDolGlobalString('CLICKTODIAL_URL', 'ErrorClickToDialModuleNotConfigured');
3789 if (!empty($user->clicktodial_url)) {
3790 $urlmask = $user->clicktodial_url;
3791 }
3792
3793 $clicktodial_poste = (!empty($user->clicktodial_poste) ? urlencode($user->clicktodial_poste) : '');
3794 $clicktodial_login = (!empty($user->clicktodial_login) ? urlencode($user->clicktodial_login) : '');
3795 $clicktodial_password = (!empty($user->clicktodial_password) ? urlencode($user->clicktodial_password) : '');
3796 // This line is for backward compatibility
3797 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
3798 // Thoose lines are for substitution
3799 $substitarray = array('__PHONEFROM__'=>$clicktodial_poste,
3800 '__PHONETO__'=>urlencode($phone),
3801 '__LOGIN__'=>$clicktodial_login,
3802 '__PASS__'=>$clicktodial_password);
3803 $url = make_substitutions($url, $substitarray);
3804 if (!getDolGlobalString('CLICKTODIAL_DO_NOT_USE_AJAX_CALL')) {
3805 // Default and recommended: New method using ajax without submiting a page making a javascript history.go(-1) back
3806 $newphoneastart = '<a href="'.$url.'" class="cssforclicktodial">'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
3807 $newphoneaend = '</a>';
3808 } else {
3809 // Old method
3810 $newphoneastart = '<a href="'.$url.'"';
3811 if (getDolGlobalString('CLICKTODIAL_FORCENEWTARGET')) {
3812 $newphoneastart .= ' target="_blank" rel="noopener noreferrer"';
3813 }
3814 $newphoneastart .= '>';
3815 $newphoneaend .= '</a>';
3816 }
3817 }
3818
3819 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
3820 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3821 $type = 'AC_TEL';
3822 $addlinktoagenda = '';
3823 if ($addlink == 'AC_FAX') {
3824 $type = 'AC_FAX';
3825 }
3826 if (getDolGlobalString('AGENDA_ADDACTIONFORPHONE')) {
3827 $addlinktoagenda = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage='. urlencode($_SERVER['REQUEST_URI']) .'&amp;actioncode='.$type.($cid ? '&amp;contactid='.$cid : '').($socid ? '&amp;socid='.$socid : '').'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3828 }
3829 if ($addlinktoagenda) {
3830 $newphone = '<span>'.$newphone.' '.$addlinktoagenda.'</span>';
3831 }
3832 }
3833 }
3834
3835 if (empty($titlealt)) {
3836 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
3837 }
3838 $rep = '';
3839
3840 if ($hookmanager) {
3841 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
3842 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
3843 $rep .= $hookmanager->resPrint;
3844 }
3845 if (empty($reshook)) {
3846 $picto = '';
3847 if ($withpicto) {
3848 if ($withpicto == 'fax') {
3849 $picto = 'phoning_fax';
3850 } elseif ($withpicto == 'phone') {
3851 $picto = 'phoning';
3852 } elseif ($withpicto == 'mobile') {
3853 $picto = 'phoning_mobile';
3854 } else {
3855 $picto = '';
3856 }
3857 }
3858 if ($adddivfloat == 1) {
3859 $rep .= '<div class="nospan float" style="margin-right: 10px">';
3860 } elseif (empty($adddivfloat)) {
3861 $rep .= '<span style="margin-right: 10px;">';
3862 }
3863
3864 $rep .= $newphoneastart;
3865 $rep .= ($withpicto ? img_picto($titlealt, 'object_'.$picto.'.png') : '');
3866 if ($separ != 'hidenum') {
3867 $rep .= ($withpicto ? ' ' : '').$newphone;
3868 }
3869 $rep .= $newphoneaend;
3870
3871 if ($adddivfloat == 1) {
3872 $rep .= '</div>';
3873 } elseif (empty($adddivfloat)) {
3874 $rep .= '</span>';
3875 }
3876 }
3877
3878 return $rep;
3879}
3880
3888function dol_print_ip($ip, $mode = 0)
3889{
3890 global $langs;
3891
3892 $ret = '';
3893
3894 if (empty($mode)) {
3895 $ret .= $ip;
3896 }
3897
3898 if ($mode != 2) {
3899 $countrycode = dolGetCountryCodeFromIp($ip);
3900 if ($countrycode) { // If success, countrycode is us, fr, ...
3901 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
3902 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
3903 } else {
3904 $ret .= ' ('.$countrycode.')';
3905 }
3906 } else {
3907 // Nothing
3908 }
3909 }
3910
3911 return $ret;
3912}
3913
3923{
3924 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
3925 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
3926 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
3927 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
3928 } else {
3929 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
3930 }
3931 } else {
3932 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
3933 }
3934 } else {
3935 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
3936 }
3937 return $ip;
3938}
3939
3948function isHTTPS()
3949{
3950 $isSecure = false;
3951 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
3952 $isSecure = true;
3953 } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
3954 $isSecure = true;
3955 }
3956 return $isSecure;
3957}
3958
3966{
3967 global $conf;
3968
3969 $countrycode = '';
3970
3971 if (!empty($conf->geoipmaxmind->enabled)) {
3972 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3973 //$ip='24.24.24.24';
3974 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
3975 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3976 $geoip = new DolGeoIP('country', $datafile);
3977 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
3978 $countrycode = $geoip->getCountryCodeFromIP($ip);
3979 }
3980
3981 return $countrycode;
3982}
3983
3984
3992{
3993 global $conf, $langs, $user;
3994
3995 //$ret=$user->xxx;
3996 $ret = '';
3997 if (!empty($conf->geoipmaxmind->enabled)) {
3998 $ip = getUserRemoteIP();
3999 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
4000 //$ip='24.24.24.24';
4001 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
4002 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
4003 $geoip = new DolGeoIP('country', $datafile);
4004 $countrycode = $geoip->getCountryCodeFromIP($ip);
4005 $ret = $countrycode;
4006 }
4007 return $ret;
4008}
4009
4022function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
4023{
4024 global $conf, $user, $langs, $hookmanager;
4025
4026 $out = '';
4027
4028 if ($address) {
4029 if ($hookmanager) {
4030 $parameters = array('element' => $element, 'id' => $id);
4031 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
4032 $out .= $hookmanager->resPrint;
4033 }
4034 if (empty($reshook)) {
4035 if (empty($charfornl)) {
4036 $out .= nl2br($address);
4037 } else {
4038 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
4039 }
4040
4041 // TODO Remove this block, we can add this using the hook now
4042 $showgmap = $showomap = 0;
4043 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS')) {
4044 $showgmap = 1;
4045 }
4046 if ($element == 'contact' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_CONTACTS')) {
4047 $showgmap = 1;
4048 }
4049 if ($element == 'member' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_MEMBERS')) {
4050 $showgmap = 1;
4051 }
4052 if ($element == 'user' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_USERS')) {
4053 $showgmap = 1;
4054 }
4055 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS')) {
4056 $showomap = 1;
4057 }
4058 if ($element == 'contact' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_CONTACTS')) {
4059 $showomap = 1;
4060 }
4061 if ($element == 'member' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_MEMBERS')) {
4062 $showomap = 1;
4063 }
4064 if ($element == 'user' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_USERS')) {
4065 $showomap = 1;
4066 }
4067 if ($showgmap) {
4068 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
4069 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4070 }
4071 if ($showomap) {
4072 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
4073 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4074 }
4075 }
4076 }
4077 if ($noprint) {
4078 return $out;
4079 } else {
4080 print $out;
4081 }
4082}
4083
4084
4094function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
4095{
4096 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
4097 return true;
4098 }
4099 if ($acceptuserkey && $address == '__USER_EMAIL__') {
4100 return true;
4101 }
4102 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
4103 return true;
4104 }
4105
4106 return false;
4107}
4108
4117function isValidMXRecord($domain)
4118{
4119 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
4120 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
4121 return 0;
4122 }
4123 if (function_exists('getmxrr')) {
4124 $mxhosts = array();
4125 $weight = array();
4126 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
4127 if (count($mxhosts) > 1) {
4128 return 1;
4129 }
4130 if (count($mxhosts) == 1 && !empty($mxhosts[0])) {
4131 return 1;
4132 }
4133
4134 return 0;
4135 }
4136 }
4137
4138 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4139 return -1;
4140}
4141
4149function isValidPhone($phone)
4150{
4151 return true;
4152}
4153
4154
4164function dolGetFirstLetters($s, $nbofchar = 1)
4165{
4166 $ret = '';
4167 $tmparray = explode(' ', $s);
4168 foreach ($tmparray as $tmps) {
4169 $ret .= dol_substr($tmps, 0, $nbofchar);
4170 }
4171
4172 return $ret;
4173}
4174
4175
4183function dol_strlen($string, $stringencoding = 'UTF-8')
4184{
4185 if (is_null($string)) {
4186 return 0;
4187 }
4188
4189 if (function_exists('mb_strlen')) {
4190 return mb_strlen($string, $stringencoding);
4191 } else {
4192 return strlen($string);
4193 }
4194}
4195
4206function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4207{
4208 global $langs;
4209
4210 if (empty($stringencoding)) {
4211 $stringencoding = $langs->charset_output;
4212 }
4213
4214 $ret = '';
4215 if (empty($trunconbytes)) {
4216 if (function_exists('mb_substr')) {
4217 $ret = mb_substr($string, $start, $length, $stringencoding);
4218 } else {
4219 $ret = substr($string, $start, $length);
4220 }
4221 } else {
4222 if (function_exists('mb_strcut')) {
4223 $ret = mb_strcut($string, $start, $length, $stringencoding);
4224 } else {
4225 $ret = substr($string, $start, $length);
4226 }
4227 }
4228 return $ret;
4229}
4230
4231
4245function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4246{
4247 global $conf;
4248
4249 if (empty($size) || getDolGlobalString('MAIN_DISABLE_TRUNC')) {
4250 return $string;
4251 }
4252
4253 if (empty($stringencoding)) {
4254 $stringencoding = 'UTF-8';
4255 }
4256 // reduce for small screen
4257 if ($conf->dol_optimize_smallscreen == 1 && $display == 1) {
4258 $size = round($size / 3);
4259 }
4260
4261 // We go always here
4262 if ($trunc == 'right') {
4263 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4264 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4265 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4266 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4267 } else {
4268 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4269 return $string;
4270 }
4271 } elseif ($trunc == 'middle') {
4272 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4273 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4274 $size1 = round($size / 2);
4275 $size2 = round($size / 2);
4276 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4277 } else {
4278 return $string;
4279 }
4280 } elseif ($trunc == 'left') {
4281 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4282 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4283 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4284 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4285 } else {
4286 return $string;
4287 }
4288 } elseif ($trunc == 'wrap') {
4289 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4290 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4291 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4292 } else {
4293 return $string;
4294 }
4295 } else {
4296 return 'BadParam3CallingDolTrunc';
4297 }
4298}
4299
4306function getPictoForType($key)
4307{
4308 // Set array with type -> picto
4309 $type2picto = array(
4310 'varchar'=>'font',
4311 'text'=>'font',
4312 'html'=>'code',
4313 'int'=>'sort-numeric-down',
4314 'double'=>'sort-numeric-down',
4315 'price'=>'currency',
4316 'pricecy'=>'multicurrency',
4317 'password' => 'key',
4318 'boolean'=>'check-square',
4319 'date'=>'calendar',
4320 'datetime'=>'calendar',
4321 'phone'=> 'phone',
4322 'mail'=> 'email',
4323 'url'=> 'url',
4324 'ip'=> 'country',
4325 'select' => 'list',
4326 'sellist' => 'list',
4327 'radio' => 'check-circle',
4328 'checkbox' => 'check-square',
4329 'chkbxlst' => 'check-square',
4330 'link' => 'link',
4331 'separate'=> 'minus'
4332 );
4333
4334 if (!empty($type2picto[$key])) {
4335 return img_picto('', $type2picto[$key], 'class="pictofixedwidth"');
4336 }
4337
4338 return img_picto('', 'generic', 'class="pictofixedwidth"');
4339}
4340
4341
4363function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4364{
4365 global $conf, $langs;
4366
4367 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4368 $url = DOL_URL_ROOT;
4369 $theme = isset($conf->theme) ? $conf->theme : null;
4370 $path = 'theme/'.$theme;
4371 if (empty($picto)) {
4372 $picto = 'generic';
4373 }
4374
4375 // Define fullpathpicto to use into src
4376 if ($pictoisfullpath) {
4377 // Clean parameters
4378 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4379 $picto .= '.png';
4380 }
4381 $fullpathpicto = $picto;
4382 $reg = array();
4383 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4384 $morecss .= ($morecss ? ' ' : '').$reg[1];
4385 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4386 }
4387 } else {
4388 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', (is_null($picto) ? '' : $picto));
4389 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4390 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4391
4392 if (strpos($pictowithouttext, 'fontawesome_') === 0 || strpos($pictowithouttext, 'fa-') === 0) {
4393 // This is a font awesome image 'fontawesome_xxx' or 'fa-xxx'
4394 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4395 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4396
4397 // Compatibility with old fontawesome versions
4398 if ($pictowithouttext == 'file-o') {
4399 $pictowithouttext = 'file';
4400 }
4401
4402 $pictowithouttextarray = explode('_', $pictowithouttext);
4403 $marginleftonlyshort = 0;
4404
4405 if (!empty($pictowithouttextarray[1])) {
4406 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4407 $fakey = 'fa-'.$pictowithouttextarray[0];
4408 $faprefix = empty($pictowithouttextarray[1]) ? 'fas' : $pictowithouttextarray[1];
4409 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4410 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4411 } else {
4412 $fakey = 'fa-'.$pictowithouttext;
4413 $faprefix = 'fas';
4414 $facolor = '';
4415 $fasize = '';
4416 }
4417
4418 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4419 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4420 $morestyle = '';
4421 $reg = array();
4422 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4423 $morecss .= ($morecss ? ' ' : '').$reg[1];
4424 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4425 }
4426 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4427 $morestyle = $reg[1];
4428 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4429 }
4430 $moreatt = trim($moreatt);
4431
4432 $enabledisablehtml = '<span class="'.$faprefix.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4433 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4434 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4435 $enabledisablehtml .= $titlealt;
4436 }*/
4437 $enabledisablehtml .= '</span>';
4438
4439 return $enabledisablehtml;
4440 }
4441
4442 if (empty($srconly) && in_array($pictowithouttext, array(
4443 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4444 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'angle-double-down', 'angle-double-up', 'asset',
4445 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building',
4446 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4447 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'code', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4448 'check-circle', 'check-square', 'currency', 'multicurrency',
4449 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies',
4450 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4451 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4452 'filter', 'file', 'file-o', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus', 'font',
4453 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4454 'hands-helping', 'help', 'holiday',
4455 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4456 'key', 'knowledgemanagement',
4457 'label', 'language', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4458 'margin', 'map-marker-alt', 'member', 'meeting', 'minus', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4459 'off', 'on', 'order',
4460 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4461 'stock', 'resize', 'service', 'stats',
4462 'security', 'setup', 'share-alt', 'sign-out', 'split', 'stripe', 'stripe-s', 'switch_off', 'switch_on', 'switch_on_warning', 'switch_on_red', 'tools', 'unlink', 'uparrow', 'user', 'user-tie', 'vcard', 'wrench',
4463 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4464 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4465 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4466 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4467 'technic', 'ticket',
4468 'error', 'warning',
4469 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4470 'shapes', 'skill', 'square', 'sort-numeric-down', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4471 'tick', 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda',
4472 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4473 'conferenceorbooth', 'eventorganization',
4474 'stamp', 'signature'
4475 ))) {
4476 $fakey = $pictowithouttext;
4477 $facolor = '';
4478 $fasize = '';
4479 $fa = getDolGlobalString('MAIN_FONTAWESOME_ICON_STYLE', 'fas');
4480 if (in_array($pictowithouttext, array('card', 'bell', 'clock', 'establishment', 'file', 'file-o', 'generic', 'minus-square', 'object_generic', 'pdf', 'plus-square', 'timespent', 'note', 'off', 'on', 'object_bookmark', 'bookmark', 'vcard'))) {
4481 $fa = 'far';
4482 }
4483 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4484 $fa = 'fab';
4485 }
4486
4487 $arrayconvpictotofa = array(
4488 'account'=>'university', 'accounting_account'=>'clipboard-list', 'accountline'=>'receipt', 'accountancy'=>'search-dollar', 'action'=>'calendar-alt', 'add'=>'plus-circle', 'address'=> 'address-book', 'asset'=>'money-check-alt', 'autofill'=>'fill',
4489 'bank_account'=>'university',
4490 'bill'=>'file-invoice-dollar', 'billa'=>'file-excel', 'billr'=>'file-invoice-dollar', 'billd'=>'file-medical',
4491 'supplier_invoice'=>'file-invoice-dollar', 'supplier_invoicea'=>'file-excel', 'supplier_invoicer'=>'file-invoice-dollar', 'supplier_invoiced'=>'file-medical',
4492 'bom'=>'shapes',
4493 'card'=>'address-card', 'chart'=>'chart-line', 'company'=>'building', 'contact'=>'address-book', 'contract'=>'suitcase', 'collab'=>'people-arrows', 'conversation'=>'comments', 'country'=>'globe-americas', 'cron'=>'business-time', 'cross'=>'times',
4494 'donation'=>'file-alt', 'dynamicprice'=>'hand-holding-usd',
4495 'setup'=>'cog', 'companies'=>'building', 'products'=>'cube', 'commercial'=>'suitcase', 'invoicing'=>'coins',
4496 'accounting'=>'search-dollar', 'category'=>'tag', 'dollyrevert'=>'dolly',
4497 'file-o'=>'file', 'generate'=>'plus-square', 'hrm'=>'user-tie', 'incoterm'=>'truck-loading',
4498 'margin'=>'calculator', 'members'=>'user-friends', 'ticket'=>'ticket-alt', 'globe'=>'external-link-alt', 'lot'=>'barcode',
4499 'email'=>'at', 'establishment'=>'building', 'edit'=>'pencil-alt', 'entity'=>'globe',
4500 'graph'=>'chart-line', 'grip_title'=>'arrows-alt', 'grip'=>'arrows-alt', 'help'=>'question-circle',
4501 'generic'=>'file', 'holiday'=>'umbrella-beach',
4502 'info'=>'info-circle', 'inventory'=>'boxes', 'intracommreport'=>'globe-europe', 'jobprofile'=>'cogs',
4503 'knowledgemanagement'=>'ticket-alt', 'label'=>'layer-group', 'line'=>'bars', 'loan'=>'money-bill-alt',
4504 'member'=>'user-alt', 'meeting'=>'chalkboard-teacher', 'mrp'=>'cubes', 'next'=>'arrow-alt-circle-right',
4505 'trip'=>'wallet', 'expensereport'=>'wallet', 'group'=>'users', 'movement'=>'people-carry',
4506 'sign-out'=>'sign-out-alt',
4507 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_warning'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star',
4508 'bank'=>'university', 'close_title'=>'times', 'delete'=>'trash', 'filter'=>'filter',
4509 'list-alt'=>'list-alt', 'calendarlist'=>'bars', 'calendar'=>'calendar-alt', 'calendarmonth'=>'calendar-alt', 'calendarweek'=>'calendar-week', 'calendarday'=>'calendar-day', 'calendarperuser'=>'table',
4510 'intervention'=>'ambulance', 'invoice'=>'file-invoice-dollar', 'order'=>'file-invoice',
4511 'error'=>'exclamation-triangle', 'warning'=>'exclamation-triangle',
4512 'other'=>'square',
4513 'playdisabled'=>'play', 'pdf'=>'file-pdf', 'poll'=>'check-double', 'pos'=>'cash-register', 'preview'=>'binoculars', 'project'=>'project-diagram', 'projectpub'=>'project-diagram', 'projecttask'=>'tasks', 'propal'=>'file-signature', 'proposal'=>'file-signature',
4514 'partnership'=>'handshake', 'payment'=>'money-check-alt', 'payment_vat'=>'money-check-alt', 'pictoconfirm'=>'check-square', 'phoning'=>'phone', 'phoning_mobile'=>'mobile-alt', 'phoning_fax'=>'fax', 'previous'=>'arrow-alt-circle-left', 'printer'=>'print', 'product'=>'cube', 'puce'=>'angle-right',
4515 'recent' => 'check-square', 'reception'=>'dolly', 'recruitmentjobposition'=>'id-card-alt', 'recruitmentcandidature'=>'id-badge',
4516 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature',
4517 'refresh'=>'redo', 'region'=>'map-marked', 'replacement'=>'exchange-alt', 'resource'=>'laptop-house', 'recurring'=>'history',
4518 'service'=>'concierge-bell',
4519 'skill'=>'shapes', 'state'=>'map-marked-alt', 'security'=>'key', 'salary'=>'wallet', 'shipment'=>'dolly', 'stock'=>'box-open', 'stats' => 'chart-bar', 'split'=>'code-branch', 'stripe'=>'stripe-s',
4520 'supplier'=>'building', 'technic'=>'cogs',
4521 'timespent'=>'clock', 'tick' => 'check', 'title_setup'=>'tools', 'title_accountancy'=>'money-check-alt', 'title_bank'=>'university', 'title_hrm'=>'umbrella-beach',
4522 'title_agenda'=>'calendar-alt',
4523 'uncheck'=>'times', 'uparrow'=>'share', 'url'=>'external-link-alt', 'vat'=>'money-check-alt', 'vcard'=>'arrow-alt-circle-down',
4524 'jabber'=>'comment-o',
4525 'website'=>'globe-americas', 'workstation'=>'pallet', 'webhook'=>'bullseye', 'world'=>'globe', 'private'=>'user-lock',
4526 'conferenceorbooth'=>'chalkboard-teacher', 'eventorganization'=>'project-diagram'
4527 );
4528 if ($conf->currency == 'EUR') {
4529 $arrayconvpictotofa['currency'] = 'euro-sign';
4530 $arrayconvpictotofa['multicurrency'] = 'dollar-sign';
4531 } else {
4532 $arrayconvpictotofa['currency'] = 'dollar-sign';
4533 $arrayconvpictotofa['multicurrency'] = 'euro-sign';
4534 }
4535 if ($pictowithouttext == 'off') {
4536 $fakey = 'fa-square';
4537 $fasize = '1.3em';
4538 } elseif ($pictowithouttext == 'on') {
4539 $fakey = 'fa-check-square';
4540 $fasize = '1.3em';
4541 } elseif ($pictowithouttext == 'listlight') {
4542 $fakey = 'fa-download';
4543 $marginleftonlyshort = 1;
4544 } elseif ($pictowithouttext == 'printer') {
4545 $fakey = 'fa-print';
4546 $fasize = '1.2em';
4547 } elseif ($pictowithouttext == 'note') {
4548 $fakey = 'fa-sticky-note';
4549 $marginleftonlyshort = 1;
4550 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
4551 $convertarray = array('1uparrow'=>'caret-up', '1downarrow'=>'caret-down', '1leftarrow'=>'caret-left', '1rightarrow'=>'caret-right', '1uparrow_selected'=>'caret-up', '1downarrow_selected'=>'caret-down', '1leftarrow_selected'=>'caret-left', '1rightarrow_selected'=>'caret-right');
4552 $fakey = 'fa-'.$convertarray[$pictowithouttext];
4553 if (preg_match('/selected/', $pictowithouttext)) {
4554 $facolor = '#888';
4555 }
4556 $marginleftonlyshort = 1;
4557 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
4558 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
4559 } else {
4560 $fakey = 'fa-'.$pictowithouttext;
4561 }
4562
4563 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment'))) {
4564 $morecss .= ' em092';
4565 }
4566 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
4567 $morecss .= ' em088';
4568 }
4569 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
4570 $morecss .= ' em080';
4571 }
4572
4573 // Define $marginleftonlyshort
4574 $arrayconvpictotomarginleftonly = array(
4575 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
4576 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
4577 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
4578 );
4579 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
4580 $marginleftonlyshort = 0;
4581 }
4582
4583 // Add CSS
4584 $arrayconvpictotomorcess = array(
4585 'action'=>'infobox-action', 'account'=>'infobox-bank_account', 'accounting_account'=>'infobox-bank_account', 'accountline'=>'infobox-bank_account', 'accountancy'=>'infobox-bank_account', 'asset'=>'infobox-bank_account',
4586 'bank_account'=>'infobox-bank_account',
4587 'bill'=>'infobox-commande', 'billa'=>'infobox-commande', 'billr'=>'infobox-commande', 'billd'=>'infobox-commande',
4588 'margin'=>'infobox-bank_account', 'conferenceorbooth'=>'infobox-project',
4589 'cash-register'=>'infobox-bank_account', 'contract'=>'infobox-contrat', 'check'=>'font-status4', 'collab'=>'infobox-action', 'conversation'=>'infobox-contrat',
4590 'donation'=>'infobox-commande', 'dolly'=>'infobox-commande', 'dollyrevert'=>'flip infobox-order_supplier',
4591 'ecm'=>'infobox-action', 'eventorganization'=>'infobox-project',
4592 'hrm'=>'infobox-adherent', 'group'=>'infobox-adherent', 'intervention'=>'infobox-contrat',
4593 'incoterm'=>'infobox-supplier_proposal',
4594 'currency'=>'infobox-bank_account', 'multicurrency'=>'infobox-bank_account',
4595 'members'=>'infobox-adherent', 'member'=>'infobox-adherent', 'money-bill-alt'=>'infobox-bank_account',
4596 'order'=>'infobox-commande',
4597 'user'=>'infobox-adherent', 'users'=>'infobox-adherent',
4598 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_warning'=>'font-status4 warning', 'switch_on_red'=>'font-status8',
4599 'holiday'=>'infobox-holiday', 'info'=>'opacityhigh', 'invoice'=>'infobox-commande',
4600 'knowledgemanagement'=>'infobox-contrat rotate90', 'loan'=>'infobox-bank_account',
4601 'payment'=>'infobox-bank_account', 'payment_vat'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'pos'=>'infobox-bank_account', 'project'=>'infobox-project', 'projecttask'=>'infobox-project',
4602 'propal'=>'infobox-propal', 'proposal'=>'infobox-propal','private'=>'infobox-project',
4603 'reception'=>'flip', 'recruitmentjobposition'=>'infobox-adherent', 'recruitmentcandidature'=>'infobox-adherent',
4604 'resource'=>'infobox-action',
4605 'salary'=>'infobox-bank_account', 'shapes'=>'infobox-adherent', 'shipment'=>'infobox-commande', 'supplier_invoice'=>'infobox-order_supplier', 'supplier_invoicea'=>'infobox-order_supplier', 'supplier_invoiced'=>'infobox-order_supplier',
4606 'supplier'=>'infobox-order_supplier', 'supplier_order'=>'infobox-order_supplier', 'supplier_proposal'=>'infobox-supplier_proposal',
4607 'ticket'=>'infobox-contrat', 'title_accountancy'=>'infobox-bank_account', 'title_hrm'=>'infobox-holiday', 'expensereport'=>'infobox-expensereport', 'trip'=>'infobox-expensereport', 'title_agenda'=>'infobox-action',
4608 'vat'=>'infobox-bank_account',
4609 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
4610 'list-alt'=>'imgforviewmode', 'calendar'=>'imgforviewmode', 'calendarweek'=>'imgforviewmode', 'calendarmonth'=>'imgforviewmode', 'calendarday'=>'imgforviewmode', 'calendarperuser'=>'imgforviewmode'
4611 );
4612 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4613 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
4614 }
4615
4616 // Define $color
4617 $arrayconvpictotocolor = array(
4618 'address'=>'#6c6aa8', 'building'=>'#6c6aa8', 'bom'=>'#a69944',
4619 'clone'=>'#999', 'cog'=>'#999', 'companies'=>'#6c6aa8', 'company'=>'#6c6aa8', 'contact'=>'#6c6aa8', 'cron'=>'#555',
4620 'dynamicprice'=>'#a69944',
4621 'edit'=>'#444', 'note'=>'#999', 'error'=>'', 'help'=>'#bbb', 'listlight'=>'#999', 'language'=>'#555',
4622 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
4623 'lock'=>'#ddd', 'lot'=>'#a69944',
4624 'map-marker-alt'=>'#aaa', 'mrp'=>'#a69944', 'product'=>'#a69944', 'service'=>'#a69944', 'inventory'=>'#a69944', 'stock'=>'#a69944', 'movement'=>'#a69944',
4625 'other'=>'#ddd', 'world'=>'#986c6a',
4626 'partnership'=>'#6c6aa8', 'playdisabled'=>'#ccc', 'printer'=>'#444', 'projectpub'=>'#986c6a', 'reception'=>'#a69944', 'resize'=>'#444', 'rss'=>'#cba',
4627 //'shipment'=>'#a69944',
4628 'security'=>'#999', 'square'=>'#888', 'stop-circle'=>'#888', 'stats'=>'#444', 'switch_off'=>'#999',
4629 'technic' => '#999', 'tick' => '#282', 'timespent' => '#555',
4630 'uncheck'=>'#800', 'uparrow'=>'#555', 'user-cog'=>'#999', 'country'=>'#aaa', 'globe-americas'=>'#aaa', 'region'=>'#aaa', 'state'=>'#aaa',
4631 'website'=>'#304', 'workstation'=>'#a69944'
4632 );
4633 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4634 $facolor = $arrayconvpictotocolor[$pictowithouttext];
4635 }
4636
4637 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4638 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4639 $morestyle = '';
4640 $reg = array();
4641 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4642 $morecss .= ($morecss ? ' ' : '').$reg[1];
4643 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4644 }
4645 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4646 $morestyle = $reg[1];
4647 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4648 }
4649 $moreatt = trim($moreatt);
4650
4651 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4652 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4653 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4654 $enabledisablehtml .= $titlealt;
4655 }*/
4656 $enabledisablehtml .= '</span>';
4657
4658 return $enabledisablehtml;
4659 }
4660
4661 if (getDolGlobalString('MAIN_OVERWRITE_THEME_PATH')) {
4662 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_PATH') . '/theme/'.$theme; // If the theme does not have the same name as the module
4663 } elseif (getDolGlobalString('MAIN_OVERWRITE_THEME_RES')) {
4664 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_RES') . '/theme/' . getDolGlobalString('MAIN_OVERWRITE_THEME_RES'); // To allow an external module to overwrite image resources whatever is activated theme
4665 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
4666 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
4667 }
4668
4669 // If we ask an image into $url/$mymodule/img (instead of default path)
4670 $regs = array();
4671 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
4672 $picto = $regs[1];
4673 $path = $regs[2]; // $path is $mymodule
4674 }
4675
4676 // Clean parameters
4677 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4678 $picto .= '.png';
4679 }
4680 // If alt path are defined, define url where img file is, according to physical path
4681 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
4682 foreach ($conf->file->dol_document_root as $type => $dirroot) {
4683 if ($type == 'main') {
4684 continue;
4685 }
4686 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommanded
4687 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
4688 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
4689 break;
4690 }
4691 }
4692
4693 // $url is '' or '/custom', $path is current theme or
4694 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
4695 }
4696
4697 if ($srconly) {
4698 return $fullpathpicto;
4699 }
4700
4701 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
4702 return '<img src="'.$fullpathpicto.'"'.($notitle ? '' : ' alt="'.dol_escape_htmltag($alt).'"').(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt.($morecss ? ' class="'.$morecss.'"' : '') : ' class="inline-block'.($morecss ? ' '.$morecss : '').'"').'>'; // Alt is used for accessibility, title for popup
4703}
4704
4718function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0)
4719{
4720 if (strpos($picto, '^') === 0) {
4721 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
4722 } else {
4723 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
4724 }
4725}
4726
4738function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
4739{
4740 global $conf;
4741
4742 if (is_numeric($picto)) {
4743 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
4744 //$picto = $leveltopicto[$picto];
4745 return '<i class="fa fa-weather-level'.$picto.'"></i>';
4746 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4747 $picto .= '.png';
4748 }
4749
4750 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
4751
4752 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
4753}
4754
4766function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
4767{
4768 global $conf;
4769
4770 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4771 $picto .= '.png';
4772 }
4773
4774 if ($pictoisfullpath) {
4775 $path = $picto;
4776 } else {
4777 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
4778
4779 if (getDolGlobalInt('MAIN_MODULE_CAN_OVERWRITE_COMMONICONS')) {
4780 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
4781
4782 if (file_exists($themepath)) {
4783 $path = $themepath;
4784 }
4785 }
4786 }
4787
4788 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
4789}
4790
4804function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
4805{
4806 global $langs;
4807
4808 if (empty($titlealt) || $titlealt == 'default') {
4809 if ($numaction == '-1' || $numaction == 'ST_NO') {
4810 $numaction = -1;
4811 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
4812 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
4813 $numaction = 0;
4814 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
4815 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
4816 $numaction = 1;
4817 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
4818 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
4819 $numaction = 2;
4820 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
4821 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
4822 $numaction = 3;
4823 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
4824 } else {
4825 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
4826 $numaction = 0;
4827 }
4828 }
4829 if (!is_numeric($numaction)) {
4830 $numaction = 0;
4831 }
4832
4833 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
4834}
4835
4843function img_pdf($titlealt = 'default', $size = 3)
4844{
4845 global $langs;
4846
4847 if ($titlealt == 'default') {
4848 $titlealt = $langs->trans('Show');
4849 }
4850
4851 return img_picto($titlealt, 'pdf'.$size.'.png');
4852}
4853
4861function img_edit_add($titlealt = 'default', $other = '')
4862{
4863 global $langs;
4864
4865 if ($titlealt == 'default') {
4866 $titlealt = $langs->trans('Add');
4867 }
4868
4869 return img_picto($titlealt, 'edit_add.png', $other);
4870}
4878function img_edit_remove($titlealt = 'default', $other = '')
4879{
4880 global $langs;
4881
4882 if ($titlealt == 'default') {
4883 $titlealt = $langs->trans('Remove');
4884 }
4885
4886 return img_picto($titlealt, 'edit_remove.png', $other);
4887}
4888
4897function img_edit($titlealt = 'default', $float = 0, $other = '')
4898{
4899 global $langs;
4900
4901 if ($titlealt == 'default') {
4902 $titlealt = $langs->trans('Modify');
4903 }
4904
4905 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
4906}
4907
4916function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
4917{
4918 global $langs;
4919
4920 if ($titlealt == 'default') {
4921 $titlealt = $langs->trans('View');
4922 }
4923
4924 $moreatt = ($float ? 'style="float: right" ' : '').$other;
4925
4926 return img_picto($titlealt, 'eye', $moreatt);
4927}
4928
4937function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
4938{
4939 global $langs;
4940
4941 if ($titlealt == 'default') {
4942 $titlealt = $langs->trans('Delete');
4943 }
4944
4945 return img_picto($titlealt, 'delete.png', $other, false, 0, 0, '', $morecss);
4946}
4947
4955function img_printer($titlealt = "default", $other = '')
4956{
4957 global $langs;
4958 if ($titlealt == "default") {
4959 $titlealt = $langs->trans("Print");
4960 }
4961 return img_picto($titlealt, 'printer.png', $other);
4962}
4963
4971function img_split($titlealt = 'default', $other = 'class="pictosplit"')
4972{
4973 global $langs;
4974
4975 if ($titlealt == 'default') {
4976 $titlealt = $langs->trans('Split');
4977 }
4978
4979 return img_picto($titlealt, 'split.png', $other);
4980}
4981
4989function img_help($usehelpcursor = 1, $usealttitle = 1)
4990{
4991 global $langs;
4992
4993 if ($usealttitle) {
4994 if (is_string($usealttitle)) {
4995 $usealttitle = dol_escape_htmltag($usealttitle);
4996 } else {
4997 $usealttitle = $langs->trans('Info');
4998 }
4999 }
5000
5001 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
5002}
5003
5010function img_info($titlealt = 'default')
5011{
5012 global $langs;
5013
5014 if ($titlealt == 'default') {
5015 $titlealt = $langs->trans('Informations');
5016 }
5017
5018 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
5019}
5020
5029function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
5030{
5031 global $langs;
5032
5033 if ($titlealt == 'default') {
5034 $titlealt = $langs->trans('Warning');
5035 }
5036
5037 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
5038 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
5039}
5040
5047function img_error($titlealt = 'default')
5048{
5049 global $langs;
5050
5051 if ($titlealt == 'default') {
5052 $titlealt = $langs->trans('Error');
5053 }
5054
5055 return img_picto($titlealt, 'error.png');
5056}
5057
5065function img_next($titlealt = 'default', $moreatt = '')
5066{
5067 global $langs;
5068
5069 if ($titlealt == 'default') {
5070 $titlealt = $langs->trans('Next');
5071 }
5072
5073 //return img_picto($titlealt, 'next.png', $moreatt);
5074 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5075}
5076
5084function img_previous($titlealt = 'default', $moreatt = '')
5085{
5086 global $langs;
5087
5088 if ($titlealt == 'default') {
5089 $titlealt = $langs->trans('Previous');
5090 }
5091
5092 //return img_picto($titlealt, 'previous.png', $moreatt);
5093 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5094}
5095
5104function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
5105{
5106 global $langs;
5107
5108 if ($titlealt == 'default') {
5109 $titlealt = $langs->trans('Down');
5110 }
5111
5112 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
5113}
5114
5123function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
5124{
5125 global $langs;
5126
5127 if ($titlealt == 'default') {
5128 $titlealt = $langs->trans('Up');
5129 }
5130
5131 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
5132}
5133
5142function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
5143{
5144 global $langs;
5145
5146 if ($titlealt == 'default') {
5147 $titlealt = $langs->trans('Left');
5148 }
5149
5150 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
5151}
5152
5161function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
5162{
5163 global $langs;
5164
5165 if ($titlealt == 'default') {
5166 $titlealt = $langs->trans('Right');
5167 }
5168
5169 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
5170}
5171
5179function img_allow($allow, $titlealt = 'default')
5180{
5181 global $langs;
5182
5183 if ($titlealt == 'default') {
5184 $titlealt = $langs->trans('Active');
5185 }
5186
5187 if ($allow == 1) {
5188 return img_picto($titlealt, 'tick.png');
5189 }
5190
5191 return '-';
5192}
5193
5201function img_credit_card($brand, $morecss = null)
5202{
5203 if (is_null($morecss)) {
5204 $morecss = 'fa-2x';
5205 }
5206
5207 if ($brand == 'visa' || $brand == 'Visa') {
5208 $brand = 'cc-visa';
5209 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5210 $brand = 'cc-mastercard';
5211 } elseif ($brand == 'amex' || $brand == 'American Express') {
5212 $brand = 'cc-amex';
5213 } elseif ($brand == 'discover' || $brand == 'Discover') {
5214 $brand = 'cc-discover';
5215 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5216 $brand = 'cc-jcb';
5217 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5218 $brand = 'cc-diners-club';
5219 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5220 $brand = 'credit-card';
5221 }
5222
5223 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5224}
5225
5234function img_mime($file, $titlealt = '', $morecss = '')
5235{
5236 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5237
5238 $mimetype = dol_mimetype($file, '', 1);
5239 $mimeimg = dol_mimetype($file, '', 2);
5240 $mimefa = dol_mimetype($file, '', 4);
5241
5242 if (empty($titlealt)) {
5243 $titlealt = 'Mime type: '.$mimetype;
5244 }
5245
5246 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5247 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5248}
5249
5250
5258function img_search($titlealt = 'default', $other = '')
5259{
5260 global $conf, $langs;
5261
5262 if ($titlealt == 'default') {
5263 $titlealt = $langs->trans('Search');
5264 }
5265
5266 $img = img_picto($titlealt, 'search.png', $other, false, 1);
5267
5268 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5269 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5270
5271 return $input;
5272}
5273
5281function img_searchclear($titlealt = 'default', $other = '')
5282{
5283 global $conf, $langs;
5284
5285 if ($titlealt == 'default') {
5286 $titlealt = $langs->trans('Search');
5287 }
5288
5289 $img = img_picto($titlealt, 'searchclear.png', $other, false, 1);
5290
5291 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5292 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5293
5294 return $input;
5295}
5296
5308function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '')
5309{
5310 global $conf, $langs;
5311
5312 if ($infoonimgalt) {
5313 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5314 } else {
5315 if (empty($conf->use_javascript_ajax)) {
5316 $textfordropdown = '';
5317 }
5318
5319 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5320 $result = ($nodiv ? '' : '<div class="'.$class.($morecss ? ' '.$morecss : '').($textfordropdown ? ' hidden' : '').'">').'<span class="fa fa-info-circle" title="'.dol_escape_htmltag($admin ? $langs->trans('InfoAdmin') : $langs->trans('Note')).'"></span> '.$text.($nodiv ? '' : '</div>');
5321
5322 if ($textfordropdown) {
5323 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5324 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5325 jQuery(document).ready(function() {
5326 jQuery(".'.$class.'text").click(function() {
5327 console.log("toggle text");
5328 jQuery(".'.$class.'").toggle();
5329 });
5330 });
5331 </script>';
5332
5333 $result = $tmpresult.$result;
5334 }
5335 }
5336
5337 return $result;
5338}
5339
5340
5352function dol_print_error($db = '', $error = '', $errors = null)
5353{
5354 global $conf, $langs, $argv;
5355 global $dolibarr_main_prod;
5356
5357 $out = '';
5358 $syslog = '';
5359
5360 // If error occurs before the $lang object was loaded
5361 if (!$langs) {
5362 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5363 $langs = new Translate('', $conf);
5364 $langs->load("main");
5365 }
5366
5367 // Load translation files required by the error messages
5368 $langs->loadLangs(array('main', 'errors'));
5369
5370 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5371 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5372 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5373 $out .= "You use an experimental or develop level of features, so please do NOT report any bugs or vulnerability, except if problem is confirmed after moving option MAIN_FEATURES_LEVEL back to 0.<br>\n";
5374 }
5375 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5376
5377 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5378 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5379 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5380 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5381 }
5382 if (function_exists("phpversion")) {
5383 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5384 }
5385 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5386 if (function_exists("php_uname")) {
5387 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5388 }
5389 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5390 $out .= "<br>\n";
5391 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5392 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5393 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5394 $out .= "<br>\n";
5395 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5396 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5397 } else { // Mode CLI
5398 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5399 $syslog .= "pid=".dol_getmypid();
5400 }
5401
5402 if (!empty($conf->modules)) {
5403 $out .= "<b>".$langs->trans("Modules").":</b> ".join(', ', $conf->modules)."<br>\n";
5404 }
5405
5406 if (is_object($db)) {
5407 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5408 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5409 $lastqueryerror = $db->lastqueryerror();
5410 if (!utf8_check($lastqueryerror)) {
5411 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5412 }
5413 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5414 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5415 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5416 $out .= "<br>\n";
5417 } else { // Mode CLI
5418 // No dol_escape_htmltag for output, we are in CLI mode
5419 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5420 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5421 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5422 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5423 }
5424 $syslog .= ", sql=".$db->lastquery();
5425 $syslog .= ", db_error=".$db->lasterror();
5426 }
5427
5428 if ($error || $errors) {
5429 $langs->load("errors");
5430
5431 // Merge all into $errors array
5432 if (is_array($error) && is_array($errors)) {
5433 $errors = array_merge($error, $errors);
5434 } elseif (is_array($error)) {
5435 $errors = $error;
5436 } elseif (is_array($errors)) {
5437 $errors = array_merge(array($error), $errors);
5438 } else {
5439 $errors = array_merge(array($error), array($errors));
5440 }
5441
5442 foreach ($errors as $msg) {
5443 if (empty($msg)) {
5444 continue;
5445 }
5446 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5447 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5448 } else { // Mode CLI
5449 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5450 }
5451 $syslog .= ", msg=".$msg;
5452 }
5453 }
5454 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5455 xdebug_print_function_stack();
5456 $out .= '<b>XDebug informations:</b>'."<br>\n";
5457 $out .= 'File: '.xdebug_call_file()."<br>\n";
5458 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5459 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5460 $out .= "<br>\n";
5461 }
5462
5463 // Return a http header with error code if possible
5464 if (!headers_sent()) {
5465 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5466 top_httphead();
5467 }
5468 //http_response_code(500); // If we use 500, message is not ouput with some command line tools
5469 http_response_code(202); // If we use 202, this is not really an error message, but this allow to ouput message on command line tools
5470 }
5471
5472 if (empty($dolibarr_main_prod)) {
5473 print $out;
5474 } else {
5475 if (empty($langs->defaultlang)) {
5476 $langs->setDefaultLang();
5477 }
5478 $langs->loadLangs(array("main", "errors")); // Reload main because language may have been set only on previous line so we have to reload files we need.
5479 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5480 print 'This website or feature is currently temporarly not available or failed after a technical error.<br><br>This may be due to a maintenance operation. Current status of operation ('.dol_print_date(dol_now(), 'dayhourrfc').') are on next line...<br><br>'."\n";
5481 print $langs->trans("DolibarrHasDetectedError").'. ';
5482 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5483 if (!defined("MAIN_CORE_ERROR")) {
5484 define("MAIN_CORE_ERROR", 1);
5485 }
5486 }
5487
5488 dol_syslog("Error ".$syslog, LOG_ERR);
5489}
5490
5501function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5502{
5503 global $langs, $conf;
5504
5505 if (empty($email)) {
5506 $email = $conf->global->MAIN_INFO_SOCIETE_MAIL;
5507 }
5508
5509 $langs->load("errors");
5510 $now = dol_now();
5511
5512 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5513 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5514 if ($errormessage) {
5515 print '<br><br>'.$errormessage;
5516 }
5517 if (is_array($errormessages) && count($errormessages)) {
5518 foreach ($errormessages as $mesgtoshow) {
5519 print '<br><br>'.$mesgtoshow;
5520 }
5521 }
5522 print '</div></div>';
5523}
5524
5541function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
5542{
5543 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
5544}
5545
5564function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
5565{
5566 global $conf, $langs, $form;
5567 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
5568
5569 if ($moreattrib == 'class="right"') {
5570 $prefix .= 'right '; // For backward compatibility
5571 }
5572
5573 $sortorder = strtoupper($sortorder);
5574 $out = '';
5575 $sortimg = '';
5576
5577 $tag = 'th';
5578 if ($thead == 2) {
5579 $tag = 'div';
5580 }
5581
5582 $tmpsortfield = explode(',', $sortfield);
5583 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
5584 $tmpfield = explode(',', $field);
5585 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
5586
5587 if (!getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle)) {
5588 $prefix = 'wrapcolumntitle '.$prefix;
5589 }
5590
5591 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
5592 // If field is used as sort criteria we use a specific css class liste_titre_sel
5593 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
5594 $liste_titre = 'liste_titre';
5595 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
5596 $liste_titre = 'liste_titre_sel';
5597 }
5598
5599 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
5600 //$out .= (($field && empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && preg_match('/^[a-zA-Z_0-9\s\.\-:&;]*$/', $name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5601 $tagstart .= ($name && !getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
5602 $tagstart .= '>';
5603
5604 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5605 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5606 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5607 $options = preg_replace('/&+/i', '&', $options);
5608 if (!preg_match('/^&/', $options)) {
5609 $options = '&'.$options;
5610 }
5611
5612 $sortordertouseinlink = '';
5613 if ($field1 != $sortfield1) { // We are on another field than current sorted field
5614 if (preg_match('/^DESC/i', $sortorder)) {
5615 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5616 } else { // We reverse the var $sortordertouseinlink
5617 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5618 }
5619 } else { // We are on field that is the first current sorting criteria
5620 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
5621 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5622 } else {
5623 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5624 }
5625 }
5626 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
5627 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
5628 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5629 $out .= '>';
5630 }
5631 if ($tooltip) {
5632 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
5633 if (preg_match('/:\w+$/', $tooltip)) {
5634 $tmptooltip = explode(':', $tooltip);
5635 } else {
5636 $tmptooltip = array($tooltip);
5637 }
5638 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
5639 } else {
5640 $out .= $langs->trans($name);
5641 }
5642
5643 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5644 $out .= '</a>';
5645 }
5646
5647 if (empty($thead) && $field) { // If this is a sort field
5648 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5649 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5650 $options = preg_replace('/&+/i', '&', $options);
5651 if (!preg_match('/^&/', $options)) {
5652 $options = '&'.$options;
5653 }
5654
5655 if (!$sortorder || ($field1 != $sortfield1)) {
5656 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5657 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5658 } else {
5659 if (preg_match('/^DESC/', $sortorder)) {
5660 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5661 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
5662 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
5663 }
5664 if (preg_match('/^ASC/', $sortorder)) {
5665 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
5666 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5667 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
5668 }
5669 }
5670 }
5671
5672 $tagend = '</'.$tag.'>';
5673
5674 $out = $tagstart.$sortimg.$out.$tagend;
5675
5676 return $out;
5677}
5678
5687function print_titre($title)
5688{
5689 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
5690
5691 print '<div class="titre">'.$title.'</div>';
5692}
5693
5705function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
5706{
5707 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
5708}
5709
5723function load_fiche_titre($titre, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
5724{
5725 global $conf;
5726
5727 $return = '';
5728
5729 if ($picto == 'setup') {
5730 $picto = 'generic';
5731 }
5732
5733 $return .= "\n";
5734 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
5735 $return .= '<tr class="titre">';
5736 if ($picto) {
5737 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
5738 }
5739 $return .= '<td class="nobordernopadding valignmiddle col-title">';
5740 $return .= '<div class="titre inline-block">'.$titre.'</div>';
5741 $return .= '</td>';
5742 if (dol_strlen($morehtmlcenter)) {
5743 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5744 }
5745 if (dol_strlen($morehtmlright)) {
5746 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
5747 }
5748 $return .= '</tr></table>'."\n";
5749
5750 return $return;
5751}
5752
5776function print_barre_liste($titre, $page, $file, $options = '', $sortfield = '', $sortorder = '', $morehtmlcenter = '', $num = -1, $totalnboflines = '', $picto = 'generic', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limit = -1, $hideselectlimit = 0, $hidenavigation = 0, $pagenavastextinput = 0, $morehtmlrightbeforearrow = '')
5777{
5778 global $conf;
5779
5780 $savlimit = $limit;
5781 $savtotalnboflines = $totalnboflines;
5782 $totalnboflines = abs((int) $totalnboflines);
5783
5784 $page = (int) $page;
5785
5786 if ($picto == 'setup') {
5787 $picto = 'title_setup.png';
5788 }
5789 if (($conf->browser->name == 'ie') && $picto == 'generic') {
5790 $picto = 'title.gif';
5791 }
5792 if ($limit < 0) {
5793 $limit = $conf->liste_limit;
5794 }
5795
5796 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
5797 $nextpage = 1;
5798 } else {
5799 $nextpage = 0;
5800 }
5801 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
5802
5803 print "\n";
5804 print "<!-- Begin title -->\n";
5805 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
5806
5807 // Left
5808
5809 if ($picto && $titre) {
5810 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
5811 }
5812
5813 print '<td class="nobordernopadding valignmiddle col-title">';
5814 print '<div class="titre inline-block">'.$titre;
5815 if (!empty($titre) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
5816 print '<span class="opacitymedium colorblack paddingleft">('.$totalnboflines.')</span>';
5817 }
5818 print '</div></td>';
5819
5820 // Center
5821 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
5822 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5823 }
5824
5825 // Right
5826 print '<td class="nobordernopadding valignmiddle right col-right">';
5827 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
5828 if ($sortfield) {
5829 $options .= "&sortfield=".urlencode($sortfield);
5830 }
5831 if ($sortorder) {
5832 $options .= "&sortorder=".urlencode($sortorder);
5833 }
5834 // Show navigation bar
5835 $pagelist = '';
5836 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
5837 if ($totalnboflines) { // If we know total nb of lines
5838 // Define nb of extra page links before and after selected page + ... + first or last
5839 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
5840
5841 if ($limit > 0) {
5842 $nbpages = ceil($totalnboflines / $limit);
5843 } else {
5844 $nbpages = 1;
5845 }
5846 $cpt = ($page - $maxnbofpage);
5847 if ($cpt < 0) {
5848 $cpt = 0;
5849 }
5850
5851 if ($cpt >= 1) {
5852 if (empty($pagenavastextinput)) {
5853 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=0'.$options.'">1</a></li>';
5854 if ($cpt > 2) {
5855 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5856 } elseif ($cpt == 2) {
5857 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=1'.$options.'">2</a></li>';
5858 }
5859 }
5860 }
5861
5862 do {
5863 if ($pagenavastextinput) {
5864 if ($cpt == $page) {
5865 $pagelist .= '<li class="pagination"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
5866 $pagelist .= '/';
5867 }
5868 } else {
5869 if ($cpt == $page) {
5870 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
5871 } else {
5872 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
5873 }
5874 }
5875 $cpt++;
5876 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
5877
5878 if (empty($pagenavastextinput)) {
5879 if ($cpt < $nbpages) {
5880 if ($cpt < $nbpages - 2) {
5881 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5882 } elseif ($cpt == $nbpages - 2) {
5883 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
5884 }
5885 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5886 }
5887 } else {
5888 //var_dump($page.' '.$cpt.' '.$nbpages);
5889 $pagelist .= '<li class="pagination paginationlastpage"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5890 }
5891 } else {
5892 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
5893 }
5894 }
5895
5896 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
5897 print_fleche_navigation($page, $file, $options, $nextpage, $pagelist, $morehtmlright, $savlimit, $totalnboflines, $hideselectlimit, $morehtmlrightbeforearrow, $hidenavigation); // output the div and ul for previous/last completed with page numbers into $pagelist
5898 }
5899
5900 // js to autoselect page field on focus
5901 if ($pagenavastextinput) {
5902 print ajax_autoselect('.pageplusone');
5903 }
5904
5905 print '</td>';
5906 print '</tr>';
5907
5908 print '</table>'."\n";
5909
5910 // Center
5911 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
5912 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
5913 }
5914
5915 print "<!-- End title -->\n\n";
5916}
5917
5934function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
5935{
5936 global $conf, $langs;
5937
5938 print '<div class="pagination"><ul>';
5939 if ($beforearrows) {
5940 print '<li class="paginationbeforearrows">';
5941 print $beforearrows;
5942 print '</li>';
5943 }
5944
5945 if (empty($hidenavigation)) {
5946 if ((int) $limit > 0 && empty($hideselectlimit)) {
5947 $pagesizechoices = '10:10,15:15,20:20,30:30,40:40,50:50,100:100,250:250,500:500,1000:1000';
5948 $pagesizechoices .= ',5000:5000,10000:10000,20000:20000';
5949 //$pagesizechoices.=',0:'.$langs->trans("All"); // Not yet supported
5950 //$pagesizechoices.=',2:2';
5951 if (getDolGlobalString('MAIN_PAGESIZE_CHOICES')) {
5952 $pagesizechoices = $conf->global->MAIN_PAGESIZE_CHOICES;
5953 }
5954
5955 print '<li class="pagination">';
5956 print '<select class="flat selectlimit" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
5957 $tmpchoice = explode(',', $pagesizechoices);
5958 $tmpkey = $limit.':'.$limit;
5959 if (!in_array($tmpkey, $tmpchoice)) {
5960 $tmpchoice[] = $tmpkey;
5961 }
5962 $tmpkey = $conf->liste_limit.':'.$conf->liste_limit;
5963 if (!in_array($tmpkey, $tmpchoice)) {
5964 $tmpchoice[] = $tmpkey;
5965 }
5966 asort($tmpchoice, SORT_NUMERIC);
5967 foreach ($tmpchoice as $val) {
5968 $selected = '';
5969 $tmp = explode(':', $val);
5970 $key = $tmp[0];
5971 $val = $tmp[1];
5972 if ($key != '' && $val != '') {
5973 if ((int) $key == (int) $limit) {
5974 $selected = ' selected="selected"';
5975 }
5976 print '<option name="'.$key.'"'.$selected.'>'.dol_escape_htmltag($val).'</option>'."\n";
5977 }
5978 }
5979 print '</select>';
5980 if ($conf->use_javascript_ajax) {
5981 print '<!-- JS CODE TO ENABLE select limit to launch submit of page -->
5982 <script>
5983 jQuery(document).ready(function () {
5984 jQuery(".selectlimit").change(function() {
5985 console.log("Change limit. Send submit");
5986 $(this).parents(\'form:first\').submit();
5987 });
5988 });
5989 </script>
5990 ';
5991 }
5992 print '</li>';
5993 }
5994 if ($page > 0) {
5995 print '<li class="pagination paginationpage paginationpageleft"><a class="paginationprevious reposition" href="'.$file.'?page='.($page - 1).$options.'"><i class="fa fa-chevron-left" title="'.dol_escape_htmltag($langs->trans("Previous")).'"></i></a></li>';
5996 }
5997 if ($betweenarrows) {
5998 print '<!--<div class="betweenarrows nowraponall inline-block">-->';
5999 print $betweenarrows;
6000 print '<!--</div>-->';
6001 }
6002 if ($nextpage > 0) {
6003 print '<li class="pagination paginationpage paginationpageright"><a class="paginationnext reposition" href="'.$file.'?page='.($page + 1).$options.'"><i class="fa fa-chevron-right" title="'.dol_escape_htmltag($langs->trans("Next")).'"></i></a></li>';
6004 }
6005 if ($afterarrows) {
6006 print '<li class="paginationafterarrows">';
6007 print $afterarrows;
6008 print '</li>';
6009 }
6010 }
6011 print '</ul></div>'."\n";
6012}
6013
6014
6026function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, $html = 0)
6027{
6028 $morelabel = '';
6029
6030 if (preg_match('/%/', $rate)) {
6031 $rate = str_replace('%', '', $rate);
6032 $addpercent = true;
6033 }
6034 $reg = array();
6035 if (preg_match('/\‍((.*)\‍)/', $rate, $reg)) {
6036 $morelabel = ' ('.$reg[1].')';
6037 $rate = preg_replace('/\s*'.preg_quote($morelabel, '/').'/', '', $rate);
6038 $morelabel = ' '.($html ? '<span class="opacitymedium">' : '').'('.$reg[1].')'.($html ? '</span>' : '');
6039 }
6040 if (preg_match('/\*/', $rate)) {
6041 $rate = str_replace('*', '', $rate);
6042 $info_bits |= 1;
6043 }
6044
6045 // If rate is '9/9/9' we don't change it. If rate is '9.000' we apply price()
6046 if (!preg_match('/\//', $rate)) {
6047 $ret = price($rate, 0, '', 0, 0).($addpercent ? '%' : '');
6048 } else {
6049 // TODO Split on / and output with a price2num to have clean numbers without ton of 000.
6050 $ret = $rate.($addpercent ? '%' : '');
6051 }
6052 if (($info_bits & 1) && $usestarfornpr >= 0) {
6053 $ret .= ' *';
6054 }
6055 $ret .= $morelabel;
6056 return $ret;
6057}
6058
6059
6075function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1, $currency_code = '')
6076{
6077 global $langs, $conf;
6078
6079 // Clean parameters
6080 if (empty($amount)) {
6081 $amount = 0; // To have a numeric value if amount not defined or = ''
6082 }
6083 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number)
6084 if ($rounding == -1) {
6085 $rounding = min(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), getDolGlobalString('MAIN_MAX_DECIMALS_TOT'));
6086 }
6087 $nbdecimal = $rounding;
6088
6089 if ($outlangs === 'none') {
6090 // Use international separators
6091 $dec = '.';
6092 $thousand = '';
6093 } else {
6094 // Output separators by default (french)
6095 $dec = ',';
6096 $thousand = ' ';
6097
6098 // If $outlangs not forced, we use use language
6099 if (!is_object($outlangs)) {
6100 $outlangs = $langs;
6101 }
6102
6103 if ($outlangs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6104 $dec = $outlangs->transnoentitiesnoconv("SeparatorDecimal");
6105 }
6106 if ($outlangs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6107 $thousand = $outlangs->transnoentitiesnoconv("SeparatorThousand");
6108 }
6109 if ($thousand == 'None') {
6110 $thousand = '';
6111 } elseif ($thousand == 'Space') {
6112 $thousand = ' ';
6113 }
6114 }
6115 //print "outlangs=".$outlangs->defaultlang." amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6116
6117 //print "amount=".$amount."-";
6118 $amount = str_replace(',', '.', $amount); // should be useless
6119 //print $amount."-";
6120 $datas = explode('.', $amount);
6121 $decpart = isset($datas[1]) ? $datas[1] : '';
6122 $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
6123 //print "decpart=".$decpart."<br>";
6124 $end = '';
6125
6126 // We increase nbdecimal if there is more decimal than asked (to not loose information)
6127 if (dol_strlen($decpart) > $nbdecimal) {
6128 $nbdecimal = dol_strlen($decpart);
6129 }
6130 // If nbdecimal is higher than max to show
6131 $nbdecimalmaxshown = (int) str_replace('...', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'));
6132 if ($trunc && $nbdecimal > $nbdecimalmaxshown) {
6133 $nbdecimal = $nbdecimalmaxshown;
6134 if (preg_match('/\.\.\./i', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'))) {
6135 // If output is truncated, we show ...
6136 $end = '...';
6137 }
6138 }
6139
6140 // If force rounding
6141 if ((string) $forcerounding != '-1') {
6142 if ($forcerounding === 'MU') {
6143 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_UNIT');
6144 } elseif ($forcerounding === 'MT') {
6145 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_TOT');
6146 } elseif ($forcerounding >= 0) {
6147 $nbdecimal = $forcerounding;
6148 }
6149 }
6150
6151 // Format number
6152 $output = number_format($amount, $nbdecimal, $dec, $thousand);
6153 if ($form) {
6154 $output = preg_replace('/\s/', '&nbsp;', $output);
6155 $output = preg_replace('/\'/', '&#039;', $output);
6156 }
6157 // Add symbol of currency if requested
6158 $cursymbolbefore = $cursymbolafter = '';
6159 if ($currency_code && is_object($outlangs)) {
6160 if ($currency_code == 'auto') {
6161 $currency_code = $conf->currency;
6162 }
6163
6164 $listofcurrenciesbefore = array('AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD', 'CRC', 'ZAR');
6165 $listoflanguagesbefore = array('nl_NL');
6166 if (in_array($currency_code, $listofcurrenciesbefore) || in_array($outlangs->defaultlang, $listoflanguagesbefore)) {
6167 $cursymbolbefore .= $outlangs->getCurrencySymbol($currency_code);
6168 } else {
6169 $tmpcur = $outlangs->getCurrencySymbol($currency_code);
6170 $cursymbolafter .= ($tmpcur == $currency_code ? ' '.$tmpcur : $tmpcur);
6171 }
6172 }
6173 $output = $cursymbolbefore.$output.$end.($cursymbolafter ? ' ' : '').$cursymbolafter;
6174
6175 return $output;
6176}
6177
6202function price2num($amount, $rounding = '', $option = 0)
6203{
6204 global $langs, $conf;
6205
6206 // Clean parameters
6207 if (is_null($amount)) {
6208 $amount = '';
6209 }
6210
6211 // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
6212 // Numbers must be '1234.56'
6213 // Decimal delimiter for PHP and database SQL requests must be '.'
6214 $dec = ',';
6215 $thousand = ' ';
6216 if (is_null($langs)) { // $langs is not defined, we use english values.
6217 $dec = '.';
6218 $thousand = ',';
6219 } else {
6220 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6221 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
6222 }
6223 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6224 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
6225 }
6226 }
6227 if ($thousand == 'None') {
6228 $thousand = '';
6229 } elseif ($thousand == 'Space') {
6230 $thousand = ' ';
6231 }
6232 //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6233
6234 // Convert value to universal number format (no thousand separator, '.' as decimal separator)
6235 if ($option != 1) { // If not a PHP number or unknown, we change or clean format
6236 //print "\n".'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'<br>';
6237 if (!is_numeric($amount)) {
6238 $amount = preg_replace('/[a-zA-Z\/\\\*\‍(\‍)<>\_]/', '', $amount);
6239 }
6240
6241 if ($option == 2 && $thousand == '.' && preg_match('/\.(\d\d\d)$/', (string) $amount)) { // It means the . is used as a thousand separator and string come from input data, so 1.123 is 1123
6242 $amount = str_replace($thousand, '', $amount);
6243 }
6244
6245 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6246 // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
6247 // So if number was already a good number, it is converted into local Dolibarr setup.
6248 if (is_numeric($amount)) {
6249 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6250 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6251 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6252 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6253 $amount = number_format($amount, $nbofdec, $dec, $thousand);
6254 }
6255 //print "QQ".$amount."<br>\n";
6256
6257 // Now make replace (the main goal of function)
6258 if ($thousand != ',' && $thousand != '.') {
6259 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6260 }
6261
6262 $amount = str_replace(' ', '', $amount); // To avoid spaces
6263 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6264 $amount = str_replace($dec, '.', $amount);
6265
6266 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6267 }
6268 //print ' XX'.$amount.' '.$rounding;
6269
6270 // Now, $amount is a real PHP float number. We make a rounding if required.
6271 if ($rounding) {
6272 $nbofdectoround = '';
6273 if ($rounding == 'MU') {
6274 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_UNIT;
6275 } elseif ($rounding == 'MT') {
6276 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_TOT;
6277 } elseif ($rounding == 'MS') {
6278 $nbofdectoround = isset($conf->global->MAIN_MAX_DECIMALS_STOCK) ? $conf->global->MAIN_MAX_DECIMALS_STOCK : 5;
6279 } elseif ($rounding == 'CU') {
6280 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), 8); // TODO Use param of currency
6281 } elseif ($rounding == 'CT') {
6282 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_TOT'), 8); // TODO Use param of currency
6283 } elseif (is_numeric($rounding)) {
6284 $nbofdectoround = (int) $rounding;
6285 }
6286
6287 //print " RR".$amount.' - '.$nbofdectoround.'<br>';
6288 if (dol_strlen($nbofdectoround)) {
6289 $amount = round(is_string($amount) ? (float) $amount : $amount, $nbofdectoround); // $nbofdectoround can be 0.
6290 } else {
6291 return 'ErrorBadParameterProvidedToFunction';
6292 }
6293 //print ' SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
6294
6295 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6296 // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
6297 if (is_numeric($amount)) {
6298 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6299 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6300 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6301 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6302 $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
6303 }
6304 //print "TT".$amount.'<br>';
6305
6306 // Always make replace because each math function (like round) replace
6307 // with local values and we want a number that has a SQL string format x.y
6308 if ($thousand != ',' && $thousand != '.') {
6309 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6310 }
6311
6312 $amount = str_replace(' ', '', $amount); // To avoid spaces
6313 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6314 $amount = str_replace($dec, '.', $amount);
6315
6316 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6317 }
6318
6319 return $amount;
6320}
6321
6334function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round = -1, $forceunitoutput = 'no', $use_short_label = 0)
6335{
6336 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
6337
6338 if (($forceunitoutput == 'no' && $dimension < 1 / 10000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -6)) {
6339 $dimension = $dimension * 1000000;
6340 $unit = $unit - 6;
6341 } elseif (($forceunitoutput == 'no' && $dimension < 1 / 10 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -3)) {
6342 $dimension = $dimension * 1000;
6343 $unit = $unit - 3;
6344 } elseif (($forceunitoutput == 'no' && $dimension > 100000000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 6)) {
6345 $dimension = $dimension / 1000000;
6346 $unit = $unit + 6;
6347 } elseif (($forceunitoutput == 'no' && $dimension > 100000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 3)) {
6348 $dimension = $dimension / 1000;
6349 $unit = $unit + 3;
6350 }
6351 // Special case when we want output unit into pound or ounce
6352 /* TODO
6353 if ($unit < 90 && $type == 'weight' && is_numeric($forceunitoutput) && (($forceunitoutput == 98) || ($forceunitoutput == 99))
6354 {
6355 $dimension = // convert dimension from standard unit into ounce or pound
6356 $unit = $forceunitoutput;
6357 }
6358 if ($unit > 90 && $type == 'weight' && is_numeric($forceunitoutput) && $forceunitoutput < 90)
6359 {
6360 $dimension = // convert dimension from standard unit into ounce or pound
6361 $unit = $forceunitoutput;
6362 }*/
6363
6364 $ret = price($dimension, 0, $outputlangs, 0, 0, $round);
6365 $ret .= ' '.measuringUnitString(0, $type, $unit, $use_short_label, $outputlangs);
6366
6367 return $ret;
6368}
6369
6370
6383function get_localtax($vatrate, $local, $thirdparty_buyer = "", $thirdparty_seller = "", $vatnpr = 0)
6384{
6385 global $db, $conf, $mysoc;
6386
6387 if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
6388 $thirdparty_seller = $mysoc;
6389 }
6390
6391 dol_syslog("get_localtax tva=".$vatrate." local=".$local." thirdparty_buyer id=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->id : '')."/country_code=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->country_code : '')." thirdparty_seller id=".$thirdparty_seller->id."/country_code=".$thirdparty_seller->country_code." thirdparty_seller localtax1_assuj=".$thirdparty_seller->localtax1_assuj." thirdparty_seller localtax2_assuj=".$thirdparty_seller->localtax2_assuj);
6392
6393 $vatratecleaned = $vatrate;
6394 $reg = array();
6395 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6396 $vatratecleaned = trim($reg[1]);
6397 $vatratecode = $reg[2];
6398 }
6399
6400 /*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
6401 {
6402 return 0;
6403 }*/
6404
6405 // Some test to guess with no need to make database access
6406 if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
6407 if ($local == 1) {
6408 if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
6409 return 0;
6410 }
6411 if ($thirdparty_seller->id == $mysoc->id) {
6412 if (!$thirdparty_buyer->localtax1_assuj) {
6413 return 0;
6414 }
6415 } else {
6416 if (!$thirdparty_seller->localtax1_assuj) {
6417 return 0;
6418 }
6419 }
6420 }
6421
6422 if ($local == 2) {
6423 //if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
6424 if (!$mysoc->localtax2_assuj) {
6425 return 0; // If main vat is 0, IRPF may be different than 0.
6426 }
6427 if ($thirdparty_seller->id == $mysoc->id) {
6428 if (!$thirdparty_buyer->localtax2_assuj) {
6429 return 0;
6430 }
6431 } else {
6432 if (!$thirdparty_seller->localtax2_assuj) {
6433 return 0;
6434 }
6435 }
6436 }
6437 } else {
6438 if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
6439 return 0;
6440 }
6441 if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
6442 return 0;
6443 }
6444 }
6445
6446 // For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
6447 if (in_array($mysoc->country_code, array('ES'))) {
6448 $conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
6449 }
6450
6451 // Search local taxes
6452 if (getDolGlobalString('MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY')) {
6453 if ($local == 1) {
6454 if ($thirdparty_seller != $mysoc) {
6455 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6456 return $thirdparty_seller->localtax1_value;
6457 }
6458 } else { // i am the seller
6459 if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
6460 return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
6461 }
6462 }
6463 }
6464 if ($local == 2) {
6465 if ($thirdparty_seller != $mysoc) {
6466 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6467 // TODO We should also return value defined on thirdparty only if defined
6468 return $thirdparty_seller->localtax2_value;
6469 }
6470 } else { // i am the seller
6471 if (in_array($mysoc->country_code, array('ES'))) {
6472 return $thirdparty_buyer->localtax2_value;
6473 } else {
6474 return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
6475 }
6476 }
6477 }
6478 }
6479
6480 // By default, search value of local tax on line of common tax
6481 $sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
6482 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6483 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
6484 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6485 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6486 if (!empty($vatratecode)) {
6487 $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
6488 } else {
6489 $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
6490 }
6491
6492 $resql = $db->query($sql);
6493
6494 if ($resql) {
6495 $obj = $db->fetch_object($resql);
6496 if ($obj) {
6497 if ($local == 1) {
6498 return $obj->localtax1;
6499 } elseif ($local == 2) {
6500 return $obj->localtax2;
6501 }
6502 }
6503 }
6504
6505 return 0;
6506}
6507
6508
6517function isOnlyOneLocalTax($local)
6518{
6519 $tax = get_localtax_by_third($local);
6520
6521 $valors = explode(":", $tax);
6522
6523 if (count($valors) > 1) {
6524 return false;
6525 } else {
6526 return true;
6527 }
6528}
6529
6537{
6538 global $db, $mysoc;
6539
6540 $sql = " SELECT t.localtax".$local." as localtax";
6541 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_pays";
6542 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.active = 1 AND t.entity IN (".getEntity('c_tva').") AND t.taux = (";
6543 $sql .= "SELECT MAX(tt.taux) FROM ".MAIN_DB_PREFIX."c_tva as tt INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = tt.fk_pays";
6544 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.entity IN (".getEntity('c_tva').") AND tt.active = 1)";
6545 $sql .= " AND t.localtax".$local."_type <> '0'";
6546 $sql .= " ORDER BY t.rowid DESC";
6547
6548 $resql = $db->query($sql);
6549 if ($resql) {
6550 $obj = $db->fetch_object($resql);
6551 if ($obj) {
6552 return $obj->localtax;
6553 } else {
6554 return '0';
6555 }
6556 }
6557
6558 return 'Error';
6559}
6560
6561
6573function getTaxesFromId($vatrate, $buyer = null, $seller = null, $firstparamisid = 1)
6574{
6575 global $db, $mysoc;
6576
6577 dol_syslog("getTaxesFromId vat id or rate = ".$vatrate);
6578
6579 // Search local taxes
6580 $sql = "SELECT t.rowid, t.code, t.taux as rate, t.recuperableonly as npr, t.accountancy_code_sell, t.accountancy_code_buy,";
6581 $sql .= " t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type";
6582 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6583 if ($firstparamisid) {
6584 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6585 } else {
6586 $vatratecleaned = $vatrate;
6587 $vatratecode = '';
6588 $reg = array();
6589 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6590 $vatratecleaned = $reg[1];
6591 $vatratecode = $reg[2];
6592 }
6593
6594 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6595 /*if ($mysoc->country_code == 'ES') $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($buyer->country_code)."'"; // vat in spain use the buyer country ??
6596 else $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";*/
6597 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";
6598 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6599 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6600 if ($vatratecode) {
6601 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6602 }
6603 }
6604
6605 $resql = $db->query($sql);
6606 if ($resql) {
6607 $obj = $db->fetch_object($resql);
6608 if ($obj) {
6609 return array(
6610 'rowid'=>$obj->rowid,
6611 'code'=>$obj->code,
6612 'rate'=>$obj->rate,
6613 'localtax1'=>$obj->localtax1,
6614 'localtax1_type'=>$obj->localtax1_type,
6615 'localtax2'=>$obj->localtax2,
6616 'localtax2_type'=>$obj->localtax2_type,
6617 'npr'=>$obj->npr,
6618 'accountancy_code_sell'=>$obj->accountancy_code_sell,
6619 'accountancy_code_buy'=>$obj->accountancy_code_buy
6620 );
6621 } else {
6622 return array();
6623 }
6624 } else {
6625 dol_print_error($db);
6626 }
6627
6628 return array();
6629}
6630
6647function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid = 0)
6648{
6649 global $db, $mysoc;
6650
6651 dol_syslog("getLocalTaxesFromRate vatrate=".$vatrate." local=".$local);
6652
6653 // Search local taxes
6654 $sql = "SELECT t.taux as rate, t.code, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.accountancy_code_sell, t.accountancy_code_buy";
6655 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6656 if ($firstparamisid) {
6657 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6658 } else {
6659 $vatratecleaned = $vatrate;
6660 $vatratecode = '';
6661 $reg = array();
6662 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "x.x (yy)"
6663 $vatratecleaned = $reg[1];
6664 $vatratecode = $reg[2];
6665 }
6666
6667 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6668 if (!empty($mysoc) && $mysoc->country_code == 'ES') {
6669 $countrycodetouse = ((empty($buyer) || empty($buyer->country_code)) ? $mysoc->country_code : $buyer->country_code);
6670 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'"; // local tax in spain use the buyer country ??
6671 } else {
6672 $countrycodetouse = ((empty($seller) || empty($seller->country_code)) ? $mysoc->country_code : $seller->country_code);
6673 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'";
6674 }
6675 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6676 if ($vatratecode) {
6677 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6678 }
6679 }
6680
6681 $resql = $db->query($sql);
6682 if ($resql) {
6683 $obj = $db->fetch_object($resql);
6684
6685 if ($obj) {
6686 $vateratestring = $obj->rate.($obj->code ? ' ('.$obj->code.')' : '');
6687
6688 if ($local == 1) {
6689 return array($obj->localtax1_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6690 } elseif ($local == 2) {
6691 return array($obj->localtax2_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6692 } else {
6693 return array($obj->localtax1_type, get_localtax($vateratestring, 1, $buyer, $seller), $obj->localtax2_type, get_localtax($vateratestring, 2, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6694 }
6695 }
6696 }
6697
6698 return array();
6699}
6700
6711function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice = 0)
6712{
6713 global $db, $conf, $mysoc;
6714
6715 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6716
6717 $ret = 0;
6718 $found = 0;
6719
6720 if ($idprod > 0) {
6721 // Load product
6722 $product = new Product($db);
6723 $product->fetch($idprod);
6724
6725 if ($mysoc->country_code == $thirdpartytouse->country_code) {
6726 // If country to consider is ours
6727 if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object
6728 $result = $product->get_buyprice($idprodfournprice, 0, 0, 0);
6729 if ($result > 0) {
6730 $ret = $product->vatrate_supplier;
6731 if ($product->default_vat_code_supplier) {
6732 $ret .= ' ('.$product->default_vat_code_supplier.')';
6733 }
6734 $found = 1;
6735 }
6736 }
6737 if (!$found) {
6738 $ret = $product->tva_tx; // Default sales vat of product
6739 if ($product->default_vat_code) {
6740 $ret .= ' ('.$product->default_vat_code.')';
6741 }
6742 $found = 1;
6743 }
6744 } else {
6745 // TODO Read default product vat according to product and an other countrycode.
6746 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6747 }
6748 }
6749
6750 if (!$found) {
6751 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
6752 // If vat of product for the country not found or not defined, we return the first rate found (sorting on use_default, then on higher vat of country).
6753 $sql = "SELECT t.taux as vat_rate, t.code as default_vat_code";
6754 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6755 $sql .= " WHERE t.active = 1 AND t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdpartytouse->country_code)."'";
6756 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6757 $sql .= " ORDER BY t.use_default DESC, t.taux DESC, t.code ASC, t.recuperableonly ASC";
6758 $sql .= $db->plimit(1);
6759
6760 $resql = $db->query($sql);
6761 if ($resql) {
6762 $obj = $db->fetch_object($resql);
6763 if ($obj) {
6764 $ret = $obj->vat_rate;
6765 if ($obj->default_vat_code) {
6766 $ret .= ' ('.$obj->default_vat_code.')';
6767 }
6768 }
6769 $db->free($resql);
6770 } else {
6771 dol_print_error($db);
6772 }
6773 } else {
6774 // Forced value if autodetect fails. MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS can be
6775 // '1.23'
6776 // or '1.23 (CODE)'
6777 $defaulttx = '';
6778 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
6779 $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6780 }
6781 /*if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6782 $defaultcode = $reg[1];
6783 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6784 }*/
6785
6786 $ret = $defaulttx;
6787 }
6788 }
6789
6790 dol_syslog("get_product_vat_for_country: ret=".$ret);
6791 return $ret;
6792}
6793
6803function get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
6804{
6805 global $db, $mysoc;
6806
6807 if (!class_exists('Product')) {
6808 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6809 }
6810
6811 $ret = 0;
6812 $found = 0;
6813
6814 if ($idprod > 0) {
6815 // Load product
6816 $product = new Product($db);
6817 $result = $product->fetch($idprod);
6818
6819 if ($mysoc->country_code == $thirdpartytouse->country_code) { // If selling country is ours
6820 /* Not defined yet, so we don't use this
6821 if ($local==1) $ret=$product->localtax1_tx;
6822 elseif ($local==2) $ret=$product->localtax2_tx;
6823 $found=1;
6824 */
6825 } else {
6826 // TODO Read default product vat according to product and another countrycode.
6827 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6828 }
6829 }
6830
6831 if (!$found) {
6832 // If vat of product for the country not found or not defined, we return higher vat of country.
6833 $sql = "SELECT taux as vat_rate, localtax1, localtax2";
6834 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6835 $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code='".$db->escape($thirdpartytouse->country_code)."'";
6836 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6837 $sql .= " ORDER BY t.taux DESC, t.recuperableonly ASC";
6838 $sql .= $db->plimit(1);
6839
6840 $resql = $db->query($sql);
6841 if ($resql) {
6842 $obj = $db->fetch_object($resql);
6843 if ($obj) {
6844 if ($local == 1) {
6845 $ret = $obj->localtax1;
6846 } elseif ($local == 2) {
6847 $ret = $obj->localtax2;
6848 }
6849 }
6850 } else {
6851 dol_print_error($db);
6852 }
6853 }
6854
6855 dol_syslog("get_product_localtax_for_country: ret=".$ret);
6856 return $ret;
6857}
6858
6875function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6876{
6877 global $conf;
6878
6879 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6880
6881 // Note: possible values for tva_assuj are 0/1 or franchise/reel
6882 $seller_use_vat = ((is_numeric($thirdparty_seller->tva_assuj) && !$thirdparty_seller->tva_assuj) || (!is_numeric($thirdparty_seller->tva_assuj) && $thirdparty_seller->tva_assuj == 'franchise')) ? 0 : 1;
6883
6884 $seller_country_code = $thirdparty_seller->country_code;
6885 $seller_in_cee = isInEEC($thirdparty_seller);
6886
6887 $buyer_country_code = $thirdparty_buyer->country_code;
6888 $buyer_in_cee = isInEEC($thirdparty_buyer);
6889
6890 dol_syslog("get_default_tva: seller use vat=".$seller_use_vat.", seller country=".$seller_country_code.", seller in cee=".$seller_in_cee.", buyer vat number=".$thirdparty_buyer->tva_intra." buyer country=".$buyer_country_code.", buyer in cee=".$buyer_in_cee.", idprod=".$idprod.", idprodfournprice=".$idprodfournprice.", SERVICE_ARE_ECOMMERCE_200238EC=".(getDolGlobalString('SERVICES_ARE_ECOMMERCE_200238EC') ? $conf->global->SERVICES_ARE_ECOMMERCE_200238EC : ''));
6891
6892 // If services are eServices according to EU Council Directive 2002/38/EC (http://ec.europa.eu/taxation_customs/taxation/vat/traders/e-commerce/article_1610_en.htm)
6893 // we use the buyer VAT.
6894 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) {
6895 if ($seller_in_cee && $buyer_in_cee) {
6896 $isacompany = $thirdparty_buyer->isACompany();
6897 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6898 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6899 if (!isValidVATID($thirdparty_buyer)) {
6900 $isacompany = 0;
6901 }
6902 }
6903
6904 if (!$isacompany) {
6905 //print 'VATRULE 0';
6906 return get_product_vat_for_country($idprod, $thirdparty_buyer, $idprodfournprice);
6907 }
6908 }
6909 }
6910
6911 // If seller does not use VAT, default VAT is 0. End of rule.
6912 if (!$seller_use_vat) {
6913 //print 'VATRULE 1';
6914 return 0;
6915 }
6916
6917 // If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule.
6918 if (($seller_country_code == $buyer_country_code)
6919 || (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC')))) { // Warning ->country_code not always defined
6920 //print 'VATRULE 2';
6921 $tmpvat = get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6922
6923 if ($seller_country_code == 'IN' && getDolGlobalString('MAIN_SALETAX_AUTOSWITCH_I_CS_FOR_INDIA')) {
6924 // Special case for india.
6925 //print 'VATRULE 2b';
6926 $reg = array();
6927 if (preg_match('/C+S-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id != $thirdparty_buyer->state_id) {
6928 // we must revert the C+S into I
6929 $tmpvat = str_replace("C+S", "I", $tmpvat);
6930 } elseif (preg_match('/I-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id == $thirdparty_buyer->state_id) {
6931 // we must revert the I into C+S
6932 $tmpvat = str_replace("I", "C+S", $tmpvat);
6933 }
6934 }
6935
6936 return $tmpvat;
6937 }
6938
6939 // If (seller and buyer in the European Community) and (property sold = new means of transport such as car, boat, plane) then VAT by default = 0 (VAT must be paid by the buyer to the tax center of his country and not to the seller). End of rule.
6940 // 'VATRULE 3' - Not supported
6941
6942 // If (seller and buyer in the European Community) and (buyer = individual) then VAT by default = VAT of the product sold. End of rule
6943 // If (seller and buyer in European Community) and (buyer = company) then VAT by default=0. End of rule
6944 if (($seller_in_cee && $buyer_in_cee)) {
6945 $isacompany = $thirdparty_buyer->isACompany();
6946 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6947 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6948 if (!isValidVATID($thirdparty_buyer)) {
6949 $isacompany = 0;
6950 }
6951 }
6952
6953 if (!$isacompany) {
6954 //print 'VATRULE 4';
6955 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6956 } else {
6957 //print 'VATRULE 5';
6958 return 0;
6959 }
6960 }
6961
6962 // If (seller in the European Community and buyer outside the European Community and private buyer) then VAT by default = VAT of the product sold. End of rule
6963 // I don't see any use case that need this rule.
6964 if (getDolGlobalString('MAIN_USE_VAT_OF_PRODUCT_FOR_INDIVIDUAL_CUSTOMER_OUT_OF_EEC') && empty($buyer_in_cee)) {
6965 $isacompany = $thirdparty_buyer->isACompany();
6966 if (!$isacompany) {
6967 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6968 //print 'VATRULE extra';
6969 }
6970 }
6971
6972 // Otherwise the VAT proposed by default=0. End of rule.
6973 // Rem: This means that at least one of the 2 is outside the European Community and the country differs
6974 //print 'VATRULE 6';
6975 return 0;
6976}
6977
6978
6989function get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6990{
6991 global $db;
6992
6993 if ($idprodfournprice > 0) {
6994 if (!class_exists('ProductFournisseur')) {
6995 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
6996 }
6997 $prodprice = new ProductFournisseur($db);
6998 $prodprice->fetch_product_fournisseur_price($idprodfournprice);
6999 return $prodprice->fourn_tva_npr;
7000 } elseif ($idprod > 0) {
7001 if (!class_exists('Product')) {
7002 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
7003 }
7004 $prod = new Product($db);
7005 $prod->fetch($idprod);
7006 return $prod->tva_npr;
7007 }
7008
7009 return 0;
7010}
7011
7025function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod = 0)
7026{
7027 global $mysoc;
7028
7029 if (!is_object($thirdparty_seller)) {
7030 return -1;
7031 }
7032 if (!is_object($thirdparty_buyer)) {
7033 return -1;
7034 }
7035
7036 if ($local == 1) { // Localtax 1
7037 if ($mysoc->country_code == 'ES') {
7038 if (is_numeric($thirdparty_buyer->localtax1_assuj) && !$thirdparty_buyer->localtax1_assuj) {
7039 return 0;
7040 }
7041 } else {
7042 // Si vendeur non assujeti a Localtax1, localtax1 par default=0
7043 if (is_numeric($thirdparty_seller->localtax1_assuj) && !$thirdparty_seller->localtax1_assuj) {
7044 return 0;
7045 }
7046 if (!is_numeric($thirdparty_seller->localtax1_assuj) && $thirdparty_seller->localtax1_assuj == 'localtax1off') {
7047 return 0;
7048 }
7049 }
7050 } elseif ($local == 2) { //I Localtax 2
7051 // Si vendeur non assujeti a Localtax2, localtax2 par default=0
7052 if (is_numeric($thirdparty_seller->localtax2_assuj) && !$thirdparty_seller->localtax2_assuj) {
7053 return 0;
7054 }
7055 if (!is_numeric($thirdparty_seller->localtax2_assuj) && $thirdparty_seller->localtax2_assuj == 'localtax2off') {
7056 return 0;
7057 }
7058 }
7059
7060 if ($thirdparty_seller->country_code == $thirdparty_buyer->country_code) {
7061 return get_product_localtax_for_country($idprod, $local, $thirdparty_seller);
7062 }
7063
7064 return 0;
7065}
7066
7075function yn($yesno, $case = 1, $color = 0)
7076{
7077 global $langs;
7078
7079 $result = 'unknown';
7080 $classname = '';
7081 if ($yesno == 1 || (isset($yesno) && (strtolower($yesno) == 'yes' || strtolower($yesno) == 'true'))) { // A mettre avant test sur no a cause du == 0
7082 $result = $langs->trans('yes');
7083 if ($case == 1 || $case == 3) {
7084 $result = $langs->trans("Yes");
7085 }
7086 if ($case == 2) {
7087 $result = '<input type="checkbox" value="1" checked disabled>';
7088 }
7089 if ($case == 3) {
7090 $result = '<input type="checkbox" value="1" checked disabled> '.$result;
7091 }
7092
7093 $classname = 'ok';
7094 } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') {
7095 $result = $langs->trans("no");
7096 if ($case == 1 || $case == 3) {
7097 $result = $langs->trans("No");
7098 }
7099 if ($case == 2) {
7100 $result = '<input type="checkbox" value="0" disabled>';
7101 }
7102 if ($case == 3) {
7103 $result = '<input type="checkbox" value="0" disabled> '.$result;
7104 }
7105
7106 if ($color == 2) {
7107 $classname = 'ok';
7108 } else {
7109 $classname = 'error';
7110 }
7111 }
7112 if ($color) {
7113 return '<span class="'.$classname.'">'.$result.'</span>';
7114 }
7115 return $result;
7116}
7117
7133function get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart = '')
7134{
7135 global $conf;
7136
7137 if (empty($modulepart) && !empty($object->module)) {
7138 $modulepart = $object->module;
7139 }
7140
7141 $path = '';
7142
7143 $arrayforoldpath = array('cheque', 'category', 'holiday', 'supplier_invoice', 'invoice_supplier', 'mailing', 'supplier_payment');
7144 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
7145 $arrayforoldpath[] = 'product';
7146 }
7147 if (!empty($level) && in_array($modulepart, $arrayforoldpath)) {
7148 // This part should be removed once all code is using "get_exdir" to forge path, with parameter $object and $modulepart provided.
7149 if (empty($alpha)) {
7150 $num = preg_replace('/([^0-9])/i', '', $num);
7151 } else {
7152 $num = preg_replace('/^.*\-/i', '', $num);
7153 }
7154 $num = substr("000".$num, -$level);
7155 if ($level == 1) {
7156 $path = substr($num, 0, 1);
7157 }
7158 if ($level == 2) {
7159 $path = substr($num, 1, 1).'/'.substr($num, 0, 1);
7160 }
7161 if ($level == 3) {
7162 $path = substr($num, 2, 1).'/'.substr($num, 1, 1).'/'.substr($num, 0, 1);
7163 }
7164 } else {
7165 // We will enhance here a common way of forging path for document storage.
7166 // In a future, we may distribute directories on several levels depending on setup and object.
7167 // Here, $object->id, $object->ref and $modulepart are required.
7168 //var_dump($modulepart);
7169 $path = dol_sanitizeFileName(empty($object->ref) ? (string) $object->id : $object->ref);
7170 }
7171
7172 if (empty($withoutslash) && !empty($path)) {
7173 $path .= '/';
7174 }
7175
7176 return $path;
7177}
7178
7187function dol_mkdir($dir, $dataroot = '', $newmask = '')
7188{
7189 global $conf;
7190
7191 dol_syslog("functions.lib::dol_mkdir: dir=".$dir, LOG_INFO);
7192
7193 $dir_osencoded = dol_osencode($dir);
7194 if (@is_dir($dir_osencoded)) {
7195 return 0;
7196 }
7197
7198 $nberr = 0;
7199 $nbcreated = 0;
7200
7201 $ccdir = '';
7202 if (!empty($dataroot)) {
7203 // Remove data root from loop
7204 $dir = str_replace($dataroot.'/', '', $dir);
7205 $ccdir = $dataroot.'/';
7206 }
7207
7208 $cdir = explode("/", $dir);
7209 $num = count($cdir);
7210 for ($i = 0; $i < $num; $i++) {
7211 if ($i > 0) {
7212 $ccdir .= '/'.$cdir[$i];
7213 } else {
7214 $ccdir .= $cdir[$i];
7215 }
7216 $regs = array();
7217 if (preg_match("/^.:$/", $ccdir, $regs)) {
7218 continue; // Si chemin Windows incomplet, on poursuit par rep suivant
7219 }
7220
7221 // Attention, le is_dir() peut echouer bien que le rep existe.
7222 // (ex selon config de open_basedir)
7223 if ($ccdir) {
7224 $ccdir_osencoded = dol_osencode($ccdir);
7225 if (!@is_dir($ccdir_osencoded)) {
7226 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.", LOG_DEBUG);
7227
7228 umask(0);
7229 $dirmaskdec = octdec((string) $newmask);
7230 if (empty($newmask)) {
7231 $dirmaskdec = !getDolGlobalString('MAIN_UMASK') ? octdec('0755') : octdec($conf->global->MAIN_UMASK);
7232 }
7233 $dirmaskdec |= octdec('0111'); // Set x bit required for directories
7234 if (!@mkdir($ccdir_osencoded, $dirmaskdec)) {
7235 // Si le is_dir a renvoye une fausse info, alors on passe ici.
7236 dol_syslog("functions.lib::dol_mkdir: Fails to create directory '".$ccdir."' or directory already exists.", LOG_WARNING);
7237 $nberr++;
7238 } else {
7239 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' created", LOG_DEBUG);
7240 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignore
7241 $nbcreated++;
7242 }
7243 } else {
7244 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignores
7245 }
7246 }
7247 }
7248 return ($nberr ? -$nberr : $nbcreated);
7249}
7250
7251
7259function dolChmod($filepath, $newmask = '')
7260{
7261 global $conf;
7262
7263 if (!empty($newmask)) {
7264 @chmod($filepath, octdec($newmask));
7265 } elseif (getDolGlobalString('MAIN_UMASK')) {
7266 @chmod($filepath, octdec($conf->global->MAIN_UMASK));
7267 }
7268}
7269
7270
7277{
7278 return '<span class="fieldrequired">*</span>';
7279}
7280
7281
7298function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = 'UTF-8', $strip_tags = 0, $removedoublespaces = 1)
7299{
7300 if (is_null($stringtoclean)) {
7301 return '';
7302 }
7303
7304 if ($removelinefeed == 2) {
7305 $stringtoclean = preg_replace('/<br[^>]*>(\n|\r)+/ims', '<br>', $stringtoclean);
7306 }
7307 $temp = preg_replace('/<br[^>]*>/i', "\n", $stringtoclean);
7308
7309 // We remove entities BEFORE stripping (in case of an open separator char that is entity encoded and not the closing other, the strip will fails)
7310 $temp = dol_html_entity_decode($temp, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7311
7312 $temp = str_replace('< ', '__ltspace__', $temp);
7313
7314 if ($strip_tags) {
7315 $temp = strip_tags($temp);
7316 } else {
7317 // Remove '<' into remainging, so remove non closing html tags like '<abc' or '<<abc'. Note: '<123abc' is not a html tag (can be kept), but '<abc123' is (must be removed).
7318 $pattern = "/<[^<>]+>/";
7319 // Example of $temp: <a href="/myurl" title="<u>A title</u>">0000-021</a>
7320 // pass 1 - $temp after pass 1: <a href="/myurl" title="A title">0000-021
7321 // pass 2 - $temp after pass 2: 0000-021
7322 $tempbis = $temp;
7323 do {
7324 $temp = $tempbis;
7325 $tempbis = str_replace('<>', '', $temp); // No reason to have this into a text, except if value is to try bypass the next html cleaning
7326 $tempbis = preg_replace($pattern, '', $tempbis);
7327 //$idowhile++; print $temp.'-'.$tempbis."\n"; if ($idowhile > 100) break;
7328 } while ($tempbis != $temp);
7329
7330 $temp = $tempbis;
7331
7332 // Remove '<' into remaining, so remove non closing html tags like '<abc' or '<<abc'. Note: '<123abc' is not a html tag (can be kept), but '<abc123' is (must be removed).
7333 $temp = preg_replace('/<+([a-z]+)/i', '\1', $temp);
7334 }
7335
7336 $temp = dol_html_entity_decode($temp, ENT_COMPAT, $pagecodeto);
7337
7338 // Remove also carriage returns
7339 if ($removelinefeed == 1) {
7340 $temp = str_replace(array("\r\n", "\r", "\n"), " ", $temp);
7341 }
7342
7343 // And double quotes
7344 if ($removedoublespaces) {
7345 while (strpos($temp, " ")) {
7346 $temp = str_replace(" ", " ", $temp);
7347 }
7348 }
7349
7350 $temp = str_replace('__ltspace__', '< ', $temp);
7351
7352 return trim($temp);
7353}
7354
7370function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1, $cleanalsojavascript = 0, $allowiframe = 0, $allowed_tags = array(), $allowlink = 0)
7371{
7372 if (empty($allowed_tags)) {
7373 $allowed_tags = array(
7374 "html", "head", "meta", "body", "article", "a", "abbr", "b", "blockquote", "br", "cite", "div", "dl", "dd", "dt", "em", "font", "img", "ins", "hr", "i", "li",
7375 "ol", "p", "q", "s", "span", "strike", "strong", "title", "table", "tr", "th", "td", "u", "ul", "sup", "sub", "blockquote", "pre", "h1", "h2", "h3", "h4", "h5", "h6",
7376 "header", "footer", "nav", "section", "menu", "menuitem" // html5 tags
7377 );
7378 }
7379 $allowed_tags[] = "comment"; // this tags is added to manage comment <!--...--> that are replaced into <comment>...</comment>
7380 if ($allowiframe) {
7381 if (!in_array('iframe', $allowed_tags)) {
7382 $allowed_tags[] = "iframe";
7383 }
7384 }
7385 if ($allowlink) {
7386 if (!in_array('link', $allowed_tags)) {
7387 $allowed_tags[] = "link";
7388 }
7389 }
7390
7391 $allowed_tags_string = join("><", $allowed_tags);
7392 $allowed_tags_string = '<'.$allowed_tags_string.'>';
7393
7394 $stringtoclean = str_replace('<!DOCTYPE html>', '__!DOCTYPE_HTML__', $stringtoclean); // Replace DOCTYPE to avoid to have it removed by the strip_tags
7395
7396 $stringtoclean = dol_string_nounprintableascii($stringtoclean, 0);
7397
7398 //$stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
7399 $stringtoclean = preg_replace('/<!--([^>]*)-->/', '<comment>\1</comment>', $stringtoclean);
7400
7401 $stringtoclean = preg_replace('/&colon;/i', ':', $stringtoclean);
7402 $stringtoclean = preg_replace('/&#58;|&#0+58|&#x3A/i', '', $stringtoclean); // refused string ':' encoded (no reason to have a : encoded like this) to disable 'javascript:...'
7403
7404 $temp = strip_tags($stringtoclean, $allowed_tags_string); // Warning: This remove also undesired </>, so may changes string obfuscated with </> that pass the injection detection into a harmfull string
7405
7406 if ($cleanalsosomestyles) { // Clean for remaining html tags
7407 $temp = preg_replace('/position\s*:\s*(absolute|fixed)\s*!\s*important/i', '', $temp); // Note: If hacker try to introduce css comment into string to bypass this regex, the string must also be encoded by the dol_htmlentitiesbr during output so it become harmless
7408 }
7409 if ($removeclassattribute) { // Clean for remaining html tags
7410 $temp = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $temp);
7411 }
7412
7413 // Remove 'javascript:' that we should not find into a text with
7414 // Warning: This is not reliable to fight against obfuscated javascript, there is a lot of other solution to include js into a common html tag (only filtered by a GETPOST(.., powerfullfilter)).
7415 if ($cleanalsojavascript) {
7416 $temp = preg_replace('/j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*:/i', '', $temp);
7417 }
7418
7419 $temp = str_replace('__!DOCTYPE_HTML__', '<!DOCTYPE html>', $temp); // Restore the DOCTYPE
7420
7421 $temp = preg_replace('/<comment>([^>]*)<\/comment>/', '<!--\1-->', $temp); // Restore html comments
7422
7423
7424 return $temp;
7425}
7426
7427
7439function dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes = null)
7440{
7441 if (is_null($allowed_attributes)) {
7442 $allowed_attributes = array(
7443 "allow", "allowfullscreen", "alt", "class", "contenteditable", "data-html", "frameborder", "height", "href", "id", "name", "src", "style", "target", "title", "width",
7444 // HTML5
7445 "header", "footer", "nav", "section", "menu", "menuitem"
7446 );
7447 }
7448
7449 if (class_exists('DOMDocument') && !empty($stringtoclean)) {
7450 $stringtoclean = '<?xml encoding="UTF-8"><html><body>'.$stringtoclean.'</body></html>';
7451
7452 // Warning: loadHTML does not support HTML5 on old libxml versions.
7453 $dom = new DOMDocument(null, 'UTF-8');
7454 $dom->loadHTML($stringtoclean, LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7455
7456 if (is_object($dom)) {
7457 for ($els = $dom->getElementsByTagname('*'), $i = $els->length - 1; $i >= 0; $i--) {
7458 for ($attrs = $els->item($i)->attributes, $ii = $attrs->length - 1; $ii >= 0; $ii--) {
7459 //var_dump($attrs->item($ii));
7460 if (!empty($attrs->item($ii)->name)) {
7461 if (! in_array($attrs->item($ii)->name, $allowed_attributes)) {
7462 // Delete attribute if not into allowed_attributes
7463 $els->item($i)->removeAttribute($attrs->item($ii)->name);
7464 } elseif (in_array($attrs->item($ii)->name, array('style'))) {
7465 // If attribute is 'style'
7466 $valuetoclean = $attrs->item($ii)->value;
7467
7468 if (isset($valuetoclean)) {
7469 do {
7470 $oldvaluetoclean = $valuetoclean;
7471 $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments
7472 $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean);
7473 if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags.
7474 $valuetoclean = preg_replace('/display\s*:/mi', '', $valuetoclean);
7475 $valuetoclean = preg_replace('/z-index\s*:/mi', '', $valuetoclean);
7476 $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*:/mi', '', $valuetoclean);
7477 }
7478
7479 // We do not allow logout|passwordforgotten.php and action= into the content of a "style" tag
7480 $valuetoclean = preg_replace('/(logout|passwordforgotten)\.php/mi', '', $valuetoclean);
7481 $valuetoclean = preg_replace('/action=/mi', '', $valuetoclean);
7482 } while ($oldvaluetoclean != $valuetoclean);
7483 }
7484
7485 $attrs->item($ii)->value = $valuetoclean;
7486 }
7487 }
7488 }
7489 }
7490 }
7491
7492 $return = $dom->saveHTML(); // This may add a LF at end of lines, so we will trim later
7493 //$return = '<html><body>aaaa</p>bb<p>ssdd</p>'."\n<p>aaa</p>aa<p>bb</p>";
7494
7495 $return = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $return);
7496 $return = preg_replace('/^'.preg_quote('<html><body>', '/').'/', '', $return);
7497 $return = preg_replace('/'.preg_quote('</body></html>', '/').'$/', '', $return);
7498 return trim($return);
7499 } else {
7500 return $stringtoclean;
7501 }
7502}
7503
7515function dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags = array('textarea'), $cleanalsosomestyles = 0)
7516{
7517 $temp = $stringtoclean;
7518 foreach ($disallowed_tags as $tagtoremove) {
7519 $temp = preg_replace('/<\/?'.$tagtoremove.'>/', '', $temp);
7520 $temp = preg_replace('/<\/?'.$tagtoremove.'\s+[^>]*>/', '', $temp);
7521 }
7522
7523 if ($cleanalsosomestyles) {
7524 $temp = preg_replace('/position\s*:\s*(absolute|fixed)\s*!\s*important/', '', $temp); // Note: If hacker try to introduce css comment into string to avoid this, string should be encoded by the dol_htmlentitiesbr so be harmless
7525 }
7526
7527 return $temp;
7528}
7529
7530
7540function dolGetFirstLineOfText($text, $nboflines = 1, $charset = 'UTF-8')
7541{
7542 if ($nboflines == 1) {
7543 if (dol_textishtml($text)) {
7544 $firstline = preg_replace('/<br[^>]*>.*$/s', '', $text); // The s pattern modifier means the . can match newline characters
7545 $firstline = preg_replace('/<div[^>]*>.*$/s', '', $firstline); // The s pattern modifier means the . can match newline characters
7546 } else {
7547 if (isset($text)) {
7548 $firstline = preg_replace('/[\n\r].*/', '', $text);
7549 } else {
7550 $firstline = '';
7551 }
7552 }
7553 return $firstline.(isset($firstline) && isset($text) && (strlen($firstline) != strlen($text)) ? '...' : '');
7554 } else {
7555 $ishtml = 0;
7556 if (dol_textishtml($text)) {
7557 $text = preg_replace('/\n/', '', $text);
7558 $ishtml = 1;
7559 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7560 } else {
7561 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7562 }
7563
7564 $text = strtr($text, $repTable);
7565 if ($charset == 'UTF-8') {
7566 $pattern = '/(<br[^>]*>)/Uu';
7567 } else {
7568 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7569 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7570 }
7571 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7572
7573 $firstline = '';
7574 $i = 0;
7575 $countline = 0;
7576 $lastaddediscontent = 1;
7577 while ($countline < $nboflines && isset($a[$i])) {
7578 if (preg_match('/<br[^>]*>/', $a[$i])) {
7579 if (array_key_exists($i+1, $a) && !empty($a[$i+1])) {
7580 $firstline .= ($ishtml ? "<br>\n" : "\n");
7581 // Is it a br for a new line of after a printed line ?
7582 if (!$lastaddediscontent) {
7583 $countline++;
7584 }
7585 $lastaddediscontent = 0;
7586 }
7587 } else {
7588 $firstline .= $a[$i];
7589 $lastaddediscontent = 1;
7590 $countline++;
7591 }
7592 $i++;
7593 }
7594
7595 $adddots = (isset($a[$i]) && (!preg_match('/<br[^>]*>/', $a[$i]) || (array_key_exists($i+1, $a) && !empty($a[$i+1]))));
7596 //unset($a);
7597 $ret = $firstline.($adddots ? '...' : '');
7598 //exit;
7599 return $ret;
7600 }
7601}
7602
7603
7615function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false)
7616{
7617 if (is_null($stringtoencode)) {
7618 return '';
7619 }
7620
7621 if (!$nl2brmode) {
7622 return nl2br($stringtoencode, $forxml);
7623 } else {
7624 $ret = preg_replace('/(\r\n|\r|\n)/i', ($forxml ? '<br />' : '<br>'), $stringtoencode);
7625 return $ret;
7626 }
7627}
7628
7638function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = 'restricthtml')
7639{
7640 if (empty($nouseofiframesandbox) && getDolGlobalString('MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS')) {
7641 // TODO using sandbox on inline html content is not possible yet with current browsers
7642 //$s = '<iframe class="iframewithsandbox" sandbox><html><body>';
7643 //$s .= $stringtoencode;
7644 //$s .= '</body></html></iframe>';
7645 return $stringtoencode;
7646 } else {
7647 $out = $stringtoencode;
7648
7649 do {
7650 $oldstringtoclean = $out;
7651
7652 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML') && $check != 'restricthtmlallowunvalid') {
7653 try {
7654 libxml_use_internal_errors(false); // Avoid to fill memory with xml errors
7655 if (LIBXML_VERSION < 20900) {
7656 // Avoid load of external entities (security problem).
7657 // Required only if LIBXML_VERSION < 20900
7658 libxml_disable_entity_loader(true);
7659 }
7660
7661 $dom = new DOMDocument();
7662 // Add a trick to solve pb with text without parent tag
7663 // like '<h1>Foo</h1><p>bar</p>' that wrongly ends up, without the trick, with '<h1>Foo<p>bar</p></h1>'
7664 // like 'abc' that wrongly ends up, without the trick, with '<p>abc</p>'
7665
7666 if (dol_textishtml($out)) {
7667 $out = '<?xml encoding="UTF-8"><div class="tricktoremove">'.$out.'</div>';
7668 } else {
7669 $out = '<?xml encoding="UTF-8"><div class="tricktoremove">'.dol_nl2br($out).'</div>';
7670 }
7671 $dom->loadHTML($out, LIBXML_HTML_NODEFDTD | LIBXML_ERR_NONE | LIBXML_HTML_NOIMPLIED | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_NOERROR | LIBXML_NOXMLDECL);
7672 $out = trim($dom->saveHTML());
7673
7674 // Remove the trick added to solve pb with text without parent tag
7675 $out = preg_replace('/^<\?xml encoding="UTF-8"><div class="tricktoremove">/', '', $out);
7676 $out = preg_replace('/<\/div>$/', '', $out);
7677 } catch (Exception $e) {
7678 // If error, invalid HTML string with no way to clean it
7679 //print $e->getMessage();
7680 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
7681 }
7682 }
7683
7684 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY') && $check != 'restricthtmlallowunvalid') {
7685 try {
7686 // Try cleaning using tidy
7687 if (extension_loaded('tidy') && class_exists("tidy")) {
7688 //print "aaa".$out."\n";
7689
7690 // See options at https://tidy.sourceforge.net/docs/quickref.html
7691 $config = array(
7692 'clean' => false,
7693 'quote-marks' => false, // do not replace " that are used for real text content (not a string symbol for html attribute) into &quot;
7694 'doctype' => 'strict',
7695 'show-body-only' => true,
7696 "indent-attributes" => false,
7697 "vertical-space" => false,
7698 'ident' => false,
7699 "wrap" => 0
7700 // HTML5 tags
7701 //'new-blocklevel-tags' => 'article aside audio bdi canvas details dialog figcaption figure footer header hgroup main menu menuitem nav section source summary template track video',
7702 //'new-blocklevel-tags' => 'footer header section menu menuitem'
7703 //'new-empty-tags' => 'command embed keygen source track wbr',
7704 //'new-inline-tags' => 'audio command datalist embed keygen mark menuitem meter output progress source time video wbr',
7705 );
7706
7707 // Tidy
7708 $tidy = new tidy();
7709 $out = $tidy->repairString($out, $config, 'utf8');
7710
7711 //print "xxx".$out;exit;
7712 }
7713 } catch (Exception $e) {
7714 // If error, invalid HTML string with no way to clean it
7715 //print $e->getMessage();
7716 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
7717 }
7718 }
7719
7720 //Clear ZERO WIDTH NO-BREAK SPACE, ZERO WIDTH SPACE, ZERO WIDTH JOINER
7721 $out = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $out);
7722
7723 // Clean some html entities that are useless so text is cleaner
7724 $out = preg_replace('/&(tab|newline);/i', ' ', $out);
7725
7726 // Ckeditor use the numeric entitic for apostrophe so we force it to text entity (all other special chars are
7727 // encoded using text entities) so we can then exclude all numeric entities.
7728 $out = preg_replace('/&#39;/i', '&apos;', $out);
7729
7730 // We replace chars from a/A to z/Z encoded with numeric HTML entities with the real char so we won't loose the chars at the next step (preg_replace).
7731 // No need to use a loop here, this step is not to sanitize (this is done at next step, this is to try to save chars, even if they are
7732 // using a non coventionnel way to be encoded, to not have them sanitized just after)
7733 $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) {
7734 return realCharForNumericEntities($m);
7735 }, $out);
7736
7737
7738 // Now we remove all remaining HTML entities starting with a number. We don't want such entities.
7739 $out = preg_replace('/&#x?[0-9]+/i', '', $out); // For example if we have j&#x61vascript with an entities without the ; to hide the 'a' of 'javascript'.
7740
7741 // Keep only some html tags and remove also some 'javascript:' strings
7742 $out = dol_string_onlythesehtmltags($out, 0, ($check == 'restricthtmlallowclass' ? 0 : 1), 1);
7743
7744 // Keep only some html attributes and exclude non expected HTML attributes and clean content of some attributes (keep only alt=, title=...).
7745 if (getDolGlobalString('MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES')) {
7747 }
7748
7749 // Restore entity &apos; into &#39; (restricthtml is for html content so we can use html entity)
7750 $out = preg_replace('/&apos;/i', "&#39;", $out);
7751 } while ($oldstringtoclean != $out);
7752
7753 // Check the limit of external links that are automatically executed in a Rich text content. We count:
7754 // '<img' to avoid <img src="http...">, we can only accept "<img src="data:..."
7755 // 'url(' to avoid inline style like background: url(http...
7756 // '<link' to avoid <link href="http...">
7757 $reg = array();
7758 $tmpout = preg_replace('/<img src="data:/mi', '<__IMG_SRC_DATA__ src="data:', $out);
7759 preg_match_all('/(<img|url\‍(|<link)/i', $tmpout, $reg);
7760 $nblinks = count($reg[0]);
7761 if ($nblinks > getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) {
7762 $out = 'ErrorTooManyLinksIntoHTMLString';
7763 }
7764
7765 if (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 2 || $check == 'restricthtmlnolink') {
7766 if ($nblinks > 0) {
7767 $out = 'ErrorHTMLLinksNotAllowed';
7768 }
7769 } elseif (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 1) {
7770 $nblinks = 0;
7771 // Loop on each url in src= and url(
7772 $pattern = '/src=["\']?(http[^"\']+)|url\‍(["\']?(http[^\‍)]+)/';
7773
7774 $matches = array();
7775 if (preg_match_all($pattern, $out, $matches)) {
7776 // URLs are into $matches[1]
7777 $urls = $matches[1];
7778
7779 // Affiche les URLs
7780 foreach ($urls as $url) {
7781 $nblinks++;
7782 echo "Found url = ".$url . "\n";
7783 }
7784 if ($nblinks > 0) {
7785 $out = 'ErrorHTMLExternalLinksNotAllowed';
7786 }
7787 }
7788 }
7789
7790 return $out;
7791 }
7792}
7793
7815function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UTF-8', $removelasteolbr = 1)
7816{
7817 if (is_null($stringtoencode)) {
7818 return '';
7819 }
7820
7821 $newstring = $stringtoencode;
7822 if (dol_textishtml($stringtoencode)) { // Check if text is already HTML or not
7823 $newstring = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', '<br>', $newstring); // Replace "<br type="_moz" />" by "<br>". It's same and avoid pb with FPDF.
7824 if ($removelasteolbr) {
7825 $newstring = preg_replace('/<br>$/i', '', $newstring); // Remove last <br> (remove only last one)
7826 }
7827 $newstring = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $newstring);
7828 $newstring = strtr($newstring, array('&'=>'__and__', '<'=>'__lt__', '>'=>'__gt__', '"'=>'__dquot__'));
7829 $newstring = dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom); // Make entity encoding
7830 $newstring = strtr($newstring, array('__and__'=>'&', '__lt__'=>'<', '__gt__'=>'>', '__dquot__'=>'"'));
7831 } else {
7832 if ($removelasteolbr) {
7833 $newstring = preg_replace('/(\r\n|\r|\n)$/i', '', $newstring); // Remove last \n (may remove several)
7834 }
7835 $newstring = dol_nl2br(dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom), $nl2brmode);
7836 }
7837 // Other substitutions that htmlentities does not do
7838 //$newstring=str_replace(chr(128),'&euro;',$newstring); // 128 = 0x80. Not in html entity table. // Seems useles with TCPDF. Make bug with UTF8 languages
7839 return $newstring;
7840}
7841
7849function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8')
7850{
7851 $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7852 $ret = preg_replace('/'."\r\n".'<br(\s[\sa-zA-Z_="]*)?\/?>/i', "<br>", $ret);
7853 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\r\n".'/i', "\r\n", $ret);
7854 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\n".'/i', "\n", $ret);
7855 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', "\n", $ret);
7856 return $ret;
7857}
7858
7865function dol_htmlcleanlastbr($stringtodecode)
7866{
7867 $ret = preg_replace('/&nbsp;$/i', "", $stringtodecode); // Because wysiwyg editor may add a &nbsp; at end of last line
7868 $ret = preg_replace('/(<br>|<br(\s[\sa-zA-Z_="]*)?\/?>|'."\n".'|'."\r".')+$/i', "", $ret);
7869 return $ret;
7870}
7871
7881function dol_html_entity_decode($a, $b, $c = 'UTF-8', $keepsomeentities = 0)
7882{
7883 $newstring = $a;
7884 if ($keepsomeentities) {
7885 $newstring = strtr($newstring, array('&amp;'=>'__andamp__', '&lt;'=>'__andlt__', '&gt;'=>'__andgt__', '"'=>'__dquot__'));
7886 }
7887 $newstring = html_entity_decode((string) $newstring, (int) $b, (string) $c);
7888 if ($keepsomeentities) {
7889 $newstring = strtr($newstring, array('__andamp__'=>'&amp;', '__andlt__'=>'&lt;', '__andgt__'=>'&gt;', '__dquot__'=>'"'));
7890 }
7891 return $newstring;
7892}
7893
7905function dol_htmlentities($string, $flags = ENT_QUOTES|ENT_SUBSTITUTE, $encoding = 'UTF-8', $double_encode = false)
7906{
7907 return htmlentities($string, $flags, $encoding, $double_encode);
7908}
7909
7921function dol_string_is_good_iso($s, $clean = 0)
7922{
7923 $len = dol_strlen($s);
7924 $out = '';
7925 $ok = 1;
7926 for ($scursor = 0; $scursor < $len; $scursor++) {
7927 $ordchar = ord($s[$scursor]);
7928 //print $scursor.'-'.$ordchar.'<br>';
7929 if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) {
7930 $ok = 0;
7931 break;
7932 } elseif ($ordchar > 126 && $ordchar < 160) {
7933 $ok = 0;
7934 break;
7935 } elseif ($clean) {
7936 $out .= $s[$scursor];
7937 }
7938 }
7939 if ($clean) {
7940 return $out;
7941 }
7942 return $ok;
7943}
7944
7953function dol_nboflines($s, $maxchar = 0)
7954{
7955 if ($s == '') {
7956 return 0;
7957 }
7958 $arraystring = explode("\n", $s);
7959 $nb = count($arraystring);
7960
7961 return $nb;
7962}
7963
7964
7974function dol_nboflines_bis($text, $maxlinesize = 0, $charset = 'UTF-8')
7975{
7976 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7977 if (dol_textishtml($text)) {
7978 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7979 }
7980
7981 $text = strtr($text, $repTable);
7982 if ($charset == 'UTF-8') {
7983 $pattern = '/(<br[^>]*>)/Uu';
7984 } else {
7985 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7986 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7987 }
7988 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7989
7990 $nblines = (int) floor((count($a) + 1) / 2);
7991 // count possible auto line breaks
7992 if ($maxlinesize) {
7993 foreach ($a as $line) {
7994 if (dol_strlen($line) > $maxlinesize) {
7995 //$line_dec = html_entity_decode(strip_tags($line));
7996 $line_dec = html_entity_decode($line);
7997 if (dol_strlen($line_dec) > $maxlinesize) {
7998 $line_dec = wordwrap($line_dec, $maxlinesize, '\n', true);
7999 $nblines += substr_count($line_dec, '\n');
8000 }
8001 }
8002 }
8003 }
8004
8005 unset($a);
8006 return $nblines;
8007}
8008
8017function dol_textishtml($msg, $option = 0)
8018{
8019 if (is_null($msg)) {
8020 return false;
8021 }
8022
8023 if ($option == 1) {
8024 if (preg_match('/<html/i', $msg)) {
8025 return true;
8026 } elseif (preg_match('/<body/i', $msg)) {
8027 return true;
8028 } elseif (preg_match('/<\/textarea/i', $msg)) {
8029 return true;
8030 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8031 return true;
8032 } elseif (preg_match('/<br/i', $msg)) {
8033 return true;
8034 }
8035 return false;
8036 } else {
8037 // Remove all urls because 'http://aa?param1=abc&amp;param2=def' must not be used inside detection
8038 $msg = preg_replace('/https?:\/\/[^"\'\s]+/i', '', $msg);
8039 if (preg_match('/<html/i', $msg)) {
8040 return true;
8041 } elseif (preg_match('/<body/i', $msg)) {
8042 return true;
8043 } elseif (preg_match('/<\/textarea/i', $msg)) {
8044 return true;
8045 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8046 return true;
8047 } elseif (preg_match('/<(br|hr)\/>/i', $msg)) {
8048 return true;
8049 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)>/i', $msg)) {
8050 return true;
8051 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)\s+[^<>\/]*\/?>/i', $msg)) {
8052 return true;
8053 } elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i', $msg)) {
8054 return true; // must accept <img src="http://example.com/aaa.png" />
8055 } elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i', $msg)) {
8056 return true; // must accept <a href="http://example.com/aaa.png" />
8057 } elseif (preg_match('/<h[0-9]>/i', $msg)) {
8058 return true;
8059 } elseif (preg_match('/&[A-Z0-9]{1,6};/i', $msg)) {
8060 // TODO If content is 'A link https://aaa?param=abc&amp;param2=def', it return true but must be false
8061 return true; // Html entities names (http://www.w3schools.com/tags/ref_entities.asp)
8062 } elseif (preg_match('/&#[0-9]{2,3};/i', $msg)) {
8063 return true; // Html entities numbers (http://www.w3schools.com/tags/ref_entities.asp)
8064 }
8065
8066 return false;
8067 }
8068}
8069
8084function dol_concatdesc($text1, $text2, $forxml = false, $invert = false)
8085{
8086 if (!empty($invert)) {
8087 $tmp = $text1;
8088 $text1 = $text2;
8089 $text2 = $tmp;
8090 }
8091
8092 $ret = '';
8093 $ret .= (!dol_textishtml($text1) && dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text1, 0, 1, '', 1), 0, $forxml) : $text1;
8094 $ret .= (!empty($text1) && !empty($text2)) ? ((dol_textishtml($text1) || dol_textishtml($text2)) ? ($forxml ? "<br >\n" : "<br>\n") : "\n") : "";
8095 $ret .= (dol_textishtml($text1) && !dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text2, 0, 1, '', 1), 0, $forxml) : $text2;
8096 return $ret;
8097}
8098
8099
8100
8112function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null)
8113{
8114 global $db, $conf, $mysoc, $user, $extrafields;
8115
8116 $substitutionarray = array();
8117
8118 if ((empty($exclude) || !in_array('user', $exclude)) && (empty($include) || in_array('user', $include))) {
8119 // Add SIGNATURE into substitutionarray first, so, when we will make the substitution,
8120 // this will include signature content first and then replace var found into content of signature
8121 //var_dump($onlykey);
8122 $emailsendersignature = $user->signature; // dy default, we use the signature of current user. We must complete substitution with signature in c_email_senderprofile of array after calling getCommonSubstitutionArray()
8123 $usersignature = $user->signature;
8124 $substitutionarray = array_merge($substitutionarray, array(
8125 '__SENDEREMAIL_SIGNATURE__' => (string) ((!getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc('SignatureFromTheSelectedSenderProfile', 30) : $emailsendersignature) : ''),
8126 '__USER_SIGNATURE__' => (string) (($usersignature && !getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc(dol_string_nohtmltag($usersignature), 30) : $usersignature) : '')
8127 ));
8128
8129 if (is_object($user)) {
8130 $substitutionarray = array_merge($substitutionarray, array(
8131 '__USER_ID__' => (string) $user->id,
8132 '__USER_LOGIN__' => (string) $user->login,
8133 '__USER_EMAIL__' => (string) $user->email,
8134 '__USER_PHONE__' => (string) dol_print_phone($user->office_phone, '', 0, 0, '', " ", '', '', -1),
8135 '__USER_PHONEPRO__' => (string) dol_print_phone($user->user_mobile, '', 0, 0, '', " ", '', '', -1),
8136 '__USER_PHONEMOBILE__' => (string) dol_print_phone($user->personal_mobile, '', 0, 0, '', " ", '', '', -1),
8137 '__USER_FAX__' => (string) $user->office_fax,
8138 '__USER_LASTNAME__' => (string) $user->lastname,
8139 '__USER_FIRSTNAME__' => (string) $user->firstname,
8140 '__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
8141 '__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
8142 '__USER_JOB__' => (string) $user->job,
8143 '__USER_REMOTE_IP__' => (string) getUserRemoteIP(),
8144 '__USER_VCARD_URL__' => (string) $user->getOnlineVirtualCardUrl('', 'external')
8145 ));
8146 }
8147 }
8148 if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc) && (empty($include) || in_array('mycompany', $include))) {
8149 $substitutionarray = array_merge($substitutionarray, array(
8150 '__MYCOMPANY_NAME__' => $mysoc->name,
8151 '__MYCOMPANY_EMAIL__' => $mysoc->email,
8152 '__MYCOMPANY_PHONE__' => dol_print_phone($mysoc->phone, '', 0, 0, '', " ", '', '', -1),
8153 '__MYCOMPANY_FAX__' => dol_print_phone($mysoc->fax, '', 0, 0, '', " ", '', '', -1),
8154 '__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
8155 '__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
8156 '__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
8157 '__MYCOMPANY_PROFID4__' => $mysoc->idprof4,
8158 '__MYCOMPANY_PROFID5__' => $mysoc->idprof5,
8159 '__MYCOMPANY_PROFID6__' => $mysoc->idprof6,
8160 '__MYCOMPANY_CAPITAL__' => $mysoc->capital,
8161 '__MYCOMPANY_FULLADDRESS__' => (method_exists($mysoc, 'getFullAddress') ? $mysoc->getFullAddress(1, ', ') : ''), // $mysoc may be stdClass
8162 '__MYCOMPANY_ADDRESS__' => $mysoc->address,
8163 '__MYCOMPANY_ZIP__' => $mysoc->zip,
8164 '__MYCOMPANY_TOWN__' => $mysoc->town,
8165 '__MYCOMPANY_COUNTRY__' => $mysoc->country,
8166 '__MYCOMPANY_COUNTRY_ID__' => $mysoc->country_id,
8167 '__MYCOMPANY_COUNTRY_CODE__' => $mysoc->country_code,
8168 '__MYCOMPANY_CURRENCY_CODE__' => $conf->currency
8169 ));
8170 }
8171
8172 if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude)) && (empty($include) || in_array('object', $include))) {
8173 if ($onlykey) {
8174 $substitutionarray['__ID__'] = '__ID__';
8175 $substitutionarray['__REF__'] = '__REF__';
8176 $substitutionarray['__NEWREF__'] = '__NEWREF__';
8177 $substitutionarray['__LABEL__'] = '__LABEL__';
8178 $substitutionarray['__REF_CLIENT__'] = '__REF_CLIENT__';
8179 $substitutionarray['__REF_SUPPLIER__'] = '__REF_SUPPLIER__';
8180 $substitutionarray['__NOTE_PUBLIC__'] = '__NOTE_PUBLIC__';
8181 $substitutionarray['__NOTE_PRIVATE__'] = '__NOTE_PRIVATE__';
8182 $substitutionarray['__EXTRAFIELD_XXX__'] = '__EXTRAFIELD_XXX__';
8183
8184 if (isModEnabled("societe")) { // Most objects are concerned
8185 $substitutionarray['__THIRDPARTY_ID__'] = '__THIRDPARTY_ID__';
8186 $substitutionarray['__THIRDPARTY_NAME__'] = '__THIRDPARTY_NAME__';
8187 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = '__THIRDPARTY_NAME_ALIAS__';
8188 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = '__THIRDPARTY_CODE_CLIENT__';
8189 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = '__THIRDPARTY_CODE_FOURNISSEUR__';
8190 $substitutionarray['__THIRDPARTY_EMAIL__'] = '__THIRDPARTY_EMAIL__';
8191 $substitutionarray['__THIRDPARTY_PHONE__'] = '__THIRDPARTY_PHONE__';
8192 $substitutionarray['__THIRDPARTY_FAX__'] = '__THIRDPARTY_FAX__';
8193 $substitutionarray['__THIRDPARTY_ADDRESS__'] = '__THIRDPARTY_ADDRESS__';
8194 $substitutionarray['__THIRDPARTY_ZIP__'] = '__THIRDPARTY_ZIP__';
8195 $substitutionarray['__THIRDPARTY_TOWN__'] = '__THIRDPARTY_TOWN__';
8196 $substitutionarray['__THIRDPARTY_IDPROF1__'] = '__THIRDPARTY_IDPROF1__';
8197 $substitutionarray['__THIRDPARTY_IDPROF2__'] = '__THIRDPARTY_IDPROF2__';
8198 $substitutionarray['__THIRDPARTY_IDPROF3__'] = '__THIRDPARTY_IDPROF3__';
8199 $substitutionarray['__THIRDPARTY_IDPROF4__'] = '__THIRDPARTY_IDPROF4__';
8200 $substitutionarray['__THIRDPARTY_IDPROF5__'] = '__THIRDPARTY_IDPROF5__';
8201 $substitutionarray['__THIRDPARTY_IDPROF6__'] = '__THIRDPARTY_IDPROF6__';
8202 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = '__THIRDPARTY_TVAINTRA__';
8203 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = '__THIRDPARTY_NOTE_PUBLIC__';
8204 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = '__THIRDPARTY_NOTE_PRIVATE__';
8205 }
8206 if (isModEnabled('adherent') && (!is_object($object) || $object->element == 'adherent') && (empty($exclude) || !in_array('member', $exclude)) && (empty($include) || in_array('member', $include))) {
8207 $substitutionarray['__MEMBER_ID__'] = '__MEMBER_ID__';
8208 $substitutionarray['__MEMBER_CIVILITY__'] = '__MEMBER_CIVILITY__';
8209 $substitutionarray['__MEMBER_FIRSTNAME__'] = '__MEMBER_FIRSTNAME__';
8210 $substitutionarray['__MEMBER_LASTNAME__'] = '__MEMBER_LASTNAME__';
8211 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = 'Login and pass of the external user account';
8212 /*$substitutionarray['__MEMBER_NOTE_PUBLIC__'] = '__MEMBER_NOTE_PUBLIC__';
8213 $substitutionarray['__MEMBER_NOTE_PRIVATE__'] = '__MEMBER_NOTE_PRIVATE__';*/
8214 }
8215 // add variables subtitutions ticket
8216 if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket') && (empty($exclude) || !in_array('ticket', $exclude)) && (empty($include) || in_array('ticket', $include))) {
8217 $substitutionarray['__TICKET_TRACKID__'] = '__TICKET_TRACKID__';
8218 $substitutionarray['__TICKET_SUBJECT__'] = '__TICKET_SUBJECT__';
8219 $substitutionarray['__TICKET_TYPE__'] = '__TICKET_TYPE__';
8220 $substitutionarray['__TICKET_SEVERITY__'] = '__TICKET_SEVERITY__';
8221 $substitutionarray['__TICKET_CATEGORY__'] = '__TICKET_CATEGORY__';
8222 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = '__TICKET_ANALYTIC_CODE__';
8223 $substitutionarray['__TICKET_MESSAGE__'] = '__TICKET_MESSAGE__';
8224 $substitutionarray['__TICKET_PROGRESSION__'] = '__TICKET_PROGRESSION__';
8225 $substitutionarray['__TICKET_USER_ASSIGN__'] = '__TICKET_USER_ASSIGN__';
8226 }
8227
8228 if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature') && (empty($exclude) || !in_array('recruitment', $exclude)) && (empty($include) || in_array('recruitment', $include))) {
8229 $substitutionarray['__CANDIDATE_FULLNAME__'] = '__CANDIDATE_FULLNAME__';
8230 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = '__CANDIDATE_FIRSTNAME__';
8231 $substitutionarray['__CANDIDATE_LASTNAME__'] = '__CANDIDATE_LASTNAME__';
8232 }
8233 if (isModEnabled('project') && (empty($exclude) || !in_array('project', $exclude)) && (empty($include) || in_array('project', $include))) { // Most objects
8234 $substitutionarray['__PROJECT_ID__'] = '__PROJECT_ID__';
8235 $substitutionarray['__PROJECT_REF__'] = '__PROJECT_REF__';
8236 $substitutionarray['__PROJECT_NAME__'] = '__PROJECT_NAME__';
8237 /*$substitutionarray['__PROJECT_NOTE_PUBLIC__'] = '__PROJECT_NOTE_PUBLIC__';
8238 $substitutionarray['__PROJECT_NOTE_PRIVATE__'] = '__PROJECT_NOTE_PRIVATE__';*/
8239 }
8240 if (isModEnabled('contrat') && (!is_object($object) || $object->element == 'contract') && (empty($exclude) || !in_array('contract', $exclude)) && (empty($include) || in_array('contract', $include))) {
8241 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = 'Highest date planned for a service start';
8242 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = 'Highest date and hour planned for service start';
8243 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = 'Lowest data for planned expiration of service';
8244 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = 'Lowest date and hour for planned expiration of service';
8245 }
8246 if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal') && (empty($exclude) || !in_array('propal', $exclude)) && (empty($include) || in_array('propal', $include))) {
8247 $substitutionarray['__ONLINE_SIGN_URL__'] = 'ToOfferALinkForOnlineSignature';
8248 }
8249 if (isModEnabled("ficheinter") && (!is_object($object) || $object->element == 'fichinter') && (empty($exclude) || !in_array('intervention', $exclude)) && (empty($include) || in_array('intervention', $include))) {
8250 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = 'ToOfferALinkForOnlineSignature';
8251 }
8252 $substitutionarray['__ONLINE_PAYMENT_URL__'] = 'UrlToPayOnlineIfApplicable';
8253 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = 'TextAndUrlToPayOnlineIfApplicable';
8254 $substitutionarray['__SECUREKEYPAYMENT__'] = 'Security key (if key is not unique per record)';
8255 $substitutionarray['__SECUREKEYPAYMENT_MEMBER__'] = 'Security key for payment on a member subscription (one key per member)';
8256 $substitutionarray['__SECUREKEYPAYMENT_ORDER__'] = 'Security key for payment on an order';
8257 $substitutionarray['__SECUREKEYPAYMENT_INVOICE__'] = 'Security key for payment on an invoice';
8258 $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'Security key for payment on a service of a contract';
8259
8260 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = 'Direct download url of a proposal';
8261 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = 'Direct download url of an order';
8262 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = 'Direct download url of an invoice';
8263 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = 'Direct download url of a contract';
8264 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = 'Direct download url of a supplier proposal';
8265
8266 if (isModEnabled("expedition") && (!is_object($object) || $object->element == 'shipping')) {
8267 $substitutionarray['__SHIPPINGTRACKNUM__'] = 'Shipping tracking number';
8268 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = 'Shipping tracking url';
8269 $substitutionarray['__SHIPPINGMETHOD__'] = 'Shipping method';
8270 }
8271 if (isModEnabled("reception") && (!is_object($object) || $object->element == 'reception')) {
8272 $substitutionarray['__RECEPTIONTRACKNUM__'] = 'Shippin tracking number of shipment';
8273 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = 'Shipping tracking url';
8274 }
8275 } else {
8276 $substitutionarray['__ID__'] = $object->id;
8277 $substitutionarray['__REF__'] = $object->ref;
8278 $substitutionarray['__NEWREF__'] = $object->newref;
8279 $substitutionarray['__LABEL__'] = (isset($object->label) ? $object->label : (isset($object->title) ? $object->title : null));
8280 $substitutionarray['__REF_CLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8281 $substitutionarray['__REF_SUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8282 $substitutionarray['__NOTE_PUBLIC__'] = (isset($object->note_public) ? $object->note_public : null);
8283 $substitutionarray['__NOTE_PRIVATE__'] = (isset($object->note_private) ? $object->note_private : null);
8284 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, 'day', 0, $outputlangs) : '');
8285 $substitutionarray['__DATE_DELIVERY_DAY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%d") : '');
8286 $substitutionarray['__DATE_DELIVERY_DAY_TEXT__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%A") : '');
8287 $substitutionarray['__DATE_DELIVERY_MON__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%m") : '');
8288 $substitutionarray['__DATE_DELIVERY_MON_TEXT__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%b") : '');
8289 $substitutionarray['__DATE_DELIVERY_YEAR__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%Y") : '');
8290 $substitutionarray['__DATE_DELIVERY_HH__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%H") : '');
8291 $substitutionarray['__DATE_DELIVERY_MM__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%M") : '');
8292 $substitutionarray['__DATE_DELIVERY_SS__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%S") : '');
8293
8294 // For backward compatibility (deprecated)
8295 $substitutionarray['__REFCLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8296 $substitutionarray['__REFSUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8297 $substitutionarray['__SUPPLIER_ORDER_DATE_DELIVERY__'] = (isset($object->delivery_date) ? dol_print_date($object->delivery_date, 'day', 0, $outputlangs) : '');
8298 $substitutionarray['__SUPPLIER_ORDER_DELAY_DELIVERY__'] = (isset($object->availability_code) ? ($outputlangs->transnoentities("AvailabilityType".$object->availability_code) != 'AvailabilityType'.$object->availability_code ? $outputlangs->transnoentities("AvailabilityType".$object->availability_code) : $outputlangs->convToOutputCharset(isset($object->availability) ? $object->availability : '')) : '');
8299 $substitutionarray['__EXPIRATION_DATE__'] = (isset($object->fin_validite) ? dol_print_date($object->fin_validite, 'daytext') : '');
8300
8301 if (is_object($object) && ($object->element == 'adherent' || $object->element == 'member') && $object->id > 0) {
8302 $birthday = (empty($object->birth) ? '' : dol_print_date($object->birth, 'day'));
8303
8304 $substitutionarray['__MEMBER_ID__'] = (isset($object->id) ? $object->id : '');
8305 if (method_exists($object, 'getCivilityLabel')) {
8306 $substitutionarray['__MEMBER_CIVILITY__'] = $object->getCivilityLabel();
8307 }
8308 $substitutionarray['__MEMBER_FIRSTNAME__'] = (isset($object->firstname) ? $object->firstname : '');
8309 $substitutionarray['__MEMBER_LASTNAME__'] = (isset($object->lastname) ? $object->lastname : '');
8310 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = '';
8311 if (method_exists($object, 'getFullName')) {
8312 $substitutionarray['__MEMBER_FULLNAME__'] = $object->getFullName($outputlangs);
8313 }
8314 $substitutionarray['__MEMBER_COMPANY__'] = (isset($object->societe) ? $object->societe : '');
8315 $substitutionarray['__MEMBER_ADDRESS__'] = (isset($object->address) ? $object->address : '');
8316 $substitutionarray['__MEMBER_ZIP__'] = (isset($object->zip) ? $object->zip : '');
8317 $substitutionarray['__MEMBER_TOWN__'] = (isset($object->town) ? $object->town : '');
8318 $substitutionarray['__MEMBER_COUNTRY__'] = (isset($object->country) ? $object->country : '');
8319 $substitutionarray['__MEMBER_EMAIL__'] = (isset($object->email) ? $object->email : '');
8320 $substitutionarray['__MEMBER_BIRTH__'] = (isset($birthday) ? $birthday : '');
8321 $substitutionarray['__MEMBER_PHOTO__'] = (isset($object->photo) ? $object->photo : '');
8322 $substitutionarray['__MEMBER_LOGIN__'] = (isset($object->login) ? $object->login : '');
8323 $substitutionarray['__MEMBER_PASSWORD__'] = (isset($object->pass) ? $object->pass : '');
8324 $substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? dol_print_phone($object->phone) : '');
8325 $substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? dol_print_phone($object->phone_perso) : '');
8326 $substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? dol_print_phone($object->phone_mobile) : '');
8327 $substitutionarray['__MEMBER_TYPE__'] = (isset($object->type) ? $object->type : '');
8328 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__'] = dol_print_date($object->first_subscription_date, 'day');
8329 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = (isset($object->first_subscription_date_start) ? dol_print_date($object->first_subscription_date_start, 'day') : '');
8330 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END__'] = (isset($object->first_subscription_date_end) ? dol_print_date($object->first_subscription_date_end, 'day') : '');
8331 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE__'] = dol_print_date($object->last_subscription_date, 'day');
8332 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->last_subscription_date_start, 'day');
8333 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END__'] = dol_print_date($object->last_subscription_date_end, 'day');
8334 }
8335
8336 if (is_object($object) && $object->element == 'societe') {
8337 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object) ? $object->id : '');
8338 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object) ? $object->name : '');
8339 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object) ? $object->name_alias : '');
8340 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object) ? $object->code_client : '');
8341 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object) ? $object->code_fournisseur : '');
8342 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object) ? $object->email : '');
8343 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? dol_print_phone($object->phone) : '');
8344 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? dol_print_phone($object->fax) : '');
8345 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object) ? $object->address : '');
8346 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object) ? $object->zip : '');
8347 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object) ? $object->town : '');
8348 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object) ? $object->country_id : '');
8349 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object) ? $object->country_code : '');
8350 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object) ? $object->idprof1 : '');
8351 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object) ? $object->idprof2 : '');
8352 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object) ? $object->idprof3 : '');
8353 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object) ? $object->idprof4 : '');
8354 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object) ? $object->idprof5 : '');
8355 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object) ? $object->idprof6 : '');
8356 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object) ? $object->tva_intra : '');
8357 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_public) : '');
8358 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_private) : '');
8359 } elseif (is_object($object->thirdparty)) {
8360 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->id : '');
8361 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object->thirdparty) ? $object->thirdparty->name : '');
8362 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object->thirdparty) ? $object->thirdparty->name_alias : '');
8363 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_client : '');
8364 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_fournisseur : '');
8365 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object->thirdparty) ? $object->thirdparty->email : '');
8366 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->phone) : '');
8367 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->fax) : '');
8368 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object->thirdparty) ? $object->thirdparty->address : '');
8369 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object->thirdparty) ? $object->thirdparty->zip : '');
8370 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object->thirdparty) ? $object->thirdparty->town : '');
8371 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_id : '');
8372 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_code : '');
8373 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof1 : '');
8374 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof2 : '');
8375 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof3 : '');
8376 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof4 : '');
8377 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof5 : '');
8378 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof6 : '');
8379 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object->thirdparty) ? $object->thirdparty->tva_intra : '');
8380 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_public) : '');
8381 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_private) : '');
8382 }
8383
8384 if (is_object($object) && $object->element == 'recruitmentcandidature') {
8385 $substitutionarray['__CANDIDATE_FULLNAME__'] = $object->getFullName($outputlangs);
8386 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8387 $substitutionarray['__CANDIDATE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8388 }
8389 if (is_object($object) && $object->element == 'conferenceorboothattendee') {
8390 $substitutionarray['__ATTENDEE_FULLNAME__'] = $object->getFullName($outputlangs);
8391 $substitutionarray['__ATTENDEE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8392 $substitutionarray['__ATTENDEE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8393 }
8394
8395 if (is_object($object) && $object->element == 'project') {
8396 $substitutionarray['__PROJECT_ID__'] = $object->id;
8397 $substitutionarray['__PROJECT_REF__'] = $object->ref;
8398 $substitutionarray['__PROJECT_NAME__'] = $object->title;
8399 } elseif (is_object($object)) {
8400 $project = null;
8401 if (!empty($object->project)) {
8402 $project = $object->project;
8403 } elseif (!empty($object->projet)) { // Deprecated, for backward compatibility
8404 $project = $object->projet;
8405 }
8406 if (!is_null($project) && is_object($project)) {
8407 $substitutionarray['__PROJECT_ID__'] = $project->id;
8408 $substitutionarray['__PROJECT_REF__'] = $project->ref;
8409 $substitutionarray['__PROJECT_NAME__'] = $project->title;
8410 } else {
8411 // can substitute variables for project : uses lazy load in "make_substitutions" method
8412 $project_id = 0;
8413 if (!empty($object->fk_project) && $object->fk_project > 0) {
8414 $project_id = $object->fk_project;
8415 } elseif (!empty($object->fk_projet) && $object->fk_projet > 0) {
8416 $project_id = $object->fk_project;
8417 }
8418 if ($project_id > 0) {
8419 // path:class:method:id
8420 $substitutionarray['__PROJECT_ID__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8421 $substitutionarray['__PROJECT_REF__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8422 $substitutionarray['__PROJECT_NAME__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8423 }
8424 }
8425 }
8426
8427 if (is_object($object) && $object->element == 'shipping') {
8428 $substitutionarray['__SHIPPINGTRACKNUM__'] = $object->tracking_number;
8429 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = $object->tracking_url;
8430 $substitutionarray['__SHIPPINGMETHOD__'] = $object->shipping_method;
8431 }
8432 if (is_object($object) && $object->element == 'reception') {
8433 $substitutionarray['__RECEPTIONTRACKNUM__'] = $object->tracking_number;
8434 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = $object->tracking_url;
8435 }
8436
8437 if (is_object($object) && $object->element == 'contrat' && $object->id > 0 && is_array($object->lines)) {
8438 $dateplannedstart = '';
8439 $datenextexpiration = '';
8440 foreach ($object->lines as $line) {
8441 if ($line->date_start > $dateplannedstart) {
8442 $dateplannedstart = $line->date_start;
8443 }
8444 if ($line->statut == 4 && $line->date_end && (!$datenextexpiration || $line->date_end < $datenextexpiration)) {
8445 $datenextexpiration = $line->date_end;
8446 }
8447 }
8448 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = dol_print_date($dateplannedstart, 'day');
8449 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = dol_print_date($dateplannedstart, 'standard');
8450 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = dol_print_date($datenextexpiration, 'day');
8451 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = dol_print_date($datenextexpiration, 'standard');
8452 }
8453 // add substition variable for ticket
8454 if (is_object($object) && $object->element == 'ticket') {
8455 $substitutionarray['__TICKET_TRACKID__'] = $object->track_id;
8456 $substitutionarray['__REF__'] = $object->ref;
8457 $substitutionarray['__TICKET_SUBJECT__'] = $object->subject;
8458 $substitutionarray['__TICKET_TYPE__'] = $object->type_code;
8459 $substitutionarray['__TICKET_SEVERITY__'] = $object->severity_code;
8460 $substitutionarray['__TICKET_CATEGORY__'] = $object->category_code; // For backward compatibility
8461 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = $object->category_code;
8462 $substitutionarray['__TICKET_MESSAGE__'] = $object->message;
8463 $substitutionarray['__TICKET_PROGRESSION__'] = $object->progress;
8464 $userstat = new User($db);
8465 if ($object->fk_user_assign > 0) {
8466 $userstat->fetch($object->fk_user_assign);
8467 $substitutionarray['__TICKET_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8468 }
8469
8470 if ($object->fk_user_create > 0) {
8471 $userstat->fetch($object->fk_user_create);
8472 $substitutionarray['__USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8473 }
8474 }
8475
8476 // Create dynamic tags for __EXTRAFIELD_FIELD__
8477 if ($object->table_element && $object->id > 0) {
8478 if (!is_object($extrafields)) {
8479 $extrafields = new ExtraFields($db);
8480 }
8481 $extrafields->fetch_name_optionals_label($object->table_element, true);
8482
8483 if ($object->fetch_optionals() > 0) {
8484 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) {
8485 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
8486 if ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
8487 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_date($object->array_options['options_'.$key], 'day');
8488 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = dol_print_date($object->array_options['options_'.$key], 'day', 'tzserver', $outputlangs);
8489 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = dol_print_date($object->array_options['options_'.$key], 'dayrfc');
8490 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'datetime') {
8491 $datetime = $object->array_options['options_'.$key];
8492 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour') : '');
8493 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : '');
8494 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_DAY_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'day', 'tzserver', $outputlangs) : '');
8495 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : '');
8496 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'phone') {
8497 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_phone($object->array_options['options_'.$key]);
8498 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
8499 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = $object->array_options['options_'.$key];
8500 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATED__'] = price($object->array_options['options_'.$key]);
8501 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] != 'separator') {
8502 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = !empty($object->array_options['options_'.$key]) ? $object->array_options['options_'.$key] : '';
8503 }
8504 }
8505 }
8506 }
8507 }
8508
8509 // Complete substitution array with the url to make online payment
8510 $paymenturl = '';
8511 if (empty($substitutionarray['__REF__'])) {
8512 $paymenturl = '';
8513 } else {
8514 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
8515 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
8516 $outputlangs->loadLangs(array('paypal', 'other'));
8517
8518 $amounttouse = 0;
8519 $typeforonlinepayment = 'free';
8520 if (is_object($object) && $object->element == 'commande') {
8521 $typeforonlinepayment = 'order';
8522 }
8523 if (is_object($object) && $object->element == 'facture') {
8524 $typeforonlinepayment = 'invoice';
8525 }
8526 if (is_object($object) && $object->element == 'member') {
8527 $typeforonlinepayment = 'member';
8528 if (!empty($object->last_subscription_amount)) {
8529 $amounttouse = $object->last_subscription_amount;
8530 }
8531 }
8532 if (is_object($object) && $object->element == 'contrat') {
8533 $typeforonlinepayment = 'contract';
8534 }
8535 if (is_object($object) && $object->element == 'fichinter') {
8536 $typeforonlinepayment = 'ficheinter';
8537 }
8538
8539 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__'], $amounttouse);
8540 $paymenturl = $url;
8541 }
8542
8543 if ($object->id > 0) {
8544 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ? str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : '');
8545 $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl;
8546
8547 if (getDolGlobalString('PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'propal') {
8548 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8549 } else {
8550 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = '';
8551 }
8552 if (getDolGlobalString('ORDER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'commande') {
8553 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = $object->getLastMainDocLink($object->element);
8554 } else {
8555 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = '';
8556 }
8557 if (getDolGlobalString('INVOICE_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'facture') {
8558 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = $object->getLastMainDocLink($object->element);
8559 } else {
8560 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = '';
8561 }
8562 if (getDolGlobalString('CONTRACT_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'contrat') {
8563 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = $object->getLastMainDocLink($object->element);
8564 } else {
8565 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = '';
8566 }
8567 if (getDolGlobalString('FICHINTER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'fichinter') {
8568 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = $object->getLastMainDocLink($object->element);
8569 } else {
8570 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = '';
8571 }
8572 if (getDolGlobalString('SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'supplier_proposal') {
8573 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8574 } else {
8575 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = '';
8576 }
8577
8578 if (is_object($object) && $object->element == 'propal') {
8579 $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id;
8580 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8581 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref);
8582 }
8583 if (is_object($object) && $object->element == 'commande') {
8584 $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id;
8585 }
8586 if (is_object($object) && $object->element == 'facture') {
8587 $substitutionarray['__URL_INVOICE__'] = DOL_MAIN_URL_ROOT."/compta/facture/card.php?id=".$object->id;
8588 }
8589 if (is_object($object) && $object->element == 'contrat') {
8590 $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id;
8591 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8592 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref);
8593 }
8594 if (is_object($object) && $object->element == 'fichinter') {
8595 $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id;
8596 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8597 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref);
8598 }
8599 if (is_object($object) && $object->element == 'supplier_proposal') {
8600 $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id;
8601 }
8602 if (is_object($object) && $object->element == 'shipping') {
8603 $substitutionarray['__URL_SHIPMENT__'] = DOL_MAIN_URL_ROOT."/expedition/card.php?id=".$object->id;
8604 }
8605 }
8606
8607 if (is_object($object) && $object->element == 'action') {
8608 $substitutionarray['__EVENT_LABEL__'] = $object->label;
8609 $substitutionarray['__EVENT_TYPE__'] = $outputlangs->trans("Action".$object->type_code);
8610 $substitutionarray['__EVENT_DATE__'] = dol_print_date($object->datep, 'day', 'auto', $outputlangs);
8611 $substitutionarray['__EVENT_TIME__'] = dol_print_date($object->datep, 'hour', 'auto', $outputlangs);
8612 }
8613 }
8614 }
8615 if ((empty($exclude) || !in_array('objectamount', $exclude)) && (empty($include) || in_array('objectamount', $include))) {
8616 include_once DOL_DOCUMENT_ROOT.'/core/lib/functionsnumtoword.lib.php';
8617
8618 $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : '';
8619 $substitutionarray['__DATE_DUE_YMD__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs) : null) : '';
8620
8621 $already_payed_all = 0;
8622 if (is_object($object) && ($object instanceof Facture)) {
8623 $already_payed_all = $object->sumpayed + $object->sumdeposit + $object->sumcreditnote;
8624 }
8625
8626 $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : '';
8627
8628 $substitutionarray['__AMOUNT__'] = is_object($object) ? $object->total_ttc : '';
8629 $substitutionarray['__AMOUNT_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, '', true) : '';
8630 $substitutionarray['__AMOUNT_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, $conf->currency, true) : '';
8631
8632 $substitutionarray['__AMOUNT_REMAIN__'] = is_object($object) ? price2num($object->total_ttc - $already_payed_all, 'MT') : '';
8633
8634 $substitutionarray['__AMOUNT_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8635 $substitutionarray['__AMOUNT_VAT_TEXT__'] = is_object($object) ? (isset($object->total_vat) ? dol_convertToWord($object->total_vat, $outputlangs, '', true) : dol_convertToWord($object->total_tva, $outputlangs, '', true)) : '';
8636 $substitutionarray['__AMOUNT_VAT_TEXTCURRENCY__'] = is_object($object) ? (isset($object->total_vat) ? dol_convertToWord($object->total_vat, $outputlangs, $conf->currency, true) : dol_convertToWord($object->total_tva, $outputlangs, $conf->currency, true)) : '';
8637
8638 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8639 $substitutionarray['__AMOUNT_TAX2__'] = is_object($object) ? $object->total_localtax1 : '';
8640 }
8641 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8642 $substitutionarray['__AMOUNT_TAX3__'] = is_object($object) ? $object->total_localtax2 : '';
8643 }
8644
8645 // Amount keys formated in a currency
8646 $substitutionarray['__AMOUNT_EXCL_TAX_FORMATED__'] = is_object($object) ? ($object->total_ht ? price($object->total_ht, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8647 $substitutionarray['__AMOUNT_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8648 $substitutionarray['__AMOUNT_REMAIN_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc - $already_payed_all, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8649 $substitutionarray['__AMOUNT_VAT_FORMATED__'] = is_object($object) ? (isset($object->total_vat) ? price($object->total_vat, 0, $outputlangs, 0, -1, -1, $conf->currency) : ($object->total_tva ? price($object->total_tva, 0, $outputlangs, 0, -1, -1, $conf->currency) : null)) : '';
8650 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8651 $substitutionarray['__AMOUNT_TAX2_FORMATED__'] = is_object($object) ? ($object->total_localtax1 ? price($object->total_localtax1, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8652 }
8653 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8654 $substitutionarray['__AMOUNT_TAX3_FORMATED__'] = is_object($object) ? ($object->total_localtax2 ? price($object->total_localtax2, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8655 }
8656
8657 $substitutionarray['__AMOUNT_MULTICURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? $object->multicurrency_total_ttc : '';
8658 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXT__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, '', true) : '';
8659 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXTCURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, $object->multicurrency_code, true) : '';
8660 // TODO Add other keys for foreign multicurrency
8661
8662 // For backward compatibility
8663 if ($onlykey != 2) {
8664 $substitutionarray['__TOTAL_TTC__'] = is_object($object) ? $object->total_ttc : '';
8665 $substitutionarray['__TOTAL_HT__'] = is_object($object) ? $object->total_ht : '';
8666 $substitutionarray['__TOTAL_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8667 }
8668 }
8669
8670 //var_dump($substitutionarray['__AMOUNT_FORMATED__']);
8671 if ((empty($exclude) || !in_array('date', $exclude)) && (empty($include) || in_array('date', $include))) {
8672 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
8673
8674 $now = dol_now();
8675
8676 $tmp = dol_getdate($now, true);
8677 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8678 $tmp3 = dol_get_prev_month($tmp['mon'], $tmp['year']);
8679 $tmp4 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8680 $tmp5 = dol_get_next_month($tmp['mon'], $tmp['year']);
8681
8682 $daytext = $outputlangs->trans('Day'.$tmp['wday']);
8683
8684 $substitutionarray = array_merge($substitutionarray, array(
8685 '__NOW_TMS__' => (string) $now, // Must be the string that represent the int
8686 '__NOW_TMS_YMD__' => dol_print_date($now, 'day', 'auto', $outputlangs),
8687 '__DAY__' => (string) $tmp['mday'],
8688 '__DAY_TEXT__' => $daytext, // Monday
8689 '__DAY_TEXT_SHORT__' => dol_trunc($daytext, 3, 'right', 'UTF-8', 1), // Mon
8690 '__DAY_TEXT_MIN__' => dol_trunc($daytext, 1, 'right', 'UTF-8', 1), // M
8691 '__MONTH__' => (string) $tmp['mon'],
8692 '__MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp['mon'])),
8693 '__MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp['mon'])),
8694 '__MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp['mon'])),
8695 '__YEAR__' => (string) $tmp['year'],
8696 '__PREVIOUS_DAY__' => (string) $tmp2['day'],
8697 '__PREVIOUS_MONTH__' => (string) $tmp3['month'],
8698 '__PREVIOUS_YEAR__' => (string) ($tmp['year'] - 1),
8699 '__NEXT_DAY__' => (string) $tmp4['day'],
8700 '__NEXT_MONTH__' => (string) $tmp5['month'],
8701 '__NEXT_MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp5['month'])),
8702 '__NEXT_MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp5['month'])),
8703 '__NEXT_MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp5['month'])),
8704 '__NEXT_YEAR__' => (string) ($tmp['year'] + 1),
8705 ));
8706 }
8707
8708 if (isModEnabled('multicompany')) {
8709 $substitutionarray = array_merge($substitutionarray, array('__ENTITY_ID__' => $conf->entity));
8710 }
8711 if ((empty($exclude) || !in_array('system', $exclude)) && (empty($include) || in_array('user', $include))) {
8712 $substitutionarray['__DOL_MAIN_URL_ROOT__'] = DOL_MAIN_URL_ROOT;
8713 $substitutionarray['__(AnyTranslationKey)__'] = $outputlangs->trans('TranslationOfKey');
8714 $substitutionarray['__(AnyTranslationKey|langfile)__'] = $outputlangs->trans('TranslationOfKey').' (load also language file before)';
8715 $substitutionarray['__[AnyConstantKey]__'] = $outputlangs->trans('ValueOfConstantKey');
8716 }
8717
8718 // Note: The lazyload variables are replaced only during the call by make_substitutions, and only if necessary
8719
8720 return $substitutionarray;
8721}
8722
8739function make_substitutions($text, $substitutionarray, $outputlangs = null, $converttextinhtmlifnecessary = 0)
8740{
8741 global $conf, $db, $langs;
8742
8743 if (!is_array($substitutionarray)) {
8744 return 'ErrorBadParameterSubstitutionArrayWhenCalling_make_substitutions';
8745 }
8746
8747 if (empty($outputlangs)) {
8748 $outputlangs = $langs;
8749 }
8750
8751 // Is initial text HTML or simple text ?
8752 $msgishtml = 0;
8753 if (dol_textishtml($text, 1)) {
8754 $msgishtml = 1;
8755 }
8756
8757 // Make substitution for language keys: __(AnyTranslationKey)__ or __(AnyTranslationKey|langfile)__
8758 if (is_object($outputlangs)) {
8759 $reg = array();
8760 while (preg_match('/__\‍(([^\‍)]+)\‍)__/', $text, $reg)) {
8761 // If key is __(TranslationKey|langfile)__, then force load of langfile.lang
8762 $tmp = explode('|', $reg[1]);
8763 if (!empty($tmp[1])) {
8764 $outputlangs->load($tmp[1]);
8765 }
8766
8767 $value = $outputlangs->transnoentitiesnoconv($reg[1]);
8768
8769 if (empty($converttextinhtmlifnecessary)) {
8770 // convert $newval into HTML is necessary
8771 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8772 } else {
8773 if (! $msgishtml) {
8774 $valueishtml = dol_textishtml($value, 1);
8775 //var_dump("valueishtml=".$valueishtml);
8776
8777 if ($valueishtml) {
8778 $text = dol_htmlentitiesbr($text);
8779 $msgishtml = 1;
8780 }
8781 } else {
8782 $value = dol_nl2br("$value");
8783 }
8784
8785 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $value, $text);
8786 }
8787 }
8788 }
8789
8790 // Make substitution for constant keys.
8791 // Must be after the substitution of translation, so if the text of translation contains a string __[xxx]__, it is also converted.
8792 $reg = array();
8793 while (preg_match('/__\[([^\]]+)\]__/', $text, $reg)) {
8794 $keyfound = $reg[1];
8795 if (isASecretKey($keyfound)) {
8796 $value = '*****forbidden*****';
8797 } else {
8798 $value = empty($conf->global->$keyfound) ? '' : $conf->global->$keyfound;
8799 }
8800
8801 if (empty($converttextinhtmlifnecessary)) {
8802 // convert $newval into HTML is necessary
8803 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8804 } else {
8805 if (! $msgishtml) {
8806 $valueishtml = dol_textishtml($value, 1);
8807
8808 if ($valueishtml) {
8809 $text = dol_htmlentitiesbr($text);
8810 $msgishtml = 1;
8811 }
8812 } else {
8813 $value = dol_nl2br("$value");
8814 }
8815
8816 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $value, $text);
8817 }
8818 }
8819
8820 // Make substitution for array $substitutionarray
8821 foreach ($substitutionarray as $key => $value) {
8822 if (!isset($value)) {
8823 continue; // If value is null, it same than not having substitution key at all into array, we do not replace.
8824 }
8825
8826 if (($key == '__USER_SIGNATURE__' || $key == '__SENDEREMAIL_SIGNATURE__') && (getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN'))) {
8827 $value = ''; // Protection
8828 }
8829
8830 if (empty($converttextinhtmlifnecessary)) {
8831 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8832 } else {
8833 if (! $msgishtml) {
8834 $valueishtml = dol_textishtml($value, 1);
8835
8836 if ($valueishtml) {
8837 $text = dol_htmlentitiesbr($text);
8838 $msgishtml = 1;
8839 }
8840 } else {
8841 $value = dol_nl2br("$value");
8842 }
8843 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8844 }
8845 }
8846
8847 // TODO Implement the lazyload substitution
8848 /*
8849 add a loop to scan $substitutionarray:
8850 For each key ending with '@lazyload', we extract the substitution key 'XXX' and we check inside the $text (the 1st parameter of make_substitutions), if the string XXX exists.
8851 If no, we don't need to make replacement, so we do nothing.
8852 If yes, we can make the substitution:
8853
8854 include_once $path;
8855 $tmpobj = new $class($db);
8856 $valuetouseforsubstitution = $tmpobj->$method($id, '__XXX__');
8857 And make the replacement of "__XXX__@lazyload" with $valuetouseforsubstitution
8858 */
8859 $memory_object_list = array();
8860 foreach ($substitutionarray as $key => $value) {
8861 $lazy_load_arr = array();
8862 if (preg_match('/(__[A-Z\_]+__)@lazyload$/', $key, $lazy_load_arr)) {
8863 if (isset($lazy_load_arr[1]) && !empty($lazy_load_arr[1])) {
8864 $key_to_substitute = $lazy_load_arr[1];
8865 if (preg_match('/' . preg_quote($key_to_substitute, '/') . '/', $text)) {
8866 $param_arr = explode(':', $value);
8867 // path:class:method:id
8868 if (count($param_arr) == 4) {
8869 $path = $param_arr[0];
8870 $class = $param_arr[1];
8871 $method = $param_arr[2];
8872 $id = (int) $param_arr[3];
8873
8874 // load class file and init object list in memory
8875 if (!isset($memory_object_list[$class])) {
8876 if (dol_is_file(DOL_DOCUMENT_ROOT . $path)) {
8877 require_once DOL_DOCUMENT_ROOT . $path;
8878 if (class_exists($class)) {
8879 $memory_object_list[$class] = array(
8880 'list' => array(),
8881 );
8882 }
8883 }
8884 }
8885
8886 // fetch object and set substitution
8887 if (isset($memory_object_list[$class]) && isset($memory_object_list[$class]['list'])) {
8888 if (method_exists($class, $method)) {
8889 if (!isset($memory_object_list[$class]['list'][$id])) {
8890 $tmpobj = new $class($db);
8891 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute);
8892 $memory_object_list[$class]['list'][$id] = $tmpobj;
8893 } else {
8894 $tmpobj = $memory_object_list[$class]['list'][$id];
8895 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute, true);
8896 }
8897
8898 $text = str_replace("$key_to_substitute", "$valuetouseforsubstitution", $text); // We must keep the " to work when value is 123.5 for example
8899 }
8900 }
8901 }
8902 }
8903 }
8904 }
8905 }
8906
8907 return $text;
8908}
8909
8922function complete_substitutions_array(&$substitutionarray, $outputlangs, $object = null, $parameters = null, $callfunc = "completesubstitutionarray")
8923{
8924 global $conf, $user;
8925
8926 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
8927
8928 // Note: substitution key for each extrafields, using key __EXTRA_XXX__ is already available into the getCommonSubstitutionArray used to build the substitution array.
8929
8930 // Check if there is external substitution to do, requested by plugins
8931 $dirsubstitutions = array_merge(array(), (array) $conf->modules_parts['substitutions']);
8932
8933 foreach ($dirsubstitutions as $reldir) {
8934 $dir = dol_buildpath($reldir, 0);
8935
8936 // Check if directory exists
8937 if (!dol_is_dir($dir)) {
8938 continue;
8939 }
8940
8941 $substitfiles = dol_dir_list($dir, 'files', 0, 'functions_');
8942 foreach ($substitfiles as $substitfile) {
8943 $reg = array();
8944 if (preg_match('/functions_(.*)\.lib\.php/i', $substitfile['name'], $reg)) {
8945 $module = $reg[1];
8946
8947 dol_syslog("Library ".$substitfile['name']." found into ".$dir);
8948 // Include the user's functions file
8949 require_once $dir.$substitfile['name'];
8950 // Call the user's function, and only if it is defined
8951 $function_name = $module."_".$callfunc;
8952 if (function_exists($function_name)) {
8953 $function_name($substitutionarray, $outputlangs, $object, $parameters);
8954 }
8955 }
8956 }
8957 }
8958 if (getDolGlobalString('ODT_ENABLE_ALL_TAGS_IN_SUBSTITUTIONS')) {
8959 // to list all tags in odt template
8960 $tags = '';
8961 foreach ($substitutionarray as $key => $value) {
8962 $tags .= '{'.$key.'} => '.$value."\n";
8963 }
8964 $substitutionarray = array_merge($substitutionarray, array('__ALL_TAGS__' => $tags));
8965 }
8966}
8967
8977function print_date_range($date_start, $date_end, $format = '', $outputlangs = '')
8978{
8979 print get_date_range($date_start, $date_end, $format, $outputlangs);
8980}
8981
8992function get_date_range($date_start, $date_end, $format = '', $outputlangs = '', $withparenthesis = 1)
8993{
8994 global $langs;
8995
8996 $out = '';
8997
8998 if (!is_object($outputlangs)) {
8999 $outputlangs = $langs;
9000 }
9001
9002 if ($date_start && $date_end) {
9003 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFromTo', dol_print_date($date_start, $format, false, $outputlangs), dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9004 }
9005 if ($date_start && !$date_end) {
9006 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($date_start, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9007 }
9008 if (!$date_start && $date_end) {
9009 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9010 }
9011
9012 return $out;
9013}
9014
9023function dolGetFirstLastname($firstname, $lastname, $nameorder = -1)
9024{
9025 global $conf;
9026
9027 $ret = '';
9028 // If order not defined, we use the setup
9029 if ($nameorder < 0) {
9030 $nameorder = (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION') ? 1 : 0);
9031 }
9032 if ($nameorder == 1) {
9033 $ret .= $firstname;
9034 if ($firstname && $lastname) {
9035 $ret .= ' ';
9036 }
9037 $ret .= $lastname;
9038 } elseif ($nameorder == 2 || $nameorder == 3) {
9039 $ret .= $firstname;
9040 if (empty($ret) && $nameorder == 3) {
9041 $ret .= $lastname;
9042 }
9043 } else { // 0, 4 or 5
9044 $ret .= $lastname;
9045 if (empty($ret) && $nameorder == 5) {
9046 $ret .= $firstname;
9047 }
9048 if ($nameorder == 0) {
9049 if ($firstname && $lastname) {
9050 $ret .= ' ';
9051 }
9052 $ret .= $firstname;
9053 }
9054 }
9055 return $ret;
9056}
9057
9058
9070function setEventMessage($mesgs, $style = 'mesgs', $noduplicate = 0)
9071{
9072 //dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING); This is not deprecated, it is used by setEventMessages function
9073 if (!is_array($mesgs)) {
9074 $mesgs = trim((string) $mesgs);
9075 // If mesgs is a not an empty string
9076 if ($mesgs) {
9077 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesgs, $_SESSION['dol_events'][$style])) {
9078 return;
9079 }
9080 $_SESSION['dol_events'][$style][] = $mesgs;
9081 }
9082 } else {
9083 // If mesgs is an array
9084 foreach ($mesgs as $mesg) {
9085 $mesg = trim((string) $mesg);
9086 if ($mesg) {
9087 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesg, $_SESSION['dol_events'][$style])) {
9088 return;
9089 }
9090 $_SESSION['dol_events'][$style][] = $mesg;
9091 }
9092 }
9093 }
9094}
9095
9108function setEventMessages($mesg, $mesgs, $style = 'mesgs', $messagekey = '', $noduplicate = 0)
9109{
9110 if (empty($mesg) && empty($mesgs)) {
9111 dol_syslog("Try to add a message in stack, but value to add is empty message", LOG_WARNING);
9112 } else {
9113 if ($messagekey) {
9114 // Complete message with a js link to set a cookie "DOLHIDEMESSAGE".$messagekey;
9115 // TODO
9116 $mesg .= '';
9117 }
9118 if (empty($messagekey) || empty($_COOKIE["DOLHIDEMESSAGE".$messagekey])) {
9119 if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
9120 dol_print_error('', 'Bad parameter style='.$style.' for setEventMessages');
9121 }
9122 if (empty($mesgs)) {
9123 setEventMessage($mesg, $style, $noduplicate);
9124 } else {
9125 if (!empty($mesg) && !in_array($mesg, $mesgs)) {
9126 setEventMessage($mesg, $style, $noduplicate); // Add message string if not already into array
9127 }
9128 setEventMessage($mesgs, $style, $noduplicate);
9129 }
9130 }
9131 }
9132}
9133
9143function dol_htmloutput_events($disabledoutputofmessages = 0)
9144{
9145 // Show mesgs
9146 if (isset($_SESSION['dol_events']['mesgs'])) {
9147 if (empty($disabledoutputofmessages)) {
9148 dol_htmloutput_mesg('', $_SESSION['dol_events']['mesgs']);
9149 }
9150 unset($_SESSION['dol_events']['mesgs']);
9151 }
9152 // Show errors
9153 if (isset($_SESSION['dol_events']['errors'])) {
9154 if (empty($disabledoutputofmessages)) {
9155 dol_htmloutput_mesg('', $_SESSION['dol_events']['errors'], 'error');
9156 }
9157 unset($_SESSION['dol_events']['errors']);
9158 }
9159
9160 // Show warnings
9161 if (isset($_SESSION['dol_events']['warnings'])) {
9162 if (empty($disabledoutputofmessages)) {
9163 dol_htmloutput_mesg('', $_SESSION['dol_events']['warnings'], 'warning');
9164 }
9165 unset($_SESSION['dol_events']['warnings']);
9166 }
9167}
9168
9183function get_htmloutput_mesg($mesgstring = '', $mesgarray = '', $style = 'ok', $keepembedded = 0)
9184{
9185 global $conf, $langs;
9186
9187 $ret = 0;
9188 $return = '';
9189 $out = '';
9190 $divstart = $divend = '';
9191
9192 // If inline message with no format, we add it.
9193 if ((empty($conf->use_javascript_ajax) || getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') || $keepembedded) && !preg_match('/<div class=".*">/i', $out)) {
9194 $divstart = '<div class="'.$style.' clearboth">';
9195 $divend = '</div>';
9196 }
9197
9198 if ((is_array($mesgarray) && count($mesgarray)) || $mesgstring) {
9199 $langs->load("errors");
9200 $out .= $divstart;
9201 if (is_array($mesgarray) && count($mesgarray)) {
9202 foreach ($mesgarray as $message) {
9203 $ret++;
9204 $out .= $langs->trans($message);
9205 if ($ret < count($mesgarray)) {
9206 $out .= "<br>\n";
9207 }
9208 }
9209 }
9210 if ($mesgstring) {
9211 $ret++;
9212 $out .= $langs->trans($mesgstring);
9213 }
9214 $out .= $divend;
9215 }
9216
9217 if ($out) {
9218 if (!empty($conf->use_javascript_ajax) && !getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') && empty($keepembedded)) {
9219 $return = '<script nonce="'.getNonce().'">
9220 $(document).ready(function() {
9221 var block = '.(getDolGlobalString('MAIN_USE_JQUERY_BLOCKUI') ? "true" : "false").'
9222 if (block) {
9223 $.dolEventValid("","'.dol_escape_js($out).'");
9224 } else {
9225 /* jnotify(message, preset of message type, keepmessage) */
9226 $.jnotify("'.dol_escape_js($out).'",
9227 "'.($style == "ok" ? 3000 : $style).'",
9228 '.($style == "ok" ? "false" : "true").',
9229 { remove: function (){} } );
9230 }
9231 });
9232 </script>';
9233 } else {
9234 $return = $out;
9235 }
9236 }
9237
9238 return $return;
9239}
9240
9252function get_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9253{
9254 return get_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9255}
9256
9270function dol_htmloutput_mesg($mesgstring = '', $mesgarray = array(), $style = 'ok', $keepembedded = 0)
9271{
9272 if (empty($mesgstring) && (!is_array($mesgarray) || count($mesgarray) == 0)) {
9273 return;
9274 }
9275
9276 $iserror = 0;
9277 $iswarning = 0;
9278 if (is_array($mesgarray)) {
9279 foreach ($mesgarray as $val) {
9280 if ($val && preg_match('/class="error"/i', $val)) {
9281 $iserror++;
9282 break;
9283 }
9284 if ($val && preg_match('/class="warning"/i', $val)) {
9285 $iswarning++;
9286 break;
9287 }
9288 }
9289 } elseif ($mesgstring && preg_match('/class="error"/i', $mesgstring)) {
9290 $iserror++;
9291 } elseif ($mesgstring && preg_match('/class="warning"/i', $mesgstring)) {
9292 $iswarning++;
9293 }
9294 if ($style == 'error') {
9295 $iserror++;
9296 }
9297 if ($style == 'warning') {
9298 $iswarning++;
9299 }
9300
9301 if ($iserror || $iswarning) {
9302 // Remove div from texts
9303 $mesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $mesgstring);
9304 $mesgstring = preg_replace('/<div class="(error|warning)">/', '', $mesgstring);
9305 $mesgstring = preg_replace('/<\/div>/', '', $mesgstring);
9306 // Remove div from texts array
9307 if (is_array($mesgarray)) {
9308 $newmesgarray = array();
9309 foreach ($mesgarray as $val) {
9310 if (is_string($val)) {
9311 $tmpmesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $val);
9312 $tmpmesgstring = preg_replace('/<div class="(error|warning)">/', '', $tmpmesgstring);
9313 $tmpmesgstring = preg_replace('/<\/div>/', '', $tmpmesgstring);
9314 $newmesgarray[] = $tmpmesgstring;
9315 } else {
9316 dol_syslog("Error call of dol_htmloutput_mesg with an array with a value that is not a string", LOG_WARNING);
9317 }
9318 }
9319 $mesgarray = $newmesgarray;
9320 }
9321 print get_htmloutput_mesg($mesgstring, $mesgarray, ($iserror ? 'error' : 'warning'), $keepembedded);
9322 } else {
9323 print get_htmloutput_mesg($mesgstring, $mesgarray, 'ok', $keepembedded);
9324 }
9325}
9326
9338function dol_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9339{
9340 dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9341}
9342
9357function dol_sort_array(&$array, $index, $order = 'asc', $natsort = 0, $case_sensitive = 0, $keepindex = 0)
9358{
9359 // Clean parameters
9360 $order = strtolower($order);
9361
9362 if (is_array($array)) {
9363 $sizearray = count($array);
9364 if ($sizearray > 0) {
9365 $temp = array();
9366 foreach (array_keys($array) as $key) {
9367 if (is_object($array[$key])) {
9368 $temp[$key] = empty($array[$key]->$index) ? 0 : $array[$key]->$index;
9369 } else {
9370 $temp[$key] = empty($array[$key][$index]) ? 0 : $array[$key][$index];
9371 }
9372 if ($natsort == -1) {
9373 $temp[$key] = '___'.$temp[$key]; // We add a string at begin of value to force an alpha order when using asort.
9374 }
9375 }
9376
9377 if (empty($natsort) || $natsort == -1) {
9378 if ($order == 'asc') {
9379 asort($temp);
9380 } else {
9381 arsort($temp);
9382 }
9383 } else {
9384 if ($case_sensitive) {
9385 natsort($temp);
9386 } else {
9387 natcasesort($temp); // natecasesort is not sensible to case
9388 }
9389 if ($order != 'asc') {
9390 $temp = array_reverse($temp, true);
9391 }
9392 }
9393
9394 $sorted = array();
9395
9396 foreach (array_keys($temp) as $key) {
9397 (is_numeric($key) && empty($keepindex)) ? $sorted[] = $array[$key] : $sorted[$key] = $array[$key];
9398 }
9399
9400 return $sorted;
9401 }
9402 }
9403 return $array;
9404}
9405
9406
9414function utf8_check($str)
9415{
9416 $str = (string) $str; // Sometimes string is an int.
9417
9418 // We must use here a binary strlen function (so not dol_strlen)
9419 $strLength = strlen($str);
9420 for ($i = 0; $i < $strLength; $i++) {
9421 if (ord($str[$i]) < 0x80) {
9422 continue; // 0bbbbbbb
9423 } elseif ((ord($str[$i]) & 0xE0) == 0xC0) {
9424 $n = 1; // 110bbbbb
9425 } elseif ((ord($str[$i]) & 0xF0) == 0xE0) {
9426 $n = 2; // 1110bbbb
9427 } elseif ((ord($str[$i]) & 0xF8) == 0xF0) {
9428 $n = 3; // 11110bbb
9429 } elseif ((ord($str[$i]) & 0xFC) == 0xF8) {
9430 $n = 4; // 111110bb
9431 } elseif ((ord($str[$i]) & 0xFE) == 0xFC) {
9432 $n = 5; // 1111110b
9433 } else {
9434 return false; // Does not match any model
9435 }
9436 for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
9437 if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80)) {
9438 return false;
9439 }
9440 }
9441 }
9442 return true;
9443}
9444
9452function utf8_valid($str)
9453{
9454 /* 2 other methods to test if string is utf8
9455 $validUTF8 = mb_check_encoding($messagetext, 'UTF-8');
9456 $validUTF8b = ! (false === mb_detect_encoding($messagetext, 'UTF-8', true));
9457 */
9458 return preg_match('//u', $str) ? true : false;
9459}
9460
9461
9468function ascii_check($str)
9469{
9470 if (function_exists('mb_check_encoding')) {
9471 //if (mb_detect_encoding($str, 'ASCII', true) return false;
9472 if (!mb_check_encoding($str, 'ASCII')) {
9473 return false;
9474 }
9475 } else {
9476 if (preg_match('/[^\x00-\x7f]/', $str)) {
9477 return false; // Contains a byte > 7f
9478 }
9479 }
9480
9481 return true;
9482}
9483
9484
9492function dol_osencode($str)
9493{
9494 global $conf;
9495
9496 $tmp = ini_get("unicode.filesystem_encoding"); // Disponible avec PHP 6.0
9497 if (empty($tmp) && !empty($_SERVER["WINDIR"])) {
9498 $tmp = 'iso-8859-1'; // By default for windows
9499 }
9500 if (empty($tmp)) {
9501 $tmp = 'utf-8'; // By default for other
9502 }
9503 if (getDolGlobalString('MAIN_FILESYSTEM_ENCODING')) {
9504 $tmp = $conf->global->MAIN_FILESYSTEM_ENCODING;
9505 }
9506
9507 if ($tmp == 'iso-8859-1') {
9508 return mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8');
9509 }
9510 return $str;
9511}
9512
9513
9528function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '')
9529{
9530 global $cache_codes;
9531
9532 // If key empty
9533 if ($key == '') {
9534 return '';
9535 }
9536
9537 // Check in cache
9538 if (isset($cache_codes[$tablename][$key][$fieldid])) { // Can be defined to 0 or ''
9539 return $cache_codes[$tablename][$key][$fieldid]; // Found in cache
9540 }
9541
9542 dol_syslog('dol_getIdFromCode (value for field '.$fieldid.' from key '.$key.' not found into cache)', LOG_DEBUG);
9543
9544 $sql = "SELECT ".$fieldid." as valuetoget";
9545 $sql .= " FROM ".MAIN_DB_PREFIX.$tablename;
9546 $sql .= " WHERE ".$fieldkey." = '".$db->escape($key)."'";
9547 if (!empty($entityfilter)) {
9548 $sql .= " AND entity IN (".getEntity($tablename).")";
9549 }
9550 if ($filters) {
9551 $sql .= $filters;
9552 }
9553
9554 $resql = $db->query($sql);
9555 if ($resql) {
9556 $obj = $db->fetch_object($resql);
9557 if ($obj) {
9558 $cache_codes[$tablename][$key][$fieldid] = $obj->valuetoget;
9559 } else {
9560 $cache_codes[$tablename][$key][$fieldid] = '';
9561 }
9562 $db->free($resql);
9563 return $cache_codes[$tablename][$key][$fieldid];
9564 } else {
9565 return -1;
9566 }
9567}
9568
9578function isStringVarMatching($var, $regextext, $matchrule = 1)
9579{
9580 if ($matchrule == 1) {
9581 if ($var == 'mainmenu') {
9582 global $mainmenu;
9583 return (preg_match('/^'.$regextext.'/', $mainmenu));
9584 } elseif ($var == 'leftmenu') {
9585 global $leftmenu;
9586 return (preg_match('/^'.$regextext.'/', $leftmenu));
9587 } else {
9588 return 'This variable is not accessible with dol_eval';
9589 }
9590 } else {
9591 return 'This value for matchrule is not implemented';
9592 }
9593}
9594
9595
9602function verifCond($strToEvaluate)
9603{
9604 //print $strToEvaluate."<br>\n";
9605 $rights = true;
9606 if (isset($strToEvaluate) && $strToEvaluate !== '') {
9607 //var_dump($strToEvaluate);
9608 //$rep = dol_eval($strToEvaluate, 1, 0, '1'); // to show the error
9609 $rep = dol_eval($strToEvaluate, 1, 1, '1'); // The dol_eval() must contains all the "global $xxx;" for all variables $xxx found into the string condition
9610 $rights = $rep && (!is_string($rep) || strpos($rep, 'Bad string syntax to evaluate') === false);
9611 //var_dump($rights);
9612 }
9613 return $rights;
9614}
9615
9629function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1')
9630{
9631 // Only this global variables can be read by eval function and returned to caller
9632 global $conf; // Read of const is done with getDolGlobalString() but we need $conf->currency for example
9633 global $db, $langs, $user, $website, $websitepage;
9634 global $action, $mainmenu, $leftmenu;
9635 global $mysoc;
9636 global $objectoffield; // To allow the use of $objectoffield in computed fields
9637
9638 // Old variables used
9639 global $object;
9640 global $obj; // To get $obj used into list when dol_eval() is used for computed fields and $obj is not yet $object
9641
9642 if (!in_array($onlysimplestring, array('0', '1', '2'))) {
9643 return "Bad call of dol_eval. Parameter onlysimplestring must be '0' (deprecated), '1' or '2'";
9644 }
9645
9646 try {
9647 // Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing
9648 if ($onlysimplestring == '1') {
9649 // We must accept: '1 && getDolGlobalInt("doesnotexist1") && getDolGlobalString("MAIN_FEATURES_LEVEL")'
9650 // We must accept: '$user->hasRight("cabinetmed", "read") && !$object->canvas=="patient@cabinetmed"'
9651 $specialcharsallowed = '^$_+-.*>&|=!?():"\',/@';
9652 if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
9653 $specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
9654 }
9655 if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
9656 if ($returnvalue) {
9657 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9658 } else {
9659 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9660 return '';
9661 }
9662 }
9663 $savescheck = '';
9664 $scheck = $s;
9665 while ($scheck && $savescheck != $scheck) {
9666 $savescheck = $scheck;
9667 $scheck = preg_replace('/->[a-zA-Z0-9_]+\‍(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
9668 $scheck = preg_replace('/^\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9669 $scheck = preg_replace('/\s\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9670 $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
9671 $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
9672 $scheck = preg_replace('/(\^|\')\‍(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
9673 }
9674 //print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
9675 if (strpos($scheck, '(') !== false) {
9676 if ($returnvalue) {
9677 return 'Bad string syntax to evaluate (mode 1, found call of a function or method without using the direct name of the function): '.$s;
9678 } else {
9679 dol_syslog('Bad string syntax to evaluate (mode 1, found call of a function or method without using the direct name of the function): '.$s);
9680 return '';
9681 }
9682 }
9683 // TODO
9684 // We can exclude $ char that are not: $db, $langs, $leftmenu, $topmenu, $user, $langs, $objectoffield, $object...,
9685 } elseif ($onlysimplestring == '2') {
9686 // We must accept: (($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : "Parent project not found"
9687 $specialcharsallowed = '^$_+-.*>&|=!?():"\',/@[]';
9688 if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
9689 $specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
9690 }
9691 if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
9692 if ($returnvalue) {
9693 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9694 } else {
9695 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9696 return '';
9697 }
9698 }
9699 $savescheck = '';
9700 $scheck = $s;
9701 while ($scheck && $savescheck != $scheck) {
9702 $savescheck = $scheck;
9703 $scheck = preg_replace('/->[a-zA-Z0-9_]+\‍(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
9704 $scheck = preg_replace('/^\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9705 $scheck = preg_replace('/\s\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9706 $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
9707 $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
9708 $scheck = preg_replace('/(\^|\')\‍(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
9709 }
9710 //print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
9711 if (strpos($scheck, '(') !== false) {
9712 if ($returnvalue) {
9713 return 'Bad string syntax to evaluate (mode 2, found call of a function or method without using the direct name of the function): '.$s;
9714 } else {
9715 dol_syslog('Bad string syntax to evaluate (mode 2, found call of a function or method without using the direct name of the function): '.$s);
9716 return '';
9717 }
9718 }
9719 // TODO
9720 // We can exclude $ char that are not: $db, $leftmenu, $topmenu, $user, $langs, $object...,
9721 }
9722 if (is_array($s) || $s === 'Array') {
9723 return 'Bad string syntax to evaluate (value is Array) '.var_export($s, true);
9724 }
9725 if (strpos($s, '::') !== false) {
9726 if ($returnvalue) {
9727 return 'Bad string syntax to evaluate (double : char is forbidden): '.$s;
9728 } else {
9729 dol_syslog('Bad string syntax to evaluate (double : char is forbidden): '.$s);
9730 return '';
9731 }
9732 }
9733 if (strpos($s, '`') !== false) {
9734 if ($returnvalue) {
9735 return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
9736 } else {
9737 dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s);
9738 return '';
9739 }
9740 }
9741 if (preg_match('/[^0-9]+\.[^0-9]+/', $s)) { // We refuse . if not between 2 numbers
9742 if ($returnvalue) {
9743 return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
9744 } else {
9745 dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s);
9746 return '';
9747 }
9748 }
9749
9750 // We block use of php exec or php file functions
9751 $forbiddenphpstrings = array('$$');
9752 $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
9753
9754 $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen");
9755 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
9756 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64_decode", "rawurldecode", "urldecode", "str_rot13", "hex2bin")); // decode string functions used to obfuscated function name
9757 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
9758 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
9759 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));
9760 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
9761 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
9762
9763 $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
9764
9765 $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
9766
9767 $forbiddenphpmethodsregex = '->('.implode('|', $forbiddenphpmethods).')';
9768
9769 do {
9770 $oldstringtoclean = $s;
9771 $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);
9772 $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);
9773 $s = preg_replace('/'.$forbiddenphpmethodsregex.'/i', '__forbiddenstring__', $s);
9774 //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\‍(/i', '', $s); // Remove $function( call and $mycall->mymethod(
9775 } while ($oldstringtoclean != $s);
9776
9777 if (strpos($s, '__forbiddenstring__') !== false) {
9778 dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
9779 if ($returnvalue) {
9780 return 'Bad string syntax to evaluate: '.$s;
9781 } else {
9782 dol_syslog('Bad string syntax to evaluate: '.$s);
9783 return '';
9784 }
9785 }
9786
9787 //print $s."<br>\n";
9788 if ($returnvalue) {
9789 if ($hideerrors) {
9790 return @eval('return '.$s.';');
9791 } else {
9792 return eval('return '.$s.';');
9793 }
9794 } else {
9795 if ($hideerrors) {
9796 @eval($s);
9797 } else {
9798 eval($s);
9799 }
9800 }
9801 } catch (Error $e) {
9802 $error = 'dol_eval try/catch error : ';
9803 $error .= $e->getMessage();
9804 dol_syslog($error, LOG_WARNING);
9805 }
9806}
9807
9815function dol_validElement($element)
9816{
9817 return (trim($element) != '');
9818}
9819
9828function picto_from_langcode($codelang, $moreatt = '', $notitlealt = 0)
9829{
9830 if (empty($codelang)) {
9831 return '';
9832 }
9833
9834 if ($codelang == 'auto') {
9835 return '<span class="fa fa-language"></span>';
9836 }
9837
9838 $langtocountryflag = array(
9839 'ar_AR' => '',
9840 'ca_ES' => 'catalonia',
9841 'da_DA' => 'dk',
9842 'fr_CA' => 'mq',
9843 'sv_SV' => 'se',
9844 'sw_SW' => 'unknown',
9845 'AQ' => 'unknown',
9846 'CW' => 'unknown',
9847 'IM' => 'unknown',
9848 'JE' => 'unknown',
9849 'MF' => 'unknown',
9850 'BL' => 'unknown',
9851 'SX' => 'unknown'
9852 );
9853
9854 if (isset($langtocountryflag[$codelang])) {
9855 $flagImage = $langtocountryflag[$codelang];
9856 } else {
9857 $tmparray = explode('_', $codelang);
9858 $flagImage = empty($tmparray[1]) ? $tmparray[0] : $tmparray[1];
9859 }
9860
9861 $morecss = '';
9862 $reg = array();
9863 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
9864 $morecss = $reg[1];
9865 $moreatt = "";
9866 }
9867
9868 // return img_picto_common($codelang, 'flags/'.strtolower($flagImage).'.png', $moreatt, 0, $notitlealt);
9869 return '<span class="flag-sprite '.strtolower($flagImage).($morecss ? ' '.$morecss : '').'"'.($moreatt ? ' '.$moreatt : '').(!$notitlealt ? ' title="'.$codelang.'"' : '').'></span>';
9870}
9871
9880{
9881 global $mysoc;
9882
9883 if (empty($countrycode)) {
9884 return null;
9885 }
9886
9887 if (strtoupper($countrycode) == 'MQ') {
9888 return 'fr_CA';
9889 }
9890 if (strtoupper($countrycode) == 'SE') {
9891 return 'sv_SE'; // se_SE is Sami/Sweden, and we want in priority sv_SE for SE country
9892 }
9893 if (strtoupper($countrycode) == 'CH') {
9894 if ($mysoc->country_code == 'FR') {
9895 return 'fr_CH';
9896 }
9897 if ($mysoc->country_code == 'DE') {
9898 return 'de_CH';
9899 }
9900 if ($mysoc->country_code == 'IT') {
9901 return 'it_CH';
9902 }
9903 }
9904
9905 // Locale list taken from:
9906 // http://stackoverflow.com/questions/3191664/
9907 // list-of-all-locales-and-their-short-codes
9908 $locales = array(
9909 'af-ZA',
9910 'am-ET',
9911 'ar-AE',
9912 'ar-BH',
9913 'ar-DZ',
9914 'ar-EG',
9915 'ar-IQ',
9916 'ar-JO',
9917 'ar-KW',
9918 'ar-LB',
9919 'ar-LY',
9920 'ar-MA',
9921 'ar-OM',
9922 'ar-QA',
9923 'ar-SA',
9924 'ar-SY',
9925 'ar-TN',
9926 'ar-YE',
9927 //'as-IN', // Moved after en-IN
9928 'ba-RU',
9929 'be-BY',
9930 'bg-BG',
9931 'bn-BD',
9932 //'bn-IN', // Moved after en-IN
9933 'bo-CN',
9934 'br-FR',
9935 'ca-ES',
9936 'co-FR',
9937 'cs-CZ',
9938 'cy-GB',
9939 'da-DK',
9940 'de-AT',
9941 'de-CH',
9942 'de-DE',
9943 'de-LI',
9944 'de-LU',
9945 'dv-MV',
9946 'el-GR',
9947 'en-AU',
9948 'en-BZ',
9949 'en-CA',
9950 'en-GB',
9951 'en-IE',
9952 'en-IN',
9953 'as-IN', // as-IN must be after en-IN (en in priority if country is IN)
9954 'bn-IN', // bn-IN must be after en-IN (en in priority if country is IN)
9955 'en-JM',
9956 'en-MY',
9957 'en-NZ',
9958 'en-PH',
9959 'en-SG',
9960 'en-TT',
9961 'en-US',
9962 'en-ZA',
9963 'en-ZW',
9964 'es-AR',
9965 'es-BO',
9966 'es-CL',
9967 'es-CO',
9968 'es-CR',
9969 'es-DO',
9970 'es-EC',
9971 'es-ES',
9972 'es-GT',
9973 'es-HN',
9974 'es-MX',
9975 'es-NI',
9976 'es-PA',
9977 'es-PE',
9978 'es-PR',
9979 'es-PY',
9980 'es-SV',
9981 'es-US',
9982 'es-UY',
9983 'es-VE',
9984 'et-EE',
9985 'eu-ES',
9986 'fa-IR',
9987 'fi-FI',
9988 'fo-FO',
9989 'fr-BE',
9990 'fr-CA',
9991 'fr-CH',
9992 'fr-FR',
9993 'fr-LU',
9994 'fr-MC',
9995 'fy-NL',
9996 'ga-IE',
9997 'gd-GB',
9998 'gl-ES',
9999 'gu-IN',
10000 'he-IL',
10001 'hi-IN',
10002 'hr-BA',
10003 'hr-HR',
10004 'hu-HU',
10005 'hy-AM',
10006 'id-ID',
10007 'ig-NG',
10008 'ii-CN',
10009 'is-IS',
10010 'it-CH',
10011 'it-IT',
10012 'ja-JP',
10013 'ka-GE',
10014 'kk-KZ',
10015 'kl-GL',
10016 'km-KH',
10017 'kn-IN',
10018 'ko-KR',
10019 'ky-KG',
10020 'lb-LU',
10021 'lo-LA',
10022 'lt-LT',
10023 'lv-LV',
10024 'mi-NZ',
10025 'mk-MK',
10026 'ml-IN',
10027 'mn-MN',
10028 'mr-IN',
10029 'ms-BN',
10030 'ms-MY',
10031 'mt-MT',
10032 'nb-NO',
10033 'ne-NP',
10034 'nl-BE',
10035 'nl-NL',
10036 'nn-NO',
10037 'oc-FR',
10038 'or-IN',
10039 'pa-IN',
10040 'pl-PL',
10041 'ps-AF',
10042 'pt-BR',
10043 'pt-PT',
10044 'rm-CH',
10045 'ro-MD',
10046 'ro-RO',
10047 'ru-RU',
10048 'rw-RW',
10049 'sa-IN',
10050 'se-FI',
10051 'se-NO',
10052 'se-SE',
10053 'si-LK',
10054 'sk-SK',
10055 'sl-SI',
10056 'sq-AL',
10057 'sv-FI',
10058 'sv-SE',
10059 'sw-KE',
10060 'ta-IN',
10061 'te-IN',
10062 'th-TH',
10063 'tk-TM',
10064 'tn-ZA',
10065 'tr-TR',
10066 'tt-RU',
10067 'ug-CN',
10068 'uk-UA',
10069 'ur-PK',
10070 'vi-VN',
10071 'wo-SN',
10072 'xh-ZA',
10073 'yo-NG',
10074 'zh-CN',
10075 'zh-HK',
10076 'zh-MO',
10077 'zh-SG',
10078 'zh-TW',
10079 'zu-ZA',
10080 );
10081
10082 $buildprimarykeytotest = strtolower($countrycode).'-'.strtoupper($countrycode);
10083 if (in_array($buildprimarykeytotest, $locales)) {
10084 return strtolower($countrycode).'_'.strtoupper($countrycode);
10085 }
10086
10087 if (function_exists('locale_get_primary_language') && function_exists('locale_get_region')) { // Need extension php-intl
10088 foreach ($locales as $locale) {
10089 $locale_language = locale_get_primary_language($locale);
10090 $locale_region = locale_get_region($locale);
10091 if (strtoupper($countrycode) == $locale_region) {
10092 //var_dump($locale.' - '.$locale_language.' - '.$locale_region);
10093 return strtolower($locale_language).'_'.strtoupper($locale_region);
10094 }
10095 }
10096 } else {
10097 dol_syslog("Warning Exention php-intl is not available", LOG_WARNING);
10098 }
10099
10100 return null;
10101}
10102
10133function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode = 'add', $filterorigmodule = '')
10134{
10135 global $hookmanager, $db;
10136
10137 if (isset($conf->modules_parts['tabs'][$type]) && is_array($conf->modules_parts['tabs'][$type])) {
10138 foreach ($conf->modules_parts['tabs'][$type] as $value) {
10139 $values = explode(':', $value);
10140
10141 $reg = array();
10142 if ($mode == 'add' && !preg_match('/^\-/', $values[1])) {
10143 $newtab = array();
10144 $postab = $h;
10145 // detect if position set in $values[1] ie : +(2)mytab@mymodule (first tab is 0, second is one, ...)
10146 $str = $values[1];
10147 $posstart = strpos($str, '(');
10148 if ($posstart > 0) {
10149 $posend = strpos($str, ')');
10150 if ($posstart > 0) {
10151 $res1 = substr($str, $posstart + 1, $posend - $posstart -1);
10152 if (is_numeric($res1)) {
10153 $postab = (int) $res1;
10154 $values[1] = '+' . substr($str, $posend + 1);
10155 }
10156 }
10157 }
10158 if (count($values) == 6) {
10159 // new declaration with permissions:
10160 // $value='objecttype:+tabname1:Title1:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10161 // $value='objecttype:+tabname1:Title1,class,pathfile,method:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10162 if ($values[0] != $type) {
10163 continue;
10164 }
10165
10166 if (verifCond($values[4])) {
10167 if ($values[3]) {
10168 if ($filterorigmodule) { // If a filter of module origin has been requested
10169 if (strpos($values[3], '@')) { // This is an external module
10170 if ($filterorigmodule != 'external') {
10171 continue;
10172 }
10173 } else { // This looks a core module
10174 if ($filterorigmodule != 'core') {
10175 continue;
10176 }
10177 }
10178 }
10179 $langs->load($values[3]);
10180 }
10181 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10182 // If label is "SUBSTITUION_..."
10183 $substitutionarray = array();
10184 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
10185 $label = make_substitutions($reg[1], $substitutionarray);
10186 } else {
10187 // If label is "Label,Class,File,Method", we call the method to show content inside the badge
10188 $labeltemp = explode(',', $values[2]);
10189 $label = $langs->trans($labeltemp[0]);
10190
10191 if (!empty($labeltemp[1]) && is_object($object) && !empty($object->id)) {
10192 dol_include_once($labeltemp[2]);
10193 $classtoload = $labeltemp[1];
10194 if (class_exists($classtoload)) {
10195 $obj = new $classtoload($db);
10196 $function = $labeltemp[3];
10197 if ($obj && $function && method_exists($obj, $function)) {
10198 $nbrec = $obj->$function($object->id, $obj);
10199 if (!empty($nbrec)) {
10200 $label .= '<span class="badge marginleftonlyshort">'.$nbrec.'</span>';
10201 }
10202 }
10203 }
10204 }
10205 }
10206
10207 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[5]), 1);
10208 $newtab[1] = $label;
10209 $newtab[2] = str_replace('+', '', $values[1]);
10210 $h++;
10211 } else {
10212 continue;
10213 }
10214 } elseif (count($values) == 5) { // case deprecated
10215 dol_syslog('Passing 5 values in tabs module_parts is deprecated. Please update to 6 with permissions.', LOG_WARNING);
10216
10217 if ($values[0] != $type) {
10218 continue;
10219 }
10220 if ($values[3]) {
10221 if ($filterorigmodule) { // If a filter of module origin has been requested
10222 if (strpos($values[3], '@')) { // This is an external module
10223 if ($filterorigmodule != 'external') {
10224 continue;
10225 }
10226 } else { // This looks a core module
10227 if ($filterorigmodule != 'core') {
10228 continue;
10229 }
10230 }
10231 }
10232 $langs->load($values[3]);
10233 }
10234 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10235 $substitutionarray = array();
10236 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
10237 $label = make_substitutions($reg[1], $substitutionarray);
10238 } else {
10239 $label = $langs->trans($values[2]);
10240 }
10241
10242 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[4]), 1);
10243 $newtab[1] = $label;
10244 $newtab[2] = str_replace('+', '', $values[1]);
10245 $h++;
10246 }
10247 // set tab at its position
10248 $head = array_merge(array_slice($head, 0, $postab), array($newtab), array_slice($head, $postab));
10249 } elseif ($mode == 'remove' && preg_match('/^\-/', $values[1])) {
10250 if ($values[0] != $type) {
10251 continue;
10252 }
10253 $tabname = str_replace('-', '', $values[1]);
10254 foreach ($head as $key => $val) {
10255 $condition = (!empty($values[3]) ? verifCond($values[3]) : 1);
10256 //var_dump($key.' - '.$tabname.' - '.$head[$key][2].' - '.$values[3].' - '.$condition);
10257 if ($head[$key][2] == $tabname && $condition) {
10258 unset($head[$key]);
10259 break;
10260 }
10261 }
10262 }
10263 }
10264 }
10265
10266 // No need to make a return $head. Var is modified as a reference
10267 if (!empty($hookmanager)) {
10268 $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule);
10269 $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters, $object);
10270 if ($reshook > 0) { // Hook ask to replace completely the array
10271 $head = $hookmanager->resArray;
10272 } else { // Hook
10273 $head = array_merge($head, $hookmanager->resArray);
10274 }
10275 $h = count($head);
10276 }
10277}
10278
10290function printCommonFooter($zone = 'private')
10291{
10292 global $conf, $hookmanager, $user, $debugbar;
10293 global $action;
10294 global $micro_start_time;
10295
10296 if ($zone == 'private') {
10297 print "\n".'<!-- Common footer for private page -->'."\n";
10298 } else {
10299 print "\n".'<!-- Common footer for public page -->'."\n";
10300 }
10301
10302 // A div to store page_y POST parameter so we can read it using javascript
10303 print "\n<!-- A div to store page_y POST parameter -->\n";
10304 print '<div id="page_y" style="display: none;">'.(GETPOST('page_y') ? GETPOST('page_y') : '').'</div>'."\n";
10305
10306 $parameters = array();
10307 $reshook = $hookmanager->executeHooks('printCommonFooter', $parameters); // Note that $action and $object may have been modified by some hooks
10308 if (empty($reshook)) {
10309 if (getDolGlobalString('MAIN_HTML_FOOTER')) {
10310 print getDolGlobalString('MAIN_HTML_FOOTER') . "\n";
10311 }
10312
10313 print "\n";
10314 if (!empty($conf->use_javascript_ajax)) {
10315 print "\n<!-- A script section to add menuhider handler on backoffice, manage focus and madatory fields, tuning info, ... -->\n";
10316 print '<script>'."\n";
10317 print 'jQuery(document).ready(function() {'."\n";
10318
10319 if ($zone == 'private' && empty($conf->dol_use_jmobile)) {
10320 print "\n";
10321 print '/* JS CODE TO ENABLE to manage handler to switch left menu page (menuhider) */'."\n";
10322 print 'jQuery("li.menuhider").click(function(event) {';
10323 print ' if (!$( "body" ).hasClass( "sidebar-collapse" )){ event.preventDefault(); }'."\n";
10324 print ' console.log("We click on .menuhider");'."\n";
10325 print ' $("body").toggleClass("sidebar-collapse")'."\n";
10326 print '});'."\n";
10327 }
10328
10329 // Management of focus and mandatory for fields
10330 if ($action == 'create' || $action == 'edit' || (empty($action) && (preg_match('/new\.php/', $_SERVER["PHP_SELF"]))) || ((empty($action) || $action == 'addline') && (preg_match('/card\.php/', $_SERVER["PHP_SELF"])))) {
10331 print '/* JS CODE TO ENABLE to manage focus and mandatory form fields */'."\n";
10332 $relativepathstring = $_SERVER["PHP_SELF"];
10333 // Clean $relativepathstring
10334 if (constant('DOL_URL_ROOT')) {
10335 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
10336 }
10337 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
10338 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
10339 //$tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
10340 if (!empty($user->default_values[$relativepathstring]['focus'])) {
10341 foreach ($user->default_values[$relativepathstring]['focus'] as $defkey => $defval) {
10342 $qualified = 0;
10343 if ($defkey != '_noquery_') {
10344 $tmpqueryarraytohave = explode('&', $defkey);
10345 $foundintru = 0;
10346 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
10347 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
10348 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
10349 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
10350 $foundintru = 1;
10351 }
10352 }
10353 if (!$foundintru) {
10354 $qualified = 1;
10355 }
10356 //var_dump($defkey.'-'.$qualified);
10357 } else {
10358 $qualified = 1;
10359 }
10360
10361 if ($qualified) {
10362 foreach ($defval as $paramkey => $paramval) {
10363 // Set focus on field
10364 print 'jQuery("input[name=\''.$paramkey.'\']").focus();'."\n";
10365 print 'jQuery("textarea[name=\''.$paramkey.'\']").focus();'."\n";
10366 print 'jQuery("select[name=\''.$paramkey.'\']").focus();'."\n"; // Not really usefull, but we keep it in case of.
10367 }
10368 }
10369 }
10370 }
10371 if (!empty($user->default_values[$relativepathstring]['mandatory'])) {
10372 foreach ($user->default_values[$relativepathstring]['mandatory'] as $defkey => $defval) {
10373 $qualified = 0;
10374 if ($defkey != '_noquery_') {
10375 $tmpqueryarraytohave = explode('&', $defkey);
10376 $foundintru = 0;
10377 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
10378 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
10379 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
10380 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
10381 $foundintru = 1;
10382 }
10383 }
10384 if (!$foundintru) {
10385 $qualified = 1;
10386 }
10387 //var_dump($defkey.'-'.$qualified);
10388 } else {
10389 $qualified = 1;
10390 }
10391
10392 if ($qualified) {
10393 foreach ($defval as $paramkey => $paramval) {
10394 // Add property 'required' on input
10395 print 'jQuery("input[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10396 print 'jQuery("textarea[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10397 print '// required on a select works only if key is "", so we add the required attributes but also we reset the key -1 or 0 to an empty string'."\n";
10398 print 'jQuery("select[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10399 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'-1\']").prop(\'value\', \'\');'."\n";
10400 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'0\']").prop(\'value\', \'\');'."\n";
10401
10402 // Add 'field required' class on closest td for all input elements : input, textarea and select
10403 print 'jQuery(":input[name=\'' . $paramkey . '\']").closest("tr").find("td:first").addClass("fieldrequired");' . "\n";
10404 }
10405 // If we submit the cancel button we remove the required attributes
10406 print 'jQuery("input[name=\'cancel\']").click(function() {
10407 console.log("We click on cancel button so removed all required attribute");
10408 jQuery("input, textarea, select").each(function(){this.removeAttribute(\'required\');});
10409 });'."\n";
10410 }
10411 }
10412 }
10413 }
10414
10415 print '});'."\n";
10416
10417 // End of tuning
10418 if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO']) || getDolGlobalString('MAIN_SHOW_TUNING_INFO')) {
10419 print "\n";
10420 print "/* JS CODE TO ENABLE to add memory info */\n";
10421 print 'window.console && console.log("';
10422 if (getDolGlobalString('MEMCACHED_SERVER')) {
10423 print 'MEMCACHED_SERVER=' . getDolGlobalString('MEMCACHED_SERVER').' - ';
10424 }
10425 print 'MAIN_OPTIMIZE_SPEED='.(isset($conf->global->MAIN_OPTIMIZE_SPEED) ? $conf->global->MAIN_OPTIMIZE_SPEED : 'off');
10426 if (!empty($micro_start_time)) { // Works only if MAIN_SHOW_TUNING_INFO is defined at $_SERVER level. Not in global variable.
10427 $micro_end_time = microtime(true);
10428 print ' - Build time: '.ceil(1000 * ($micro_end_time - $micro_start_time)).' ms';
10429 }
10430
10431 if (function_exists("memory_get_usage")) {
10432 print ' - Mem: '.memory_get_usage(); // Do not use true here, it seems it takes the peak amount
10433 }
10434 if (function_exists("memory_get_peak_usage")) {
10435 print ' - Real mem peak: '.memory_get_peak_usage(true);
10436 }
10437 if (function_exists("zend_loader_file_encoded")) {
10438 print ' - Zend encoded file: '.(zend_loader_file_encoded() ? 'yes' : 'no');
10439 }
10440 print '");'."\n";
10441 }
10442
10443 print "\n".'</script>'."\n";
10444
10445 // Google Analytics
10446 // TODO Add a hook here
10447 if (isModEnabled('google') && getDolGlobalString('MAIN_GOOGLE_AN_ID')) {
10448 $tmptagarray = explode(',', getDolGlobalString('MAIN_GOOGLE_AN_ID'));
10449 foreach ($tmptagarray as $tmptag) {
10450 print "\n";
10451 print "<!-- JS CODE TO ENABLE for google analtics tag -->\n";
10452 print '
10453 <!-- Global site tag (gtag.js) - Google Analytics -->
10454 <script nonce="'.getNonce().'" async src="https://www.googletagmanager.com/gtag/js?id='.trim($tmptag).'"></script>
10455 <script>
10456 window.dataLayer = window.dataLayer || [];
10457 function gtag(){dataLayer.push(arguments);}
10458 gtag(\'js\', new Date());
10459
10460 gtag(\'config\', \''.trim($tmptag).'\');
10461 </script>';
10462 print "\n";
10463 }
10464 }
10465 }
10466
10467 // Add Xdebug coverage of code
10468 if (defined('XDEBUGCOVERAGE')) {
10469 print_r(xdebug_get_code_coverage());
10470 }
10471
10472 // Add DebugBar data
10473 if ($user->hasRight('debugbar', 'read') && is_object($debugbar)) {
10474 $debugbar['time']->stopMeasure('pageaftermaster');
10475 print '<!-- Output debugbar data -->'."\n";
10476 $renderer = $debugbar->getRenderer();
10477 print $debugbar->getRenderer()->render();
10478 } elseif (count($conf->logbuffer)) { // If there is some logs in buffer to show
10479 print "\n";
10480 print "<!-- Start of log output\n";
10481 //print '<div class="hidden">'."\n";
10482 foreach ($conf->logbuffer as $logline) {
10483 print $logline."<br>\n";
10484 }
10485 //print '</div>'."\n";
10486 print "End of log output -->\n";
10487 }
10488 }
10489}
10490
10500function dolExplodeIntoArray($string, $delimiter = ';', $kv = '=')
10501{
10502 if (is_null($string)) {
10503 return array();
10504 }
10505
10506 if (preg_match('/^\[.*\]$/sm', $delimiter) || preg_match('/^\‍(.*\‍)$/sm', $delimiter)) {
10507 // This is a regex string
10508 $newdelimiter = $delimiter;
10509 } else {
10510 // This is a simple string
10511 $newdelimiter = preg_quote($delimiter, '/');
10512 }
10513
10514 if ($a = preg_split('/'.$newdelimiter.'/', $string)) {
10515 $ka = array();
10516 foreach ($a as $s) { // each part
10517 if ($s) {
10518 if ($pos = strpos($s, $kv)) { // key/value delimiter
10519 $ka[trim(substr($s, 0, $pos))] = trim(substr($s, $pos + strlen($kv)));
10520 } else { // key delimiter not found
10521 $ka[] = trim($s);
10522 }
10523 }
10524 }
10525 return $ka;
10526 }
10527
10528 return array();
10529}
10530
10531
10538function dol_set_focus($selector)
10539{
10540 print "\n".'<!-- Set focus onto a specific field -->'."\n";
10541 print '<script nonce="'.getNonce().'">jQuery(document).ready(function() { jQuery("'.dol_escape_js($selector).'").focus(); });</script>'."\n";
10542}
10543
10544
10552function dol_getmypid()
10553{
10554 if (!function_exists('getmypid')) {
10555 return mt_rand(99900000, 99965535);
10556 } else {
10557 return getmypid(); // May be a number on 64 bits (depending on OS)
10558 }
10559}
10560
10561
10579function natural_search($fields, $value, $mode = 0, $nofirstand = 0)
10580{
10581 global $db, $langs;
10582
10583 $value = trim($value);
10584
10585 if ($mode == 0) {
10586 $value = preg_replace('/\*/', '%', $value); // Replace * with %
10587 }
10588 if ($mode == 1) {
10589 $value = preg_replace('/([!<>=]+)\s+([0-9'.preg_quote($langs->trans("DecimalSeparator"), '/').'\-])/', '\1\2', $value); // Clean string '< 10' into '<10' so we can then explode on space to get all tests to do
10590 }
10591
10592 $value = preg_replace('/\s*\|\s*/', '|', $value);
10593
10594 $crits = explode(' ', $value);
10595 $res = '';
10596 if (!is_array($fields)) {
10597 $fields = array($fields);
10598 }
10599
10600 $i1 = 0; // count the nb of and criteria added (all fields / criterias)
10601 foreach ($crits as $crit) { // Loop on each AND criteria
10602 $crit = trim($crit);
10603 $i2 = 0; // count the nb of valid criteria added for this this first criteria
10604 $newres = '';
10605 foreach ($fields as $field) {
10606 if ($mode == 1) {
10607 $tmpcrits = explode('|', $crit);
10608 $i3 = 0; // count the nb of valid criteria added for this current field
10609 foreach ($tmpcrits as $tmpcrit) {
10610 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10611 continue;
10612 }
10613 $tmpcrit = trim($tmpcrit);
10614
10615 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10616
10617 $operator = '=';
10618 $newcrit = preg_replace('/([!<>=]+)/', '', $tmpcrit);
10619
10620 $reg = array();
10621 preg_match('/([!<>=]+)/', $tmpcrit, $reg);
10622 if (!empty($reg[1])) {
10623 $operator = $reg[1];
10624 }
10625 if ($newcrit != '') {
10626 $numnewcrit = price2num($newcrit);
10627 if (is_numeric($numnewcrit)) {
10628 $newres .= $field.' '.$operator.' '.((float) $numnewcrit); // should be a numeric
10629 } else {
10630 $newres .= '1 = 2'; // force false, we received a corrupted data
10631 }
10632 $i3++; // a criteria was added to string
10633 }
10634 }
10635 $i2++; // a criteria for 1 more field was added to string
10636 } elseif ($mode == 2 || $mode == -2) {
10637 $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer
10638 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -2 ? 'NOT ' : '');
10639 $newres .= $crit ? "IN (".$db->sanitize($db->escape($crit)).")" : "IN (0)";
10640 if ($mode == -2) {
10641 $newres .= ' OR '.$field.' IS NULL';
10642 }
10643 $i2++; // a criteria for 1 more field was added to string
10644 } elseif ($mode == 3 || $mode == -3) {
10645 $tmparray = explode(',', $crit);
10646 if (count($tmparray)) {
10647 $listofcodes = '';
10648 foreach ($tmparray as $val) {
10649 $val = trim($val);
10650 if ($val) {
10651 $listofcodes .= ($listofcodes ? ',' : '');
10652 $listofcodes .= "'".$db->escape($val)."'";
10653 }
10654 }
10655 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -3 ? 'NOT ' : '')."IN (".$db->sanitize($listofcodes, 1).")";
10656 $i2++; // a criteria for 1 more field was added to string
10657 }
10658 if ($mode == -3) {
10659 $newres .= ' OR '.$field.' IS NULL';
10660 }
10661 } elseif ($mode == 4) {
10662 $tmparray = explode(',', $crit);
10663 if (count($tmparray)) {
10664 $listofcodes = '';
10665 foreach ($tmparray as $val) {
10666 $val = trim($val);
10667 if ($val) {
10668 $newres .= ($i2 > 0 ? " OR (" : "(").$field." LIKE '".$db->escape($val).",%'";
10669 $newres .= ' OR '.$field." = '".$db->escape($val)."'";
10670 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val)."'";
10671 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val).",%'";
10672 $newres .= ')';
10673 $i2++; // a criteria for 1 more field was added to string (we can add several citeria for the same field as it is a multiselect search criteria)
10674 }
10675 }
10676 }
10677 } else { // $mode=0
10678 $tmpcrits = explode('|', $crit);
10679 $i3 = 0; // count the nb of valid criteria added for the current couple criteria/field
10680 foreach ($tmpcrits as $tmpcrit) { // loop on each OR criteria
10681 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10682 continue;
10683 }
10684 $tmpcrit = trim($tmpcrit);
10685
10686 if ($tmpcrit == '^$' || strpos($crit, '!') === 0) { // If we search empty, we must combined different OR fields with AND
10687 $newres .= (($i2 > 0 || $i3 > 0) ? ' AND ' : '');
10688 } else {
10689 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10690 }
10691
10692 if (preg_match('/\.(id|rowid)$/', $field)) { // Special case for rowid that is sometimes a ref so used as a search field
10693 $newres .= $field." = ".(is_numeric($tmpcrit) ? ((float) $tmpcrit) : '0');
10694 } else {
10695 $tmpcrit2 = $tmpcrit;
10696 $tmpbefore = '%';
10697 $tmpafter = '%';
10698 $tmps = '';
10699
10700 if (preg_match('/^!/', $tmpcrit)) {
10701 $tmps .= $field." NOT LIKE "; // ! as exclude character
10702 $tmpcrit2 = preg_replace('/^!/', '', $tmpcrit2);
10703 } else {
10704 $tmps .= $field." LIKE ";
10705 }
10706 $tmps .= "'";
10707
10708 if (preg_match('/^[\^\$]/', $tmpcrit)) {
10709 $tmpbefore = '';
10710 $tmpcrit2 = preg_replace('/^[\^\$]/', '', $tmpcrit2);
10711 }
10712 if (preg_match('/[\^\$]$/', $tmpcrit)) {
10713 $tmpafter = '';
10714 $tmpcrit2 = preg_replace('/[\^\$]$/', '', $tmpcrit2);
10715 }
10716
10717 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10718 $tmps = "(".$tmps;
10719 }
10720 $newres .= $tmps;
10721 $newres .= $tmpbefore;
10722 $newres .= $db->escape($tmpcrit2);
10723 $newres .= $tmpafter;
10724 $newres .= "'";
10725 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10726 $newres .= " OR ".$field." IS NULL)";
10727 }
10728 }
10729
10730 $i3++;
10731 }
10732
10733 $i2++; // a criteria for 1 more field was added to string
10734 }
10735 }
10736
10737 if ($newres) {
10738 $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : '');
10739 }
10740 $i1++;
10741 }
10742 $res = ($nofirstand ? "" : " AND ")."(".$res.")";
10743
10744 return $res;
10745}
10746
10753function showDirectDownloadLink($object)
10754{
10755 global $conf, $langs;
10756
10757 $out = '';
10758 $url = $object->getLastMainDocLink($object->element);
10759
10760 $out .= img_picto($langs->trans("PublicDownloadLinkDesc"), 'globe').' <span class="opacitymedium">'.$langs->trans("DirectDownloadLink").'</span><br>';
10761 if ($url) {
10762 $out .= '<div class="urllink"><input type="text" id="directdownloadlink" class="quatrevingtpercent" value="'.$url.'"></div>';
10763 $out .= ajax_autoselect("directdownloadlink", 0);
10764 } else {
10765 $out .= '<div class="urllink">'.$langs->trans("FileNotShared").'</div>';
10766 }
10767
10768 return $out;
10769}
10770
10779function getImageFileNameForSize($file, $extName, $extImgTarget = '')
10780{
10781 $dirName = dirname($file);
10782 if ($dirName == '.') {
10783 $dirName = '';
10784 }
10785
10786 $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.webp)$/i', '', $file); // We remove extension, whatever is its case
10787 $fileName = basename($fileName);
10788
10789 if (empty($extImgTarget)) {
10790 $extImgTarget = (preg_match('/\.jpg$/i', $file) ? '.jpg' : '');
10791 }
10792 if (empty($extImgTarget)) {
10793 $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '');
10794 }
10795 if (empty($extImgTarget)) {
10796 $extImgTarget = (preg_match('/\.gif$/i', $file) ? '.gif' : '');
10797 }
10798 if (empty($extImgTarget)) {
10799 $extImgTarget = (preg_match('/\.png$/i', $file) ? '.png' : '');
10800 }
10801 if (empty($extImgTarget)) {
10802 $extImgTarget = (preg_match('/\.bmp$/i', $file) ? '.bmp' : '');
10803 }
10804 if (empty($extImgTarget)) {
10805 $extImgTarget = (preg_match('/\.webp$/i', $file) ? '.webp' : '');
10806 }
10807
10808 if (!$extImgTarget) {
10809 return $file;
10810 }
10811
10812 $subdir = '';
10813 if ($extName) {
10814 $subdir = 'thumbs/';
10815 }
10816
10817 return ($dirName ? $dirName.'/' : '').$subdir.$fileName.$extName.$extImgTarget; // New filename for thumb
10818}
10819
10820
10830function getAdvancedPreviewUrl($modulepart, $relativepath, $alldata = 0, $param = '')
10831{
10832 global $conf, $langs;
10833
10834 if (empty($conf->use_javascript_ajax)) {
10835 return '';
10836 }
10837
10838 $isAllowedForPreview = dolIsAllowedForPreview($relativepath);
10839
10840 if ($alldata == 1) {
10841 if ($isAllowedForPreview) {
10842 return array('target'=>'_blank', 'css'=>'documentpreview', 'url'=>DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : ''), 'mime'=>dol_mimetype($relativepath));
10843 } else {
10844 return array();
10845 }
10846 }
10847
10848 // old behavior, return a string
10849 if ($isAllowedForPreview) {
10850 $tmpurl = DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : '');
10851 $title = $langs->trans("Preview");
10852 //$title = '%27-alert(document.domain)-%27';
10853 //$tmpurl = 'file='.urlencode("'-alert(document.domain)-'_small.jpg");
10854
10855 // We need to urlencode the parameter after the dol_escape_js($tmpurl) because $tmpurl may contain n url with param file=abc%27def if file has a ' inside.
10856 // and when we click on href with this javascript string, a urlcode is done by browser, converted the %27 of file param
10857 return 'javascript:document_preview(\''.urlencode(dol_escape_js($tmpurl)).'\', \''.urlencode(dol_mimetype($relativepath)).'\', \''.urlencode(dol_escape_js($title)).'\')';
10858 } else {
10859 return '';
10860 }
10861}
10862
10863
10872function ajax_autoselect($htmlname, $addlink = '', $textonlink = 'Link')
10873{
10874 global $langs;
10875 $out = '<script nonce="'.getNonce().'">
10876 jQuery(document).ready(function () {
10877 jQuery("'.((strpos($htmlname, '.') === 0 ? '' : '#').$htmlname).'").click(function() { jQuery(this).select(); } );
10878 });
10879 </script>';
10880 if ($addlink) {
10881 if ($textonlink === 'image') {
10882 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.img_picto('', 'globe').'</a>';
10883 } else {
10884 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.$langs->trans("Link").'</a>';
10885 }
10886 }
10887 return $out;
10888}
10889
10897function dolIsAllowedForPreview($file)
10898{
10899 global $conf;
10900
10901 // Check .noexe extension in filename
10902 if (preg_match('/\.noexe$/i', $file)) {
10903 return 0;
10904 }
10905
10906 // Check mime types
10907 $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'webp');
10908 if (getDolGlobalString('MAIN_ALLOW_SVG_FILES_AS_IMAGES')) {
10909 $mime_preview[] = 'svg+xml';
10910 }
10911 //$mime_preview[]='vnd.oasis.opendocument.presentation';
10912 //$mime_preview[]='archive';
10913 $num_mime = array_search(dol_mimetype($file, '', 1), $mime_preview);
10914 if ($num_mime !== false) {
10915 return 1;
10916 }
10917
10918 // By default, not allowed for preview
10919 return 0;
10920}
10921
10922
10932function dol_mimetype($file, $default = 'application/octet-stream', $mode = 0)
10933{
10934 $mime = $default;
10935 $imgmime = 'other.png';
10936 $famime = 'file-o';
10937 $srclang = '';
10938
10939 $tmpfile = preg_replace('/\.noexe$/', '', $file);
10940
10941 // Plain text files
10942 if (preg_match('/\.txt$/i', $tmpfile)) {
10943 $mime = 'text/plain';
10944 $imgmime = 'text.png';
10945 $famime = 'file-alt';
10946 } elseif (preg_match('/\.rtx$/i', $tmpfile)) {
10947 $mime = 'text/richtext';
10948 $imgmime = 'text.png';
10949 $famime = 'file-alt';
10950 } elseif (preg_match('/\.csv$/i', $tmpfile)) {
10951 $mime = 'text/csv';
10952 $imgmime = 'text.png';
10953 $famime = 'file-csv';
10954 } elseif (preg_match('/\.tsv$/i', $tmpfile)) {
10955 $mime = 'text/tab-separated-values';
10956 $imgmime = 'text.png';
10957 $famime = 'file-alt';
10958 } elseif (preg_match('/\.(cf|conf|log)$/i', $tmpfile)) {
10959 $mime = 'text/plain';
10960 $imgmime = 'text.png';
10961 $famime = 'file-alt';
10962 } elseif (preg_match('/\.ini$/i', $tmpfile)) {
10963 $mime = 'text/plain';
10964 $imgmime = 'text.png';
10965 $srclang = 'ini';
10966 $famime = 'file-alt';
10967 } elseif (preg_match('/\.md$/i', $tmpfile)) {
10968 $mime = 'text/plain';
10969 $imgmime = 'text.png';
10970 $srclang = 'md';
10971 $famime = 'file-alt';
10972 } elseif (preg_match('/\.css$/i', $tmpfile)) {
10973 $mime = 'text/css';
10974 $imgmime = 'css.png';
10975 $srclang = 'css';
10976 $famime = 'file-alt';
10977 } elseif (preg_match('/\.lang$/i', $tmpfile)) {
10978 $mime = 'text/plain';
10979 $imgmime = 'text.png';
10980 $srclang = 'lang';
10981 $famime = 'file-alt';
10982 } elseif (preg_match('/\.(crt|cer|key|pub)$/i', $tmpfile)) { // Certificate files
10983 $mime = 'text/plain';
10984 $imgmime = 'text.png';
10985 $famime = 'file-alt';
10986 } elseif (preg_match('/\.(html|htm|shtml)$/i', $tmpfile)) { // XML based (HTML/XML/XAML)
10987 $mime = 'text/html';
10988 $imgmime = 'html.png';
10989 $srclang = 'html';
10990 $famime = 'file-alt';
10991 } elseif (preg_match('/\.(xml|xhtml)$/i', $tmpfile)) {
10992 $mime = 'text/xml';
10993 $imgmime = 'other.png';
10994 $srclang = 'xml';
10995 $famime = 'file-alt';
10996 } elseif (preg_match('/\.xaml$/i', $tmpfile)) {
10997 $mime = 'text/xml';
10998 $imgmime = 'other.png';
10999 $srclang = 'xaml';
11000 $famime = 'file-alt';
11001 } elseif (preg_match('/\.bas$/i', $tmpfile)) { // Languages
11002 $mime = 'text/plain';
11003 $imgmime = 'text.png';
11004 $srclang = 'bas';
11005 $famime = 'file-code';
11006 } elseif (preg_match('/\.(c)$/i', $tmpfile)) {
11007 $mime = 'text/plain';
11008 $imgmime = 'text.png';
11009 $srclang = 'c';
11010 $famime = 'file-code';
11011 } elseif (preg_match('/\.(cpp)$/i', $tmpfile)) {
11012 $mime = 'text/plain';
11013 $imgmime = 'text.png';
11014 $srclang = 'cpp';
11015 $famime = 'file-code';
11016 } elseif (preg_match('/\.cs$/i', $tmpfile)) {
11017 $mime = 'text/plain';
11018 $imgmime = 'text.png';
11019 $srclang = 'cs';
11020 $famime = 'file-code';
11021 } elseif (preg_match('/\.(h)$/i', $tmpfile)) {
11022 $mime = 'text/plain';
11023 $imgmime = 'text.png';
11024 $srclang = 'h';
11025 $famime = 'file-code';
11026 } elseif (preg_match('/\.(java|jsp)$/i', $tmpfile)) {
11027 $mime = 'text/plain';
11028 $imgmime = 'text.png';
11029 $srclang = 'java';
11030 $famime = 'file-code';
11031 } elseif (preg_match('/\.php([0-9]{1})?$/i', $tmpfile)) {
11032 $mime = 'text/plain';
11033 $imgmime = 'php.png';
11034 $srclang = 'php';
11035 $famime = 'file-code';
11036 } elseif (preg_match('/\.phtml$/i', $tmpfile)) {
11037 $mime = 'text/plain';
11038 $imgmime = 'php.png';
11039 $srclang = 'php';
11040 $famime = 'file-code';
11041 } elseif (preg_match('/\.(pl|pm)$/i', $tmpfile)) {
11042 $mime = 'text/plain';
11043 $imgmime = 'pl.png';
11044 $srclang = 'perl';
11045 $famime = 'file-code';
11046 } elseif (preg_match('/\.sql$/i', $tmpfile)) {
11047 $mime = 'text/plain';
11048 $imgmime = 'text.png';
11049 $srclang = 'sql';
11050 $famime = 'file-code';
11051 } elseif (preg_match('/\.js$/i', $tmpfile)) {
11052 $mime = 'text/x-javascript';
11053 $imgmime = 'jscript.png';
11054 $srclang = 'js';
11055 $famime = 'file-code';
11056 } elseif (preg_match('/\.odp$/i', $tmpfile)) { // Open office
11057 $mime = 'application/vnd.oasis.opendocument.presentation';
11058 $imgmime = 'ooffice.png';
11059 $famime = 'file-powerpoint';
11060 } elseif (preg_match('/\.ods$/i', $tmpfile)) {
11061 $mime = 'application/vnd.oasis.opendocument.spreadsheet';
11062 $imgmime = 'ooffice.png';
11063 $famime = 'file-excel';
11064 } elseif (preg_match('/\.odt$/i', $tmpfile)) {
11065 $mime = 'application/vnd.oasis.opendocument.text';
11066 $imgmime = 'ooffice.png';
11067 $famime = 'file-word';
11068 } elseif (preg_match('/\.mdb$/i', $tmpfile)) { // MS Office
11069 $mime = 'application/msaccess';
11070 $imgmime = 'mdb.png';
11071 $famime = 'file';
11072 } elseif (preg_match('/\.doc[xm]?$/i', $tmpfile)) {
11073 $mime = 'application/msword';
11074 $imgmime = 'doc.png';
11075 $famime = 'file-word';
11076 } elseif (preg_match('/\.dot[xm]?$/i', $tmpfile)) {
11077 $mime = 'application/msword';
11078 $imgmime = 'doc.png';
11079 $famime = 'file-word';
11080 } elseif (preg_match('/\.xlt(x)?$/i', $tmpfile)) {
11081 $mime = 'application/vnd.ms-excel';
11082 $imgmime = 'xls.png';
11083 $famime = 'file-excel';
11084 } elseif (preg_match('/\.xla(m)?$/i', $tmpfile)) {
11085 $mime = 'application/vnd.ms-excel';
11086 $imgmime = 'xls.png';
11087 $famime = 'file-excel';
11088 } elseif (preg_match('/\.xls$/i', $tmpfile)) {
11089 $mime = 'application/vnd.ms-excel';
11090 $imgmime = 'xls.png';
11091 $famime = 'file-excel';
11092 } elseif (preg_match('/\.xls[bmx]$/i', $tmpfile)) {
11093 $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
11094 $imgmime = 'xls.png';
11095 $famime = 'file-excel';
11096 } elseif (preg_match('/\.pps[mx]?$/i', $tmpfile)) {
11097 $mime = 'application/vnd.ms-powerpoint';
11098 $imgmime = 'ppt.png';
11099 $famime = 'file-powerpoint';
11100 } elseif (preg_match('/\.ppt[mx]?$/i', $tmpfile)) {
11101 $mime = 'application/x-mspowerpoint';
11102 $imgmime = 'ppt.png';
11103 $famime = 'file-powerpoint';
11104 } elseif (preg_match('/\.pdf$/i', $tmpfile)) { // Other
11105 $mime = 'application/pdf';
11106 $imgmime = 'pdf.png';
11107 $famime = 'file-pdf';
11108 } elseif (preg_match('/\.bat$/i', $tmpfile)) { // Scripts
11109 $mime = 'text/x-bat';
11110 $imgmime = 'script.png';
11111 $srclang = 'dos';
11112 $famime = 'file-code';
11113 } elseif (preg_match('/\.sh$/i', $tmpfile)) {
11114 $mime = 'text/x-sh';
11115 $imgmime = 'script.png';
11116 $srclang = 'bash';
11117 $famime = 'file-code';
11118 } elseif (preg_match('/\.ksh$/i', $tmpfile)) {
11119 $mime = 'text/x-ksh';
11120 $imgmime = 'script.png';
11121 $srclang = 'bash';
11122 $famime = 'file-code';
11123 } elseif (preg_match('/\.bash$/i', $tmpfile)) {
11124 $mime = 'text/x-bash';
11125 $imgmime = 'script.png';
11126 $srclang = 'bash';
11127 $famime = 'file-code';
11128 } elseif (preg_match('/\.ico$/i', $tmpfile)) { // Images
11129 $mime = 'image/x-icon';
11130 $imgmime = 'image.png';
11131 $famime = 'file-image';
11132 } elseif (preg_match('/\.(jpg|jpeg)$/i', $tmpfile)) {
11133 $mime = 'image/jpeg';
11134 $imgmime = 'image.png';
11135 $famime = 'file-image';
11136 } elseif (preg_match('/\.png$/i', $tmpfile)) {
11137 $mime = 'image/png';
11138 $imgmime = 'image.png';
11139 $famime = 'file-image';
11140 } elseif (preg_match('/\.gif$/i', $tmpfile)) {
11141 $mime = 'image/gif';
11142 $imgmime = 'image.png';
11143 $famime = 'file-image';
11144 } elseif (preg_match('/\.bmp$/i', $tmpfile)) {
11145 $mime = 'image/bmp';
11146 $imgmime = 'image.png';
11147 $famime = 'file-image';
11148 } elseif (preg_match('/\.(tif|tiff)$/i', $tmpfile)) {
11149 $mime = 'image/tiff';
11150 $imgmime = 'image.png';
11151 $famime = 'file-image';
11152 } elseif (preg_match('/\.svg$/i', $tmpfile)) {
11153 $mime = 'image/svg+xml';
11154 $imgmime = 'image.png';
11155 $famime = 'file-image';
11156 } elseif (preg_match('/\.webp$/i', $tmpfile)) {
11157 $mime = 'image/webp';
11158 $imgmime = 'image.png';
11159 $famime = 'file-image';
11160 } elseif (preg_match('/\.vcs$/i', $tmpfile)) { // Calendar
11161 $mime = 'text/calendar';
11162 $imgmime = 'other.png';
11163 $famime = 'file-alt';
11164 } elseif (preg_match('/\.ics$/i', $tmpfile)) {
11165 $mime = 'text/calendar';
11166 $imgmime = 'other.png';
11167 $famime = 'file-alt';
11168 } elseif (preg_match('/\.torrent$/i', $tmpfile)) { // Other
11169 $mime = 'application/x-bittorrent';
11170 $imgmime = 'other.png';
11171 $famime = 'file-o';
11172 } elseif (preg_match('/\.(mp3|ogg|au|wav|wma|mid)$/i', $tmpfile)) { // Audio
11173 $mime = 'audio';
11174 $imgmime = 'audio.png';
11175 $famime = 'file-audio';
11176 } elseif (preg_match('/\.mp4$/i', $tmpfile)) { // Video
11177 $mime = 'video/mp4';
11178 $imgmime = 'video.png';
11179 $famime = 'file-video';
11180 } elseif (preg_match('/\.ogv$/i', $tmpfile)) {
11181 $mime = 'video/ogg';
11182 $imgmime = 'video.png';
11183 $famime = 'file-video';
11184 } elseif (preg_match('/\.webm$/i', $tmpfile)) {
11185 $mime = 'video/webm';
11186 $imgmime = 'video.png';
11187 $famime = 'file-video';
11188 } elseif (preg_match('/\.avi$/i', $tmpfile)) {
11189 $mime = 'video/x-msvideo';
11190 $imgmime = 'video.png';
11191 $famime = 'file-video';
11192 } elseif (preg_match('/\.divx$/i', $tmpfile)) {
11193 $mime = 'video/divx';
11194 $imgmime = 'video.png';
11195 $famime = 'file-video';
11196 } elseif (preg_match('/\.xvid$/i', $tmpfile)) {
11197 $mime = 'video/xvid';
11198 $imgmime = 'video.png';
11199 $famime = 'file-video';
11200 } elseif (preg_match('/\.(wmv|mpg|mpeg)$/i', $tmpfile)) {
11201 $mime = 'video';
11202 $imgmime = 'video.png';
11203 $famime = 'file-video';
11204 } elseif (preg_match('/\.(zip|rar|gz|tgz|z|cab|bz2|7z|tar|lzh|zst)$/i', $tmpfile)) { // Archive
11205 // application/xxx where zzz is zip, ...
11206 $mime = 'archive';
11207 $imgmime = 'archive.png';
11208 $famime = 'file-archive';
11209 } elseif (preg_match('/\.(exe|com)$/i', $tmpfile)) { // Exe
11210 $mime = 'application/octet-stream';
11211 $imgmime = 'other.png';
11212 $famime = 'file-o';
11213 } elseif (preg_match('/\.(dll|lib|o|so|a)$/i', $tmpfile)) { // Lib
11214 $mime = 'library';
11215 $imgmime = 'library.png';
11216 $famime = 'file-o';
11217 } elseif (preg_match('/\.err$/i', $tmpfile)) { // phpcs:ignore
11218 $mime = 'error';
11219 $imgmime = 'error.png';
11220 $famime = 'file-alt';
11221 }
11222
11223 // Return mimetype string
11224 switch ((int) $mode) {
11225 case 1:
11226 $tmp = explode('/', $mime);
11227 return (!empty($tmp[1]) ? $tmp[1] : $tmp[0]);
11228 case 2:
11229 return $imgmime;
11230 case 3:
11231 return $srclang;
11232 case 4:
11233 return $famime;
11234 }
11235 return $mime;
11236}
11237
11249function getDictionaryValue($tablename, $field, $id, $checkentity = false, $rowidfield = 'rowid')
11250{
11251 global $conf, $db;
11252
11253 $tablename = preg_replace('/^'.preg_quote(MAIN_DB_PREFIX, '/').'/', '', $tablename); // Clean name of table for backward compatibility.
11254
11255 $dictvalues = (isset($conf->cache['dictvalues_'.$tablename]) ? $conf->cache['dictvalues_'.$tablename] : null);
11256
11257 if (is_null($dictvalues)) {
11258 $dictvalues = array();
11259
11260 $sql = "SELECT * FROM ".MAIN_DB_PREFIX.$tablename." WHERE 1 = 1"; // Here select * is allowed as it is generic code and we don't have list of fields
11261 if ($checkentity) {
11262 $sql .= ' AND entity IN (0,'.getEntity($tablename).')';
11263 }
11264
11265 $resql = $db->query($sql);
11266 if ($resql) {
11267 while ($obj = $db->fetch_object($resql)) {
11268 $dictvalues[$obj->$rowidfield] = $obj; // $obj is stdClass
11269 }
11270 } else {
11271 dol_print_error($db);
11272 }
11273
11274 $conf->cache['dictvalues_'.$tablename] = $dictvalues;
11275 }
11276
11277 if (!empty($dictvalues[$id])) {
11278 // Found
11279 $tmp = $dictvalues[$id];
11280 return (property_exists($tmp, $field) ? $tmp->$field : '');
11281 } else {
11282 // Not found
11283 return '';
11284 }
11285}
11286
11293function colorIsLight($stringcolor)
11294{
11295 $stringcolor = str_replace('#', '', $stringcolor);
11296 $res = -1;
11297 if (!empty($stringcolor)) {
11298 $res = 0;
11299 $tmp = explode(',', $stringcolor);
11300 if (count($tmp) > 1) { // This is a comma RGB ('255','255','255')
11301 $r = $tmp[0];
11302 $g = $tmp[1];
11303 $b = $tmp[2];
11304 } else {
11305 $hexr = $stringcolor[0].$stringcolor[1];
11306 $hexg = $stringcolor[2].$stringcolor[3];
11307 $hexb = $stringcolor[4].$stringcolor[5];
11308 $r = hexdec($hexr);
11309 $g = hexdec($hexg);
11310 $b = hexdec($hexb);
11311 }
11312 $bright = (max($r, $g, $b) + min($r, $g, $b)) / 510.0; // HSL algorithm
11313 if ($bright > 0.6) {
11314 $res = 1;
11315 }
11316 }
11317 return $res;
11318}
11319
11328function isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
11329{
11330 global $conf;
11331
11332 //print 'type_user='.$type_user.' module='.$menuentry['module'].' enabled='.$menuentry['enabled'].' perms='.$menuentry['perms'];
11333 //print 'ok='.in_array($menuentry['module'], $listofmodulesforexternal);
11334 if (empty($menuentry['enabled'])) {
11335 return 0; // Entry disabled by condition
11336 }
11337 if ($type_user && $menuentry['module']) {
11338 $tmploops = explode('|', $menuentry['module']);
11339 $found = 0;
11340 foreach ($tmploops as $tmploop) {
11341 if (in_array($tmploop, $listofmodulesforexternal)) {
11342 $found++;
11343 break;
11344 }
11345 }
11346 if (!$found) {
11347 return 0; // Entry is for menus all excluded to external users
11348 }
11349 }
11350 if (!$menuentry['perms'] && $type_user) {
11351 return 0; // No permissions and user is external
11352 }
11353 if (!$menuentry['perms'] && getDolGlobalString('MAIN_MENU_HIDE_UNAUTHORIZED')) {
11354 return 0; // No permissions and option to hide when not allowed, even for internal user, is on
11355 }
11356 if (!$menuentry['perms']) {
11357 return 2; // No permissions and user is external
11358 }
11359 return 1;
11360}
11361
11369function roundUpToNextMultiple($n, $x = 5)
11370{
11371 return (ceil($n) % $x === 0) ? ceil($n) : round(($n + $x / 2) / $x) * $x;
11372}
11373
11385function dolGetBadge($label, $html = '', $type = 'primary', $mode = '', $url = '', $params = array())
11386{
11387 $attr = array(
11388 'class'=>'badge '.(!empty($mode) ? ' badge-'.$mode : '').(!empty($type) ? ' badge-'.$type : '').(empty($params['css']) ? '' : ' '.$params['css'])
11389 );
11390
11391 if (empty($html)) {
11392 $html = $label;
11393 }
11394
11395 if (!empty($url)) {
11396 $attr['href'] = $url;
11397 }
11398
11399 if ($mode === 'dot') {
11400 $attr['class'] .= ' classfortooltip';
11401 $attr['title'] = $html;
11402 $attr['aria-label'] = $label;
11403 $html = '';
11404 }
11405
11406 // Override attr
11407 if (!empty($params['attr']) && is_array($params['attr'])) {
11408 foreach ($params['attr'] as $key => $value) {
11409 if ($key == 'class') {
11410 $attr['class'] .= ' '.$value;
11411 } elseif ($key == 'classOverride') {
11412 $attr['class'] = $value;
11413 } else {
11414 $attr[$key] = $value;
11415 }
11416 }
11417 }
11418
11419 // TODO: add hook
11420
11421 // escape all attribute
11422 $attr = array_map('dol_escape_htmltag', $attr);
11423
11424 $TCompiledAttr = array();
11425 foreach ($attr as $key => $value) {
11426 $TCompiledAttr[] = $key.'="'.$value.'"';
11427 }
11428
11429 $compiledAttributes = !empty($TCompiledAttr) ? implode(' ', $TCompiledAttr) : '';
11430
11431 $tag = !empty($url) ? 'a' : 'span';
11432
11433 return '<'.$tag.' '.$compiledAttributes.'>'.$html.'</'.$tag.'>';
11434}
11435
11436
11449function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $statusType = 'status0', $displayMode = 0, $url = '', $params = array())
11450{
11451 global $conf;
11452
11453 $return = '';
11454 $dolGetBadgeParams = array();
11455
11456 if (!empty($params['badgeParams'])) {
11457 $dolGetBadgeParams = $params['badgeParams'];
11458 }
11459
11460 // TODO : add a hook
11461 if ($displayMode == 0) {
11462 $return = !empty($html) ? $html : (empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort));
11463 } elseif ($displayMode == 1) {
11464 $return = !empty($html) ? $html : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11465 } elseif (getDolGlobalString('MAIN_STATUS_USES_IMAGES')) {
11466 // Use status with images (for backward compatibility)
11467 $return = '';
11468 $htmlLabel = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : $statusLabel).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
11469 $htmlLabelShort = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : (!empty($statusLabelShort) ? $statusLabelShort : $statusLabel)).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
11470
11471 // For small screen, we always use the short label instead of long label.
11472 if (!empty($conf->dol_optimize_smallscreen)) {
11473 if ($displayMode == 0) {
11474 $displayMode = 1;
11475 } elseif ($displayMode == 4) {
11476 $displayMode = 2;
11477 } elseif ($displayMode == 6) {
11478 $displayMode = 5;
11479 }
11480 }
11481
11482 // For backward compatibility. Image's filename are still in French, so we use this array to convert
11483 $statusImg = array(
11484 'status0' => 'statut0',
11485 'status1' => 'statut1',
11486 'status2' => 'statut2',
11487 'status3' => 'statut3',
11488 'status4' => 'statut4',
11489 'status5' => 'statut5',
11490 'status6' => 'statut6',
11491 'status7' => 'statut7',
11492 'status8' => 'statut8',
11493 'status9' => 'statut9'
11494 );
11495
11496 if (!empty($statusImg[$statusType])) {
11497 $htmlImg = img_picto($statusLabel, $statusImg[$statusType]);
11498 } else {
11499 $htmlImg = img_picto($statusLabel, $statusType);
11500 }
11501
11502 if ($displayMode === 2) {
11503 $return = $htmlImg.' '.$htmlLabelShort;
11504 } elseif ($displayMode === 3) {
11505 $return = $htmlImg;
11506 } elseif ($displayMode === 4) {
11507 $return = $htmlImg.' '.$htmlLabel;
11508 } elseif ($displayMode === 5) {
11509 $return = $htmlLabelShort.' '.$htmlImg;
11510 } else { // $displayMode >= 6
11511 $return = $htmlLabel.' '.$htmlImg;
11512 }
11513 } elseif (!getDolGlobalString('MAIN_STATUS_USES_IMAGES') && !empty($displayMode)) {
11514 // Use new badge
11515 $statusLabelShort = (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11516
11517 $dolGetBadgeParams['attr']['class'] = 'badge-status';
11518 $dolGetBadgeParams['attr']['title'] = empty($params['tooltip']) ? $statusLabel : ($params['tooltip'] != 'no' ? $params['tooltip'] : '');
11519
11520 if ($displayMode == 3) {
11521 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), '', $statusType, 'dot', $url, $dolGetBadgeParams);
11522 } elseif ($displayMode === 5) {
11523 $return = dolGetBadge($statusLabelShort, $html, $statusType, '', $url, $dolGetBadgeParams);
11524 } else {
11525 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), $html, $statusType, '', $url, $dolGetBadgeParams);
11526 }
11527 }
11528
11529 return $return;
11530}
11531
11532
11567function dolGetButtonAction($label, $text = '', $actionType = 'default', $url = '', $id = '', $userRight = 1, $params = array())
11568{
11569 global $hookmanager, $action, $object, $langs;
11570
11571 // If $url is an array, we must build a dropdown button
11572 if (is_array($url)) {
11573 // Loop on $url array to remove entries of disabled modules
11574 foreach ($url as $key => $subbutton) {
11575 if (isset($subbutton['enabled']) && empty($subbutton['enabled'])) {
11576 unset($url[$key]);
11577 }
11578 }
11579
11580 $out = '';
11581
11582 if (count($url) > 1) {
11583 $out .= '<div class="dropdown inline-block dropdown-holder">';
11584 $out .= '<a style="margin-right: auto;" class="dropdown-toggle classfortooltip butAction'.($userRight ? '' : 'Refused').'" title="'.dol_escape_htmltag($label).'" data-toggle="dropdown">'.($text ? $text : $label).'</a>';
11585 $out .= '<div class="dropdown-content">';
11586 foreach ($url as $subbutton) {
11587 if (!empty($subbutton['lang'])) {
11588 $langs->load($subbutton['lang']);
11589 }
11590 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
11591 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm'], array('isDropDown' => true));
11592 }
11593 $out .= "</div>";
11594 $out .= "</div>";
11595 } else {
11596 foreach ($url as $subbutton) { // Should loop on 1 record only
11597 if (!empty($subbutton['lang'])) {
11598 $langs->load($subbutton['lang']);
11599 }
11600 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
11601 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm']);
11602 }
11603 }
11604
11605 return $out;
11606 }
11607
11608 // Here, $url is a simple link
11609
11610 if (!empty($params['isDropdown'])) {
11611 $class = "dropdown-item";
11612 } else {
11613 $class = 'butAction';
11614 if ($actionType == 'danger' || $actionType == 'delete') {
11615 $class = 'butActionDelete';
11616 if (!empty($url) && strpos($url, 'token=') === false) {
11617 $url .= '&token='.newToken();
11618 }
11619 }
11620 }
11621 $attr = array(
11622 'class' => $class,
11623 'href' => empty($url) ? '' : $url,
11624 'title' => $label
11625 );
11626
11627 if (empty($text)) {
11628 $text = $label;
11629 $attr['title'] = ''; // if html not set, leave label on title is redundant
11630 } else {
11631 $attr['title'] = $label;
11632 $attr['aria-label'] = $label;
11633 }
11634
11635 if (empty($userRight)) {
11636 $attr['class'] = 'butActionRefused';
11637 $attr['href'] = '';
11638 $attr['title'] = (($label && $text && $label != $text) ? $label : $langs->trans('NotEnoughPermissions'));
11639 }
11640
11641 if (!empty($id)) {
11642 $attr['id'] = $id;
11643 }
11644
11645 // Override attr
11646 if (!empty($params['attr']) && is_array($params['attr'])) {
11647 foreach ($params['attr'] as $key => $value) {
11648 if ($key == 'class') {
11649 $attr['class'] .= ' '.$value;
11650 } elseif ($key == 'classOverride') {
11651 $attr['class'] = $value;
11652 } else {
11653 $attr[$key] = $value;
11654 }
11655 }
11656 }
11657
11658 // automatic add tooltip when title is detected
11659 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
11660 $attr['class'].= ' classfortooltip';
11661 }
11662
11663 // Js Confirm button
11664 if ($userRight && !empty($params['confirm'])) {
11665 if (!is_array($params['confirm'])) {
11666 $params['confirm'] = array();
11667 }
11668
11669 if (empty($params['confirm']['url'])) {
11670 $params['confirm']['url'] = $url . (strpos($url, '?') > 0 ? '&' : '?') . 'confirm=yes';
11671 }
11672
11673 // for js desabled compatibility set $url as call to confirm action and $params['confirm']['url'] to confirmed action
11674 $attr['data-confirm-url'] = $params['confirm']['url'];
11675 $attr['data-confirm-title'] = !empty($params['confirm']['title']) ? $params['confirm']['title'] : $langs->trans('ConfirmBtnCommonTitle', $label);
11676 $attr['data-confirm-content'] = !empty($params['confirm']['content']) ? $params['confirm']['content'] : $langs->trans('ConfirmBtnCommonContent', $label);
11677 $attr['data-confirm-content'] = preg_replace("/\r|\n/", "", $attr['data-confirm-content']);
11678 $attr['data-confirm-action-btn-label'] = !empty($params['confirm']['action-btn-label']) ? $params['confirm']['action-btn-label'] : $langs->trans('Confirm');
11679 $attr['data-confirm-cancel-btn-label'] = !empty($params['confirm']['cancel-btn-label']) ? $params['confirm']['cancel-btn-label'] : $langs->trans('CloseDialog');
11680 $attr['data-confirm-modal'] = !empty($params['confirm']['modal']) ? $params['confirm']['modal'] : true;
11681
11682 $attr['class'].= ' butActionConfirm';
11683 }
11684
11685 if (isset($attr['href']) && empty($attr['href'])) {
11686 unset($attr['href']);
11687 }
11688
11689 // escape all attribute
11690 $attr = array_map('dol_escape_htmltag', $attr);
11691
11692 $TCompiledAttr = array();
11693 foreach ($attr as $key => $value) {
11694 $TCompiledAttr[] = $key.'= "'.$value.'"';
11695 }
11696
11697 $compiledAttributes = empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr);
11698
11699 $tag = !empty($attr['href']) ? 'a' : 'span';
11700
11701
11702 $parameters = array(
11703 'TCompiledAttr' => $TCompiledAttr, // array
11704 'compiledAttributes' => $compiledAttributes, // string
11705 'attr' => $attr,
11706 'tag' => $tag,
11707 'label' => $label,
11708 'html' => $text,
11709 'actionType' => $actionType,
11710 'url' => $url,
11711 'id' => $id,
11712 'userRight' => $userRight,
11713 'params' => $params
11714 );
11715
11716 $reshook = $hookmanager->executeHooks('dolGetButtonAction', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
11717 if ($reshook < 0) {
11718 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
11719 }
11720
11721 if (empty($reshook)) {
11722 if (dol_textishtml($text)) { // If content already HTML encoded
11723 return '<' . $tag . ' ' . $compiledAttributes . '>' . $text . '</' . $tag . '>';
11724 } else {
11725 return '<' . $tag . ' ' . $compiledAttributes . '>' . dol_escape_htmltag($text) . '</' . $tag . '>';
11726 }
11727 } else {
11728 return $hookmanager->resPrint;
11729 }
11730}
11731
11738function dolGetButtonTitleSeparator($moreClass = "")
11739{
11740 return '<span class="button-title-separator '.$moreClass.'" ></span>';
11741}
11742
11749function getFieldErrorIcon($fieldValidationErrorMsg)
11750{
11751 $out = '';
11752 if (!empty($fieldValidationErrorMsg)) {
11753 $out.= '<span class="field-error-icon classfortooltip" title="'.dol_escape_htmltag($fieldValidationErrorMsg, 1).'" role="alert" >'; // role alert is used for accessibility
11754 $out.= '<span class="fa fa-exclamation-circle" aria-hidden="true" ></span>'; // For accessibility icon is separated and aria-hidden
11755 $out.= '</span>';
11756 }
11757
11758 return $out;
11759}
11760
11773function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $url = '', $id = '', $status = 1, $params = array())
11774{
11775 global $langs, $conf, $user;
11776
11777 // Actually this conf is used in css too for external module compatibility and smooth transition to this function
11778 if (getDolGlobalString('MAIN_BUTTON_HIDE_UNAUTHORIZED') && (!$user->admin) && $status <= 0) {
11779 return '';
11780 }
11781
11782 $class = 'btnTitle';
11783 if (in_array($iconClass, array('fa fa-plus-circle', 'fa fa-plus-circle size15x', 'fa fa-comment-dots', 'fa fa-paper-plane'))) {
11784 $class .= ' btnTitlePlus';
11785 }
11786 $useclassfortooltip = 1;
11787
11788 if (!empty($params['morecss'])) {
11789 $class .= ' '.$params['morecss'];
11790 }
11791
11792 $attr = array(
11793 'class' => $class,
11794 'href' => empty($url) ? '' : $url
11795 );
11796
11797 if (!empty($helpText)) {
11798 $attr['title'] = dol_escape_htmltag($helpText);
11799 } elseif (empty($attr['title']) && $label) {
11800 $attr['title'] = $label;
11801 $useclassfortooltip = 0;
11802 }
11803
11804 if ($status == 2) {
11805 $attr['class'] .= ' btnTitleSelected';
11806 } elseif ($status <= 0) {
11807 $attr['class'] .= ' refused';
11808
11809 $attr['href'] = '';
11810
11811 if ($status == -1) { // disable
11812 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("FeatureDisabled"));
11813 } elseif ($status == 0) { // Not enough permissions
11814 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions"));
11815 }
11816 }
11817
11818 if (!empty($attr['title']) && $useclassfortooltip) {
11819 $attr['class'] .= ' classfortooltip';
11820 }
11821
11822 if (!empty($id)) {
11823 $attr['id'] = $id;
11824 }
11825
11826 // Override attr
11827 if (!empty($params['attr']) && is_array($params['attr'])) {
11828 foreach ($params['attr'] as $key => $value) {
11829 if ($key == 'class') {
11830 $attr['class'] .= ' '.$value;
11831 } elseif ($key == 'classOverride') {
11832 $attr['class'] = $value;
11833 } else {
11834 $attr[$key] = $value;
11835 }
11836 }
11837 }
11838
11839 if (isset($attr['href']) && empty($attr['href'])) {
11840 unset($attr['href']);
11841 }
11842
11843 // TODO : add a hook
11844
11845 // escape all attribute
11846 $attr = array_map('dol_escape_htmltag', $attr);
11847
11848 $TCompiledAttr = array();
11849 foreach ($attr as $key => $value) {
11850 $TCompiledAttr[] = $key.'="'.$value.'"';
11851 }
11852
11853 $compiledAttributes = (empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr));
11854
11855 $tag = (empty($attr['href']) ? 'span' : 'a');
11856
11857 $button = '<'.$tag.' '.$compiledAttributes.'>';
11858 $button .= '<span class="'.$iconClass.' valignmiddle btnTitle-icon"></span>';
11859 if (!empty($params['forcenohideoftext'])) {
11860 $button .= '<span class="valignmiddle text-plus-circle btnTitle-label'.(empty($params['forcenohideoftext']) ? ' hideonsmartphone' : '').'">'.$label.'</span>';
11861 }
11862 $button .= '</'.$tag.'>';
11863
11864 return $button;
11865}
11866
11877function getElementProperties($element_type)
11878{
11879 global $conf, $db, $hookmanager;
11880
11881 $regs = array();
11882
11883 //$element_type='facture';
11884
11885 $classfile = $classname = $classpath = $subdir = $dir_output = '';
11886
11887 // Parse element/subelement
11888 $module = $element_type;
11889 $element = $element_type;
11890 $subelement = $element_type;
11891 $table_element = $element_type;
11892
11893 // If we ask a resource form external module (instead of default path)
11894 if (preg_match('/^([^@]+)@([^@]+)$/i', $element_type, $regs)) { // 'myobject@mymodule'
11895 $element = $subelement = $regs[1];
11896 $module = $regs[2];
11897 }
11898
11899 // If we ask a resource for a string with an element and a subelement
11900 // Example 'project_task'
11901 if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { // 'myobject_mysubobject' with myobject=mymodule
11902 $module = $element = $regs[1];
11903 $subelement = $regs[2];
11904 }
11905
11906 // For compatibility and to work with non standard path
11907 if ($element_type == "action" || $element_type == "actioncomm") {
11908 $classpath = 'comm/action/class';
11909 $subelement = 'Actioncomm';
11910 $module = 'agenda';
11911 $table_element = 'actioncomm';
11912 } elseif ($element_type == 'cronjob') {
11913 $classpath = 'cron/class';
11914 $module = 'cron';
11915 $table_element = 'cron';
11916 } elseif ($element_type == 'adherent_type') {
11917 $classpath = 'adherents/class';
11918 $classfile = 'adherent_type';
11919 $module = 'adherent';
11920 $subelement = 'adherent_type';
11921 $classname = 'AdherentType';
11922 $table_element = 'adherent_type';
11923 } elseif ($element_type == 'bank_account') {
11924 $classpath = 'compta/bank/class';
11925 $module = 'bank'; // We need $conf->bank->dir_output and not $conf->banque->dir_output
11926 $classfile = 'account';
11927 $classname = 'Account';
11928 } elseif ($element_type == 'category') {
11929 $classpath = 'categories/class';
11930 $module = 'categorie';
11931 $subelement = 'categorie';
11932 $table_element = 'categorie';
11933 } elseif ($element_type == 'contact') {
11934 $classpath = 'contact/class';
11935 $classfile = 'contact';
11936 $module = 'societe';
11937 $subelement = 'contact';
11938 $table_element = 'socpeople';
11939 } elseif ($element_type == 'inventory') {
11940 $module = 'product';
11941 $classpath = 'product/inventory/class';
11942 } elseif ($element_type == 'stock' || $element_type == 'entrepot') {
11943 $module = 'stock';
11944 $classpath = 'product/stock/class';
11945 $classfile = 'entrepot';
11946 $classname = 'Entrepot';
11947 $table_element = 'entrepot';
11948 } elseif ($element_type == 'project') {
11949 $classpath = 'projet/class';
11950 $module = 'projet';
11951 $table_element = 'projet';
11952 } elseif ($element_type == 'project_task') {
11953 $classpath = 'projet/class';
11954 $module = 'projet';
11955 $subelement = 'task';
11956 $table_element = 'projet_task';
11957 } elseif ($element_type == 'facture' || $element_type == 'invoice') {
11958 $classpath = 'compta/facture/class';
11959 $module = 'facture';
11960 $subelement = 'facture';
11961 $table_element = 'facture';
11962 } elseif ($element_type == 'commande' || $element_type == 'order') {
11963 $classpath = 'commande/class';
11964 $module = 'commande';
11965 $subelement = 'commande';
11966 $table_element = 'commande';
11967 } elseif ($element_type == 'propal') {
11968 $classpath = 'comm/propal/class';
11969 $table_element = 'propal';
11970 } elseif ($element_type == 'shipping') {
11971 $classpath = 'expedition/class';
11972 $classfile = 'expedition';
11973 $classname = 'Expedition';
11974 $module = 'expedition';
11975 $table_element = 'expedition';
11976 } elseif ($element_type == 'supplier_proposal') {
11977 $classpath = 'supplier_proposal/class';
11978 $module = 'supplier_proposal';
11979 $element = 'supplierproposal';
11980 $classfile = 'supplier_proposal';
11981 $subelement = 'supplierproposal';
11982 } elseif ($element_type == 'shipping') {
11983 $classpath = 'expedition/class';
11984 $subelement = 'expedition';
11985 $module = 'expedition_bon';
11986 } elseif ($element_type == 'delivery') {
11987 $classpath = 'delivery/class';
11988 $subelement = 'delivery';
11989 $module = 'expedition';
11990 } elseif ($element_type == 'contract') {
11991 $classpath = 'contrat/class';
11992 $module = 'contrat';
11993 $subelement = 'contrat';
11994 $table_element = 'contract';
11995 } elseif ($element_type == 'mailing') {
11996 $classpath = 'comm/mailing/class';
11997 $module = 'mailing';
11998 $classfile = 'mailing';
11999 $classname = 'Mailing';
12000 $subelement = '';
12001 } elseif ($element_type == 'member') {
12002 $classpath = 'adherents/class';
12003 $module = 'adherent';
12004 $subelement = 'adherent';
12005 $table_element = 'adherent';
12006 } elseif ($element_type == 'usergroup') {
12007 $classpath = 'user/class';
12008 $module = 'user';
12009 } elseif ($element_type == 'mo') {
12010 $classpath = 'mrp/class';
12011 $classfile = 'mo';
12012 $classname = 'Mo';
12013 $module = 'mrp';
12014 $subelement = '';
12015 $table_element = 'mrp_mo';
12016 } elseif ($element_type == 'cabinetmed_cons') {
12017 $classpath = 'cabinetmed/class';
12018 $module = 'cabinetmed';
12019 $subelement = 'cabinetmedcons';
12020 $table_element = 'cabinetmedcons';
12021 } elseif ($element_type == 'fichinter') {
12022 $classpath = 'fichinter/class';
12023 $module = 'ficheinter';
12024 $subelement = 'fichinter';
12025 $table_element = 'fichinter';
12026 } elseif ($element_type == 'dolresource' || $element_type == 'resource') {
12027 $classpath = 'resource/class';
12028 $module = 'resource';
12029 $subelement = 'dolresource';
12030 $table_element = 'resource';
12031 } elseif ($element_type == 'propaldet') {
12032 $classpath = 'comm/propal/class';
12033 $module = 'propal';
12034 $subelement = 'propaleligne';
12035 } elseif ($element_type == 'opensurvey_sondage') {
12036 $classpath = 'opensurvey/class';
12037 $module = 'opensurvey';
12038 $subelement = 'opensurveysondage';
12039 } elseif ($element_type == 'order_supplier') {
12040 $classpath = 'fourn/class';
12041 $module = 'fournisseur';
12042 $classfile = 'fournisseur.commande';
12043 $element = 'order_supplier';
12044 $subelement = '';
12045 $classname = 'CommandeFournisseur';
12046 $table_element = 'commande_fournisseur';
12047 } elseif ($element_type == 'commande_fournisseurdet') {
12048 $classpath = 'fourn/class';
12049 $module = 'fournisseur';
12050 $classfile = 'fournisseur.commande';
12051 $element = 'commande_fournisseurdet';
12052 $subelement = '';
12053 $classname = 'CommandeFournisseurLigne';
12054 $table_element = 'commande_fournisseurdet';
12055 } elseif ($element_type == 'invoice_supplier') {
12056 $classpath = 'fourn/class';
12057 $module = 'fournisseur';
12058 $classfile = 'fournisseur.facture';
12059 $element = 'invoice_supplier';
12060 $subelement = '';
12061 $classname = 'FactureFournisseur';
12062 $table_element = 'facture_fourn';
12063 } elseif ($element_type == "service") {
12064 $classpath = 'product/class';
12065 $subelement = 'product';
12066 $table_element = 'product';
12067 } elseif ($element_type == 'salary') {
12068 $classpath = 'salaries/class';
12069 $module = 'salaries';
12070 } elseif ($element_type == 'payment_salary') {
12071 $classpath = 'salaries/class';
12072 $classfile = 'paymentsalary';
12073 $classname = 'PaymentSalary';
12074 $module = 'salaries';
12075 } elseif ($element_type == 'productlot') {
12076 $module = 'productbatch';
12077 $classpath = 'product/stock/class';
12078 $classfile = 'productlot';
12079 $classname = 'Productlot';
12080 $element = 'productlot';
12081 $subelement = '';
12082 $table_element = 'product_lot';
12083 } elseif ($element_type == 'websitepage') {
12084 $classpath = 'website/class';
12085 $classfile = 'websitepage';
12086 $classname = 'Websitepage';
12087 $module = 'website';
12088 $subelement = 'websitepage';
12089 $table_element = 'website_page';
12090 } elseif ($element_type == 'fiscalyear') {
12091 $classpath = 'core/class';
12092 $module = 'accounting';
12093 $subelement = 'fiscalyear';
12094 } elseif ($element_type == 'chargesociales') {
12095 $classpath = 'compta/sociales/class';
12096 $module = 'tax';
12097 $table_element = 'chargesociales';
12098 } elseif ($element_type == 'tva') {
12099 $classpath = 'compta/tva/class';
12100 $module = 'tax';
12101 $subdir = '/vat';
12102 $table_element = 'tva';
12103 } elseif ($element_type == 'emailsenderprofile') {
12104 $module = '';
12105 $classpath = 'core/class';
12106 $classfile = 'emailsenderprofile';
12107 $classname = 'EmailSenderProfile';
12108 $table_element = 'c_email_senderprofile';
12109 $subelement = '';
12110 } elseif ($element_type == 'ccountry') {
12111 $module = '';
12112 $classpath = 'core/class';
12113 $classfile = 'ccountry';
12114 $classname = 'Ccountry';
12115 $table_element = 'c_country';
12116 $subelement = '';
12117 }
12118
12119 if (empty($classfile)) {
12120 $classfile = strtolower($subelement);
12121 }
12122 if (empty($classname)) {
12123 $classname = ucfirst($subelement);
12124 }
12125 if (empty($classpath)) {
12126 $classpath = $module.'/class';
12127 }
12128
12129 //print 'getElementProperties subdir='.$subdir;
12130
12131 // Set dir_output
12132 if ($module && isset($conf->$module)) { // The generic case
12133 if (!empty($conf->$module->multidir_output[$conf->entity])) {
12134 $dir_output = $conf->$module->multidir_output[$conf->entity];
12135 } elseif (!empty($conf->$module->output[$conf->entity])) {
12136 $dir_output = $conf->$module->output[$conf->entity];
12137 } elseif (!empty($conf->$module->dir_output)) {
12138 $dir_output = $conf->$module->dir_output;
12139 }
12140 }
12141
12142 // Overwrite value for special cases
12143 if ($element == 'order_supplier') {
12144 $dir_output = $conf->fournisseur->commande->dir_output;
12145 } elseif ($element == 'invoice_supplier') {
12146 $dir_output = $conf->fournisseur->facture->dir_output;
12147 }
12148 $dir_output .= $subdir;
12149
12150 $elementProperties = array(
12151 'module' => $module,
12152 'element' => $element,
12153 'table_element' => $table_element,
12154 'subelement' => $subelement,
12155 'classpath' => $classpath,
12156 'classfile' => $classfile,
12157 'classname' => $classname,
12158 'dir_output' => $dir_output
12159 );
12160
12161
12162 // Add hook
12163 if (!is_object($hookmanager)) {
12164 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
12165 $hookmanager = new HookManager($db);
12166 }
12167 $hookmanager->initHooks(array('elementproperties'));
12168
12169
12170 // Hook params
12171 $parameters = array(
12172 'elementType' => $element_type,
12173 'elementProperties' => $elementProperties
12174 );
12175
12176 $reshook = $hookmanager->executeHooks('getElementProperties', $parameters);
12177
12178 if ($reshook) {
12179 $elementProperties = $hookmanager->resArray;
12180 } elseif (!empty($hookmanager->resArray) && is_array($hookmanager->resArray)) { // resArray is always an array but for sécurity against misconfigured external modules
12181 $elementProperties = array_replace($elementProperties, $hookmanager->resArray);
12182 }
12183
12184 // context of elementproperties doesn't need to exist out of this function so delete it to avoid elementproperties context is equal to all
12185 if (($key = array_search('elementproperties', $hookmanager->contextarray)) !== false) {
12186 unset($hookmanager->contextarray[$key]);
12187 }
12188
12189 return $elementProperties;
12190}
12191
12202function fetchObjectByElement($element_id, $element_type, $element_ref = '')
12203{
12204 global $db;
12205
12206 $ret = 0;
12207
12208 $element_prop = getElementProperties($element_type);
12209
12210 if ($element_prop['module'] == 'product' || $element_prop['module'] == 'service') {
12211 // For example, for an extrafield 'product' (shared for both product and service) that is a link to an object,
12212 // this is called with $element_type = 'product' when we need element properties of a service, we must return a product. If we create the
12213 // extrafield for a service, it is not supported and not found when editing the product/service card. So we must keep 'product' for extrafields
12214 // of service and we will return properties of a product.
12215 $ismodenabled = (isModEnabled('product') || isModEnabled('service'));
12216 } else {
12217 $ismodenabled = isModEnabled($element_prop['module']);
12218 }
12219 //var_dump('element_type='.$element_type);
12220 //var_dump($element_prop);
12221 //var_dump($element_prop['module'].' '.$ismodenabled);
12222 if (is_array($element_prop) && (empty($element_prop['module']) || $ismodenabled)) {
12223 dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php');
12224
12225 if (class_exists($element_prop['classname'])) {
12226 $classname = $element_prop['classname'];
12227 $objecttmp = new $classname($db);
12228
12229 if ($element_id > 0 || !empty($element_ref)) {
12230 $ret = $objecttmp->fetch($element_id, $element_ref);
12231 if ($ret >= 0) {
12232 if (empty($objecttmp->module)) {
12233 $objecttmp->module = $element_prop['module'];
12234 }
12235 return $objecttmp;
12236 }
12237 } else {
12238 return $objecttmp; // returned an object without fetch
12239 }
12240 } else {
12241 return -1;
12242 }
12243 }
12244
12245 return $ret;
12246}
12247
12255{
12256 if (preg_match('/\.(htm|html|js|phar|php|php\d+|phtml|pht|pl|py|cgi|ksh|sh|shtml|bash|bat|cmd|wpk|exe|dmg)$/i', $filename)) {
12257 return true;
12258 }
12259
12260 return false;
12261}
12262
12270function newToken()
12271{
12272 return empty($_SESSION['newtoken']) ? '' : $_SESSION['newtoken'];
12273}
12274
12283{
12284 return isset($_SESSION['token']) ? $_SESSION['token'] : '';
12285}
12286
12292function getNonce()
12293{
12294 global $conf;
12295
12296 if (empty($conf->cache['nonce'])) {
12297 $conf->cache['nonce'] = dolGetRandomBytes(8);
12298 }
12299
12300 return $conf->cache['nonce'];
12301}
12302
12303
12316function startSimpleTable($header, $link = "", $arguments = "", $emptyRows = 0, $number = -1)
12317{
12318 global $langs;
12319
12320 print '<div class="div-table-responsive-no-min">';
12321 print '<table class="noborder centpercent">';
12322 print '<tr class="liste_titre">';
12323
12324 print $emptyRows < 1 ? '<th>' : '<th colspan="'.($emptyRows + 1).'">';
12325
12326 print $langs->trans($header);
12327
12328 // extra space between the first header and the number
12329 if ($number > -1) {
12330 print ' ';
12331 }
12332
12333 if (!empty($link)) {
12334 if (!empty($arguments)) {
12335 print '<a href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
12336 } else {
12337 print '<a href="'.DOL_URL_ROOT.'/'.$link.'">';
12338 }
12339 }
12340
12341 if ($number > -1) {
12342 print '<span class="badge">'.$number.'</span>';
12343 }
12344
12345 if (!empty($link)) {
12346 print '</a>';
12347 }
12348
12349 print '</th>';
12350
12351 if ($number < 0 && !empty($link)) {
12352 print '<th class="right">';
12353
12354 if (!empty($arguments)) {
12355 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
12356 } else {
12357 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'">';
12358 }
12359
12360 print $langs->trans("FullList");
12361 print '</a>';
12362 print '</th>';
12363 }
12364
12365 print '</tr>';
12366}
12367
12376function finishSimpleTable($addLineBreak = false)
12377{
12378 print '</table>';
12379 print '</div>';
12380
12381 if ($addLineBreak) {
12382 print '<br>';
12383 }
12384}
12385
12397function addSummaryTableLine($tableColumnCount, $num, $nbofloop = 0, $total = 0, $noneWord = "None", $extraRightColumn = false)
12398{
12399 global $langs;
12400
12401 if ($num === 0) {
12402 print '<tr class="oddeven">';
12403 print '<td colspan="'.$tableColumnCount.'"><span class="opacitymedium">'.$langs->trans($noneWord).'</span></td>';
12404 print '</tr>';
12405 return;
12406 }
12407
12408 if ($nbofloop === 0) {
12409 // don't show a summary line
12410 return;
12411 }
12412
12413 if ($num === 0) {
12414 $colspan = $tableColumnCount;
12415 } elseif ($num > $nbofloop) {
12416 $colspan = $tableColumnCount;
12417 } else {
12418 $colspan = $tableColumnCount - 1;
12419 }
12420
12421 if ($extraRightColumn) {
12422 $colspan--;
12423 }
12424
12425 print '<tr class="liste_total">';
12426
12427 if ($nbofloop > 0 && $num > $nbofloop) {
12428 print '<td colspan="'.$colspan.'" class="right">'.$langs->trans("XMoreLines", ($num - $nbofloop)).'</td>';
12429 } else {
12430 print '<td colspan="'.$colspan.'" class="right"> '.$langs->trans("Total").'</td>';
12431 print '<td class="right centpercent">'.price($total).'</td>';
12432 }
12433
12434 if ($extraRightColumn) {
12435 print '<td></td>';
12436 }
12437
12438 print '</tr>';
12439}
12440
12449function readfileLowMemory($fullpath_original_file_osencoded, $method = -1)
12450{
12451 if ($method == -1) {
12452 $method = 0;
12453 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_FREAD')) {
12454 $method = 1;
12455 }
12456 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_STREAM_COPY')) {
12457 $method = 2;
12458 }
12459 }
12460
12461 // Be sure we don't have output buffering enabled to have readfile working correctly
12462 while (ob_get_level()) {
12463 ob_end_flush();
12464 }
12465
12466 // Solution 0
12467 if ($method == 0) {
12468 readfile($fullpath_original_file_osencoded);
12469 } elseif ($method == 1) {
12470 // Solution 1
12471 $handle = fopen($fullpath_original_file_osencoded, "rb");
12472 while (!feof($handle)) {
12473 print fread($handle, 8192);
12474 }
12475 fclose($handle);
12476 } elseif ($method == 2) {
12477 // Solution 2
12478 $handle1 = fopen($fullpath_original_file_osencoded, "rb");
12479 $handle2 = fopen("php://output", "wb");
12480 stream_copy_to_stream($handle1, $handle2);
12481 fclose($handle1);
12482 fclose($handle2);
12483 }
12484}
12485
12495function showValueWithClipboardCPButton($valuetocopy, $showonlyonhover = 1, $texttoshow = '')
12496{
12497 /*
12498 global $conf;
12499
12500 if (!empty($conf->dol_no_mouse_hover)) {
12501 $showonlyonhover = 0;
12502 }*/
12503
12504 $tag = 'span'; // Using div (like any style of type 'block') does not work when using the js copy code.
12505 if ($texttoshow === 'none') {
12506 $result = '<span class="clipboardCP'.($showonlyonhover ? ' clipboardCPShowOnHover' : '').'"><'.$tag.' class="clipboardCPValue hidewithsize">'.dol_escape_htmltag($valuetocopy, 1, 1).'</'.$tag.'><span class="clipboardCPValueToPrint"></span><span class="clipboardCPButton far fa-clipboard opacitymedium paddingleft paddingright"></span><span class="clipboardCPText"></span></span>';
12507 } elseif ($texttoshow) {
12508 $result = '<span class="clipboardCP'.($showonlyonhover ? ' clipboardCPShowOnHover' : '').'"><'.$tag.' class="clipboardCPValue hidewithsize">'.dol_escape_htmltag($valuetocopy, 1, 1).'</'.$tag.'><span class="clipboardCPValueToPrint">'.dol_escape_htmltag($texttoshow, 1, 1).'</span><span class="clipboardCPButton far fa-clipboard opacitymedium paddingleft paddingright"></span><span class="clipboardCPText"></span></span>';
12509 } else {
12510 $result = '<span class="clipboardCP'.($showonlyonhover ? ' clipboardCPShowOnHover' : '').'"><'.$tag.' class="clipboardCPValue">'.dol_escape_htmltag($valuetocopy, 1, 1).'</'.$tag.'><span class="clipboardCPButton far fa-clipboard opacitymedium paddingleft paddingright"></span><span class="clipboardCPText"></span></span>';
12511 }
12512
12513 return $result;
12514}
12515
12516
12523function jsonOrUnserialize($stringtodecode)
12524{
12525 $result = json_decode($stringtodecode);
12526 if ($result === null) {
12527 $result = unserialize($stringtodecode);
12528 }
12529
12530 return $result;
12531}
12532
12533
12547function forgeSQLFromUniversalSearchCriteria($filter, &$errorstr = '', $noand = 0, $nopar = 0, $noerror = 0)
12548{
12549 if (!preg_match('/^\‍(.*\‍)$/', $filter)) { // If $filter does not start and end with ()
12550 $filter = '(' . $filter . ')';
12551 }
12552
12553 $regexstring = '\‍(([a-zA-Z0-9_\.]+:[<>!=insotlke]+:[^\‍(\‍)]+)\‍)'; // Must be (aaa:bbb:...) with aaa is a field name (with alias or not) and bbb is one of this operator '=', '<', '>', '<=', '>=', '!=', 'in', 'notin', 'like', 'notlike', 'is', 'isnot'
12554
12555 if (!dolCheckFilters($filter, $errorstr)) {
12556 if ($noerror) {
12557 return '1 = 2';
12558 } else {
12559 return 'Filter syntax error - '.$errorstr; // Bad balance of parenthesis, we return an error message or force a SQL not found
12560 }
12561 }
12562
12563 // Test the filter syntax
12564 $t = preg_replace_callback('/'.$regexstring.'/i', 'dolForgeDummyCriteriaCallback', $filter);
12565 $t = str_replace(array('and','or','AND','OR',' '), '', $t); // Remove the only strings allowed between each () criteria
12566 // If the string result contains something else than '()', the syntax was wrong
12567 if (preg_match('/[^\‍(\‍)]/', $t)) {
12568 $errorstr = 'Bad syntax of the search string';
12569 if ($noerror) {
12570 return '1 = 2';
12571 } else {
12572 return 'Filter syntax error - '.$errorstr; // Bad syntax of the search string, we return an error message or force a SQL not found
12573 }
12574 }
12575
12576 return ($noand ? "" : " AND ").($nopar ? "" : '(').preg_replace_callback('/'.$regexstring.'/i', 'dolForgeCriteriaCallback', $filter).($nopar ? "" : ')');
12577}
12578
12586function dolCheckFilters($sqlfilters, &$error = '')
12587{
12588 //$regexstring='\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^:\‍(\‍)]+)\‍)';
12589 //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
12590 $tmp = $sqlfilters;
12591 $i = 0;
12592 $nb = strlen($tmp);
12593 $counter = 0;
12594 while ($i < $nb) {
12595 if ($tmp[$i] == '(') {
12596 $counter++;
12597 }
12598 if ($tmp[$i] == ')') {
12599 $counter--;
12600 }
12601 if ($counter < 0) {
12602 $error = "Wrond balance of parenthesis in sqlfilters=".$sqlfilters;
12603 dol_syslog($error, LOG_WARNING);
12604 return false;
12605 }
12606 $i++;
12607 }
12608 return true;
12609}
12610
12619{
12620 //dol_syslog("Convert matches ".$matches[1]);
12621 if (empty($matches[1])) {
12622 return '';
12623 }
12624 $tmp = explode(':', $matches[1]);
12625 if (count($tmp) < 3) {
12626 return '';
12627 }
12628
12629 return '()'; // An empty criteria
12630}
12631
12641{
12642 global $db;
12643
12644 //dol_syslog("Convert matches ".$matches[1]);
12645 if (empty($matches[1])) {
12646 return '';
12647 }
12648 $tmp = explode(':', $matches[1]);
12649 if (count($tmp) < 3) {
12650 return '';
12651 }
12652
12653 $operand = preg_replace('/[^a-z0-9\._]/i', '', trim($tmp[0]));
12654
12655 $operator = strtoupper(preg_replace('/[^a-z<>!=]/i', '', trim($tmp[1])));
12656
12657 $realOperator = [
12658 'NOTLIKE' => 'NOT LIKE',
12659 'ISNOT' => 'IS NOT',
12660 'NOTIN' => 'NOT IN',
12661 '!=' => '<>',
12662 ];
12663
12664 if (array_key_exists($operator, $realOperator)) {
12665 $operator = $realOperator[$operator];
12666 }
12667
12668
12669 $tmpescaped = $tmp[2];
12670 $regbis = array();
12671
12672 if ($operator == 'IN' || $operator == 'NOT IN') { // IN is allowed for list of ID or code only
12673 //if (!preg_match('/^\‍(.*\‍)$/', $tmpescaped)) {
12674 $tmpescaped2 = '(';
12675 // Explode and sanitize each element in list
12676 $tmpelemarray = explode(',', $tmpescaped);
12677 foreach ($tmpelemarray as $tmpkey => $tmpelem) {
12678 $reg = array();
12679 if (preg_match('/^\'(.*)\'$/', $tmpelem, $reg)) {
12680 $tmpelemarray[$tmpkey] = "'".$db->escape($db->sanitize($reg[1], 1, 1, 1))."'";
12681 } else {
12682 $tmpelemarray[$tmpkey] = $db->escape($db->sanitize($tmpelem, 1, 1, 1));
12683 }
12684 }
12685 $tmpescaped2 .= join(',', $tmpelemarray);
12686 $tmpescaped2 .= ')';
12687
12688 $tmpescaped = $tmpescaped2;
12689 } elseif ($operator == 'LIKE' || $operator == 'NOT LIKE') {
12690 if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12691 $tmpescaped = $regbis[1];
12692 }
12693 //$tmpescaped = "'".$db->escape($db->escapeforlike($regbis[1]))."'";
12694 $tmpescaped = "'".$db->escape($tmpescaped)."'"; // We do not escape the _ and % so the like will works
12695 } elseif (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12696 $tmpescaped = "'".$db->escape($regbis[1])."'";
12697 } else {
12698 if (strtoupper($tmpescaped) == 'NULL') {
12699 $tmpescaped = 'NULL';
12700 } elseif (is_int($tmpescaped)) {
12701 $tmpescaped = (int) $tmpescaped;
12702 } else {
12703 $tmpescaped = (float) $tmpescaped;
12704 }
12705 }
12706
12707 return '('.$db->escape($operand).' '.strtoupper($operator).' '.$tmpescaped.')';
12708}
12709
12710
12720function getTimelineIcon($actionstatic, &$histo, $key)
12721{
12722 global $conf, $langs;
12723
12724 $out = '<!-- timeline icon -->'."\n";
12725 $iconClass = 'fa fa-comments';
12726 $img_picto = '';
12727 $colorClass = '';
12728 $pictoTitle = '';
12729
12730 if ($histo[$key]['percent'] == -1) {
12731 $colorClass = 'timeline-icon-not-applicble';
12732 $pictoTitle = $langs->trans('StatusNotApplicable');
12733 } elseif ($histo[$key]['percent'] == 0) {
12734 $colorClass = 'timeline-icon-todo';
12735 $pictoTitle = $langs->trans('StatusActionToDo').' (0%)';
12736 } elseif ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100) {
12737 $colorClass = 'timeline-icon-in-progress';
12738 $pictoTitle = $langs->trans('StatusActionInProcess').' ('.$histo[$key]['percent'].'%)';
12739 } elseif ($histo[$key]['percent'] >= 100) {
12740 $colorClass = 'timeline-icon-done';
12741 $pictoTitle = $langs->trans('StatusActionDone').' (100%)';
12742 }
12743
12744 if ($actionstatic->code == 'AC_TICKET_CREATE') {
12745 $iconClass = 'fa fa-ticket';
12746 } elseif ($actionstatic->code == 'AC_TICKET_MODIFY') {
12747 $iconClass = 'fa fa-pencilxxx';
12748 } elseif (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12749 $iconClass = 'fa fa-comments';
12750 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12751 $iconClass = 'fa fa-mask';
12752 } elseif (getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
12753 if ($actionstatic->type_picto) {
12754 $img_picto = img_picto('', $actionstatic->type_picto);
12755 } else {
12756 if ($actionstatic->type_code == 'AC_RDV') {
12757 $iconClass = 'fa fa-handshake';
12758 } elseif ($actionstatic->type_code == 'AC_TEL') {
12759 $iconClass = 'fa fa-phone';
12760 } elseif ($actionstatic->type_code == 'AC_FAX') {
12761 $iconClass = 'fa fa-fax';
12762 } elseif ($actionstatic->type_code == 'AC_EMAIL') {
12763 $iconClass = 'fa fa-envelope';
12764 } elseif ($actionstatic->type_code == 'AC_INT') {
12765 $iconClass = 'fa fa-shipping-fast';
12766 } elseif ($actionstatic->type_code == 'AC_OTH_AUTO') {
12767 $iconClass = 'fa fa-robot';
12768 } elseif (!preg_match('/_AUTO/', $actionstatic->type_code)) {
12769 $iconClass = 'fa fa-robot';
12770 }
12771 }
12772 }
12773
12774 $out .= '<i class="'.$iconClass.' '.$colorClass.'" title="'.$pictoTitle.'">'.$img_picto.'</i>'."\n";
12775 return $out;
12776}
12777
12784function getActionCommEcmList($object)
12785{
12786 global $conf, $db;
12787
12788 $documents = array();
12789
12790 $sql = 'SELECT ecm.rowid as id, ecm.src_object_type, ecm.src_object_id, ecm.filepath, ecm.filename';
12791 $sql .= ' FROM '.MAIN_DB_PREFIX.'ecm_files ecm';
12792 $sql .= " WHERE ecm.filepath = 'agenda/".((int) $object->id)."'";
12793 //$sql.= " ecm.src_object_type = '".$db->escape($object->element)."' AND ecm.src_object_id = ".((int) $object->id); // Old version didn't add object_type during upload
12794 $sql .= ' ORDER BY ecm.position ASC';
12795
12796 $resql = $db->query($sql);
12797 if ($resql) {
12798 if ($db->num_rows($resql)) {
12799 while ($obj = $db->fetch_object($resql)) {
12800 $documents[$obj->id] = $obj;
12801 }
12802 }
12803 }
12804
12805 return $documents;
12806}
12807
12808
12809
12827function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
12828{
12829 global $user, $conf;
12830 global $form;
12831
12832 global $param, $massactionbutton;
12833
12834 dol_include_once('/comm/action/class/actioncomm.class.php');
12835
12836 // Check parameters
12837 if (!is_object($filterobj) && !is_object($objcon)) {
12838 dol_print_error('', 'BadParameter');
12839 }
12840
12841 $histo = array();
12842 $numaction = 0;
12843 $now = dol_now();
12844
12845 $sortfield_list = explode(',', $sortfield);
12846 $sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent');
12847 $sortfield_new_list = array();
12848 foreach ($sortfield_list as $sortfield_value) {
12849 $sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)];
12850 }
12851 $sortfield_new = implode(',', $sortfield_new_list);
12852
12853 if (isModEnabled('agenda')) {
12854 // Search histo on actioncomm
12855 if (is_object($objcon) && $objcon->id > 0) {
12856 $sql = "SELECT DISTINCT a.id, a.label as label,";
12857 } else {
12858 $sql = "SELECT a.id, a.label as label,";
12859 }
12860 $sql .= " a.datep as dp,";
12861 $sql .= " a.note as message,";
12862 $sql .= " a.datep2 as dp2,";
12863 $sql .= " a.percent as percent, 'action' as type,";
12864 $sql .= " a.fk_element, a.elementtype,";
12865 $sql .= " a.fk_contact,";
12866 $sql .= " a.email_from as msg_from,";
12867 $sql .= " c.code as acode, c.libelle as alabel, c.picto as apicto,";
12868 $sql .= " u.rowid as user_id, u.login as user_login, u.photo as user_photo, u.firstname as user_firstname, u.lastname as user_lastname";
12869 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12870 $sql .= ", sp.lastname, sp.firstname";
12871 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12872 $sql .= ", m.lastname, m.firstname";
12873 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12874 $sql .= ", o.ref";
12875 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12876 $sql .= ", o.ref";
12877 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12878 $sql .= ", o.ref";
12879 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12880 $sql .= ", o.ref";
12881 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12882 $sql .= ", o.ref";
12883 }
12884 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
12885 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
12886 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
12887
12888 $force_filter_contact = false;
12889 if (is_object($objcon) && $objcon->id > 0) {
12890 $force_filter_contact = true;
12891 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
12892 $sql .= " AND r.element_type = '".$db->escape($objcon->table_element)."' AND r.fk_element = ".((int) $objcon->id);
12893 }
12894
12895 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12896 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
12897 } elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
12898 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er";
12899 $sql .= " ON er.resource_type = 'dolresource'";
12900 $sql .= " AND er.element_id = a.id";
12901 $sql .= " AND er.resource_id = ".((int) $filterobj->id);
12902 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12903 $sql .= ", ".MAIN_DB_PREFIX."adherent as m";
12904 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12905 $sql .= ", ".MAIN_DB_PREFIX."commande_fournisseur as o";
12906 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12907 $sql .= ", ".MAIN_DB_PREFIX."product as o";
12908 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12909 $sql .= ", ".MAIN_DB_PREFIX."ticket as o";
12910 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12911 $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o";
12912 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12913 $sql .= ", ".MAIN_DB_PREFIX."contrat as o";
12914 }
12915
12916 $sql .= " WHERE a.entity IN (".getEntity('agenda').")";
12917 if ($force_filter_contact === false) {
12918 if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) {
12919 $sql .= " AND a.fk_soc = ".((int) $filterobj->id);
12920 } elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) {
12921 $sql .= " AND a.fk_project = ".((int) $filterobj->id);
12922 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12923 $sql .= " AND a.fk_element = m.rowid AND a.elementtype = 'member'";
12924 if ($filterobj->id) {
12925 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12926 }
12927 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12928 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'order_supplier'";
12929 if ($filterobj->id) {
12930 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12931 }
12932 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12933 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
12934 if ($filterobj->id) {
12935 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12936 }
12937 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12938 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'ticket'";
12939 if ($filterobj->id) {
12940 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12941 }
12942 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12943 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'bom'";
12944 if ($filterobj->id) {
12945 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12946 }
12947 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12948 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'contract'";
12949 if ($filterobj->id) {
12950 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12951 }
12952 }
12953 }
12954
12955 // Condition on actioncode
12956 if (!empty($actioncode)) {
12957 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
12958 if ($actioncode == 'AC_NON_AUTO') {
12959 $sql .= " AND c.type != 'systemauto'";
12960 } elseif ($actioncode == 'AC_ALL_AUTO') {
12961 $sql .= " AND c.type = 'systemauto'";
12962 } else {
12963 if ($actioncode == 'AC_OTH') {
12964 $sql .= " AND c.type != 'systemauto'";
12965 } elseif ($actioncode == 'AC_OTH_AUTO') {
12966 $sql .= " AND c.type = 'systemauto'";
12967 }
12968 }
12969 } else {
12970 if ($actioncode == 'AC_NON_AUTO') {
12971 $sql .= " AND c.type != 'systemauto'";
12972 } elseif ($actioncode == 'AC_ALL_AUTO') {
12973 $sql .= " AND c.type = 'systemauto'";
12974 } else {
12975 $sql .= " AND c.code = '".$db->escape($actioncode)."'";
12976 }
12977 }
12978 }
12979 if ($donetodo == 'todo') {
12980 $sql .= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
12981 } elseif ($donetodo == 'done') {
12982 $sql .= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
12983 }
12984 if (is_array($filters) && $filters['search_agenda_label']) {
12985 $sql .= natural_search('a.label', $filters['search_agenda_label']);
12986 }
12987 }
12988
12989 // Add also event from emailings. TODO This should be replaced by an automatic event ? May be it's too much for very large emailing.
12990 if (isModEnabled('mailing') && !empty($objcon->email)
12991 && (empty($actioncode) || $actioncode == 'AC_OTH_AUTO' || $actioncode == 'AC_EMAILING')) {
12992 $langs->load("mails");
12993
12994 $sql2 = "SELECT m.rowid as id, m.titre as label, mc.date_envoi as dp, mc.date_envoi as dp2, '100' as percent, 'mailing' as type";
12995 $sql2 .= ", null as fk_element, '' as elementtype, null as contact_id";
12996 $sql2 .= ", 'AC_EMAILING' as acode, '' as alabel, '' as apicto";
12997 $sql2 .= ", u.rowid as user_id, u.login as user_login, u.photo as user_photo, u.firstname as user_firstname, u.lastname as user_lastname"; // User that valid action
12998 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12999 $sql2 .= ", '' as lastname, '' as firstname";
13000 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
13001 $sql2 .= ", '' as lastname, '' as firstname";
13002 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
13003 $sql2 .= ", '' as ref";
13004 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
13005 $sql2 .= ", '' as ref";
13006 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
13007 $sql2 .= ", '' as ref";
13008 }
13009 $sql2 .= " FROM ".MAIN_DB_PREFIX."mailing as m, ".MAIN_DB_PREFIX."mailing_cibles as mc, ".MAIN_DB_PREFIX."user as u";
13010 $sql2 .= " WHERE mc.email = '".$db->escape($objcon->email)."'"; // Search is done on email.
13011 $sql2 .= " AND mc.statut = 1";
13012 $sql2 .= " AND u.rowid = m.fk_user_valid";
13013 $sql2 .= " AND mc.fk_mailing=m.rowid";
13014 }
13015
13016 if (!empty($sql) && !empty($sql2)) {
13017 $sql = $sql." UNION ".$sql2;
13018 } elseif (empty($sql) && !empty($sql2)) {
13019 $sql = $sql2;
13020 }
13021
13022 // TODO Add limit in nb of results
13023 if ($sql) { // May not be defined if module Agenda is not enabled and mailing module disabled too
13024 $sql .= $db->order($sortfield_new, $sortorder);
13025
13026 dol_syslog("function.lib::show_actions_messaging", LOG_DEBUG);
13027 $resql = $db->query($sql);
13028 if ($resql) {
13029 $i = 0;
13030 $num = $db->num_rows($resql);
13031
13032 while ($i < $num) {
13033 $obj = $db->fetch_object($resql);
13034
13035 if ($obj->type == 'action') {
13036 $contactaction = new ActionComm($db);
13037 $contactaction->id = $obj->id;
13038 $result = $contactaction->fetchResources();
13039 if ($result < 0) {
13040 dol_print_error($db);
13041 setEventMessage("actions.lib::show_actions_messaging Error fetch ressource", 'errors');
13042 }
13043
13044 //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
13045 //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
13046 $tododone = '';
13047 if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && $obj->dp > $now)) {
13048 $tododone = 'todo';
13049 }
13050
13051 $histo[$numaction] = array(
13052 'type'=>$obj->type,
13053 'tododone'=>$tododone,
13054 'id'=>$obj->id,
13055 'datestart'=>$db->jdate($obj->dp),
13056 'dateend'=>$db->jdate($obj->dp2),
13057 'note'=>$obj->label,
13058 'message'=>$obj->message,
13059 'percent'=>$obj->percent,
13060
13061 'userid'=>$obj->user_id,
13062 'login'=>$obj->user_login,
13063 'userfirstname'=>$obj->user_firstname,
13064 'userlastname'=>$obj->user_lastname,
13065 'userphoto'=>$obj->user_photo,
13066 'msg_from'=>$obj->msg_from,
13067
13068 'contact_id'=>$obj->fk_contact,
13069 'socpeopleassigned' => $contactaction->socpeopleassigned,
13070 'lastname' => (empty($obj->lastname) ? '' : $obj->lastname),
13071 'firstname' => (empty($obj->firstname) ? '' : $obj->firstname),
13072 'fk_element'=>$obj->fk_element,
13073 'elementtype'=>$obj->elementtype,
13074 // Type of event
13075 'acode'=>$obj->acode,
13076 'alabel'=>$obj->alabel,
13077 'libelle'=>$obj->alabel, // deprecated
13078 'apicto'=>$obj->apicto
13079 );
13080 } else {
13081 $histo[$numaction] = array(
13082 'type'=>$obj->type,
13083 'tododone'=>'done',
13084 'id'=>$obj->id,
13085 'datestart'=>$db->jdate($obj->dp),
13086 'dateend'=>$db->jdate($obj->dp2),
13087 'note'=>$obj->label,
13088 'message'=>$obj->message,
13089 'percent'=>$obj->percent,
13090 'acode'=>$obj->acode,
13091
13092 'userid'=>$obj->user_id,
13093 'login'=>$obj->user_login,
13094 'userfirstname'=>$obj->user_firstname,
13095 'userlastname'=>$obj->user_lastname,
13096 'userphoto'=>$obj->user_photo
13097 );
13098 }
13099
13100 $numaction++;
13101 $i++;
13102 }
13103 } else {
13104 dol_print_error($db);
13105 }
13106 }
13107
13108 // Set $out to show events
13109 $out = '';
13110
13111 if (!isModEnabled('agenda')) {
13112 $langs->loadLangs(array("admin", "errors"));
13113 $out = info_admin($langs->trans("WarningModuleXDisabledSoYouMayMissEventHere", $langs->transnoentitiesnoconv("Module2400Name")), 0, 0, 'warning');
13114 }
13115
13116 if (isModEnabled('agenda') || (isModEnabled('mailing') && !empty($objcon->email))) {
13117 $delay_warning = $conf->global->MAIN_DELAY_ACTIONS_TODO * 24 * 60 * 60;
13118
13119 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
13120 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
13121 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
13122 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
13123
13124 $formactions = new FormActions($db);
13125
13126 $actionstatic = new ActionComm($db);
13127 $userstatic = new User($db);
13128 $contactstatic = new Contact($db);
13129 $userGetNomUrlCache = array();
13130 $contactGetNomUrlCache = array();
13131
13132 $out .= '<div class="filters-container" >';
13133 $out .= '<form name="listactionsfilter" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
13134 $out .= '<input type="hidden" name="token" value="'.newToken().'">';
13135
13136 if ($objcon && get_class($objcon) == 'Contact' &&
13137 (is_null($filterobj) || get_class($filterobj) == 'Societe')) {
13138 $out .= '<input type="hidden" name="id" value="'.$objcon->id.'" />';
13139 } else {
13140 $out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
13141 }
13142 if ($filterobj && get_class($filterobj) == 'Societe') {
13143 $out .= '<input type="hidden" name="socid" value="'.$filterobj->id.'" />';
13144 }
13145
13146 $out .= "\n";
13147
13148 $out .= '<div class="div-table-responsive-no-min">';
13149 $out .= '<table class="noborder borderbottom centpercent">';
13150
13151 $out .= '<tr class="liste_titre">';
13152
13153 // Action column
13154 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
13155 $out .= '<th class="liste_titre width50 middle">';
13156 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
13157 $out .= $searchpicto;
13158 $out .= '</th>';
13159 }
13160
13161 $out .= getTitleFieldOfList('Date', 0, $_SERVER["PHP_SELF"], 'a.datep', '', $param, '', $sortfield, $sortorder, '')."\n";
13162
13163 $out .= '<th class="liste_titre"><strong class="hideonsmartphone">'.$langs->trans("Search").' : </strong></th>';
13164 if ($donetodo) {
13165 $out .= '<th class="liste_titre"></th>';
13166 }
13167 $out .= '<th class="liste_titre">';
13168 $out .= '<span class="fas fa-square inline-block fawidth30" style=" color: #ddd;" title="'.$langs->trans("ActionType").'"></span>';
13169 //$out .= img_picto($langs->trans("Type"), 'type');
13170 $out .= $formactions->select_type_actions($actioncode, "actioncode", '', !getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : -1, 0, 0, 1, 'minwidth200imp');
13171 $out .= '</th>';
13172 $out .= '<th class="liste_titre maxwidth100onsmartphone">';
13173 $out .= '<input type="text" class="maxwidth100onsmartphone" name="search_agenda_label" value="'.$filters['search_agenda_label'].'" placeholder="'.$langs->trans("Label").'">';
13174 $out .= '</th>';
13175
13176 // Action column
13177 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
13178 $out .= '<th class="liste_titre width50 middle">';
13179 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
13180 $out .= $searchpicto;
13181 $out .= '</th>';
13182 }
13183
13184 $out .= '</tr>';
13185
13186
13187 $out .= '</table>';
13188
13189 $out .= '</form>';
13190 $out .= '</div>';
13191
13192 $out .= "\n";
13193
13194 $out .= '<ul class="timeline">';
13195
13196 if ($donetodo) {
13197 $tmp = '';
13198 if (get_class($filterobj) == 'Societe') {
13199 $tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&socid='.$filterobj->id.'&status=done">';
13200 }
13201 $tmp .= ($donetodo != 'done' ? $langs->trans("ActionsToDoShort") : '');
13202 $tmp .= ($donetodo != 'done' && $donetodo != 'todo' ? ' / ' : '');
13203 $tmp .= ($donetodo != 'todo' ? $langs->trans("ActionsDoneShort") : '');
13204 //$out.=$langs->trans("ActionsToDoShort").' / '.$langs->trans("ActionsDoneShort");
13205 if (get_class($filterobj) == 'Societe') {
13206 $tmp .= '</a>';
13207 }
13208 $out .= getTitleFieldOfList($tmp);
13209 }
13210
13211 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
13212 $caction = new CActionComm($db);
13213 $arraylist = $caction->liste_array(1, 'code', '', (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : 0), '', 1);
13214
13215 $actualCycleDate = false;
13216
13217 // Loop on each event to show it
13218 foreach ($histo as $key => $value) {
13219 $actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo
13220
13221 $actionstatic->type_picto = $histo[$key]['apicto'];
13222 $actionstatic->type_code = $histo[$key]['acode'];
13223
13224 $labeltype = $actionstatic->type_code;
13225 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') && empty($arraylist[$labeltype])) {
13226 $labeltype = 'AC_OTH';
13227 }
13228 if (!empty($actionstatic->code) && preg_match('/^TICKET_MSG/', $actionstatic->code)) {
13229 $labeltype = $langs->trans("Message");
13230 } else {
13231 if (!empty($arraylist[$labeltype])) {
13232 $labeltype = $arraylist[$labeltype];
13233 }
13234 if ($actionstatic->type_code == 'AC_OTH_AUTO' && ($actionstatic->type_code != $actionstatic->code) && $labeltype && !empty($arraylist[$actionstatic->code])) {
13235 $labeltype .= ' - '.$arraylist[$actionstatic->code]; // Use code in priority on type_code
13236 }
13237 }
13238
13239 $url = DOL_URL_ROOT.'/comm/action/card.php?id='.$histo[$key]['id'];
13240
13241 $tmpa = dol_getdate($histo[$key]['datestart'], false);
13242
13243 if (isset($tmpa['year']) && isset($tmpa['yday']) && $actualCycleDate !== $tmpa['year'].'-'.$tmpa['yday']) {
13244 $actualCycleDate = $tmpa['year'].'-'.$tmpa['yday'];
13245 $out .= '<!-- timeline time label -->';
13246 $out .= '<li class="time-label">';
13247 $out .= '<span class="timeline-badge-date">';
13248 $out .= dol_print_date($histo[$key]['datestart'], 'daytext', 'tzuserrel', $langs);
13249 $out .= '</span>';
13250 $out .= '</li>';
13251 $out .= '<!-- /.timeline-label -->';
13252 }
13253
13254
13255 $out .= '<!-- timeline item -->'."\n";
13256 $out .= '<li class="timeline-code-'.strtolower($actionstatic->code).'">';
13257
13258 //$timelineicon = getTimelineIcon($actionstatic, $histo, $key);
13259 $typeicon = $actionstatic->getTypePicto('pictofixedwidth timeline-icon-not-applicble', $labeltype);
13260 //$out .= $timelineicon;
13261 //var_dump($timelineicon);
13262 $out .= $typeicon;
13263
13264 $out .= '<div class="timeline-item">'."\n";
13265
13266 $out .= '<span class="time timeline-header-action2">';
13267
13268 if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
13269 $out .= '<a class="paddingleft paddingright timeline-btn2 editfielda" href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
13270 $out .= $histo[$key]['id'];
13271 $out .= '</a> ';
13272 } else {
13273 $out .= $actionstatic->getNomUrl(1, -1, 'valignmiddle').' ';
13274 }
13275
13276 if ($user->hasRight('agenda', 'allactions', 'create') ||
13277 (($actionstatic->authorid == $user->id || $actionstatic->userownerid == $user->id) && $user->hasRight('agenda', 'myactions', 'create'))) {
13278 $out .= '<a class="paddingleft paddingright timeline-btn2 editfielda" href="'.DOL_MAIN_URL_ROOT.'/comm/action/card.php?action=edit&token='.newToken().'&id='.$actionstatic->id.'&backtopage='.urlencode($_SERVER["PHP_SELF"].'?'.$param).'">';
13279 //$out .= '<i class="fa fa-pencil" title="'.$langs->trans("Modify").'" ></i>';
13280 $out .= img_picto($langs->trans("Modify"), 'edit', 'class="edita"');
13281 $out .= '</a>';
13282 }
13283
13284 $out .= '</span>';
13285
13286 // Date
13287 $out .= '<span class="time"><i class="fa fa-clock-o valignmiddle"></i> <span class="valignmiddle">';
13288 $out .= dol_print_date($histo[$key]['datestart'], 'dayhour', 'tzuserrel');
13289 if ($histo[$key]['dateend'] && $histo[$key]['dateend'] != $histo[$key]['datestart']) {
13290 $tmpa = dol_getdate($histo[$key]['datestart'], true);
13291 $tmpb = dol_getdate($histo[$key]['dateend'], true);
13292 if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
13293 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'hour', 'tzuserrel');
13294 } else {
13295 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'dayhour', 'tzuserrel');
13296 }
13297 }
13298 $late = 0;
13299 if ($histo[$key]['percent'] == 0 && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13300 $late = 1;
13301 }
13302 if ($histo[$key]['percent'] == 0 && !$histo[$key]['datestart'] && $histo[$key]['dateend'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13303 $late = 1;
13304 }
13305 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && $histo[$key]['dateend'] && $histo[$key]['dateend'] < ($now - $delay_warning)) {
13306 $late = 1;
13307 }
13308 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && !$histo[$key]['dateend'] && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13309 $late = 1;
13310 }
13311 if ($late) {
13312 $out .= img_warning($langs->trans("Late")).' ';
13313 }
13314 $out .= "</span></span>\n";
13315
13316 // Ref
13317 $out .= '<h3 class="timeline-header">';
13318
13319 // Author of event
13320 $out .= '<div class="messaging-author inline-block tdoverflowmax150 valignmiddle marginrightonly">';
13321 if ($histo[$key]['userid'] > 0) {
13322 if (!isset($userGetNomUrlCache[$histo[$key]['userid']])) { // is in cache ?
13323 $userstatic->fetch($histo[$key]['userid']);
13324 $userGetNomUrlCache[$histo[$key]['userid']] = $userstatic->getNomUrl(-1, '', 0, 0, 16, 0, 'firstelselast', '');
13325 }
13326 $out .= $userGetNomUrlCache[$histo[$key]['userid']];
13327 } elseif (!empty($histo[$key]['msg_from']) && $actionstatic->code == 'TICKET_MSG') {
13328 if (!isset($contactGetNomUrlCache[$histo[$key]['msg_from']])) {
13329 if ($contactstatic->fetch(0, null, '', $histo[$key]['msg_from']) > 0) {
13330 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $contactstatic->getNomUrl(-1, '', 16);
13331 } else {
13332 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $histo[$key]['msg_from'];
13333 }
13334 }
13335 $out .= $contactGetNomUrlCache[$histo[$key]['msg_from']];
13336 }
13337 $out .= '</div>';
13338
13339 // Title
13340 $out .= ' <div class="messaging-title inline-block">';
13341 //$out .= $actionstatic->getTypePicto();
13342 if (empty($conf->dol_optimize_smallscreen) && $actionstatic->type_code != 'AC_OTH_AUTO') {
13343 $out .= $labeltype.' - ';
13344 }
13345
13346 $libelle = '';
13347 if (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
13348 $out .= $langs->trans('TicketNewMessage');
13349 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
13350 $out .= $langs->trans('TicketNewMessage').' <em>('.$langs->trans('Private').')</em>';
13351 } elseif (isset($histo[$key]['type'])) {
13352 if ($histo[$key]['type'] == 'action') {
13353 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
13354 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : $histo[$key]['alabel']);
13355 $libelle = $histo[$key]['note'];
13356 $actionstatic->id = $histo[$key]['id'];
13357 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13358 } elseif ($histo[$key]['type'] == 'mailing') {
13359 $out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
13360 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
13361 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : 'Send mass mailing');
13362 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13363 } else {
13364 $libelle .= $histo[$key]['note'];
13365 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13366 }
13367 }
13368
13369 if (isset($histo[$key]['elementtype']) && !empty($histo[$key]['fk_element'])) {
13370 if (isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']]) && isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']])) {
13371 $link = $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']];
13372 } else {
13373 if (!isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']])) {
13374 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']] = array();
13375 }
13376 $link = dolGetElementUrl($histo[$key]['fk_element'], $histo[$key]['elementtype'], 1);
13377 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']] = $link;
13378 }
13379 if ($link) {
13380 $out .= ' - '.$link;
13381 }
13382 }
13383
13384 $out .= '</div>';
13385
13386 $out .= '</h3>';
13387
13388 // Message
13389 if (!empty($histo[$key]['message'] && $histo[$key]['message'] != $libelle)
13390 && $actionstatic->code != 'AC_TICKET_CREATE'
13391 && $actionstatic->code != 'AC_TICKET_MODIFY'
13392 ) {
13393 $out .= '<div class="timeline-body wordbreak">';
13394 $truncateLines = getDolGlobalInt('MAIN_TRUNCATE_TIMELINE_MESSAGE', 3);
13395 $truncatedText = dolGetFirstLineOfText($histo[$key]['message'], $truncateLines);
13396 if ($truncateLines > 0 && strlen($histo[$key]['message']) > strlen($truncatedText)) {
13397 $out .= '<div class="readmore-block --closed" >';
13398 $out .= ' <div class="readmore-block__excerpt" >';
13399 $out .= $truncatedText ;
13400 $out .= ' <a class="read-more-link" data-read-more-action="open" href="'.DOL_MAIN_URL_ROOT.'/comm/action/card.php?id='.$actionstatic->id.'&backtopage='.urlencode($_SERVER["PHP_SELF"].'?'.$param).'" >'.$langs->trans("ReadMore").' <span class="fa fa-chevron-right" aria-hidden="true"></span></a>';
13401 $out .= ' </div>';
13402 $out .= ' <div class="readmore-block__full-text" >';
13403 $out .= $histo[$key]['message'];
13404 $out .= ' <a class="read-less-link" data-read-more-action="close" href="#" ><span class="fa fa-chevron-up" aria-hidden="true"></span> '.$langs->trans("ReadLess").'</a>';
13405 $out .= ' </div>';
13406 $out .= '</div>';
13407 } else {
13408 $out .= $histo[$key]['message'];
13409 }
13410
13411 $out .= '</div>';
13412 }
13413
13414 // Timeline footer
13415 $footer = '';
13416
13417 // Contact for this action
13418 if (isset($histo[$key]['socpeopleassigned']) && is_array($histo[$key]['socpeopleassigned']) && count($histo[$key]['socpeopleassigned']) > 0) {
13419 $contactList = '';
13420 foreach ($histo[$key]['socpeopleassigned'] as $cid => $Tab) {
13421 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
13422 $contact = new Contact($db);
13423 $contact->fetch($cid);
13424 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
13425 } else {
13426 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
13427 }
13428
13429 if ($contact) {
13430 $contactList .= !empty($contactList) ? ', ' : '';
13431 $contactList .= $contact->getNomUrl(1);
13432 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
13433 if (!empty($contact->phone_pro)) {
13434 $contactList .= '('.dol_print_phone($contact->phone_pro).')';
13435 }
13436 }
13437 }
13438 }
13439
13440 $footer .= $langs->trans('ActionOnContact').' : '.$contactList;
13441 } elseif (empty($objcon->id) && isset($histo[$key]['contact_id']) && $histo[$key]['contact_id'] > 0) {
13442 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
13443 $contact = new Contact($db);
13444 $result = $contact->fetch($histo[$key]['contact_id']);
13445 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
13446 } else {
13447 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
13448 }
13449
13450 if ($result > 0) {
13451 $footer .= $contact->getNomUrl(1);
13452 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
13453 if (!empty($contact->phone_pro)) {
13454 $footer .= '('.dol_print_phone($contact->phone_pro).')';
13455 }
13456 }
13457 }
13458 }
13459
13460 $documents = getActionCommEcmList($actionstatic);
13461 if (!empty($documents)) {
13462 $footer .= '<div class="timeline-documents-container">';
13463 foreach ($documents as $doc) {
13464 $footer .= '<span id="document_'.$doc->id.'" class="timeline-documents" ';
13465 $footer .= ' data-id="'.$doc->id.'" ';
13466 $footer .= ' data-path="'.$doc->filepath.'"';
13467 $footer .= ' data-filename="'.dol_escape_htmltag($doc->filename).'" ';
13468 $footer .= '>';
13469
13470 $filePath = DOL_DATA_ROOT.'/'.$doc->filepath.'/'.$doc->filename;
13471 $mime = dol_mimetype($filePath);
13472 $file = $actionstatic->id.'/'.$doc->filename;
13473 $thumb = $actionstatic->id.'/thumbs/'.substr($doc->filename, 0, strrpos($doc->filename, '.')).'_mini'.substr($doc->filename, strrpos($doc->filename, '.'));
13474 $doclink = dol_buildpath('document.php', 1).'?modulepart=actions&attachment=0&file='.urlencode($file).'&entity='.$conf->entity;
13475 $viewlink = dol_buildpath('viewimage.php', 1).'?modulepart=actions&file='.urlencode($thumb).'&entity='.$conf->entity;
13476
13477 $mimeAttr = ' mime="'.$mime.'" ';
13478 $class = '';
13479 if (in_array($mime, array('image/png', 'image/jpeg', 'application/pdf'))) {
13480 $class .= ' documentpreview';
13481 }
13482
13483 $footer .= '<a href="'.$doclink.'" class="btn-link '.$class.'" target="_blank" rel="noopener noreferrer" '.$mimeAttr.' >';
13484 $footer .= img_mime($filePath).' '.$doc->filename;
13485 $footer .= '</a>';
13486
13487 $footer .= '</span>';
13488 }
13489 $footer .= '</div>';
13490 }
13491
13492 if (!empty($footer)) {
13493 $out .= '<div class="timeline-footer">'.$footer.'</div>';
13494 }
13495
13496 $out .= '</div>'."\n"; // end timeline-item
13497
13498 $out .= '</li>';
13499 $out .= '<!-- END timeline item -->';
13500
13501 $i++;
13502 }
13503
13504 $out .= "</ul>\n";
13505
13506 $out .= '<script>
13507 jQuery(document).ready(function () {
13508 $(document).on("click", "[data-read-more-action]", function(e){
13509 let readMoreBloc = $(this).closest(".readmore-block");
13510 if(readMoreBloc.length > 0){
13511 e.preventDefault();
13512 if($(this).attr("data-read-more-action") == "close"){
13513 readMoreBloc.addClass("--closed").removeClass("--open");
13514 $("html, body").animate({
13515 scrollTop: readMoreBloc.offset().top - 200
13516 }, 100);
13517 }else{
13518 readMoreBloc.addClass("--open").removeClass("--closed");
13519 }
13520 }
13521 });
13522 });
13523 </script>';
13524
13525
13526 if (empty($histo)) {
13527 $out .= '<span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span>';
13528 }
13529 }
13530
13531 if ($noprint) {
13532 return $out;
13533 } else {
13534 print $out;
13535 }
13536}
13537
13548function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto')
13549{
13550 if ($hourTime === 'getpost') {
13551 $hour = GETPOSTINT($prefix . 'hour');
13552 $minute = GETPOSTINT($prefix . 'minute');
13553 $second = GETPOSTINT($prefix . 'second');
13554 } elseif (preg_match('/^(\d\d):(\d\d):(\d\d)$/', $hourTime, $m)) {
13555 $hour = intval($m[1]);
13556 $minute = intval($m[2]);
13557 $second = intval($m[3]);
13558 } else {
13559 $hour = $minute = $second = 0;
13560 }
13561 // normalize out of range values
13562 $hour = min($hour, 23);
13563 $minute = min($minute, 59);
13564 $second = min($second, 59);
13565 return dol_mktime($hour, $minute, $second, GETPOSTINT($prefix . 'month'), GETPOSTINT($prefix . 'day'), GETPOSTINT($prefix . 'year'), $gm);
13566}
13567
13579function buildParamDate($prefix, $timestamp = null, $hourTime = '', $gm = 'auto')
13580{
13581 if ($timestamp === null) {
13582 $timestamp = GETPOSTDATE($prefix, $hourTime, $gm);
13583 }
13584 $TParam = array(
13585 $prefix . 'day' => intval(dol_print_date($timestamp, '%d')),
13586 $prefix . 'month' => intval(dol_print_date($timestamp, '%m')),
13587 $prefix . 'year' => intval(dol_print_date($timestamp, '%Y')),
13588 );
13589 if ($hourTime === 'getpost' || ($timestamp !== null && dol_print_date($timestamp, '%H:%M:%S') !== '00:00:00')) {
13590 $TParam = array_merge($TParam, array(
13591 $prefix . 'hour' => intval(dol_print_date($timestamp, '%H')),
13592 $prefix . 'minute' => intval(dol_print_date($timestamp, '%M')),
13593 $prefix . 'second' => intval(dol_print_date($timestamp, '%S'))
13594 ));
13595 }
13596
13597 return '&' . http_build_query($TParam);
13598}
if(preg_match('/set_([a-z0-9_\-]+)/i', $action, $reg)) if(preg_match('/del_([a-z0-9_\-]+)/i', $action, $reg)) if($action=='set') elseif( $action=='specimen') elseif($action=='setmodel') elseif( $action=='del') elseif($action=='setdoc') $formactions
View.
ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input=array(), $morecss='', $htmlname='', $forcenojs=0)
On/off button to change a property status of an object This uses the ajax service objectonoff....
Definition ajax.lib.php:709
Class to manage agenda events (actions)
Class to manage different types of events.
Class to manage GeoIP conversion Usage: $geoip=new GeoIP('country',$datfile); $geoip->getCountryCodeF...
Class to manage standard extra fields.
Class to manage invoices.
Class to manage building of HTML components.
Class to manage hooks.
Class to manage predefined suppliers products.
Class to manage products or services.
Class to manage third parties objects (customers, suppliers, prospects...)
isACompany()
Return if third party is a company (Business) or an end user (Consumer)
Class to manage translations.
Class to manage Dolibarr users.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
dol_get_prev_month($month, $year)
Return previous month.
Definition date.lib.php:512
dol_get_next_day($day, $month, $year)
Return next day.
Definition date.lib.php:497
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:85
dol_get_prev_day($day, $month, $year)
Return previous day.
Definition date.lib.php:481
dol_get_next_month($month, $year)
Return next month.
Definition date.lib.php:531
dol_convert_file($fileinput, $ext='png', $fileoutput='', $page='')
Convert an image file or a PDF into another image format.
dragAndDropFileUpload($htmlname)
Function to manage the drag and drop of a file.
dol_is_file($pathoffile)
Return if path is a file.
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
dol_is_dir($folder)
Test if filename is a directory.
dolGetElementUrl($objectid, $objecttype, $withpicto=0, $option='')
Return link url to an object.
isValidVATID($company)
Check if VAT numero is valid (check done on syntax only, no database or remote access)
dol_html_entity_decode($a, $b, $c='UTF-8', $keepsomeentities=0)
Replace html_entity_decode functions to manage errors.
dol_fiche_end($notab=0)
Show tab footer of a card.
dolCheckFilters($sqlfilters, &$error='')
Return if a $sqlfilters parameter has a valid balance of parenthesis.
dol_print_size($size, $shortvalue=0, $shortunit=0)
Return string with formated size.
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
isOnlyOneLocalTax($local)
Return true if LocalTax (1 or 2) is unique.
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...
get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod=0)
Function that return localtax of a product line (according to seller, buyer and product vat rate) Si ...
img_weather($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $morecss='')
Show weather picto.
finishSimpleTable($addLineBreak=false)
Add the correct HTML close tags for "startSimpleTable(...)" (use after the last table line)
startSimpleTable($header, $link="", $arguments="", $emptyRows=0, $number=-1)
Start a table with headers and a optinal clickable number (don't forget to use "finishSimpleTable()" ...
getLanguageCodeFromCountryCode($countrycode)
Return default language from country code.
setEntity($currentobject)
Set entity id to use when to create an object.
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_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks=array())
Show social network link.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
dol_ucfirst($string, $encoding="UTF-8")
Convert first character of the first word of a string to upper.
img_right($titlealt='default', $selected=0, $moreatt='')
Show right arrow logo.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
dol_strtolower($string, $encoding="UTF-8")
Convert a string to lower.
showValueWithClipboardCPButton($valuetocopy, $showonlyonhover=1, $texttoshow='')
Create a button to copy $valuetocopy in the clipboard (for copy and paste feature).
dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto='UTF-8')
This function is called to decode a HTML string (it decodes entities and br tags)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_left($titlealt='default', $selected=0, $moreatt='')
Show left arrow logo.
dol_print_ip($ip, $mode=0)
Return an IP formated to be shown on screen.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
GETPOSTINT($paramname, $method=0)
Return value of a param into GET or POST supervariable.
isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
Function to test if an entry is enabled or not.
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
getDolUserInt($key, $default=0, $tmpuser=null)
Return Dolibarr user constant int value.
yn($yesno, $case=1, $color=0)
Return yes or no in current language.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dolPrintHTML($s, $allowiframe=0)
Return a string ready to be output on HTML page To use text inside an attribute, you can simply use d...
isASecretKey($keyname)
Return if string has a name dedicated to store a secret.
dolPrintHTMLForTextArea($s, $allowiframe=0)
Return a string ready to be output on input textarea To use text inside an attribute,...
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
print_fleche_navigation($page, $file, $options='', $nextpage=0, $betweenarrows='', $afterarrows='', $limit=-1, $totalnboflines=0, $hideselectlimit=0, $beforearrows='', $hidenavigation=0)
Function to show navigation arrows into lists.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
get_date_range($date_start, $date_end, $format='', $outputlangs='', $withparenthesis=1)
Format output for start and end date.
get_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Get formated error messages to output (Used to show messages on html output).
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
roundUpToNextMultiple($n, $x=5)
Round to next multiple.
dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled='', $morecss='classlink button bordertransp', $jsonopen='', $backtopagejsfields='', $accesskey='')
Return HTML code to output a button to open a dialog popup box.
dol_user_country()
Return country code for current user.
dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes=null)
Clean a string from some undesirable HTML tags.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_format_address($object, $withcountry=0, $sep="\n", $outputlangs='', $mode=0, $extralangcode='')
Return a formated address (part address/zip/town/state) according to country rules.
isHTTPS()
Return if we are using a HTTPS connexion Check HTTPS (no way to be modified by user but may be empty ...
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
picto_required()
Return picto saying a field is required.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
img_action($titlealt, $numaction, $picto='', $moreatt='')
Show logo action.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0)
Set event message in dol_events session object.
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
GETPOSTDATE($prefix, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
printCommonFooter($zone='private')
Print common footer : conf->global->MAIN_HTML_FOOTER js for switch of menu hider js for conf->global-...
checkVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
img_down($titlealt='default', $selected=0, $moreclass='')
Show down arrow logo.
getTaxesFromId($vatrate, $buyer=null, $seller=null, $firstparamisid=1)
Get tax (VAT) main information from Id.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
utf8_valid($str)
Check if a string is in UTF8.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
getDolUserString($key, $default='', $tmpuser=null)
Return Dolibarr user constant string value.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
img_allow($allow, $titlealt='default')
Show tick logo if allowed.
isValidMXRecord($domain)
Return if the domain name has a valid MX record.
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
get_htmloutput_mesg($mesgstring='', $mesgarray='', $style='ok', $keepembedded=0)
Get formated messages to output (Used to show messages on html output).
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0)
Format phone numbers according to country.
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
dol_fiche_head($links=array(), $active='0', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tab header of a card.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
get_localtax_by_third($local)
Get values of localtaxes (1 or 2) for company country for the common vat with the highest value.
dol_escape_php($stringtoescape, $stringforquotes=2)
Returns text escaped for inclusion into a php string, build with double quotes " or '.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0)
Clean a string to keep only desirable HTML tags.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
ajax_autoselect($htmlname, $addlink='', $textonlink='Link')
Make content of an input box selected when we click into input field.
img_view($titlealt='default', $float=0, $other='class="valignmiddle"')
Show logo view card.
dolPrintHTMLForAttribute($s)
Return a string ready to be output on an HTML attribute (alt, title, data-html, .....
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_eval($s, $returnvalue=0, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_strftime($fmt, $ts=false, $is_gmt=false)
Format a string.
img_picto_common($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $notitle=0)
Show picto (generic function)
img_search($titlealt='default', $other='')
Show search logo.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
isValidPhone($phone)
Return true if phone number syntax is ok TODO Decide what to do with this.
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
img_previous($titlealt='default', $moreatt='')
Show previous logo.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
fieldLabel($langkey, $fieldkey, $fieldrequired=0)
Show a string with the label tag dedicated to the HTML edit field.
getBrowserInfo($user_agent)
Return information about user browser.
dolGetFirstLetters($s, $nbofchar=1)
Return first letters of a strings.
dol_strtoupper($string, $encoding="UTF-8")
Convert a string to upper.
dol_sanitizeUrl($stringtoclean, $type=1)
Clean a string to use it as an URL (into a href or src attribute)
img_printer($titlealt="default", $other='')
Show printer logo.
dol_htmloutput_events($disabledoutputofmessages=0)
Print formated messages to output (Used to show messages on html output).
getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $disablesortlink=0, $tooltip='', $forcenowrapcolumntitle=0)
Get title line of an array.
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
ascii_check($str)
Check if a string is in ASCII.
getPictoForType($key)
Return the picto for a data type.
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
getArrayOfSocialNetworks()
Get array of social network dictionary.
dolGetButtonTitleSeparator($moreClass="")
Add space between dolGetButtonTitle.
num2Alpha($n)
Return a numeric value into an Excel like column number.
dol_size($size, $type='')
Optimize a size for some browsers (phone, smarphone, ...)
img_split($titlealt='default', $other='class="pictosplit"')
Show split logo.
img_pdf($titlealt='default', $size=3)
Show pdf logo.
dolGetCountryCodeFromIp($ip)
Return a country code from IP.
dol_textishtml($msg, $option=0)
Return if a text is a html content.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolPrintPassword($s)
Return a string ready to be output on an HTML attribute (alt, title, ...)
colorIsLight($stringcolor)
Return true if the color is light.
readfileLowMemory($fullpath_original_file_osencoded, $method=-1)
Return a file on output using a low memory.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
dol_shutdown()
Function called at end of web php process.
dol_print_address($address, $htmlid, $element, $id, $noprint=0, $charfornl='')
Format address string.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_print_error_email($prefixcode, $errormessage='', $errormessages=array(), $morecss='error', $email='')
Show a public email and error code to contact if technical error.
dol_print_profids($profID, $profIDtype, $countrycode='', $addcpButton=1)
Format professional IDs according to their country.
print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
dol_bc($var, $moreclass='')
Return string to add class property on html element with pair/impair.
print_titre($title)
Show a title.
getElementProperties($element_type)
Get an array with properties of an element.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_string_nounprintableascii($str, $removetabcrlf=1)
Clean a string from all non printable ASCII chars (0x00-0x1F and 0x7F).
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
img_error($titlealt='default')
Show error logo.
getTimelineIcon($actionstatic, &$histo, $key)
Get timeline icon.
dol_htmloutput_mesg($mesgstring='', $mesgarray=array(), $style='ok', $keepembedded=0)
Print formated messages to output (Used to show messages on html output).
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
buildParamDate($prefix, $timestamp=null, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
img_next($titlealt='default', $moreatt='')
Show next logo.
print_date_range($date_start, $date_end, $format='', $outputlangs='')
Format output for start and end date.
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
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.
dol_string_is_good_iso($s, $clean=0)
Check if a string is a correct iso string If not, it will not be considered as HTML encoded even if i...
getNonce()
Return a random string to be used as a nonce value for js.
isStringVarMatching($var, $regextext, $matchrule=1)
Check if a variable with name $var start with $text.
complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode='add', $filterorigmodule='')
Complete or removed entries into a head array (used to build tabs).
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
Return localtax vat rate of a product in a particular country or default country vat if product is un...
getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $object=null, $include=null)
Return array of possible common substitutions.
dol_nboflines($s, $maxchar=0)
Return nb of lines of a clear text.
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js, dangerous content and external link.
jsonOrUnserialize($stringtodecode)
Decode an encode string.
addSummaryTableLine($tableColumnCount, $num, $nbofloop=0, $total=0, $noneWord="None", $extraRightColumn=false)
Add a summary line to the current open table ("None", "XMoreLines" or "Total xxx")
isValidEmail($address, $acceptsupervisorkey=0, $acceptuserkey=0)
Return true if email syntax is ok.
dol_escape_xml($stringtoescape)
Returns text escaped for inclusion into a XML string.
getActionCommEcmList($object)
getActionCommEcmList
dol_ucwords($string, $encoding="UTF-8")
Convert first character of all the words of a string to upper.
img_edit_add($titlealt='default', $other='')
Show logo +.
verifCond($strToEvaluate)
Verify if condition in string is ok or not.
if(!function_exists( 'utf8_encode')) if(!function_exists('utf8_decode')) if(!function_exists( 'str_starts_with')) if(!function_exists('str_ends_with')) if(!function_exists( 'str_contains')) getMultidirOutput($object, $module='')
Return the full path of the directory where a module (or an object of a module) stores its files.
print_fiche_titre($title, $mesg='', $picto='generic', $pictoisfullpath=0, $id='')
Show a title with picto.
get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice=0)
Return vat rate of a product in a particular country, or default country vat if product is unknown.
dolForgeDummyCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
dol_escape_json($stringtoescape)
Returns text escaped for inclusion into javascript code.
dolForgeCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
getUserRemoteIP()
Return the IP of remote user.
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_validElement($element)
Return if var element is ok.
img_credit_card($brand, $morecss=null)
Return image of a credit card according to its brand name.
img_searchclear($titlealt='default', $other='')
Show search logo.
dolPrintLabel($s)
Return a string label (so on 1 line only and that should not contains any HTML) ready to be output on...
fetchObjectByElement($element_id, $element_type, $element_ref='')
Fetch an object from its id and element_type Inclusion of classes is automatic.
utf8_check($str)
Check if a string is in UTF8.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
show_actions_messaging($conf, $langs, $db, $filterobj, $objcon='', $noprint=0, $actioncode='', $donetodo='done', $filters=array(), $sortfield='a.datep, a.id', $sortorder='DESC')
Show html area with actions in messaging format.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
img_up($titlealt='default', $selected=0, $moreclass='')
Show top arrow logo.
dol_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Print formated error messages to output (Used to show messages on html output).
getFieldErrorIcon($fieldValidationErrorMsg)
get field error icon
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
img_edit_remove($titlealt='default', $other='')
Show logo -.
img_info($titlealt='default')
Show info logo.
getDoliDBInstance($type, $host, $user, $pass, $name, $port)
Return a DoliDB instance (database handler).
dol_sanitizeEmail($stringtoclean)
Clean a string to use it as an Email.
dol_nboflines_bis($text, $maxlinesize=0, $charset='UTF-8')
Return nb of lines of a formated text with and (WARNING: string must not have mixed and br sepa...
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
dol_convertToWord($num, $langs, $currency='', $centimes=false)
Function to return a number into a text.
conf($dolibarr_main_document_root)
Load conf file (file must exists)
Definition inc.php:403
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1907
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
if(!empty( $_SERVER[ 'MAIN_SHOW_TUNING_INFO'])) realCharForNumericEntities($matches)
Return the real char for a numeric entities.
Definition main.inc.php:63
dol_setcache($memoryid, $data, $expire=0)
Save data into a memory area shared by all users, all sessions on server.
dol_getcache($memoryid)
Read a memory area shared by all users, all sessions on server.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:121
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:124
dolGetRandomBytes($length)
Return a string of random bytes (hexa string) with length = $length fro cryptographic purposes.
Contact()
Old copy.
Definition index.php:572