dolibarr 19.0.4
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-2024 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_all($stringtoescape)
1634{
1635 return preg_replace('/[^a-z0-9_]/i', '', $stringtoescape);
1636}
1637
1644function dol_escape_xml($stringtoescape)
1645{
1646 return $stringtoescape;
1647}
1648
1656function dolPrintLabel($s)
1657{
1659}
1660
1669function dolPrintHTML($s, $allowiframe = 0)
1670{
1671 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, 'common', 0, 1);
1672}
1673
1681{
1682 // The dol_htmlentitiesbr will convert simple text into html
1683 // The dol_escape_htmltag will escape html chars.
1684 return dol_escape_htmltag(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 0, 0, 0, array('br', 'b', 'font', 'span')), 1, -1, '', 0, 1);
1685}
1686
1695function dolPrintHTMLForTextArea($s, $allowiframe = 0)
1696{
1697 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, '', 0, 1);
1698}
1699
1707{
1708 return htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
1709}
1710
1711
1728function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapetags = '', $escapeonlyhtmltags = 0, $cleanalsojavascript = 0)
1729{
1730 if ($noescapetags == 'common') {
1731 $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';
1732 // Add also html5 tags
1733 $noescapetags .= ',header,footer,nav,section,menu,menuitem';
1734 }
1735 if ($cleanalsojavascript) {
1736 $stringtoescape = dol_string_onlythesehtmltags($stringtoescape, 0, 0, $cleanalsojavascript, 0, array(), 0);
1737 }
1738
1739 // escape quotes and backslashes, newlines, etc.
1740 if ($escapeonlyhtmltags) {
1741 $tmp = htmlspecialchars_decode((string) $stringtoescape, ENT_COMPAT);
1742 } else {
1743 $tmp = html_entity_decode((string) $stringtoescape, ENT_COMPAT, 'UTF-8');
1744 }
1745 if (!$keepb) {
1746 $tmp = strtr($tmp, array("<b>"=>'', '</b>'=>'', '<strong>'=>'', '</strong>'=>''));
1747 }
1748 if (!$keepn) {
1749 $tmp = strtr($tmp, array("\r"=>'\\r', "\n"=>'\\n'));
1750 } elseif ($keepn == -1) {
1751 $tmp = strtr($tmp, array("\r"=>'', "\n"=>''));
1752 }
1753
1754 if ($escapeonlyhtmltags) {
1755 return htmlspecialchars($tmp, ENT_COMPAT, 'UTF-8');
1756 } else {
1757 // Escape tags to keep
1758 $tmparrayoftags = array();
1759 if ($noescapetags) {
1760 $tmparrayoftags = explode(',', $noescapetags);
1761 }
1762 if (count($tmparrayoftags)) {
1763 // TODO Does not works yet when there is attributes into tag
1764 foreach ($tmparrayoftags as $tagtoreplace) {
1765 $tmp = str_ireplace('<'.$tagtoreplace.'>', '__BEGINTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1766 $tmp = str_ireplace('</'.$tagtoreplace.'>', '__ENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1767 $tmp = str_ireplace('<'.$tagtoreplace.' />', '__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1768 }
1769 }
1770
1771 $result = htmlentities($tmp, ENT_COMPAT, 'UTF-8');
1772
1773 if (count($tmparrayoftags)) {
1774 foreach ($tmparrayoftags as $tagtoreplace) {
1775 $result = str_ireplace('__BEGINTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.'>', $result);
1776 $result = str_ireplace('__ENDTAGTOREPLACE'.$tagtoreplace.'__', '</'.$tagtoreplace.'>', $result);
1777 $result = str_ireplace('__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.' />', $result);
1778 }
1779 }
1780
1781 return $result;
1782 }
1783}
1784
1792function dol_strtolower($string, $encoding = "UTF-8")
1793{
1794 if (function_exists('mb_strtolower')) {
1795 return mb_strtolower($string, $encoding);
1796 } else {
1797 return strtolower($string);
1798 }
1799}
1800
1809function dol_strtoupper($string, $encoding = "UTF-8")
1810{
1811 if (function_exists('mb_strtoupper')) {
1812 return mb_strtoupper($string, $encoding);
1813 } else {
1814 return strtoupper($string);
1815 }
1816}
1817
1826function dol_ucfirst($string, $encoding = "UTF-8")
1827{
1828 if (function_exists('mb_substr')) {
1829 return mb_strtoupper(mb_substr($string, 0, 1, $encoding), $encoding).mb_substr($string, 1, null, $encoding);
1830 } else {
1831 return ucfirst($string);
1832 }
1833}
1834
1843function dol_ucwords($string, $encoding = "UTF-8")
1844{
1845 if (function_exists('mb_convert_case')) {
1846 return mb_convert_case($string, MB_CASE_TITLE, $encoding);
1847 } else {
1848 return ucwords($string);
1849 }
1850}
1851
1873function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = '', $restricttologhandler = '', $logcontext = null)
1874{
1875 global $conf, $user, $debugbar;
1876
1877 // If syslog module enabled
1878 if (!isModEnabled('syslog')) {
1879 return;
1880 }
1881
1882 // Check if we are into execution of code of a website
1883 if (defined('USEEXTERNALSERVER') && !defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) {
1884 global $website, $websitekey;
1885 if (is_object($website) && !empty($website->ref)) {
1886 $suffixinfilename .= '_website_'.$website->ref;
1887 } elseif (!empty($websitekey)) {
1888 $suffixinfilename .= '_website_'.$websitekey;
1889 }
1890 }
1891
1892 // Check if we have a forced suffix
1893 if (defined('USESUFFIXINLOG')) {
1894 $suffixinfilename .= constant('USESUFFIXINLOG');
1895 }
1896
1897 if ($ident < 0) {
1898 foreach ($conf->loghandlers as $loghandlerinstance) {
1899 $loghandlerinstance->setIdent($ident);
1900 }
1901 }
1902
1903 if (!empty($message)) {
1904 // Test log level
1905 $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');
1906
1907 if (!array_key_exists($level, $logLevels)) {
1908 dol_syslog('Error Bad Log Level '.$level, LOG_ERR);
1909 $level = $logLevels[LOG_ERR];
1910 }
1911 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
1912 return;
1913 }
1914
1915 if (!getDolGlobalString('MAIN_SHOW_PASSWORD_INTO_LOG')) {
1916 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
1917 }
1918
1919 // If adding log inside HTML page is required
1920 if ((!empty($_REQUEST['logtohtml']) && getDolGlobalString('MAIN_ENABLE_LOG_TO_HTML'))
1921 || (is_object($user) && $user->hasRight('debugbar', 'read') && is_object($debugbar))) {
1922 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".$logLevels[$level]." ".$message;
1923 }
1924
1925 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
1926 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
1927 if (getDolGlobalString('MAIN_ENABLE_LOG_INLINE_HTML') && !empty($_GET["log"])) {
1928 print "\n\n<!-- Log start\n";
1929 print dol_escape_htmltag($message)."\n";
1930 print "Log end -->\n";
1931 }
1932
1933 $data = array(
1934 'message' => $message,
1935 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
1936 'level' => $level,
1937 'user' => ((is_object($user) && $user->id) ? $user->login : false),
1938 'ip' => false
1939 );
1940
1941 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
1942 if (!empty($remoteip)) {
1943 $data['ip'] = $remoteip;
1944 // This is when server run behind a reverse proxy
1945 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
1946 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
1947 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
1948 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
1949 }
1950 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
1951 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
1952 $data['ip'] = $_SERVER['SERVER_ADDR'];
1953 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
1954 // 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).
1955 $data['ip'] = $_SERVER['COMPUTERNAME'].(empty($_SERVER['USERNAME']) ? '' : '@'.$_SERVER['USERNAME']);
1956 } elseif (!empty($_SERVER['LOGNAME'])) {
1957 // 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).
1958 $data['ip'] = '???@'.$_SERVER['LOGNAME'];
1959 }
1960
1961 // Loop on each log handler and send output
1962 foreach ($conf->loghandlers as $loghandlerinstance) {
1963 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
1964 continue;
1965 }
1966 $loghandlerinstance->export($data, $suffixinfilename);
1967 }
1968 unset($data);
1969 }
1970
1971 if ($ident > 0) {
1972 foreach ($conf->loghandlers as $loghandlerinstance) {
1973 $loghandlerinstance->setIdent($ident);
1974 }
1975 }
1976}
1977
1994function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
1995{
1996 global $conf;
1997
1998 if (strpos($url, '?') > 0) {
1999 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2000 } else {
2001 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2002 }
2003
2004 $out = '';
2005
2006 $backtopagejsfieldsid = '';
2007 $backtopagejsfieldslabel = '';
2008 if ($backtopagejsfields) {
2009 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
2010 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
2011 $backtopagejsfields = $name.":".$backtopagejsfields;
2012 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
2013 } else {
2014 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
2015 }
2016 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
2017 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
2018 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
2019 }
2020
2021 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
2022 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
2023 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
2024 if (empty($conf->use_javascript_ajax)) {
2025 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
2026 } elseif ($jsonopen) {
2027 $out .= ' href="#" onclick="'.$jsonopen.'"';
2028 } else {
2029 $out .= ' href="#"';
2030 }
2031 $out .= '>'.$buttonstring.'</a>';
2032
2033 if (!empty($conf->use_javascript_ajax)) {
2034 // Add code to open url using the popup. Add also hidden field to retreive the returned variables
2035 $out .= '<!-- code to open popup and variables to retreive returned variables -->';
2036 $out .= '<div id="idfordialog'.$name.'" class="hidden">div for dialog</div>';
2037 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">div for returned id</div>';
2038 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">div for returned label</div>';
2039 $out .= '<!-- Add js code to open dialog popup on dialog -->';
2040 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
2041 jQuery(document).ready(function () {
2042 jQuery(".button_'.$name.'").click(function () {
2043 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
2044 var $tmpdialog = $(\'#idfordialog'.$name.'\');
2045 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
2046 $tmpdialog.dialog({
2047 autoOpen: false,
2048 modal: true,
2049 height: (window.innerHeight - 150),
2050 width: \'80%\',
2051 title: \''.dol_escape_js($label).'\',
2052 open: function (event, ui) {
2053 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
2054 },
2055 close: function (event, ui) {
2056 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
2057 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
2058 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
2059 if (returnedid != "" && returnedid != "div for returned id") {
2060 jQuery("#'.(empty($backtopagejsfieldsid) ? "none" : $backtopagejsfieldsid).'").val(returnedid);
2061 }
2062 if (returnedlabel != "" && returnedlabel != "div for returned label") {
2063 jQuery("#'.(empty($backtopagejsfieldslabel) ? "none" : $backtopagejsfieldslabel).'").val(returnedlabel);
2064 }
2065 }
2066 });
2067
2068 $tmpdialog.dialog(\'open\');
2069 return false;
2070 });
2071 });
2072 </script>';
2073 }
2074 return $out;
2075}
2076
2093function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2094{
2095 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2096}
2097
2114function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2115{
2116 global $conf, $langs, $hookmanager;
2117
2118 // Show title
2119 $showtitle = 1;
2120 if (!empty($conf->dol_optimize_smallscreen)) {
2121 $showtitle = 0;
2122 }
2123
2124 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2125
2126 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2127 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2128 }
2129
2130 // Show right part
2131 if ($morehtmlright) {
2132 $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.
2133 }
2134
2135 // Show title
2136 if (!empty($title) && $showtitle && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2137 $limittitle = 30;
2138 $out .= '<a class="tabTitle">';
2139 if ($picto) {
2140 $noprefix = $pictoisfullpath;
2141 if (strpos($picto, 'fontawesome_') !== false) {
2142 $noprefix = 1;
2143 }
2144 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2145 }
2146 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2147 $out .= '</a>';
2148 }
2149
2150 // Show tabs
2151
2152 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2153 $maxkey = -1;
2154 if (is_array($links) && !empty($links)) {
2155 $keys = array_keys($links);
2156 if (count($keys)) {
2157 $maxkey = max($keys);
2158 }
2159 }
2160
2161 // Show tabs
2162 // if =0 we don't use the feature
2163 if (empty($limittoshow)) {
2164 $limittoshow = (!getDolGlobalString('MAIN_MAXTABS_IN_CARD') ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2165 }
2166 if (!empty($conf->dol_optimize_smallscreen)) {
2167 $limittoshow = 2;
2168 }
2169
2170 $displaytab = 0;
2171 $nbintab = 0;
2172 $popuptab = 0;
2173 $outmore = '';
2174 for ($i = 0; $i <= $maxkey; $i++) {
2175 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2176 // If active tab is already present
2177 if ($i >= $limittoshow) {
2178 $limittoshow--;
2179 }
2180 }
2181 }
2182
2183 for ($i = 0; $i <= $maxkey; $i++) {
2184 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2185 $isactive = true;
2186 } else {
2187 $isactive = false;
2188 }
2189
2190 if ($i < $limittoshow || $isactive) {
2191 // Output entry with a visible tab
2192 $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])).' -->';
2193
2194 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2195 if (!empty($links[$i][0])) {
2196 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2197 } else {
2198 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2199 }
2200 } elseif (!empty($links[$i][1])) {
2201 //print "x $i $active ".$links[$i][2]." z";
2202 $out .= '<div class="tab tab'.($isactive ? 'active' : 'unactive').'" style="margin: 0 !important">';
2203 if (!empty($links[$i][0])) {
2204 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2205 $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).'">';
2206 }
2207 $out .= $links[$i][1];
2208 if (!empty($links[$i][0])) {
2209 $out .= '</a>'."\n";
2210 }
2211 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2212 $out .= '</div>';
2213 }
2214
2215 $out .= '</div>';
2216 } else {
2217 // Add entry into the combo popup with the other tabs
2218 if (!$popuptab) {
2219 $popuptab = 1;
2220 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2221 }
2222 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2223 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2224 if (!empty($links[$i][0])) {
2225 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2226 } else {
2227 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2228 }
2229 } elseif (!empty($links[$i][1])) {
2230 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2231 $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.
2232 $outmore .= '</a>'."\n";
2233 }
2234 $outmore .= '</div>';
2235
2236 $nbintab++;
2237 }
2238 $displaytab = $i;
2239 }
2240 if ($popuptab) {
2241 $outmore .= '</div>';
2242 }
2243
2244 if ($popuptab) { // If there is some tabs not shown
2245 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2246 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2247 $widthofpopup = 200;
2248
2249 $tabsname = $moretabssuffix;
2250 if (empty($tabsname)) {
2251 $tabsname = str_replace("@", "", $picto);
2252 }
2253 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2254 $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".
2255 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2256 $out .= $outmore;
2257 $out .= '</div>';
2258 $out .= '<div></div>';
2259 $out .= "</div>\n";
2260
2261 $out .= '<script nonce="'.getNonce().'">';
2262 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2263 var x = this.offsetLeft, y = this.offsetTop;
2264 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2265 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2266 $('#moretabsList".$tabsname."').css('".$right."','8px');
2267 }
2268 $('#moretabsList".$tabsname."').css('".$left."','auto');
2269 });
2270 ";
2271 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2272 $out .= "</script>";
2273 }
2274
2275 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2276 $out .= "</div>\n";
2277 }
2278
2279 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2280 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom'))).'">'."\n";
2281 }
2282 if (!empty($dragdropfile)) {
2283 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2284 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2285 }
2286 $parameters = array('tabname' => $active, 'out' => $out);
2287 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2288 if ($reshook > 0) {
2289 $out = $hookmanager->resPrint;
2290 }
2291
2292 return $out;
2293}
2294
2302function dol_fiche_end($notab = 0)
2303{
2304 print dol_get_fiche_end($notab);
2305}
2306
2313function dol_get_fiche_end($notab = 0)
2314{
2315 if (!$notab || $notab == -1) {
2316 return "\n</div>\n";
2317 } else {
2318 return '';
2319 }
2320}
2321
2341function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2342{
2343 global $conf, $form, $user, $langs, $hookmanager, $action;
2344
2345 $error = 0;
2346
2347 $maxvisiblephotos = 1;
2348 $showimage = 1;
2349 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2350 $showbarcode = empty($conf->barcode->enabled) ? 0 : (empty($object->barcode) ? 0 : 1);
2351 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2352 $showbarcode = 0;
2353 }
2354 $modulepart = 'unknown';
2355
2356 if ($object->element == 'societe' || $object->element == 'contact' || $object->element == 'product' || $object->element == 'ticket') {
2357 $modulepart = $object->element;
2358 } elseif ($object->element == 'member') {
2359 $modulepart = 'memberphoto';
2360 } elseif ($object->element == 'user') {
2361 $modulepart = 'userphoto';
2362 }
2363
2364 if (class_exists("Imagick")) {
2365 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2366 $modulepart = $object->element;
2367 } elseif ($object->element == 'fichinter') {
2368 $modulepart = 'ficheinter';
2369 } elseif ($object->element == 'contrat') {
2370 $modulepart = 'contract';
2371 } elseif ($object->element == 'order_supplier') {
2372 $modulepart = 'supplier_order';
2373 } elseif ($object->element == 'invoice_supplier') {
2374 $modulepart = 'supplier_invoice';
2375 }
2376 }
2377
2378 if ($object->element == 'product') {
2379 $width = 80;
2380 $cssclass = 'photowithmargin photoref';
2381 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2382 $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : 5);
2383 if ($conf->browser->layout == 'phone') {
2384 $maxvisiblephotos = 1;
2385 }
2386 if ($showimage) {
2387 $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>';
2388 } else {
2389 if (getDolGlobalString('PRODUCT_NODISPLAYIFNOPHOTO')) {
2390 $nophoto = '';
2391 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2392 } else { // Show no photo link
2393 $nophoto = '/public/theme/common/nophoto.png';
2394 $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>';
2395 }
2396 }
2397 } elseif ($object->element == 'ticket') {
2398 $width = 80;
2399 $cssclass = 'photoref';
2400 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2401 $maxvisiblephotos = (isset($conf->global->TICKET_MAX_VISIBLE_PHOTO) ? $conf->global->TICKET_MAX_VISIBLE_PHOTO : 2);
2402 if ($conf->browser->layout == 'phone') {
2403 $maxvisiblephotos = 1;
2404 }
2405
2406 if ($showimage) {
2407 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2408 if ($object->nbphoto > 0) {
2409 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2410 } else {
2411 $showimage = 0;
2412 }
2413 }
2414 if (!$showimage) {
2415 if (getDolGlobalString('TICKET_NODISPLAYIFNOPHOTO')) {
2416 $nophoto = '';
2417 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2418 } else { // Show no photo link
2419 $nophoto = img_picto('No photo', 'object_ticket');
2420 $morehtmlleft .= '<!-- No photo to show -->';
2421 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2422 $morehtmlleft .= $nophoto;
2423 $morehtmlleft .= '</div></div>';
2424 }
2425 }
2426 } else {
2427 if ($showimage) {
2428 if ($modulepart != 'unknown') {
2429 $phototoshow = '';
2430 // Check if a preview file is available
2431 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2432 $objectref = dol_sanitizeFileName($object->ref);
2433 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2434 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2435 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2436 $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
2437 } else {
2438 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2439 }
2440 if (empty($subdir)) {
2441 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2442 }
2443
2444 $filepath = $dir_output.$subdir."/";
2445
2446 $filepdf = $filepath.$objectref.".pdf";
2447 $relativepath = $subdir.'/'.$objectref.'.pdf';
2448
2449 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2450 $fileimage = $filepdf.'_preview.png';
2451 $relativepathimage = $relativepath.'_preview.png';
2452
2453 $pdfexists = file_exists($filepdf);
2454
2455 // If PDF file exists
2456 if ($pdfexists) {
2457 // Conversion du PDF en image png si fichier png non existant
2458 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2459 if (!getDolGlobalString('MAIN_DISABLE_PDF_THUMBS')) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2460 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2461 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2462 if ($ret < 0) {
2463 $error++;
2464 }
2465 }
2466 }
2467 }
2468
2469 if ($pdfexists && !$error) {
2470 $heightforphotref = 80;
2471 if (!empty($conf->dol_optimize_smallscreen)) {
2472 $heightforphotref = 60;
2473 }
2474 // If the preview file is found
2475 if (file_exists($fileimage)) {
2476 $phototoshow = '<div class="photoref">';
2477 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2478 $phototoshow .= '</div>';
2479 }
2480 }
2481 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo'
2482 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2483 }
2484
2485 if ($phototoshow) {
2486 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2487 $morehtmlleft .= $phototoshow;
2488 $morehtmlleft .= '</div>';
2489 }
2490 }
2491
2492 if (empty($phototoshow)) { // Show No photo link (picto of object)
2493 if ($object->element == 'action') {
2494 $width = 80;
2495 $cssclass = 'photorefcenter';
2496 $nophoto = img_picto('No photo', 'title_agenda');
2497 } else {
2498 $width = 14;
2499 $cssclass = 'photorefcenter';
2500 $picto = $object->picto;
2501 $prefix = 'object_';
2502 if ($object->element == 'project' && !$object->public) {
2503 $picto = 'project'; // instead of projectpub
2504 }
2505 if (strpos($picto, 'fontawesome_') !== false) {
2506 $prefix = '';
2507 }
2508 $nophoto = img_picto('No photo', $prefix.$picto);
2509 }
2510 $morehtmlleft .= '<!-- No photo to show -->';
2511 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2512 $morehtmlleft .= $nophoto;
2513 $morehtmlleft .= '</div></div>';
2514 }
2515 }
2516 }
2517
2518 // Show barcode
2519 if ($showbarcode) {
2520 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2521 }
2522
2523 if ($object->element == 'societe') {
2524 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2525 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2526 } else {
2527 $morehtmlstatus .= $object->getLibStatut(6);
2528 }
2529 } elseif ($object->element == 'product') {
2530 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2531 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2532 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2533 } else {
2534 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2535 }
2536 $morehtmlstatus .= ' &nbsp; ';
2537 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2538 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2539 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2540 } else {
2541 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2542 }
2543 } elseif (in_array($object->element, array('salary'))) {
2544 $tmptxt = $object->getLibStatut(6, $object->alreadypaid);
2545 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2546 $tmptxt = $object->getLibStatut(5, $object->alreadypaid);
2547 }
2548 $morehtmlstatus .= $tmptxt;
2549 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier'))) { // TODO Move this to use ->alreadypaid
2550 $totalallpayments = $object->getSommePaiement(0);
2551 $totalallpayments += $object->getSumCreditNotesUsed(0);
2552 $totalallpayments += $object->getSumDepositsUsed(0);
2553 $tmptxt = $object->getLibStatut(6, $totalallpayments);
2554 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2555 $tmptxt = $object->getLibStatut(5, $totalallpayments);
2556 }
2557 $morehtmlstatus .= $tmptxt;
2558 } elseif (in_array($object->element, array('chargesociales', 'loan', 'tva'))) { // TODO Move this to use ->alreadypaid
2559 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2560 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2561 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2562 }
2563 $morehtmlstatus .= $tmptxt;
2564 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2565 if ($object->statut == 0) {
2566 $morehtmlstatus .= $object->getLibStatut(5);
2567 } else {
2568 $morehtmlstatus .= $object->getLibStatut(4);
2569 }
2570 } elseif ($object->element == 'facturerec') {
2571 if ($object->frequency == 0) {
2572 $morehtmlstatus .= $object->getLibStatut(2);
2573 } else {
2574 $morehtmlstatus .= $object->getLibStatut(5);
2575 }
2576 } elseif ($object->element == 'project_task') {
2577 $object->fk_statut = 1;
2578 if ($object->progress > 0) {
2579 $object->fk_statut = 2;
2580 }
2581 if ($object->progress >= 100) {
2582 $object->fk_statut = 3;
2583 }
2584 $tmptxt = $object->getLibStatut(5);
2585 $morehtmlstatus .= $tmptxt; // No status on task
2586 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2587 $tmptxt = $object->getLibStatut(6);
2588 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2589 $tmptxt = $object->getLibStatut(5);
2590 }
2591 $morehtmlstatus .= $tmptxt;
2592 }
2593
2594 // Add if object was dispatched "into accountancy"
2595 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2596 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2597 if (method_exists($object, 'getVentilExportCompta')) {
2598 $accounted = $object->getVentilExportCompta();
2599 $langs->load("accountancy");
2600 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2601 }
2602 }
2603
2604 // Add alias for thirdparty
2605 if (!empty($object->name_alias)) {
2606 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
2607 }
2608
2609 // Add label
2610 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
2611 if (!empty($object->label)) {
2612 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
2613 }
2614 }
2615
2616 // Show address and email
2617 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
2618 $moreaddress = $object->getBannerAddress('refaddress', $object); // address, email, url, social networks
2619 if ($moreaddress) {
2620 $morehtmlref .= '<div class="refidno refaddress">';
2621 $morehtmlref .= $moreaddress;
2622 $morehtmlref .= '</div>';
2623 }
2624 }
2625 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)) {
2626 $morehtmlref .= '<div style="clear: both;"></div>';
2627 $morehtmlref .= '<div class="refidno opacitymedium">';
2628 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
2629 $morehtmlref .= '</div>';
2630 }
2631
2632 $parameters=array('morehtmlref'=>$morehtmlref);
2633 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
2634 if ($reshook < 0) {
2635 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2636 } elseif (empty($reshook)) {
2637 $morehtmlref .= $hookmanager->resPrint;
2638 } elseif ($reshook > 0) {
2639 $morehtmlref = $hookmanager->resPrint;
2640 }
2641
2642 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
2643 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
2644 print '</div>';
2645 print '<div class="underrefbanner clearboth"></div>';
2646}
2647
2657function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
2658{
2659 global $langs;
2660 $ret = '';
2661 if ($fieldrequired) {
2662 $ret .= '<span class="fieldrequired">';
2663 }
2664 $ret .= '<label for="'.$fieldkey.'">';
2665 $ret .= $langs->trans($langkey);
2666 $ret .= '</label>';
2667 if ($fieldrequired) {
2668 $ret .= '</span>';
2669 }
2670 return $ret;
2671}
2672
2680function dol_bc($var, $moreclass = '')
2681{
2682 global $bc;
2683 $ret = ' '.$bc[$var];
2684 if ($moreclass) {
2685 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
2686 }
2687 return $ret;
2688}
2689
2703function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = '', $mode = 0, $extralangcode = '')
2704{
2705 global $conf, $langs, $hookmanager;
2706
2707 $ret = '';
2708 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
2709
2710 // See format of addresses on https://en.wikipedia.org/wiki/Address
2711 // Address
2712 if (empty($mode)) {
2713 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
2714 }
2715 // Zip/Town/State
2716 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || getDolGlobalString('MAIN_FORCE_STATE_INTO_ADDRESS')) {
2717 // US: title firstname name \n address lines \n town, state, zip \n country
2718 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2719 $ret .= (($ret && $town) ? $sep : '').$town;
2720
2721 if (!empty($object->state)) {
2722 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
2723 }
2724 if (!empty($object->zip)) {
2725 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
2726 }
2727 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
2728 // UK: title firstname name \n address lines \n town state \n zip \n country
2729 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2730 $ret .= ($ret ? $sep : '').$town;
2731 if (!empty($object->state)) {
2732 $ret .= ($ret ? ", " : '').$object->state;
2733 }
2734 if (!empty($object->zip)) {
2735 $ret .= ($ret ? $sep : '').$object->zip;
2736 }
2737 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
2738 // ES: title firstname name \n address lines \n zip town \n state \n country
2739 $ret .= ($ret ? $sep : '').$object->zip;
2740 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2741 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2742 if (!empty($object->state)) {
2743 $ret .= $sep.$object->state;
2744 }
2745 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
2746 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
2747 // See https://www.sljfaq.org/afaq/addresses.html
2748 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2749 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
2750 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
2751 // IT: title firstname name\n address lines \n zip town state_code \n country
2752 $ret .= ($ret ? $sep : '').$object->zip;
2753 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2754 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2755 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
2756 } else {
2757 // Other: title firstname name \n address lines \n zip town[, state] \n country
2758 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2759 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
2760 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
2761 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
2762 $ret .= ($ret ? ", " : '').$object->state;
2763 }
2764 }
2765
2766 if (!is_object($outputlangs)) {
2767 $outputlangs = $langs;
2768 }
2769 if ($withcountry) {
2770 $langs->load("dict");
2771 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
2772 }
2773 if ($hookmanager) {
2774 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
2775 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
2776 if ($reshook > 0) {
2777 $ret = '';
2778 }
2779 $ret .= $hookmanager->resPrint;
2780 }
2781
2782 return $ret;
2783}
2784
2785
2786
2795function dol_strftime($fmt, $ts = false, $is_gmt = false)
2796{
2797 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
2798 return ($is_gmt) ? @gmstrftime($fmt, $ts) : @strftime($fmt, $ts);
2799 } else {
2800 return 'Error date into a not supported range';
2801 }
2802}
2803
2825function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = '', $encodetooutput = false)
2826{
2827 global $conf, $langs;
2828
2829 // If date undefined or "", we return ""
2830 if (dol_strlen($time) == 0) {
2831 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
2832 }
2833
2834 if ($tzoutput === 'auto') {
2835 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
2836 }
2837
2838 // Clean parameters
2839 $to_gmt = false;
2840 $offsettz = $offsetdst = 0;
2841 if ($tzoutput) {
2842 $to_gmt = true; // For backward compatibility
2843 if (is_string($tzoutput)) {
2844 if ($tzoutput == 'tzserver') {
2845 $to_gmt = false;
2846 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
2847 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
2848 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
2849 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
2850 $to_gmt = true;
2851 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
2852
2853 if (class_exists('DateTimeZone')) {
2854 $user_date_tz = new DateTimeZone($offsettzstring);
2855 $user_dt = new DateTime();
2856 $user_dt->setTimezone($user_date_tz);
2857 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
2858 $offsettz = $user_dt->getOffset(); // should include dst ?
2859 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
2860 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
2861 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
2862 }
2863 }
2864 }
2865 }
2866 if (!is_object($outputlangs)) {
2867 $outputlangs = $langs;
2868 }
2869 if (!$format) {
2870 $format = 'daytextshort';
2871 }
2872
2873 // Do we have to reduce the length of date (year on 2 chars) to save space.
2874 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
2875 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour', 'dayhoursec'))) ? 1 : 0; // Test on original $format param.
2876 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
2877 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
2878 if ($formatwithoutreduce != $format) {
2879 $format = $formatwithoutreduce;
2880 $reduceformat = 1;
2881 } // so format 'dayreduceformat' is processed like day
2882
2883 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
2884 // TODO Add format daysmallyear and dayhoursmallyear
2885 if ($format == 'day') {
2886 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
2887 } elseif ($format == 'hour') {
2888 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
2889 } elseif ($format == 'hourduration') {
2890 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
2891 } elseif ($format == 'daytext') {
2892 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
2893 } elseif ($format == 'daytextshort') {
2894 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
2895 } elseif ($format == 'dayhour') {
2896 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
2897 } elseif ($format == 'dayhoursec') {
2898 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
2899 } elseif ($format == 'dayhourtext') {
2900 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
2901 } elseif ($format == 'dayhourtextshort') {
2902 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
2903 } elseif ($format == 'dayhourlog') {
2904 // Format not sensitive to language
2905 $format = '%Y%m%d%H%M%S';
2906 } elseif ($format == 'dayhourlogsmall') {
2907 // Format not sensitive to language
2908 $format = '%y%m%d%H%M';
2909 } elseif ($format == 'dayhourldap') {
2910 $format = '%Y%m%d%H%M%SZ';
2911 } elseif ($format == 'dayhourxcard') {
2912 $format = '%Y%m%dT%H%M%SZ';
2913 } elseif ($format == 'dayxcard') {
2914 $format = '%Y%m%d';
2915 } elseif ($format == 'dayrfc') {
2916 $format = '%Y-%m-%d'; // DATE_RFC3339
2917 } elseif ($format == 'dayhourrfc') {
2918 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
2919 } elseif ($format == 'standard') {
2920 $format = '%Y-%m-%d %H:%M:%S';
2921 }
2922
2923 if ($reduceformat) {
2924 $format = str_replace('%Y', '%y', $format);
2925 $format = str_replace('yyyy', 'yy', $format);
2926 }
2927
2928 // Clean format
2929 if (preg_match('/%b/i', $format)) { // There is some text to translate
2930 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2931 $format = str_replace('%b', '__b__', $format);
2932 $format = str_replace('%B', '__B__', $format);
2933 }
2934 if (preg_match('/%a/i', $format)) { // There is some text to translate
2935 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2936 $format = str_replace('%a', '__a__', $format);
2937 $format = str_replace('%A', '__A__', $format);
2938 }
2939
2940 // Analyze date
2941 $reg = array();
2942 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
2943 dol_print_error('', "Functions.lib::dol_print_date function called with a bad value from page ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]));
2944 return '';
2945 } 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
2946 // This part of code should not be used anymore.
2947 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);
2948 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
2949 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
2950 $syear = (!empty($reg[1]) ? $reg[1] : '');
2951 $smonth = (!empty($reg[2]) ? $reg[2] : '');
2952 $sday = (!empty($reg[3]) ? $reg[3] : '');
2953 $shour = (!empty($reg[4]) ? $reg[4] : '');
2954 $smin = (!empty($reg[5]) ? $reg[5] : '');
2955 $ssec = (!empty($reg[6]) ? $reg[6] : '');
2956
2957 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
2958
2959 if ($to_gmt) {
2960 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2961 } else {
2962 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2963 }
2964 $dtts = new DateTime();
2965 $dtts->setTimestamp($time);
2966 $dtts->setTimezone($tzo);
2967 $newformat = str_replace(
2968 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2969 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2970 $format
2971 );
2972 $ret = $dtts->format($newformat);
2973 $ret = str_replace(
2974 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2975 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2976 $ret
2977 );
2978 } else {
2979 // Date is a timestamps
2980 if ($time < 100000000000) { // Protection against bad date values
2981 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2982
2983 if ($to_gmt) {
2984 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2985 } else {
2986 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2987 }
2988 $dtts = new DateTime();
2989 $dtts->setTimestamp($timetouse);
2990 $dtts->setTimezone($tzo);
2991 $newformat = str_replace(
2992 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2993 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2994 $format
2995 );
2996 $ret = $dtts->format($newformat);
2997 $ret = str_replace(
2998 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2999 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
3000 $ret
3001 );
3002 //var_dump($ret);exit;
3003 } else {
3004 $ret = 'Bad value '.$time.' for date';
3005 }
3006 }
3007
3008 if (preg_match('/__b__/i', $format)) {
3009 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
3010
3011 if ($to_gmt) {
3012 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
3013 } else {
3014 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
3015 }
3016 $dtts = new DateTime();
3017 $dtts->setTimestamp($timetouse);
3018 $dtts->setTimezone($tzo);
3019 $month = $dtts->format("m");
3020 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
3021 if ($encodetooutput) {
3022 $monthtext = $outputlangs->transnoentities('Month'.$month);
3023 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
3024 } else {
3025 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
3026 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
3027 }
3028 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
3029 $ret = str_replace('__b__', $monthtextshort, $ret);
3030 $ret = str_replace('__B__', $monthtext, $ret);
3031 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
3032 //return $ret;
3033 }
3034 if (preg_match('/__a__/i', $format)) {
3035 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
3036 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
3037
3038 if ($to_gmt) {
3039 $tzo = new DateTimeZone('UTC');
3040 } else {
3041 $tzo = new DateTimeZone(date_default_timezone_get());
3042 }
3043 $dtts = new DateTime();
3044 $dtts->setTimestamp($timetouse);
3045 $dtts->setTimezone($tzo);
3046 $w = $dtts->format("w");
3047 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
3048
3049 $ret = str_replace('__A__', $dayweek, $ret);
3050 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
3051 }
3052
3053 return $ret;
3054}
3055
3056
3077function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
3078{
3079 if ($timestamp === '') {
3080 return array();
3081 }
3082
3083 $datetimeobj = new DateTime();
3084 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
3085 if ($forcetimezone) {
3086 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
3087 }
3088 $arrayinfo = array(
3089 'year'=>((int) date_format($datetimeobj, 'Y')),
3090 'mon'=>((int) date_format($datetimeobj, 'm')),
3091 'mday'=>((int) date_format($datetimeobj, 'd')),
3092 'wday'=>((int) date_format($datetimeobj, 'w')),
3093 'yday'=>((int) date_format($datetimeobj, 'z')),
3094 'hours'=>((int) date_format($datetimeobj, 'H')),
3095 'minutes'=>((int) date_format($datetimeobj, 'i')),
3096 'seconds'=>((int) date_format($datetimeobj, 's')),
3097 '0'=>$timestamp
3098 );
3099
3100 return $arrayinfo;
3101}
3102
3124function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3125{
3126 global $conf;
3127 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3128
3129 if ($gm === 'auto') {
3130 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3131 }
3132 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3133
3134 // Clean parameters
3135 if ($hour == -1 || empty($hour)) {
3136 $hour = 0;
3137 }
3138 if ($minute == -1 || empty($minute)) {
3139 $minute = 0;
3140 }
3141 if ($second == -1 || empty($second)) {
3142 $second = 0;
3143 }
3144
3145 // Check parameters
3146 if ($check) {
3147 if (!$month || !$day) {
3148 return '';
3149 }
3150 if ($day > 31) {
3151 return '';
3152 }
3153 if ($month > 12) {
3154 return '';
3155 }
3156 if ($hour < 0 || $hour > 24) {
3157 return '';
3158 }
3159 if ($minute < 0 || $minute > 60) {
3160 return '';
3161 }
3162 if ($second < 0 || $second > 60) {
3163 return '';
3164 }
3165 }
3166
3167 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3168 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3169 $localtz = new DateTimeZone($default_timezone);
3170 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3171 // We use dol_tz_string first because it is more reliable.
3172 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3173 try {
3174 $localtz = new DateTimeZone($default_timezone);
3175 } catch (Exception $e) {
3176 dol_syslog("Warning dol_tz_string contains an invalid value ".$_SESSION["dol_tz_string"], LOG_WARNING);
3177 $default_timezone = @date_default_timezone_get();
3178 }
3179 } elseif (strrpos($gm, "tz,") !== false) {
3180 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3181 try {
3182 $localtz = new DateTimeZone($timezone);
3183 } catch (Exception $e) {
3184 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3185 }
3186 }
3187
3188 if (empty($localtz)) {
3189 $localtz = new DateTimeZone('UTC');
3190 }
3191 //var_dump($localtz);
3192 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3193 $dt = new DateTime('now', $localtz);
3194 $dt->setDate((int) $year, (int) $month, (int) $day);
3195 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3196 $date = $dt->getTimestamp(); // should include daylight saving time
3197 //var_dump($date);
3198 return $date;
3199}
3200
3201
3212function dol_now($mode = 'auto')
3213{
3214 $ret = 0;
3215
3216 if ($mode === 'auto') {
3217 $mode = 'gmt';
3218 }
3219
3220 if ($mode == 'gmt') {
3221 $ret = time(); // Time for now at greenwich.
3222 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3223 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3224 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3225 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3226 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3227 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3228 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3229 // $ret=dol_now('gmt')+($tzsecond*3600);
3230 //}
3231 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3232 // Time for now with user timezone added
3233 //print 'time: '.time();
3234 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3235 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3236 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3237 }
3238
3239 return $ret;
3240}
3241
3242
3251function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3252{
3253 global $conf, $langs;
3254 $level = 1024;
3255
3256 if (!empty($conf->dol_optimize_smallscreen)) {
3257 $shortunit = 1;
3258 }
3259
3260 // Set value text
3261 if (empty($shortvalue) || $size < ($level * 10)) {
3262 $ret = $size;
3263 $textunitshort = $langs->trans("b");
3264 $textunitlong = $langs->trans("Bytes");
3265 } else {
3266 $ret = round($size / $level, 0);
3267 $textunitshort = $langs->trans("Kb");
3268 $textunitlong = $langs->trans("KiloBytes");
3269 }
3270 // Use long or short text unit
3271 if (empty($shortunit)) {
3272 $ret .= ' '.$textunitlong;
3273 } else {
3274 $ret .= ' '.$textunitshort;
3275 }
3276
3277 return $ret;
3278}
3279
3290function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = '')
3291{
3292 global $langs;
3293
3294 if (empty($url)) {
3295 return '';
3296 }
3297
3298 $linkstart = '<a href="';
3299 if (!preg_match('/^http/i', $url)) {
3300 $linkstart .= 'http://';
3301 }
3302 $linkstart .= $url;
3303 $linkstart .= '"';
3304 if ($target) {
3305 $linkstart .= ' target="'.$target.'"';
3306 }
3307 $linkstart .= ' title="'.$langs->trans("URL").': '.$url.'"';
3308 $linkstart .= '>';
3309
3310 $link = '';
3311 if (!preg_match('/^http/i', $url)) {
3312 $link .= 'http://';
3313 }
3314 $link .= dol_trunc($url, $max);
3315
3316 $linkend = '</a>';
3317
3318 if ($morecss == 'float') { // deprecated
3319 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto($langs->trans("Url"), 'globe', 'class="paddingrightonly"') : '').$link.'</div>';
3320 } else {
3321 return $linkstart.'<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto('', 'globe', 'class="paddingrightonly"') : '').$link.'</span>'.$linkend;
3322 }
3323}
3324
3337function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3338{
3339 global $user, $langs, $hookmanager;
3340
3341 //global $conf; $conf->global->AGENDA_ADDACTIONFOREMAIL = 1;
3342 //$showinvalid = 1; $email = 'rrrrr';
3343
3344 $newemail = dol_escape_htmltag($email);
3345
3346 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && $withpicto) {
3347 $withpicto = 0;
3348 }
3349
3350 if (empty($email)) {
3351 return '&nbsp;';
3352 }
3353
3354 if (!empty($addlink)) {
3355 $newemail = '<a class="paddingrightonly" style="text-overflow: ellipsis;" href="';
3356 if (!preg_match('/^mailto:/i', $email)) {
3357 $newemail .= 'mailto:';
3358 }
3359 $newemail .= $email;
3360 $newemail .= '">';
3361
3362 $newemail .= ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '');
3363
3364 $newemail .= dol_trunc($email, $max);
3365 $newemail .= '</a>';
3366 if ($showinvalid && !isValidEmail($email)) {
3367 $langs->load("errors");
3368 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email), '', 'paddingrightonly');
3369 }
3370
3371 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3372 $type = 'AC_EMAIL';
3373 $linktoaddaction = '';
3374 if (getDolGlobalString('AGENDA_ADDACTIONFOREMAIL')) {
3375 $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>';
3376 }
3377 if ($linktoaddaction) {
3378 $newemail = '<div>'.$newemail.' '.$linktoaddaction.'</div>';
3379 }
3380 }
3381 } else {
3382 $newemail = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3383
3384 if ($showinvalid && !isValidEmail($email)) {
3385 $langs->load("errors");
3386 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3387 }
3388 }
3389
3390 //$rep = '<div class="nospan" style="margin-right: 10px">';
3391 //$rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3392 //$rep .= '</div>';
3393 $rep = $newemail;
3394
3395 if ($hookmanager) {
3396 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3397
3398 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3399 if ($reshook > 0) {
3400 $rep = '';
3401 }
3402 $rep .= $hookmanager->resPrint;
3403 }
3404
3405 return $rep;
3406}
3407
3414{
3415 global $conf, $db;
3416
3417 $socialnetworks = array();
3418 // Enable caching of array
3419 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3420 $cachekey = 'socialnetworks_' . $conf->entity;
3421 $dataretrieved = dol_getcache($cachekey);
3422 if (!is_null($dataretrieved)) {
3423 $socialnetworks = $dataretrieved;
3424 } else {
3425 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3426 $sql .= " WHERE entity=".$conf->entity;
3427 $resql = $db->query($sql);
3428 if ($resql) {
3429 while ($obj = $db->fetch_object($resql)) {
3430 $socialnetworks[$obj->code] = array(
3431 'rowid' => $obj->rowid,
3432 'label' => $obj->label,
3433 'url' => $obj->url,
3434 'icon' => $obj->icon,
3435 'active' => $obj->active,
3436 );
3437 }
3438 }
3439 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3440 }
3441
3442 return $socialnetworks;
3443}
3444
3455function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3456{
3457 global $conf, $user, $langs;
3458
3459 $htmllink = $value;
3460
3461 if (empty($value)) {
3462 return '&nbsp;';
3463 }
3464
3465 if (!empty($type)) {
3466 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3467 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3468 $htmllink .= '<span class="fab pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3469 if ($type == 'skype') {
3470 $htmllink .= dol_escape_htmltag($value);
3471 $htmllink .= '&nbsp; <a href="skype:';
3472 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3473 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3474 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3475 $htmllink .= '</a><a href="skype:';
3476 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3477 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3478 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3479 $htmllink .= '</a>';
3480 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3481 $addlink = 'AC_SKYPE';
3482 $link = '';
3483 if (getDolGlobalString('AGENDA_ADDACTIONFORSKYPE')) {
3484 $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>';
3485 }
3486 $htmllink .= ($link ? ' '.$link : '');
3487 }
3488 } else {
3489 $networkconstname = 'MAIN_INFO_SOCIETE_'.strtoupper($type).'_URL';
3490 if (getDolGlobalString($networkconstname)) {
3491 $link = str_replace('{socialid}', $value, getDolGlobalString($networkconstname));
3492 if (preg_match('/^https?:\/\//i', $link)) {
3493 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3494 } else {
3495 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3496 }
3497 } elseif (!empty($dictsocialnetworks[$type]['url'])) {
3498 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3499 if ($tmpvirginurl) {
3500 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3501 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3502
3503 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3504 if ($tmpvirginurl3) {
3505 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3506 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3507 }
3508
3509 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3510 if ($tmpvirginurl2) {
3511 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3512 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3513 }
3514 }
3515 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3516 if (preg_match('/^https?:\/\//i', $link)) {
3517 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3518 } else {
3519 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3520 }
3521 } else {
3522 $htmllink .= dol_escape_htmltag($value);
3523 }
3524 }
3525 $htmllink .= '</div>';
3526 } else {
3527 $langs->load("errors");
3528 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3529 }
3530 return $htmllink;
3531}
3532
3542function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1)
3543{
3544 global $mysoc;
3545
3546 if (empty($profID) || empty($profIDtype)) {
3547 return '';
3548 }
3549 if (empty($countrycode)) {
3550 $countrycode = $mysoc->country_code;
3551 }
3552 $newProfID = $profID;
3553 $id = substr($profIDtype, -1);
3554 $ret = '';
3555 if (strtoupper($countrycode) == 'FR') {
3556 // France
3557 // (see https://www.economie.gouv.fr/entreprises/numeros-identification-entreprise)
3558
3559 if ($id == 1 && dol_strlen($newProfID) == 9) {
3560 // SIREN (ex: 123 123 123)
3561 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3);
3562 }
3563 if ($id == 2 && dol_strlen($newProfID) == 14) {
3564 // SIRET (ex: 123 123 123 12345)
3565 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3).' '.substr($newProfID, 9, 5);
3566 }
3567 if ($id == 3 && dol_strlen($newProfID) == 5) {
3568 // NAF/APE (ex: 69.20Z)
3569 $newProfID = substr($newProfID, 0, 2).'.'.substr($newProfID, 2, 3);
3570 }
3571 if ($profIDtype === 'VAT' && dol_strlen($newProfID) == 13) {
3572 // TVA intracommunautaire (ex: FR12 123 123 123)
3573 $newProfID = substr($newProfID, 0, 4).' '.substr($newProfID, 4, 3).' '.substr($newProfID, 7, 3).' '.substr($newProfID, 10, 3);
3574 }
3575 }
3576 if (!empty($addcpButton)) {
3577 $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3578 } else {
3579 $ret = $newProfID;
3580 }
3581 return $ret;
3582}
3583
3598function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0)
3599{
3600 global $conf, $user, $langs, $mysoc, $hookmanager;
3601
3602 // Clean phone parameter
3603 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
3604 if (empty($phone)) {
3605 return '';
3606 }
3607 if (getDolGlobalString('MAIN_PHONE_SEPAR')) {
3608 $separ = $conf->global->MAIN_PHONE_SEPAR;
3609 }
3610 if (empty($countrycode) && is_object($mysoc)) {
3611 $countrycode = $mysoc->country_code;
3612 }
3613
3614 // Short format for small screens
3615 if ($conf->dol_optimize_smallscreen) {
3616 $separ = '';
3617 }
3618
3619 $newphone = $phone;
3620 if (strtoupper($countrycode) == "FR") {
3621 // France
3622 if (dol_strlen($phone) == 10) {
3623 $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);
3624 } elseif (dol_strlen($phone) == 7) {
3625 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
3626 } elseif (dol_strlen($phone) == 9) {
3627 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
3628 } elseif (dol_strlen($phone) == 11) {
3629 $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);
3630 } elseif (dol_strlen($phone) == 12) {
3631 $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);
3632 } elseif (dol_strlen($phone) == 13) {
3633 $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);
3634 }
3635 } elseif (strtoupper($countrycode) == "CA") {
3636 if (dol_strlen($phone) == 10) {
3637 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
3638 }
3639 } elseif (strtoupper($countrycode) == "PT") {//Portugal
3640 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
3641 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3642 }
3643 } elseif (strtoupper($countrycode) == "SR") {//Suriname
3644 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
3645 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
3646 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
3647 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
3648 }
3649 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
3650 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
3651 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
3652 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
3653 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
3654 }
3655 } elseif (strtoupper($countrycode) == "ES") {//Espagne
3656 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
3657 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3658 }
3659 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
3660 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
3661 $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);
3662 }
3663 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
3664 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
3665 $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);
3666 }
3667 } elseif (strtoupper($countrycode) == "TR") {//Turquie
3668 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
3669 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3670 }
3671 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
3672 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
3673 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3674 }
3675 } elseif (strtoupper($countrycode) == "MX") {//Mexique
3676 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
3677 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3678 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
3679 $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);
3680 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
3681 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3682 }
3683 } elseif (strtoupper($countrycode) == "ML") {//Mali
3684 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
3685 $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);
3686 }
3687 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
3688 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
3689 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3690 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
3691 $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);
3692 }
3693 } elseif (strtoupper($countrycode) == "MU") {
3694 //Maurice
3695 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
3696 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3697 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
3698 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3699 }
3700 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
3701 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
3702 $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);
3703 }
3704 } elseif (strtoupper($countrycode) == "SY") {//Syrie
3705 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
3706 $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);
3707 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
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, 3);
3709 }
3710 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
3711 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
3712 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3713 } elseif (dol_strlen($phone) == 13) {//ex: +971_ABC_DEF_GHI
3714 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3715 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
3716 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
3717 }
3718 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
3719 if (dol_strlen($phone) == 13) {//ex: +213_ABC_DEF_GHI
3720 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3721 }
3722 } elseif (strtoupper($countrycode) == "BE") {//Belgique
3723 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
3724 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3725 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
3726 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3727 }
3728 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
3729 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
3730 $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);
3731 }
3732 } elseif (strtoupper($countrycode) == "CO") {//Colombie
3733 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
3734 $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);
3735 }
3736 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
3737 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
3738 $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);
3739 }
3740 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
3741 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
3742 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3743 }
3744 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
3745 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
3746 $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);
3747 }
3748 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
3749 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
3750 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3751 }
3752 } elseif (strtoupper($countrycode) == "CH") {//Suisse
3753 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
3754 $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);
3755 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
3756 $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);
3757 }
3758 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
3759 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
3760 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3761 }
3762 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
3763 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
3764 $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);
3765 }
3766 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
3767 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
3768 $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);
3769 }
3770 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
3771 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
3772 $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);
3773 }
3774 } elseif (strtoupper($countrycode) == "IT") {//Italie
3775 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
3776 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3777 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
3778 $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);
3779 }
3780 } elseif (strtoupper($countrycode) == "AU") {
3781 //Australie
3782 if (dol_strlen($phone) == 12) {
3783 //ex: +61_A_BCDE_FGHI
3784 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
3785 }
3786 } elseif (strtoupper($countrycode) == "LU") {
3787 // Luxembourg
3788 if (dol_strlen($phone) == 10) {// fixe 6 chiffres +352_AA_BB_CC
3789 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3790 } elseif (dol_strlen($phone) == 11) {// fixe 7 chiffres +352_AA_BB_CC_D
3791 $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);
3792 } elseif (dol_strlen($phone) == 12) {// fixe 8 chiffres +352_AA_BB_CC_DD
3793 $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);
3794 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
3795 $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);
3796 }
3797 }
3798
3799 $newphoneastart = $newphoneaend = '';
3800 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
3801 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
3802 $newphoneastart = '<a href="tel:'.$phone.'">';
3803 $newphoneaend .= '</a>';
3804 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
3805 if (empty($user->clicktodial_loaded)) {
3806 $user->fetch_clicktodial();
3807 }
3808
3809 // Define urlmask
3810 $urlmask = getDolGlobalString('CLICKTODIAL_URL', 'ErrorClickToDialModuleNotConfigured');
3811 if (!empty($user->clicktodial_url)) {
3812 $urlmask = $user->clicktodial_url;
3813 }
3814
3815 $clicktodial_poste = (!empty($user->clicktodial_poste) ? urlencode($user->clicktodial_poste) : '');
3816 $clicktodial_login = (!empty($user->clicktodial_login) ? urlencode($user->clicktodial_login) : '');
3817 $clicktodial_password = (!empty($user->clicktodial_password) ? urlencode($user->clicktodial_password) : '');
3818 // This line is for backward compatibility
3819 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
3820 // Thoose lines are for substitution
3821 $substitarray = array('__PHONEFROM__'=>$clicktodial_poste,
3822 '__PHONETO__'=>urlencode($phone),
3823 '__LOGIN__'=>$clicktodial_login,
3824 '__PASS__'=>$clicktodial_password);
3825 $url = make_substitutions($url, $substitarray);
3826 if (!getDolGlobalString('CLICKTODIAL_DO_NOT_USE_AJAX_CALL')) {
3827 // Default and recommended: New method using ajax without submiting a page making a javascript history.go(-1) back
3828 $newphoneastart = '<a href="'.$url.'" class="cssforclicktodial">'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
3829 $newphoneaend = '</a>';
3830 } else {
3831 // Old method
3832 $newphoneastart = '<a href="'.$url.'"';
3833 if (getDolGlobalString('CLICKTODIAL_FORCENEWTARGET')) {
3834 $newphoneastart .= ' target="_blank" rel="noopener noreferrer"';
3835 }
3836 $newphoneastart .= '>';
3837 $newphoneaend .= '</a>';
3838 }
3839 }
3840
3841 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
3842 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3843 $type = 'AC_TEL';
3844 $addlinktoagenda = '';
3845 if ($addlink == 'AC_FAX') {
3846 $type = 'AC_FAX';
3847 }
3848 if (getDolGlobalString('AGENDA_ADDACTIONFORPHONE')) {
3849 $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>';
3850 }
3851 if ($addlinktoagenda) {
3852 $newphone = '<span>'.$newphone.' '.$addlinktoagenda.'</span>';
3853 }
3854 }
3855 }
3856
3857 if (empty($titlealt)) {
3858 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
3859 }
3860 $rep = '';
3861
3862 if ($hookmanager) {
3863 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
3864 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
3865 $rep .= $hookmanager->resPrint;
3866 }
3867 if (empty($reshook)) {
3868 $picto = '';
3869 if ($withpicto) {
3870 if ($withpicto == 'fax') {
3871 $picto = 'phoning_fax';
3872 } elseif ($withpicto == 'phone') {
3873 $picto = 'phoning';
3874 } elseif ($withpicto == 'mobile') {
3875 $picto = 'phoning_mobile';
3876 } else {
3877 $picto = '';
3878 }
3879 }
3880 if ($adddivfloat == 1) {
3881 $rep .= '<div class="nospan float" style="margin-right: 10px">';
3882 } elseif (empty($adddivfloat)) {
3883 $rep .= '<span style="margin-right: 10px;">';
3884 }
3885
3886 $rep .= $newphoneastart;
3887 $rep .= ($withpicto ? img_picto($titlealt, 'object_'.$picto.'.png') : '');
3888 if ($separ != 'hidenum') {
3889 $rep .= ($withpicto ? ' ' : '').$newphone;
3890 }
3891 $rep .= $newphoneaend;
3892
3893 if ($adddivfloat == 1) {
3894 $rep .= '</div>';
3895 } elseif (empty($adddivfloat)) {
3896 $rep .= '</span>';
3897 }
3898 }
3899
3900 return $rep;
3901}
3902
3910function dol_print_ip($ip, $mode = 0)
3911{
3912 global $langs;
3913
3914 $ret = '';
3915
3916 if (empty($mode)) {
3917 $ret .= $ip;
3918 }
3919
3920 if ($mode != 2) {
3921 $countrycode = dolGetCountryCodeFromIp($ip);
3922 if ($countrycode) { // If success, countrycode is us, fr, ...
3923 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
3924 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
3925 } else {
3926 $ret .= ' ('.$countrycode.')';
3927 }
3928 } else {
3929 // Nothing
3930 }
3931 }
3932
3933 return $ret;
3934}
3935
3945{
3946 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
3947 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
3948 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
3949 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
3950 } else {
3951 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
3952 }
3953 } else {
3954 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
3955 }
3956 } else {
3957 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
3958 }
3959 return $ip;
3960}
3961
3970function isHTTPS()
3971{
3972 $isSecure = false;
3973 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
3974 $isSecure = true;
3975 } 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') {
3976 $isSecure = true;
3977 }
3978 return $isSecure;
3979}
3980
3988{
3989 global $conf;
3990
3991 $countrycode = '';
3992
3993 if (!empty($conf->geoipmaxmind->enabled)) {
3994 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3995 //$ip='24.24.24.24';
3996 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
3997 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3998 $geoip = new DolGeoIP('country', $datafile);
3999 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
4000 $countrycode = $geoip->getCountryCodeFromIP($ip);
4001 }
4002
4003 return $countrycode;
4004}
4005
4006
4014{
4015 global $conf, $langs, $user;
4016
4017 //$ret=$user->xxx;
4018 $ret = '';
4019 if (!empty($conf->geoipmaxmind->enabled)) {
4020 $ip = getUserRemoteIP();
4021 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
4022 //$ip='24.24.24.24';
4023 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
4024 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
4025 $geoip = new DolGeoIP('country', $datafile);
4026 $countrycode = $geoip->getCountryCodeFromIP($ip);
4027 $ret = $countrycode;
4028 }
4029 return $ret;
4030}
4031
4044function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
4045{
4046 global $conf, $user, $langs, $hookmanager;
4047
4048 $out = '';
4049
4050 if ($address) {
4051 if ($hookmanager) {
4052 $parameters = array('element' => $element, 'id' => $id);
4053 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
4054 $out .= $hookmanager->resPrint;
4055 }
4056 if (empty($reshook)) {
4057 if (empty($charfornl)) {
4058 $out .= nl2br($address);
4059 } else {
4060 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
4061 }
4062
4063 // TODO Remove this block, we can add this using the hook now
4064 $showgmap = $showomap = 0;
4065 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS')) {
4066 $showgmap = 1;
4067 }
4068 if ($element == 'contact' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_CONTACTS')) {
4069 $showgmap = 1;
4070 }
4071 if ($element == 'member' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_MEMBERS')) {
4072 $showgmap = 1;
4073 }
4074 if ($element == 'user' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_USERS')) {
4075 $showgmap = 1;
4076 }
4077 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS')) {
4078 $showomap = 1;
4079 }
4080 if ($element == 'contact' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_CONTACTS')) {
4081 $showomap = 1;
4082 }
4083 if ($element == 'member' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_MEMBERS')) {
4084 $showomap = 1;
4085 }
4086 if ($element == 'user' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_USERS')) {
4087 $showomap = 1;
4088 }
4089 if ($showgmap) {
4090 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
4091 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4092 }
4093 if ($showomap) {
4094 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
4095 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4096 }
4097 }
4098 }
4099 if ($noprint) {
4100 return $out;
4101 } else {
4102 print $out;
4103 }
4104}
4105
4106
4116function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
4117{
4118 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
4119 return true;
4120 }
4121 if ($acceptuserkey && $address == '__USER_EMAIL__') {
4122 return true;
4123 }
4124 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
4125 return true;
4126 }
4127
4128 return false;
4129}
4130
4139function isValidMXRecord($domain)
4140{
4141 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
4142 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
4143 return 0;
4144 }
4145 if (function_exists('getmxrr')) {
4146 $mxhosts = array();
4147 $weight = array();
4148 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
4149 if (count($mxhosts) > 1) {
4150 return 1;
4151 }
4152 if (count($mxhosts) == 1 && !empty($mxhosts[0])) {
4153 return 1;
4154 }
4155
4156 return 0;
4157 }
4158 }
4159
4160 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4161 return -1;
4162}
4163
4171function isValidPhone($phone)
4172{
4173 return true;
4174}
4175
4176
4186function dolGetFirstLetters($s, $nbofchar = 1)
4187{
4188 $ret = '';
4189 $tmparray = explode(' ', $s);
4190 foreach ($tmparray as $tmps) {
4191 $ret .= dol_substr($tmps, 0, $nbofchar);
4192 }
4193
4194 return $ret;
4195}
4196
4197
4205function dol_strlen($string, $stringencoding = 'UTF-8')
4206{
4207 if (is_null($string)) {
4208 return 0;
4209 }
4210
4211 if (function_exists('mb_strlen')) {
4212 return mb_strlen($string, $stringencoding);
4213 } else {
4214 return strlen($string);
4215 }
4216}
4217
4228function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4229{
4230 global $langs;
4231
4232 if (empty($stringencoding)) {
4233 $stringencoding = $langs->charset_output;
4234 }
4235
4236 $ret = '';
4237 if (empty($trunconbytes)) {
4238 if (function_exists('mb_substr')) {
4239 $ret = mb_substr($string, $start, $length, $stringencoding);
4240 } else {
4241 $ret = substr($string, $start, $length);
4242 }
4243 } else {
4244 if (function_exists('mb_strcut')) {
4245 $ret = mb_strcut($string, $start, $length, $stringencoding);
4246 } else {
4247 $ret = substr($string, $start, $length);
4248 }
4249 }
4250 return $ret;
4251}
4252
4253
4267function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4268{
4269 global $conf;
4270
4271 if (empty($size) || getDolGlobalString('MAIN_DISABLE_TRUNC')) {
4272 return $string;
4273 }
4274
4275 if (empty($stringencoding)) {
4276 $stringencoding = 'UTF-8';
4277 }
4278 // reduce for small screen
4279 if ($conf->dol_optimize_smallscreen == 1 && $display == 1) {
4280 $size = round($size / 3);
4281 }
4282
4283 // We go always here
4284 if ($trunc == 'right') {
4285 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4286 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4287 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4288 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4289 } else {
4290 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4291 return $string;
4292 }
4293 } elseif ($trunc == 'middle') {
4294 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4295 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4296 $size1 = round($size / 2);
4297 $size2 = round($size / 2);
4298 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4299 } else {
4300 return $string;
4301 }
4302 } elseif ($trunc == 'left') {
4303 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4304 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4305 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4306 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4307 } else {
4308 return $string;
4309 }
4310 } elseif ($trunc == 'wrap') {
4311 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4312 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4313 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4314 } else {
4315 return $string;
4316 }
4317 } else {
4318 return 'BadParam3CallingDolTrunc';
4319 }
4320}
4321
4328function getPictoForType($key)
4329{
4330 // Set array with type -> picto
4331 $type2picto = array(
4332 'varchar'=>'font',
4333 'text'=>'font',
4334 'html'=>'code',
4335 'int'=>'sort-numeric-down',
4336 'double'=>'sort-numeric-down',
4337 'price'=>'currency',
4338 'pricecy'=>'multicurrency',
4339 'password' => 'key',
4340 'boolean'=>'check-square',
4341 'date'=>'calendar',
4342 'datetime'=>'calendar',
4343 'phone'=> 'phone',
4344 'mail'=> 'email',
4345 'url'=> 'url',
4346 'ip'=> 'country',
4347 'select' => 'list',
4348 'sellist' => 'list',
4349 'radio' => 'check-circle',
4350 'checkbox' => 'check-square',
4351 'chkbxlst' => 'check-square',
4352 'link' => 'link',
4353 'separate'=> 'minus'
4354 );
4355
4356 if (!empty($type2picto[$key])) {
4357 return img_picto('', $type2picto[$key], 'class="pictofixedwidth"');
4358 }
4359
4360 return img_picto('', 'generic', 'class="pictofixedwidth"');
4361}
4362
4363
4385function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4386{
4387 global $conf, $langs;
4388
4389 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4390 $url = DOL_URL_ROOT;
4391 $theme = isset($conf->theme) ? $conf->theme : null;
4392 $path = 'theme/'.$theme;
4393 if (empty($picto)) {
4394 $picto = 'generic';
4395 }
4396
4397 // Define fullpathpicto to use into src
4398 if ($pictoisfullpath) {
4399 // Clean parameters
4400 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4401 $picto .= '.png';
4402 }
4403 $fullpathpicto = $picto;
4404 $reg = array();
4405 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4406 $morecss .= ($morecss ? ' ' : '').$reg[1];
4407 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4408 }
4409 } else {
4410 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', (is_null($picto) ? '' : $picto));
4411 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4412 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4413
4414 if (strpos($pictowithouttext, 'fontawesome_') === 0 || strpos($pictowithouttext, 'fa-') === 0) {
4415 // This is a font awesome image 'fontawesome_xxx' or 'fa-xxx'
4416 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4417 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4418
4419 // Compatibility with old fontawesome versions
4420 if ($pictowithouttext == 'file-o') {
4421 $pictowithouttext = 'file';
4422 }
4423
4424 $pictowithouttextarray = explode('_', $pictowithouttext);
4425 $marginleftonlyshort = 0;
4426
4427 if (!empty($pictowithouttextarray[1])) {
4428 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4429 $fakey = 'fa-'.$pictowithouttextarray[0];
4430 $faprefix = empty($pictowithouttextarray[1]) ? 'fas' : $pictowithouttextarray[1];
4431 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4432 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4433 } else {
4434 $fakey = 'fa-'.$pictowithouttext;
4435 $faprefix = 'fas';
4436 $facolor = '';
4437 $fasize = '';
4438 }
4439
4440 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4441 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4442 $morestyle = '';
4443 $reg = array();
4444 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4445 $morecss .= ($morecss ? ' ' : '').$reg[1];
4446 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4447 }
4448 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4449 $morestyle = $reg[1];
4450 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4451 }
4452 $moreatt = trim($moreatt);
4453
4454 $enabledisablehtml = '<span class="'.$faprefix.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4455 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4456 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4457 $enabledisablehtml .= $titlealt;
4458 }*/
4459 $enabledisablehtml .= '</span>';
4460
4461 return $enabledisablehtml;
4462 }
4463
4464 if (empty($srconly) && in_array($pictowithouttext, array(
4465 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4466 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'angle-double-down', 'angle-double-up', 'asset',
4467 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building',
4468 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4469 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'code', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4470 'check-circle', 'check-square', 'currency', 'multicurrency',
4471 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies',
4472 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4473 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4474 'filter', 'file', 'file-o', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus', 'font',
4475 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4476 'hands-helping', 'help', 'holiday',
4477 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4478 'key', 'knowledgemanagement',
4479 'label', 'language', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4480 'margin', 'map-marker-alt', 'member', 'meeting', 'minus', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4481 'off', 'on', 'order',
4482 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4483 'stock', 'resize', 'service', 'stats',
4484 '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',
4485 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4486 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4487 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4488 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4489 'technic', 'ticket',
4490 'error', 'warning',
4491 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4492 'shapes', 'skill', 'square', 'sort-numeric-down', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4493 'tick', 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda',
4494 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4495 'conferenceorbooth', 'eventorganization',
4496 'stamp', 'signature'
4497 ))) {
4498 $fakey = $pictowithouttext;
4499 $facolor = '';
4500 $fasize = '';
4501 $fa = getDolGlobalString('MAIN_FONTAWESOME_ICON_STYLE', 'fas');
4502 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'))) {
4503 $fa = 'far';
4504 }
4505 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4506 $fa = 'fab';
4507 }
4508
4509 $arrayconvpictotofa = array(
4510 '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',
4511 'bank_account'=>'university',
4512 'bill'=>'file-invoice-dollar', 'billa'=>'file-excel', 'billr'=>'file-invoice-dollar', 'billd'=>'file-medical',
4513 'supplier_invoice'=>'file-invoice-dollar', 'supplier_invoicea'=>'file-excel', 'supplier_invoicer'=>'file-invoice-dollar', 'supplier_invoiced'=>'file-medical',
4514 'bom'=>'shapes',
4515 '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',
4516 'donation'=>'file-alt', 'dynamicprice'=>'hand-holding-usd',
4517 'setup'=>'cog', 'companies'=>'building', 'products'=>'cube', 'commercial'=>'suitcase', 'invoicing'=>'coins',
4518 'accounting'=>'search-dollar', 'category'=>'tag', 'dollyrevert'=>'dolly',
4519 'file-o'=>'file', 'generate'=>'plus-square', 'hrm'=>'user-tie', 'incoterm'=>'truck-loading',
4520 'margin'=>'calculator', 'members'=>'user-friends', 'ticket'=>'ticket-alt', 'globe'=>'external-link-alt', 'lot'=>'barcode',
4521 'email'=>'at', 'establishment'=>'building', 'edit'=>'pencil-alt', 'entity'=>'globe',
4522 'graph'=>'chart-line', 'grip_title'=>'arrows-alt', 'grip'=>'arrows-alt', 'help'=>'question-circle',
4523 'generic'=>'file', 'holiday'=>'umbrella-beach',
4524 'info'=>'info-circle', 'inventory'=>'boxes', 'intracommreport'=>'globe-europe', 'jobprofile'=>'cogs',
4525 'knowledgemanagement'=>'ticket-alt', 'label'=>'layer-group', 'line'=>'bars', 'loan'=>'money-bill-alt',
4526 'member'=>'user-alt', 'meeting'=>'chalkboard-teacher', 'mrp'=>'cubes', 'next'=>'arrow-alt-circle-right',
4527 'trip'=>'wallet', 'expensereport'=>'wallet', 'group'=>'users', 'movement'=>'people-carry',
4528 'sign-out'=>'sign-out-alt',
4529 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_warning'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star',
4530 'bank'=>'university', 'close_title'=>'times', 'delete'=>'trash', 'filter'=>'filter',
4531 'list-alt'=>'list-alt', 'calendarlist'=>'bars', 'calendar'=>'calendar-alt', 'calendarmonth'=>'calendar-alt', 'calendarweek'=>'calendar-week', 'calendarday'=>'calendar-day', 'calendarperuser'=>'table',
4532 'intervention'=>'ambulance', 'invoice'=>'file-invoice-dollar', 'order'=>'file-invoice',
4533 'error'=>'exclamation-triangle', 'warning'=>'exclamation-triangle',
4534 'other'=>'square',
4535 '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',
4536 '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',
4537 'recent' => 'check-square', 'reception'=>'dolly', 'recruitmentjobposition'=>'id-card-alt', 'recruitmentcandidature'=>'id-badge',
4538 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature',
4539 'refresh'=>'redo', 'region'=>'map-marked', 'replacement'=>'exchange-alt', 'resource'=>'laptop-house', 'recurring'=>'history',
4540 'service'=>'concierge-bell',
4541 'skill'=>'shapes', 'state'=>'map-marked-alt', 'security'=>'key', 'salary'=>'wallet', 'shipment'=>'dolly', 'stock'=>'box-open', 'stats' => 'chart-bar', 'split'=>'code-branch', 'stripe'=>'stripe-s',
4542 'supplier'=>'building', 'technic'=>'cogs',
4543 'timespent'=>'clock', 'tick' => 'check', 'title_setup'=>'tools', 'title_accountancy'=>'money-check-alt', 'title_bank'=>'university', 'title_hrm'=>'umbrella-beach',
4544 'title_agenda'=>'calendar-alt',
4545 'uncheck'=>'times', 'uparrow'=>'share', 'url'=>'external-link-alt', 'vat'=>'money-check-alt', 'vcard'=>'arrow-alt-circle-down',
4546 'jabber'=>'comment-o',
4547 'website'=>'globe-americas', 'workstation'=>'pallet', 'webhook'=>'bullseye', 'world'=>'globe', 'private'=>'user-lock',
4548 'conferenceorbooth'=>'chalkboard-teacher', 'eventorganization'=>'project-diagram'
4549 );
4550 if ($conf->currency == 'EUR') {
4551 $arrayconvpictotofa['currency'] = 'euro-sign';
4552 $arrayconvpictotofa['multicurrency'] = 'dollar-sign';
4553 } else {
4554 $arrayconvpictotofa['currency'] = 'dollar-sign';
4555 $arrayconvpictotofa['multicurrency'] = 'euro-sign';
4556 }
4557 if ($pictowithouttext == 'off') {
4558 $fakey = 'fa-square';
4559 $fasize = '1.3em';
4560 } elseif ($pictowithouttext == 'on') {
4561 $fakey = 'fa-check-square';
4562 $fasize = '1.3em';
4563 } elseif ($pictowithouttext == 'listlight') {
4564 $fakey = 'fa-download';
4565 $marginleftonlyshort = 1;
4566 } elseif ($pictowithouttext == 'printer') {
4567 $fakey = 'fa-print';
4568 $fasize = '1.2em';
4569 } elseif ($pictowithouttext == 'note') {
4570 $fakey = 'fa-sticky-note';
4571 $marginleftonlyshort = 1;
4572 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
4573 $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');
4574 $fakey = 'fa-'.$convertarray[$pictowithouttext];
4575 if (preg_match('/selected/', $pictowithouttext)) {
4576 $facolor = '#888';
4577 }
4578 $marginleftonlyshort = 1;
4579 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
4580 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
4581 } else {
4582 $fakey = 'fa-'.$pictowithouttext;
4583 }
4584
4585 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment'))) {
4586 $morecss .= ' em092';
4587 }
4588 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
4589 $morecss .= ' em088';
4590 }
4591 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
4592 $morecss .= ' em080';
4593 }
4594
4595 // Define $marginleftonlyshort
4596 $arrayconvpictotomarginleftonly = array(
4597 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
4598 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
4599 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
4600 );
4601 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
4602 $marginleftonlyshort = 0;
4603 }
4604
4605 // Add CSS
4606 $arrayconvpictotomorcess = array(
4607 'action'=>'infobox-action', 'account'=>'infobox-bank_account', 'accounting_account'=>'infobox-bank_account', 'accountline'=>'infobox-bank_account', 'accountancy'=>'infobox-bank_account', 'asset'=>'infobox-bank_account',
4608 'bank_account'=>'infobox-bank_account',
4609 'bill'=>'infobox-commande', 'billa'=>'infobox-commande', 'billr'=>'infobox-commande', 'billd'=>'infobox-commande',
4610 'margin'=>'infobox-bank_account', 'conferenceorbooth'=>'infobox-project',
4611 'cash-register'=>'infobox-bank_account', 'contract'=>'infobox-contrat', 'check'=>'font-status4', 'collab'=>'infobox-action', 'conversation'=>'infobox-contrat',
4612 'donation'=>'infobox-commande', 'dolly'=>'infobox-commande', 'dollyrevert'=>'flip infobox-order_supplier',
4613 'ecm'=>'infobox-action', 'eventorganization'=>'infobox-project',
4614 'hrm'=>'infobox-adherent', 'group'=>'infobox-adherent', 'intervention'=>'infobox-contrat',
4615 'incoterm'=>'infobox-supplier_proposal',
4616 'currency'=>'infobox-bank_account', 'multicurrency'=>'infobox-bank_account',
4617 'members'=>'infobox-adherent', 'member'=>'infobox-adherent', 'money-bill-alt'=>'infobox-bank_account',
4618 'order'=>'infobox-commande',
4619 'user'=>'infobox-adherent', 'users'=>'infobox-adherent',
4620 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_warning'=>'font-status4 warning', 'switch_on_red'=>'font-status8',
4621 'holiday'=>'infobox-holiday', 'info'=>'opacityhigh', 'invoice'=>'infobox-commande',
4622 'knowledgemanagement'=>'infobox-contrat rotate90', 'loan'=>'infobox-bank_account',
4623 'payment'=>'infobox-bank_account', 'payment_vat'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'pos'=>'infobox-bank_account', 'project'=>'infobox-project', 'projecttask'=>'infobox-project',
4624 'propal'=>'infobox-propal', 'proposal'=>'infobox-propal','private'=>'infobox-project',
4625 'reception'=>'flip', 'recruitmentjobposition'=>'infobox-adherent', 'recruitmentcandidature'=>'infobox-adherent',
4626 'resource'=>'infobox-action',
4627 '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',
4628 'supplier'=>'infobox-order_supplier', 'supplier_order'=>'infobox-order_supplier', 'supplier_proposal'=>'infobox-supplier_proposal',
4629 'ticket'=>'infobox-contrat', 'title_accountancy'=>'infobox-bank_account', 'title_hrm'=>'infobox-holiday', 'expensereport'=>'infobox-expensereport', 'trip'=>'infobox-expensereport', 'title_agenda'=>'infobox-action',
4630 'vat'=>'infobox-bank_account',
4631 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
4632 'list-alt'=>'imgforviewmode', 'calendar'=>'imgforviewmode', 'calendarweek'=>'imgforviewmode', 'calendarmonth'=>'imgforviewmode', 'calendarday'=>'imgforviewmode', 'calendarperuser'=>'imgforviewmode'
4633 );
4634 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4635 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
4636 }
4637
4638 // Define $color
4639 $arrayconvpictotocolor = array(
4640 'address'=>'#6c6aa8', 'building'=>'#6c6aa8', 'bom'=>'#a69944',
4641 'clone'=>'#999', 'cog'=>'#999', 'companies'=>'#6c6aa8', 'company'=>'#6c6aa8', 'contact'=>'#6c6aa8', 'cron'=>'#555',
4642 'dynamicprice'=>'#a69944',
4643 'edit'=>'#444', 'note'=>'#999', 'error'=>'', 'help'=>'#bbb', 'listlight'=>'#999', 'language'=>'#555',
4644 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
4645 'lock'=>'#ddd', 'lot'=>'#a69944',
4646 'map-marker-alt'=>'#aaa', 'mrp'=>'#a69944', 'product'=>'#a69944', 'service'=>'#a69944', 'inventory'=>'#a69944', 'stock'=>'#a69944', 'movement'=>'#a69944',
4647 'other'=>'#ddd', 'world'=>'#986c6a',
4648 'partnership'=>'#6c6aa8', 'playdisabled'=>'#ccc', 'printer'=>'#444', 'projectpub'=>'#986c6a', 'reception'=>'#a69944', 'resize'=>'#444', 'rss'=>'#cba',
4649 //'shipment'=>'#a69944',
4650 'security'=>'#999', 'square'=>'#888', 'stop-circle'=>'#888', 'stats'=>'#444', 'switch_off'=>'#999',
4651 'technic' => '#999', 'tick' => '#282', 'timespent' => '#555',
4652 'uncheck'=>'#800', 'uparrow'=>'#555', 'user-cog'=>'#999', 'country'=>'#aaa', 'globe-americas'=>'#aaa', 'region'=>'#aaa', 'state'=>'#aaa',
4653 'website'=>'#304', 'workstation'=>'#a69944'
4654 );
4655 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4656 $facolor = $arrayconvpictotocolor[$pictowithouttext];
4657 }
4658
4659 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4660 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4661 $morestyle = '';
4662 $reg = array();
4663 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4664 $morecss .= ($morecss ? ' ' : '').$reg[1];
4665 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4666 }
4667 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4668 $morestyle = $reg[1];
4669 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4670 }
4671 $moreatt = trim($moreatt);
4672
4673 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4674 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4675 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4676 $enabledisablehtml .= $titlealt;
4677 }*/
4678 $enabledisablehtml .= '</span>';
4679
4680 return $enabledisablehtml;
4681 }
4682
4683 if (getDolGlobalString('MAIN_OVERWRITE_THEME_PATH')) {
4684 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_PATH') . '/theme/'.$theme; // If the theme does not have the same name as the module
4685 } elseif (getDolGlobalString('MAIN_OVERWRITE_THEME_RES')) {
4686 $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
4687 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
4688 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
4689 }
4690
4691 // If we ask an image into $url/$mymodule/img (instead of default path)
4692 $regs = array();
4693 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
4694 $picto = $regs[1];
4695 $path = $regs[2]; // $path is $mymodule
4696 }
4697
4698 // Clean parameters
4699 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4700 $picto .= '.png';
4701 }
4702 // If alt path are defined, define url where img file is, according to physical path
4703 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
4704 foreach ($conf->file->dol_document_root as $type => $dirroot) {
4705 if ($type == 'main') {
4706 continue;
4707 }
4708 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommanded
4709 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
4710 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
4711 break;
4712 }
4713 }
4714
4715 // $url is '' or '/custom', $path is current theme or
4716 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
4717 }
4718
4719 if ($srconly) {
4720 return $fullpathpicto;
4721 }
4722
4723 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
4724 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
4725}
4726
4740function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0)
4741{
4742 if (strpos($picto, '^') === 0) {
4743 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
4744 } else {
4745 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
4746 }
4747}
4748
4760function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
4761{
4762 global $conf;
4763
4764 if (is_numeric($picto)) {
4765 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
4766 //$picto = $leveltopicto[$picto];
4767 return '<i class="fa fa-weather-level'.$picto.'"></i>';
4768 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4769 $picto .= '.png';
4770 }
4771
4772 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
4773
4774 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
4775}
4776
4788function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
4789{
4790 global $conf;
4791
4792 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4793 $picto .= '.png';
4794 }
4795
4796 if ($pictoisfullpath) {
4797 $path = $picto;
4798 } else {
4799 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
4800
4801 if (getDolGlobalInt('MAIN_MODULE_CAN_OVERWRITE_COMMONICONS')) {
4802 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
4803
4804 if (file_exists($themepath)) {
4805 $path = $themepath;
4806 }
4807 }
4808 }
4809
4810 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
4811}
4812
4826function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
4827{
4828 global $langs;
4829
4830 if (empty($titlealt) || $titlealt == 'default') {
4831 if ($numaction == '-1' || $numaction == 'ST_NO') {
4832 $numaction = -1;
4833 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
4834 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
4835 $numaction = 0;
4836 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
4837 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
4838 $numaction = 1;
4839 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
4840 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
4841 $numaction = 2;
4842 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
4843 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
4844 $numaction = 3;
4845 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
4846 } else {
4847 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
4848 $numaction = 0;
4849 }
4850 }
4851 if (!is_numeric($numaction)) {
4852 $numaction = 0;
4853 }
4854
4855 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
4856}
4857
4865function img_pdf($titlealt = 'default', $size = 3)
4866{
4867 global $langs;
4868
4869 if ($titlealt == 'default') {
4870 $titlealt = $langs->trans('Show');
4871 }
4872
4873 return img_picto($titlealt, 'pdf'.$size.'.png');
4874}
4875
4883function img_edit_add($titlealt = 'default', $other = '')
4884{
4885 global $langs;
4886
4887 if ($titlealt == 'default') {
4888 $titlealt = $langs->trans('Add');
4889 }
4890
4891 return img_picto($titlealt, 'edit_add.png', $other);
4892}
4900function img_edit_remove($titlealt = 'default', $other = '')
4901{
4902 global $langs;
4903
4904 if ($titlealt == 'default') {
4905 $titlealt = $langs->trans('Remove');
4906 }
4907
4908 return img_picto($titlealt, 'edit_remove.png', $other);
4909}
4910
4919function img_edit($titlealt = 'default', $float = 0, $other = '')
4920{
4921 global $langs;
4922
4923 if ($titlealt == 'default') {
4924 $titlealt = $langs->trans('Modify');
4925 }
4926
4927 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
4928}
4929
4938function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
4939{
4940 global $langs;
4941
4942 if ($titlealt == 'default') {
4943 $titlealt = $langs->trans('View');
4944 }
4945
4946 $moreatt = ($float ? 'style="float: right" ' : '').$other;
4947
4948 return img_picto($titlealt, 'eye', $moreatt);
4949}
4950
4959function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
4960{
4961 global $langs;
4962
4963 if ($titlealt == 'default') {
4964 $titlealt = $langs->trans('Delete');
4965 }
4966
4967 return img_picto($titlealt, 'delete.png', $other, false, 0, 0, '', $morecss);
4968}
4969
4977function img_printer($titlealt = "default", $other = '')
4978{
4979 global $langs;
4980 if ($titlealt == "default") {
4981 $titlealt = $langs->trans("Print");
4982 }
4983 return img_picto($titlealt, 'printer.png', $other);
4984}
4985
4993function img_split($titlealt = 'default', $other = 'class="pictosplit"')
4994{
4995 global $langs;
4996
4997 if ($titlealt == 'default') {
4998 $titlealt = $langs->trans('Split');
4999 }
5000
5001 return img_picto($titlealt, 'split.png', $other);
5002}
5003
5011function img_help($usehelpcursor = 1, $usealttitle = 1)
5012{
5013 global $langs;
5014
5015 if ($usealttitle) {
5016 if (is_string($usealttitle)) {
5017 $usealttitle = dol_escape_htmltag($usealttitle);
5018 } else {
5019 $usealttitle = $langs->trans('Info');
5020 }
5021 }
5022
5023 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
5024}
5025
5032function img_info($titlealt = 'default')
5033{
5034 global $langs;
5035
5036 if ($titlealt == 'default') {
5037 $titlealt = $langs->trans('Informations');
5038 }
5039
5040 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
5041}
5042
5051function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
5052{
5053 global $langs;
5054
5055 if ($titlealt == 'default') {
5056 $titlealt = $langs->trans('Warning');
5057 }
5058
5059 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
5060 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
5061}
5062
5069function img_error($titlealt = 'default')
5070{
5071 global $langs;
5072
5073 if ($titlealt == 'default') {
5074 $titlealt = $langs->trans('Error');
5075 }
5076
5077 return img_picto($titlealt, 'error.png');
5078}
5079
5087function img_next($titlealt = 'default', $moreatt = '')
5088{
5089 global $langs;
5090
5091 if ($titlealt == 'default') {
5092 $titlealt = $langs->trans('Next');
5093 }
5094
5095 //return img_picto($titlealt, 'next.png', $moreatt);
5096 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5097}
5098
5106function img_previous($titlealt = 'default', $moreatt = '')
5107{
5108 global $langs;
5109
5110 if ($titlealt == 'default') {
5111 $titlealt = $langs->trans('Previous');
5112 }
5113
5114 //return img_picto($titlealt, 'previous.png', $moreatt);
5115 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5116}
5117
5126function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
5127{
5128 global $langs;
5129
5130 if ($titlealt == 'default') {
5131 $titlealt = $langs->trans('Down');
5132 }
5133
5134 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
5135}
5136
5145function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
5146{
5147 global $langs;
5148
5149 if ($titlealt == 'default') {
5150 $titlealt = $langs->trans('Up');
5151 }
5152
5153 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
5154}
5155
5164function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
5165{
5166 global $langs;
5167
5168 if ($titlealt == 'default') {
5169 $titlealt = $langs->trans('Left');
5170 }
5171
5172 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
5173}
5174
5183function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
5184{
5185 global $langs;
5186
5187 if ($titlealt == 'default') {
5188 $titlealt = $langs->trans('Right');
5189 }
5190
5191 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
5192}
5193
5201function img_allow($allow, $titlealt = 'default')
5202{
5203 global $langs;
5204
5205 if ($titlealt == 'default') {
5206 $titlealt = $langs->trans('Active');
5207 }
5208
5209 if ($allow == 1) {
5210 return img_picto($titlealt, 'tick.png');
5211 }
5212
5213 return '-';
5214}
5215
5223function img_credit_card($brand, $morecss = null)
5224{
5225 if (is_null($morecss)) {
5226 $morecss = 'fa-2x';
5227 }
5228
5229 if ($brand == 'visa' || $brand == 'Visa') {
5230 $brand = 'cc-visa';
5231 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5232 $brand = 'cc-mastercard';
5233 } elseif ($brand == 'amex' || $brand == 'American Express') {
5234 $brand = 'cc-amex';
5235 } elseif ($brand == 'discover' || $brand == 'Discover') {
5236 $brand = 'cc-discover';
5237 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5238 $brand = 'cc-jcb';
5239 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5240 $brand = 'cc-diners-club';
5241 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5242 $brand = 'credit-card';
5243 }
5244
5245 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5246}
5247
5256function img_mime($file, $titlealt = '', $morecss = '')
5257{
5258 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5259
5260 $mimetype = dol_mimetype($file, '', 1);
5261 $mimeimg = dol_mimetype($file, '', 2);
5262 $mimefa = dol_mimetype($file, '', 4);
5263
5264 if (empty($titlealt)) {
5265 $titlealt = 'Mime type: '.$mimetype;
5266 }
5267
5268 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5269 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5270}
5271
5272
5280function img_search($titlealt = 'default', $other = '')
5281{
5282 global $conf, $langs;
5283
5284 if ($titlealt == 'default') {
5285 $titlealt = $langs->trans('Search');
5286 }
5287
5288 $img = img_picto($titlealt, 'search.png', $other, false, 1);
5289
5290 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5291 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5292
5293 return $input;
5294}
5295
5303function img_searchclear($titlealt = 'default', $other = '')
5304{
5305 global $conf, $langs;
5306
5307 if ($titlealt == 'default') {
5308 $titlealt = $langs->trans('Search');
5309 }
5310
5311 $img = img_picto($titlealt, 'searchclear.png', $other, false, 1);
5312
5313 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5314 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5315
5316 return $input;
5317}
5318
5330function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '')
5331{
5332 global $conf, $langs;
5333
5334 if ($infoonimgalt) {
5335 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5336 } else {
5337 if (empty($conf->use_javascript_ajax)) {
5338 $textfordropdown = '';
5339 }
5340
5341 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5342 $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>');
5343
5344 if ($textfordropdown) {
5345 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5346 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5347 jQuery(document).ready(function() {
5348 jQuery(".'.$class.'text").click(function() {
5349 console.log("toggle text");
5350 jQuery(".'.$class.'").toggle();
5351 });
5352 });
5353 </script>';
5354
5355 $result = $tmpresult.$result;
5356 }
5357 }
5358
5359 return $result;
5360}
5361
5362
5374function dol_print_error($db = '', $error = '', $errors = null)
5375{
5376 global $conf, $langs, $argv;
5377 global $dolibarr_main_prod;
5378
5379 $out = '';
5380 $syslog = '';
5381
5382 // If error occurs before the $lang object was loaded
5383 if (!$langs) {
5384 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5385 $langs = new Translate('', $conf);
5386 $langs->load("main");
5387 }
5388
5389 // Load translation files required by the error messages
5390 $langs->loadLangs(array('main', 'errors'));
5391
5392 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5393 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5394 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5395 $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";
5396 }
5397 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5398
5399 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5400 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5401 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5402 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5403 }
5404 if (function_exists("phpversion")) {
5405 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5406 }
5407 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5408 if (function_exists("php_uname")) {
5409 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5410 }
5411 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5412 $out .= "<br>\n";
5413 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5414 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5415 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5416 $out .= "<br>\n";
5417 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5418 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5419 } else { // Mode CLI
5420 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5421 $syslog .= "pid=".dol_getmypid();
5422 }
5423
5424 if (!empty($conf->modules)) {
5425 $out .= "<b>".$langs->trans("Modules").":</b> ".join(', ', $conf->modules)."<br>\n";
5426 }
5427
5428 if (is_object($db)) {
5429 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5430 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5431 $lastqueryerror = $db->lastqueryerror();
5432 if (!utf8_check($lastqueryerror)) {
5433 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5434 }
5435 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5436 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5437 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5438 $out .= "<br>\n";
5439 } else { // Mode CLI
5440 // No dol_escape_htmltag for output, we are in CLI mode
5441 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5442 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5443 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5444 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5445 }
5446 $syslog .= ", sql=".$db->lastquery();
5447 $syslog .= ", db_error=".$db->lasterror();
5448 }
5449
5450 if ($error || $errors) {
5451 $langs->load("errors");
5452
5453 // Merge all into $errors array
5454 if (is_array($error) && is_array($errors)) {
5455 $errors = array_merge($error, $errors);
5456 } elseif (is_array($error)) {
5457 $errors = $error;
5458 } elseif (is_array($errors)) {
5459 $errors = array_merge(array($error), $errors);
5460 } else {
5461 $errors = array_merge(array($error), array($errors));
5462 }
5463
5464 foreach ($errors as $msg) {
5465 if (empty($msg)) {
5466 continue;
5467 }
5468 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5469 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5470 } else { // Mode CLI
5471 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5472 }
5473 $syslog .= ", msg=".$msg;
5474 }
5475 }
5476 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5477 xdebug_print_function_stack();
5478 $out .= '<b>XDebug informations:</b>'."<br>\n";
5479 $out .= 'File: '.xdebug_call_file()."<br>\n";
5480 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5481 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5482 $out .= "<br>\n";
5483 }
5484
5485 // Return a http header with error code if possible
5486 if (!headers_sent()) {
5487 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5488 top_httphead();
5489 }
5490 //http_response_code(500); // If we use 500, message is not ouput with some command line tools
5491 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
5492 }
5493
5494 if (empty($dolibarr_main_prod)) {
5495 print $out;
5496 } else {
5497 if (empty($langs->defaultlang)) {
5498 $langs->setDefaultLang();
5499 }
5500 $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.
5501 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5502 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";
5503 print $langs->trans("DolibarrHasDetectedError").'. ';
5504 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5505 if (!defined("MAIN_CORE_ERROR")) {
5506 define("MAIN_CORE_ERROR", 1);
5507 }
5508 }
5509
5510 dol_syslog("Error ".$syslog, LOG_ERR);
5511}
5512
5523function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5524{
5525 global $langs, $conf;
5526
5527 if (empty($email)) {
5528 $email = $conf->global->MAIN_INFO_SOCIETE_MAIL;
5529 }
5530
5531 $langs->load("errors");
5532 $now = dol_now();
5533
5534 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5535 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5536 if ($errormessage) {
5537 print '<br><br>'.$errormessage;
5538 }
5539 if (is_array($errormessages) && count($errormessages)) {
5540 foreach ($errormessages as $mesgtoshow) {
5541 print '<br><br>'.$mesgtoshow;
5542 }
5543 }
5544 print '</div></div>';
5545}
5546
5563function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
5564{
5565 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
5566}
5567
5586function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
5587{
5588 global $conf, $langs, $form;
5589 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
5590
5591 if ($moreattrib == 'class="right"') {
5592 $prefix .= 'right '; // For backward compatibility
5593 }
5594
5595 $sortorder = strtoupper($sortorder);
5596 $out = '';
5597 $sortimg = '';
5598
5599 $tag = 'th';
5600 if ($thead == 2) {
5601 $tag = 'div';
5602 }
5603
5604 $tmpsortfield = explode(',', $sortfield);
5605 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
5606 $tmpfield = explode(',', $field);
5607 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
5608
5609 if (!getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle)) {
5610 $prefix = 'wrapcolumntitle '.$prefix;
5611 }
5612
5613 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
5614 // If field is used as sort criteria we use a specific css class liste_titre_sel
5615 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
5616 $liste_titre = 'liste_titre';
5617 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
5618 $liste_titre = 'liste_titre_sel';
5619 }
5620
5621 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
5622 //$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)).'"' : '');
5623 $tagstart .= ($name && !getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
5624 $tagstart .= '>';
5625
5626 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5627 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5628 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5629 $options = preg_replace('/&+/i', '&', $options);
5630 if (!preg_match('/^&/', $options)) {
5631 $options = '&'.$options;
5632 }
5633
5634 $sortordertouseinlink = '';
5635 if ($field1 != $sortfield1) { // We are on another field than current sorted field
5636 if (preg_match('/^DESC/i', $sortorder)) {
5637 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5638 } else { // We reverse the var $sortordertouseinlink
5639 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5640 }
5641 } else { // We are on field that is the first current sorting criteria
5642 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
5643 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5644 } else {
5645 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5646 }
5647 }
5648 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
5649 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
5650 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5651 $out .= '>';
5652 }
5653 if ($tooltip) {
5654 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
5655 if (preg_match('/:\w+$/', $tooltip)) {
5656 $tmptooltip = explode(':', $tooltip);
5657 } else {
5658 $tmptooltip = array($tooltip);
5659 }
5660 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
5661 } else {
5662 $out .= $langs->trans($name);
5663 }
5664
5665 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5666 $out .= '</a>';
5667 }
5668
5669 if (empty($thead) && $field) { // If this is a sort field
5670 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5671 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5672 $options = preg_replace('/&+/i', '&', $options);
5673 if (!preg_match('/^&/', $options)) {
5674 $options = '&'.$options;
5675 }
5676
5677 if (!$sortorder || ($field1 != $sortfield1)) {
5678 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5679 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5680 } else {
5681 if (preg_match('/^DESC/', $sortorder)) {
5682 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5683 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
5684 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
5685 }
5686 if (preg_match('/^ASC/', $sortorder)) {
5687 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
5688 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5689 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
5690 }
5691 }
5692 }
5693
5694 $tagend = '</'.$tag.'>';
5695
5696 $out = $tagstart.$sortimg.$out.$tagend;
5697
5698 return $out;
5699}
5700
5709function print_titre($title)
5710{
5711 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
5712
5713 print '<div class="titre">'.$title.'</div>';
5714}
5715
5727function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
5728{
5729 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
5730}
5731
5745function load_fiche_titre($titre, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
5746{
5747 global $conf;
5748
5749 $return = '';
5750
5751 if ($picto == 'setup') {
5752 $picto = 'generic';
5753 }
5754
5755 $return .= "\n";
5756 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
5757 $return .= '<tr class="titre">';
5758 if ($picto) {
5759 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
5760 }
5761 $return .= '<td class="nobordernopadding valignmiddle col-title">';
5762 $return .= '<div class="titre inline-block">'.$titre.'</div>';
5763 $return .= '</td>';
5764 if (dol_strlen($morehtmlcenter)) {
5765 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5766 }
5767 if (dol_strlen($morehtmlright)) {
5768 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
5769 }
5770 $return .= '</tr></table>'."\n";
5771
5772 return $return;
5773}
5774
5798function 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 = '')
5799{
5800 global $conf;
5801
5802 $savlimit = $limit;
5803 $savtotalnboflines = $totalnboflines;
5804 $totalnboflines = abs((int) $totalnboflines);
5805
5806 $page = (int) $page;
5807
5808 if ($picto == 'setup') {
5809 $picto = 'title_setup.png';
5810 }
5811 if (($conf->browser->name == 'ie') && $picto == 'generic') {
5812 $picto = 'title.gif';
5813 }
5814 if ($limit < 0) {
5815 $limit = $conf->liste_limit;
5816 }
5817
5818 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
5819 $nextpage = 1;
5820 } else {
5821 $nextpage = 0;
5822 }
5823 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
5824
5825 print "\n";
5826 print "<!-- Begin title -->\n";
5827 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
5828
5829 // Left
5830
5831 if ($picto && $titre) {
5832 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
5833 }
5834
5835 print '<td class="nobordernopadding valignmiddle col-title">';
5836 print '<div class="titre inline-block">'.$titre;
5837 if (!empty($titre) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
5838 print '<span class="opacitymedium colorblack paddingleft">('.$totalnboflines.')</span>';
5839 }
5840 print '</div></td>';
5841
5842 // Center
5843 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
5844 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5845 }
5846
5847 // Right
5848 print '<td class="nobordernopadding valignmiddle right col-right">';
5849 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
5850 if ($sortfield) {
5851 $options .= "&sortfield=".urlencode($sortfield);
5852 }
5853 if ($sortorder) {
5854 $options .= "&sortorder=".urlencode($sortorder);
5855 }
5856 // Show navigation bar
5857 $pagelist = '';
5858 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
5859 if ($totalnboflines) { // If we know total nb of lines
5860 // Define nb of extra page links before and after selected page + ... + first or last
5861 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
5862
5863 if ($limit > 0) {
5864 $nbpages = ceil($totalnboflines / $limit);
5865 } else {
5866 $nbpages = 1;
5867 }
5868 $cpt = ($page - $maxnbofpage);
5869 if ($cpt < 0) {
5870 $cpt = 0;
5871 }
5872
5873 if ($cpt >= 1) {
5874 if (empty($pagenavastextinput)) {
5875 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=0'.$options.'">1</a></li>';
5876 if ($cpt > 2) {
5877 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5878 } elseif ($cpt == 2) {
5879 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=1'.$options.'">2</a></li>';
5880 }
5881 }
5882 }
5883
5884 do {
5885 if ($pagenavastextinput) {
5886 if ($cpt == $page) {
5887 $pagelist .= '<li class="pagination"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
5888 $pagelist .= '/';
5889 }
5890 } else {
5891 if ($cpt == $page) {
5892 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
5893 } else {
5894 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
5895 }
5896 }
5897 $cpt++;
5898 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
5899
5900 if (empty($pagenavastextinput)) {
5901 if ($cpt < $nbpages) {
5902 if ($cpt < $nbpages - 2) {
5903 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5904 } elseif ($cpt == $nbpages - 2) {
5905 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
5906 }
5907 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5908 }
5909 } else {
5910 //var_dump($page.' '.$cpt.' '.$nbpages);
5911 $pagelist .= '<li class="pagination paginationlastpage"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5912 }
5913 } else {
5914 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
5915 }
5916 }
5917
5918 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
5919 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
5920 }
5921
5922 // js to autoselect page field on focus
5923 if ($pagenavastextinput) {
5924 print ajax_autoselect('.pageplusone');
5925 }
5926
5927 print '</td>';
5928 print '</tr>';
5929
5930 print '</table>'."\n";
5931
5932 // Center
5933 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
5934 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
5935 }
5936
5937 print "<!-- End title -->\n\n";
5938}
5939
5956function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
5957{
5958 global $conf, $langs;
5959
5960 print '<div class="pagination"><ul>';
5961 if ($beforearrows) {
5962 print '<li class="paginationbeforearrows">';
5963 print $beforearrows;
5964 print '</li>';
5965 }
5966
5967 if (empty($hidenavigation)) {
5968 if ((int) $limit > 0 && empty($hideselectlimit)) {
5969 $pagesizechoices = '10:10,15:15,20:20,30:30,40:40,50:50,100:100,250:250,500:500,1000:1000';
5970 $pagesizechoices .= ',5000:5000,10000:10000,20000:20000';
5971 //$pagesizechoices.=',0:'.$langs->trans("All"); // Not yet supported
5972 //$pagesizechoices.=',2:2';
5973 if (getDolGlobalString('MAIN_PAGESIZE_CHOICES')) {
5974 $pagesizechoices = $conf->global->MAIN_PAGESIZE_CHOICES;
5975 }
5976
5977 print '<li class="pagination">';
5978 print '<select class="flat selectlimit" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
5979 $tmpchoice = explode(',', $pagesizechoices);
5980 $tmpkey = $limit.':'.$limit;
5981 if (!in_array($tmpkey, $tmpchoice)) {
5982 $tmpchoice[] = $tmpkey;
5983 }
5984 $tmpkey = $conf->liste_limit.':'.$conf->liste_limit;
5985 if (!in_array($tmpkey, $tmpchoice)) {
5986 $tmpchoice[] = $tmpkey;
5987 }
5988 asort($tmpchoice, SORT_NUMERIC);
5989 foreach ($tmpchoice as $val) {
5990 $selected = '';
5991 $tmp = explode(':', $val);
5992 $key = $tmp[0];
5993 $val = $tmp[1];
5994 if ($key != '' && $val != '') {
5995 if ((int) $key == (int) $limit) {
5996 $selected = ' selected="selected"';
5997 }
5998 print '<option name="'.$key.'"'.$selected.'>'.dol_escape_htmltag($val).'</option>'."\n";
5999 }
6000 }
6001 print '</select>';
6002 if ($conf->use_javascript_ajax) {
6003 print '<!-- JS CODE TO ENABLE select limit to launch submit of page -->
6004 <script>
6005 jQuery(document).ready(function () {
6006 jQuery(".selectlimit").change(function() {
6007 console.log("Change limit. Send submit");
6008 $(this).parents(\'form:first\').submit();
6009 });
6010 });
6011 </script>
6012 ';
6013 }
6014 print '</li>';
6015 }
6016 if ($page > 0) {
6017 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>';
6018 }
6019 if ($betweenarrows) {
6020 print '<!--<div class="betweenarrows nowraponall inline-block">-->';
6021 print $betweenarrows;
6022 print '<!--</div>-->';
6023 }
6024 if ($nextpage > 0) {
6025 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>';
6026 }
6027 if ($afterarrows) {
6028 print '<li class="paginationafterarrows">';
6029 print $afterarrows;
6030 print '</li>';
6031 }
6032 }
6033 print '</ul></div>'."\n";
6034}
6035
6036
6048function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, $html = 0)
6049{
6050 $morelabel = '';
6051
6052 if (preg_match('/%/', $rate)) {
6053 $rate = str_replace('%', '', $rate);
6054 $addpercent = true;
6055 }
6056 $reg = array();
6057 if (preg_match('/\‍((.*)\‍)/', $rate, $reg)) {
6058 $morelabel = ' ('.$reg[1].')';
6059 $rate = preg_replace('/\s*'.preg_quote($morelabel, '/').'/', '', $rate);
6060 $morelabel = ' '.($html ? '<span class="opacitymedium">' : '').'('.$reg[1].')'.($html ? '</span>' : '');
6061 }
6062 if (preg_match('/\*/', $rate)) {
6063 $rate = str_replace('*', '', $rate);
6064 $info_bits |= 1;
6065 }
6066
6067 // If rate is '9/9/9' we don't change it. If rate is '9.000' we apply price()
6068 if (!preg_match('/\//', $rate)) {
6069 $ret = price($rate, 0, '', 0, 0).($addpercent ? '%' : '');
6070 } else {
6071 // TODO Split on / and output with a price2num to have clean numbers without ton of 000.
6072 $ret = $rate.($addpercent ? '%' : '');
6073 }
6074 if (($info_bits & 1) && $usestarfornpr >= 0) {
6075 $ret .= ' *';
6076 }
6077 $ret .= $morelabel;
6078 return $ret;
6079}
6080
6081
6097function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1, $currency_code = '')
6098{
6099 global $langs, $conf;
6100
6101 // Clean parameters
6102 if (empty($amount)) {
6103 $amount = 0; // To have a numeric value if amount not defined or = ''
6104 }
6105 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number)
6106 if ($rounding == -1) {
6107 $rounding = min(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), getDolGlobalString('MAIN_MAX_DECIMALS_TOT'));
6108 }
6109 $nbdecimal = $rounding;
6110
6111 if ($outlangs === 'none') {
6112 // Use international separators
6113 $dec = '.';
6114 $thousand = '';
6115 } else {
6116 // Output separators by default (french)
6117 $dec = ',';
6118 $thousand = ' ';
6119
6120 // If $outlangs not forced, we use use language
6121 if (!is_object($outlangs)) {
6122 $outlangs = $langs;
6123 }
6124
6125 if ($outlangs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6126 $dec = $outlangs->transnoentitiesnoconv("SeparatorDecimal");
6127 }
6128 if ($outlangs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6129 $thousand = $outlangs->transnoentitiesnoconv("SeparatorThousand");
6130 }
6131 if ($thousand == 'None') {
6132 $thousand = '';
6133 } elseif ($thousand == 'Space') {
6134 $thousand = ' ';
6135 }
6136 }
6137 //print "outlangs=".$outlangs->defaultlang." amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6138
6139 //print "amount=".$amount."-";
6140 $amount = str_replace(',', '.', $amount); // should be useless
6141 //print $amount."-";
6142 $datas = explode('.', $amount);
6143 $decpart = isset($datas[1]) ? $datas[1] : '';
6144 $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
6145 //print "decpart=".$decpart."<br>";
6146 $end = '';
6147
6148 // We increase nbdecimal if there is more decimal than asked (to not loose information)
6149 if (dol_strlen($decpart) > $nbdecimal) {
6150 $nbdecimal = dol_strlen($decpart);
6151 }
6152
6153 // If nbdecimal is higher than max to show
6154 $nbdecimalmaxshown = (int) str_replace('...', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'));
6155 if ($trunc && $nbdecimal > $nbdecimalmaxshown) {
6156 $nbdecimal = $nbdecimalmaxshown;
6157 if (preg_match('/\.\.\./i', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'))) {
6158 // If output is truncated, we show ...
6159 $end = '...';
6160 }
6161 }
6162
6163 // If force rounding
6164 if ((string) $forcerounding != '-1') {
6165 if ($forcerounding === 'MU') {
6166 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_UNIT');
6167 } elseif ($forcerounding === 'MT') {
6168 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_TOT');
6169 } elseif ($forcerounding >= 0) {
6170 $nbdecimal = $forcerounding;
6171 }
6172 }
6173
6174 // Format number
6175 $output = number_format($amount, $nbdecimal, $dec, $thousand);
6176 if ($form) {
6177 $output = preg_replace('/\s/', '&nbsp;', $output);
6178 $output = preg_replace('/\'/', '&#039;', $output);
6179 }
6180 // Add symbol of currency if requested
6181 $cursymbolbefore = $cursymbolafter = '';
6182 if ($currency_code && is_object($outlangs)) {
6183 if ($currency_code == 'auto') {
6184 $currency_code = $conf->currency;
6185 }
6186
6187 $listofcurrenciesbefore = array('AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD', 'CRC', 'ZAR');
6188 $listoflanguagesbefore = array('nl_NL');
6189 if (in_array($currency_code, $listofcurrenciesbefore) || in_array($outlangs->defaultlang, $listoflanguagesbefore)) {
6190 $cursymbolbefore .= $outlangs->getCurrencySymbol($currency_code);
6191 } else {
6192 $tmpcur = $outlangs->getCurrencySymbol($currency_code);
6193 $cursymbolafter .= ($tmpcur == $currency_code ? ' '.$tmpcur : $tmpcur);
6194 }
6195 }
6196 $output = $cursymbolbefore.$output.$end.($cursymbolafter ? ' ' : '').$cursymbolafter;
6197
6198 return $output;
6199}
6200
6225function price2num($amount, $rounding = '', $option = 0)
6226{
6227 global $langs, $conf;
6228
6229 // Clean parameters
6230 if (is_null($amount)) {
6231 $amount = '';
6232 }
6233
6234 // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
6235 // Numbers must be '1234.56'
6236 // Decimal delimiter for PHP and database SQL requests must be '.'
6237 $dec = ',';
6238 $thousand = ' ';
6239 if (is_null($langs)) { // $langs is not defined, we use english values.
6240 $dec = '.';
6241 $thousand = ',';
6242 } else {
6243 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6244 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
6245 }
6246 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6247 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
6248 }
6249 }
6250 if ($thousand == 'None') {
6251 $thousand = '';
6252 } elseif ($thousand == 'Space') {
6253 $thousand = ' ';
6254 }
6255 //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6256
6257 // Convert value to universal number format (no thousand separator, '.' as decimal separator)
6258 if ($option != 1) { // If not a PHP number or unknown, we change or clean format
6259 //print "\n".'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'<br>';
6260 if (!is_numeric($amount)) {
6261 $amount = preg_replace('/[a-zA-Z\/\\\*\‍(\‍)<>\_]/', '', $amount);
6262 }
6263
6264 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
6265 $amount = str_replace($thousand, '', $amount);
6266 }
6267
6268 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6269 // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
6270 // So if number was already a good number, it is converted into local Dolibarr setup.
6271 if (is_numeric($amount)) {
6272 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6273 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6274 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6275 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6276 $amount = number_format($amount, $nbofdec, $dec, $thousand);
6277 }
6278 //print "QQ".$amount."<br>\n";
6279
6280 // Now make replace (the main goal of function)
6281 if ($thousand != ',' && $thousand != '.') {
6282 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6283 }
6284
6285 $amount = str_replace(' ', '', $amount); // To avoid spaces
6286 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6287 $amount = str_replace($dec, '.', $amount);
6288
6289 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6290 }
6291 //print ' XX'.$amount.' '.$rounding;
6292
6293 // Now, $amount is a real PHP float number. We make a rounding if required.
6294 if ($rounding) {
6295 $nbofdectoround = '';
6296 if ($rounding == 'MU') {
6297 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_UNIT;
6298 } elseif ($rounding == 'MT') {
6299 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_TOT;
6300 } elseif ($rounding == 'MS') {
6301 $nbofdectoround = isset($conf->global->MAIN_MAX_DECIMALS_STOCK) ? $conf->global->MAIN_MAX_DECIMALS_STOCK : 5;
6302 } elseif ($rounding == 'CU') {
6303 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), 8); // TODO Use param of currency
6304 } elseif ($rounding == 'CT') {
6305 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_TOT'), 8); // TODO Use param of currency
6306 } elseif (is_numeric($rounding)) {
6307 $nbofdectoround = (int) $rounding;
6308 }
6309
6310 //print " RR".$amount.' - '.$nbofdectoround.'<br>';
6311 if (dol_strlen($nbofdectoround)) {
6312 $amount = round(is_string($amount) ? (float) $amount : $amount, $nbofdectoround); // $nbofdectoround can be 0.
6313 } else {
6314 return 'ErrorBadParameterProvidedToFunction';
6315 }
6316 //print ' SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
6317
6318 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6319 // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
6320 if (is_numeric($amount)) {
6321 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6322 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6323 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6324 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6325 $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
6326 }
6327 //print "TT".$amount.'<br>';
6328
6329 // Always make replace because each math function (like round) replace
6330 // with local values and we want a number that has a SQL string format x.y
6331 if ($thousand != ',' && $thousand != '.') {
6332 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6333 }
6334
6335 $amount = str_replace(' ', '', $amount); // To avoid spaces
6336 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6337 $amount = str_replace($dec, '.', $amount);
6338
6339 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6340 }
6341
6342 return $amount;
6343}
6344
6357function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round = -1, $forceunitoutput = 'no', $use_short_label = 0)
6358{
6359 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
6360
6361 if (($forceunitoutput == 'no' && $dimension < 1 / 10000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -6)) {
6362 $dimension = $dimension * 1000000;
6363 $unit = $unit - 6;
6364 } elseif (($forceunitoutput == 'no' && $dimension < 1 / 10 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -3)) {
6365 $dimension = $dimension * 1000;
6366 $unit = $unit - 3;
6367 } elseif (($forceunitoutput == 'no' && $dimension > 100000000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 6)) {
6368 $dimension = $dimension / 1000000;
6369 $unit = $unit + 6;
6370 } elseif (($forceunitoutput == 'no' && $dimension > 100000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 3)) {
6371 $dimension = $dimension / 1000;
6372 $unit = $unit + 3;
6373 }
6374 // Special case when we want output unit into pound or ounce
6375 /* TODO
6376 if ($unit < 90 && $type == 'weight' && is_numeric($forceunitoutput) && (($forceunitoutput == 98) || ($forceunitoutput == 99))
6377 {
6378 $dimension = // convert dimension from standard unit into ounce or pound
6379 $unit = $forceunitoutput;
6380 }
6381 if ($unit > 90 && $type == 'weight' && is_numeric($forceunitoutput) && $forceunitoutput < 90)
6382 {
6383 $dimension = // convert dimension from standard unit into ounce or pound
6384 $unit = $forceunitoutput;
6385 }*/
6386
6387 $ret = price($dimension, 0, $outputlangs, 0, 0, $round);
6388 $ret .= ' '.measuringUnitString(0, $type, $unit, $use_short_label, $outputlangs);
6389
6390 return $ret;
6391}
6392
6393
6406function get_localtax($vatrate, $local, $thirdparty_buyer = "", $thirdparty_seller = "", $vatnpr = 0)
6407{
6408 global $db, $conf, $mysoc;
6409
6410 if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
6411 $thirdparty_seller = $mysoc;
6412 }
6413
6414 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);
6415
6416 $vatratecleaned = $vatrate;
6417 $reg = array();
6418 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6419 $vatratecleaned = trim($reg[1]);
6420 $vatratecode = $reg[2];
6421 }
6422
6423 /*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
6424 {
6425 return 0;
6426 }*/
6427
6428 // Some test to guess with no need to make database access
6429 if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
6430 if ($local == 1) {
6431 if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
6432 return 0;
6433 }
6434 if ($thirdparty_seller->id == $mysoc->id) {
6435 if (!$thirdparty_buyer->localtax1_assuj) {
6436 return 0;
6437 }
6438 } else {
6439 if (!$thirdparty_seller->localtax1_assuj) {
6440 return 0;
6441 }
6442 }
6443 }
6444
6445 if ($local == 2) {
6446 //if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
6447 if (!$mysoc->localtax2_assuj) {
6448 return 0; // If main vat is 0, IRPF may be different than 0.
6449 }
6450 if ($thirdparty_seller->id == $mysoc->id) {
6451 if (!$thirdparty_buyer->localtax2_assuj) {
6452 return 0;
6453 }
6454 } else {
6455 if (!$thirdparty_seller->localtax2_assuj) {
6456 return 0;
6457 }
6458 }
6459 }
6460 } else {
6461 if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
6462 return 0;
6463 }
6464 if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
6465 return 0;
6466 }
6467 }
6468
6469 // For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
6470 if (in_array($mysoc->country_code, array('ES'))) {
6471 $conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
6472 }
6473
6474 // Search local taxes
6475 if (getDolGlobalString('MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY')) {
6476 if ($local == 1) {
6477 if ($thirdparty_seller != $mysoc) {
6478 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6479 return $thirdparty_seller->localtax1_value;
6480 }
6481 } else { // i am the seller
6482 if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
6483 return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
6484 }
6485 }
6486 }
6487 if ($local == 2) {
6488 if ($thirdparty_seller != $mysoc) {
6489 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6490 // TODO We should also return value defined on thirdparty only if defined
6491 return $thirdparty_seller->localtax2_value;
6492 }
6493 } else { // i am the seller
6494 if (in_array($mysoc->country_code, array('ES'))) {
6495 return $thirdparty_buyer->localtax2_value;
6496 } else {
6497 return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
6498 }
6499 }
6500 }
6501 }
6502
6503 // By default, search value of local tax on line of common tax
6504 $sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
6505 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6506 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
6507 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6508 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6509 if (!empty($vatratecode)) {
6510 $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
6511 } else {
6512 $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
6513 }
6514
6515 $resql = $db->query($sql);
6516
6517 if ($resql) {
6518 $obj = $db->fetch_object($resql);
6519 if ($obj) {
6520 if ($local == 1) {
6521 return $obj->localtax1;
6522 } elseif ($local == 2) {
6523 return $obj->localtax2;
6524 }
6525 }
6526 }
6527
6528 return 0;
6529}
6530
6531
6540function isOnlyOneLocalTax($local)
6541{
6542 $tax = get_localtax_by_third($local);
6543
6544 $valors = explode(":", $tax);
6545
6546 if (count($valors) > 1) {
6547 return false;
6548 } else {
6549 return true;
6550 }
6551}
6552
6560{
6561 global $db, $mysoc;
6562
6563 $sql = " SELECT t.localtax".$local." as localtax";
6564 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_pays";
6565 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.active = 1 AND t.entity IN (".getEntity('c_tva').") AND t.taux = (";
6566 $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";
6567 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.entity IN (".getEntity('c_tva').") AND tt.active = 1)";
6568 $sql .= " AND t.localtax".$local."_type <> '0'";
6569 $sql .= " ORDER BY t.rowid DESC";
6570
6571 $resql = $db->query($sql);
6572 if ($resql) {
6573 $obj = $db->fetch_object($resql);
6574 if ($obj) {
6575 return $obj->localtax;
6576 } else {
6577 return '0';
6578 }
6579 }
6580
6581 return 'Error';
6582}
6583
6584
6596function getTaxesFromId($vatrate, $buyer = null, $seller = null, $firstparamisid = 1)
6597{
6598 global $db, $mysoc;
6599
6600 dol_syslog("getTaxesFromId vat id or rate = ".$vatrate);
6601
6602 // Search local taxes
6603 $sql = "SELECT t.rowid, t.code, t.taux as rate, t.recuperableonly as npr, t.accountancy_code_sell, t.accountancy_code_buy,";
6604 $sql .= " t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type";
6605 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6606 if ($firstparamisid) {
6607 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6608 } else {
6609 $vatratecleaned = $vatrate;
6610 $vatratecode = '';
6611 $reg = array();
6612 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6613 $vatratecleaned = $reg[1];
6614 $vatratecode = $reg[2];
6615 }
6616
6617 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6618 /*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 ??
6619 else $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";*/
6620 $sql .= " WHERE t.fk_pays = c.rowid";
6621 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) {
6622 $sql .= " AND c.code = '".$db->escape($buyer->country_code)."'";
6623 } else {
6624 $sql .= " AND c.code = '".$db->escape($seller->country_code)."'";
6625 }
6626 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6627 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6628 if ($vatratecode) {
6629 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6630 }
6631 }
6632
6633 $resql = $db->query($sql);
6634 if ($resql) {
6635 $obj = $db->fetch_object($resql);
6636 if ($obj) {
6637 return array(
6638 'rowid'=>$obj->rowid,
6639 'code'=>$obj->code,
6640 'rate'=>$obj->rate,
6641 'localtax1'=>$obj->localtax1,
6642 'localtax1_type'=>$obj->localtax1_type,
6643 'localtax2'=>$obj->localtax2,
6644 'localtax2_type'=>$obj->localtax2_type,
6645 'npr'=>$obj->npr,
6646 'accountancy_code_sell'=>$obj->accountancy_code_sell,
6647 'accountancy_code_buy'=>$obj->accountancy_code_buy
6648 );
6649 } else {
6650 return array();
6651 }
6652 } else {
6653 dol_print_error($db);
6654 }
6655
6656 return array();
6657}
6658
6675function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid = 0)
6676{
6677 global $db, $mysoc;
6678
6679 dol_syslog("getLocalTaxesFromRate vatrate=".$vatrate." local=".$local);
6680
6681 // Search local taxes
6682 $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";
6683 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6684 if ($firstparamisid) {
6685 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6686 } else {
6687 $vatratecleaned = $vatrate;
6688 $vatratecode = '';
6689 $reg = array();
6690 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "x.x (yy)"
6691 $vatratecleaned = $reg[1];
6692 $vatratecode = $reg[2];
6693 }
6694
6695 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6696 if (!empty($mysoc) && $mysoc->country_code == 'ES') {
6697 $countrycodetouse = ((empty($buyer) || empty($buyer->country_code)) ? $mysoc->country_code : $buyer->country_code);
6698 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'"; // local tax in spain use the buyer country ??
6699 } else {
6700 $countrycodetouse = ((empty($seller) || empty($seller->country_code)) ? $mysoc->country_code : $seller->country_code);
6701 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'";
6702 }
6703 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6704 if ($vatratecode) {
6705 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6706 }
6707 }
6708
6709 $resql = $db->query($sql);
6710 if ($resql) {
6711 $obj = $db->fetch_object($resql);
6712
6713 if ($obj) {
6714 $vateratestring = $obj->rate.($obj->code ? ' ('.$obj->code.')' : '');
6715
6716 if ($local == 1) {
6717 return array($obj->localtax1_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6718 } elseif ($local == 2) {
6719 return array($obj->localtax2_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6720 } else {
6721 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);
6722 }
6723 }
6724 }
6725
6726 return array();
6727}
6728
6739function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice = 0)
6740{
6741 global $db, $conf, $mysoc;
6742
6743 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6744
6745 $ret = 0;
6746 $found = 0;
6747
6748 if ($idprod > 0) {
6749 // Load product
6750 $product = new Product($db);
6751 $product->fetch($idprod);
6752
6753 if ($mysoc->country_code == $thirdpartytouse->country_code) {
6754 // If country to consider is ours
6755 if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object
6756 $result = $product->get_buyprice($idprodfournprice, 0, 0, 0);
6757 if ($result > 0) {
6758 $ret = $product->vatrate_supplier;
6759 if ($product->default_vat_code_supplier) {
6760 $ret .= ' ('.$product->default_vat_code_supplier.')';
6761 }
6762 $found = 1;
6763 }
6764 }
6765 if (!$found) {
6766 $ret = $product->tva_tx; // Default sales vat of product
6767 if ($product->default_vat_code) {
6768 $ret .= ' ('.$product->default_vat_code.')';
6769 }
6770 $found = 1;
6771 }
6772 } else {
6773 // TODO Read default product vat according to product and an other countrycode.
6774 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6775 }
6776 }
6777
6778 if (!$found) {
6779 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
6780 // 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).
6781 $sql = "SELECT t.taux as vat_rate, t.code as default_vat_code";
6782 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6783 $sql .= " WHERE t.active = 1 AND t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdpartytouse->country_code)."'";
6784 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6785 $sql .= " ORDER BY t.use_default DESC, t.taux DESC, t.code ASC, t.recuperableonly ASC";
6786 $sql .= $db->plimit(1);
6787
6788 $resql = $db->query($sql);
6789 if ($resql) {
6790 $obj = $db->fetch_object($resql);
6791 if ($obj) {
6792 $ret = $obj->vat_rate;
6793 if ($obj->default_vat_code) {
6794 $ret .= ' ('.$obj->default_vat_code.')';
6795 }
6796 }
6797 $db->free($resql);
6798 } else {
6799 dol_print_error($db);
6800 }
6801 } else {
6802 // Forced value if autodetect fails. MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS can be
6803 // '1.23'
6804 // or '1.23 (CODE)'
6805 $defaulttx = '';
6806 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
6807 $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6808 }
6809 /*if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6810 $defaultcode = $reg[1];
6811 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6812 }*/
6813
6814 $ret = $defaulttx;
6815 }
6816 }
6817
6818 dol_syslog("get_product_vat_for_country: ret=".$ret);
6819 return $ret;
6820}
6821
6831function get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
6832{
6833 global $db, $mysoc;
6834
6835 if (!class_exists('Product')) {
6836 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6837 }
6838
6839 $ret = 0;
6840 $found = 0;
6841
6842 if ($idprod > 0) {
6843 // Load product
6844 $product = new Product($db);
6845 $result = $product->fetch($idprod);
6846
6847 if ($mysoc->country_code == $thirdpartytouse->country_code) { // If selling country is ours
6848 /* Not defined yet, so we don't use this
6849 if ($local==1) $ret=$product->localtax1_tx;
6850 elseif ($local==2) $ret=$product->localtax2_tx;
6851 $found=1;
6852 */
6853 } else {
6854 // TODO Read default product vat according to product and another countrycode.
6855 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6856 }
6857 }
6858
6859 if (!$found) {
6860 // If vat of product for the country not found or not defined, we return higher vat of country.
6861 $sql = "SELECT taux as vat_rate, localtax1, localtax2";
6862 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6863 $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code='".$db->escape($thirdpartytouse->country_code)."'";
6864 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6865 $sql .= " ORDER BY t.taux DESC, t.recuperableonly ASC";
6866 $sql .= $db->plimit(1);
6867
6868 $resql = $db->query($sql);
6869 if ($resql) {
6870 $obj = $db->fetch_object($resql);
6871 if ($obj) {
6872 if ($local == 1) {
6873 $ret = $obj->localtax1;
6874 } elseif ($local == 2) {
6875 $ret = $obj->localtax2;
6876 }
6877 }
6878 } else {
6879 dol_print_error($db);
6880 }
6881 }
6882
6883 dol_syslog("get_product_localtax_for_country: ret=".$ret);
6884 return $ret;
6885}
6886
6903function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6904{
6905 global $conf;
6906
6907 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6908
6909 // Note: possible values for tva_assuj are 0/1 or franchise/reel
6910 $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;
6911
6912 $seller_country_code = $thirdparty_seller->country_code;
6913 $seller_in_cee = isInEEC($thirdparty_seller);
6914
6915 $buyer_country_code = $thirdparty_buyer->country_code;
6916 $buyer_in_cee = isInEEC($thirdparty_buyer);
6917
6918 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 : ''));
6919
6920 // 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)
6921 // we use the buyer VAT.
6922 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) {
6923 if ($seller_in_cee && $buyer_in_cee) {
6924 $isacompany = $thirdparty_buyer->isACompany();
6925 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6926 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6927 if (!isValidVATID($thirdparty_buyer)) {
6928 $isacompany = 0;
6929 }
6930 }
6931
6932 if (!$isacompany) {
6933 //print 'VATRULE 0';
6934 return get_product_vat_for_country($idprod, $thirdparty_buyer, $idprodfournprice);
6935 }
6936 }
6937 }
6938
6939 // If seller does not use VAT, default VAT is 0. End of rule.
6940 if (!$seller_use_vat) {
6941 //print 'VATRULE 1';
6942 return 0;
6943 }
6944
6945 // If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule.
6946 if (($seller_country_code == $buyer_country_code)
6947 || (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC')))) { // Warning ->country_code not always defined
6948 //print 'VATRULE 2';
6949 $tmpvat = get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6950
6951 if ($seller_country_code == 'IN' && getDolGlobalString('MAIN_SALETAX_AUTOSWITCH_I_CS_FOR_INDIA')) {
6952 // Special case for india.
6953 //print 'VATRULE 2b';
6954 $reg = array();
6955 if (preg_match('/C+S-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id != $thirdparty_buyer->state_id) {
6956 // we must revert the C+S into I
6957 $tmpvat = str_replace("C+S", "I", $tmpvat);
6958 } elseif (preg_match('/I-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id == $thirdparty_buyer->state_id) {
6959 // we must revert the I into C+S
6960 $tmpvat = str_replace("I", "C+S", $tmpvat);
6961 }
6962 }
6963
6964 return $tmpvat;
6965 }
6966
6967 // 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.
6968 // 'VATRULE 3' - Not supported
6969
6970 // If (seller and buyer in the European Community) and (buyer = individual) then VAT by default = VAT of the product sold. End of rule
6971 // If (seller and buyer in European Community) and (buyer = company) then VAT by default=0. End of rule
6972 if (($seller_in_cee && $buyer_in_cee)) {
6973 $isacompany = $thirdparty_buyer->isACompany();
6974 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6975 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6976 if (!isValidVATID($thirdparty_buyer)) {
6977 $isacompany = 0;
6978 }
6979 }
6980
6981 if (!$isacompany) {
6982 //print 'VATRULE 4';
6983 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6984 } else {
6985 //print 'VATRULE 5';
6986 return 0;
6987 }
6988 }
6989
6990 // 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
6991 // I don't see any use case that need this rule.
6992 if (getDolGlobalString('MAIN_USE_VAT_OF_PRODUCT_FOR_INDIVIDUAL_CUSTOMER_OUT_OF_EEC') && empty($buyer_in_cee)) {
6993 $isacompany = $thirdparty_buyer->isACompany();
6994 if (!$isacompany) {
6995 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6996 //print 'VATRULE extra';
6997 }
6998 }
6999
7000 // Otherwise the VAT proposed by default=0. End of rule.
7001 // Rem: This means that at least one of the 2 is outside the European Community and the country differs
7002 //print 'VATRULE 6';
7003 return 0;
7004}
7005
7006
7017function get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
7018{
7019 global $db;
7020
7021 if ($idprodfournprice > 0) {
7022 if (!class_exists('ProductFournisseur')) {
7023 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
7024 }
7025 $prodprice = new ProductFournisseur($db);
7026 $prodprice->fetch_product_fournisseur_price($idprodfournprice);
7027 return $prodprice->fourn_tva_npr;
7028 } elseif ($idprod > 0) {
7029 if (!class_exists('Product')) {
7030 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
7031 }
7032 $prod = new Product($db);
7033 $prod->fetch($idprod);
7034 return $prod->tva_npr;
7035 }
7036
7037 return 0;
7038}
7039
7053function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod = 0)
7054{
7055 global $mysoc;
7056
7057 if (!is_object($thirdparty_seller)) {
7058 return -1;
7059 }
7060 if (!is_object($thirdparty_buyer)) {
7061 return -1;
7062 }
7063
7064 if ($local == 1) { // Localtax 1
7065 if ($mysoc->country_code == 'ES') {
7066 if (is_numeric($thirdparty_buyer->localtax1_assuj) && !$thirdparty_buyer->localtax1_assuj) {
7067 return 0;
7068 }
7069 } else {
7070 // Si vendeur non assujeti a Localtax1, localtax1 par default=0
7071 if (is_numeric($thirdparty_seller->localtax1_assuj) && !$thirdparty_seller->localtax1_assuj) {
7072 return 0;
7073 }
7074 if (!is_numeric($thirdparty_seller->localtax1_assuj) && $thirdparty_seller->localtax1_assuj == 'localtax1off') {
7075 return 0;
7076 }
7077 }
7078 } elseif ($local == 2) { //I Localtax 2
7079 // Si vendeur non assujeti a Localtax2, localtax2 par default=0
7080 if (is_numeric($thirdparty_seller->localtax2_assuj) && !$thirdparty_seller->localtax2_assuj) {
7081 return 0;
7082 }
7083 if (!is_numeric($thirdparty_seller->localtax2_assuj) && $thirdparty_seller->localtax2_assuj == 'localtax2off') {
7084 return 0;
7085 }
7086 }
7087
7088 if ($thirdparty_seller->country_code == $thirdparty_buyer->country_code) {
7089 return get_product_localtax_for_country($idprod, $local, $thirdparty_seller);
7090 }
7091
7092 return 0;
7093}
7094
7103function yn($yesno, $case = 1, $color = 0)
7104{
7105 global $langs;
7106
7107 $result = 'unknown';
7108 $classname = '';
7109 if ($yesno == 1 || (isset($yesno) && (strtolower($yesno) == 'yes' || strtolower($yesno) == 'true'))) { // A mettre avant test sur no a cause du == 0
7110 $result = $langs->trans('yes');
7111 if ($case == 1 || $case == 3) {
7112 $result = $langs->trans("Yes");
7113 }
7114 if ($case == 2) {
7115 $result = '<input type="checkbox" value="1" checked disabled>';
7116 }
7117 if ($case == 3) {
7118 $result = '<input type="checkbox" value="1" checked disabled> '.$result;
7119 }
7120
7121 $classname = 'ok';
7122 } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') {
7123 $result = $langs->trans("no");
7124 if ($case == 1 || $case == 3) {
7125 $result = $langs->trans("No");
7126 }
7127 if ($case == 2) {
7128 $result = '<input type="checkbox" value="0" disabled>';
7129 }
7130 if ($case == 3) {
7131 $result = '<input type="checkbox" value="0" disabled> '.$result;
7132 }
7133
7134 if ($color == 2) {
7135 $classname = 'ok';
7136 } else {
7137 $classname = 'error';
7138 }
7139 }
7140 if ($color) {
7141 return '<span class="'.$classname.'">'.$result.'</span>';
7142 }
7143 return $result;
7144}
7145
7161function get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart = '')
7162{
7163 global $conf;
7164
7165 if (empty($modulepart) && !empty($object->module)) {
7166 $modulepart = $object->module;
7167 }
7168
7169 $path = '';
7170
7171 $arrayforoldpath = array('cheque', 'category', 'holiday', 'supplier_invoice', 'invoice_supplier', 'mailing', 'supplier_payment');
7172 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
7173 $arrayforoldpath[] = 'product';
7174 }
7175 if (!empty($level) && in_array($modulepart, $arrayforoldpath)) {
7176 // This part should be removed once all code is using "get_exdir" to forge path, with parameter $object and $modulepart provided.
7177 if (empty($alpha)) {
7178 $num = preg_replace('/([^0-9])/i', '', $num);
7179 } else {
7180 $num = preg_replace('/^.*\-/i', '', $num);
7181 }
7182 $num = substr("000".$num, -$level);
7183 if ($level == 1) {
7184 $path = substr($num, 0, 1);
7185 }
7186 if ($level == 2) {
7187 $path = substr($num, 1, 1).'/'.substr($num, 0, 1);
7188 }
7189 if ($level == 3) {
7190 $path = substr($num, 2, 1).'/'.substr($num, 1, 1).'/'.substr($num, 0, 1);
7191 }
7192 } else {
7193 // We will enhance here a common way of forging path for document storage.
7194 // In a future, we may distribute directories on several levels depending on setup and object.
7195 // Here, $object->id, $object->ref and $modulepart are required.
7196 //var_dump($modulepart);
7197 $path = dol_sanitizeFileName(empty($object->ref) ? (string) $object->id : $object->ref);
7198 }
7199
7200 if (empty($withoutslash) && !empty($path)) {
7201 $path .= '/';
7202 }
7203
7204 return $path;
7205}
7206
7215function dol_mkdir($dir, $dataroot = '', $newmask = '')
7216{
7217 global $conf;
7218
7219 dol_syslog("functions.lib::dol_mkdir: dir=".$dir, LOG_INFO);
7220
7221 $dir_osencoded = dol_osencode($dir);
7222 if (@is_dir($dir_osencoded)) {
7223 return 0;
7224 }
7225
7226 $nberr = 0;
7227 $nbcreated = 0;
7228
7229 $ccdir = '';
7230 if (!empty($dataroot)) {
7231 // Remove data root from loop
7232 $dir = str_replace($dataroot.'/', '', $dir);
7233 $ccdir = $dataroot.'/';
7234 }
7235
7236 $cdir = explode("/", $dir);
7237 $num = count($cdir);
7238 for ($i = 0; $i < $num; $i++) {
7239 if ($i > 0) {
7240 $ccdir .= '/'.$cdir[$i];
7241 } else {
7242 $ccdir .= $cdir[$i];
7243 }
7244 $regs = array();
7245 if (preg_match("/^.:$/", $ccdir, $regs)) {
7246 continue; // Si chemin Windows incomplet, on poursuit par rep suivant
7247 }
7248
7249 // Attention, le is_dir() peut echouer bien que le rep existe.
7250 // (ex selon config de open_basedir)
7251 if ($ccdir) {
7252 $ccdir_osencoded = dol_osencode($ccdir);
7253 if (!@is_dir($ccdir_osencoded)) {
7254 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.", LOG_DEBUG);
7255
7256 umask(0);
7257 $dirmaskdec = octdec((string) $newmask);
7258 if (empty($newmask)) {
7259 $dirmaskdec = !getDolGlobalString('MAIN_UMASK') ? octdec('0755') : octdec($conf->global->MAIN_UMASK);
7260 }
7261 $dirmaskdec |= octdec('0111'); // Set x bit required for directories
7262 if (!@mkdir($ccdir_osencoded, $dirmaskdec)) {
7263 // Si le is_dir a renvoye une fausse info, alors on passe ici.
7264 dol_syslog("functions.lib::dol_mkdir: Fails to create directory '".$ccdir."' or directory already exists.", LOG_WARNING);
7265 $nberr++;
7266 } else {
7267 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' created", LOG_DEBUG);
7268 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignore
7269 $nbcreated++;
7270 }
7271 } else {
7272 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignores
7273 }
7274 }
7275 }
7276 return ($nberr ? -$nberr : $nbcreated);
7277}
7278
7279
7287function dolChmod($filepath, $newmask = '')
7288{
7289 global $conf;
7290
7291 if (!empty($newmask)) {
7292 @chmod($filepath, octdec($newmask));
7293 } elseif (getDolGlobalString('MAIN_UMASK')) {
7294 @chmod($filepath, octdec($conf->global->MAIN_UMASK));
7295 }
7296}
7297
7298
7305{
7306 return '<span class="fieldrequired">*</span>';
7307}
7308
7309
7326function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = 'UTF-8', $strip_tags = 0, $removedoublespaces = 1)
7327{
7328 if (is_null($stringtoclean)) {
7329 return '';
7330 }
7331
7332 if ($removelinefeed == 2) {
7333 $stringtoclean = preg_replace('/<br[^>]*>(\n|\r)+/ims', '<br>', $stringtoclean);
7334 }
7335 $temp = preg_replace('/<br[^>]*>/i', "\n", $stringtoclean);
7336
7337 // 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)
7338 $temp = dol_html_entity_decode($temp, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7339
7340 $temp = str_replace('< ', '__ltspace__', $temp);
7341
7342 if ($strip_tags) {
7343 $temp = strip_tags($temp);
7344 } else {
7345 // 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).
7346 $pattern = "/<[^<>]+>/";
7347 // Example of $temp: <a href="/myurl" title="<u>A title</u>">0000-021</a>
7348 // pass 1 - $temp after pass 1: <a href="/myurl" title="A title">0000-021
7349 // pass 2 - $temp after pass 2: 0000-021
7350 $tempbis = $temp;
7351 do {
7352 $temp = $tempbis;
7353 $tempbis = str_replace('<>', '', $temp); // No reason to have this into a text, except if value is to try bypass the next html cleaning
7354 $tempbis = preg_replace($pattern, '', $tempbis);
7355 //$idowhile++; print $temp.'-'.$tempbis."\n"; if ($idowhile > 100) break;
7356 } while ($tempbis != $temp);
7357
7358 $temp = $tempbis;
7359
7360 // 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).
7361 $temp = preg_replace('/<+([a-z]+)/i', '\1', $temp);
7362 }
7363
7364 $temp = dol_html_entity_decode($temp, ENT_COMPAT, $pagecodeto);
7365
7366 // Remove also carriage returns
7367 if ($removelinefeed == 1) {
7368 $temp = str_replace(array("\r\n", "\r", "\n"), " ", $temp);
7369 }
7370
7371 // And double quotes
7372 if ($removedoublespaces) {
7373 while (strpos($temp, " ")) {
7374 $temp = str_replace(" ", " ", $temp);
7375 }
7376 }
7377
7378 $temp = str_replace('__ltspace__', '< ', $temp);
7379
7380 return trim($temp);
7381}
7382
7398function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1, $cleanalsojavascript = 0, $allowiframe = 0, $allowed_tags = array(), $allowlink = 0)
7399{
7400 if (empty($allowed_tags)) {
7401 $allowed_tags = array(
7402 "html", "head", "meta", "body", "article", "a", "abbr", "b", "blockquote", "br", "cite", "div", "dl", "dd", "dt", "em", "font", "img", "ins", "hr", "i", "li",
7403 "ol", "p", "q", "s", "span", "strike", "strong", "title", "table", "tr", "th", "td", "u", "ul", "sup", "sub", "blockquote", "pre", "h1", "h2", "h3", "h4", "h5", "h6",
7404 "header", "footer", "nav", "section", "menu", "menuitem" // html5 tags
7405 );
7406 }
7407 $allowed_tags[] = "comment"; // this tags is added to manage comment <!--...--> that are replaced into <comment>...</comment>
7408 if ($allowiframe) {
7409 if (!in_array('iframe', $allowed_tags)) {
7410 $allowed_tags[] = "iframe";
7411 }
7412 }
7413 if ($allowlink) {
7414 if (!in_array('link', $allowed_tags)) {
7415 $allowed_tags[] = "link";
7416 }
7417 }
7418
7419 $allowed_tags_string = join("><", $allowed_tags);
7420 $allowed_tags_string = '<'.$allowed_tags_string.'>';
7421
7422 $stringtoclean = str_replace('<!DOCTYPE html>', '__!DOCTYPE_HTML__', $stringtoclean); // Replace DOCTYPE to avoid to have it removed by the strip_tags
7423
7424 $stringtoclean = dol_string_nounprintableascii($stringtoclean, 0);
7425
7426 //$stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
7427 $stringtoclean = preg_replace('/<!--([^>]*)-->/', '<comment>\1</comment>', $stringtoclean);
7428
7429 $stringtoclean = preg_replace('/&colon;/i', ':', $stringtoclean);
7430 $stringtoclean = preg_replace('/&#58;|&#0+58|&#x3A/i', '', $stringtoclean); // refused string ':' encoded (no reason to have a : encoded like this) to disable 'javascript:...'
7431
7432 $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
7433
7434 if ($cleanalsosomestyles) { // Clean for remaining html tags
7435 $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
7436 }
7437 if ($removeclassattribute) { // Clean for remaining html tags
7438 $temp = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $temp);
7439 }
7440
7441 // Remove 'javascript:' that we should not find into a text with
7442 // 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)).
7443 if ($cleanalsojavascript) {
7444 $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);
7445 }
7446
7447 $temp = str_replace('__!DOCTYPE_HTML__', '<!DOCTYPE html>', $temp); // Restore the DOCTYPE
7448
7449 $temp = preg_replace('/<comment>([^>]*)<\/comment>/', '<!--\1-->', $temp); // Restore html comments
7450
7451
7452 return $temp;
7453}
7454
7455
7467function dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes = null)
7468{
7469 if (is_null($allowed_attributes)) {
7470 $allowed_attributes = array(
7471 "allow", "allowfullscreen", "alt", "async", "class", "contenteditable", "crossorigin", "data-html", "frameborder", "height", "href", "id", "name", "property", "rel", "src", "style", "target", "title", "type", "width",
7472 // HTML5
7473 "header", "footer", "nav", "section", "menu", "menuitem"
7474 );
7475 }
7476 // Always add content and http-equiv for meta tags, required to force encoding and keep html content in utf8 by load/saveHTML functions.
7477 if (!in_array("content", $allowed_attributes)) {
7478 $allowed_attributes[] = "content";
7479 }
7480 if (!in_array("http-equiv", $allowed_attributes)) {
7481 $allowed_attributes[] = "http-equiv";
7482 }
7483
7484 if (class_exists('DOMDocument') && !empty($stringtoclean)) {
7485 $stringtoclean = '<?xml encoding="UTF-8"><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>'.$stringtoclean.'</body></html>';
7486
7487 // Warning: loadHTML does not support HTML5 on old libxml versions.
7488 $dom = new DOMDocument(null, 'UTF-8');
7489 $dom->loadHTML($stringtoclean, LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7490
7491 if (is_object($dom)) {
7492 for ($els = $dom->getElementsByTagname('*'), $i = $els->length - 1; $i >= 0; $i--) {
7493 for ($attrs = $els->item($i)->attributes, $ii = $attrs->length - 1; $ii >= 0; $ii--) {
7494 //var_dump($attrs->item($ii));
7495 if (!empty($attrs->item($ii)->name)) {
7496 if (! in_array($attrs->item($ii)->name, $allowed_attributes)) {
7497 // Delete attribute if not into allowed_attributes
7498 $els->item($i)->removeAttribute($attrs->item($ii)->name);
7499 } elseif (in_array($attrs->item($ii)->name, array('style'))) {
7500 // If attribute is 'style'
7501 $valuetoclean = $attrs->item($ii)->value;
7502
7503 if (isset($valuetoclean)) {
7504 do {
7505 $oldvaluetoclean = $valuetoclean;
7506 $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments
7507 $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean);
7508 if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags.
7509 $valuetoclean = preg_replace('/display\s*:/mi', '', $valuetoclean);
7510 $valuetoclean = preg_replace('/z-index\s*:/mi', '', $valuetoclean);
7511 $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*:/mi', '', $valuetoclean);
7512 }
7513
7514 // We do not allow logout|passwordforgotten.php and action= into the content of a "style" tag
7515 $valuetoclean = preg_replace('/(logout|passwordforgotten)\.php/mi', '', $valuetoclean);
7516 $valuetoclean = preg_replace('/action=/mi', '', $valuetoclean);
7517 } while ($oldvaluetoclean != $valuetoclean);
7518 }
7519
7520 $attrs->item($ii)->value = $valuetoclean;
7521 }
7522 }
7523 }
7524 }
7525 }
7526
7527 $dom->encoding = 'UTF-8';
7528
7529 $return = $dom->saveHTML(); // This may add a LF at end of lines, so we will trim later
7530 //$return = '<html><body>aaaa</p>bb<p>ssdd</p>'."\n<p>aaa</p>aa<p>bb</p>";
7531
7532 $return = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $return);
7533 $return = preg_replace('/^'.preg_quote('<html><head><', '/').'[^<>]*'.preg_quote('></head><body>', '/').'/', '', $return);
7534 $return = preg_replace('/'.preg_quote('</body></html>', '/').'$/', '', trim($return));
7535
7536 return trim($return);
7537 } else {
7538 return $stringtoclean;
7539 }
7540}
7541
7553function dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags = array('textarea'), $cleanalsosomestyles = 0)
7554{
7555 $temp = $stringtoclean;
7556 foreach ($disallowed_tags as $tagtoremove) {
7557 $temp = preg_replace('/<\/?'.$tagtoremove.'>/', '', $temp);
7558 $temp = preg_replace('/<\/?'.$tagtoremove.'\s+[^>]*>/', '', $temp);
7559 }
7560
7561 if ($cleanalsosomestyles) {
7562 $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
7563 }
7564
7565 return $temp;
7566}
7567
7568
7578function dolGetFirstLineOfText($text, $nboflines = 1, $charset = 'UTF-8')
7579{
7580 if ($nboflines == 1) {
7581 if (dol_textishtml($text)) {
7582 $firstline = preg_replace('/<br[^>]*>.*$/s', '', $text); // The s pattern modifier means the . can match newline characters
7583 $firstline = preg_replace('/<div[^>]*>.*$/s', '', $firstline); // The s pattern modifier means the . can match newline characters
7584 } else {
7585 if (isset($text)) {
7586 $firstline = preg_replace('/[\n\r].*/', '', $text);
7587 } else {
7588 $firstline = '';
7589 }
7590 }
7591 return $firstline.(isset($firstline) && isset($text) && (strlen($firstline) != strlen($text)) ? '...' : '');
7592 } else {
7593 $ishtml = 0;
7594 if (dol_textishtml($text)) {
7595 $text = preg_replace('/\n/', '', $text);
7596 $ishtml = 1;
7597 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7598 } else {
7599 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7600 }
7601
7602 $text = strtr($text, $repTable);
7603 if ($charset == 'UTF-8') {
7604 $pattern = '/(<br[^>]*>)/Uu';
7605 } else {
7606 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7607 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7608 }
7609 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7610
7611 $firstline = '';
7612 $i = 0;
7613 $countline = 0;
7614 $lastaddediscontent = 1;
7615 while ($countline < $nboflines && isset($a[$i])) {
7616 if (preg_match('/<br[^>]*>/', $a[$i])) {
7617 if (array_key_exists($i+1, $a) && !empty($a[$i+1])) {
7618 $firstline .= ($ishtml ? "<br>\n" : "\n");
7619 // Is it a br for a new line of after a printed line ?
7620 if (!$lastaddediscontent) {
7621 $countline++;
7622 }
7623 $lastaddediscontent = 0;
7624 }
7625 } else {
7626 $firstline .= $a[$i];
7627 $lastaddediscontent = 1;
7628 $countline++;
7629 }
7630 $i++;
7631 }
7632
7633 $adddots = (isset($a[$i]) && (!preg_match('/<br[^>]*>/', $a[$i]) || (array_key_exists($i+1, $a) && !empty($a[$i+1]))));
7634 //unset($a);
7635 $ret = $firstline.($adddots ? '...' : '');
7636 //exit;
7637 return $ret;
7638 }
7639}
7640
7641
7653function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false)
7654{
7655 if (is_null($stringtoencode)) {
7656 return '';
7657 }
7658
7659 if (!$nl2brmode) {
7660 return nl2br($stringtoencode, $forxml);
7661 } else {
7662 $ret = preg_replace('/(\r\n|\r|\n)/i', ($forxml ? '<br />' : '<br>'), $stringtoencode);
7663 return $ret;
7664 }
7665}
7666
7676function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = 'restricthtml')
7677{
7678 if (empty($nouseofiframesandbox) && getDolGlobalString('MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS')) {
7679 // TODO using sandbox on inline html content is not possible yet with current browsers
7680 //$s = '<iframe class="iframewithsandbox" sandbox><html><body>';
7681 //$s .= $stringtoencode;
7682 //$s .= '</body></html></iframe>';
7683 return $stringtoencode;
7684 } else {
7685 $out = $stringtoencode;
7686
7687 do {
7688 $oldstringtoclean = $out;
7689
7690 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML') && $check != 'restricthtmlallowunvalid') {
7691 try {
7692 libxml_use_internal_errors(false); // Avoid to fill memory with xml errors
7693 if (LIBXML_VERSION < 20900) {
7694 // Avoid load of external entities (security problem).
7695 // Required only if LIBXML_VERSION < 20900
7696 libxml_disable_entity_loader(true);
7697 }
7698
7699 $dom = new DOMDocument();
7700 // Add a trick to solve pb with text without parent tag
7701 // like '<h1>Foo</h1><p>bar</p>' that wrongly ends up, without the trick, with '<h1>Foo<p>bar</p></h1>'
7702 // like 'abc' that wrongly ends up, without the trick, with '<p>abc</p>'
7703
7704 if (dol_textishtml($out)) {
7705 $out = '<?xml encoding="UTF-8"><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body><div class="tricktoremove">'.$out.'</div></body></html>';
7706 } else {
7707 $out = '<?xml encoding="UTF-8"><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body><div class="tricktoremove">'.dol_nl2br($out).'</div></body></html>';
7708 }
7709
7710 $dom->loadHTML($out, LIBXML_HTML_NODEFDTD | LIBXML_ERR_NONE | LIBXML_HTML_NOIMPLIED | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_NOERROR | LIBXML_NOXMLDECL);
7711
7712 $dom->encoding = 'UTF-8';
7713
7714 $out = trim($dom->saveHTML());
7715
7716 // Remove the trick added to solve pb with text in utf8 and text without parent tag
7717 $out = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $out);
7718 $out = preg_replace('/^'.preg_quote('<html><head><', '/').'[^<>]+'.preg_quote('></head><body><div class="tricktoremove">', '/').'/', '', $out);
7719 $out = preg_replace('/'.preg_quote('</div></body></html>', '/').'$/', '', trim($out));
7720 // $out = preg_replace('/^<\?xml encoding="UTF-8"><div class="tricktoremove">/', '', $out);
7721 // $out = preg_replace('/<\/div>$/', '', $out);
7722 // var_dump('rrrrrrrrrrrrrrrrrrrrrrrrrrrrr'.$out);
7723 } catch (Exception $e) {
7724 // If error, invalid HTML string with no way to clean it
7725 //print $e->getMessage();
7726 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
7727 }
7728 }
7729
7730 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY') && $check != 'restricthtmlallowunvalid') {
7731 try {
7732 // Try cleaning using tidy
7733 if (extension_loaded('tidy') && class_exists("tidy")) {
7734 //print "aaa".$out."\n";
7735
7736 // See options at https://tidy.sourceforge.net/docs/quickref.html
7737 $config = array(
7738 'clean' => false,
7739 'quote-marks' => false, // do not replace " that are used for real text content (not a string symbol for html attribute) into &quot;
7740 'doctype' => 'strict',
7741 'show-body-only' => true,
7742 "indent-attributes" => false,
7743 "vertical-space" => false,
7744 'ident' => false,
7745 "wrap" => 0
7746 // HTML5 tags
7747 //'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',
7748 //'new-blocklevel-tags' => 'footer header section menu menuitem'
7749 //'new-empty-tags' => 'command embed keygen source track wbr',
7750 //'new-inline-tags' => 'audio command datalist embed keygen mark menuitem meter output progress source time video wbr',
7751 );
7752
7753 // Tidy
7754 $tidy = new tidy();
7755 $out = $tidy->repairString($out, $config, 'utf8');
7756
7757 //print "xxx".$out;exit;
7758 }
7759 } catch (Exception $e) {
7760 // If error, invalid HTML string with no way to clean it
7761 //print $e->getMessage();
7762 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
7763 }
7764 }
7765
7766 //Clear ZERO WIDTH NO-BREAK SPACE, ZERO WIDTH SPACE, ZERO WIDTH JOINER
7767 $out = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $out);
7768
7769 // Clean some html entities that are useless so text is cleaner
7770 $out = preg_replace('/&(tab|newline);/i', ' ', $out);
7771
7772 // Ckeditor use the numeric entitic for apostrophe so we force it to text entity (all other special chars are
7773 // encoded using text entities) so we can then exclude all numeric entities.
7774 $out = preg_replace('/&#39;/i', '&apos;', $out);
7775
7776 // 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).
7777 // 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
7778 // using a non coventionnel way to be encoded, to not have them sanitized just after)
7779 $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) {
7780 return realCharForNumericEntities($m);
7781 }, $out);
7782
7783
7784 // Now we remove all remaining HTML entities starting with a number. We don't want such entities.
7785 $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'.
7786
7787 // Keep only some html tags and remove also some 'javascript:' strings
7788 $out = dol_string_onlythesehtmltags($out, 0, ($check == 'restricthtmlallowclass' ? 0 : 1), 1);
7789
7790 // Keep only some html attributes and exclude non expected HTML attributes and clean content of some attributes (keep only alt=, title=...).
7791 if (getDolGlobalString('MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES')) {
7793 }
7794
7795 // Restore entity &apos; into &#39; (restricthtml is for html content so we can use html entity)
7796 $out = preg_replace('/&apos;/i', "&#39;", $out);
7797 } while ($oldstringtoclean != $out);
7798
7799 // Check the limit of external links that are automatically executed in a Rich text content. We count:
7800 // '<img' to avoid <img src="http...">, we can only accept "<img src="data:..."
7801 // 'url(' to avoid inline style like background: url(http...
7802 // '<link' to avoid <link href="http...">
7803 $reg = array();
7804 $tmpout = preg_replace('/<img src="data:/mi', '<__IMG_SRC_DATA__ src="data:', $out);
7805 preg_match_all('/(<img|url\‍(|<link)/i', $tmpout, $reg);
7806 $nblinks = count($reg[0]);
7807 if ($nblinks > getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) {
7808 $out = 'ErrorTooManyLinksIntoHTMLString';
7809 }
7810
7811 if (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 2 || $check == 'restricthtmlnolink') {
7812 if ($nblinks > 0) {
7813 $out = 'ErrorHTMLLinksNotAllowed';
7814 }
7815 } elseif (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 1) {
7816 $nblinks = 0;
7817 // Loop on each url in src= and url(
7818 $pattern = '/src=["\']?(http[^"\']+)|url\‍(["\']?(http[^\‍)]+)/';
7819
7820 $matches = array();
7821 if (preg_match_all($pattern, $out, $matches)) {
7822 // URLs are into $matches[1]
7823 $urls = $matches[1];
7824
7825 // Affiche les URLs
7826 foreach ($urls as $url) {
7827 $nblinks++;
7828 echo "Found url = ".$url . "\n";
7829 }
7830 if ($nblinks > 0) {
7831 $out = 'ErrorHTMLExternalLinksNotAllowed';
7832 }
7833 }
7834 }
7835
7836 return $out;
7837 }
7838}
7839
7861function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UTF-8', $removelasteolbr = 1)
7862{
7863 if (is_null($stringtoencode)) {
7864 return '';
7865 }
7866
7867 $newstring = $stringtoencode;
7868 if (dol_textishtml($stringtoencode)) { // Check if text is already HTML or not
7869 $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.
7870 if ($removelasteolbr) {
7871 $newstring = preg_replace('/<br>$/i', '', $newstring); // Remove last <br> (remove only last one)
7872 }
7873 $newstring = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $newstring);
7874 $newstring = strtr($newstring, array('&'=>'__and__', '<'=>'__lt__', '>'=>'__gt__', '"'=>'__dquot__'));
7875 $newstring = dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom); // Make entity encoding
7876 $newstring = strtr($newstring, array('__and__'=>'&', '__lt__'=>'<', '__gt__'=>'>', '__dquot__'=>'"'));
7877 } else {
7878 if ($removelasteolbr) {
7879 $newstring = preg_replace('/(\r\n|\r|\n)$/i', '', $newstring); // Remove last \n (may remove several)
7880 }
7881 $newstring = dol_nl2br(dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom), $nl2brmode);
7882 }
7883 // Other substitutions that htmlentities does not do
7884 //$newstring=str_replace(chr(128),'&euro;',$newstring); // 128 = 0x80. Not in html entity table. // Seems useles with TCPDF. Make bug with UTF8 languages
7885 return $newstring;
7886}
7887
7895function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8')
7896{
7897 $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7898 $ret = preg_replace('/'."\r\n".'<br(\s[\sa-zA-Z_="]*)?\/?>/i', "<br>", $ret);
7899 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\r\n".'/i', "\r\n", $ret);
7900 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\n".'/i', "\n", $ret);
7901 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', "\n", $ret);
7902 return $ret;
7903}
7904
7911function dol_htmlcleanlastbr($stringtodecode)
7912{
7913 $ret = preg_replace('/&nbsp;$/i', "", $stringtodecode); // Because wysiwyg editor may add a &nbsp; at end of last line
7914 $ret = preg_replace('/(<br>|<br(\s[\sa-zA-Z_="]*)?\/?>|'."\n".'|'."\r".')+$/i', "", $ret);
7915 return $ret;
7916}
7917
7927function dol_html_entity_decode($a, $b, $c = 'UTF-8', $keepsomeentities = 0)
7928{
7929 $newstring = $a;
7930 if ($keepsomeentities) {
7931 $newstring = strtr($newstring, array('&amp;'=>'__andamp__', '&lt;'=>'__andlt__', '&gt;'=>'__andgt__', '"'=>'__dquot__'));
7932 }
7933 $newstring = html_entity_decode((string) $newstring, (int) $b, (string) $c);
7934 if ($keepsomeentities) {
7935 $newstring = strtr($newstring, array('__andamp__'=>'&amp;', '__andlt__'=>'&lt;', '__andgt__'=>'&gt;', '__dquot__'=>'"'));
7936 }
7937 return $newstring;
7938}
7939
7951function dol_htmlentities($string, $flags = ENT_QUOTES|ENT_SUBSTITUTE, $encoding = 'UTF-8', $double_encode = false)
7952{
7953 return htmlentities($string, $flags, $encoding, $double_encode);
7954}
7955
7967function dol_string_is_good_iso($s, $clean = 0)
7968{
7969 $len = dol_strlen($s);
7970 $out = '';
7971 $ok = 1;
7972 for ($scursor = 0; $scursor < $len; $scursor++) {
7973 $ordchar = ord($s[$scursor]);
7974 //print $scursor.'-'.$ordchar.'<br>';
7975 if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) {
7976 $ok = 0;
7977 break;
7978 } elseif ($ordchar > 126 && $ordchar < 160) {
7979 $ok = 0;
7980 break;
7981 } elseif ($clean) {
7982 $out .= $s[$scursor];
7983 }
7984 }
7985 if ($clean) {
7986 return $out;
7987 }
7988 return $ok;
7989}
7990
7999function dol_nboflines($s, $maxchar = 0)
8000{
8001 if ($s == '') {
8002 return 0;
8003 }
8004 $arraystring = explode("\n", $s);
8005 $nb = count($arraystring);
8006
8007 return $nb;
8008}
8009
8010
8020function dol_nboflines_bis($text, $maxlinesize = 0, $charset = 'UTF-8')
8021{
8022 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
8023 if (dol_textishtml($text)) {
8024 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
8025 }
8026
8027 $text = strtr($text, $repTable);
8028 if ($charset == 'UTF-8') {
8029 $pattern = '/(<br[^>]*>)/Uu';
8030 } else {
8031 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
8032 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
8033 }
8034 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
8035
8036 $nblines = (int) floor((count($a) + 1) / 2);
8037 // count possible auto line breaks
8038 if ($maxlinesize) {
8039 foreach ($a as $line) {
8040 if (dol_strlen($line) > $maxlinesize) {
8041 //$line_dec = html_entity_decode(strip_tags($line));
8042 $line_dec = html_entity_decode($line);
8043 if (dol_strlen($line_dec) > $maxlinesize) {
8044 $line_dec = wordwrap($line_dec, $maxlinesize, '\n', true);
8045 $nblines += substr_count($line_dec, '\n');
8046 }
8047 }
8048 }
8049 }
8050
8051 unset($a);
8052 return $nblines;
8053}
8054
8063function dol_textishtml($msg, $option = 0)
8064{
8065 if (is_null($msg)) {
8066 return false;
8067 }
8068
8069 if ($option == 1) {
8070 if (preg_match('/<html/i', $msg)) {
8071 return true;
8072 } elseif (preg_match('/<body/i', $msg)) {
8073 return true;
8074 } elseif (preg_match('/<\/textarea/i', $msg)) {
8075 return true;
8076 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8077 return true;
8078 } elseif (preg_match('/<br/i', $msg)) {
8079 return true;
8080 }
8081 return false;
8082 } else {
8083 // Remove all urls because 'http://aa?param1=abc&amp;param2=def' must not be used inside detection
8084 $msg = preg_replace('/https?:\/\/[^"\'\s]+/i', '', $msg);
8085 if (preg_match('/<html/i', $msg)) {
8086 return true;
8087 } elseif (preg_match('/<body/i', $msg)) {
8088 return true;
8089 } elseif (preg_match('/<\/textarea/i', $msg)) {
8090 return true;
8091 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8092 return true;
8093 } elseif (preg_match('/<(br|hr)\/>/i', $msg)) {
8094 return true;
8095 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)>/i', $msg)) {
8096 return true;
8097 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)\s+[^<>\/]*\/?>/i', $msg)) {
8098 return true;
8099 } elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i', $msg)) {
8100 return true; // must accept <img src="http://example.com/aaa.png" />
8101 } elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i', $msg)) {
8102 return true; // must accept <a href="http://example.com/aaa.png" />
8103 } elseif (preg_match('/<h[0-9]>/i', $msg)) {
8104 return true;
8105 } elseif (preg_match('/&[A-Z0-9]{1,6};/i', $msg)) {
8106 // TODO If content is 'A link https://aaa?param=abc&amp;param2=def', it return true but must be false
8107 return true; // Html entities names (http://www.w3schools.com/tags/ref_entities.asp)
8108 } elseif (preg_match('/&#[0-9]{2,3};/i', $msg)) {
8109 return true; // Html entities numbers (http://www.w3schools.com/tags/ref_entities.asp)
8110 }
8111
8112 return false;
8113 }
8114}
8115
8130function dol_concatdesc($text1, $text2, $forxml = false, $invert = false)
8131{
8132 if (!empty($invert)) {
8133 $tmp = $text1;
8134 $text1 = $text2;
8135 $text2 = $tmp;
8136 }
8137
8138 $ret = '';
8139 $ret .= (!dol_textishtml($text1) && dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text1, 0, 1, '', 1), 0, $forxml) : $text1;
8140 $ret .= (!empty($text1) && !empty($text2)) ? ((dol_textishtml($text1) || dol_textishtml($text2)) ? ($forxml ? "<br >\n" : "<br>\n") : "\n") : "";
8141 $ret .= (dol_textishtml($text1) && !dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text2, 0, 1, '', 1), 0, $forxml) : $text2;
8142 return $ret;
8143}
8144
8145
8146
8158function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null)
8159{
8160 global $db, $conf, $mysoc, $user, $extrafields;
8161
8162 $substitutionarray = array();
8163
8164 if ((empty($exclude) || !in_array('user', $exclude)) && (empty($include) || in_array('user', $include))) {
8165 // Add SIGNATURE into substitutionarray first, so, when we will make the substitution,
8166 // this will include signature content first and then replace var found into content of signature
8167 //var_dump($onlykey);
8168 $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()
8169 $usersignature = $user->signature;
8170 $substitutionarray = array_merge($substitutionarray, array(
8171 '__SENDEREMAIL_SIGNATURE__' => (string) ((!getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc('SignatureFromTheSelectedSenderProfile', 30) : $emailsendersignature) : ''),
8172 '__USER_SIGNATURE__' => (string) (($usersignature && !getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc(dol_string_nohtmltag($usersignature), 30) : $usersignature) : '')
8173 ));
8174
8175 if (is_object($user)) {
8176 $substitutionarray = array_merge($substitutionarray, array(
8177 '__USER_ID__' => (string) $user->id,
8178 '__USER_LOGIN__' => (string) $user->login,
8179 '__USER_EMAIL__' => (string) $user->email,
8180 '__USER_PHONE__' => (string) dol_print_phone($user->office_phone, '', 0, 0, '', " ", '', '', -1),
8181 '__USER_PHONEPRO__' => (string) dol_print_phone($user->user_mobile, '', 0, 0, '', " ", '', '', -1),
8182 '__USER_PHONEMOBILE__' => (string) dol_print_phone($user->personal_mobile, '', 0, 0, '', " ", '', '', -1),
8183 '__USER_FAX__' => (string) $user->office_fax,
8184 '__USER_LASTNAME__' => (string) $user->lastname,
8185 '__USER_FIRSTNAME__' => (string) $user->firstname,
8186 '__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
8187 '__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
8188 '__USER_JOB__' => (string) $user->job,
8189 '__USER_REMOTE_IP__' => (string) getUserRemoteIP(),
8190 '__USER_VCARD_URL__' => (string) $user->getOnlineVirtualCardUrl('', 'external')
8191 ));
8192 }
8193 }
8194 if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc) && (empty($include) || in_array('mycompany', $include))) {
8195 $substitutionarray = array_merge($substitutionarray, array(
8196 '__MYCOMPANY_NAME__' => $mysoc->name,
8197 '__MYCOMPANY_EMAIL__' => $mysoc->email,
8198 '__MYCOMPANY_PHONE__' => dol_print_phone($mysoc->phone, '', 0, 0, '', " ", '', '', -1),
8199 '__MYCOMPANY_FAX__' => dol_print_phone($mysoc->fax, '', 0, 0, '', " ", '', '', -1),
8200 '__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
8201 '__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
8202 '__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
8203 '__MYCOMPANY_PROFID4__' => $mysoc->idprof4,
8204 '__MYCOMPANY_PROFID5__' => $mysoc->idprof5,
8205 '__MYCOMPANY_PROFID6__' => $mysoc->idprof6,
8206 '__MYCOMPANY_CAPITAL__' => $mysoc->capital,
8207 '__MYCOMPANY_FULLADDRESS__' => (method_exists($mysoc, 'getFullAddress') ? $mysoc->getFullAddress(1, ', ') : ''), // $mysoc may be stdClass
8208 '__MYCOMPANY_ADDRESS__' => $mysoc->address,
8209 '__MYCOMPANY_ZIP__' => $mysoc->zip,
8210 '__MYCOMPANY_TOWN__' => $mysoc->town,
8211 '__MYCOMPANY_COUNTRY__' => $mysoc->country,
8212 '__MYCOMPANY_COUNTRY_ID__' => $mysoc->country_id,
8213 '__MYCOMPANY_COUNTRY_CODE__' => $mysoc->country_code,
8214 '__MYCOMPANY_CURRENCY_CODE__' => $conf->currency
8215 ));
8216 }
8217
8218 if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude)) && (empty($include) || in_array('object', $include))) {
8219 if ($onlykey) {
8220 $substitutionarray['__ID__'] = '__ID__';
8221 $substitutionarray['__REF__'] = '__REF__';
8222 $substitutionarray['__NEWREF__'] = '__NEWREF__';
8223 $substitutionarray['__LABEL__'] = '__LABEL__';
8224 $substitutionarray['__REF_CLIENT__'] = '__REF_CLIENT__';
8225 $substitutionarray['__REF_SUPPLIER__'] = '__REF_SUPPLIER__';
8226 $substitutionarray['__NOTE_PUBLIC__'] = '__NOTE_PUBLIC__';
8227 $substitutionarray['__NOTE_PRIVATE__'] = '__NOTE_PRIVATE__';
8228 $substitutionarray['__EXTRAFIELD_XXX__'] = '__EXTRAFIELD_XXX__';
8229
8230 if (isModEnabled("societe")) { // Most objects are concerned
8231 $substitutionarray['__THIRDPARTY_ID__'] = '__THIRDPARTY_ID__';
8232 $substitutionarray['__THIRDPARTY_NAME__'] = '__THIRDPARTY_NAME__';
8233 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = '__THIRDPARTY_NAME_ALIAS__';
8234 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = '__THIRDPARTY_CODE_CLIENT__';
8235 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = '__THIRDPARTY_CODE_FOURNISSEUR__';
8236 $substitutionarray['__THIRDPARTY_EMAIL__'] = '__THIRDPARTY_EMAIL__';
8237 $substitutionarray['__THIRDPARTY_PHONE__'] = '__THIRDPARTY_PHONE__';
8238 $substitutionarray['__THIRDPARTY_FAX__'] = '__THIRDPARTY_FAX__';
8239 $substitutionarray['__THIRDPARTY_ADDRESS__'] = '__THIRDPARTY_ADDRESS__';
8240 $substitutionarray['__THIRDPARTY_ZIP__'] = '__THIRDPARTY_ZIP__';
8241 $substitutionarray['__THIRDPARTY_TOWN__'] = '__THIRDPARTY_TOWN__';
8242 $substitutionarray['__THIRDPARTY_IDPROF1__'] = '__THIRDPARTY_IDPROF1__';
8243 $substitutionarray['__THIRDPARTY_IDPROF2__'] = '__THIRDPARTY_IDPROF2__';
8244 $substitutionarray['__THIRDPARTY_IDPROF3__'] = '__THIRDPARTY_IDPROF3__';
8245 $substitutionarray['__THIRDPARTY_IDPROF4__'] = '__THIRDPARTY_IDPROF4__';
8246 $substitutionarray['__THIRDPARTY_IDPROF5__'] = '__THIRDPARTY_IDPROF5__';
8247 $substitutionarray['__THIRDPARTY_IDPROF6__'] = '__THIRDPARTY_IDPROF6__';
8248 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = '__THIRDPARTY_TVAINTRA__';
8249 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = '__THIRDPARTY_NOTE_PUBLIC__';
8250 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = '__THIRDPARTY_NOTE_PRIVATE__';
8251 }
8252 if (isModEnabled('adherent') && (!is_object($object) || $object->element == 'adherent') && (empty($exclude) || !in_array('member', $exclude)) && (empty($include) || in_array('member', $include))) {
8253 $substitutionarray['__MEMBER_ID__'] = '__MEMBER_ID__';
8254 $substitutionarray['__MEMBER_CIVILITY__'] = '__MEMBER_CIVILITY__';
8255 $substitutionarray['__MEMBER_FIRSTNAME__'] = '__MEMBER_FIRSTNAME__';
8256 $substitutionarray['__MEMBER_LASTNAME__'] = '__MEMBER_LASTNAME__';
8257 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = 'Login and pass of the external user account';
8258 /*$substitutionarray['__MEMBER_NOTE_PUBLIC__'] = '__MEMBER_NOTE_PUBLIC__';
8259 $substitutionarray['__MEMBER_NOTE_PRIVATE__'] = '__MEMBER_NOTE_PRIVATE__';*/
8260 }
8261 // add variables subtitutions ticket
8262 if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket') && (empty($exclude) || !in_array('ticket', $exclude)) && (empty($include) || in_array('ticket', $include))) {
8263 $substitutionarray['__TICKET_TRACKID__'] = '__TICKET_TRACKID__';
8264 $substitutionarray['__TICKET_SUBJECT__'] = '__TICKET_SUBJECT__';
8265 $substitutionarray['__TICKET_TYPE__'] = '__TICKET_TYPE__';
8266 $substitutionarray['__TICKET_SEVERITY__'] = '__TICKET_SEVERITY__';
8267 $substitutionarray['__TICKET_CATEGORY__'] = '__TICKET_CATEGORY__';
8268 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = '__TICKET_ANALYTIC_CODE__';
8269 $substitutionarray['__TICKET_MESSAGE__'] = '__TICKET_MESSAGE__';
8270 $substitutionarray['__TICKET_PROGRESSION__'] = '__TICKET_PROGRESSION__';
8271 $substitutionarray['__TICKET_USER_ASSIGN__'] = '__TICKET_USER_ASSIGN__';
8272 }
8273
8274 if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature') && (empty($exclude) || !in_array('recruitment', $exclude)) && (empty($include) || in_array('recruitment', $include))) {
8275 $substitutionarray['__CANDIDATE_FULLNAME__'] = '__CANDIDATE_FULLNAME__';
8276 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = '__CANDIDATE_FIRSTNAME__';
8277 $substitutionarray['__CANDIDATE_LASTNAME__'] = '__CANDIDATE_LASTNAME__';
8278 }
8279 if (isModEnabled('project') && (empty($exclude) || !in_array('project', $exclude)) && (empty($include) || in_array('project', $include))) { // Most objects
8280 $substitutionarray['__PROJECT_ID__'] = '__PROJECT_ID__';
8281 $substitutionarray['__PROJECT_REF__'] = '__PROJECT_REF__';
8282 $substitutionarray['__PROJECT_NAME__'] = '__PROJECT_NAME__';
8283 /*$substitutionarray['__PROJECT_NOTE_PUBLIC__'] = '__PROJECT_NOTE_PUBLIC__';
8284 $substitutionarray['__PROJECT_NOTE_PRIVATE__'] = '__PROJECT_NOTE_PRIVATE__';*/
8285 }
8286 if (isModEnabled('contrat') && (!is_object($object) || $object->element == 'contract') && (empty($exclude) || !in_array('contract', $exclude)) && (empty($include) || in_array('contract', $include))) {
8287 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = 'Highest date planned for a service start';
8288 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = 'Highest date and hour planned for service start';
8289 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = 'Lowest data for planned expiration of service';
8290 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = 'Lowest date and hour for planned expiration of service';
8291 }
8292 if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal') && (empty($exclude) || !in_array('propal', $exclude)) && (empty($include) || in_array('propal', $include))) {
8293 $substitutionarray['__ONLINE_SIGN_URL__'] = 'ToOfferALinkForOnlineSignature';
8294 }
8295 if (isModEnabled("ficheinter") && (!is_object($object) || $object->element == 'fichinter') && (empty($exclude) || !in_array('intervention', $exclude)) && (empty($include) || in_array('intervention', $include))) {
8296 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = 'ToOfferALinkForOnlineSignature';
8297 }
8298 $substitutionarray['__ONLINE_PAYMENT_URL__'] = 'UrlToPayOnlineIfApplicable';
8299 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = 'TextAndUrlToPayOnlineIfApplicable';
8300 $substitutionarray['__SECUREKEYPAYMENT__'] = 'Security key (if key is not unique per record)';
8301 $substitutionarray['__SECUREKEYPAYMENT_MEMBER__'] = 'Security key for payment on a member subscription (one key per member)';
8302 $substitutionarray['__SECUREKEYPAYMENT_ORDER__'] = 'Security key for payment on an order';
8303 $substitutionarray['__SECUREKEYPAYMENT_INVOICE__'] = 'Security key for payment on an invoice';
8304 $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'Security key for payment on a service of a contract';
8305
8306 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = 'Direct download url of a proposal';
8307 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = 'Direct download url of an order';
8308 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = 'Direct download url of an invoice';
8309 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = 'Direct download url of a contract';
8310 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = 'Direct download url of a supplier proposal';
8311
8312 if (isModEnabled("expedition") && (!is_object($object) || $object->element == 'shipping')) {
8313 $substitutionarray['__SHIPPINGTRACKNUM__'] = 'Shipping tracking number';
8314 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = 'Shipping tracking url';
8315 $substitutionarray['__SHIPPINGMETHOD__'] = 'Shipping method';
8316 }
8317 if (isModEnabled("reception") && (!is_object($object) || $object->element == 'reception')) {
8318 $substitutionarray['__RECEPTIONTRACKNUM__'] = 'Shippin tracking number of shipment';
8319 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = 'Shipping tracking url';
8320 }
8321 } else {
8322 $substitutionarray['__ID__'] = $object->id;
8323 $substitutionarray['__REF__'] = $object->ref;
8324 $substitutionarray['__NEWREF__'] = $object->newref;
8325 $substitutionarray['__LABEL__'] = (isset($object->label) ? $object->label : (isset($object->title) ? $object->title : null));
8326 $substitutionarray['__REF_CLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8327 $substitutionarray['__REF_SUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8328 $substitutionarray['__NOTE_PUBLIC__'] = (isset($object->note_public) ? $object->note_public : null);
8329 $substitutionarray['__NOTE_PRIVATE__'] = (isset($object->note_private) ? $object->note_private : null);
8330 // handle date_delivery: in customer order/supplier order, the property name is delivery_date, in shipment/reception it is date_delivery
8331 $date_delivery = null;
8332 if (property_exists($object, 'date_delivery')) {
8333 $date_delivery = $object->date_delivery;
8334 } elseif (property_exists($object, 'delivery_date')) {
8335 $date_delivery = $object->delivery_date;
8336 }
8337 $substitutionarray['__DATE_DELIVERY__'] = (isset($date_delivery) ? dol_print_date($date_delivery, 'day', 0, $outputlangs) : '');
8338 $substitutionarray['__DATE_DELIVERY_DAY__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%d") : '');
8339 $substitutionarray['__DATE_DELIVERY_DAY_TEXT__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%A") : '');
8340 $substitutionarray['__DATE_DELIVERY_MON__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%m") : '');
8341 $substitutionarray['__DATE_DELIVERY_MON_TEXT__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%b") : '');
8342 $substitutionarray['__DATE_DELIVERY_YEAR__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%Y") : '');
8343 $substitutionarray['__DATE_DELIVERY_HH__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%H") : '');
8344 $substitutionarray['__DATE_DELIVERY_MM__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%M") : '');
8345 $substitutionarray['__DATE_DELIVERY_SS__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%S") : '');
8346
8347 // For backward compatibility (deprecated)
8348 $substitutionarray['__REFCLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8349 $substitutionarray['__REFSUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8350 $substitutionarray['__SUPPLIER_ORDER_DATE_DELIVERY__'] = (isset($date_delivery) ? dol_print_date($date_delivery, 'day', 0, $outputlangs) : '');
8351 $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 : '')) : '');
8352 $substitutionarray['__EXPIRATION_DATE__'] = (isset($object->fin_validite) ? dol_print_date($object->fin_validite, 'daytext') : '');
8353
8354 if (is_object($object) && ($object->element == 'adherent' || $object->element == 'member') && $object->id > 0) {
8355 $birthday = (empty($object->birth) ? '' : dol_print_date($object->birth, 'day'));
8356
8357 $substitutionarray['__MEMBER_ID__'] = (isset($object->id) ? $object->id : '');
8358 if (method_exists($object, 'getCivilityLabel')) {
8359 $substitutionarray['__MEMBER_CIVILITY__'] = $object->getCivilityLabel();
8360 }
8361 $substitutionarray['__MEMBER_FIRSTNAME__'] = (isset($object->firstname) ? $object->firstname : '');
8362 $substitutionarray['__MEMBER_LASTNAME__'] = (isset($object->lastname) ? $object->lastname : '');
8363 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = '';
8364 if (method_exists($object, 'getFullName')) {
8365 $substitutionarray['__MEMBER_FULLNAME__'] = $object->getFullName($outputlangs);
8366 }
8367 $substitutionarray['__MEMBER_COMPANY__'] = (isset($object->societe) ? $object->societe : '');
8368 $substitutionarray['__MEMBER_ADDRESS__'] = (isset($object->address) ? $object->address : '');
8369 $substitutionarray['__MEMBER_ZIP__'] = (isset($object->zip) ? $object->zip : '');
8370 $substitutionarray['__MEMBER_TOWN__'] = (isset($object->town) ? $object->town : '');
8371 $substitutionarray['__MEMBER_COUNTRY__'] = (isset($object->country) ? $object->country : '');
8372 $substitutionarray['__MEMBER_EMAIL__'] = (isset($object->email) ? $object->email : '');
8373 $substitutionarray['__MEMBER_BIRTH__'] = (isset($birthday) ? $birthday : '');
8374 $substitutionarray['__MEMBER_PHOTO__'] = (isset($object->photo) ? $object->photo : '');
8375 $substitutionarray['__MEMBER_LOGIN__'] = (isset($object->login) ? $object->login : '');
8376 $substitutionarray['__MEMBER_PASSWORD__'] = (isset($object->pass) ? $object->pass : '');
8377 $substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? dol_print_phone($object->phone) : '');
8378 $substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? dol_print_phone($object->phone_perso) : '');
8379 $substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? dol_print_phone($object->phone_mobile) : '');
8380 $substitutionarray['__MEMBER_TYPE__'] = (isset($object->type) ? $object->type : '');
8381 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__'] = dol_print_date($object->first_subscription_date, 'day');
8382 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = (isset($object->first_subscription_date_start) ? dol_print_date($object->first_subscription_date_start, 'day') : '');
8383 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END__'] = (isset($object->first_subscription_date_end) ? dol_print_date($object->first_subscription_date_end, 'day') : '');
8384 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE__'] = dol_print_date($object->last_subscription_date, 'day');
8385 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->last_subscription_date_start, 'day');
8386 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END__'] = dol_print_date($object->last_subscription_date_end, 'day');
8387 }
8388
8389 if (is_object($object) && $object->element == 'societe') {
8390 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object) ? $object->id : '');
8391 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object) ? $object->name : '');
8392 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object) ? $object->name_alias : '');
8393 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object) ? $object->code_client : '');
8394 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object) ? $object->code_fournisseur : '');
8395 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object) ? $object->email : '');
8396 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? dol_print_phone($object->phone) : '');
8397 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? dol_print_phone($object->fax) : '');
8398 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object) ? $object->address : '');
8399 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object) ? $object->zip : '');
8400 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object) ? $object->town : '');
8401 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object) ? $object->country_id : '');
8402 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object) ? $object->country_code : '');
8403 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object) ? $object->idprof1 : '');
8404 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object) ? $object->idprof2 : '');
8405 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object) ? $object->idprof3 : '');
8406 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object) ? $object->idprof4 : '');
8407 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object) ? $object->idprof5 : '');
8408 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object) ? $object->idprof6 : '');
8409 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object) ? $object->tva_intra : '');
8410 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_public) : '');
8411 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_private) : '');
8412 } elseif (is_object($object->thirdparty)) {
8413 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->id : '');
8414 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object->thirdparty) ? $object->thirdparty->name : '');
8415 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object->thirdparty) ? $object->thirdparty->name_alias : '');
8416 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_client : '');
8417 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_fournisseur : '');
8418 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object->thirdparty) ? $object->thirdparty->email : '');
8419 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->phone) : '');
8420 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->fax) : '');
8421 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object->thirdparty) ? $object->thirdparty->address : '');
8422 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object->thirdparty) ? $object->thirdparty->zip : '');
8423 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object->thirdparty) ? $object->thirdparty->town : '');
8424 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_id : '');
8425 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_code : '');
8426 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof1 : '');
8427 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof2 : '');
8428 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof3 : '');
8429 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof4 : '');
8430 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof5 : '');
8431 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof6 : '');
8432 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object->thirdparty) ? $object->thirdparty->tva_intra : '');
8433 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_public) : '');
8434 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_private) : '');
8435 }
8436
8437 if (is_object($object) && $object->element == 'recruitmentcandidature') {
8438 $substitutionarray['__CANDIDATE_FULLNAME__'] = $object->getFullName($outputlangs);
8439 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8440 $substitutionarray['__CANDIDATE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8441 }
8442 if (is_object($object) && $object->element == 'conferenceorboothattendee') {
8443 $substitutionarray['__ATTENDEE_FULLNAME__'] = $object->getFullName($outputlangs);
8444 $substitutionarray['__ATTENDEE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8445 $substitutionarray['__ATTENDEE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8446 }
8447
8448 if (is_object($object) && $object->element == 'project') {
8449 $substitutionarray['__PROJECT_ID__'] = $object->id;
8450 $substitutionarray['__PROJECT_REF__'] = $object->ref;
8451 $substitutionarray['__PROJECT_NAME__'] = $object->title;
8452 } elseif (is_object($object)) {
8453 $project = null;
8454 if (!empty($object->project)) {
8455 $project = $object->project;
8456 } elseif (!empty($object->projet)) { // Deprecated, for backward compatibility
8457 $project = $object->projet;
8458 }
8459 if (!is_null($project) && is_object($project)) {
8460 $substitutionarray['__PROJECT_ID__'] = $project->id;
8461 $substitutionarray['__PROJECT_REF__'] = $project->ref;
8462 $substitutionarray['__PROJECT_NAME__'] = $project->title;
8463 } else {
8464 // can substitute variables for project : uses lazy load in "make_substitutions" method
8465 $project_id = 0;
8466 if (!empty($object->fk_project) && $object->fk_project > 0) {
8467 $project_id = $object->fk_project;
8468 } elseif (!empty($object->fk_projet) && $object->fk_projet > 0) {
8469 $project_id = $object->fk_project;
8470 }
8471 if ($project_id > 0) {
8472 // path:class:method:id
8473 $substitutionarray['__PROJECT_ID__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8474 $substitutionarray['__PROJECT_REF__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8475 $substitutionarray['__PROJECT_NAME__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8476 }
8477 }
8478 }
8479
8480 if (is_object($object) && $object->element == 'shipping') {
8481 $substitutionarray['__SHIPPINGTRACKNUM__'] = $object->tracking_number;
8482 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = $object->tracking_url;
8483 $substitutionarray['__SHIPPINGMETHOD__'] = $object->shipping_method;
8484 }
8485 if (is_object($object) && $object->element == 'reception') {
8486 $substitutionarray['__RECEPTIONTRACKNUM__'] = $object->tracking_number;
8487 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = $object->tracking_url;
8488 }
8489
8490 if (is_object($object) && $object->element == 'contrat' && $object->id > 0 && is_array($object->lines)) {
8491 $dateplannedstart = '';
8492 $datenextexpiration = '';
8493 foreach ($object->lines as $line) {
8494 if ($line->date_start > $dateplannedstart) {
8495 $dateplannedstart = $line->date_start;
8496 }
8497 if ($line->statut == 4 && $line->date_end && (!$datenextexpiration || $line->date_end < $datenextexpiration)) {
8498 $datenextexpiration = $line->date_end;
8499 }
8500 }
8501 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = dol_print_date($dateplannedstart, 'day');
8502 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = dol_print_date($dateplannedstart, 'standard');
8503 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = dol_print_date($datenextexpiration, 'day');
8504 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = dol_print_date($datenextexpiration, 'standard');
8505 }
8506 // add substition variable for ticket
8507 if (is_object($object) && $object->element == 'ticket') {
8508 $substitutionarray['__TICKET_TRACKID__'] = $object->track_id;
8509 $substitutionarray['__REF__'] = $object->ref;
8510 $substitutionarray['__TICKET_SUBJECT__'] = $object->subject;
8511 $substitutionarray['__TICKET_TYPE__'] = $object->type_code;
8512 $substitutionarray['__TICKET_SEVERITY__'] = $object->severity_code;
8513 $substitutionarray['__TICKET_CATEGORY__'] = $object->category_code; // For backward compatibility
8514 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = $object->category_code;
8515 $substitutionarray['__TICKET_MESSAGE__'] = $object->message;
8516 $substitutionarray['__TICKET_PROGRESSION__'] = $object->progress;
8517 $userstat = new User($db);
8518 if ($object->fk_user_assign > 0) {
8519 $userstat->fetch($object->fk_user_assign);
8520 $substitutionarray['__TICKET_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8521 }
8522
8523 if ($object->fk_user_create > 0) {
8524 $userstat->fetch($object->fk_user_create);
8525 $substitutionarray['__USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8526 }
8527 }
8528
8529 // Create dynamic tags for __EXTRAFIELD_FIELD__
8530 if ($object->table_element && $object->id > 0) {
8531 if (!is_object($extrafields)) {
8532 $extrafields = new ExtraFields($db);
8533 }
8534 $extrafields->fetch_name_optionals_label($object->table_element, true);
8535
8536 if ($object->fetch_optionals() > 0) {
8537 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) {
8538 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
8539 if ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
8540 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_date($object->array_options['options_'.$key], 'day');
8541 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = dol_print_date($object->array_options['options_'.$key], 'day', 'tzserver', $outputlangs);
8542 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = dol_print_date($object->array_options['options_'.$key], 'dayrfc');
8543 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'datetime') {
8544 $datetime = $object->array_options['options_'.$key];
8545 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour') : '');
8546 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : '');
8547 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_DAY_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'day', 'tzserver', $outputlangs) : '');
8548 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : '');
8549 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'phone') {
8550 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_phone($object->array_options['options_'.$key]);
8551 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
8552 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = $object->array_options['options_'.$key];
8553 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATED__'] = price($object->array_options['options_'.$key]);
8554 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] != 'separator') {
8555 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = !empty($object->array_options['options_'.$key]) ? $object->array_options['options_'.$key] : '';
8556 }
8557 }
8558 }
8559 }
8560 }
8561
8562 // Complete substitution array with the url to make online payment
8563 $paymenturl = '';
8564 if (empty($substitutionarray['__REF__'])) {
8565 $paymenturl = '';
8566 } else {
8567 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
8568 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
8569 $outputlangs->loadLangs(array('paypal', 'other'));
8570
8571 $amounttouse = 0;
8572 $typeforonlinepayment = 'free';
8573 if (is_object($object) && $object->element == 'commande') {
8574 $typeforonlinepayment = 'order';
8575 }
8576 if (is_object($object) && $object->element == 'facture') {
8577 $typeforonlinepayment = 'invoice';
8578 }
8579 if (is_object($object) && $object->element == 'member') {
8580 $typeforonlinepayment = 'member';
8581 if (!empty($object->last_subscription_amount)) {
8582 $amounttouse = $object->last_subscription_amount;
8583 }
8584 }
8585 if (is_object($object) && $object->element == 'contrat') {
8586 $typeforonlinepayment = 'contract';
8587 }
8588 if (is_object($object) && $object->element == 'fichinter') {
8589 $typeforonlinepayment = 'ficheinter';
8590 }
8591
8592 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__'], $amounttouse);
8593 $paymenturl = $url;
8594 }
8595
8596 if ($object->id > 0) {
8597 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ? str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : '');
8598 $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl;
8599
8600 if (getDolGlobalString('PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'propal') {
8601 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8602 } else {
8603 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = '';
8604 }
8605 if (getDolGlobalString('ORDER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'commande') {
8606 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = $object->getLastMainDocLink($object->element);
8607 } else {
8608 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = '';
8609 }
8610 if (getDolGlobalString('INVOICE_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'facture') {
8611 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = $object->getLastMainDocLink($object->element);
8612 } else {
8613 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = '';
8614 }
8615 if (getDolGlobalString('CONTRACT_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'contrat') {
8616 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = $object->getLastMainDocLink($object->element);
8617 } else {
8618 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = '';
8619 }
8620 if (getDolGlobalString('FICHINTER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'fichinter') {
8621 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = $object->getLastMainDocLink($object->element);
8622 } else {
8623 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = '';
8624 }
8625 if (getDolGlobalString('SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'supplier_proposal') {
8626 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8627 } else {
8628 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = '';
8629 }
8630
8631 if (is_object($object) && $object->element == 'propal') {
8632 $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id;
8633 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8634 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref, 1, $object);
8635 }
8636 if (is_object($object) && $object->element == 'commande') {
8637 $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id;
8638 }
8639 if (is_object($object) && $object->element == 'facture') {
8640 $substitutionarray['__URL_INVOICE__'] = DOL_MAIN_URL_ROOT."/compta/facture/card.php?id=".$object->id;
8641 }
8642 if (is_object($object) && $object->element == 'contrat') {
8643 $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id;
8644 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8645 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref, 1, $object);
8646 }
8647 if (is_object($object) && $object->element == 'fichinter') {
8648 $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id;
8649 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8650 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref, 1, $object);
8651 }
8652 if (is_object($object) && $object->element == 'supplier_proposal') {
8653 $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id;
8654 }
8655 if (is_object($object) && $object->element == 'shipping') {
8656 $substitutionarray['__URL_SHIPMENT__'] = DOL_MAIN_URL_ROOT."/expedition/card.php?id=".$object->id;
8657 }
8658 }
8659
8660 if (is_object($object) && $object->element == 'action') {
8661 $substitutionarray['__EVENT_LABEL__'] = $object->label;
8662 $substitutionarray['__EVENT_TYPE__'] = $outputlangs->trans("Action".$object->type_code);
8663 $substitutionarray['__EVENT_DATE__'] = dol_print_date($object->datep, 'day', 'auto', $outputlangs);
8664 $substitutionarray['__EVENT_TIME__'] = dol_print_date($object->datep, 'hour', 'auto', $outputlangs);
8665 }
8666 }
8667 }
8668 if ((empty($exclude) || !in_array('objectamount', $exclude)) && (empty($include) || in_array('objectamount', $include))) {
8669 include_once DOL_DOCUMENT_ROOT.'/core/lib/functionsnumtoword.lib.php';
8670
8671 $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : '';
8672 $substitutionarray['__DATE_DUE_YMD__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs) : null) : '';
8673
8674 $already_payed_all = 0;
8675 if (is_object($object) && ($object instanceof Facture)) {
8676 $already_payed_all = $object->sumpayed + $object->sumdeposit + $object->sumcreditnote;
8677 }
8678
8679 $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : '';
8680
8681 $substitutionarray['__AMOUNT__'] = is_object($object) ? $object->total_ttc : '';
8682 $substitutionarray['__AMOUNT_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, '', true) : '';
8683 $substitutionarray['__AMOUNT_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, $conf->currency, true) : '';
8684
8685 $substitutionarray['__AMOUNT_REMAIN__'] = is_object($object) ? price2num($object->total_ttc - $already_payed_all, 'MT') : '';
8686
8687 $substitutionarray['__AMOUNT_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8688 $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)) : '';
8689 $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)) : '';
8690
8691 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8692 $substitutionarray['__AMOUNT_TAX2__'] = is_object($object) ? $object->total_localtax1 : '';
8693 }
8694 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8695 $substitutionarray['__AMOUNT_TAX3__'] = is_object($object) ? $object->total_localtax2 : '';
8696 }
8697
8698 // Amount keys formated in a currency
8699 $substitutionarray['__AMOUNT_EXCL_TAX_FORMATED__'] = is_object($object) ? ($object->total_ht ? price($object->total_ht, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8700 $substitutionarray['__AMOUNT_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8701 $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) : '';
8702 $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)) : '';
8703 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8704 $substitutionarray['__AMOUNT_TAX2_FORMATED__'] = is_object($object) ? ($object->total_localtax1 ? price($object->total_localtax1, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8705 }
8706 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8707 $substitutionarray['__AMOUNT_TAX3_FORMATED__'] = is_object($object) ? ($object->total_localtax2 ? price($object->total_localtax2, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8708 }
8709
8710 $substitutionarray['__AMOUNT_MULTICURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? $object->multicurrency_total_ttc : '';
8711 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXT__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, '', true) : '';
8712 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXTCURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, $object->multicurrency_code, true) : '';
8713 // TODO Add other keys for foreign multicurrency
8714
8715 // For backward compatibility
8716 if ($onlykey != 2) {
8717 $substitutionarray['__TOTAL_TTC__'] = is_object($object) ? $object->total_ttc : '';
8718 $substitutionarray['__TOTAL_HT__'] = is_object($object) ? $object->total_ht : '';
8719 $substitutionarray['__TOTAL_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8720 }
8721 }
8722
8723 //var_dump($substitutionarray['__AMOUNT_FORMATED__']);
8724 if ((empty($exclude) || !in_array('date', $exclude)) && (empty($include) || in_array('date', $include))) {
8725 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
8726
8727 $now = dol_now();
8728
8729 $tmp = dol_getdate($now, true);
8730 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8731 $tmp3 = dol_get_prev_month($tmp['mon'], $tmp['year']);
8732 $tmp4 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8733 $tmp5 = dol_get_next_month($tmp['mon'], $tmp['year']);
8734
8735 $daytext = $outputlangs->trans('Day'.$tmp['wday']);
8736
8737 $substitutionarray = array_merge($substitutionarray, array(
8738 '__NOW_TMS__' => (string) $now, // Must be the string that represent the int
8739 '__NOW_TMS_YMD__' => dol_print_date($now, 'day', 'auto', $outputlangs),
8740 '__DAY__' => (string) $tmp['mday'],
8741 '__DAY_TEXT__' => $daytext, // Monday
8742 '__DAY_TEXT_SHORT__' => dol_trunc($daytext, 3, 'right', 'UTF-8', 1), // Mon
8743 '__DAY_TEXT_MIN__' => dol_trunc($daytext, 1, 'right', 'UTF-8', 1), // M
8744 '__MONTH__' => (string) $tmp['mon'],
8745 '__MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp['mon'])),
8746 '__MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp['mon'])),
8747 '__MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp['mon'])),
8748 '__YEAR__' => (string) $tmp['year'],
8749 '__PREVIOUS_DAY__' => (string) $tmp2['day'],
8750 '__PREVIOUS_MONTH__' => (string) $tmp3['month'],
8751 '__PREVIOUS_YEAR__' => (string) ($tmp['year'] - 1),
8752 '__NEXT_DAY__' => (string) $tmp4['day'],
8753 '__NEXT_MONTH__' => (string) $tmp5['month'],
8754 '__NEXT_MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp5['month'])),
8755 '__NEXT_MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp5['month'])),
8756 '__NEXT_MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp5['month'])),
8757 '__NEXT_YEAR__' => (string) ($tmp['year'] + 1),
8758 ));
8759 }
8760
8761 if (isModEnabled('multicompany')) {
8762 $substitutionarray = array_merge($substitutionarray, array('__ENTITY_ID__' => $conf->entity));
8763 }
8764 if ((empty($exclude) || !in_array('system', $exclude)) && (empty($include) || in_array('user', $include))) {
8765 $substitutionarray['__DOL_MAIN_URL_ROOT__'] = DOL_MAIN_URL_ROOT;
8766 $substitutionarray['__(AnyTranslationKey)__'] = $outputlangs->trans('TranslationOfKey');
8767 $substitutionarray['__(AnyTranslationKey|langfile)__'] = $outputlangs->trans('TranslationOfKey').' (load also language file before)';
8768 $substitutionarray['__[AnyConstantKey]__'] = $outputlangs->trans('ValueOfConstantKey');
8769 }
8770
8771 // Note: The lazyload variables are replaced only during the call by make_substitutions, and only if necessary
8772
8773 return $substitutionarray;
8774}
8775
8792function make_substitutions($text, $substitutionarray, $outputlangs = null, $converttextinhtmlifnecessary = 0)
8793{
8794 global $conf, $db, $langs;
8795
8796 if (!is_array($substitutionarray)) {
8797 return 'ErrorBadParameterSubstitutionArrayWhenCalling_make_substitutions';
8798 }
8799
8800 if (empty($outputlangs)) {
8801 $outputlangs = $langs;
8802 }
8803
8804 // Is initial text HTML or simple text ?
8805 $msgishtml = 0;
8806 if (dol_textishtml($text, 1)) {
8807 $msgishtml = 1;
8808 }
8809
8810 // Make substitution for language keys: __(AnyTranslationKey)__ or __(AnyTranslationKey|langfile)__
8811 if (is_object($outputlangs)) {
8812 $reg = array();
8813 while (preg_match('/__\‍(([^\‍)]+)\‍)__/', $text, $reg)) {
8814 // If key is __(TranslationKey|langfile)__, then force load of langfile.lang
8815 $tmp = explode('|', $reg[1]);
8816 if (!empty($tmp[1])) {
8817 $outputlangs->load($tmp[1]);
8818 }
8819
8820 $value = $outputlangs->transnoentitiesnoconv($reg[1]);
8821
8822 if (empty($converttextinhtmlifnecessary)) {
8823 // convert $newval into HTML is necessary
8824 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8825 } else {
8826 if (! $msgishtml) {
8827 $valueishtml = dol_textishtml($value, 1);
8828 //var_dump("valueishtml=".$valueishtml);
8829
8830 if ($valueishtml) {
8831 $text = dol_htmlentitiesbr($text);
8832 $msgishtml = 1;
8833 }
8834 } else {
8835 $value = dol_nl2br("$value");
8836 }
8837
8838 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $value, $text);
8839 }
8840 }
8841 }
8842
8843 // Make substitution for constant keys.
8844 // Must be after the substitution of translation, so if the text of translation contains a string __[xxx]__, it is also converted.
8845 $reg = array();
8846 while (preg_match('/__\[([^\]]+)\]__/', $text, $reg)) {
8847 $keyfound = $reg[1];
8848 if (isASecretKey($keyfound)) {
8849 $value = '*****forbidden*****';
8850 } else {
8851 $value = empty($conf->global->$keyfound) ? '' : $conf->global->$keyfound;
8852 }
8853
8854 if (empty($converttextinhtmlifnecessary)) {
8855 // convert $newval into HTML is necessary
8856 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8857 } else {
8858 if (! $msgishtml) {
8859 $valueishtml = dol_textishtml($value, 1);
8860
8861 if ($valueishtml) {
8862 $text = dol_htmlentitiesbr($text);
8863 $msgishtml = 1;
8864 }
8865 } else {
8866 $value = dol_nl2br("$value");
8867 }
8868
8869 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $value, $text);
8870 }
8871 }
8872
8873 // Make substitution for array $substitutionarray
8874 foreach ($substitutionarray as $key => $value) {
8875 if (!isset($value)) {
8876 continue; // If value is null, it same than not having substitution key at all into array, we do not replace.
8877 }
8878
8879 if (($key == '__USER_SIGNATURE__' || $key == '__SENDEREMAIL_SIGNATURE__') && (getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN'))) {
8880 $value = ''; // Protection
8881 }
8882
8883 if (empty($converttextinhtmlifnecessary)) {
8884 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8885 } else {
8886 if (! $msgishtml) {
8887 $valueishtml = dol_textishtml($value, 1);
8888
8889 if ($valueishtml) {
8890 $text = dol_htmlentitiesbr($text);
8891 $msgishtml = 1;
8892 }
8893 } else {
8894 $value = dol_nl2br("$value");
8895 }
8896 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8897 }
8898 }
8899
8900 // TODO Implement the lazyload substitution
8901 /*
8902 add a loop to scan $substitutionarray:
8903 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.
8904 If no, we don't need to make replacement, so we do nothing.
8905 If yes, we can make the substitution:
8906
8907 include_once $path;
8908 $tmpobj = new $class($db);
8909 $valuetouseforsubstitution = $tmpobj->$method($id, '__XXX__');
8910 And make the replacement of "__XXX__@lazyload" with $valuetouseforsubstitution
8911 */
8912 $memory_object_list = array();
8913 foreach ($substitutionarray as $key => $value) {
8914 $lazy_load_arr = array();
8915 if (preg_match('/(__[A-Z\_]+__)@lazyload$/', $key, $lazy_load_arr)) {
8916 if (isset($lazy_load_arr[1]) && !empty($lazy_load_arr[1])) {
8917 $key_to_substitute = $lazy_load_arr[1];
8918 if (preg_match('/' . preg_quote($key_to_substitute, '/') . '/', $text)) {
8919 $param_arr = explode(':', $value);
8920 // path:class:method:id
8921 if (count($param_arr) == 4) {
8922 $path = $param_arr[0];
8923 $class = $param_arr[1];
8924 $method = $param_arr[2];
8925 $id = (int) $param_arr[3];
8926
8927 // load class file and init object list in memory
8928 if (!isset($memory_object_list[$class])) {
8929 if (dol_is_file(DOL_DOCUMENT_ROOT . $path)) {
8930 require_once DOL_DOCUMENT_ROOT . $path;
8931 if (class_exists($class)) {
8932 $memory_object_list[$class] = array(
8933 'list' => array(),
8934 );
8935 }
8936 }
8937 }
8938
8939 // fetch object and set substitution
8940 if (isset($memory_object_list[$class]) && isset($memory_object_list[$class]['list'])) {
8941 if (method_exists($class, $method)) {
8942 if (!isset($memory_object_list[$class]['list'][$id])) {
8943 $tmpobj = new $class($db);
8944 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute);
8945 $memory_object_list[$class]['list'][$id] = $tmpobj;
8946 } else {
8947 $tmpobj = $memory_object_list[$class]['list'][$id];
8948 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute, true);
8949 }
8950
8951 $text = str_replace("$key_to_substitute", "$valuetouseforsubstitution", $text); // We must keep the " to work when value is 123.5 for example
8952 }
8953 }
8954 }
8955 }
8956 }
8957 }
8958 }
8959
8960 return $text;
8961}
8962
8975function complete_substitutions_array(&$substitutionarray, $outputlangs, $object = null, $parameters = null, $callfunc = "completesubstitutionarray")
8976{
8977 global $conf, $user;
8978
8979 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
8980
8981 // Note: substitution key for each extrafields, using key __EXTRA_XXX__ is already available into the getCommonSubstitutionArray used to build the substitution array.
8982
8983 // Check if there is external substitution to do, requested by plugins
8984 $dirsubstitutions = array_merge(array(), (array) $conf->modules_parts['substitutions']);
8985
8986 foreach ($dirsubstitutions as $reldir) {
8987 $dir = dol_buildpath($reldir, 0);
8988
8989 // Check if directory exists
8990 if (!dol_is_dir($dir)) {
8991 continue;
8992 }
8993
8994 $substitfiles = dol_dir_list($dir, 'files', 0, 'functions_');
8995 foreach ($substitfiles as $substitfile) {
8996 $reg = array();
8997 if (preg_match('/functions_(.*)\.lib\.php/i', $substitfile['name'], $reg)) {
8998 $module = $reg[1];
8999
9000 dol_syslog("Library ".$substitfile['name']." found into ".$dir);
9001 // Include the user's functions file
9002 require_once $dir.$substitfile['name'];
9003 // Call the user's function, and only if it is defined
9004 $function_name = $module."_".$callfunc;
9005 if (function_exists($function_name)) {
9006 $function_name($substitutionarray, $outputlangs, $object, $parameters);
9007 }
9008 }
9009 }
9010 }
9011 if (getDolGlobalString('ODT_ENABLE_ALL_TAGS_IN_SUBSTITUTIONS')) {
9012 // to list all tags in odt template
9013 $tags = '';
9014 foreach ($substitutionarray as $key => $value) {
9015 $tags .= '{'.$key.'} => '.$value."\n";
9016 }
9017 $substitutionarray = array_merge($substitutionarray, array('__ALL_TAGS__' => $tags));
9018 }
9019}
9020
9030function print_date_range($date_start, $date_end, $format = '', $outputlangs = '')
9031{
9032 print get_date_range($date_start, $date_end, $format, $outputlangs);
9033}
9034
9045function get_date_range($date_start, $date_end, $format = '', $outputlangs = '', $withparenthesis = 1)
9046{
9047 global $langs;
9048
9049 $out = '';
9050
9051 if (!is_object($outputlangs)) {
9052 $outputlangs = $langs;
9053 }
9054
9055 if ($date_start && $date_end) {
9056 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFromTo', dol_print_date($date_start, $format, false, $outputlangs), dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9057 }
9058 if ($date_start && !$date_end) {
9059 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($date_start, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9060 }
9061 if (!$date_start && $date_end) {
9062 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9063 }
9064
9065 return $out;
9066}
9067
9076function dolGetFirstLastname($firstname, $lastname, $nameorder = -1)
9077{
9078 global $conf;
9079
9080 $ret = '';
9081 // If order not defined, we use the setup
9082 if ($nameorder < 0) {
9083 $nameorder = (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION') ? 1 : 0);
9084 }
9085 if ($nameorder == 1) {
9086 $ret .= $firstname;
9087 if ($firstname && $lastname) {
9088 $ret .= ' ';
9089 }
9090 $ret .= $lastname;
9091 } elseif ($nameorder == 2 || $nameorder == 3) {
9092 $ret .= $firstname;
9093 if (empty($ret) && $nameorder == 3) {
9094 $ret .= $lastname;
9095 }
9096 } else { // 0, 4 or 5
9097 $ret .= $lastname;
9098 if (empty($ret) && $nameorder == 5) {
9099 $ret .= $firstname;
9100 }
9101 if ($nameorder == 0) {
9102 if ($firstname && $lastname) {
9103 $ret .= ' ';
9104 }
9105 $ret .= $firstname;
9106 }
9107 }
9108 return $ret;
9109}
9110
9111
9123function setEventMessage($mesgs, $style = 'mesgs', $noduplicate = 0)
9124{
9125 //dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING); This is not deprecated, it is used by setEventMessages function
9126 if (!is_array($mesgs)) {
9127 $mesgs = trim((string) $mesgs);
9128 // If mesgs is a not an empty string
9129 if ($mesgs) {
9130 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesgs, $_SESSION['dol_events'][$style])) {
9131 return;
9132 }
9133 $_SESSION['dol_events'][$style][] = $mesgs;
9134 }
9135 } else {
9136 // If mesgs is an array
9137 foreach ($mesgs as $mesg) {
9138 $mesg = trim((string) $mesg);
9139 if ($mesg) {
9140 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesg, $_SESSION['dol_events'][$style])) {
9141 return;
9142 }
9143 $_SESSION['dol_events'][$style][] = $mesg;
9144 }
9145 }
9146 }
9147}
9148
9161function setEventMessages($mesg, $mesgs, $style = 'mesgs', $messagekey = '', $noduplicate = 0)
9162{
9163 if (empty($mesg) && empty($mesgs)) {
9164 dol_syslog("Try to add a message in stack, but value to add is empty message", LOG_WARNING);
9165 } else {
9166 if ($messagekey) {
9167 // Complete message with a js link to set a cookie "DOLHIDEMESSAGE".$messagekey;
9168 // TODO
9169 $mesg .= '';
9170 }
9171 if (empty($messagekey) || empty($_COOKIE["DOLHIDEMESSAGE".$messagekey])) {
9172 if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
9173 dol_print_error('', 'Bad parameter style='.$style.' for setEventMessages');
9174 }
9175 if (empty($mesgs)) {
9176 setEventMessage($mesg, $style, $noduplicate);
9177 } else {
9178 if (!empty($mesg) && !in_array($mesg, $mesgs)) {
9179 setEventMessage($mesg, $style, $noduplicate); // Add message string if not already into array
9180 }
9181 setEventMessage($mesgs, $style, $noduplicate);
9182 }
9183 }
9184 }
9185}
9186
9196function dol_htmloutput_events($disabledoutputofmessages = 0)
9197{
9198 // Show mesgs
9199 if (isset($_SESSION['dol_events']['mesgs'])) {
9200 if (empty($disabledoutputofmessages)) {
9201 dol_htmloutput_mesg('', $_SESSION['dol_events']['mesgs']);
9202 }
9203 unset($_SESSION['dol_events']['mesgs']);
9204 }
9205 // Show errors
9206 if (isset($_SESSION['dol_events']['errors'])) {
9207 if (empty($disabledoutputofmessages)) {
9208 dol_htmloutput_mesg('', $_SESSION['dol_events']['errors'], 'error');
9209 }
9210 unset($_SESSION['dol_events']['errors']);
9211 }
9212
9213 // Show warnings
9214 if (isset($_SESSION['dol_events']['warnings'])) {
9215 if (empty($disabledoutputofmessages)) {
9216 dol_htmloutput_mesg('', $_SESSION['dol_events']['warnings'], 'warning');
9217 }
9218 unset($_SESSION['dol_events']['warnings']);
9219 }
9220}
9221
9236function get_htmloutput_mesg($mesgstring = '', $mesgarray = '', $style = 'ok', $keepembedded = 0)
9237{
9238 global $conf, $langs;
9239
9240 $ret = 0;
9241 $return = '';
9242 $out = '';
9243 $divstart = $divend = '';
9244
9245 // If inline message with no format, we add it.
9246 if ((empty($conf->use_javascript_ajax) || getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') || $keepembedded) && !preg_match('/<div class=".*">/i', $out)) {
9247 $divstart = '<div class="'.$style.' clearboth">';
9248 $divend = '</div>';
9249 }
9250
9251 if ((is_array($mesgarray) && count($mesgarray)) || $mesgstring) {
9252 $langs->load("errors");
9253 $out .= $divstart;
9254 if (is_array($mesgarray) && count($mesgarray)) {
9255 foreach ($mesgarray as $message) {
9256 $ret++;
9257 $out .= $langs->trans($message);
9258 if ($ret < count($mesgarray)) {
9259 $out .= "<br>\n";
9260 }
9261 }
9262 }
9263 if ($mesgstring) {
9264 $ret++;
9265 $out .= $langs->trans($mesgstring);
9266 }
9267 $out .= $divend;
9268 }
9269
9270 if ($out) {
9271 if (!empty($conf->use_javascript_ajax) && !getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') && empty($keepembedded)) {
9272 $return = '<script nonce="'.getNonce().'">
9273 $(document).ready(function() {
9274 var block = '.(getDolGlobalString('MAIN_USE_JQUERY_BLOCKUI') ? "true" : "false").'
9275 if (block) {
9276 $.dolEventValid("","'.dol_escape_js($out).'");
9277 } else {
9278 /* jnotify(message, preset of message type, keepmessage) */
9279 $.jnotify("'.dol_escape_js($out).'",
9280 "'.($style == "ok" ? 3000 : $style).'",
9281 '.($style == "ok" ? "false" : "true").',
9282 { remove: function (){} } );
9283 }
9284 });
9285 </script>';
9286 } else {
9287 $return = $out;
9288 }
9289 }
9290
9291 return $return;
9292}
9293
9305function get_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9306{
9307 return get_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9308}
9309
9323function dol_htmloutput_mesg($mesgstring = '', $mesgarray = array(), $style = 'ok', $keepembedded = 0)
9324{
9325 if (empty($mesgstring) && (!is_array($mesgarray) || count($mesgarray) == 0)) {
9326 return;
9327 }
9328
9329 $iserror = 0;
9330 $iswarning = 0;
9331 if (is_array($mesgarray)) {
9332 foreach ($mesgarray as $val) {
9333 if ($val && preg_match('/class="error"/i', $val)) {
9334 $iserror++;
9335 break;
9336 }
9337 if ($val && preg_match('/class="warning"/i', $val)) {
9338 $iswarning++;
9339 break;
9340 }
9341 }
9342 } elseif ($mesgstring && preg_match('/class="error"/i', $mesgstring)) {
9343 $iserror++;
9344 } elseif ($mesgstring && preg_match('/class="warning"/i', $mesgstring)) {
9345 $iswarning++;
9346 }
9347 if ($style == 'error') {
9348 $iserror++;
9349 }
9350 if ($style == 'warning') {
9351 $iswarning++;
9352 }
9353
9354 if ($iserror || $iswarning) {
9355 // Remove div from texts
9356 $mesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $mesgstring);
9357 $mesgstring = preg_replace('/<div class="(error|warning)">/', '', $mesgstring);
9358 $mesgstring = preg_replace('/<\/div>/', '', $mesgstring);
9359 // Remove div from texts array
9360 if (is_array($mesgarray)) {
9361 $newmesgarray = array();
9362 foreach ($mesgarray as $val) {
9363 if (is_string($val)) {
9364 $tmpmesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $val);
9365 $tmpmesgstring = preg_replace('/<div class="(error|warning)">/', '', $tmpmesgstring);
9366 $tmpmesgstring = preg_replace('/<\/div>/', '', $tmpmesgstring);
9367 $newmesgarray[] = $tmpmesgstring;
9368 } else {
9369 dol_syslog("Error call of dol_htmloutput_mesg with an array with a value that is not a string", LOG_WARNING);
9370 }
9371 }
9372 $mesgarray = $newmesgarray;
9373 }
9374 print get_htmloutput_mesg($mesgstring, $mesgarray, ($iserror ? 'error' : 'warning'), $keepembedded);
9375 } else {
9376 print get_htmloutput_mesg($mesgstring, $mesgarray, 'ok', $keepembedded);
9377 }
9378}
9379
9391function dol_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9392{
9393 dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9394}
9395
9410function dol_sort_array(&$array, $index, $order = 'asc', $natsort = 0, $case_sensitive = 0, $keepindex = 0)
9411{
9412 // Clean parameters
9413 $order = strtolower($order);
9414
9415 if (is_array($array)) {
9416 $sizearray = count($array);
9417 if ($sizearray > 0) {
9418 $temp = array();
9419 foreach (array_keys($array) as $key) {
9420 if (is_object($array[$key])) {
9421 $temp[$key] = empty($array[$key]->$index) ? 0 : $array[$key]->$index;
9422 } else {
9423 $temp[$key] = empty($array[$key][$index]) ? 0 : $array[$key][$index];
9424 }
9425 if ($natsort == -1) {
9426 $temp[$key] = '___'.$temp[$key]; // We add a string at begin of value to force an alpha order when using asort.
9427 }
9428 }
9429
9430 if (empty($natsort) || $natsort == -1) {
9431 if ($order == 'asc') {
9432 asort($temp);
9433 } else {
9434 arsort($temp);
9435 }
9436 } else {
9437 if ($case_sensitive) {
9438 natsort($temp);
9439 } else {
9440 natcasesort($temp); // natecasesort is not sensible to case
9441 }
9442 if ($order != 'asc') {
9443 $temp = array_reverse($temp, true);
9444 }
9445 }
9446
9447 $sorted = array();
9448
9449 foreach (array_keys($temp) as $key) {
9450 (is_numeric($key) && empty($keepindex)) ? $sorted[] = $array[$key] : $sorted[$key] = $array[$key];
9451 }
9452
9453 return $sorted;
9454 }
9455 }
9456 return $array;
9457}
9458
9459
9467function utf8_check($str)
9468{
9469 $str = (string) $str; // Sometimes string is an int.
9470
9471 // We must use here a binary strlen function (so not dol_strlen)
9472 $strLength = strlen($str);
9473 for ($i = 0; $i < $strLength; $i++) {
9474 if (ord($str[$i]) < 0x80) {
9475 continue; // 0bbbbbbb
9476 } elseif ((ord($str[$i]) & 0xE0) == 0xC0) {
9477 $n = 1; // 110bbbbb
9478 } elseif ((ord($str[$i]) & 0xF0) == 0xE0) {
9479 $n = 2; // 1110bbbb
9480 } elseif ((ord($str[$i]) & 0xF8) == 0xF0) {
9481 $n = 3; // 11110bbb
9482 } elseif ((ord($str[$i]) & 0xFC) == 0xF8) {
9483 $n = 4; // 111110bb
9484 } elseif ((ord($str[$i]) & 0xFE) == 0xFC) {
9485 $n = 5; // 1111110b
9486 } else {
9487 return false; // Does not match any model
9488 }
9489 for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
9490 if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80)) {
9491 return false;
9492 }
9493 }
9494 }
9495 return true;
9496}
9497
9505function utf8_valid($str)
9506{
9507 /* 2 other methods to test if string is utf8
9508 $validUTF8 = mb_check_encoding($messagetext, 'UTF-8');
9509 $validUTF8b = ! (false === mb_detect_encoding($messagetext, 'UTF-8', true));
9510 */
9511 return preg_match('//u', $str) ? true : false;
9512}
9513
9514
9521function ascii_check($str)
9522{
9523 if (function_exists('mb_check_encoding')) {
9524 //if (mb_detect_encoding($str, 'ASCII', true) return false;
9525 if (!mb_check_encoding($str, 'ASCII')) {
9526 return false;
9527 }
9528 } else {
9529 if (preg_match('/[^\x00-\x7f]/', $str)) {
9530 return false; // Contains a byte > 7f
9531 }
9532 }
9533
9534 return true;
9535}
9536
9537
9545function dol_osencode($str)
9546{
9547 global $conf;
9548
9549 $tmp = ini_get("unicode.filesystem_encoding"); // Disponible avec PHP 6.0
9550 if (empty($tmp) && !empty($_SERVER["WINDIR"])) {
9551 $tmp = 'iso-8859-1'; // By default for windows
9552 }
9553 if (empty($tmp)) {
9554 $tmp = 'utf-8'; // By default for other
9555 }
9556 if (getDolGlobalString('MAIN_FILESYSTEM_ENCODING')) {
9557 $tmp = $conf->global->MAIN_FILESYSTEM_ENCODING;
9558 }
9559
9560 if ($tmp == 'iso-8859-1') {
9561 return mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8');
9562 }
9563 return $str;
9564}
9565
9566
9582function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '', $useCache = true)
9583{
9584 global $cache_codes;
9585
9586 // If key empty
9587 if ($key == '') {
9588 return '';
9589 }
9590
9591 // Check in cache
9592 if ($useCache && isset($cache_codes[$tablename][$fieldkey][$fieldid][$entityfilter][$filters][$key])) { // Can be defined to 0 or ''
9593 return $cache_codes[$tablename][$fieldkey][$fieldid][$entityfilter][$filters][$key]; // Found in cache
9594 }
9595
9596 dol_syslog('dol_getIdFromCode (value for field '.$fieldid.' from key '.$key.' not found into cache)', LOG_DEBUG);
9597
9598 $sql = "SELECT ".$fieldid." as valuetoget";
9599 $sql .= " FROM ".MAIN_DB_PREFIX.$tablename;
9600 $sql .= " WHERE ".$fieldkey." = '".$db->escape($key)."'";
9601 if (!empty($entityfilter)) {
9602 $sql .= " AND entity IN (".getEntity($tablename).")";
9603 }
9604 if ($filters) {
9605 $sql .= $filters;
9606 }
9607
9608 $resql = $db->query($sql);
9609 if ($resql) {
9610 $obj = $db->fetch_object($resql);
9611 $valuetoget = '';
9612 if ($obj) {
9613 $valuetoget = $obj->valuetoget;
9614 }
9615 $db->free($resql);
9616 if ($useCache) {
9617 $cache_codes[$tablename][$fieldkey][$fieldid][$entityfilter][$filters][$key] = $valuetoget;
9618 }
9619 return $valuetoget;
9620 } else {
9621 return -1;
9622 }
9623}
9624
9634function isStringVarMatching($var, $regextext, $matchrule = 1)
9635{
9636 if ($matchrule == 1) {
9637 if ($var == 'mainmenu') {
9638 global $mainmenu;
9639 return (preg_match('/^'.$regextext.'/', $mainmenu));
9640 } elseif ($var == 'leftmenu') {
9641 global $leftmenu;
9642 return (preg_match('/^'.$regextext.'/', $leftmenu));
9643 } else {
9644 return 'This variable is not accessible with dol_eval';
9645 }
9646 } else {
9647 return 'This value for matchrule is not implemented';
9648 }
9649}
9650
9651
9658function verifCond($strToEvaluate)
9659{
9660 //print $strToEvaluate."<br>\n";
9661 $rights = true;
9662 if (isset($strToEvaluate) && $strToEvaluate !== '') {
9663 //var_dump($strToEvaluate);
9664 //$rep = dol_eval($strToEvaluate, 1, 0, '1'); // to show the error
9665 $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
9666 $rights = $rep && (!is_string($rep) || strpos($rep, 'Bad string syntax to evaluate') === false);
9667 //var_dump($rights);
9668 }
9669 return $rights;
9670}
9671
9685function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1')
9686{
9687 // Only this global variables can be read by eval function and returned to caller
9688 global $conf; // Read of const is done with getDolGlobalString() but we need $conf->currency for example
9689 global $db, $langs, $user, $website, $websitepage;
9690 global $action, $mainmenu, $leftmenu;
9691 global $mysoc;
9692 global $objectoffield; // To allow the use of $objectoffield in computed fields
9693
9694 // Old variables used
9695 global $object;
9696 global $obj; // To get $obj used into list when dol_eval() is used for computed fields and $obj is not yet $object
9697
9698 if (!in_array($onlysimplestring, array('0', '1', '2'))) {
9699 return "Bad call of dol_eval. Parameter onlysimplestring must be '0' (deprecated), '1' or '2'";
9700 }
9701
9702 try {
9703 // Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing
9704 if ($onlysimplestring == '1') {
9705 // We must accept: '1 && getDolGlobalInt("doesnotexist1") && getDolGlobalString("MAIN_FEATURES_LEVEL")'
9706 // We must accept: '$user->hasRight("cabinetmed", "read") && !$object->canvas=="patient@cabinetmed"'
9707 $specialcharsallowed = '^$_+-.*>&|=!?():"\',/@';
9708 if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
9709 $specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
9710 }
9711 if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
9712 if ($returnvalue) {
9713 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9714 } else {
9715 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9716 return '';
9717 }
9718 }
9719 $savescheck = '';
9720 $scheck = $s;
9721 while ($scheck && $savescheck != $scheck) {
9722 $savescheck = $scheck;
9723 $scheck = preg_replace('/->[a-zA-Z0-9_]+\‍(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
9724 $scheck = preg_replace('/^\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9725 $scheck = preg_replace('/\s\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9726 $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
9727 $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
9728 $scheck = preg_replace('/(\^|\')\‍(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
9729 }
9730 //print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
9731 if (strpos($scheck, '(') !== false) {
9732 if ($returnvalue) {
9733 return 'Bad string syntax to evaluate (mode 1, found call of a function or method without using the direct name of the function): '.$s;
9734 } else {
9735 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);
9736 return '';
9737 }
9738 }
9739 // TODO
9740 // We can exclude $ char that are not: $db, $langs, $leftmenu, $topmenu, $user, $langs, $objectoffield, $object...,
9741 } elseif ($onlysimplestring == '2') {
9742 // 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"
9743 $specialcharsallowed = '^$_+-.*>&|=!?():"\',/@[]';
9744 if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
9745 $specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
9746 }
9747 if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
9748 if ($returnvalue) {
9749 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9750 } else {
9751 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9752 return '';
9753 }
9754 }
9755 $savescheck = '';
9756 $scheck = $s;
9757 while ($scheck && $savescheck != $scheck) {
9758 $savescheck = $scheck;
9759 $scheck = preg_replace('/->[a-zA-Z0-9_]+\‍(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
9760 $scheck = preg_replace('/^\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9761 $scheck = preg_replace('/\s\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9762 $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
9763 $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
9764 $scheck = preg_replace('/(\^|\')\‍(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
9765 }
9766 //print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
9767 if (strpos($scheck, '(') !== false) {
9768 if ($returnvalue) {
9769 return 'Bad string syntax to evaluate (mode 2, found call of a function or method without using the direct name of the function): '.$s;
9770 } else {
9771 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);
9772 return '';
9773 }
9774 }
9775 // TODO
9776 // We can exclude $ char that are not: $db, $leftmenu, $topmenu, $user, $langs, $object...,
9777 }
9778 if (is_array($s) || $s === 'Array') {
9779 return 'Bad string syntax to evaluate (value is Array) '.var_export($s, true);
9780 }
9781
9782 if (!getDolGlobalString('MAIN_ALLOW_DOUBLE_COLON_IN_DOL_EVAL') && strpos($s, '::') !== false) {
9783 if ($returnvalue) {
9784 return 'Bad string syntax to evaluate (double : char is forbidden without setting MAIN_ALLOW_DOUBLE_COLON_IN_DOL_EVAL): '.$s;
9785 } else {
9786 dol_syslog('Bad string syntax to evaluate (double : char is forbidden without setting MAIN_ALLOW_DOUBLE_COLON_IN_DOL_EVAL): '.$s, LOG_WARNING);
9787 return '';
9788 }
9789 }
9790
9791 if (strpos($s, '`') !== false) {
9792 if ($returnvalue) {
9793 return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
9794 } else {
9795 dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s);
9796 return '';
9797 }
9798 }
9799
9800 // Disallow also concat
9801 if (getDolGlobalString('MAIN_DISALLOW_STRING_OBFUSCATION_IN_DOL_EVAL')) {
9802 if (preg_match('/[^0-9]+\.[^0-9]+/', $s)) { // We refuse . if not between 2 numbers
9803 if ($returnvalue) {
9804 return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
9805 } else {
9806 dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s);
9807 return '';
9808 }
9809 }
9810 }
9811
9812 // We block use of php exec or php file functions
9813 $forbiddenphpstrings = array('$$');
9814 $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
9815
9816 // We list all forbidden function as keywords we don't want to see (we don't mind it if is "kewyord(" or just "keyword", we don't want "keyword" at all)
9817 // We must exclude all functions that allow to execute another function. This includes all function that has a parameter with type "callable" to avoid things
9818 // like we can do with array_map and its callable parameter: dol_eval('json_encode(array_map(implode("",["ex","ec"]), ["id"]))', 1, 1, '0')
9819 $forbiddenphpfunctions = array();
9820 // @phpcs:ignore
9821 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64"."_"."decode", "rawurl"."decode", "url"."decode", "str"."_rot13", "hex"."2bin")); // name of forbidden functions are split to avoid false positive
9822 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("override_function", "session_id", "session_create_id", "session_regenerate_id"));
9823 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
9824 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func", "call_user_func_array"));
9825
9826 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("array_all", "array_any", "array_diff_ukey", "array_filter", "array_find", "array_find_key", "array_map", "array_reduce", "array_intersect_uassoc", "array_intersect_ukey", "array_walk", "array_walk_recursive"));
9827 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("usort", "uasort", "uksort", "preg_replace_callback", "preg_replace_callback_array", "header_register_callback"));
9828 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("set_error_handler", "set_exception_handler", "libxml_set_external_entity_loader", "register_shutdown_function", "register_tick_function", "unregister_tick_function"));
9829 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("spl_autoload_register", "spl_autoload_unregister", "iterator_apply", "session_set_save_handler"));
9830 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("forward_static_call", "forward_static_call_array", "register_postsend_function"));
9831
9832 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("ob_start"));
9833
9834 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
9835 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("exec", "passthru", "shell_exec", "system", "proc_open", "popen"));
9836 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
9837 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace", "mb_ereg_replace_callback")); // function with eval capabilities
9838 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("readline_completion_function", "readline_callback_handler_install"));
9839 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_compress_dir", "dol_decode", "dol_delete_file", "dol_delete_dir", "dol_delete_dir_recursive", "dol_copy", "archiveOrBackupFile")); // more dolibarr functions
9840 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
9841 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include"));
9842
9843 $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
9844
9845 $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
9846
9847 $forbiddenphpmethodsregex = '->('.implode('|', $forbiddenphpmethods).')';
9848
9849 do {
9850 $oldstringtoclean = $s;
9851 $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);
9852 $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);
9853 $s = preg_replace('/'.$forbiddenphpmethodsregex.'/i', '__forbiddenstring__', $s);
9854 //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\‍(/i', '', $s); // Remove $function( call and $mycall->mymethod(
9855 } while ($oldstringtoclean != $s);
9856
9857 if (strpos($s, '__forbiddenstring__') !== false) {
9858 dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
9859 if ($returnvalue) {
9860 return 'Bad string syntax to evaluate: '.$s;
9861 } else {
9862 dol_syslog('Bad string syntax to evaluate: '.$s);
9863 return '';
9864 }
9865 }
9866
9867 //print $s."<br>\n";
9868 if ($returnvalue) {
9869 if ($hideerrors) {
9870 return @eval('return '.$s.';');
9871 } else {
9872 return eval('return '.$s.';');
9873 }
9874 } else {
9875 if ($hideerrors) {
9876 @eval($s);
9877 } else {
9878 eval($s);
9879 }
9880 }
9881 } catch (Error $e) {
9882 $error = 'dol_eval try/catch error : ';
9883 $error .= $e->getMessage();
9884 dol_syslog($error, LOG_WARNING);
9885 }
9886}
9887
9895function dol_validElement($element)
9896{
9897 return (trim($element) != '');
9898}
9899
9908function picto_from_langcode($codelang, $moreatt = '', $notitlealt = 0)
9909{
9910 if (empty($codelang)) {
9911 return '';
9912 }
9913
9914 if ($codelang == 'auto') {
9915 return '<span class="fa fa-language"></span>';
9916 }
9917
9918 $langtocountryflag = array(
9919 'ar_AR' => '',
9920 'ca_ES' => 'catalonia',
9921 'da_DA' => 'dk',
9922 'fr_CA' => 'mq',
9923 'sv_SV' => 'se',
9924 'sw_SW' => 'unknown',
9925 'AQ' => 'unknown',
9926 'CW' => 'unknown',
9927 'IM' => 'unknown',
9928 'JE' => 'unknown',
9929 'MF' => 'unknown',
9930 'BL' => 'unknown',
9931 'SX' => 'unknown'
9932 );
9933
9934 if (isset($langtocountryflag[$codelang])) {
9935 $flagImage = $langtocountryflag[$codelang];
9936 } else {
9937 $tmparray = explode('_', $codelang);
9938 $flagImage = empty($tmparray[1]) ? $tmparray[0] : $tmparray[1];
9939 }
9940
9941 $morecss = '';
9942 $reg = array();
9943 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
9944 $morecss = $reg[1];
9945 $moreatt = "";
9946 }
9947
9948 // return img_picto_common($codelang, 'flags/'.strtolower($flagImage).'.png', $moreatt, 0, $notitlealt);
9949 return '<span class="flag-sprite '.strtolower($flagImage).($morecss ? ' '.$morecss : '').'"'.($moreatt ? ' '.$moreatt : '').(!$notitlealt ? ' title="'.$codelang.'"' : '').'></span>';
9950}
9951
9960{
9961 global $mysoc;
9962
9963 if (empty($countrycode)) {
9964 return null;
9965 }
9966
9967 if (strtoupper($countrycode) == 'MQ') {
9968 return 'fr_CA';
9969 }
9970 if (strtoupper($countrycode) == 'SE') {
9971 return 'sv_SE'; // se_SE is Sami/Sweden, and we want in priority sv_SE for SE country
9972 }
9973 if (strtoupper($countrycode) == 'CH') {
9974 if ($mysoc->country_code == 'FR') {
9975 return 'fr_CH';
9976 }
9977 if ($mysoc->country_code == 'DE') {
9978 return 'de_CH';
9979 }
9980 if ($mysoc->country_code == 'IT') {
9981 return 'it_CH';
9982 }
9983 }
9984
9985 // Locale list taken from:
9986 // http://stackoverflow.com/questions/3191664/
9987 // list-of-all-locales-and-their-short-codes
9988 $locales = array(
9989 'af-ZA',
9990 'am-ET',
9991 'ar-AE',
9992 'ar-BH',
9993 'ar-DZ',
9994 'ar-EG',
9995 'ar-IQ',
9996 'ar-JO',
9997 'ar-KW',
9998 'ar-LB',
9999 'ar-LY',
10000 'ar-MA',
10001 'ar-OM',
10002 'ar-QA',
10003 'ar-SA',
10004 'ar-SY',
10005 'ar-TN',
10006 'ar-YE',
10007 //'as-IN', // Moved after en-IN
10008 'ba-RU',
10009 'be-BY',
10010 'bg-BG',
10011 'bn-BD',
10012 //'bn-IN', // Moved after en-IN
10013 'bo-CN',
10014 'br-FR',
10015 'ca-ES',
10016 'co-FR',
10017 'cs-CZ',
10018 'cy-GB',
10019 'da-DK',
10020 'de-AT',
10021 'de-CH',
10022 'de-DE',
10023 'de-LI',
10024 'de-LU',
10025 'dv-MV',
10026 'el-GR',
10027 'en-AU',
10028 'en-BZ',
10029 'en-CA',
10030 'en-GB',
10031 'en-IE',
10032 'en-IN',
10033 'as-IN', // as-IN must be after en-IN (en in priority if country is IN)
10034 'bn-IN', // bn-IN must be after en-IN (en in priority if country is IN)
10035 'en-JM',
10036 'en-MY',
10037 'en-NZ',
10038 'en-PH',
10039 'en-SG',
10040 'en-TT',
10041 'en-US',
10042 'en-ZA',
10043 'en-ZW',
10044 'es-AR',
10045 'es-BO',
10046 'es-CL',
10047 'es-CO',
10048 'es-CR',
10049 'es-DO',
10050 'es-EC',
10051 'es-ES',
10052 'es-GT',
10053 'es-HN',
10054 'es-MX',
10055 'es-NI',
10056 'es-PA',
10057 'es-PE',
10058 'es-PR',
10059 'es-PY',
10060 'es-SV',
10061 'es-US',
10062 'es-UY',
10063 'es-VE',
10064 'et-EE',
10065 'eu-ES',
10066 'fa-IR',
10067 'fi-FI',
10068 'fo-FO',
10069 'fr-BE',
10070 'fr-CA',
10071 'fr-CH',
10072 'fr-FR',
10073 'fr-LU',
10074 'fr-MC',
10075 'fy-NL',
10076 'ga-IE',
10077 'gd-GB',
10078 'gl-ES',
10079 'gu-IN',
10080 'he-IL',
10081 'hi-IN',
10082 'hr-BA',
10083 'hr-HR',
10084 'hu-HU',
10085 'hy-AM',
10086 'id-ID',
10087 'ig-NG',
10088 'ii-CN',
10089 'is-IS',
10090 'it-CH',
10091 'it-IT',
10092 'ja-JP',
10093 'ka-GE',
10094 'kk-KZ',
10095 'kl-GL',
10096 'km-KH',
10097 'kn-IN',
10098 'ko-KR',
10099 'ky-KG',
10100 'lb-LU',
10101 'lo-LA',
10102 'lt-LT',
10103 'lv-LV',
10104 'mi-NZ',
10105 'mk-MK',
10106 'ml-IN',
10107 'mn-MN',
10108 'mr-IN',
10109 'ms-BN',
10110 'ms-MY',
10111 'mt-MT',
10112 'nb-NO',
10113 'ne-NP',
10114 'nl-BE',
10115 'nl-NL',
10116 'nn-NO',
10117 'oc-FR',
10118 'or-IN',
10119 'pa-IN',
10120 'pl-PL',
10121 'ps-AF',
10122 'pt-BR',
10123 'pt-PT',
10124 'rm-CH',
10125 'ro-MD',
10126 'ro-RO',
10127 'ru-RU',
10128 'rw-RW',
10129 'sa-IN',
10130 'se-FI',
10131 'se-NO',
10132 'se-SE',
10133 'si-LK',
10134 'sk-SK',
10135 'sl-SI',
10136 'sq-AL',
10137 'sv-FI',
10138 'sv-SE',
10139 'sw-KE',
10140 'ta-IN',
10141 'te-IN',
10142 'th-TH',
10143 'tk-TM',
10144 'tn-ZA',
10145 'tr-TR',
10146 'tt-RU',
10147 'ug-CN',
10148 'uk-UA',
10149 'ur-PK',
10150 'vi-VN',
10151 'wo-SN',
10152 'xh-ZA',
10153 'yo-NG',
10154 'zh-CN',
10155 'zh-HK',
10156 'zh-MO',
10157 'zh-SG',
10158 'zh-TW',
10159 'zu-ZA',
10160 );
10161
10162 $buildprimarykeytotest = strtolower($countrycode).'-'.strtoupper($countrycode);
10163 if (in_array($buildprimarykeytotest, $locales)) {
10164 return strtolower($countrycode).'_'.strtoupper($countrycode);
10165 }
10166
10167 if (function_exists('locale_get_primary_language') && function_exists('locale_get_region')) { // Need extension php-intl
10168 foreach ($locales as $locale) {
10169 $locale_language = locale_get_primary_language($locale);
10170 $locale_region = locale_get_region($locale);
10171 if (strtoupper($countrycode) == $locale_region) {
10172 //var_dump($locale.' - '.$locale_language.' - '.$locale_region);
10173 return strtolower($locale_language).'_'.strtoupper($locale_region);
10174 }
10175 }
10176 } else {
10177 dol_syslog("Warning Exention php-intl is not available", LOG_WARNING);
10178 }
10179
10180 return null;
10181}
10182
10213function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode = 'add', $filterorigmodule = '')
10214{
10215 global $hookmanager, $db;
10216
10217 if (isset($conf->modules_parts['tabs'][$type]) && is_array($conf->modules_parts['tabs'][$type])) {
10218 foreach ($conf->modules_parts['tabs'][$type] as $value) {
10219 $values = explode(':', $value);
10220
10221 $reg = array();
10222 if ($mode == 'add' && !preg_match('/^\-/', $values[1])) {
10223 $newtab = array();
10224 $postab = $h;
10225 // detect if position set in $values[1] ie : +(2)mytab@mymodule (first tab is 0, second is one, ...)
10226 $str = $values[1];
10227 $posstart = strpos($str, '(');
10228 if ($posstart > 0) {
10229 $posend = strpos($str, ')');
10230 if ($posstart > 0) {
10231 $res1 = substr($str, $posstart + 1, $posend - $posstart -1);
10232 if (is_numeric($res1)) {
10233 $postab = (int) $res1;
10234 $values[1] = '+' . substr($str, $posend + 1);
10235 }
10236 }
10237 }
10238 if (count($values) == 6) {
10239 // new declaration with permissions:
10240 // $value='objecttype:+tabname1:Title1:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10241 // $value='objecttype:+tabname1:Title1,class,pathfile,method:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10242 if ($values[0] != $type) {
10243 continue;
10244 }
10245
10246 if (verifCond($values[4])) {
10247 if ($values[3]) {
10248 if ($filterorigmodule) { // If a filter of module origin has been requested
10249 if (strpos($values[3], '@')) { // This is an external module
10250 if ($filterorigmodule != 'external') {
10251 continue;
10252 }
10253 } else { // This looks a core module
10254 if ($filterorigmodule != 'core') {
10255 continue;
10256 }
10257 }
10258 }
10259 $langs->load($values[3]);
10260 }
10261 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10262 // If label is "SUBSTITUION_..."
10263 $substitutionarray = array();
10264 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
10265 $label = make_substitutions($reg[1], $substitutionarray);
10266 } else {
10267 // If label is "Label,Class,File,Method", we call the method to show content inside the badge
10268 $labeltemp = explode(',', $values[2]);
10269 $label = $langs->trans($labeltemp[0]);
10270
10271 if (!empty($labeltemp[1]) && is_object($object) && !empty($object->id)) {
10272 dol_include_once($labeltemp[2]);
10273 $classtoload = $labeltemp[1];
10274 if (class_exists($classtoload)) {
10275 $obj = new $classtoload($db);
10276 $function = $labeltemp[3];
10277 if ($obj && $function && method_exists($obj, $function)) {
10278 $nbrec = $obj->$function($object->id, $obj);
10279 if (!empty($nbrec)) {
10280 $label .= '<span class="badge marginleftonlyshort">'.$nbrec.'</span>';
10281 }
10282 }
10283 }
10284 }
10285 }
10286
10287 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[5]), 1);
10288 $newtab[1] = $label;
10289 $newtab[2] = str_replace('+', '', $values[1]);
10290 $h++;
10291 } else {
10292 continue;
10293 }
10294 } elseif (count($values) == 5) { // case deprecated
10295 dol_syslog('Passing 5 values in tabs module_parts is deprecated. Please update to 6 with permissions.', LOG_WARNING);
10296
10297 if ($values[0] != $type) {
10298 continue;
10299 }
10300 if ($values[3]) {
10301 if ($filterorigmodule) { // If a filter of module origin has been requested
10302 if (strpos($values[3], '@')) { // This is an external module
10303 if ($filterorigmodule != 'external') {
10304 continue;
10305 }
10306 } else { // This looks a core module
10307 if ($filterorigmodule != 'core') {
10308 continue;
10309 }
10310 }
10311 }
10312 $langs->load($values[3]);
10313 }
10314 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10315 $substitutionarray = array();
10316 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
10317 $label = make_substitutions($reg[1], $substitutionarray);
10318 } else {
10319 $label = $langs->trans($values[2]);
10320 }
10321
10322 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[4]), 1);
10323 $newtab[1] = $label;
10324 $newtab[2] = str_replace('+', '', $values[1]);
10325 $h++;
10326 }
10327 // set tab at its position
10328 $head = array_merge(array_slice($head, 0, $postab), array($newtab), array_slice($head, $postab));
10329 } elseif ($mode == 'remove' && preg_match('/^\-/', $values[1])) {
10330 if ($values[0] != $type) {
10331 continue;
10332 }
10333 $tabname = str_replace('-', '', $values[1]);
10334 foreach ($head as $key => $val) {
10335 $condition = (!empty($values[3]) ? verifCond($values[3]) : 1);
10336 //var_dump($key.' - '.$tabname.' - '.$head[$key][2].' - '.$values[3].' - '.$condition);
10337 if ($head[$key][2] == $tabname && $condition) {
10338 unset($head[$key]);
10339 break;
10340 }
10341 }
10342 }
10343 }
10344 }
10345
10346 // No need to make a return $head. Var is modified as a reference
10347 if (!empty($hookmanager)) {
10348 $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule);
10349 $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters, $object);
10350 if ($reshook > 0) { // Hook ask to replace completely the array
10351 $head = $hookmanager->resArray;
10352 } else { // Hook
10353 $head = array_merge($head, $hookmanager->resArray);
10354 }
10355 $h = count($head);
10356 }
10357}
10358
10370function printCommonFooter($zone = 'private')
10371{
10372 global $conf, $hookmanager, $user, $debugbar;
10373 global $action;
10374 global $micro_start_time;
10375
10376 if ($zone == 'private') {
10377 print "\n".'<!-- Common footer for private page -->'."\n";
10378 } else {
10379 print "\n".'<!-- Common footer for public page -->'."\n";
10380 }
10381
10382 // A div to store page_y POST parameter so we can read it using javascript
10383 print "\n<!-- A div to store page_y POST parameter -->\n";
10384 print '<div id="page_y" style="display: none;">'.(GETPOST('page_y') ? GETPOST('page_y') : '').'</div>'."\n";
10385
10386 $parameters = array();
10387 $reshook = $hookmanager->executeHooks('printCommonFooter', $parameters); // Note that $action and $object may have been modified by some hooks
10388 if (empty($reshook)) {
10389 if (getDolGlobalString('MAIN_HTML_FOOTER')) {
10390 print getDolGlobalString('MAIN_HTML_FOOTER') . "\n";
10391 }
10392
10393 print "\n";
10394 if (!empty($conf->use_javascript_ajax)) {
10395 print "\n<!-- A script section to add menuhider handler on backoffice, manage focus and madatory fields, tuning info, ... -->\n";
10396 print '<script>'."\n";
10397 print 'jQuery(document).ready(function() {'."\n";
10398
10399 if ($zone == 'private' && empty($conf->dol_use_jmobile)) {
10400 print "\n";
10401 print '/* JS CODE TO ENABLE to manage handler to switch left menu page (menuhider) */'."\n";
10402 print 'jQuery("li.menuhider").click(function(event) {';
10403 print ' if (!$( "body" ).hasClass( "sidebar-collapse" )){ event.preventDefault(); }'."\n";
10404 print ' console.log("We click on .menuhider");'."\n";
10405 print ' $("body").toggleClass("sidebar-collapse")'."\n";
10406 print '});'."\n";
10407 }
10408
10409 // Management of focus and mandatory for fields
10410 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"])))) {
10411 print '/* JS CODE TO ENABLE to manage focus and mandatory form fields */'."\n";
10412 $relativepathstring = $_SERVER["PHP_SELF"];
10413 // Clean $relativepathstring
10414 if (constant('DOL_URL_ROOT')) {
10415 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
10416 }
10417 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
10418 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
10419 //$tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
10420 if (!empty($user->default_values[$relativepathstring]['focus'])) {
10421 foreach ($user->default_values[$relativepathstring]['focus'] as $defkey => $defval) {
10422 $qualified = 0;
10423 if ($defkey != '_noquery_') {
10424 $tmpqueryarraytohave = explode('&', $defkey);
10425 $foundintru = 0;
10426 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
10427 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
10428 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
10429 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
10430 $foundintru = 1;
10431 }
10432 }
10433 if (!$foundintru) {
10434 $qualified = 1;
10435 }
10436 //var_dump($defkey.'-'.$qualified);
10437 } else {
10438 $qualified = 1;
10439 }
10440
10441 if ($qualified) {
10442 foreach ($defval as $paramkey => $paramval) {
10443 // Set focus on field
10444 print 'jQuery("input[name=\''.$paramkey.'\']").focus();'."\n";
10445 print 'jQuery("textarea[name=\''.$paramkey.'\']").focus();'."\n";
10446 print 'jQuery("select[name=\''.$paramkey.'\']").focus();'."\n"; // Not really usefull, but we keep it in case of.
10447 }
10448 }
10449 }
10450 }
10451 if (!empty($user->default_values[$relativepathstring]['mandatory'])) {
10452 foreach ($user->default_values[$relativepathstring]['mandatory'] as $defkey => $defval) {
10453 $qualified = 0;
10454 if ($defkey != '_noquery_') {
10455 $tmpqueryarraytohave = explode('&', $defkey);
10456 $foundintru = 0;
10457 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
10458 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
10459 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
10460 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
10461 $foundintru = 1;
10462 }
10463 }
10464 if (!$foundintru) {
10465 $qualified = 1;
10466 }
10467 //var_dump($defkey.'-'.$qualified);
10468 } else {
10469 $qualified = 1;
10470 }
10471
10472 if ($qualified) {
10473 foreach ($defval as $paramkey => $paramval) {
10474 // Add property 'required' on input
10475 print 'jQuery("input[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10476 print 'jQuery("textarea[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10477 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";
10478 print 'if (jQuery("select[name=\''.$paramkey.'\']").is(\':visible\')===true) {'."\n";
10479 print 'jQuery("select[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n"; // can set focus only if this element is visible
10480 print '}'."\n";
10481 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'-1\']").prop(\'value\', \'\');'."\n";
10482 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'0\']").prop(\'value\', \'\');'."\n";
10483
10484 // Add 'field required' class on closest td for all input elements : input, textarea and select
10485 print 'jQuery(":input[name=\'' . $paramkey . '\']").closest("tr").find("td:first").addClass("fieldrequired");' . "\n";
10486 }
10487 // If we submit the cancel button we remove the required attributes
10488 print 'jQuery("input[name=\'cancel\']").click(function() {
10489 console.log("We click on cancel button so removed all required attribute");
10490 jQuery("input, textarea, select").each(function(){this.removeAttribute(\'required\');});
10491 });'."\n";
10492 }
10493 }
10494 }
10495 }
10496
10497 print '});'."\n";
10498
10499 // End of tuning
10500 if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO']) || getDolGlobalString('MAIN_SHOW_TUNING_INFO')) {
10501 print "\n";
10502 print "/* JS CODE TO ENABLE to add memory info */\n";
10503 print 'window.console && console.log("';
10504 if (getDolGlobalString('MEMCACHED_SERVER')) {
10505 print 'MEMCACHED_SERVER=' . getDolGlobalString('MEMCACHED_SERVER').' - ';
10506 }
10507 print 'MAIN_OPTIMIZE_SPEED='.(isset($conf->global->MAIN_OPTIMIZE_SPEED) ? $conf->global->MAIN_OPTIMIZE_SPEED : 'off');
10508 if (!empty($micro_start_time)) { // Works only if MAIN_SHOW_TUNING_INFO is defined at $_SERVER level. Not in global variable.
10509 $micro_end_time = microtime(true);
10510 print ' - Build time: '.ceil(1000 * ($micro_end_time - $micro_start_time)).' ms';
10511 }
10512
10513 if (function_exists("memory_get_usage")) {
10514 print ' - Mem: '.memory_get_usage(); // Do not use true here, it seems it takes the peak amount
10515 }
10516 if (function_exists("memory_get_peak_usage")) {
10517 print ' - Real mem peak: '.memory_get_peak_usage(true);
10518 }
10519 if (function_exists("zend_loader_file_encoded")) {
10520 print ' - Zend encoded file: '.(zend_loader_file_encoded() ? 'yes' : 'no');
10521 }
10522 print '");'."\n";
10523 }
10524
10525 print "\n".'</script>'."\n";
10526
10527 // Google Analytics
10528 // TODO Add a hook here
10529 if (isModEnabled('google') && getDolGlobalString('MAIN_GOOGLE_AN_ID')) {
10530 $tmptagarray = explode(',', getDolGlobalString('MAIN_GOOGLE_AN_ID'));
10531 foreach ($tmptagarray as $tmptag) {
10532 print "\n";
10533 print "<!-- JS CODE TO ENABLE for google analtics tag -->\n";
10534 print '
10535 <!-- Global site tag (gtag.js) - Google Analytics -->
10536 <script nonce="'.getNonce().'" async src="https://www.googletagmanager.com/gtag/js?id='.trim($tmptag).'"></script>
10537 <script>
10538 window.dataLayer = window.dataLayer || [];
10539 function gtag(){dataLayer.push(arguments);}
10540 gtag(\'js\', new Date());
10541
10542 gtag(\'config\', \''.trim($tmptag).'\');
10543 </script>';
10544 print "\n";
10545 }
10546 }
10547 }
10548
10549 // Add Xdebug coverage of code
10550 if (defined('XDEBUGCOVERAGE')) {
10551 print_r(xdebug_get_code_coverage());
10552 }
10553
10554 // Add DebugBar data
10555 if ($user->hasRight('debugbar', 'read') && is_object($debugbar)) {
10556 $debugbar['time']->stopMeasure('pageaftermaster');
10557 print '<!-- Output debugbar data -->'."\n";
10558 $renderer = $debugbar->getRenderer();
10559 print $debugbar->getRenderer()->render();
10560 } elseif (count($conf->logbuffer)) { // If there is some logs in buffer to show
10561 print "\n";
10562 print "<!-- Start of log output\n";
10563 //print '<div class="hidden">'."\n";
10564 foreach ($conf->logbuffer as $logline) {
10565 print $logline."<br>\n";
10566 }
10567 //print '</div>'."\n";
10568 print "End of log output -->\n";
10569 }
10570 }
10571}
10572
10582function dolExplodeIntoArray($string, $delimiter = ';', $kv = '=')
10583{
10584 if (is_null($string)) {
10585 return array();
10586 }
10587
10588 if (preg_match('/^\[.*\]$/sm', $delimiter) || preg_match('/^\‍(.*\‍)$/sm', $delimiter)) {
10589 // This is a regex string
10590 $newdelimiter = $delimiter;
10591 } else {
10592 // This is a simple string
10593 $newdelimiter = preg_quote($delimiter, '/');
10594 }
10595
10596 if ($a = preg_split('/'.$newdelimiter.'/', $string)) {
10597 $ka = array();
10598 foreach ($a as $s) { // each part
10599 if ($s) {
10600 if ($pos = strpos($s, $kv)) { // key/value delimiter
10601 $ka[trim(substr($s, 0, $pos))] = trim(substr($s, $pos + strlen($kv)));
10602 } else { // key delimiter not found
10603 $ka[] = trim($s);
10604 }
10605 }
10606 }
10607 return $ka;
10608 }
10609
10610 return array();
10611}
10612
10613
10620function dol_set_focus($selector)
10621{
10622 print "\n".'<!-- Set focus onto a specific field -->'."\n";
10623 print '<script nonce="'.getNonce().'">jQuery(document).ready(function() { jQuery("'.dol_escape_js($selector).'").focus(); });</script>'."\n";
10624}
10625
10626
10634function dol_getmypid()
10635{
10636 if (!function_exists('getmypid')) {
10637 return mt_rand(99900000, 99965535);
10638 } else {
10639 return getmypid(); // May be a number on 64 bits (depending on OS)
10640 }
10641}
10642
10643
10661function natural_search($fields, $value, $mode = 0, $nofirstand = 0)
10662{
10663 global $db, $langs;
10664
10665 $value = trim($value);
10666
10667 if ($mode == 0) {
10668 $value = preg_replace('/\*/', '%', $value); // Replace * with %
10669 }
10670 if ($mode == 1) {
10671 $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
10672 }
10673
10674 $value = preg_replace('/\s*\|\s*/', '|', $value);
10675
10676 //natural mode search type 3 allow spaces into search ...
10677 if ($mode == 3 || $mode == -3) {
10678 $crits = explode(',', $value);
10679 } else {
10680 $crits = explode(' ', $value);
10681 }
10682 $res = '';
10683 if (!is_array($fields)) {
10684 $fields = array($fields);
10685 }
10686
10687 $i1 = 0; // count the nb of and criteria added (all fields / criterias)
10688 foreach ($crits as $crit) { // Loop on each AND criteria
10689 $crit = trim($crit);
10690 $i2 = 0; // count the nb of valid criteria added for this this first criteria
10691 $newres = '';
10692 foreach ($fields as $field) {
10693 if ($mode == 1) {
10694 $tmpcrits = explode('|', $crit);
10695 $i3 = 0; // count the nb of valid criteria added for this current field
10696 foreach ($tmpcrits as $tmpcrit) {
10697 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10698 continue;
10699 }
10700 $tmpcrit = trim($tmpcrit);
10701
10702 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10703
10704 $operator = '=';
10705 $newcrit = preg_replace('/([!<>=]+)/', '', $tmpcrit);
10706
10707 $reg = array();
10708 preg_match('/([!<>=]+)/', $tmpcrit, $reg);
10709 if (!empty($reg[1])) {
10710 $operator = $reg[1];
10711 }
10712 if ($newcrit != '') {
10713 $numnewcrit = price2num($newcrit);
10714 if (is_numeric($numnewcrit)) {
10715 $newres .= $field.' '.$operator.' '.((float) $numnewcrit); // should be a numeric
10716 } else {
10717 $newres .= '1 = 2'; // force false, we received a corrupted data
10718 }
10719 $i3++; // a criteria was added to string
10720 }
10721 }
10722 $i2++; // a criteria for 1 more field was added to string
10723 } elseif ($mode == 2 || $mode == -2) {
10724 $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer
10725 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -2 ? 'NOT ' : '');
10726 $newres .= $crit ? "IN (".$db->sanitize($db->escape($crit)).")" : "IN (0)";
10727 if ($mode == -2) {
10728 $newres .= ' OR '.$field.' IS NULL';
10729 }
10730 $i2++; // a criteria for 1 more field was added to string
10731 } elseif ($mode == 3 || $mode == -3) {
10732 $tmparray = explode(',', $crit);
10733 if (count($tmparray)) {
10734 $listofcodes = '';
10735 foreach ($tmparray as $val) {
10736 $val = trim($val);
10737 if ($val) {
10738 $listofcodes .= ($listofcodes ? ',' : '');
10739 $listofcodes .= "'".$db->escape($val)."'";
10740 }
10741 }
10742 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -3 ? 'NOT ' : '')."IN (".$db->sanitize($listofcodes, 1, 0, 1).")";
10743 $i2++; // a criteria for 1 more field was added to string
10744 }
10745 if ($mode == -3) {
10746 $newres .= ' OR '.$field.' IS NULL';
10747 }
10748 } elseif ($mode == 4) {
10749 $tmparray = explode(',', $crit);
10750 if (count($tmparray)) {
10751 $listofcodes = '';
10752 foreach ($tmparray as $val) {
10753 $val = trim($val);
10754 if ($val) {
10755 $newres .= ($i2 > 0 ? " OR (" : "(").$field." LIKE '".$db->escape($val).",%'";
10756 $newres .= ' OR '.$field." = '".$db->escape($val)."'";
10757 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val)."'";
10758 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val).",%'";
10759 $newres .= ')';
10760 $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)
10761 }
10762 }
10763 }
10764 } else { // $mode=0
10765 $tmpcrits = explode('|', $crit);
10766 $i3 = 0; // count the nb of valid criteria added for the current couple criteria/field
10767 foreach ($tmpcrits as $tmpcrit) { // loop on each OR criteria
10768 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10769 continue;
10770 }
10771 $tmpcrit = trim($tmpcrit);
10772
10773 if ($tmpcrit == '^$' || strpos($crit, '!') === 0) { // If we search empty, we must combined different OR fields with AND
10774 $newres .= (($i2 > 0 || $i3 > 0) ? ' AND ' : '');
10775 } else {
10776 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10777 }
10778
10779 if (preg_match('/\.(id|rowid)$/', $field)) { // Special case for rowid that is sometimes a ref so used as a search field
10780 $newres .= $field." = ".(is_numeric($tmpcrit) ? ((float) $tmpcrit) : '0');
10781 } else {
10782 $tmpcrit2 = $tmpcrit;
10783 $tmpbefore = '%';
10784 $tmpafter = '%';
10785 $tmps = '';
10786
10787 if (preg_match('/^!/', $tmpcrit)) {
10788 $tmps .= $field." NOT LIKE "; // ! as exclude character
10789 $tmpcrit2 = preg_replace('/^!/', '', $tmpcrit2);
10790 } else {
10791 $tmps .= $field." LIKE ";
10792 }
10793 $tmps .= "'";
10794
10795 if (preg_match('/^[\^\$]/', $tmpcrit)) {
10796 $tmpbefore = '';
10797 $tmpcrit2 = preg_replace('/^[\^\$]/', '', $tmpcrit2);
10798 }
10799 if (preg_match('/[\^\$]$/', $tmpcrit)) {
10800 $tmpafter = '';
10801 $tmpcrit2 = preg_replace('/[\^\$]$/', '', $tmpcrit2);
10802 }
10803
10804 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10805 $tmps = "(".$tmps;
10806 }
10807 $newres .= $tmps;
10808 $newres .= $tmpbefore;
10809 $newres .= $db->escape($tmpcrit2);
10810 $newres .= $tmpafter;
10811 $newres .= "'";
10812 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10813 $newres .= " OR ".$field." IS NULL)";
10814 }
10815 }
10816
10817 $i3++;
10818 }
10819
10820 $i2++; // a criteria for 1 more field was added to string
10821 }
10822 }
10823
10824 if ($newres) {
10825 $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : '');
10826 }
10827 $i1++;
10828 }
10829 $res = ($nofirstand ? "" : " AND ")."(".$res.")";
10830
10831 return $res;
10832}
10833
10840function showDirectDownloadLink($object)
10841{
10842 global $conf, $langs;
10843
10844 $out = '';
10845 $url = $object->getLastMainDocLink($object->element);
10846
10847 $out .= img_picto($langs->trans("PublicDownloadLinkDesc"), 'globe').' <span class="opacitymedium">'.$langs->trans("DirectDownloadLink").'</span><br>';
10848 if ($url) {
10849 $out .= '<div class="urllink"><input type="text" id="directdownloadlink" class="quatrevingtpercent" value="'.$url.'"></div>';
10850 $out .= ajax_autoselect("directdownloadlink", 0);
10851 } else {
10852 $out .= '<div class="urllink">'.$langs->trans("FileNotShared").'</div>';
10853 }
10854
10855 return $out;
10856}
10857
10866function getImageFileNameForSize($file, $extName, $extImgTarget = '')
10867{
10868 $dirName = dirname($file);
10869 if ($dirName == '.') {
10870 $dirName = '';
10871 }
10872
10873 $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.webp)$/i', '', $file); // We remove extension, whatever is its case
10874 $fileName = basename($fileName);
10875
10876 if (empty($extImgTarget)) {
10877 $extImgTarget = (preg_match('/\.jpg$/i', $file) ? '.jpg' : '');
10878 }
10879 if (empty($extImgTarget)) {
10880 $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '');
10881 }
10882 if (empty($extImgTarget)) {
10883 $extImgTarget = (preg_match('/\.gif$/i', $file) ? '.gif' : '');
10884 }
10885 if (empty($extImgTarget)) {
10886 $extImgTarget = (preg_match('/\.png$/i', $file) ? '.png' : '');
10887 }
10888 if (empty($extImgTarget)) {
10889 $extImgTarget = (preg_match('/\.bmp$/i', $file) ? '.bmp' : '');
10890 }
10891 if (empty($extImgTarget)) {
10892 $extImgTarget = (preg_match('/\.webp$/i', $file) ? '.webp' : '');
10893 }
10894
10895 if (!$extImgTarget) {
10896 return $file;
10897 }
10898
10899 $subdir = '';
10900 if ($extName) {
10901 $subdir = 'thumbs/';
10902 }
10903
10904 return ($dirName ? $dirName.'/' : '').$subdir.$fileName.$extName.$extImgTarget; // New filename for thumb
10905}
10906
10907
10917function getAdvancedPreviewUrl($modulepart, $relativepath, $alldata = 0, $param = '')
10918{
10919 global $conf, $langs;
10920
10921 if (empty($conf->use_javascript_ajax)) {
10922 return '';
10923 }
10924
10925 $isAllowedForPreview = dolIsAllowedForPreview($relativepath);
10926
10927 if ($alldata == 1) {
10928 if ($isAllowedForPreview) {
10929 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));
10930 } else {
10931 return array();
10932 }
10933 }
10934
10935 // old behavior, return a string
10936 if ($isAllowedForPreview) {
10937 $tmpurl = DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : '');
10938
10939 $title = $langs->trans("Preview");
10940 //$title = '%27-alert(document.domain)-%27';
10941 //$tmpurl = 'file='.urlencode("'-alert(document.domain)-'_small.jpg");
10942
10943 // 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.
10944 // and when we click on href with this javascript string, a urlcode is done by browser, converted the %27 of file param
10945 return 'javascript:document_preview(\''.urlencode(dol_escape_js($tmpurl)).'\', \''.urlencode(dol_mimetype($relativepath)).'\', \''.rawurlencode(dol_escape_js($title)).'\')';
10946 } else {
10947 return '';
10948 }
10949}
10950
10951
10960function ajax_autoselect($htmlname, $addlink = '', $textonlink = 'Link')
10961{
10962 global $langs;
10963 $out = '<script nonce="'.getNonce().'">
10964 jQuery(document).ready(function () {
10965 jQuery("'.((strpos($htmlname, '.') === 0 ? '' : '#').$htmlname).'").click(function() { jQuery(this).select(); } );
10966 });
10967 </script>';
10968 if ($addlink) {
10969 if ($textonlink === 'image') {
10970 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.img_picto('', 'globe').'</a>';
10971 } else {
10972 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.$langs->trans("Link").'</a>';
10973 }
10974 }
10975 return $out;
10976}
10977
10985function dolIsAllowedForPreview($file)
10986{
10987 global $conf;
10988
10989 // Check .noexe extension in filename
10990 if (preg_match('/\.noexe$/i', $file)) {
10991 return 0;
10992 }
10993
10994 // Check mime types
10995 $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'webp');
10996 if (getDolGlobalString('MAIN_ALLOW_SVG_FILES_AS_IMAGES')) {
10997 $mime_preview[] = 'svg+xml';
10998 }
10999 //$mime_preview[]='vnd.oasis.opendocument.presentation';
11000 //$mime_preview[]='archive';
11001 $num_mime = array_search(dol_mimetype($file, '', 1), $mime_preview);
11002 if ($num_mime !== false) {
11003 return 1;
11004 }
11005
11006 // By default, not allowed for preview
11007 return 0;
11008}
11009
11010
11020function dol_mimetype($file, $default = 'application/octet-stream', $mode = 0)
11021{
11022 $mime = $default;
11023 $imgmime = 'other.png';
11024 $famime = 'file-o';
11025 $srclang = '';
11026
11027 $tmpfile = preg_replace('/\.noexe$/', '', $file);
11028
11029 // Plain text files
11030 if (preg_match('/\.txt$/i', $tmpfile)) {
11031 $mime = 'text/plain';
11032 $imgmime = 'text.png';
11033 $famime = 'file-alt';
11034 } elseif (preg_match('/\.rtx$/i', $tmpfile)) {
11035 $mime = 'text/richtext';
11036 $imgmime = 'text.png';
11037 $famime = 'file-alt';
11038 } elseif (preg_match('/\.csv$/i', $tmpfile)) {
11039 $mime = 'text/csv';
11040 $imgmime = 'text.png';
11041 $famime = 'file-csv';
11042 } elseif (preg_match('/\.tsv$/i', $tmpfile)) {
11043 $mime = 'text/tab-separated-values';
11044 $imgmime = 'text.png';
11045 $famime = 'file-alt';
11046 } elseif (preg_match('/\.(cf|conf|log)$/i', $tmpfile)) {
11047 $mime = 'text/plain';
11048 $imgmime = 'text.png';
11049 $famime = 'file-alt';
11050 } elseif (preg_match('/\.ini$/i', $tmpfile)) {
11051 $mime = 'text/plain';
11052 $imgmime = 'text.png';
11053 $srclang = 'ini';
11054 $famime = 'file-alt';
11055 } elseif (preg_match('/\.md$/i', $tmpfile)) {
11056 $mime = 'text/plain';
11057 $imgmime = 'text.png';
11058 $srclang = 'md';
11059 $famime = 'file-alt';
11060 } elseif (preg_match('/\.css$/i', $tmpfile)) {
11061 $mime = 'text/css';
11062 $imgmime = 'css.png';
11063 $srclang = 'css';
11064 $famime = 'file-alt';
11065 } elseif (preg_match('/\.lang$/i', $tmpfile)) {
11066 $mime = 'text/plain';
11067 $imgmime = 'text.png';
11068 $srclang = 'lang';
11069 $famime = 'file-alt';
11070 } elseif (preg_match('/\.(crt|cer|key|pub)$/i', $tmpfile)) { // Certificate files
11071 $mime = 'text/plain';
11072 $imgmime = 'text.png';
11073 $famime = 'file-alt';
11074 } elseif (preg_match('/\.(html|htm|shtml)$/i', $tmpfile)) { // XML based (HTML/XML/XAML)
11075 $mime = 'text/html';
11076 $imgmime = 'html.png';
11077 $srclang = 'html';
11078 $famime = 'file-alt';
11079 } elseif (preg_match('/\.(xml|xhtml)$/i', $tmpfile)) {
11080 $mime = 'text/xml';
11081 $imgmime = 'other.png';
11082 $srclang = 'xml';
11083 $famime = 'file-alt';
11084 } elseif (preg_match('/\.xaml$/i', $tmpfile)) {
11085 $mime = 'text/xml';
11086 $imgmime = 'other.png';
11087 $srclang = 'xaml';
11088 $famime = 'file-alt';
11089 } elseif (preg_match('/\.bas$/i', $tmpfile)) { // Languages
11090 $mime = 'text/plain';
11091 $imgmime = 'text.png';
11092 $srclang = 'bas';
11093 $famime = 'file-code';
11094 } elseif (preg_match('/\.(c)$/i', $tmpfile)) {
11095 $mime = 'text/plain';
11096 $imgmime = 'text.png';
11097 $srclang = 'c';
11098 $famime = 'file-code';
11099 } elseif (preg_match('/\.(cpp)$/i', $tmpfile)) {
11100 $mime = 'text/plain';
11101 $imgmime = 'text.png';
11102 $srclang = 'cpp';
11103 $famime = 'file-code';
11104 } elseif (preg_match('/\.cs$/i', $tmpfile)) {
11105 $mime = 'text/plain';
11106 $imgmime = 'text.png';
11107 $srclang = 'cs';
11108 $famime = 'file-code';
11109 } elseif (preg_match('/\.(h)$/i', $tmpfile)) {
11110 $mime = 'text/plain';
11111 $imgmime = 'text.png';
11112 $srclang = 'h';
11113 $famime = 'file-code';
11114 } elseif (preg_match('/\.(java|jsp)$/i', $tmpfile)) {
11115 $mime = 'text/plain';
11116 $imgmime = 'text.png';
11117 $srclang = 'java';
11118 $famime = 'file-code';
11119 } elseif (preg_match('/\.php([0-9]{1})?$/i', $tmpfile)) {
11120 $mime = 'text/plain';
11121 $imgmime = 'php.png';
11122 $srclang = 'php';
11123 $famime = 'file-code';
11124 } elseif (preg_match('/\.phtml$/i', $tmpfile)) {
11125 $mime = 'text/plain';
11126 $imgmime = 'php.png';
11127 $srclang = 'php';
11128 $famime = 'file-code';
11129 } elseif (preg_match('/\.(pl|pm)$/i', $tmpfile)) {
11130 $mime = 'text/plain';
11131 $imgmime = 'pl.png';
11132 $srclang = 'perl';
11133 $famime = 'file-code';
11134 } elseif (preg_match('/\.sql$/i', $tmpfile)) {
11135 $mime = 'text/plain';
11136 $imgmime = 'text.png';
11137 $srclang = 'sql';
11138 $famime = 'file-code';
11139 } elseif (preg_match('/\.js$/i', $tmpfile)) {
11140 $mime = 'text/x-javascript';
11141 $imgmime = 'jscript.png';
11142 $srclang = 'js';
11143 $famime = 'file-code';
11144 } elseif (preg_match('/\.odp$/i', $tmpfile)) { // Open office
11145 $mime = 'application/vnd.oasis.opendocument.presentation';
11146 $imgmime = 'ooffice.png';
11147 $famime = 'file-powerpoint';
11148 } elseif (preg_match('/\.ods$/i', $tmpfile)) {
11149 $mime = 'application/vnd.oasis.opendocument.spreadsheet';
11150 $imgmime = 'ooffice.png';
11151 $famime = 'file-excel';
11152 } elseif (preg_match('/\.odt$/i', $tmpfile)) {
11153 $mime = 'application/vnd.oasis.opendocument.text';
11154 $imgmime = 'ooffice.png';
11155 $famime = 'file-word';
11156 } elseif (preg_match('/\.mdb$/i', $tmpfile)) { // MS Office
11157 $mime = 'application/msaccess';
11158 $imgmime = 'mdb.png';
11159 $famime = 'file';
11160 } elseif (preg_match('/\.doc[xm]?$/i', $tmpfile)) {
11161 $mime = 'application/msword';
11162 $imgmime = 'doc.png';
11163 $famime = 'file-word';
11164 } elseif (preg_match('/\.dot[xm]?$/i', $tmpfile)) {
11165 $mime = 'application/msword';
11166 $imgmime = 'doc.png';
11167 $famime = 'file-word';
11168 } elseif (preg_match('/\.xlt(x)?$/i', $tmpfile)) {
11169 $mime = 'application/vnd.ms-excel';
11170 $imgmime = 'xls.png';
11171 $famime = 'file-excel';
11172 } elseif (preg_match('/\.xla(m)?$/i', $tmpfile)) {
11173 $mime = 'application/vnd.ms-excel';
11174 $imgmime = 'xls.png';
11175 $famime = 'file-excel';
11176 } elseif (preg_match('/\.xls$/i', $tmpfile)) {
11177 $mime = 'application/vnd.ms-excel';
11178 $imgmime = 'xls.png';
11179 $famime = 'file-excel';
11180 } elseif (preg_match('/\.xls[bmx]$/i', $tmpfile)) {
11181 $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
11182 $imgmime = 'xls.png';
11183 $famime = 'file-excel';
11184 } elseif (preg_match('/\.pps[mx]?$/i', $tmpfile)) {
11185 $mime = 'application/vnd.ms-powerpoint';
11186 $imgmime = 'ppt.png';
11187 $famime = 'file-powerpoint';
11188 } elseif (preg_match('/\.ppt[mx]?$/i', $tmpfile)) {
11189 $mime = 'application/x-mspowerpoint';
11190 $imgmime = 'ppt.png';
11191 $famime = 'file-powerpoint';
11192 } elseif (preg_match('/\.pdf$/i', $tmpfile)) { // Other
11193 $mime = 'application/pdf';
11194 $imgmime = 'pdf.png';
11195 $famime = 'file-pdf';
11196 } elseif (preg_match('/\.bat$/i', $tmpfile)) { // Scripts
11197 $mime = 'text/x-bat';
11198 $imgmime = 'script.png';
11199 $srclang = 'dos';
11200 $famime = 'file-code';
11201 } elseif (preg_match('/\.sh$/i', $tmpfile)) {
11202 $mime = 'text/x-sh';
11203 $imgmime = 'script.png';
11204 $srclang = 'bash';
11205 $famime = 'file-code';
11206 } elseif (preg_match('/\.ksh$/i', $tmpfile)) {
11207 $mime = 'text/x-ksh';
11208 $imgmime = 'script.png';
11209 $srclang = 'bash';
11210 $famime = 'file-code';
11211 } elseif (preg_match('/\.bash$/i', $tmpfile)) {
11212 $mime = 'text/x-bash';
11213 $imgmime = 'script.png';
11214 $srclang = 'bash';
11215 $famime = 'file-code';
11216 } elseif (preg_match('/\.ico$/i', $tmpfile)) { // Images
11217 $mime = 'image/x-icon';
11218 $imgmime = 'image.png';
11219 $famime = 'file-image';
11220 } elseif (preg_match('/\.(jpg|jpeg)$/i', $tmpfile)) {
11221 $mime = 'image/jpeg';
11222 $imgmime = 'image.png';
11223 $famime = 'file-image';
11224 } elseif (preg_match('/\.png$/i', $tmpfile)) {
11225 $mime = 'image/png';
11226 $imgmime = 'image.png';
11227 $famime = 'file-image';
11228 } elseif (preg_match('/\.gif$/i', $tmpfile)) {
11229 $mime = 'image/gif';
11230 $imgmime = 'image.png';
11231 $famime = 'file-image';
11232 } elseif (preg_match('/\.bmp$/i', $tmpfile)) {
11233 $mime = 'image/bmp';
11234 $imgmime = 'image.png';
11235 $famime = 'file-image';
11236 } elseif (preg_match('/\.(tif|tiff)$/i', $tmpfile)) {
11237 $mime = 'image/tiff';
11238 $imgmime = 'image.png';
11239 $famime = 'file-image';
11240 } elseif (preg_match('/\.svg$/i', $tmpfile)) {
11241 $mime = 'image/svg+xml';
11242 $imgmime = 'image.png';
11243 $famime = 'file-image';
11244 } elseif (preg_match('/\.webp$/i', $tmpfile)) {
11245 $mime = 'image/webp';
11246 $imgmime = 'image.png';
11247 $famime = 'file-image';
11248 } elseif (preg_match('/\.vcs$/i', $tmpfile)) { // Calendar
11249 $mime = 'text/calendar';
11250 $imgmime = 'other.png';
11251 $famime = 'file-alt';
11252 } elseif (preg_match('/\.ics$/i', $tmpfile)) {
11253 $mime = 'text/calendar';
11254 $imgmime = 'other.png';
11255 $famime = 'file-alt';
11256 } elseif (preg_match('/\.torrent$/i', $tmpfile)) { // Other
11257 $mime = 'application/x-bittorrent';
11258 $imgmime = 'other.png';
11259 $famime = 'file-o';
11260 } elseif (preg_match('/\.(mp3|ogg|au|wav|wma|mid)$/i', $tmpfile)) { // Audio
11261 $mime = 'audio';
11262 $imgmime = 'audio.png';
11263 $famime = 'file-audio';
11264 } elseif (preg_match('/\.mp4$/i', $tmpfile)) { // Video
11265 $mime = 'video/mp4';
11266 $imgmime = 'video.png';
11267 $famime = 'file-video';
11268 } elseif (preg_match('/\.ogv$/i', $tmpfile)) {
11269 $mime = 'video/ogg';
11270 $imgmime = 'video.png';
11271 $famime = 'file-video';
11272 } elseif (preg_match('/\.webm$/i', $tmpfile)) {
11273 $mime = 'video/webm';
11274 $imgmime = 'video.png';
11275 $famime = 'file-video';
11276 } elseif (preg_match('/\.avi$/i', $tmpfile)) {
11277 $mime = 'video/x-msvideo';
11278 $imgmime = 'video.png';
11279 $famime = 'file-video';
11280 } elseif (preg_match('/\.divx$/i', $tmpfile)) {
11281 $mime = 'video/divx';
11282 $imgmime = 'video.png';
11283 $famime = 'file-video';
11284 } elseif (preg_match('/\.xvid$/i', $tmpfile)) {
11285 $mime = 'video/xvid';
11286 $imgmime = 'video.png';
11287 $famime = 'file-video';
11288 } elseif (preg_match('/\.(wmv|mpg|mpeg)$/i', $tmpfile)) {
11289 $mime = 'video';
11290 $imgmime = 'video.png';
11291 $famime = 'file-video';
11292 } elseif (preg_match('/\.(zip|rar|gz|tgz|z|cab|bz2|7z|tar|lzh|zst)$/i', $tmpfile)) { // Archive
11293 // application/xxx where zzz is zip, ...
11294 $mime = 'archive';
11295 $imgmime = 'archive.png';
11296 $famime = 'file-archive';
11297 } elseif (preg_match('/\.(exe|com)$/i', $tmpfile)) { // Exe
11298 $mime = 'application/octet-stream';
11299 $imgmime = 'other.png';
11300 $famime = 'file-o';
11301 } elseif (preg_match('/\.(dll|lib|o|so|a)$/i', $tmpfile)) { // Lib
11302 $mime = 'library';
11303 $imgmime = 'library.png';
11304 $famime = 'file-o';
11305 } elseif (preg_match('/\.err$/i', $tmpfile)) { // phpcs:ignore
11306 $mime = 'error';
11307 $imgmime = 'error.png';
11308 $famime = 'file-alt';
11309 }
11310
11311 // Return mimetype string
11312 switch ((int) $mode) {
11313 case 1:
11314 $tmp = explode('/', $mime);
11315 return (!empty($tmp[1]) ? $tmp[1] : $tmp[0]);
11316 case 2:
11317 return $imgmime;
11318 case 3:
11319 return $srclang;
11320 case 4:
11321 return $famime;
11322 }
11323 return $mime;
11324}
11325
11337function getDictionaryValue($tablename, $field, $id, $checkentity = false, $rowidfield = 'rowid')
11338{
11339 global $conf, $db;
11340
11341 $tablename = preg_replace('/^'.preg_quote(MAIN_DB_PREFIX, '/').'/', '', $tablename); // Clean name of table for backward compatibility.
11342
11343 $dictvalues = (isset($conf->cache['dictvalues_'.$tablename]) ? $conf->cache['dictvalues_'.$tablename] : null);
11344
11345 if (is_null($dictvalues)) {
11346 $dictvalues = array();
11347
11348 $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
11349 if ($checkentity) {
11350 $sql .= ' AND entity IN (0,'.getEntity($tablename).')';
11351 }
11352
11353 $resql = $db->query($sql);
11354 if ($resql) {
11355 while ($obj = $db->fetch_object($resql)) {
11356 $dictvalues[$obj->$rowidfield] = $obj; // $obj is stdClass
11357 }
11358 } else {
11359 dol_print_error($db);
11360 }
11361
11362 $conf->cache['dictvalues_'.$tablename] = $dictvalues;
11363 }
11364
11365 if (!empty($dictvalues[$id])) {
11366 // Found
11367 $tmp = $dictvalues[$id];
11368 return (property_exists($tmp, $field) ? $tmp->$field : '');
11369 } else {
11370 // Not found
11371 return '';
11372 }
11373}
11374
11381function colorIsLight($stringcolor)
11382{
11383 $stringcolor = str_replace('#', '', $stringcolor);
11384 $res = -1;
11385 if (!empty($stringcolor)) {
11386 $res = 0;
11387 $tmp = explode(',', $stringcolor);
11388 if (count($tmp) > 1) { // This is a comma RGB ('255','255','255')
11389 $r = $tmp[0];
11390 $g = $tmp[1];
11391 $b = $tmp[2];
11392 } else {
11393 $hexr = $stringcolor[0].$stringcolor[1];
11394 $hexg = $stringcolor[2].$stringcolor[3];
11395 $hexb = $stringcolor[4].$stringcolor[5];
11396 $r = hexdec($hexr);
11397 $g = hexdec($hexg);
11398 $b = hexdec($hexb);
11399 }
11400 $bright = (max($r, $g, $b) + min($r, $g, $b)) / 510.0; // HSL algorithm
11401 if ($bright > 0.6) {
11402 $res = 1;
11403 }
11404 }
11405 return $res;
11406}
11407
11416function isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
11417{
11418 global $conf;
11419
11420 //print 'type_user='.$type_user.' module='.$menuentry['module'].' enabled='.$menuentry['enabled'].' perms='.$menuentry['perms'];
11421 //print 'ok='.in_array($menuentry['module'], $listofmodulesforexternal);
11422 if (empty($menuentry['enabled'])) {
11423 return 0; // Entry disabled by condition
11424 }
11425 if ($type_user && $menuentry['module']) {
11426 $tmploops = explode('|', $menuentry['module']);
11427 $found = 0;
11428 foreach ($tmploops as $tmploop) {
11429 if (in_array($tmploop, $listofmodulesforexternal)) {
11430 $found++;
11431 break;
11432 }
11433 }
11434 if (!$found) {
11435 return 0; // Entry is for menus all excluded to external users
11436 }
11437 }
11438 if (!$menuentry['perms'] && $type_user) {
11439 return 0; // No permissions and user is external
11440 }
11441 if (!$menuentry['perms'] && getDolGlobalString('MAIN_MENU_HIDE_UNAUTHORIZED')) {
11442 return 0; // No permissions and option to hide when not allowed, even for internal user, is on
11443 }
11444 if (!$menuentry['perms']) {
11445 return 2; // No permissions and user is external
11446 }
11447 return 1;
11448}
11449
11457function roundUpToNextMultiple($n, $x = 5)
11458{
11459 return (ceil($n) % $x === 0) ? ceil($n) : round(($n + $x / 2) / $x) * $x;
11460}
11461
11473function dolGetBadge($label, $html = '', $type = 'primary', $mode = '', $url = '', $params = array())
11474{
11475 $attr = array(
11476 'class'=>'badge '.(!empty($mode) ? ' badge-'.$mode : '').(!empty($type) ? ' badge-'.$type : '').(empty($params['css']) ? '' : ' '.$params['css'])
11477 );
11478
11479 if (empty($html)) {
11480 $html = $label;
11481 }
11482
11483 if (!empty($url)) {
11484 $attr['href'] = $url;
11485 }
11486
11487 if ($mode === 'dot') {
11488 $attr['class'] .= ' classfortooltip';
11489 $attr['title'] = $html;
11490 $attr['aria-label'] = $label;
11491 $html = '';
11492 }
11493
11494 // Override attr
11495 if (!empty($params['attr']) && is_array($params['attr'])) {
11496 foreach ($params['attr'] as $key => $value) {
11497 if ($key == 'class') {
11498 $attr['class'] .= ' '.$value;
11499 } elseif ($key == 'classOverride') {
11500 $attr['class'] = $value;
11501 } else {
11502 $attr[$key] = $value;
11503 }
11504 }
11505 }
11506
11507 // TODO: add hook
11508
11509 // escape all attribute
11510 $attr = array_map('dol_escape_htmltag', $attr);
11511
11512 $TCompiledAttr = array();
11513 foreach ($attr as $key => $value) {
11514 $TCompiledAttr[] = $key.'="'.$value.'"';
11515 }
11516
11517 $compiledAttributes = !empty($TCompiledAttr) ? implode(' ', $TCompiledAttr) : '';
11518
11519 $tag = !empty($url) ? 'a' : 'span';
11520
11521 return '<'.$tag.' '.$compiledAttributes.'>'.$html.'</'.$tag.'>';
11522}
11523
11524
11537function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $statusType = 'status0', $displayMode = 0, $url = '', $params = array())
11538{
11539 global $conf;
11540
11541 $return = '';
11542 $dolGetBadgeParams = array();
11543
11544 if (!empty($params['badgeParams'])) {
11545 $dolGetBadgeParams = $params['badgeParams'];
11546 }
11547
11548 // TODO : add a hook
11549 if ($displayMode == 0) {
11550 $return = !empty($html) ? $html : (empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort));
11551 } elseif ($displayMode == 1) {
11552 $return = !empty($html) ? $html : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11553 } elseif (getDolGlobalString('MAIN_STATUS_USES_IMAGES')) {
11554 // Use status with images (for backward compatibility)
11555 $return = '';
11556 $htmlLabel = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : $statusLabel).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
11557 $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>' : '');
11558
11559 // For small screen, we always use the short label instead of long label.
11560 if (!empty($conf->dol_optimize_smallscreen)) {
11561 if ($displayMode == 0) {
11562 $displayMode = 1;
11563 } elseif ($displayMode == 4) {
11564 $displayMode = 2;
11565 } elseif ($displayMode == 6) {
11566 $displayMode = 5;
11567 }
11568 }
11569
11570 // For backward compatibility. Image's filename are still in French, so we use this array to convert
11571 $statusImg = array(
11572 'status0' => 'statut0',
11573 'status1' => 'statut1',
11574 'status2' => 'statut2',
11575 'status3' => 'statut3',
11576 'status4' => 'statut4',
11577 'status5' => 'statut5',
11578 'status6' => 'statut6',
11579 'status7' => 'statut7',
11580 'status8' => 'statut8',
11581 'status9' => 'statut9'
11582 );
11583
11584 if (!empty($statusImg[$statusType])) {
11585 $htmlImg = img_picto($statusLabel, $statusImg[$statusType]);
11586 } else {
11587 $htmlImg = img_picto($statusLabel, $statusType);
11588 }
11589
11590 if ($displayMode === 2) {
11591 $return = $htmlImg.' '.$htmlLabelShort;
11592 } elseif ($displayMode === 3) {
11593 $return = $htmlImg;
11594 } elseif ($displayMode === 4) {
11595 $return = $htmlImg.' '.$htmlLabel;
11596 } elseif ($displayMode === 5) {
11597 $return = $htmlLabelShort.' '.$htmlImg;
11598 } else { // $displayMode >= 6
11599 $return = $htmlLabel.' '.$htmlImg;
11600 }
11601 } elseif (!getDolGlobalString('MAIN_STATUS_USES_IMAGES') && !empty($displayMode)) {
11602 // Use new badge
11603 $statusLabelShort = (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11604
11605 $dolGetBadgeParams['attr']['class'] = 'badge-status';
11606 $dolGetBadgeParams['attr']['title'] = empty($params['tooltip']) ? $statusLabel : ($params['tooltip'] != 'no' ? $params['tooltip'] : '');
11607
11608 if ($displayMode == 3) {
11609 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), '', $statusType, 'dot', $url, $dolGetBadgeParams);
11610 } elseif ($displayMode === 5) {
11611 $return = dolGetBadge($statusLabelShort, $html, $statusType, '', $url, $dolGetBadgeParams);
11612 } else {
11613 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), $html, $statusType, '', $url, $dolGetBadgeParams);
11614 }
11615 }
11616
11617 return $return;
11618}
11619
11620
11655function dolGetButtonAction($label, $text = '', $actionType = 'default', $url = '', $id = '', $userRight = 1, $params = array())
11656{
11657 global $hookmanager, $action, $object, $langs;
11658
11659 // If $url is an array, we must build a dropdown button
11660 if (is_array($url)) {
11661 // Loop on $url array to remove entries of disabled modules
11662 foreach ($url as $key => $subbutton) {
11663 if (isset($subbutton['enabled']) && empty($subbutton['enabled'])) {
11664 unset($url[$key]);
11665 }
11666 }
11667
11668 $out = '';
11669
11670 if (count($url) > 1) {
11671 $out .= '<div class="dropdown inline-block dropdown-holder">';
11672 $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>';
11673 $out .= '<div class="dropdown-content">';
11674 foreach ($url as $subbutton) {
11675 if (!empty($subbutton['lang'])) {
11676 $langs->load($subbutton['lang']);
11677 }
11678 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
11679 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm'], array('isDropDown' => true));
11680 }
11681 $out .= "</div>";
11682 $out .= "</div>";
11683 } else {
11684 foreach ($url as $subbutton) { // Should loop on 1 record only
11685 if (!empty($subbutton['lang'])) {
11686 $langs->load($subbutton['lang']);
11687 }
11688 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
11689 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm']);
11690 }
11691 }
11692
11693 return $out;
11694 }
11695
11696 // Here, $url is a simple link
11697
11698 if (!empty($params['isDropdown'])) {
11699 $class = "dropdown-item";
11700 } else {
11701 $class = 'butAction';
11702 if ($actionType == 'danger' || $actionType == 'delete') {
11703 $class = 'butActionDelete';
11704 if (!empty($url) && strpos($url, 'token=') === false) {
11705 $url .= '&token='.newToken();
11706 }
11707 }
11708 }
11709 $attr = array(
11710 'class' => $class,
11711 'href' => empty($url) ? '' : $url,
11712 'title' => $label
11713 );
11714
11715 if (empty($text)) {
11716 $text = $label;
11717 $attr['title'] = ''; // if html not set, leave label on title is redundant
11718 } else {
11719 $attr['title'] = $label;
11720 $attr['aria-label'] = $label;
11721 }
11722
11723 if (empty($userRight)) {
11724 $attr['class'] = 'butActionRefused';
11725 $attr['href'] = '';
11726 $attr['title'] = (($label && $text && $label != $text) ? $label : $langs->trans('NotEnoughPermissions'));
11727 }
11728
11729 if (!empty($id)) {
11730 $attr['id'] = $id;
11731 }
11732
11733 // Override attr
11734 if (!empty($params['attr']) && is_array($params['attr'])) {
11735 foreach ($params['attr'] as $key => $value) {
11736 if ($key == 'class') {
11737 $attr['class'] .= ' '.$value;
11738 } elseif ($key == 'classOverride') {
11739 $attr['class'] = $value;
11740 } else {
11741 $attr[$key] = $value;
11742 }
11743 }
11744 }
11745
11746 // automatic add tooltip when title is detected
11747 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
11748 $attr['class'].= ' classfortooltip';
11749 }
11750
11751 // Js Confirm button
11752 if ($userRight && !empty($params['confirm'])) {
11753 if (!is_array($params['confirm'])) {
11754 $params['confirm'] = array();
11755 }
11756
11757 if (empty($params['confirm']['url'])) {
11758 $params['confirm']['url'] = $url . (strpos($url, '?') > 0 ? '&' : '?') . 'confirm=yes';
11759 }
11760
11761 // for js desabled compatibility set $url as call to confirm action and $params['confirm']['url'] to confirmed action
11762 $attr['data-confirm-url'] = $params['confirm']['url'];
11763 $attr['data-confirm-title'] = !empty($params['confirm']['title']) ? $params['confirm']['title'] : $langs->trans('ConfirmBtnCommonTitle', $label);
11764 $attr['data-confirm-content'] = !empty($params['confirm']['content']) ? $params['confirm']['content'] : $langs->trans('ConfirmBtnCommonContent', $label);
11765 $attr['data-confirm-content'] = preg_replace("/\r|\n/", "", $attr['data-confirm-content']);
11766 $attr['data-confirm-action-btn-label'] = !empty($params['confirm']['action-btn-label']) ? $params['confirm']['action-btn-label'] : $langs->trans('Confirm');
11767 $attr['data-confirm-cancel-btn-label'] = !empty($params['confirm']['cancel-btn-label']) ? $params['confirm']['cancel-btn-label'] : $langs->trans('CloseDialog');
11768 $attr['data-confirm-modal'] = !empty($params['confirm']['modal']) ? $params['confirm']['modal'] : true;
11769
11770 $attr['class'].= ' butActionConfirm';
11771 }
11772
11773 if (isset($attr['href']) && empty($attr['href'])) {
11774 unset($attr['href']);
11775 }
11776
11777 // escape all attribute
11778 $attr = array_map('dol_escape_htmltag', $attr);
11779
11780 $TCompiledAttr = array();
11781 foreach ($attr as $key => $value) {
11782 $TCompiledAttr[] = $key.'= "'.$value.'"';
11783 }
11784
11785 $compiledAttributes = empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr);
11786
11787 $tag = !empty($attr['href']) ? 'a' : 'span';
11788
11789
11790 $parameters = array(
11791 'TCompiledAttr' => $TCompiledAttr, // array
11792 'compiledAttributes' => $compiledAttributes, // string
11793 'attr' => $attr,
11794 'tag' => $tag,
11795 'label' => $label,
11796 'html' => $text,
11797 'actionType' => $actionType,
11798 'url' => $url,
11799 'id' => $id,
11800 'userRight' => $userRight,
11801 'params' => $params
11802 );
11803
11804 $reshook = $hookmanager->executeHooks('dolGetButtonAction', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
11805 if ($reshook < 0) {
11806 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
11807 }
11808
11809 if (empty($reshook)) {
11810 if (dol_textishtml($text)) { // If content already HTML encoded
11811 return '<' . $tag . ' ' . $compiledAttributes . '>' . $text . '</' . $tag . '>';
11812 } else {
11813 return '<' . $tag . ' ' . $compiledAttributes . '>' . dol_escape_htmltag($text) . '</' . $tag . '>';
11814 }
11815 } else {
11816 return $hookmanager->resPrint;
11817 }
11818}
11819
11826function dolGetButtonTitleSeparator($moreClass = "")
11827{
11828 return '<span class="button-title-separator '.$moreClass.'" ></span>';
11829}
11830
11837function getFieldErrorIcon($fieldValidationErrorMsg)
11838{
11839 $out = '';
11840 if (!empty($fieldValidationErrorMsg)) {
11841 $out.= '<span class="field-error-icon classfortooltip" title="'.dol_escape_htmltag($fieldValidationErrorMsg, 1).'" role="alert" >'; // role alert is used for accessibility
11842 $out.= '<span class="fa fa-exclamation-circle" aria-hidden="true" ></span>'; // For accessibility icon is separated and aria-hidden
11843 $out.= '</span>';
11844 }
11845
11846 return $out;
11847}
11848
11861function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $url = '', $id = '', $status = 1, $params = array())
11862{
11863 global $langs, $conf, $user;
11864
11865 // Actually this conf is used in css too for external module compatibility and smooth transition to this function
11866 if (getDolGlobalString('MAIN_BUTTON_HIDE_UNAUTHORIZED') && (!$user->admin) && $status <= 0) {
11867 return '';
11868 }
11869
11870 $class = 'btnTitle';
11871 if (in_array($iconClass, array('fa fa-plus-circle', 'fa fa-plus-circle size15x', 'fa fa-comment-dots', 'fa fa-paper-plane'))) {
11872 $class .= ' btnTitlePlus';
11873 }
11874 $useclassfortooltip = 1;
11875
11876 if (!empty($params['morecss'])) {
11877 $class .= ' '.$params['morecss'];
11878 }
11879
11880 $attr = array(
11881 'class' => $class,
11882 'href' => empty($url) ? '' : $url
11883 );
11884
11885 if (!empty($helpText)) {
11886 $attr['title'] = dol_escape_htmltag($helpText);
11887 } elseif (empty($attr['title']) && $label) {
11888 $attr['title'] = $label;
11889 $useclassfortooltip = 0;
11890 }
11891
11892 if ($status == 2) {
11893 $attr['class'] .= ' btnTitleSelected';
11894 } elseif ($status <= 0) {
11895 $attr['class'] .= ' refused';
11896
11897 $attr['href'] = '';
11898
11899 if ($status == -1) { // disable
11900 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("FeatureDisabled"));
11901 } elseif ($status == 0) { // Not enough permissions
11902 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions"));
11903 }
11904 }
11905
11906 if (!empty($attr['title']) && $useclassfortooltip) {
11907 $attr['class'] .= ' classfortooltip';
11908 }
11909
11910 if (!empty($id)) {
11911 $attr['id'] = $id;
11912 }
11913
11914 // Override attr
11915 if (!empty($params['attr']) && is_array($params['attr'])) {
11916 foreach ($params['attr'] as $key => $value) {
11917 if ($key == 'class') {
11918 $attr['class'] .= ' '.$value;
11919 } elseif ($key == 'classOverride') {
11920 $attr['class'] = $value;
11921 } else {
11922 $attr[$key] = $value;
11923 }
11924 }
11925 }
11926
11927 if (isset($attr['href']) && empty($attr['href'])) {
11928 unset($attr['href']);
11929 }
11930
11931 // TODO : add a hook
11932
11933 // escape all attribute
11934 $attr = array_map('dol_escape_htmltag', $attr);
11935
11936 $TCompiledAttr = array();
11937 foreach ($attr as $key => $value) {
11938 $TCompiledAttr[] = $key.'="'.$value.'"';
11939 }
11940
11941 $compiledAttributes = (empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr));
11942
11943 $tag = (empty($attr['href']) ? 'span' : 'a');
11944
11945 $button = '<'.$tag.' '.$compiledAttributes.'>';
11946 $button .= '<span class="'.$iconClass.' valignmiddle btnTitle-icon"></span>';
11947 if (!empty($params['forcenohideoftext'])) {
11948 $button .= '<span class="valignmiddle text-plus-circle btnTitle-label'.(empty($params['forcenohideoftext']) ? ' hideonsmartphone' : '').'">'.$label.'</span>';
11949 }
11950 $button .= '</'.$tag.'>';
11951
11952 return $button;
11953}
11954
11965function getElementProperties($element_type)
11966{
11967 global $conf, $db, $hookmanager;
11968
11969 $regs = array();
11970
11971 //$element_type='facture';
11972
11973 $classfile = $classname = $classpath = $subdir = $dir_output = '';
11974
11975 // Parse element/subelement
11976 $module = $element_type;
11977 $element = $element_type;
11978 $subelement = $element_type;
11979 $table_element = $element_type;
11980
11981 // If we ask a resource form external module (instead of default path)
11982 if (preg_match('/^([^@]+)@([^@]+)$/i', $element_type, $regs)) { // 'myobject@mymodule'
11983 $element = $subelement = $regs[1];
11984 $module = $regs[2];
11985 }
11986
11987 // If we ask a resource for a string with an element and a subelement
11988 // Example 'project_task'
11989 if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { // 'myobject_mysubobject' with myobject=mymodule
11990 $module = $element = $regs[1];
11991 $subelement = $regs[2];
11992 }
11993
11994 // For compatibility and to work with non standard path
11995 if ($element_type == "action" || $element_type == "actioncomm") {
11996 $classpath = 'comm/action/class';
11997 $subelement = 'Actioncomm';
11998 $module = 'agenda';
11999 $table_element = 'actioncomm';
12000 } elseif ($element_type == 'cronjob') {
12001 $classpath = 'cron/class';
12002 $module = 'cron';
12003 $table_element = 'cron';
12004 } elseif ($element_type == 'adherent_type') {
12005 $classpath = 'adherents/class';
12006 $classfile = 'adherent_type';
12007 $module = 'adherent';
12008 $subelement = 'adherent_type';
12009 $classname = 'AdherentType';
12010 $table_element = 'adherent_type';
12011 } elseif ($element_type == 'bank_account') {
12012 $classpath = 'compta/bank/class';
12013 $module = 'bank'; // We need $conf->bank->dir_output and not $conf->banque->dir_output
12014 $classfile = 'account';
12015 $classname = 'Account';
12016 } elseif ($element_type == 'category') {
12017 $classpath = 'categories/class';
12018 $module = 'categorie';
12019 $subelement = 'categorie';
12020 $table_element = 'categorie';
12021 } elseif ($element_type == 'contact') {
12022 $classpath = 'contact/class';
12023 $classfile = 'contact';
12024 $module = 'societe';
12025 $subelement = 'contact';
12026 $table_element = 'socpeople';
12027 } elseif ($element_type == 'inventory') {
12028 $module = 'product';
12029 $classpath = 'product/inventory/class';
12030 } elseif ($element_type == 'stock' || $element_type == 'entrepot') {
12031 $module = 'stock';
12032 $classpath = 'product/stock/class';
12033 $classfile = 'entrepot';
12034 $classname = 'Entrepot';
12035 $table_element = 'entrepot';
12036 } elseif ($element_type == 'project') {
12037 $classpath = 'projet/class';
12038 $module = 'projet';
12039 $table_element = 'projet';
12040 } elseif ($element_type == 'project_task') {
12041 $classpath = 'projet/class';
12042 $module = 'projet';
12043 $subelement = 'task';
12044 $table_element = 'projet_task';
12045 } elseif ($element_type == 'facture' || $element_type == 'invoice') {
12046 $classpath = 'compta/facture/class';
12047 $module = 'facture';
12048 $subelement = 'facture';
12049 $table_element = 'facture';
12050 } elseif ($element_type == 'commande' || $element_type == 'order') {
12051 $classpath = 'commande/class';
12052 $module = 'commande';
12053 $subelement = 'commande';
12054 $table_element = 'commande';
12055 } elseif ($element_type == 'propal') {
12056 $classpath = 'comm/propal/class';
12057 $table_element = 'propal';
12058 } elseif ($element_type == 'shipping') {
12059 $classpath = 'expedition/class';
12060 $classfile = 'expedition';
12061 $classname = 'Expedition';
12062 $module = 'expedition';
12063 $table_element = 'expedition';
12064 } elseif ($element_type == 'supplier_proposal') {
12065 $classpath = 'supplier_proposal/class';
12066 $module = 'supplier_proposal';
12067 $element = 'supplierproposal';
12068 $classfile = 'supplier_proposal';
12069 $subelement = 'supplierproposal';
12070 } elseif ($element_type == 'shipping') {
12071 $classpath = 'expedition/class';
12072 $subelement = 'expedition';
12073 $module = 'expedition_bon';
12074 } elseif ($element_type == 'delivery') {
12075 $classpath = 'delivery/class';
12076 $subelement = 'delivery';
12077 $module = 'expedition';
12078 } elseif ($element_type == 'contract') {
12079 $classpath = 'contrat/class';
12080 $module = 'contrat';
12081 $subelement = 'contrat';
12082 $table_element = 'contract';
12083 } elseif ($element_type == 'mailing') {
12084 $classpath = 'comm/mailing/class';
12085 $module = 'mailing';
12086 $classfile = 'mailing';
12087 $classname = 'Mailing';
12088 $subelement = '';
12089 } elseif ($element_type == 'member') {
12090 $classpath = 'adherents/class';
12091 $module = 'adherent';
12092 $subelement = 'adherent';
12093 $table_element = 'adherent';
12094 } elseif ($element_type == 'usergroup') {
12095 $classpath = 'user/class';
12096 $module = 'user';
12097 } elseif ($element_type == 'mo') {
12098 $classpath = 'mrp/class';
12099 $classfile = 'mo';
12100 $classname = 'Mo';
12101 $module = 'mrp';
12102 $subelement = '';
12103 $table_element = 'mrp_mo';
12104 } elseif ($element_type == 'cabinetmed_cons') {
12105 $classpath = 'cabinetmed/class';
12106 $module = 'cabinetmed';
12107 $subelement = 'cabinetmedcons';
12108 $table_element = 'cabinetmedcons';
12109 } elseif ($element_type == 'fichinter') {
12110 $classpath = 'fichinter/class';
12111 $module = 'ficheinter';
12112 $subelement = 'fichinter';
12113 $table_element = 'fichinter';
12114 } elseif ($element_type == 'dolresource' || $element_type == 'resource') {
12115 $classpath = 'resource/class';
12116 $module = 'resource';
12117 $subelement = 'dolresource';
12118 $table_element = 'resource';
12119 } elseif ($element_type == 'propaldet') {
12120 $classpath = 'comm/propal/class';
12121 $module = 'propal';
12122 $subelement = 'propaleligne';
12123 } elseif ($element_type == 'opensurvey_sondage') {
12124 $classpath = 'opensurvey/class';
12125 $module = 'opensurvey';
12126 $subelement = 'opensurveysondage';
12127 } elseif ($element_type == 'order_supplier') {
12128 $classpath = 'fourn/class';
12129 $module = 'fournisseur';
12130 $classfile = 'fournisseur.commande';
12131 $element = 'order_supplier';
12132 $subelement = '';
12133 $classname = 'CommandeFournisseur';
12134 $table_element = 'commande_fournisseur';
12135 } elseif ($element_type == 'commande_fournisseurdet') {
12136 $classpath = 'fourn/class';
12137 $module = 'fournisseur';
12138 $classfile = 'fournisseur.commande';
12139 $element = 'commande_fournisseurdet';
12140 $subelement = '';
12141 $classname = 'CommandeFournisseurLigne';
12142 $table_element = 'commande_fournisseurdet';
12143 } elseif ($element_type == 'invoice_supplier') {
12144 $classpath = 'fourn/class';
12145 $module = 'fournisseur';
12146 $classfile = 'fournisseur.facture';
12147 $element = 'invoice_supplier';
12148 $subelement = '';
12149 $classname = 'FactureFournisseur';
12150 $table_element = 'facture_fourn';
12151 } elseif ($element_type == "service") {
12152 $classpath = 'product/class';
12153 $subelement = 'product';
12154 $table_element = 'product';
12155 } elseif ($element_type == 'salary') {
12156 $classpath = 'salaries/class';
12157 $module = 'salaries';
12158 } elseif ($element_type == 'payment_salary') {
12159 $classpath = 'salaries/class';
12160 $classfile = 'paymentsalary';
12161 $classname = 'PaymentSalary';
12162 $module = 'salaries';
12163 } elseif ($element_type == 'productlot') {
12164 $module = 'productbatch';
12165 $classpath = 'product/stock/class';
12166 $classfile = 'productlot';
12167 $classname = 'Productlot';
12168 $element = 'productlot';
12169 $subelement = '';
12170 $table_element = 'product_lot';
12171 } elseif ($element_type == 'websitepage') {
12172 $classpath = 'website/class';
12173 $classfile = 'websitepage';
12174 $classname = 'Websitepage';
12175 $module = 'website';
12176 $subelement = 'websitepage';
12177 $table_element = 'website_page';
12178 } elseif ($element_type == 'fiscalyear') {
12179 $classpath = 'core/class';
12180 $module = 'accounting';
12181 $subelement = 'fiscalyear';
12182 } elseif ($element_type == 'chargesociales') {
12183 $classpath = 'compta/sociales/class';
12184 $module = 'tax';
12185 $table_element = 'chargesociales';
12186 } elseif ($element_type == 'tva') {
12187 $classpath = 'compta/tva/class';
12188 $module = 'tax';
12189 $subdir = '/vat';
12190 $table_element = 'tva';
12191 } elseif ($element_type == 'emailsenderprofile') {
12192 $module = '';
12193 $classpath = 'core/class';
12194 $classfile = 'emailsenderprofile';
12195 $classname = 'EmailSenderProfile';
12196 $table_element = 'c_email_senderprofile';
12197 $subelement = '';
12198 } elseif ($element_type == 'ccountry') {
12199 $module = '';
12200 $classpath = 'core/class';
12201 $classfile = 'ccountry';
12202 $classname = 'Ccountry';
12203 $table_element = 'c_country';
12204 $subelement = '';
12205 }
12206
12207 if (empty($classfile)) {
12208 $classfile = strtolower($subelement);
12209 }
12210 if (empty($classname)) {
12211 $classname = ucfirst($subelement);
12212 }
12213 if (empty($classpath)) {
12214 $classpath = $module.'/class';
12215 }
12216
12217 //print 'getElementProperties subdir='.$subdir;
12218
12219 // Set dir_output
12220 if ($module && isset($conf->$module)) { // The generic case
12221 if (!empty($conf->$module->multidir_output[$conf->entity])) {
12222 $dir_output = $conf->$module->multidir_output[$conf->entity];
12223 } elseif (!empty($conf->$module->output[$conf->entity])) {
12224 $dir_output = $conf->$module->output[$conf->entity];
12225 } elseif (!empty($conf->$module->dir_output)) {
12226 $dir_output = $conf->$module->dir_output;
12227 }
12228 }
12229
12230 // Overwrite value for special cases
12231 if ($element == 'order_supplier') {
12232 $dir_output = $conf->fournisseur->commande->dir_output;
12233 } elseif ($element == 'invoice_supplier') {
12234 $dir_output = $conf->fournisseur->facture->dir_output;
12235 }
12236 $dir_output .= $subdir;
12237
12238 $elementProperties = array(
12239 'module' => $module,
12240 'element' => $element,
12241 'table_element' => $table_element,
12242 'subelement' => $subelement,
12243 'classpath' => $classpath,
12244 'classfile' => $classfile,
12245 'classname' => $classname,
12246 'dir_output' => $dir_output
12247 );
12248
12249
12250 // Add hook
12251 if (!is_object($hookmanager)) {
12252 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
12253 $hookmanager = new HookManager($db);
12254 }
12255 $hookmanager->initHooks(array('elementproperties'));
12256
12257
12258 // Hook params
12259 $parameters = array(
12260 'elementType' => $element_type,
12261 'elementProperties' => $elementProperties
12262 );
12263
12264 $reshook = $hookmanager->executeHooks('getElementProperties', $parameters);
12265
12266 if ($reshook) {
12267 $elementProperties = $hookmanager->resArray;
12268 } elseif (!empty($hookmanager->resArray) && is_array($hookmanager->resArray)) { // resArray is always an array but for sécurity against misconfigured external modules
12269 $elementProperties = array_replace($elementProperties, $hookmanager->resArray);
12270 }
12271
12272 // context of elementproperties doesn't need to exist out of this function so delete it to avoid elementproperties context is equal to all
12273 if (($key = array_search('elementproperties', $hookmanager->contextarray)) !== false) {
12274 unset($hookmanager->contextarray[$key]);
12275 }
12276
12277 return $elementProperties;
12278}
12279
12290function fetchObjectByElement($element_id, $element_type, $element_ref = '')
12291{
12292 global $db;
12293
12294 $ret = 0;
12295
12296 $element_prop = getElementProperties($element_type);
12297
12298 if ($element_prop['module'] == 'product' || $element_prop['module'] == 'service') {
12299 // For example, for an extrafield 'product' (shared for both product and service) that is a link to an object,
12300 // this is called with $element_type = 'product' when we need element properties of a service, we must return a product. If we create the
12301 // extrafield for a service, it is not supported and not found when editing the product/service card. So we must keep 'product' for extrafields
12302 // of service and we will return properties of a product.
12303 $ismodenabled = (isModEnabled('product') || isModEnabled('service'));
12304 } else {
12305 $ismodenabled = isModEnabled($element_prop['module']);
12306 }
12307 //var_dump('element_type='.$element_type);
12308 //var_dump($element_prop);
12309 //var_dump($element_prop['module'].' '.$ismodenabled);
12310 if (is_array($element_prop) && (empty($element_prop['module']) || $ismodenabled)) {
12311 dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php');
12312
12313 if (class_exists($element_prop['classname'])) {
12314 $classname = $element_prop['classname'];
12315 $objecttmp = new $classname($db);
12316
12317 if ($element_id > 0 || !empty($element_ref)) {
12318 $ret = $objecttmp->fetch($element_id, $element_ref);
12319 if ($ret >= 0) {
12320 if (empty($objecttmp->module)) {
12321 $objecttmp->module = $element_prop['module'];
12322 }
12323 return $objecttmp;
12324 }
12325 } else {
12326 return $objecttmp; // returned an object without fetch
12327 }
12328 } else {
12329 return -1;
12330 }
12331 }
12332
12333 return $ret;
12334}
12335
12343{
12344 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)) {
12345 return true;
12346 }
12347
12348 return false;
12349}
12350
12358function newToken()
12359{
12360 return empty($_SESSION['newtoken']) ? '' : $_SESSION['newtoken'];
12361}
12362
12371{
12372 return isset($_SESSION['token']) ? $_SESSION['token'] : '';
12373}
12374
12380function getNonce()
12381{
12382 global $conf;
12383
12384 if (empty($conf->cache['nonce'])) {
12385 $conf->cache['nonce'] = dolGetRandomBytes(8);
12386 }
12387
12388 return $conf->cache['nonce'];
12389}
12390
12391
12404function startSimpleTable($header, $link = "", $arguments = "", $emptyRows = 0, $number = -1)
12405{
12406 global $langs;
12407
12408 print '<div class="div-table-responsive-no-min">';
12409 print '<table class="noborder centpercent">';
12410 print '<tr class="liste_titre">';
12411
12412 print $emptyRows < 1 ? '<th>' : '<th colspan="'.($emptyRows + 1).'">';
12413
12414 print $langs->trans($header);
12415
12416 // extra space between the first header and the number
12417 if ($number > -1) {
12418 print ' ';
12419 }
12420
12421 if (!empty($link)) {
12422 if (!empty($arguments)) {
12423 print '<a href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
12424 } else {
12425 print '<a href="'.DOL_URL_ROOT.'/'.$link.'">';
12426 }
12427 }
12428
12429 if ($number > -1) {
12430 print '<span class="badge">'.$number.'</span>';
12431 }
12432
12433 if (!empty($link)) {
12434 print '</a>';
12435 }
12436
12437 print '</th>';
12438
12439 if ($number < 0 && !empty($link)) {
12440 print '<th class="right">';
12441
12442 if (!empty($arguments)) {
12443 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
12444 } else {
12445 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'">';
12446 }
12447
12448 print $langs->trans("FullList");
12449 print '</a>';
12450 print '</th>';
12451 }
12452
12453 print '</tr>';
12454}
12455
12464function finishSimpleTable($addLineBreak = false)
12465{
12466 print '</table>';
12467 print '</div>';
12468
12469 if ($addLineBreak) {
12470 print '<br>';
12471 }
12472}
12473
12485function addSummaryTableLine($tableColumnCount, $num, $nbofloop = 0, $total = 0, $noneWord = "None", $extraRightColumn = false)
12486{
12487 global $langs;
12488
12489 if ($num === 0) {
12490 print '<tr class="oddeven">';
12491 print '<td colspan="'.$tableColumnCount.'"><span class="opacitymedium">'.$langs->trans($noneWord).'</span></td>';
12492 print '</tr>';
12493 return;
12494 }
12495
12496 if ($nbofloop === 0) {
12497 // don't show a summary line
12498 return;
12499 }
12500
12501 if ($num === 0) {
12502 $colspan = $tableColumnCount;
12503 } elseif ($num > $nbofloop) {
12504 $colspan = $tableColumnCount;
12505 } else {
12506 $colspan = $tableColumnCount - 1;
12507 }
12508
12509 if ($extraRightColumn) {
12510 $colspan--;
12511 }
12512
12513 print '<tr class="liste_total">';
12514
12515 if ($nbofloop > 0 && $num > $nbofloop) {
12516 print '<td colspan="'.$colspan.'" class="right">'.$langs->trans("XMoreLines", ($num - $nbofloop)).'</td>';
12517 } else {
12518 print '<td colspan="'.$colspan.'" class="right"> '.$langs->trans("Total").'</td>';
12519 print '<td class="right centpercent">'.price($total).'</td>';
12520 }
12521
12522 if ($extraRightColumn) {
12523 print '<td></td>';
12524 }
12525
12526 print '</tr>';
12527}
12528
12537function readfileLowMemory($fullpath_original_file_osencoded, $method = -1)
12538{
12539 if ($method == -1) {
12540 $method = 0;
12541 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_FREAD')) {
12542 $method = 1;
12543 }
12544 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_STREAM_COPY')) {
12545 $method = 2;
12546 }
12547 }
12548
12549 // Be sure we don't have output buffering enabled to have readfile working correctly
12550 while (ob_get_level()) {
12551 ob_end_flush();
12552 }
12553
12554 // Solution 0
12555 if ($method == 0) {
12556 readfile($fullpath_original_file_osencoded);
12557 } elseif ($method == 1) {
12558 // Solution 1
12559 $handle = fopen($fullpath_original_file_osencoded, "rb");
12560 while (!feof($handle)) {
12561 print fread($handle, 8192);
12562 }
12563 fclose($handle);
12564 } elseif ($method == 2) {
12565 // Solution 2
12566 $handle1 = fopen($fullpath_original_file_osencoded, "rb");
12567 $handle2 = fopen("php://output", "wb");
12568 stream_copy_to_stream($handle1, $handle2);
12569 fclose($handle1);
12570 fclose($handle2);
12571 }
12572}
12573
12583function showValueWithClipboardCPButton($valuetocopy, $showonlyonhover = 1, $texttoshow = '')
12584{
12585 /*
12586 global $conf;
12587
12588 if (!empty($conf->dol_no_mouse_hover)) {
12589 $showonlyonhover = 0;
12590 }*/
12591
12592 $tag = 'span'; // Using div (like any style of type 'block') does not work when using the js copy code.
12593 if ($texttoshow === 'none') {
12594 $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>';
12595 } elseif ($texttoshow) {
12596 $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>';
12597 } else {
12598 $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>';
12599 }
12600
12601 return $result;
12602}
12603
12604
12611function jsonOrUnserialize($stringtodecode)
12612{
12613 $result = json_decode($stringtodecode);
12614 if ($result === null) {
12615 $result = unserialize($stringtodecode);
12616 }
12617
12618 return $result;
12619}
12620
12621
12635function forgeSQLFromUniversalSearchCriteria($filter, &$errorstr = '', $noand = 0, $nopar = 0, $noerror = 0)
12636{
12637 if (empty($filter)) {
12638 return ''; // to avoid the return "AND (())"
12639 }
12640
12641 if (!preg_match('/^\‍(.*\‍)$/', $filter)) { // If $filter does not start and end with ()
12642 $filter = '(' . $filter . ')';
12643 }
12644
12645 $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'
12646
12647 if (!dolCheckFilters($filter, $errorstr)) {
12648 if ($noerror) {
12649 return '1 = 2';
12650 } else {
12651 return 'Filter syntax error - '.$errorstr; // Bad balance of parenthesis, we return an error message or force a SQL not found
12652 }
12653 }
12654
12655 // Test the filter syntax
12656 $t = preg_replace_callback('/'.$regexstring.'/i', 'dolForgeDummyCriteriaCallback', $filter);
12657 $t = str_replace(array('and','or','AND','OR',' '), '', $t); // Remove the only strings allowed between each () criteria
12658 // If the string result contains something else than '()', the syntax was wrong
12659 if (preg_match('/[^\‍(\‍)]/', $t)) {
12660 $errorstr = 'Bad syntax of the search string';
12661 if ($noerror) {
12662 return '1 = 2';
12663 } else {
12664 return 'Filter syntax error - '.$errorstr; // Bad syntax of the search string, we return an error message or force a SQL not found
12665 }
12666 }
12667
12668 return ($noand ? "" : " AND ").($nopar ? "" : '(').preg_replace_callback('/'.$regexstring.'/i', 'dolForgeCriteriaCallback', $filter).($nopar ? "" : ')');
12669}
12670
12678function dolCheckFilters($sqlfilters, &$error = '')
12679{
12680 //$regexstring='\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^:\‍(\‍)]+)\‍)';
12681 //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
12682 $tmp = $sqlfilters;
12683 $i = 0;
12684 $nb = strlen($tmp);
12685 $counter = 0;
12686 while ($i < $nb) {
12687 if ($tmp[$i] == '(') {
12688 $counter++;
12689 }
12690 if ($tmp[$i] == ')') {
12691 $counter--;
12692 }
12693 if ($counter < 0) {
12694 $error = "Wrond balance of parenthesis in sqlfilters=".$sqlfilters;
12695 dol_syslog($error, LOG_WARNING);
12696 return false;
12697 }
12698 $i++;
12699 }
12700 return true;
12701}
12702
12711{
12712 //dol_syslog("Convert matches ".$matches[1]);
12713 if (empty($matches[1])) {
12714 return '';
12715 }
12716 $tmp = explode(':', $matches[1]);
12717 if (count($tmp) < 3) {
12718 return '';
12719 }
12720
12721 return '()'; // An empty criteria
12722}
12723
12733{
12734 global $db;
12735
12736 //dol_syslog("Convert matches ".$matches[1]);
12737 if (empty($matches[1])) {
12738 return '';
12739 }
12740 $tmp = explode(':', $matches[1]);
12741 if (count($tmp) < 3) {
12742 return '';
12743 }
12744
12745 $operand = preg_replace('/[^a-z0-9\._]/i', '', trim($tmp[0]));
12746
12747 $operator = strtoupper(preg_replace('/[^a-z<>!=]/i', '', trim($tmp[1])));
12748
12749 $realOperator = [
12750 'NOTLIKE' => 'NOT LIKE',
12751 'ISNOT' => 'IS NOT',
12752 'NOTIN' => 'NOT IN',
12753 '!=' => '<>',
12754 ];
12755
12756 if (array_key_exists($operator, $realOperator)) {
12757 $operator = $realOperator[$operator];
12758 }
12759
12760
12761 $tmpescaped = $tmp[2];
12762 $regbis = array();
12763
12764 if ($operator == 'IN' || $operator == 'NOT IN') { // IN is allowed for list of ID or code only
12765 //if (!preg_match('/^\‍(.*\‍)$/', $tmpescaped)) {
12766 $tmpescaped2 = '(';
12767 // Explode and sanitize each element in list
12768 $tmpelemarray = explode(',', $tmpescaped);
12769 foreach ($tmpelemarray as $tmpkey => $tmpelem) {
12770 $reg = array();
12771 if (preg_match('/^\'(.*)\'$/', $tmpelem, $reg)) {
12772 $tmpelemarray[$tmpkey] = "'".$db->escape($db->sanitize($reg[1], 1, 1, 1))."'";
12773 } else {
12774 $tmpelemarray[$tmpkey] = $db->escape($db->sanitize($tmpelem, 1, 1, 1));
12775 }
12776 }
12777 $tmpescaped2 .= join(',', $tmpelemarray);
12778 $tmpescaped2 .= ')';
12779
12780 $tmpescaped = $tmpescaped2;
12781 } elseif ($operator == 'LIKE' || $operator == 'NOT LIKE') {
12782 if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12783 $tmpescaped = $regbis[1];
12784 }
12785 //$tmpescaped = "'".$db->escape($db->escapeforlike($regbis[1]))."'";
12786 $tmpescaped = "'".$db->escape($tmpescaped)."'"; // We do not escape the _ and % so the like will works
12787 } elseif (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12788 $tmpescaped = "'".$db->escape($regbis[1])."'";
12789 } else {
12790 if (strtoupper($tmpescaped) == 'NULL') {
12791 $tmpescaped = 'NULL';
12792 } elseif (is_int($tmpescaped)) {
12793 $tmpescaped = (int) $tmpescaped;
12794 } else {
12795 $tmpescaped = (float) $tmpescaped;
12796 }
12797 }
12798
12799 return '('.$db->escape($operand).' '.strtoupper($operator).' '.$tmpescaped.')';
12800}
12801
12802
12812function getTimelineIcon($actionstatic, &$histo, $key)
12813{
12814 global $conf, $langs;
12815
12816 $out = '<!-- timeline icon -->'."\n";
12817 $iconClass = 'fa fa-comments';
12818 $img_picto = '';
12819 $colorClass = '';
12820 $pictoTitle = '';
12821
12822 if ($histo[$key]['percent'] == -1) {
12823 $colorClass = 'timeline-icon-not-applicble';
12824 $pictoTitle = $langs->trans('StatusNotApplicable');
12825 } elseif ($histo[$key]['percent'] == 0) {
12826 $colorClass = 'timeline-icon-todo';
12827 $pictoTitle = $langs->trans('StatusActionToDo').' (0%)';
12828 } elseif ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100) {
12829 $colorClass = 'timeline-icon-in-progress';
12830 $pictoTitle = $langs->trans('StatusActionInProcess').' ('.$histo[$key]['percent'].'%)';
12831 } elseif ($histo[$key]['percent'] >= 100) {
12832 $colorClass = 'timeline-icon-done';
12833 $pictoTitle = $langs->trans('StatusActionDone').' (100%)';
12834 }
12835
12836 if ($actionstatic->code == 'AC_TICKET_CREATE') {
12837 $iconClass = 'fa fa-ticket';
12838 } elseif ($actionstatic->code == 'AC_TICKET_MODIFY') {
12839 $iconClass = 'fa fa-pencilxxx';
12840 } elseif (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12841 $iconClass = 'fa fa-comments';
12842 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12843 $iconClass = 'fa fa-mask';
12844 } elseif (getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
12845 if ($actionstatic->type_picto) {
12846 $img_picto = img_picto('', $actionstatic->type_picto);
12847 } else {
12848 if ($actionstatic->type_code == 'AC_RDV') {
12849 $iconClass = 'fa fa-handshake';
12850 } elseif ($actionstatic->type_code == 'AC_TEL') {
12851 $iconClass = 'fa fa-phone';
12852 } elseif ($actionstatic->type_code == 'AC_FAX') {
12853 $iconClass = 'fa fa-fax';
12854 } elseif ($actionstatic->type_code == 'AC_EMAIL') {
12855 $iconClass = 'fa fa-envelope';
12856 } elseif ($actionstatic->type_code == 'AC_INT') {
12857 $iconClass = 'fa fa-shipping-fast';
12858 } elseif ($actionstatic->type_code == 'AC_OTH_AUTO') {
12859 $iconClass = 'fa fa-robot';
12860 } elseif (!preg_match('/_AUTO/', $actionstatic->type_code)) {
12861 $iconClass = 'fa fa-robot';
12862 }
12863 }
12864 }
12865
12866 $out .= '<i class="'.$iconClass.' '.$colorClass.'" title="'.$pictoTitle.'">'.$img_picto.'</i>'."\n";
12867 return $out;
12868}
12869
12876function getActionCommEcmList($object)
12877{
12878 global $conf, $db;
12879
12880 $documents = array();
12881
12882 $sql = 'SELECT ecm.rowid as id, ecm.src_object_type, ecm.src_object_id, ecm.filepath, ecm.filename';
12883 $sql .= ' FROM '.MAIN_DB_PREFIX.'ecm_files ecm';
12884 $sql .= " WHERE ecm.filepath = 'agenda/".((int) $object->id)."'";
12885 //$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
12886 $sql .= ' ORDER BY ecm.position ASC';
12887
12888 $resql = $db->query($sql);
12889 if ($resql) {
12890 if ($db->num_rows($resql)) {
12891 while ($obj = $db->fetch_object($resql)) {
12892 $documents[$obj->id] = $obj;
12893 }
12894 }
12895 }
12896
12897 return $documents;
12898}
12899
12900
12901
12919function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
12920{
12921 global $user, $conf;
12922 global $form;
12923
12924 global $param, $massactionbutton;
12925
12926 dol_include_once('/comm/action/class/actioncomm.class.php');
12927
12928 // Check parameters
12929 if (!is_object($filterobj) && !is_object($objcon)) {
12930 dol_print_error('', 'BadParameter');
12931 }
12932
12933 $histo = array();
12934 $numaction = 0;
12935 $now = dol_now();
12936
12937 $sortfield_list = explode(',', $sortfield);
12938 $sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent');
12939 $sortfield_new_list = array();
12940 foreach ($sortfield_list as $sortfield_value) {
12941 $sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)];
12942 }
12943 $sortfield_new = implode(',', $sortfield_new_list);
12944
12945 if (isModEnabled('agenda')) {
12946 // Search histo on actioncomm
12947 if (is_object($objcon) && $objcon->id > 0) {
12948 $sql = "SELECT DISTINCT a.id, a.label as label,";
12949 } else {
12950 $sql = "SELECT a.id, a.label as label,";
12951 }
12952 $sql .= " a.datep as dp,";
12953 $sql .= " a.note as message,";
12954 $sql .= " a.datep2 as dp2,";
12955 $sql .= " a.percent as percent, 'action' as type,";
12956 $sql .= " a.fk_element, a.elementtype,";
12957 $sql .= " a.fk_contact,";
12958 $sql .= " a.email_from as msg_from,";
12959 $sql .= " c.code as acode, c.libelle as alabel, c.picto as apicto,";
12960 $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";
12961 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12962 $sql .= ", sp.lastname, sp.firstname";
12963 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12964 $sql .= ", m.lastname, m.firstname";
12965 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12966 $sql .= ", o.ref";
12967 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12968 $sql .= ", o.ref";
12969 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12970 $sql .= ", o.ref";
12971 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12972 $sql .= ", o.ref";
12973 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12974 $sql .= ", o.ref";
12975 }
12976 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
12977 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
12978 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
12979
12980 $force_filter_contact = false;
12981 if (is_object($objcon) && $objcon->id > 0) {
12982 $force_filter_contact = true;
12983 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
12984 $sql .= " AND r.element_type = '".$db->escape($objcon->table_element)."' AND r.fk_element = ".((int) $objcon->id);
12985 }
12986
12987 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12988 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
12989 } elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
12990 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er";
12991 $sql .= " ON er.resource_type = 'dolresource'";
12992 $sql .= " AND er.element_id = a.id";
12993 $sql .= " AND er.resource_id = ".((int) $filterobj->id);
12994 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12995 $sql .= ", ".MAIN_DB_PREFIX."adherent as m";
12996 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12997 $sql .= ", ".MAIN_DB_PREFIX."commande_fournisseur as o";
12998 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12999 $sql .= ", ".MAIN_DB_PREFIX."product as o";
13000 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
13001 $sql .= ", ".MAIN_DB_PREFIX."ticket as o";
13002 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
13003 $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o";
13004 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
13005 $sql .= ", ".MAIN_DB_PREFIX."contrat as o";
13006 }
13007
13008 $sql .= " WHERE a.entity IN (".getEntity('agenda').")";
13009 if ($force_filter_contact === false) {
13010 if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) {
13011 $sql .= " AND a.fk_soc = ".((int) $filterobj->id);
13012 } elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) {
13013 $sql .= " AND a.fk_project = ".((int) $filterobj->id);
13014 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
13015 $sql .= " AND a.fk_element = m.rowid AND a.elementtype = 'member'";
13016 if ($filterobj->id) {
13017 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13018 }
13019 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
13020 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'order_supplier'";
13021 if ($filterobj->id) {
13022 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13023 }
13024 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
13025 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
13026 if ($filterobj->id) {
13027 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13028 }
13029 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
13030 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'ticket'";
13031 if ($filterobj->id) {
13032 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13033 }
13034 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
13035 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'bom'";
13036 if ($filterobj->id) {
13037 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13038 }
13039 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
13040 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'contract'";
13041 if ($filterobj->id) {
13042 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13043 }
13044 }
13045 }
13046
13047 // Condition on actioncode
13048 if (!empty($actioncode)) {
13049 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
13050 if ($actioncode == 'AC_NON_AUTO') {
13051 $sql .= " AND c.type != 'systemauto'";
13052 } elseif ($actioncode == 'AC_ALL_AUTO') {
13053 $sql .= " AND c.type = 'systemauto'";
13054 } else {
13055 if ($actioncode == 'AC_OTH') {
13056 $sql .= " AND c.type != 'systemauto'";
13057 } elseif ($actioncode == 'AC_OTH_AUTO') {
13058 $sql .= " AND c.type = 'systemauto'";
13059 }
13060 }
13061 } else {
13062 if ($actioncode == 'AC_NON_AUTO') {
13063 $sql .= " AND c.type != 'systemauto'";
13064 } elseif ($actioncode == 'AC_ALL_AUTO') {
13065 $sql .= " AND c.type = 'systemauto'";
13066 } else {
13067 $sql .= " AND c.code = '".$db->escape($actioncode)."'";
13068 }
13069 }
13070 }
13071 if ($donetodo == 'todo') {
13072 $sql .= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
13073 } elseif ($donetodo == 'done') {
13074 $sql .= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
13075 }
13076 if (is_array($filters) && $filters['search_agenda_label']) {
13077 $sql .= natural_search('a.label', $filters['search_agenda_label']);
13078 }
13079 }
13080
13081 // Add also event from emailings. TODO This should be replaced by an automatic event ? May be it's too much for very large emailing.
13082 if (isModEnabled('mailing') && !empty($objcon->email)
13083 && (empty($actioncode) || $actioncode == 'AC_OTH_AUTO' || $actioncode == 'AC_EMAILING')) {
13084 $langs->load("mails");
13085
13086 $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";
13087 $sql2 .= ", null as fk_element, '' as elementtype, null as contact_id";
13088 $sql2 .= ", 'AC_EMAILING' as acode, '' as alabel, '' as apicto";
13089 $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
13090 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
13091 $sql2 .= ", '' as lastname, '' as firstname";
13092 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
13093 $sql2 .= ", '' as lastname, '' as firstname";
13094 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
13095 $sql2 .= ", '' as ref";
13096 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
13097 $sql2 .= ", '' as ref";
13098 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
13099 $sql2 .= ", '' as ref";
13100 }
13101 $sql2 .= " FROM ".MAIN_DB_PREFIX."mailing as m, ".MAIN_DB_PREFIX."mailing_cibles as mc, ".MAIN_DB_PREFIX."user as u";
13102 $sql2 .= " WHERE mc.email = '".$db->escape($objcon->email)."'"; // Search is done on email.
13103 $sql2 .= " AND mc.statut = 1";
13104 $sql2 .= " AND u.rowid = m.fk_user_valid";
13105 $sql2 .= " AND mc.fk_mailing=m.rowid";
13106 }
13107
13108 if (!empty($sql) && !empty($sql2)) {
13109 $sql = $sql." UNION ".$sql2;
13110 } elseif (empty($sql) && !empty($sql2)) {
13111 $sql = $sql2;
13112 }
13113
13114 // TODO Add limit in nb of results
13115 if ($sql) { // May not be defined if module Agenda is not enabled and mailing module disabled too
13116 $sql .= $db->order($sortfield_new, $sortorder);
13117
13118 dol_syslog("function.lib::show_actions_messaging", LOG_DEBUG);
13119 $resql = $db->query($sql);
13120 if ($resql) {
13121 $i = 0;
13122 $num = $db->num_rows($resql);
13123
13124 while ($i < $num) {
13125 $obj = $db->fetch_object($resql);
13126
13127 if ($obj->type == 'action') {
13128 $contactaction = new ActionComm($db);
13129 $contactaction->id = $obj->id;
13130 $result = $contactaction->fetchResources();
13131 if ($result < 0) {
13132 dol_print_error($db);
13133 setEventMessage("actions.lib::show_actions_messaging Error fetch ressource", 'errors');
13134 }
13135
13136 //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
13137 //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
13138 $tododone = '';
13139 if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && $obj->dp > $now)) {
13140 $tododone = 'todo';
13141 }
13142
13143 $histo[$numaction] = array(
13144 'type'=>$obj->type,
13145 'tododone'=>$tododone,
13146 'id'=>$obj->id,
13147 'datestart'=>$db->jdate($obj->dp),
13148 'dateend'=>$db->jdate($obj->dp2),
13149 'note'=>$obj->label,
13150 'message'=>$obj->message,
13151 'percent'=>$obj->percent,
13152
13153 'userid'=>$obj->user_id,
13154 'login'=>$obj->user_login,
13155 'userfirstname'=>$obj->user_firstname,
13156 'userlastname'=>$obj->user_lastname,
13157 'userphoto'=>$obj->user_photo,
13158 'msg_from'=>$obj->msg_from,
13159
13160 'contact_id'=>$obj->fk_contact,
13161 'socpeopleassigned' => $contactaction->socpeopleassigned,
13162 'lastname' => (empty($obj->lastname) ? '' : $obj->lastname),
13163 'firstname' => (empty($obj->firstname) ? '' : $obj->firstname),
13164 'fk_element'=>$obj->fk_element,
13165 'elementtype'=>$obj->elementtype,
13166 // Type of event
13167 'acode'=>$obj->acode,
13168 'alabel'=>$obj->alabel,
13169 'libelle'=>$obj->alabel, // deprecated
13170 'apicto'=>$obj->apicto
13171 );
13172 } else {
13173 $histo[$numaction] = array(
13174 'type'=>$obj->type,
13175 'tododone'=>'done',
13176 'id'=>$obj->id,
13177 'datestart'=>$db->jdate($obj->dp),
13178 'dateend'=>$db->jdate($obj->dp2),
13179 'note'=>$obj->label,
13180 'message'=>$obj->message,
13181 'percent'=>$obj->percent,
13182 'acode'=>$obj->acode,
13183
13184 'userid'=>$obj->user_id,
13185 'login'=>$obj->user_login,
13186 'userfirstname'=>$obj->user_firstname,
13187 'userlastname'=>$obj->user_lastname,
13188 'userphoto'=>$obj->user_photo
13189 );
13190 }
13191
13192 $numaction++;
13193 $i++;
13194 }
13195 } else {
13196 dol_print_error($db);
13197 }
13198 }
13199
13200 // Set $out to show events
13201 $out = '';
13202
13203 if (!isModEnabled('agenda')) {
13204 $langs->loadLangs(array("admin", "errors"));
13205 $out = info_admin($langs->trans("WarningModuleXDisabledSoYouMayMissEventHere", $langs->transnoentitiesnoconv("Module2400Name")), 0, 0, 'warning');
13206 }
13207
13208 if (isModEnabled('agenda') || (isModEnabled('mailing') && !empty($objcon->email))) {
13209 $delay_warning = $conf->global->MAIN_DELAY_ACTIONS_TODO * 24 * 60 * 60;
13210
13211 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
13212 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
13213 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
13214 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
13215
13216 $formactions = new FormActions($db);
13217
13218 $actionstatic = new ActionComm($db);
13219 $userstatic = new User($db);
13220 $contactstatic = new Contact($db);
13221 $userGetNomUrlCache = array();
13222 $contactGetNomUrlCache = array();
13223
13224 $out .= '<div class="filters-container" >';
13225 $out .= '<form name="listactionsfilter" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
13226 $out .= '<input type="hidden" name="token" value="'.newToken().'">';
13227
13228 if ($objcon && get_class($objcon) == 'Contact' &&
13229 (is_null($filterobj) || get_class($filterobj) == 'Societe')) {
13230 $out .= '<input type="hidden" name="id" value="'.$objcon->id.'" />';
13231 } else {
13232 $out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
13233 }
13234 if ($filterobj && get_class($filterobj) == 'Societe') {
13235 $out .= '<input type="hidden" name="socid" value="'.$filterobj->id.'" />';
13236 }
13237
13238 $out .= "\n";
13239
13240 $out .= '<div class="div-table-responsive-no-min">';
13241 $out .= '<table class="noborder borderbottom centpercent">';
13242
13243 $out .= '<tr class="liste_titre">';
13244
13245 // Action column
13246 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
13247 $out .= '<th class="liste_titre width50 middle">';
13248 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
13249 $out .= $searchpicto;
13250 $out .= '</th>';
13251 }
13252
13253 $out .= getTitleFieldOfList('Date', 0, $_SERVER["PHP_SELF"], 'a.datep', '', $param, '', $sortfield, $sortorder, '')."\n";
13254
13255 $out .= '<th class="liste_titre"><strong class="hideonsmartphone">'.$langs->trans("Search").' : </strong></th>';
13256 if ($donetodo) {
13257 $out .= '<th class="liste_titre"></th>';
13258 }
13259 $out .= '<th class="liste_titre">';
13260 $out .= '<span class="fas fa-square inline-block fawidth30" style=" color: #ddd;" title="'.$langs->trans("ActionType").'"></span>';
13261 //$out .= img_picto($langs->trans("Type"), 'type');
13262 $out .= $formactions->select_type_actions($actioncode, "actioncode", '', !getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : -1, 0, 0, 1, 'minwidth200imp');
13263 $out .= '</th>';
13264 $out .= '<th class="liste_titre maxwidth100onsmartphone">';
13265 $out .= '<input type="text" class="maxwidth100onsmartphone" name="search_agenda_label" value="'.$filters['search_agenda_label'].'" placeholder="'.$langs->trans("Label").'">';
13266 $out .= '</th>';
13267
13268 // Action column
13269 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
13270 $out .= '<th class="liste_titre width50 middle">';
13271 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
13272 $out .= $searchpicto;
13273 $out .= '</th>';
13274 }
13275
13276 $out .= '</tr>';
13277
13278
13279 $out .= '</table>';
13280
13281 $out .= '</form>';
13282 $out .= '</div>';
13283
13284 $out .= "\n";
13285
13286 $out .= '<ul class="timeline">';
13287
13288 if ($donetodo) {
13289 $tmp = '';
13290 if (get_class($filterobj) == 'Societe') {
13291 $tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&socid='.$filterobj->id.'&status=done">';
13292 }
13293 $tmp .= ($donetodo != 'done' ? $langs->trans("ActionsToDoShort") : '');
13294 $tmp .= ($donetodo != 'done' && $donetodo != 'todo' ? ' / ' : '');
13295 $tmp .= ($donetodo != 'todo' ? $langs->trans("ActionsDoneShort") : '');
13296 //$out.=$langs->trans("ActionsToDoShort").' / '.$langs->trans("ActionsDoneShort");
13297 if (get_class($filterobj) == 'Societe') {
13298 $tmp .= '</a>';
13299 }
13300 $out .= getTitleFieldOfList($tmp);
13301 }
13302
13303 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
13304 $caction = new CActionComm($db);
13305 $arraylist = $caction->liste_array(1, 'code', '', (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : 0), '', 1);
13306
13307 $actualCycleDate = false;
13308
13309 // Loop on each event to show it
13310 foreach ($histo as $key => $value) {
13311 $actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo
13312
13313 $actionstatic->type_picto = $histo[$key]['apicto'];
13314 $actionstatic->type_code = $histo[$key]['acode'];
13315
13316 $labeltype = $actionstatic->type_code;
13317 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') && empty($arraylist[$labeltype])) {
13318 $labeltype = 'AC_OTH';
13319 }
13320 if (!empty($actionstatic->code) && preg_match('/^TICKET_MSG/', $actionstatic->code)) {
13321 $labeltype = $langs->trans("Message");
13322 } else {
13323 if (!empty($arraylist[$labeltype])) {
13324 $labeltype = $arraylist[$labeltype];
13325 }
13326 if ($actionstatic->type_code == 'AC_OTH_AUTO' && ($actionstatic->type_code != $actionstatic->code) && $labeltype && !empty($arraylist[$actionstatic->code])) {
13327 $labeltype .= ' - '.$arraylist[$actionstatic->code]; // Use code in priority on type_code
13328 }
13329 }
13330
13331 $url = DOL_URL_ROOT.'/comm/action/card.php?id='.$histo[$key]['id'];
13332
13333 $tmpa = dol_getdate($histo[$key]['datestart'], false);
13334
13335 if (isset($tmpa['year']) && isset($tmpa['yday']) && $actualCycleDate !== $tmpa['year'].'-'.$tmpa['yday']) {
13336 $actualCycleDate = $tmpa['year'].'-'.$tmpa['yday'];
13337 $out .= '<!-- timeline time label -->';
13338 $out .= '<li class="time-label">';
13339 $out .= '<span class="timeline-badge-date">';
13340 $out .= dol_print_date($histo[$key]['datestart'], 'daytext', 'tzuserrel', $langs);
13341 $out .= '</span>';
13342 $out .= '</li>';
13343 $out .= '<!-- /.timeline-label -->';
13344 }
13345
13346
13347 $out .= '<!-- timeline item -->'."\n";
13348 $out .= '<li class="timeline-code-'.strtolower($actionstatic->code).'">';
13349
13350 //$timelineicon = getTimelineIcon($actionstatic, $histo, $key);
13351 $typeicon = $actionstatic->getTypePicto('pictofixedwidth timeline-icon-not-applicble', $labeltype);
13352 //$out .= $timelineicon;
13353 //var_dump($timelineicon);
13354 $out .= $typeicon;
13355
13356 $out .= '<div class="timeline-item">'."\n";
13357
13358 $out .= '<span class="time timeline-header-action2">';
13359
13360 if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
13361 $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").' ';
13362 $out .= $histo[$key]['id'];
13363 $out .= '</a> ';
13364 } else {
13365 $out .= $actionstatic->getNomUrl(1, -1, 'valignmiddle').' ';
13366 }
13367
13368 if ($user->hasRight('agenda', 'allactions', 'create') ||
13369 (($actionstatic->authorid == $user->id || $actionstatic->userownerid == $user->id) && $user->hasRight('agenda', 'myactions', 'create'))) {
13370 $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).'">';
13371 //$out .= '<i class="fa fa-pencil" title="'.$langs->trans("Modify").'" ></i>';
13372 $out .= img_picto($langs->trans("Modify"), 'edit', 'class="edita"');
13373 $out .= '</a>';
13374 }
13375
13376 $out .= '</span>';
13377
13378 // Date
13379 $out .= '<span class="time"><i class="fa fa-clock-o valignmiddle"></i> <span class="valignmiddle">';
13380 $out .= dol_print_date($histo[$key]['datestart'], 'dayhour', 'tzuserrel');
13381 if ($histo[$key]['dateend'] && $histo[$key]['dateend'] != $histo[$key]['datestart']) {
13382 $tmpa = dol_getdate($histo[$key]['datestart'], true);
13383 $tmpb = dol_getdate($histo[$key]['dateend'], true);
13384 if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
13385 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'hour', 'tzuserrel');
13386 } else {
13387 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'dayhour', 'tzuserrel');
13388 }
13389 }
13390 $late = 0;
13391 if ($histo[$key]['percent'] == 0 && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13392 $late = 1;
13393 }
13394 if ($histo[$key]['percent'] == 0 && !$histo[$key]['datestart'] && $histo[$key]['dateend'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13395 $late = 1;
13396 }
13397 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && $histo[$key]['dateend'] && $histo[$key]['dateend'] < ($now - $delay_warning)) {
13398 $late = 1;
13399 }
13400 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && !$histo[$key]['dateend'] && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13401 $late = 1;
13402 }
13403 if ($late) {
13404 $out .= img_warning($langs->trans("Late")).' ';
13405 }
13406 $out .= "</span></span>\n";
13407
13408 // Ref
13409 $out .= '<h3 class="timeline-header">';
13410
13411 // Author of event
13412 $out .= '<div class="messaging-author inline-block tdoverflowmax150 valignmiddle marginrightonly">';
13413 if ($histo[$key]['userid'] > 0) {
13414 if (!isset($userGetNomUrlCache[$histo[$key]['userid']])) { // is in cache ?
13415 $userstatic->fetch($histo[$key]['userid']);
13416 $userGetNomUrlCache[$histo[$key]['userid']] = $userstatic->getNomUrl(-1, '', 0, 0, 16, 0, 'firstelselast', '');
13417 }
13418 $out .= $userGetNomUrlCache[$histo[$key]['userid']];
13419 } elseif (!empty($histo[$key]['msg_from']) && $actionstatic->code == 'TICKET_MSG') {
13420 if (!isset($contactGetNomUrlCache[$histo[$key]['msg_from']])) {
13421 if ($contactstatic->fetch(0, null, '', $histo[$key]['msg_from']) > 0) {
13422 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $contactstatic->getNomUrl(-1, '', 16);
13423 } else {
13424 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $histo[$key]['msg_from'];
13425 }
13426 }
13427 $out .= $contactGetNomUrlCache[$histo[$key]['msg_from']];
13428 }
13429 $out .= '</div>';
13430
13431 // Title
13432 $out .= ' <div class="messaging-title inline-block">';
13433 //$out .= $actionstatic->getTypePicto();
13434 if (empty($conf->dol_optimize_smallscreen) && $actionstatic->type_code != 'AC_OTH_AUTO') {
13435 $out .= $labeltype.' - ';
13436 }
13437
13438 $libelle = '';
13439 if (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
13440 $out .= $langs->trans('TicketNewMessage');
13441 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
13442 $out .= $langs->trans('TicketNewMessage').' <em>('.$langs->trans('Private').')</em>';
13443 } elseif (isset($histo[$key]['type'])) {
13444 if ($histo[$key]['type'] == 'action') {
13445 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
13446 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : $histo[$key]['alabel']);
13447 $libelle = $histo[$key]['note'];
13448 $actionstatic->id = $histo[$key]['id'];
13449 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13450 } elseif ($histo[$key]['type'] == 'mailing') {
13451 $out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
13452 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
13453 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : 'Send mass mailing');
13454 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13455 } else {
13456 $libelle .= $histo[$key]['note'];
13457 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13458 }
13459 }
13460
13461 if (isset($histo[$key]['elementtype']) && !empty($histo[$key]['fk_element'])) {
13462 if (isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']]) && isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']])) {
13463 $link = $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']];
13464 } else {
13465 if (!isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']])) {
13466 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']] = array();
13467 }
13468 $link = dolGetElementUrl($histo[$key]['fk_element'], $histo[$key]['elementtype'], 1);
13469 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']] = $link;
13470 }
13471 if ($link) {
13472 $out .= ' - '.$link;
13473 }
13474 }
13475
13476 $out .= '</div>';
13477
13478 $out .= '</h3>';
13479
13480 // Message
13481 if (!empty($histo[$key]['message'] && $histo[$key]['message'] != $libelle)
13482 && $actionstatic->code != 'AC_TICKET_CREATE'
13483 && $actionstatic->code != 'AC_TICKET_MODIFY'
13484 ) {
13485 $out .= '<div class="timeline-body wordbreak">';
13486 $truncateLines = getDolGlobalInt('MAIN_TRUNCATE_TIMELINE_MESSAGE', 3);
13487 $truncatedText = dolGetFirstLineOfText($histo[$key]['message'], $truncateLines);
13488 if ($truncateLines > 0 && strlen($histo[$key]['message']) > strlen($truncatedText)) {
13489 $out .= '<div class="readmore-block --closed" >';
13490 $out .= ' <div class="readmore-block__excerpt" >';
13491 $out .= $truncatedText ;
13492 $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>';
13493 $out .= ' </div>';
13494 $out .= ' <div class="readmore-block__full-text" >';
13495 $out .= $histo[$key]['message'];
13496 $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>';
13497 $out .= ' </div>';
13498 $out .= '</div>';
13499 } else {
13500 $out .= $histo[$key]['message'];
13501 }
13502
13503 $out .= '</div>';
13504 }
13505
13506 // Timeline footer
13507 $footer = '';
13508
13509 // Contact for this action
13510 if (isset($histo[$key]['socpeopleassigned']) && is_array($histo[$key]['socpeopleassigned']) && count($histo[$key]['socpeopleassigned']) > 0) {
13511 $contactList = '';
13512 foreach ($histo[$key]['socpeopleassigned'] as $cid => $Tab) {
13513 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
13514 $contact = new Contact($db);
13515 $contact->fetch($cid);
13516 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
13517 } else {
13518 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
13519 }
13520
13521 if ($contact) {
13522 $contactList .= !empty($contactList) ? ', ' : '';
13523 $contactList .= $contact->getNomUrl(1);
13524 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
13525 if (!empty($contact->phone_pro)) {
13526 $contactList .= '('.dol_print_phone($contact->phone_pro).')';
13527 }
13528 }
13529 }
13530 }
13531
13532 $footer .= $langs->trans('ActionOnContact').' : '.$contactList;
13533 } elseif (empty($objcon->id) && isset($histo[$key]['contact_id']) && $histo[$key]['contact_id'] > 0) {
13534 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
13535 $contact = new Contact($db);
13536 $result = $contact->fetch($histo[$key]['contact_id']);
13537 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
13538 } else {
13539 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
13540 }
13541
13542 if ($result > 0) {
13543 $footer .= $contact->getNomUrl(1);
13544 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
13545 if (!empty($contact->phone_pro)) {
13546 $footer .= '('.dol_print_phone($contact->phone_pro).')';
13547 }
13548 }
13549 }
13550 }
13551
13552 $documents = getActionCommEcmList($actionstatic);
13553 if (!empty($documents)) {
13554 $footer .= '<div class="timeline-documents-container">';
13555 foreach ($documents as $doc) {
13556 $footer .= '<span id="document_'.$doc->id.'" class="timeline-documents" ';
13557 $footer .= ' data-id="'.$doc->id.'" ';
13558 $footer .= ' data-path="'.$doc->filepath.'"';
13559 $footer .= ' data-filename="'.dol_escape_htmltag($doc->filename).'" ';
13560 $footer .= '>';
13561
13562 $filePath = DOL_DATA_ROOT.'/'.$doc->filepath.'/'.$doc->filename;
13563 $mime = dol_mimetype($filePath);
13564 $file = $actionstatic->id.'/'.$doc->filename;
13565 $thumb = $actionstatic->id.'/thumbs/'.substr($doc->filename, 0, strrpos($doc->filename, '.')).'_mini'.substr($doc->filename, strrpos($doc->filename, '.'));
13566 $doclink = dol_buildpath('document.php', 1).'?modulepart=actions&attachment=0&file='.urlencode($file).'&entity='.$conf->entity;
13567 $viewlink = dol_buildpath('viewimage.php', 1).'?modulepart=actions&file='.urlencode($thumb).'&entity='.$conf->entity;
13568
13569 $mimeAttr = ' mime="'.$mime.'" ';
13570 $class = '';
13571 if (in_array($mime, array('image/png', 'image/jpeg', 'application/pdf'))) {
13572 $class .= ' documentpreview';
13573 }
13574
13575 $footer .= '<a href="'.$doclink.'" class="btn-link '.$class.'" target="_blank" rel="noopener noreferrer" '.$mimeAttr.' >';
13576 $footer .= img_mime($filePath).' '.$doc->filename;
13577 $footer .= '</a>';
13578
13579 $footer .= '</span>';
13580 }
13581 $footer .= '</div>';
13582 }
13583
13584 if (!empty($footer)) {
13585 $out .= '<div class="timeline-footer">'.$footer.'</div>';
13586 }
13587
13588 $out .= '</div>'."\n"; // end timeline-item
13589
13590 $out .= '</li>';
13591 $out .= '<!-- END timeline item -->';
13592
13593 $i++;
13594 }
13595
13596 $out .= "</ul>\n";
13597
13598 $out .= '<script>
13599 jQuery(document).ready(function () {
13600 $(document).on("click", "[data-read-more-action]", function(e){
13601 let readMoreBloc = $(this).closest(".readmore-block");
13602 if(readMoreBloc.length > 0){
13603 e.preventDefault();
13604 if($(this).attr("data-read-more-action") == "close"){
13605 readMoreBloc.addClass("--closed").removeClass("--open");
13606 $("html, body").animate({
13607 scrollTop: readMoreBloc.offset().top - 200
13608 }, 100);
13609 }else{
13610 readMoreBloc.addClass("--open").removeClass("--closed");
13611 }
13612 }
13613 });
13614 });
13615 </script>';
13616
13617
13618 if (empty($histo)) {
13619 $out .= '<span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span>';
13620 }
13621 }
13622
13623 if ($noprint) {
13624 return $out;
13625 } else {
13626 print $out;
13627 }
13628}
13629
13640function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto')
13641{
13642 if ($hourTime === 'getpost') {
13643 $hour = GETPOSTINT($prefix . 'hour');
13644 $minute = GETPOSTINT($prefix . 'minute');
13645 $second = GETPOSTINT($prefix . 'second');
13646 } elseif (preg_match('/^(\d\d):(\d\d):(\d\d)$/', $hourTime, $m)) {
13647 $hour = intval($m[1]);
13648 $minute = intval($m[2]);
13649 $second = intval($m[3]);
13650 } else {
13651 $hour = $minute = $second = 0;
13652 }
13653 // normalize out of range values
13654 $hour = min($hour, 23);
13655 $minute = min($minute, 59);
13656 $second = min($second, 59);
13657 return dol_mktime($hour, $minute, $second, GETPOSTINT($prefix . 'month'), GETPOSTINT($prefix . 'day'), GETPOSTINT($prefix . 'year'), $gm);
13658}
13659
13671function buildParamDate($prefix, $timestamp = null, $hourTime = '', $gm = 'auto')
13672{
13673 if ($timestamp === null) {
13674 $timestamp = GETPOSTDATE($prefix, $hourTime, $gm);
13675 }
13676 $TParam = array(
13677 $prefix . 'day' => intval(dol_print_date($timestamp, '%d')),
13678 $prefix . 'month' => intval(dol_print_date($timestamp, '%m')),
13679 $prefix . 'year' => intval(dol_print_date($timestamp, '%Y')),
13680 );
13681 if ($hourTime === 'getpost' || ($timestamp !== null && dol_print_date($timestamp, '%H:%M:%S') !== '00:00:00')) {
13682 $TParam = array_merge($TParam, array(
13683 $prefix . 'hour' => intval(dol_print_date($timestamp, '%H')),
13684 $prefix . 'minute' => intval(dol_print_date($timestamp, '%M')),
13685 $prefix . 'second' => intval(dol_print_date($timestamp, '%S'))
13686 ));
13687 }
13688
13689 return '&' . http_build_query($TParam);
13690}
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:717
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:513
dol_get_next_day($day, $month, $year)
Return next day.
Definition date.lib.php:498
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:86
dol_get_prev_day($day, $month, $year)
Return previous day.
Definition date.lib.php:482
dol_get_next_month($month, $year)
Return next month.
Definition date.lib.php:532
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.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='', $useCache=true)
Return an id or code from a code or id.
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_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.
dol_escape_all($stringtoescape)
Returns text escaped for all protocols (so only alpha chars and numbers)
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:1948
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