dolibarr 19.0.3
functions.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2000-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2003 Jean-Louis Bergamo <jlb@j1b.org>
4 * Copyright (C) 2004-2022 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
7 * Copyright (C) 2004 Christophe Combelles <ccomb@free.fr>
8 * Copyright (C) 2005-2019 Regis Houssin <regis.houssin@inodbox.com>
9 * Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr>
10 * Copyright (C) 2010-2018 Juanjo Menent <jmenent@2byte.es>
11 * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
12 * Copyright (C) 2013-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
13 * Copyright (C) 2014 Cédric GROSS <c.gross@kreiz-it.fr>
14 * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
15 * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
16 * Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
17 * Copyright (C) 2019-2023 Thibault Foucart <support@ptibogxiv.net>
18 * Copyright (C) 2020 Open-Dsi <support@open-dsi.fr>
19 * Copyright (C) 2021 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
20 * Copyright (C) 2022 Anthony Berton <anthony.berton@bb2a.fr>
21 * Copyright (C) 2022 Ferran Marcet <fmarcet@2byte.es>
22 * Copyright (C) 2022 Charlene Benke <charlene@patas-monkey.com>
23 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 3 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program. If not, see <https://www.gnu.org/licenses/>.
37 * or see https://www.gnu.org/
38 */
39
46include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
47
48// Function for better PHP x compatibility
49if (!function_exists('utf8_encode')) {
56 function utf8_encode($elements)
57 {
58 return mb_convert_encoding($elements, 'UTF-8', 'ISO-8859-1');
59 }
60}
61
62if (!function_exists('utf8_decode')) {
69 function utf8_decode($elements)
70 {
71 return mb_convert_encoding($elements, 'ISO-8859-1', 'UTF-8');
72 }
73}
74if (!function_exists('str_starts_with')) {
82 function str_starts_with($haystack, $needle)
83 {
84 return (string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0;
85 }
86}
87if (!function_exists('str_ends_with')) {
95 function str_ends_with($haystack, $needle)
96 {
97 return $needle !== '' && substr($haystack, -strlen($needle)) === (string) $needle;
98 }
99}
100if (!function_exists('str_contains')) {
108 function str_contains($haystack, $needle)
109 {
110 return $needle !== '' && mb_strpos($haystack, $needle) !== false;
111 }
112}
113
114
123function getMultidirOutput($object, $module = '')
124{
125 global $conf;
126
127 if (!is_object($object) && empty($module)) {
128 return null;
129 }
130 if (empty($module) && !empty($object->element)) {
131 $module = $object->element;
132 }
133 // Special case for backward compatibility
134 if ($module == 'fichinter') {
135 $module = 'ficheinter';
136 }
137 if (isset($conf->$module) && property_exists($conf->$module, 'multidir_output')) {
138 return $conf->$module->multidir_output[(empty($object->entity) ? $conf->entity : $object->entity)];
139 } else {
140 return 'error-diroutput-not-defined-for-this-object='.$module;
141 }
142}
143
151function getDolGlobalString($key, $default = '')
152{
153 global $conf;
154 return (string) (isset($conf->global->$key) ? $conf->global->$key : $default);
155}
156
165function getDolGlobalInt($key, $default = 0)
166{
167 global $conf;
168 return (int) (isset($conf->global->$key) ? $conf->global->$key : $default);
169}
170
179function getDolUserString($key, $default = '', $tmpuser = null)
180{
181 if (empty($tmpuser)) {
182 global $user;
183 $tmpuser = $user;
184 }
185
186 return (string) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
187}
188
197function getDolUserInt($key, $default = 0, $tmpuser = null)
198{
199 if (empty($tmpuser)) {
200 global $user;
201 $tmpuser = $user;
202 }
203
204 return (int) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
205}
206
213function isModEnabled($module)
214{
215 global $conf;
216
217 // Fix special cases
218 $arrayconv = array(
219 'bank' => 'banque',
220 'category' => 'categorie',
221 'contract' => 'contrat',
222 'project' => 'projet',
223 'delivery_note' => 'expedition'
224 );
225 if (!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD')) {
226 $arrayconv['supplier_order'] = 'fournisseur';
227 $arrayconv['supplier_invoice'] = 'fournisseur';
228 }
229 if (!empty($arrayconv[$module])) {
230 $module = $arrayconv[$module];
231 }
232
233 return !empty($conf->modules[$module]);
234 //return !empty($conf->$module->enabled);
235}
236
248function getDoliDBInstance($type, $host, $user, $pass, $name, $port)
249{
250 require_once DOL_DOCUMENT_ROOT."/core/db/".$type.'.class.php';
251
252 $class = 'DoliDB'.ucfirst($type);
253 $dolidb = new $class($type, $host, $user, $pass, $name, $port);
254 return $dolidb;
255}
256
274function getEntity($element, $shared = 1, $currentobject = null)
275{
276 global $conf, $mc, $hookmanager, $object, $action, $db;
277
278 if (!is_object($hookmanager)) {
279 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
280 $hookmanager = new HookManager($db);
281 }
282
283 // fix different element names (France to English)
284 switch ($element) {
285 case 'projet':
286 $element = 'project';
287 break;
288 case 'contrat':
289 $element = 'contract';
290 break; // "/contrat/class/contrat.class.php"
291 case 'order_supplier':
292 $element = 'supplier_order';
293 break; // "/fourn/class/fournisseur.commande.class.php"
294 case 'invoice_supplier':
295 $element = 'supplier_invoice';
296 break; // "/fourn/class/fournisseur.facture.class.php"
297 }
298
299 if (is_object($mc)) {
300 $out = $mc->getEntity($element, $shared, $currentobject);
301 } else {
302 $out = '';
303 $addzero = array('user', 'usergroup', 'cronjob', 'c_email_templates', 'email_template', 'default_values', 'overwrite_trans');
304 if (in_array($element, $addzero)) {
305 $out .= '0,';
306 }
307 $out .= ((int) $conf->entity);
308 }
309
310 // Manipulate entities to query on the fly
311 $parameters = array(
312 'element' => $element,
313 'shared' => $shared,
314 'object' => $object,
315 'currentobject' => $currentobject,
316 'out' => $out
317 );
318 $reshook = $hookmanager->executeHooks('hookGetEntity', $parameters, $currentobject, $action); // Note that $action and $object may have been modified by some hooks
319
320 if (is_numeric($reshook)) {
321 if ($reshook == 0 && !empty($hookmanager->resPrint)) {
322 $out .= ','.$hookmanager->resPrint; // add
323 } elseif ($reshook == 1) {
324 $out = $hookmanager->resPrint; // replace
325 }
326 }
327
328 return $out;
329}
330
337function setEntity($currentobject)
338{
339 global $conf, $mc;
340
341 if (is_object($mc) && method_exists($mc, 'setEntity')) {
342 return $mc->setEntity($currentobject);
343 } else {
344 return ((is_object($currentobject) && $currentobject->id > 0 && $currentobject->entity > 0) ? $currentobject->entity : $conf->entity);
345 }
346}
347
354function isASecretKey($keyname)
355{
356 return preg_match('/(_pass|password|_pw|_key|securekey|serverkey|secret\d?|p12key|exportkey|_PW_[a-z]+|token)$/i', $keyname);
357}
358
359
366function num2Alpha($n)
367{
368 for ($r = ""; $n >= 0; $n = intval($n / 26) - 1) {
369 $r = chr($n % 26 + 0x41) . $r;
370 }
371 return $r;
372}
373
374
391function getBrowserInfo($user_agent)
392{
393 include_once DOL_DOCUMENT_ROOT.'/includes/mobiledetect/mobiledetectlib/Mobile_Detect.php';
394
395 $name = 'unknown';
396 $version = '';
397 $os = 'unknown';
398 $phone = '';
399
400 $user_agent = substr($user_agent, 0, 512); // Avoid to process too large user agent
401
402 $detectmobile = new Mobile_Detect(null, $user_agent);
403 $tablet = $detectmobile->isTablet();
404
405 if ($detectmobile->isMobile()) {
406 $phone = 'unknown';
407
408 // If phone/smartphone, we set phone os name.
409 if ($detectmobile->is('AndroidOS')) {
410 $os = $phone = 'android';
411 } elseif ($detectmobile->is('BlackBerryOS')) {
412 $os = $phone = 'blackberry';
413 } elseif ($detectmobile->is('iOS')) {
414 $os = 'ios';
415 $phone = 'iphone';
416 } elseif ($detectmobile->is('PalmOS')) {
417 $os = $phone = 'palm';
418 } elseif ($detectmobile->is('SymbianOS')) {
419 $os = 'symbian';
420 } elseif ($detectmobile->is('webOS')) {
421 $os = 'webos';
422 } elseif ($detectmobile->is('MaemoOS')) {
423 $os = 'maemo';
424 } elseif ($detectmobile->is('WindowsMobileOS') || $detectmobile->is('WindowsPhoneOS')) {
425 $os = 'windows';
426 }
427 }
428
429 // OS
430 if (preg_match('/linux/i', $user_agent)) {
431 $os = 'linux';
432 } elseif (preg_match('/macintosh/i', $user_agent)) {
433 $os = 'macintosh';
434 } elseif (preg_match('/windows/i', $user_agent)) {
435 $os = 'windows';
436 }
437
438 // Name
439 $reg = array();
440 if (preg_match('/firefox(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
441 $name = 'firefox';
442 $version = empty($reg[2]) ? '' : $reg[2];
443 } elseif (preg_match('/edge(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
444 $name = 'edge';
445 $version = empty($reg[2]) ? '' : $reg[2];
446 } elseif (preg_match('/chrome(\/|\s)([\d\.]+)/i', $user_agent, $reg)) {
447 $name = 'chrome';
448 $version = empty($reg[2]) ? '' : $reg[2];
449 } elseif (preg_match('/chrome/i', $user_agent, $reg)) {
450 // we can have 'chrome (Mozilla...) chrome x.y' in one string
451 $name = 'chrome';
452 } elseif (preg_match('/iceweasel/i', $user_agent)) {
453 $name = 'iceweasel';
454 } elseif (preg_match('/epiphany/i', $user_agent)) {
455 $name = 'epiphany';
456 } elseif (preg_match('/safari(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
457 $name = 'safari';
458 $version = empty($reg[2]) ? '' : $reg[2];
459 } elseif (preg_match('/opera(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
460 // Safari is often present in string for mobile but its not.
461 $name = 'opera';
462 $version = empty($reg[2]) ? '' : $reg[2];
463 } elseif (preg_match('/(MSIE\s([0-9]+\.[0-9]))|.*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
464 $name = 'ie';
465 $version = end($reg);
466 } elseif (preg_match('/(Windows NT\s([0-9]+\.[0-9])).*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
467 // MS products at end
468 $name = 'ie';
469 $version = end($reg);
470 } elseif (preg_match('/l[iy]n(x|ks)(\‍(|\/|\s)*([\d\.]+)/i', $user_agent, $reg)) {
471 // MS products at end
472 $name = 'lynxlinks';
473 $version = empty($reg[3]) ? '' : $reg[3];
474 }
475
476 if ($tablet) {
477 $layout = 'tablet';
478 } elseif ($phone) {
479 $layout = 'phone';
480 } else {
481 $layout = 'classic';
482 }
483
484 return array(
485 'browsername' => $name,
486 'browserversion' => $version,
487 'browseros' => $os,
488 'browserua' => $user_agent,
489 'layout' => $layout, // tablet, phone, classic
490 'phone' => $phone, // deprecated
491 'tablet' => $tablet // deprecated
492 );
493}
494
500function dol_shutdown()
501{
502 global $db;
503 $disconnectdone = false;
504 $depth = 0;
505 if (is_object($db) && !empty($db->connected)) {
506 $depth = $db->transaction_opened;
507 $disconnectdone = $db->close();
508 }
509 dol_syslog("--- End access to ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]).(($disconnectdone && $depth) ? ' (Warn: db disconnection forced, transaction depth was '.$depth.')' : ''), (($disconnectdone && $depth) ? LOG_WARNING : LOG_INFO));
510}
511
521function GETPOSTISSET($paramname)
522{
523 $isset = false;
524
525 $relativepathstring = $_SERVER["PHP_SELF"];
526 // Clean $relativepathstring
527 if (constant('DOL_URL_ROOT')) {
528 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
529 }
530 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
531 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
532 //var_dump($relativepathstring);
533 //var_dump($user->default_values);
534
535 // Code for search criteria persistence.
536 // Retrieve values if restore_lastsearch_values
537 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
538 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
539 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
540 if (is_array($tmp)) {
541 foreach ($tmp as $key => $val) {
542 if ($key == $paramname) { // We are on the requested parameter
543 $isset = true;
544 break;
545 }
546 }
547 }
548 }
549 // If there is saved contextpage, limit, page or mode
550 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
551 $isset = true;
552 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
553 $isset = true;
554 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
555 $isset = true;
556 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
557 $isset = true;
558 }
559 } else {
560 $isset = (isset($_POST[$paramname]) || isset($_GET[$paramname])); // We must keep $_POST and $_GET here
561 }
562
563 return $isset;
564}
565
574function GETPOSTISARRAY($paramname, $method = 0)
575{
576 // for $method test need return the same $val as GETPOST
577 if (empty($method)) {
578 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
579 } elseif ($method == 1) {
580 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
581 } elseif ($method == 2) {
582 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
583 } elseif ($method == 3) {
584 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
585 } else {
586 $val = 'BadFirstParameterForGETPOST';
587 }
588
589 return is_array($val);
590}
591
621function GETPOST($paramname, $check = 'alphanohtml', $method = 0, $filter = null, $options = null, $noreplace = 0)
622{
623 global $mysoc, $user, $conf;
624
625 if (empty($paramname)) {
626 return 'BadFirstParameterForGETPOST';
627 }
628 if (empty($check)) {
629 dol_syslog("Deprecated use of GETPOST, called with 1st param = ".$paramname." and a 2nd param that is '', when calling page ".$_SERVER["PHP_SELF"], LOG_WARNING);
630 // Enable this line to know who call the GETPOST with '' $check parameter.
631 //var_dump(debug_backtrace()[0]);
632 }
633
634 if (empty($method)) {
635 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
636 } elseif ($method == 1) {
637 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
638 } elseif ($method == 2) {
639 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
640 } elseif ($method == 3) {
641 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
642 } else {
643 return 'BadThirdParameterForGETPOST';
644 }
645
646 if (empty($method) || $method == 3 || $method == 4) {
647 $relativepathstring = (empty($_SERVER["PHP_SELF"]) ? '' : $_SERVER["PHP_SELF"]);
648 // Clean $relativepathstring
649 if (constant('DOL_URL_ROOT')) {
650 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
651 }
652 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
653 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
654 //var_dump($relativepathstring);
655 //var_dump($user->default_values);
656
657 // Code for search criteria persistence.
658 // Retrieve saved values if restore_lastsearch_values is set
659 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
660 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
661 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
662 if (is_array($tmp)) {
663 foreach ($tmp as $key => $val) {
664 if ($key == $paramname) { // We are on the requested parameter
665 $out = $val;
666 break;
667 }
668 }
669 }
670 }
671 // If there is saved contextpage, page or limit
672 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
673 $out = $_SESSION['lastsearch_contextpage_'.$relativepathstring];
674 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
675 $out = $_SESSION['lastsearch_limit_'.$relativepathstring];
676 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
677 $out = $_SESSION['lastsearch_page_'.$relativepathstring];
678 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
679 $out = $_SESSION['lastsearch_mode_'.$relativepathstring];
680 }
681 } elseif (!isset($_GET['sortfield'])) {
682 // Else, retrieve default values if we are not doing a sort
683 // If we did a click on a field to sort, we do no apply default values. Same if option MAIN_ENABLE_DEFAULT_VALUES is not set
684 if (!empty($_GET['action']) && $_GET['action'] == 'create' && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
685 // Search default value from $object->field
686 global $object;
687 if (is_object($object) && isset($object->fields[$paramname]['default'])) {
688 $out = $object->fields[$paramname]['default'];
689 }
690 }
691 if (getDolGlobalString('MAIN_ENABLE_DEFAULT_VALUES')) {
692 if (!empty($_GET['action']) && (preg_match('/^create/', $_GET['action']) || preg_match('/^presend/', $_GET['action'])) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
693 // Now search in setup to overwrite default values
694 if (!empty($user->default_values)) { // $user->default_values defined from menu 'Setup - Default values'
695 if (isset($user->default_values[$relativepathstring]['createform'])) {
696 foreach ($user->default_values[$relativepathstring]['createform'] as $defkey => $defval) {
697 $qualified = 0;
698 if ($defkey != '_noquery_') {
699 $tmpqueryarraytohave = explode('&', $defkey);
700 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
701 $foundintru = 0;
702 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
703 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
704 $foundintru = 1;
705 }
706 }
707 if (!$foundintru) {
708 $qualified = 1;
709 }
710 //var_dump($defkey.'-'.$qualified);
711 } else {
712 $qualified = 1;
713 }
714
715 if ($qualified) {
716 if (isset($user->default_values[$relativepathstring]['createform'][$defkey][$paramname])) {
717 $out = $user->default_values[$relativepathstring]['createform'][$defkey][$paramname];
718 break;
719 }
720 }
721 }
722 }
723 }
724 } elseif (!empty($paramname) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
725 // Management of default search_filters and sort order
726 if (!empty($user->default_values)) {
727 // $user->default_values defined from menu 'Setup - Default values'
728 //var_dump($user->default_values[$relativepathstring]);
729 if ($paramname == 'sortfield' || $paramname == 'sortorder') {
730 // Sorted on which fields ? ASC or DESC ?
731 if (isset($user->default_values[$relativepathstring]['sortorder'])) {
732 // Even if paramname is sortfield, data are stored into ['sortorder...']
733 foreach ($user->default_values[$relativepathstring]['sortorder'] as $defkey => $defval) {
734 $qualified = 0;
735 if ($defkey != '_noquery_') {
736 $tmpqueryarraytohave = explode('&', $defkey);
737 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
738 $foundintru = 0;
739 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
740 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
741 $foundintru = 1;
742 }
743 }
744 if (!$foundintru) {
745 $qualified = 1;
746 }
747 //var_dump($defkey.'-'.$qualified);
748 } else {
749 $qualified = 1;
750 }
751
752 if ($qualified) {
753 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
754 foreach ($user->default_values[$relativepathstring]['sortorder'][$defkey] as $key => $val) {
755 if ($out) {
756 $out .= ', ';
757 }
758 if ($paramname == 'sortfield') {
759 $out .= dol_string_nospecial($key, '', $forbidden_chars_to_replace);
760 }
761 if ($paramname == 'sortorder') {
762 $out .= dol_string_nospecial($val, '', $forbidden_chars_to_replace);
763 }
764 }
765 //break; // No break for sortfield and sortorder so we can cumulate fields (is it realy usefull ?)
766 }
767 }
768 }
769 } elseif (isset($user->default_values[$relativepathstring]['filters'])) {
770 foreach ($user->default_values[$relativepathstring]['filters'] as $defkey => $defval) { // $defkey is a querystring like 'a=b&c=d', $defval is key of user
771 if (!empty($_GET['disabledefaultvalues'])) { // If set of default values has been disabled by a request parameter
772 continue;
773 }
774 $qualified = 0;
775 if ($defkey != '_noquery_') {
776 $tmpqueryarraytohave = explode('&', $defkey);
777 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
778 $foundintru = 0;
779 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
780 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
781 $foundintru = 1;
782 }
783 }
784 if (!$foundintru) {
785 $qualified = 1;
786 }
787 //var_dump($defkey.'-'.$qualified);
788 } else {
789 $qualified = 1;
790 }
791
792 if ($qualified && isset($user->default_values[$relativepathstring]['filters'][$defkey][$paramname])) {
793 // We must keep $_POST and $_GET here
794 if (isset($_POST['sall']) || isset($_POST['search_all']) || isset($_GET['sall']) || isset($_GET['search_all'])) {
795 // We made a search from quick search menu, do we still use default filter ?
796 if (!getDolGlobalString('MAIN_DISABLE_DEFAULT_FILTER_FOR_QUICK_SEARCH')) {
797 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
798 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
799 }
800 } else {
801 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
802 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
803 }
804 break;
805 }
806 }
807 }
808 }
809 }
810 }
811 }
812 }
813
814 // Substitution variables for GETPOST (used to get final url with variable parameters or final default value, when using variable parameters __XXX__ in the GET URL)
815 // Example of variables: __DAY__, __MONTH__, __YEAR__, __MYCOMPANY_COUNTRY_ID__, __USER_ID__, ...
816 // We do this only if var is a GET. If it is a POST, may be we want to post the text with vars as the setup text.
817 if (!is_array($out) && empty($_POST[$paramname]) && empty($noreplace)) {
818 $reg = array();
819 $maxloop = 20;
820 $loopnb = 0; // Protection against infinite loop
821 while (preg_match('/__([A-Z0-9]+_?[A-Z0-9]+)__/i', $out, $reg) && ($loopnb < $maxloop)) { // Detect '__ABCDEF__' as key 'ABCDEF' and '__ABC_DEF__' as key 'ABC_DEF'. Detection is also correct when 2 vars are side by side.
822 $loopnb++;
823 $newout = '';
824
825 if ($reg[1] == 'DAY') {
826 $tmp = dol_getdate(dol_now(), true);
827 $newout = $tmp['mday'];
828 } elseif ($reg[1] == 'MONTH') {
829 $tmp = dol_getdate(dol_now(), true);
830 $newout = $tmp['mon'];
831 } elseif ($reg[1] == 'YEAR') {
832 $tmp = dol_getdate(dol_now(), true);
833 $newout = $tmp['year'];
834 } elseif ($reg[1] == 'PREVIOUS_DAY') {
835 $tmp = dol_getdate(dol_now(), true);
836 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
837 $newout = $tmp2['day'];
838 } elseif ($reg[1] == 'PREVIOUS_MONTH') {
839 $tmp = dol_getdate(dol_now(), true);
840 $tmp2 = dol_get_prev_month($tmp['mon'], $tmp['year']);
841 $newout = $tmp2['month'];
842 } elseif ($reg[1] == 'PREVIOUS_YEAR') {
843 $tmp = dol_getdate(dol_now(), true);
844 $newout = ($tmp['year'] - 1);
845 } elseif ($reg[1] == 'NEXT_DAY') {
846 $tmp = dol_getdate(dol_now(), true);
847 $tmp2 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
848 $newout = $tmp2['day'];
849 } elseif ($reg[1] == 'NEXT_MONTH') {
850 $tmp = dol_getdate(dol_now(), true);
851 $tmp2 = dol_get_next_month($tmp['mon'], $tmp['year']);
852 $newout = $tmp2['month'];
853 } elseif ($reg[1] == 'NEXT_YEAR') {
854 $tmp = dol_getdate(dol_now(), true);
855 $newout = ($tmp['year'] + 1);
856 } elseif ($reg[1] == 'MYCOMPANY_COUNTRY_ID' || $reg[1] == 'MYCOUNTRY_ID' || $reg[1] == 'MYCOUNTRYID') {
857 $newout = $mysoc->country_id;
858 } elseif ($reg[1] == 'USER_ID' || $reg[1] == 'USERID') {
859 $newout = $user->id;
860 } elseif ($reg[1] == 'USER_SUPERVISOR_ID' || $reg[1] == 'SUPERVISOR_ID' || $reg[1] == 'SUPERVISORID') {
861 $newout = $user->fk_user;
862 } elseif ($reg[1] == 'ENTITY_ID' || $reg[1] == 'ENTITYID') {
863 $newout = $conf->entity;
864 } else {
865 $newout = ''; // Key not found, we replace with empty string
866 }
867 //var_dump('__'.$reg[1].'__ -> '.$newout);
868 $out = preg_replace('/__'.preg_quote($reg[1], '/').'__/', $newout, $out);
869 }
870 }
871
872 // Check type of variable and make sanitization according to this
873 if (preg_match('/^array/', $check)) { // If 'array' or 'array:restricthtml' or 'array:aZ09' or 'array:intcomma'
874 if (!is_array($out) || empty($out)) {
875 $out = array();
876 } else {
877 $tmparray = explode(':', $check);
878 if (!empty($tmparray[1])) {
879 $tmpcheck = $tmparray[1];
880 } else {
881 $tmpcheck = 'alphanohtml';
882 }
883 foreach ($out as $outkey => $outval) {
884 $out[$outkey] = sanitizeVal($outval, $tmpcheck, $filter, $options);
885 }
886 }
887 } else {
888 // If field name is 'search_xxx' then we force the add of space after each < and > (when following char is numeric) because it means
889 // we use the < or > to make a search on a numeric value to do higher or lower so we can add a space to break html tags
890 if (strpos($paramname, 'search_') === 0) {
891 $out = preg_replace('/([<>])([-+]?\d)/', '\1 \2', $out);
892 }
893
894 $out = sanitizeVal($out, $check, $filter, $options);
895 }
896
897 // Sanitizing for special parameters.
898 // Note: There is no reason to allow the backtopage, backtolist or backtourl parameter to contains an external URL. Only relative URLs are allowed.
899 if ($paramname == 'backtopage' || $paramname == 'backtolist' || $paramname == 'backtourl') {
900 $out = str_replace('\\', '/', $out); // Can be before the loop because only 1 char is replaced. No risk to get it after other replacements.
901 $out = str_replace(array(':', ';', '@', "\t", ' '), '', $out); // Can be before the loop because only 1 char is replaced. No risk to retreive it after other replacements.
902 do {
903 $oldstringtoclean = $out;
904 $out = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $out);
905 $out = preg_replace(array('/^[^\?]*%/'), '', $out); // We remove any % chars before the ?. Example in url: '/product/stock/card.php?action=create&backtopage=%2Fdolibarr_dev%2Fhtdocs%2Fpro%25duct%2Fcard.php%3Fid%3Dabc'
906 $out = preg_replace(array('/^[a-z]*\/\s*\/+/i'), '', $out); // We remove schema*// to remove external URL
907 } while ($oldstringtoclean != $out);
908 }
909
910 // Code for search criteria persistence.
911 // Save data into session if key start with 'search_' or is 'smonth', 'syear', 'month', 'year'
912 if (empty($method) || $method == 3 || $method == 4) {
913 if (preg_match('/^search_/', $paramname) || in_array($paramname, array('sortorder', 'sortfield'))) {
914 //var_dump($paramname.' - '.$out.' '.$user->default_values[$relativepathstring]['filters'][$paramname]);
915
916 // We save search key only if $out not empty that means:
917 // - posted value not empty, or
918 // - if posted value is empty and a default value exists that is not empty (it means we did a filter to an empty value when default was not).
919
920 if ($out != '' && isset($user)) {// $out = '0' or 'abc', it is a search criteria to keep
921 $user->lastsearch_values_tmp[$relativepathstring][$paramname] = $out;
922 }
923 }
924 }
925
926 return $out;
927}
928
938function GETPOSTINT($paramname, $method = 0)
939{
940 return (int) GETPOST($paramname, 'int', $method, null, null, 0);
941}
942
943
954function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
955{
956 return sanitizeVal($out, $check, $filter, $options);
957}
958
968function sanitizeVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
969{
970 // TODO : use class "Validate" to perform tests (and add missing tests) if needed for factorize
971 // Check is done after replacement
972 switch ($check) {
973 case 'none':
974 break;
975 case 'int': // Check param is a numeric value (integer but also float or hexadecimal)
976 if (!is_numeric($out)) {
977 $out = '';
978 }
979 break;
980 case 'intcomma':
981 if (is_array($out)) {
982 $out = implode(',', $out);
983 }
984 if (preg_match('/[^0-9,-]+/i', $out)) {
985 $out = '';
986 }
987 break;
988 case 'san_alpha':
989 $out = filter_var($out, FILTER_SANITIZE_STRING);
990 break;
991 case 'email':
992 $out = filter_var($out, FILTER_SANITIZE_EMAIL);
993 break;
994 case 'aZ':
995 if (!is_array($out)) {
996 $out = trim($out);
997 if (preg_match('/[^a-z]+/i', $out)) {
998 $out = '';
999 }
1000 }
1001 break;
1002 case 'aZ09':
1003 if (!is_array($out)) {
1004 $out = trim($out);
1005 if (preg_match('/[^a-z0-9_\-\.]+/i', $out)) {
1006 $out = '';
1007 }
1008 }
1009 break;
1010 case 'aZ09arobase': // great to sanitize $objecttype parameter
1011 if (!is_array($out)) {
1012 $out = trim($out);
1013 if (preg_match('/[^a-z0-9_\-\.@]+/i', $out)) {
1014 $out = '';
1015 }
1016 }
1017 break;
1018 case 'aZ09comma': // great to sanitize $sortfield or $sortorder params that can be 't.abc,t.def_gh'
1019 if (!is_array($out)) {
1020 $out = trim($out);
1021 if (preg_match('/[^a-z0-9_\-\.,]+/i', $out)) {
1022 $out = '';
1023 }
1024 }
1025 break;
1026 case 'alpha': // No html and no ../ and "
1027 case 'alphanohtml': // Recommended for most scalar parameters and search parameters
1028 if (!is_array($out)) {
1029 $out = trim($out);
1030 do {
1031 $oldstringtoclean = $out;
1032 // Remove html tags
1033 $out = dol_string_nohtmltag($out, 0);
1034 // Remove also other dangerous string sequences
1035 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1036 // '../' or '..\' is dangerous because it allows dir transversals
1037 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1038 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1039 } while ($oldstringtoclean != $out);
1040 // keep lines feed
1041 }
1042 break;
1043 case 'alphawithlgt': // No " and no ../ but we keep balanced < > tags with no special chars inside. Can be used for email string like "Name <email>". Less secured than 'alphanohtml'
1044 if (!is_array($out)) {
1045 $out = trim($out);
1046 do {
1047 $oldstringtoclean = $out;
1048 // Remove html tags
1049 $out = dol_html_entity_decode($out, ENT_COMPAT | ENT_HTML5, 'UTF-8');
1050 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1051 // '../' or '..\' is dangerous because it allows dir transversals
1052 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1053 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1054 } while ($oldstringtoclean != $out);
1055 }
1056 break;
1057 case 'nohtml': // No html
1058 $out = dol_string_nohtmltag($out, 0);
1059 break;
1060 case 'restricthtmlnolink':
1061 case 'restricthtml': // Recommended for most html textarea
1062 case 'restricthtmlallowclass':
1063 case 'restricthtmlallowunvalid':
1064 $out = dol_htmlwithnojs($out, 1, $check);
1065 break;
1066 case 'custom':
1067 if (!empty($out)) {
1068 if (empty($filter)) {
1069 return 'BadParameterForGETPOST - Param 3 of sanitizeVal()';
1070 }
1071 /*if (empty($options)) {
1072 return 'BadParameterForGETPOST - Param 4 of sanitizeVal()';
1073 }*/
1074 $out = filter_var($out, $filter, $options);
1075 }
1076 break;
1077 default:
1078 dol_syslog("Error, you call sanitizeVal() with a bad value for the check type. Data can't be sanitized.", LOG_ERR);
1079 break;
1080 }
1081
1082 return $out;
1083}
1084
1085
1086if (!function_exists('dol_getprefix')) {
1096 function dol_getprefix($mode = '')
1097 {
1098 // If prefix is for email (we need to have $conf already loaded for this case)
1099 if ($mode == 'email') {
1100 global $conf;
1101
1102 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID')) { // If MAIL_PREFIX_FOR_EMAIL_ID is set
1103 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID') != 'SERVER_NAME') {
1104 return $conf->global->MAIL_PREFIX_FOR_EMAIL_ID;
1105 } elseif (isset($_SERVER["SERVER_NAME"])) { // If MAIL_PREFIX_FOR_EMAIL_ID is set to 'SERVER_NAME'
1106 return $_SERVER["SERVER_NAME"];
1107 }
1108 }
1109
1110 // The recommended value if MAIL_PREFIX_FOR_EMAIL_ID is not defined (may be not defined for old versions)
1111 if (!empty($conf->file->instance_unique_id)) {
1112 return sha1('dolibarr'.$conf->file->instance_unique_id);
1113 }
1114
1115 // For backward compatibility when instance_unique_id is not set
1116 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1117 }
1118
1119 // If prefix is for session (no need to have $conf loaded)
1120 global $dolibarr_main_instance_unique_id, $dolibarr_main_cookie_cryptkey; // This is loaded by filefunc.inc.php
1121 $tmp_instance_unique_id = empty($dolibarr_main_instance_unique_id) ? (empty($dolibarr_main_cookie_cryptkey) ? '' : $dolibarr_main_cookie_cryptkey) : $dolibarr_main_instance_unique_id; // Unique id of instance
1122
1123 // The recommended value (may be not defined for old versions)
1124 if (!empty($tmp_instance_unique_id)) {
1125 return sha1('dolibarr'.$tmp_instance_unique_id);
1126 }
1127
1128 // For backward compatibility when instance_unique_id is not set
1129 if (isset($_SERVER["SERVER_NAME"]) && isset($_SERVER["DOCUMENT_ROOT"])) {
1130 return sha1($_SERVER["SERVER_NAME"].$_SERVER["DOCUMENT_ROOT"].DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1131 } else {
1132 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1133 }
1134 }
1135}
1136
1147function dol_include_once($relpath, $classname = '')
1148{
1149 global $conf, $langs, $user, $mysoc; // Do not remove this. They must be defined for files we include. Other globals var must be retrieved with $GLOBALS['var']
1150
1151 $fullpath = dol_buildpath($relpath);
1152
1153 if (!file_exists($fullpath)) {
1154 dol_syslog('functions::dol_include_once Tried to load unexisting file: '.$relpath, LOG_WARNING);
1155 return false;
1156 }
1157
1158 if (!empty($classname) && !class_exists($classname)) {
1159 return include $fullpath;
1160 } else {
1161 return include_once $fullpath;
1162 }
1163}
1164
1165
1176function dol_buildpath($path, $type = 0, $returnemptyifnotfound = 0)
1177{
1178 global $conf;
1179
1180 $path = preg_replace('/^\//', '', $path);
1181
1182 if (empty($type)) { // For a filesystem path
1183 $res = DOL_DOCUMENT_ROOT.'/'.$path; // Standard default path
1184 if (is_array($conf->file->dol_document_root)) {
1185 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array("main"=>"/home/main/htdocs", "alt0"=>"/home/dirmod/htdocs", ...)
1186 if ($key == 'main') {
1187 continue;
1188 }
1189 // if (@file_exists($dirroot.'/'.$path)) {
1190 if (@file_exists($dirroot.'/'.$path)) { // avoid [php:warn]
1191 $res = $dirroot.'/'.$path;
1192 return $res;
1193 }
1194 }
1195 }
1196 if ($returnemptyifnotfound) {
1197 // Not found into alternate dir
1198 if ($returnemptyifnotfound == 1 || !file_exists($res)) {
1199 return '';
1200 }
1201 }
1202 } else {
1203 // For an url path
1204 // We try to get local path of file on filesystem from url
1205 // Note that trying to know if a file on disk exist by forging path on disk from url
1206 // works only for some web server and some setup. This is bugged when
1207 // using proxy, rewriting, virtual path, etc...
1208 $res = '';
1209 if ($type == 1) {
1210 $res = DOL_URL_ROOT.'/'.$path; // Standard value
1211 }
1212 if ($type == 2) {
1213 $res = DOL_MAIN_URL_ROOT.'/'.$path; // Standard value
1214 }
1215 if ($type == 3) {
1216 $res = DOL_URL_ROOT.'/'.$path;
1217 }
1218
1219 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array(["main"]=>"/home/main/htdocs", ["alt0"]=>"/home/dirmod/htdocs", ...)
1220 if ($key == 'main') {
1221 if ($type == 3) {
1222 /*global $dolibarr_main_url_root;*/
1223
1224 // Define $urlwithroot
1225 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1226 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1227 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1228
1229 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).'/'.$path; // Test on start with http is for old conf syntax
1230 }
1231 continue;
1232 }
1233 $regs = array();
1234 preg_match('/^([^\?]+(\.css\.php|\.css|\.js\.php|\.js|\.png|\.jpg|\.php)?)/i', $path, $regs); // Take part before '?'
1235 if (!empty($regs[1])) {
1236 //print $key.'-'.$dirroot.'/'.$path.'-'.$conf->file->dol_url_root[$type].'<br>'."\n";
1237 //if (file_exists($dirroot.'/'.$regs[1])) {
1238 if (@file_exists($dirroot.'/'.$regs[1])) { // avoid [php:warn]
1239 if ($type == 1) {
1240 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1241 }
1242 if ($type == 2) {
1243 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_MAIN_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1244 }
1245 if ($type == 3) {
1246 /*global $dolibarr_main_url_root;*/
1247
1248 // Define $urlwithroot
1249 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1250 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1251 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1252
1253 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).$conf->file->dol_url_root[$key].'/'.$path; // Test on start with http is for old conf syntax
1254 }
1255 break;
1256 }
1257 }
1258 }
1259 }
1260
1261 return $res;
1262}
1263
1275function dol_clone($object, $native = 0)
1276{
1277 if ($native == 0) {
1278 // deprecated method, use the method with native = 2 instead
1279 $tmpsavdb = null;
1280 if (isset($object->db) && isset($object->db->db) && is_object($object->db->db) && get_class($object->db->db) == 'PgSql\Connection') {
1281 $tmpsavdb = $object->db;
1282 unset($object->db); // Such property can not be serialized with pgsl (when object->db->db = 'PgSql\Connection')
1283 }
1284
1285 $myclone = unserialize(serialize($object)); // serialize then unserialize is a hack to be sure to have a new object for all fields
1286
1287 if (!empty($tmpsavdb)) {
1288 $object->db = $tmpsavdb;
1289 }
1290 } elseif ($native == 2) {
1291 // recommended method to have a full isolated cloned object
1292 $myclone = new stdClass();
1293 $tmparray = get_object_vars($object); // return only public properties
1294
1295 if (is_array($tmparray)) {
1296 foreach ($tmparray as $propertykey => $propertyval) {
1297 if (is_scalar($propertyval) || is_array($propertyval)) {
1298 $myclone->$propertykey = $propertyval;
1299 }
1300 }
1301 }
1302 } else {
1303 $myclone = clone $object; // PHP clone is a shallow copy only, not a real clone, so properties of references will keep the reference (refering to the same target/variable)
1304 }
1305
1306 return $myclone;
1307}
1308
1318function dol_size($size, $type = '')
1319{
1320 global $conf;
1321 if (empty($conf->dol_optimize_smallscreen)) {
1322 return $size;
1323 }
1324 if ($type == 'width' && $size > 250) {
1325 return 250;
1326 } else {
1327 return 10;
1328 }
1329}
1330
1331
1343function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1)
1344{
1345 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1346 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1347 // Char '/' and '\' are file delimiters.
1348 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1349 $filesystem_forbidden_chars = array('<', '>', '/', '\\', '?', '*', '|', '"', ':', '°', '$', ';', '`');
1350 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1351 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1352 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1353 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1354 $tmp = str_replace('..', '', $tmp);
1355 return $tmp;
1356}
1357
1369function dol_sanitizePathName($str, $newstr = '_', $unaccent = 1)
1370{
1371 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1372 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1373 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1374 $filesystem_forbidden_chars = array('<', '>', '?', '*', '|', '"', '°', '$', ';', '`');
1375 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1376 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1377 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1378 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1379 $tmp = str_replace('..', '', $tmp);
1380 return $tmp;
1381}
1382
1390function dol_sanitizeUrl($stringtoclean, $type = 1)
1391{
1392 // We clean string because some hacks try to obfuscate evil strings by inserting non printable chars. Example: 'java(ascci09)scr(ascii00)ipt' is processed like 'javascript' (whatever is place of evil ascii char)
1393 // We should use dol_string_nounprintableascii but function may not be yet loaded/available
1394 $stringtoclean = preg_replace('/[\x00-\x1F\x7F]/u', '', $stringtoclean); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1395 // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: on<!-- -->error=alert(1)
1396 $stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
1397
1398 $stringtoclean = str_replace('\\', '/', $stringtoclean);
1399 if ($type == 1) {
1400 // removing : should disable links to external url like http:aaa)
1401 // removing ';' should disable "named" html entities encode into an url (we should not have this into an url)
1402 $stringtoclean = str_replace(array(':', ';', '@'), '', $stringtoclean);
1403 }
1404
1405 do {
1406 $oldstringtoclean = $stringtoclean;
1407 // removing '&colon' should disable links to external url like http:aaa)
1408 // removing '&#' should disable "numeric" html entities encode into an url (we should not have this into an url)
1409 $stringtoclean = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $stringtoclean);
1410 } while ($oldstringtoclean != $stringtoclean);
1411
1412 if ($type == 1) {
1413 // removing '//' should disable links to external url like //aaa or http//)
1414 $stringtoclean = preg_replace(array('/^[a-z]*\/\/+/i'), '', $stringtoclean);
1415 }
1416
1417 return $stringtoclean;
1418}
1419
1426function dol_sanitizeEmail($stringtoclean)
1427{
1428 do {
1429 $oldstringtoclean = $stringtoclean;
1430 $stringtoclean = str_ireplace(array('"', ':', '[', ']',"\n", "\r", '\\', '\/'), '', $stringtoclean);
1431 } while ($oldstringtoclean != $stringtoclean);
1432
1433 return $stringtoclean;
1434}
1435
1445{
1446 global $conf;
1447
1448 if (is_null($str)) {
1449 return '';
1450 }
1451
1452 if (utf8_check($str)) {
1453 if (extension_loaded('intl') && getDolGlobalString('MAIN_UNACCENT_USE_TRANSLITERATOR')) {
1454 $transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: NFC;', Transliterator::FORWARD);
1455 return $transliterator->transliterate($str);
1456 }
1457 // See http://www.utf8-chartable.de/
1458 $string = rawurlencode($str);
1459 $replacements = array(
1460 '%C3%80' => 'A', '%C3%81' => 'A', '%C3%82' => 'A', '%C3%83' => 'A', '%C3%84' => 'A', '%C3%85' => 'A',
1461 '%C3%87' => 'C',
1462 '%C3%88' => 'E', '%C3%89' => 'E', '%C3%8A' => 'E', '%C3%8B' => 'E',
1463 '%C3%8C' => 'I', '%C3%8D' => 'I', '%C3%8E' => 'I', '%C3%8F' => 'I',
1464 '%C3%91' => 'N',
1465 '%C3%92' => 'O', '%C3%93' => 'O', '%C3%94' => 'O', '%C3%95' => 'O', '%C3%96' => 'O',
1466 '%C5%A0' => 'S',
1467 '%C3%99' => 'U', '%C3%9A' => 'U', '%C3%9B' => 'U', '%C3%9C' => 'U',
1468 '%C3%9D' => 'Y', '%C5%B8' => 'y',
1469 '%C3%A0' => 'a', '%C3%A1' => 'a', '%C3%A2' => 'a', '%C3%A3' => 'a', '%C3%A4' => 'a', '%C3%A5' => 'a',
1470 '%C3%A7' => 'c',
1471 '%C3%A8' => 'e', '%C3%A9' => 'e', '%C3%AA' => 'e', '%C3%AB' => 'e',
1472 '%C3%AC' => 'i', '%C3%AD' => 'i', '%C3%AE' => 'i', '%C3%AF' => 'i',
1473 '%C3%B1' => 'n',
1474 '%C3%B2' => 'o', '%C3%B3' => 'o', '%C3%B4' => 'o', '%C3%B5' => 'o', '%C3%B6' => 'o',
1475 '%C5%A1' => 's',
1476 '%C3%B9' => 'u', '%C3%BA' => 'u', '%C3%BB' => 'u', '%C3%BC' => 'u',
1477 '%C3%BD' => 'y', '%C3%BF' => 'y'
1478 );
1479 $string = strtr($string, $replacements);
1480 return rawurldecode($string);
1481 } else {
1482 // See http://www.ascii-code.com/
1483 $string = strtr(
1484 $str,
1485 "\xC0\xC1\xC2\xC3\xC4\xC5\xC7
1486 \xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1
1487 \xD2\xD3\xD4\xD5\xD8\xD9\xDA\xDB\xDD
1488 \xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB
1489 \xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF8
1490 \xF9\xFA\xFB\xFC\xFD\xFF",
1491 "AAAAAAC
1492 EEEEIIIIDN
1493 OOOOOUUUY
1494 aaaaaaceeee
1495 iiiidnooooo
1496 uuuuyy"
1497 );
1498 $string = strtr($string, array("\xC4"=>"Ae", "\xC6"=>"AE", "\xD6"=>"Oe", "\xDC"=>"Ue", "\xDE"=>"TH", "\xDF"=>"ss", "\xE4"=>"ae", "\xE6"=>"ae", "\xF6"=>"oe", "\xFC"=>"ue", "\xFE"=>"th"));
1499 return $string;
1500 }
1501}
1502
1516function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '', $badcharstoremove = '', $keepspaces = 0)
1517{
1518 $forbidden_chars_to_replace = array("'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=", '°', '$', ';'); // more complete than dol_sanitizeFileName
1519 if (empty($keepspaces)) {
1520 $forbidden_chars_to_replace[] = " ";
1521 }
1522 $forbidden_chars_to_remove = array();
1523 //$forbidden_chars_to_remove=array("(",")");
1524
1525 if (is_array($badcharstoreplace)) {
1526 $forbidden_chars_to_replace = $badcharstoreplace;
1527 }
1528 if (is_array($badcharstoremove)) {
1529 $forbidden_chars_to_remove = $badcharstoremove;
1530 }
1531
1532 return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str));
1533}
1534
1535
1549function dol_string_nounprintableascii($str, $removetabcrlf = 1)
1550{
1551 if ($removetabcrlf) {
1552 return preg_replace('/[\x00-\x1F\x7F]/u', '', $str); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1553 } else {
1554 return preg_replace('/[\x00-\x08\x11-\x12\x14-\x1F\x7F]/u', '', $str); // /u operator should make UTF8 valid characters being ignored so are not included into the replace
1555 }
1556}
1557
1566function dol_escape_js($stringtoescape, $mode = 0, $noescapebackslashn = 0)
1567{
1568 if (is_null($stringtoescape)) {
1569 return '';
1570 }
1571
1572 // escape quotes and backslashes, newlines, etc.
1573 $substitjs = array("&#039;"=>"\\'", "\r"=>'\\r');
1574 //$substitjs['</']='<\/'; // We removed this. Should be useless.
1575 if (empty($noescapebackslashn)) {
1576 $substitjs["\n"] = '\\n';
1577 $substitjs['\\'] = '\\\\';
1578 }
1579 if (empty($mode)) {
1580 $substitjs["'"] = "\\'";
1581 $substitjs['"'] = "\\'";
1582 } elseif ($mode == 1) {
1583 $substitjs["'"] = "\\'";
1584 } elseif ($mode == 2) {
1585 $substitjs['"'] = '\\"';
1586 } elseif ($mode == 3) {
1587 $substitjs["'"] = "\\'";
1588 $substitjs['"'] = "\\\"";
1589 }
1590 return strtr($stringtoescape, $substitjs);
1591}
1592
1599function dol_escape_json($stringtoescape)
1600{
1601 return str_replace('"', '\"', $stringtoescape);
1602}
1603
1611function dol_escape_php($stringtoescape, $stringforquotes = 2)
1612{
1613 if (is_null($stringtoescape)) {
1614 return '';
1615 }
1616
1617 if ($stringforquotes == 2) {
1618 return str_replace('"', "'", $stringtoescape);
1619 }
1620 if ($stringforquotes == 1) {
1621 return str_replace("'", "\'", str_replace('"', "'", $stringtoescape));
1622 }
1623
1624 return 'Bad parameter for stringforquotes in dol_escape_php';
1625}
1626
1633function dol_escape_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 if (!array_key_exists($level, $logLevels)) {
1907 throw new Exception('Incorrect log level');
1908 }
1909 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
1910 return;
1911 }
1912
1913 if (!getDolGlobalString('MAIN_SHOW_PASSWORD_INTO_LOG')) {
1914 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
1915 }
1916
1917 // If adding log inside HTML page is required
1918 if ((!empty($_REQUEST['logtohtml']) && getDolGlobalString('MAIN_ENABLE_LOG_TO_HTML'))
1919 || (is_object($user) && $user->hasRight('debugbar', 'read') && is_object($debugbar))) {
1920 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".$logLevels[$level]." ".$message;
1921 }
1922
1923 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
1924 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
1925 if (getDolGlobalString('MAIN_ENABLE_LOG_INLINE_HTML') && !empty($_GET["log"])) {
1926 print "\n\n<!-- Log start\n";
1927 print dol_escape_htmltag($message)."\n";
1928 print "Log end -->\n";
1929 }
1930
1931 $data = array(
1932 'message' => $message,
1933 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
1934 'level' => $level,
1935 'user' => ((is_object($user) && $user->id) ? $user->login : false),
1936 'ip' => false
1937 );
1938
1939 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
1940 if (!empty($remoteip)) {
1941 $data['ip'] = $remoteip;
1942 // This is when server run behind a reverse proxy
1943 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
1944 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
1945 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
1946 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
1947 }
1948 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
1949 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
1950 $data['ip'] = $_SERVER['SERVER_ADDR'];
1951 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
1952 // 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).
1953 $data['ip'] = $_SERVER['COMPUTERNAME'].(empty($_SERVER['USERNAME']) ? '' : '@'.$_SERVER['USERNAME']);
1954 } elseif (!empty($_SERVER['LOGNAME'])) {
1955 // 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).
1956 $data['ip'] = '???@'.$_SERVER['LOGNAME'];
1957 }
1958
1959 // Loop on each log handler and send output
1960 foreach ($conf->loghandlers as $loghandlerinstance) {
1961 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
1962 continue;
1963 }
1964 $loghandlerinstance->export($data, $suffixinfilename);
1965 }
1966 unset($data);
1967 }
1968
1969 if ($ident > 0) {
1970 foreach ($conf->loghandlers as $loghandlerinstance) {
1971 $loghandlerinstance->setIdent($ident);
1972 }
1973 }
1974}
1975
1992function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
1993{
1994 global $conf;
1995
1996 if (strpos($url, '?') > 0) {
1997 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1998 } else {
1999 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2000 }
2001
2002 $out = '';
2003
2004 $backtopagejsfieldsid = '';
2005 $backtopagejsfieldslabel = '';
2006 if ($backtopagejsfields) {
2007 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
2008 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
2009 $backtopagejsfields = $name.":".$backtopagejsfields;
2010 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
2011 } else {
2012 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
2013 }
2014 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
2015 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
2016 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
2017 }
2018
2019 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
2020 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
2021 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
2022 if (empty($conf->use_javascript_ajax)) {
2023 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
2024 } elseif ($jsonopen) {
2025 $out .= ' href="#" onclick="'.$jsonopen.'"';
2026 } else {
2027 $out .= ' href="#"';
2028 }
2029 $out .= '>'.$buttonstring.'</a>';
2030
2031 if (!empty($conf->use_javascript_ajax)) {
2032 // Add code to open url using the popup. Add also hidden field to retreive the returned variables
2033 $out .= '<!-- code to open popup and variables to retreive returned variables -->';
2034 $out .= '<div id="idfordialog'.$name.'" class="hidden">div for dialog</div>';
2035 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">div for returned id</div>';
2036 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">div for returned label</div>';
2037 $out .= '<!-- Add js code to open dialog popup on dialog -->';
2038 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
2039 jQuery(document).ready(function () {
2040 jQuery(".button_'.$name.'").click(function () {
2041 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
2042 var $tmpdialog = $(\'#idfordialog'.$name.'\');
2043 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
2044 $tmpdialog.dialog({
2045 autoOpen: false,
2046 modal: true,
2047 height: (window.innerHeight - 150),
2048 width: \'80%\',
2049 title: \''.dol_escape_js($label).'\',
2050 open: function (event, ui) {
2051 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
2052 },
2053 close: function (event, ui) {
2054 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
2055 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
2056 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
2057 if (returnedid != "" && returnedid != "div for returned id") {
2058 jQuery("#'.(empty($backtopagejsfieldsid) ? "none" : $backtopagejsfieldsid).'").val(returnedid);
2059 }
2060 if (returnedlabel != "" && returnedlabel != "div for returned label") {
2061 jQuery("#'.(empty($backtopagejsfieldslabel) ? "none" : $backtopagejsfieldslabel).'").val(returnedlabel);
2062 }
2063 }
2064 });
2065
2066 $tmpdialog.dialog(\'open\');
2067 return false;
2068 });
2069 });
2070 </script>';
2071 }
2072 return $out;
2073}
2074
2091function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2092{
2093 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2094}
2095
2112function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2113{
2114 global $conf, $langs, $hookmanager;
2115
2116 // Show title
2117 $showtitle = 1;
2118 if (!empty($conf->dol_optimize_smallscreen)) {
2119 $showtitle = 0;
2120 }
2121
2122 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2123
2124 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2125 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2126 }
2127
2128 // Show right part
2129 if ($morehtmlright) {
2130 $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.
2131 }
2132
2133 // Show title
2134 if (!empty($title) && $showtitle && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2135 $limittitle = 30;
2136 $out .= '<a class="tabTitle">';
2137 if ($picto) {
2138 $noprefix = $pictoisfullpath;
2139 if (strpos($picto, 'fontawesome_') !== false) {
2140 $noprefix = 1;
2141 }
2142 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2143 }
2144 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2145 $out .= '</a>';
2146 }
2147
2148 // Show tabs
2149
2150 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2151 $maxkey = -1;
2152 if (is_array($links) && !empty($links)) {
2153 $keys = array_keys($links);
2154 if (count($keys)) {
2155 $maxkey = max($keys);
2156 }
2157 }
2158
2159 // Show tabs
2160 // if =0 we don't use the feature
2161 if (empty($limittoshow)) {
2162 $limittoshow = (!getDolGlobalString('MAIN_MAXTABS_IN_CARD') ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2163 }
2164 if (!empty($conf->dol_optimize_smallscreen)) {
2165 $limittoshow = 2;
2166 }
2167
2168 $displaytab = 0;
2169 $nbintab = 0;
2170 $popuptab = 0;
2171 $outmore = '';
2172 for ($i = 0; $i <= $maxkey; $i++) {
2173 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2174 // If active tab is already present
2175 if ($i >= $limittoshow) {
2176 $limittoshow--;
2177 }
2178 }
2179 }
2180
2181 for ($i = 0; $i <= $maxkey; $i++) {
2182 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2183 $isactive = true;
2184 } else {
2185 $isactive = false;
2186 }
2187
2188 if ($i < $limittoshow || $isactive) {
2189 // Output entry with a visible tab
2190 $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])).' -->';
2191
2192 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2193 if (!empty($links[$i][0])) {
2194 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2195 } else {
2196 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2197 }
2198 } elseif (!empty($links[$i][1])) {
2199 //print "x $i $active ".$links[$i][2]." z";
2200 $out .= '<div class="tab tab'.($isactive ? 'active' : 'unactive').'" style="margin: 0 !important">';
2201 if (!empty($links[$i][0])) {
2202 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2203 $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).'">';
2204 }
2205 $out .= $links[$i][1];
2206 if (!empty($links[$i][0])) {
2207 $out .= '</a>'."\n";
2208 }
2209 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2210 $out .= '</div>';
2211 }
2212
2213 $out .= '</div>';
2214 } else {
2215 // Add entry into the combo popup with the other tabs
2216 if (!$popuptab) {
2217 $popuptab = 1;
2218 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2219 }
2220 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2221 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2222 if (!empty($links[$i][0])) {
2223 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2224 } else {
2225 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2226 }
2227 } elseif (!empty($links[$i][1])) {
2228 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2229 $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.
2230 $outmore .= '</a>'."\n";
2231 }
2232 $outmore .= '</div>';
2233
2234 $nbintab++;
2235 }
2236 $displaytab = $i;
2237 }
2238 if ($popuptab) {
2239 $outmore .= '</div>';
2240 }
2241
2242 if ($popuptab) { // If there is some tabs not shown
2243 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2244 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2245 $widthofpopup = 200;
2246
2247 $tabsname = $moretabssuffix;
2248 if (empty($tabsname)) {
2249 $tabsname = str_replace("@", "", $picto);
2250 }
2251 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2252 $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".
2253 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2254 $out .= $outmore;
2255 $out .= '</div>';
2256 $out .= '<div></div>';
2257 $out .= "</div>\n";
2258
2259 $out .= '<script nonce="'.getNonce().'">';
2260 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2261 var x = this.offsetLeft, y = this.offsetTop;
2262 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2263 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2264 $('#moretabsList".$tabsname."').css('".$right."','8px');
2265 }
2266 $('#moretabsList".$tabsname."').css('".$left."','auto');
2267 });
2268 ";
2269 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2270 $out .= "</script>";
2271 }
2272
2273 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2274 $out .= "</div>\n";
2275 }
2276
2277 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2278 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom'))).'">'."\n";
2279 }
2280 if (!empty($dragdropfile)) {
2281 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2282 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2283 }
2284 $parameters = array('tabname' => $active, 'out' => $out);
2285 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2286 if ($reshook > 0) {
2287 $out = $hookmanager->resPrint;
2288 }
2289
2290 return $out;
2291}
2292
2300function dol_fiche_end($notab = 0)
2301{
2302 print dol_get_fiche_end($notab);
2303}
2304
2311function dol_get_fiche_end($notab = 0)
2312{
2313 if (!$notab || $notab == -1) {
2314 return "\n</div>\n";
2315 } else {
2316 return '';
2317 }
2318}
2319
2339function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2340{
2341 global $conf, $form, $user, $langs, $hookmanager, $action;
2342
2343 $error = 0;
2344
2345 $maxvisiblephotos = 1;
2346 $showimage = 1;
2347 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2348 $showbarcode = empty($conf->barcode->enabled) ? 0 : (empty($object->barcode) ? 0 : 1);
2349 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2350 $showbarcode = 0;
2351 }
2352 $modulepart = 'unknown';
2353
2354 if ($object->element == 'societe' || $object->element == 'contact' || $object->element == 'product' || $object->element == 'ticket') {
2355 $modulepart = $object->element;
2356 } elseif ($object->element == 'member') {
2357 $modulepart = 'memberphoto';
2358 } elseif ($object->element == 'user') {
2359 $modulepart = 'userphoto';
2360 }
2361
2362 if (class_exists("Imagick")) {
2363 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2364 $modulepart = $object->element;
2365 } elseif ($object->element == 'fichinter') {
2366 $modulepart = 'ficheinter';
2367 } elseif ($object->element == 'contrat') {
2368 $modulepart = 'contract';
2369 } elseif ($object->element == 'order_supplier') {
2370 $modulepart = 'supplier_order';
2371 } elseif ($object->element == 'invoice_supplier') {
2372 $modulepart = 'supplier_invoice';
2373 }
2374 }
2375
2376 if ($object->element == 'product') {
2377 $width = 80;
2378 $cssclass = 'photowithmargin photoref';
2379 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2380 $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : 5);
2381 if ($conf->browser->layout == 'phone') {
2382 $maxvisiblephotos = 1;
2383 }
2384 if ($showimage) {
2385 $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>';
2386 } else {
2387 if (getDolGlobalString('PRODUCT_NODISPLAYIFNOPHOTO')) {
2388 $nophoto = '';
2389 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2390 } else { // Show no photo link
2391 $nophoto = '/public/theme/common/nophoto.png';
2392 $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>';
2393 }
2394 }
2395 } elseif ($object->element == 'ticket') {
2396 $width = 80;
2397 $cssclass = 'photoref';
2398 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2399 $maxvisiblephotos = (isset($conf->global->TICKET_MAX_VISIBLE_PHOTO) ? $conf->global->TICKET_MAX_VISIBLE_PHOTO : 2);
2400 if ($conf->browser->layout == 'phone') {
2401 $maxvisiblephotos = 1;
2402 }
2403
2404 if ($showimage) {
2405 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2406 if ($object->nbphoto > 0) {
2407 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2408 } else {
2409 $showimage = 0;
2410 }
2411 }
2412 if (!$showimage) {
2413 if (getDolGlobalString('TICKET_NODISPLAYIFNOPHOTO')) {
2414 $nophoto = '';
2415 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2416 } else { // Show no photo link
2417 $nophoto = img_picto('No photo', 'object_ticket');
2418 $morehtmlleft .= '<!-- No photo to show -->';
2419 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2420 $morehtmlleft .= $nophoto;
2421 $morehtmlleft .= '</div></div>';
2422 }
2423 }
2424 } else {
2425 if ($showimage) {
2426 if ($modulepart != 'unknown') {
2427 $phototoshow = '';
2428 // Check if a preview file is available
2429 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2430 $objectref = dol_sanitizeFileName($object->ref);
2431 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2432 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2433 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2434 $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
2435 } else {
2436 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2437 }
2438 if (empty($subdir)) {
2439 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2440 }
2441
2442 $filepath = $dir_output.$subdir."/";
2443
2444 $filepdf = $filepath.$objectref.".pdf";
2445 $relativepath = $subdir.'/'.$objectref.'.pdf';
2446
2447 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2448 $fileimage = $filepdf.'_preview.png';
2449 $relativepathimage = $relativepath.'_preview.png';
2450
2451 $pdfexists = file_exists($filepdf);
2452
2453 // If PDF file exists
2454 if ($pdfexists) {
2455 // Conversion du PDF en image png si fichier png non existant
2456 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2457 if (!getDolGlobalString('MAIN_DISABLE_PDF_THUMBS')) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2458 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2459 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2460 if ($ret < 0) {
2461 $error++;
2462 }
2463 }
2464 }
2465 }
2466
2467 if ($pdfexists && !$error) {
2468 $heightforphotref = 80;
2469 if (!empty($conf->dol_optimize_smallscreen)) {
2470 $heightforphotref = 60;
2471 }
2472 // If the preview file is found
2473 if (file_exists($fileimage)) {
2474 $phototoshow = '<div class="photoref">';
2475 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2476 $phototoshow .= '</div>';
2477 }
2478 }
2479 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo'
2480 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2481 }
2482
2483 if ($phototoshow) {
2484 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2485 $morehtmlleft .= $phototoshow;
2486 $morehtmlleft .= '</div>';
2487 }
2488 }
2489
2490 if (empty($phototoshow)) { // Show No photo link (picto of object)
2491 if ($object->element == 'action') {
2492 $width = 80;
2493 $cssclass = 'photorefcenter';
2494 $nophoto = img_picto('No photo', 'title_agenda');
2495 } else {
2496 $width = 14;
2497 $cssclass = 'photorefcenter';
2498 $picto = $object->picto;
2499 $prefix = 'object_';
2500 if ($object->element == 'project' && !$object->public) {
2501 $picto = 'project'; // instead of projectpub
2502 }
2503 if (strpos($picto, 'fontawesome_') !== false) {
2504 $prefix = '';
2505 }
2506 $nophoto = img_picto('No photo', $prefix.$picto);
2507 }
2508 $morehtmlleft .= '<!-- No photo to show -->';
2509 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2510 $morehtmlleft .= $nophoto;
2511 $morehtmlleft .= '</div></div>';
2512 }
2513 }
2514 }
2515
2516 // Show barcode
2517 if ($showbarcode) {
2518 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2519 }
2520
2521 if ($object->element == 'societe') {
2522 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2523 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2524 } else {
2525 $morehtmlstatus .= $object->getLibStatut(6);
2526 }
2527 } elseif ($object->element == 'product') {
2528 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2529 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2530 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2531 } else {
2532 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2533 }
2534 $morehtmlstatus .= ' &nbsp; ';
2535 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2536 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2537 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2538 } else {
2539 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2540 }
2541 } elseif (in_array($object->element, array('salary'))) {
2542 $tmptxt = $object->getLibStatut(6, $object->alreadypaid);
2543 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2544 $tmptxt = $object->getLibStatut(5, $object->alreadypaid);
2545 }
2546 $morehtmlstatus .= $tmptxt;
2547 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier'))) { // TODO Move this to use ->alreadypaid
2548 $totalallpayments = $object->getSommePaiement(0);
2549 $totalallpayments += $object->getSumCreditNotesUsed(0);
2550 $totalallpayments += $object->getSumDepositsUsed(0);
2551 $tmptxt = $object->getLibStatut(6, $totalallpayments);
2552 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2553 $tmptxt = $object->getLibStatut(5, $totalallpayments);
2554 }
2555 $morehtmlstatus .= $tmptxt;
2556 } elseif (in_array($object->element, array('chargesociales', 'loan', 'tva'))) { // TODO Move this to use ->alreadypaid
2557 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2558 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2559 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2560 }
2561 $morehtmlstatus .= $tmptxt;
2562 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2563 if ($object->statut == 0) {
2564 $morehtmlstatus .= $object->getLibStatut(5);
2565 } else {
2566 $morehtmlstatus .= $object->getLibStatut(4);
2567 }
2568 } elseif ($object->element == 'facturerec') {
2569 if ($object->frequency == 0) {
2570 $morehtmlstatus .= $object->getLibStatut(2);
2571 } else {
2572 $morehtmlstatus .= $object->getLibStatut(5);
2573 }
2574 } elseif ($object->element == 'project_task') {
2575 $object->fk_statut = 1;
2576 if ($object->progress > 0) {
2577 $object->fk_statut = 2;
2578 }
2579 if ($object->progress >= 100) {
2580 $object->fk_statut = 3;
2581 }
2582 $tmptxt = $object->getLibStatut(5);
2583 $morehtmlstatus .= $tmptxt; // No status on task
2584 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2585 $tmptxt = $object->getLibStatut(6);
2586 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2587 $tmptxt = $object->getLibStatut(5);
2588 }
2589 $morehtmlstatus .= $tmptxt;
2590 }
2591
2592 // Add if object was dispatched "into accountancy"
2593 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2594 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2595 if (method_exists($object, 'getVentilExportCompta')) {
2596 $accounted = $object->getVentilExportCompta();
2597 $langs->load("accountancy");
2598 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2599 }
2600 }
2601
2602 // Add alias for thirdparty
2603 if (!empty($object->name_alias)) {
2604 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
2605 }
2606
2607 // Add label
2608 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
2609 if (!empty($object->label)) {
2610 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
2611 }
2612 }
2613
2614 // Show address and email
2615 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
2616 $moreaddress = $object->getBannerAddress('refaddress', $object); // address, email, url, social networks
2617 if ($moreaddress) {
2618 $morehtmlref .= '<div class="refidno refaddress">';
2619 $morehtmlref .= $moreaddress;
2620 $morehtmlref .= '</div>';
2621 }
2622 }
2623 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)) {
2624 $morehtmlref .= '<div style="clear: both;"></div>';
2625 $morehtmlref .= '<div class="refidno opacitymedium">';
2626 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
2627 $morehtmlref .= '</div>';
2628 }
2629
2630 $parameters=array('morehtmlref'=>$morehtmlref);
2631 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
2632 if ($reshook < 0) {
2633 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2634 } elseif (empty($reshook)) {
2635 $morehtmlref .= $hookmanager->resPrint;
2636 } elseif ($reshook > 0) {
2637 $morehtmlref = $hookmanager->resPrint;
2638 }
2639
2640 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
2641 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
2642 print '</div>';
2643 print '<div class="underrefbanner clearboth"></div>';
2644}
2645
2655function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
2656{
2657 global $langs;
2658 $ret = '';
2659 if ($fieldrequired) {
2660 $ret .= '<span class="fieldrequired">';
2661 }
2662 $ret .= '<label for="'.$fieldkey.'">';
2663 $ret .= $langs->trans($langkey);
2664 $ret .= '</label>';
2665 if ($fieldrequired) {
2666 $ret .= '</span>';
2667 }
2668 return $ret;
2669}
2670
2678function dol_bc($var, $moreclass = '')
2679{
2680 global $bc;
2681 $ret = ' '.$bc[$var];
2682 if ($moreclass) {
2683 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
2684 }
2685 return $ret;
2686}
2687
2701function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = '', $mode = 0, $extralangcode = '')
2702{
2703 global $conf, $langs, $hookmanager;
2704
2705 $ret = '';
2706 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
2707
2708 // See format of addresses on https://en.wikipedia.org/wiki/Address
2709 // Address
2710 if (empty($mode)) {
2711 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
2712 }
2713 // Zip/Town/State
2714 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || getDolGlobalString('MAIN_FORCE_STATE_INTO_ADDRESS')) {
2715 // US: title firstname name \n address lines \n town, state, zip \n country
2716 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2717 $ret .= (($ret && $town) ? $sep : '').$town;
2718
2719 if (!empty($object->state)) {
2720 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
2721 }
2722 if (!empty($object->zip)) {
2723 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
2724 }
2725 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
2726 // UK: title firstname name \n address lines \n town state \n zip \n country
2727 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2728 $ret .= ($ret ? $sep : '').$town;
2729 if (!empty($object->state)) {
2730 $ret .= ($ret ? ", " : '').$object->state;
2731 }
2732 if (!empty($object->zip)) {
2733 $ret .= ($ret ? $sep : '').$object->zip;
2734 }
2735 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
2736 // ES: title firstname name \n address lines \n zip town \n state \n country
2737 $ret .= ($ret ? $sep : '').$object->zip;
2738 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2739 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2740 if (!empty($object->state)) {
2741 $ret .= $sep.$object->state;
2742 }
2743 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
2744 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
2745 // See https://www.sljfaq.org/afaq/addresses.html
2746 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2747 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
2748 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
2749 // IT: title firstname name\n address lines \n zip town state_code \n country
2750 $ret .= ($ret ? $sep : '').$object->zip;
2751 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2752 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2753 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
2754 } else {
2755 // Other: title firstname name \n address lines \n zip town[, state] \n country
2756 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2757 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
2758 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
2759 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
2760 $ret .= ($ret ? ", " : '').$object->state;
2761 }
2762 }
2763
2764 if (!is_object($outputlangs)) {
2765 $outputlangs = $langs;
2766 }
2767 if ($withcountry) {
2768 $langs->load("dict");
2769 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
2770 }
2771 if ($hookmanager) {
2772 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
2773 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
2774 if ($reshook > 0) {
2775 $ret = '';
2776 }
2777 $ret .= $hookmanager->resPrint;
2778 }
2779
2780 return $ret;
2781}
2782
2783
2784
2793function dol_strftime($fmt, $ts = false, $is_gmt = false)
2794{
2795 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
2796 return ($is_gmt) ? @gmstrftime($fmt, $ts) : @strftime($fmt, $ts);
2797 } else {
2798 return 'Error date into a not supported range';
2799 }
2800}
2801
2823function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = '', $encodetooutput = false)
2824{
2825 global $conf, $langs;
2826
2827 // If date undefined or "", we return ""
2828 if (dol_strlen($time) == 0) {
2829 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
2830 }
2831
2832 if ($tzoutput === 'auto') {
2833 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
2834 }
2835
2836 // Clean parameters
2837 $to_gmt = false;
2838 $offsettz = $offsetdst = 0;
2839 if ($tzoutput) {
2840 $to_gmt = true; // For backward compatibility
2841 if (is_string($tzoutput)) {
2842 if ($tzoutput == 'tzserver') {
2843 $to_gmt = false;
2844 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
2845 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
2846 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
2847 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
2848 $to_gmt = true;
2849 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
2850
2851 if (class_exists('DateTimeZone')) {
2852 $user_date_tz = new DateTimeZone($offsettzstring);
2853 $user_dt = new DateTime();
2854 $user_dt->setTimezone($user_date_tz);
2855 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
2856 $offsettz = $user_dt->getOffset(); // should include dst ?
2857 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
2858 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
2859 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
2860 }
2861 }
2862 }
2863 }
2864 if (!is_object($outputlangs)) {
2865 $outputlangs = $langs;
2866 }
2867 if (!$format) {
2868 $format = 'daytextshort';
2869 }
2870
2871 // Do we have to reduce the length of date (year on 2 chars) to save space.
2872 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
2873 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour', 'dayhoursec'))) ? 1 : 0; // Test on original $format param.
2874 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
2875 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
2876 if ($formatwithoutreduce != $format) {
2877 $format = $formatwithoutreduce;
2878 $reduceformat = 1;
2879 } // so format 'dayreduceformat' is processed like day
2880
2881 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
2882 // TODO Add format daysmallyear and dayhoursmallyear
2883 if ($format == 'day') {
2884 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
2885 } elseif ($format == 'hour') {
2886 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
2887 } elseif ($format == 'hourduration') {
2888 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
2889 } elseif ($format == 'daytext') {
2890 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
2891 } elseif ($format == 'daytextshort') {
2892 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
2893 } elseif ($format == 'dayhour') {
2894 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
2895 } elseif ($format == 'dayhoursec') {
2896 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
2897 } elseif ($format == 'dayhourtext') {
2898 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
2899 } elseif ($format == 'dayhourtextshort') {
2900 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
2901 } elseif ($format == 'dayhourlog') {
2902 // Format not sensitive to language
2903 $format = '%Y%m%d%H%M%S';
2904 } elseif ($format == 'dayhourlogsmall') {
2905 // Format not sensitive to language
2906 $format = '%y%m%d%H%M';
2907 } elseif ($format == 'dayhourldap') {
2908 $format = '%Y%m%d%H%M%SZ';
2909 } elseif ($format == 'dayhourxcard') {
2910 $format = '%Y%m%dT%H%M%SZ';
2911 } elseif ($format == 'dayxcard') {
2912 $format = '%Y%m%d';
2913 } elseif ($format == 'dayrfc') {
2914 $format = '%Y-%m-%d'; // DATE_RFC3339
2915 } elseif ($format == 'dayhourrfc') {
2916 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
2917 } elseif ($format == 'standard') {
2918 $format = '%Y-%m-%d %H:%M:%S';
2919 }
2920
2921 if ($reduceformat) {
2922 $format = str_replace('%Y', '%y', $format);
2923 $format = str_replace('yyyy', 'yy', $format);
2924 }
2925
2926 // Clean format
2927 if (preg_match('/%b/i', $format)) { // There is some text to translate
2928 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2929 $format = str_replace('%b', '__b__', $format);
2930 $format = str_replace('%B', '__B__', $format);
2931 }
2932 if (preg_match('/%a/i', $format)) { // There is some text to translate
2933 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2934 $format = str_replace('%a', '__a__', $format);
2935 $format = str_replace('%A', '__A__', $format);
2936 }
2937
2938 // Analyze date
2939 $reg = array();
2940 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
2941 dol_print_error('', "Functions.lib::dol_print_date function called with a bad value from page ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]));
2942 return '';
2943 } 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
2944 // This part of code should not be used anymore.
2945 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);
2946 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
2947 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
2948 $syear = (!empty($reg[1]) ? $reg[1] : '');
2949 $smonth = (!empty($reg[2]) ? $reg[2] : '');
2950 $sday = (!empty($reg[3]) ? $reg[3] : '');
2951 $shour = (!empty($reg[4]) ? $reg[4] : '');
2952 $smin = (!empty($reg[5]) ? $reg[5] : '');
2953 $ssec = (!empty($reg[6]) ? $reg[6] : '');
2954
2955 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
2956
2957 if ($to_gmt) {
2958 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2959 } else {
2960 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2961 }
2962 $dtts = new DateTime();
2963 $dtts->setTimestamp($time);
2964 $dtts->setTimezone($tzo);
2965 $newformat = str_replace(
2966 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2967 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2968 $format
2969 );
2970 $ret = $dtts->format($newformat);
2971 $ret = str_replace(
2972 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2973 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2974 $ret
2975 );
2976 } else {
2977 // Date is a timestamps
2978 if ($time < 100000000000) { // Protection against bad date values
2979 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2980
2981 if ($to_gmt) {
2982 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2983 } else {
2984 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2985 }
2986 $dtts = new DateTime();
2987 $dtts->setTimestamp($timetouse);
2988 $dtts->setTimezone($tzo);
2989 $newformat = str_replace(
2990 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2991 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2992 $format
2993 );
2994 $ret = $dtts->format($newformat);
2995 $ret = str_replace(
2996 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2997 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2998 $ret
2999 );
3000 //var_dump($ret);exit;
3001 } else {
3002 $ret = 'Bad value '.$time.' for date';
3003 }
3004 }
3005
3006 if (preg_match('/__b__/i', $format)) {
3007 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
3008
3009 if ($to_gmt) {
3010 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
3011 } else {
3012 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
3013 }
3014 $dtts = new DateTime();
3015 $dtts->setTimestamp($timetouse);
3016 $dtts->setTimezone($tzo);
3017 $month = $dtts->format("m");
3018 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
3019 if ($encodetooutput) {
3020 $monthtext = $outputlangs->transnoentities('Month'.$month);
3021 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
3022 } else {
3023 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
3024 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
3025 }
3026 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
3027 $ret = str_replace('__b__', $monthtextshort, $ret);
3028 $ret = str_replace('__B__', $monthtext, $ret);
3029 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
3030 //return $ret;
3031 }
3032 if (preg_match('/__a__/i', $format)) {
3033 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
3034 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
3035
3036 if ($to_gmt) {
3037 $tzo = new DateTimeZone('UTC');
3038 } else {
3039 $tzo = new DateTimeZone(date_default_timezone_get());
3040 }
3041 $dtts = new DateTime();
3042 $dtts->setTimestamp($timetouse);
3043 $dtts->setTimezone($tzo);
3044 $w = $dtts->format("w");
3045 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
3046
3047 $ret = str_replace('__A__', $dayweek, $ret);
3048 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
3049 }
3050
3051 return $ret;
3052}
3053
3054
3075function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
3076{
3077 if ($timestamp === '') {
3078 return array();
3079 }
3080
3081 $datetimeobj = new DateTime();
3082 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
3083 if ($forcetimezone) {
3084 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
3085 }
3086 $arrayinfo = array(
3087 'year'=>((int) date_format($datetimeobj, 'Y')),
3088 'mon'=>((int) date_format($datetimeobj, 'm')),
3089 'mday'=>((int) date_format($datetimeobj, 'd')),
3090 'wday'=>((int) date_format($datetimeobj, 'w')),
3091 'yday'=>((int) date_format($datetimeobj, 'z')),
3092 'hours'=>((int) date_format($datetimeobj, 'H')),
3093 'minutes'=>((int) date_format($datetimeobj, 'i')),
3094 'seconds'=>((int) date_format($datetimeobj, 's')),
3095 '0'=>$timestamp
3096 );
3097
3098 return $arrayinfo;
3099}
3100
3122function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3123{
3124 global $conf;
3125 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3126
3127 if ($gm === 'auto') {
3128 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3129 }
3130 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3131
3132 // Clean parameters
3133 if ($hour == -1 || empty($hour)) {
3134 $hour = 0;
3135 }
3136 if ($minute == -1 || empty($minute)) {
3137 $minute = 0;
3138 }
3139 if ($second == -1 || empty($second)) {
3140 $second = 0;
3141 }
3142
3143 // Check parameters
3144 if ($check) {
3145 if (!$month || !$day) {
3146 return '';
3147 }
3148 if ($day > 31) {
3149 return '';
3150 }
3151 if ($month > 12) {
3152 return '';
3153 }
3154 if ($hour < 0 || $hour > 24) {
3155 return '';
3156 }
3157 if ($minute < 0 || $minute > 60) {
3158 return '';
3159 }
3160 if ($second < 0 || $second > 60) {
3161 return '';
3162 }
3163 }
3164
3165 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3166 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3167 $localtz = new DateTimeZone($default_timezone);
3168 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3169 // We use dol_tz_string first because it is more reliable.
3170 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3171 try {
3172 $localtz = new DateTimeZone($default_timezone);
3173 } catch (Exception $e) {
3174 dol_syslog("Warning dol_tz_string contains an invalid value ".$_SESSION["dol_tz_string"], LOG_WARNING);
3175 $default_timezone = @date_default_timezone_get();
3176 }
3177 } elseif (strrpos($gm, "tz,") !== false) {
3178 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3179 try {
3180 $localtz = new DateTimeZone($timezone);
3181 } catch (Exception $e) {
3182 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3183 }
3184 }
3185
3186 if (empty($localtz)) {
3187 $localtz = new DateTimeZone('UTC');
3188 }
3189 //var_dump($localtz);
3190 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3191 $dt = new DateTime('now', $localtz);
3192 $dt->setDate((int) $year, (int) $month, (int) $day);
3193 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3194 $date = $dt->getTimestamp(); // should include daylight saving time
3195 //var_dump($date);
3196 return $date;
3197}
3198
3199
3210function dol_now($mode = 'auto')
3211{
3212 $ret = 0;
3213
3214 if ($mode === 'auto') {
3215 $mode = 'gmt';
3216 }
3217
3218 if ($mode == 'gmt') {
3219 $ret = time(); // Time for now at greenwich.
3220 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3221 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3222 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3223 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3224 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3225 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3226 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3227 // $ret=dol_now('gmt')+($tzsecond*3600);
3228 //}
3229 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3230 // Time for now with user timezone added
3231 //print 'time: '.time();
3232 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3233 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3234 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3235 }
3236
3237 return $ret;
3238}
3239
3240
3249function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3250{
3251 global $conf, $langs;
3252 $level = 1024;
3253
3254 if (!empty($conf->dol_optimize_smallscreen)) {
3255 $shortunit = 1;
3256 }
3257
3258 // Set value text
3259 if (empty($shortvalue) || $size < ($level * 10)) {
3260 $ret = $size;
3261 $textunitshort = $langs->trans("b");
3262 $textunitlong = $langs->trans("Bytes");
3263 } else {
3264 $ret = round($size / $level, 0);
3265 $textunitshort = $langs->trans("Kb");
3266 $textunitlong = $langs->trans("KiloBytes");
3267 }
3268 // Use long or short text unit
3269 if (empty($shortunit)) {
3270 $ret .= ' '.$textunitlong;
3271 } else {
3272 $ret .= ' '.$textunitshort;
3273 }
3274
3275 return $ret;
3276}
3277
3288function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = '')
3289{
3290 global $langs;
3291
3292 if (empty($url)) {
3293 return '';
3294 }
3295
3296 $linkstart = '<a href="';
3297 if (!preg_match('/^http/i', $url)) {
3298 $linkstart .= 'http://';
3299 }
3300 $linkstart .= $url;
3301 $linkstart .= '"';
3302 if ($target) {
3303 $linkstart .= ' target="'.$target.'"';
3304 }
3305 $linkstart .= ' title="'.$langs->trans("URL").': '.$url.'"';
3306 $linkstart .= '>';
3307
3308 $link = '';
3309 if (!preg_match('/^http/i', $url)) {
3310 $link .= 'http://';
3311 }
3312 $link .= dol_trunc($url, $max);
3313
3314 $linkend = '</a>';
3315
3316 if ($morecss == 'float') { // deprecated
3317 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto($langs->trans("Url"), 'globe', 'class="paddingrightonly"') : '').$link.'</div>';
3318 } else {
3319 return $linkstart.'<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto('', 'globe', 'class="paddingrightonly"') : '').$link.'</span>'.$linkend;
3320 }
3321}
3322
3335function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3336{
3337 global $user, $langs, $hookmanager;
3338
3339 //global $conf; $conf->global->AGENDA_ADDACTIONFOREMAIL = 1;
3340 //$showinvalid = 1; $email = 'rrrrr';
3341
3342 $newemail = dol_escape_htmltag($email);
3343
3344 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && $withpicto) {
3345 $withpicto = 0;
3346 }
3347
3348 if (empty($email)) {
3349 return '&nbsp;';
3350 }
3351
3352 if (!empty($addlink)) {
3353 $newemail = '<a class="paddingrightonly" style="text-overflow: ellipsis;" href="';
3354 if (!preg_match('/^mailto:/i', $email)) {
3355 $newemail .= 'mailto:';
3356 }
3357 $newemail .= $email;
3358 $newemail .= '">';
3359
3360 $newemail .= ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '');
3361
3362 $newemail .= dol_trunc($email, $max);
3363 $newemail .= '</a>';
3364 if ($showinvalid && !isValidEmail($email)) {
3365 $langs->load("errors");
3366 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email), '', 'paddingrightonly');
3367 }
3368
3369 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3370 $type = 'AC_EMAIL';
3371 $linktoaddaction = '';
3372 if (getDolGlobalString('AGENDA_ADDACTIONFOREMAIL')) {
3373 $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>';
3374 }
3375 if ($linktoaddaction) {
3376 $newemail = '<div>'.$newemail.' '.$linktoaddaction.'</div>';
3377 }
3378 }
3379 } else {
3380 $newemail = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3381
3382 if ($showinvalid && !isValidEmail($email)) {
3383 $langs->load("errors");
3384 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3385 }
3386 }
3387
3388 //$rep = '<div class="nospan" style="margin-right: 10px">';
3389 //$rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3390 //$rep .= '</div>';
3391 $rep = $newemail;
3392
3393 if ($hookmanager) {
3394 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3395
3396 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3397 if ($reshook > 0) {
3398 $rep = '';
3399 }
3400 $rep .= $hookmanager->resPrint;
3401 }
3402
3403 return $rep;
3404}
3405
3412{
3413 global $conf, $db;
3414
3415 $socialnetworks = array();
3416 // Enable caching of array
3417 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3418 $cachekey = 'socialnetworks_' . $conf->entity;
3419 $dataretrieved = dol_getcache($cachekey);
3420 if (!is_null($dataretrieved)) {
3421 $socialnetworks = $dataretrieved;
3422 } else {
3423 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3424 $sql .= " WHERE entity=".$conf->entity;
3425 $resql = $db->query($sql);
3426 if ($resql) {
3427 while ($obj = $db->fetch_object($resql)) {
3428 $socialnetworks[$obj->code] = array(
3429 'rowid' => $obj->rowid,
3430 'label' => $obj->label,
3431 'url' => $obj->url,
3432 'icon' => $obj->icon,
3433 'active' => $obj->active,
3434 );
3435 }
3436 }
3437 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3438 }
3439
3440 return $socialnetworks;
3441}
3442
3453function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3454{
3455 global $conf, $user, $langs;
3456
3457 $htmllink = $value;
3458
3459 if (empty($value)) {
3460 return '&nbsp;';
3461 }
3462
3463 if (!empty($type)) {
3464 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3465 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3466 $htmllink .= '<span class="fab pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3467 if ($type == 'skype') {
3468 $htmllink .= dol_escape_htmltag($value);
3469 $htmllink .= '&nbsp; <a href="skype:';
3470 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3471 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3472 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3473 $htmllink .= '</a><a href="skype:';
3474 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3475 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3476 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3477 $htmllink .= '</a>';
3478 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3479 $addlink = 'AC_SKYPE';
3480 $link = '';
3481 if (getDolGlobalString('AGENDA_ADDACTIONFORSKYPE')) {
3482 $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>';
3483 }
3484 $htmllink .= ($link ? ' '.$link : '');
3485 }
3486 } else {
3487 $networkconstname = 'MAIN_INFO_SOCIETE_'.strtoupper($type).'_URL';
3488 if (getDolGlobalString($networkconstname)) {
3489 $link = str_replace('{socialid}', $value, getDolGlobalString($networkconstname));
3490 if (preg_match('/^https?:\/\//i', $link)) {
3491 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3492 } else {
3493 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3494 }
3495 } elseif (!empty($dictsocialnetworks[$type]['url'])) {
3496 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3497 if ($tmpvirginurl) {
3498 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3499 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3500
3501 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3502 if ($tmpvirginurl3) {
3503 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3504 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3505 }
3506
3507 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3508 if ($tmpvirginurl2) {
3509 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3510 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3511 }
3512 }
3513 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3514 if (preg_match('/^https?:\/\//i', $link)) {
3515 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3516 } else {
3517 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3518 }
3519 } else {
3520 $htmllink .= dol_escape_htmltag($value);
3521 }
3522 }
3523 $htmllink .= '</div>';
3524 } else {
3525 $langs->load("errors");
3526 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3527 }
3528 return $htmllink;
3529}
3530
3540function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1)
3541{
3542 global $mysoc;
3543
3544 if (empty($profID) || empty($profIDtype)) {
3545 return '';
3546 }
3547 if (empty($countrycode)) {
3548 $countrycode = $mysoc->country_code;
3549 }
3550 $newProfID = $profID;
3551 $id = substr($profIDtype, -1);
3552 $ret = '';
3553 if (strtoupper($countrycode) == 'FR') {
3554 // France
3555 // (see https://www.economie.gouv.fr/entreprises/numeros-identification-entreprise)
3556
3557 if ($id == 1 && dol_strlen($newProfID) == 9) {
3558 // SIREN (ex: 123 123 123)
3559 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3);
3560 }
3561 if ($id == 2 && dol_strlen($newProfID) == 14) {
3562 // SIRET (ex: 123 123 123 12345)
3563 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3).' '.substr($newProfID, 9, 5);
3564 }
3565 if ($id == 3 && dol_strlen($newProfID) == 5) {
3566 // NAF/APE (ex: 69.20Z)
3567 $newProfID = substr($newProfID, 0, 2).'.'.substr($newProfID, 2, 3);
3568 }
3569 if ($profIDtype === 'VAT' && dol_strlen($newProfID) == 13) {
3570 // TVA intracommunautaire (ex: FR12 123 123 123)
3571 $newProfID = substr($newProfID, 0, 4).' '.substr($newProfID, 4, 3).' '.substr($newProfID, 7, 3).' '.substr($newProfID, 10, 3);
3572 }
3573 }
3574 if (!empty($addcpButton)) {
3575 $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3576 } else {
3577 $ret = $newProfID;
3578 }
3579 return $ret;
3580}
3581
3596function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0)
3597{
3598 global $conf, $user, $langs, $mysoc, $hookmanager;
3599
3600 // Clean phone parameter
3601 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
3602 if (empty($phone)) {
3603 return '';
3604 }
3605 if (getDolGlobalString('MAIN_PHONE_SEPAR')) {
3606 $separ = $conf->global->MAIN_PHONE_SEPAR;
3607 }
3608 if (empty($countrycode) && is_object($mysoc)) {
3609 $countrycode = $mysoc->country_code;
3610 }
3611
3612 // Short format for small screens
3613 if ($conf->dol_optimize_smallscreen) {
3614 $separ = '';
3615 }
3616
3617 $newphone = $phone;
3618 if (strtoupper($countrycode) == "FR") {
3619 // France
3620 if (dol_strlen($phone) == 10) {
3621 $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);
3622 } elseif (dol_strlen($phone) == 7) {
3623 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
3624 } elseif (dol_strlen($phone) == 9) {
3625 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
3626 } elseif (dol_strlen($phone) == 11) {
3627 $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);
3628 } elseif (dol_strlen($phone) == 12) {
3629 $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);
3630 } elseif (dol_strlen($phone) == 13) {
3631 $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);
3632 }
3633 } elseif (strtoupper($countrycode) == "CA") {
3634 if (dol_strlen($phone) == 10) {
3635 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
3636 }
3637 } elseif (strtoupper($countrycode) == "PT") {//Portugal
3638 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
3639 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3640 }
3641 } elseif (strtoupper($countrycode) == "SR") {//Suriname
3642 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
3643 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
3644 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
3645 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
3646 }
3647 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
3648 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
3649 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
3650 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
3651 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
3652 }
3653 } elseif (strtoupper($countrycode) == "ES") {//Espagne
3654 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
3655 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3656 }
3657 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
3658 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
3659 $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);
3660 }
3661 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
3662 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
3663 $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);
3664 }
3665 } elseif (strtoupper($countrycode) == "TR") {//Turquie
3666 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
3667 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3668 }
3669 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
3670 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
3671 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3672 }
3673 } elseif (strtoupper($countrycode) == "MX") {//Mexique
3674 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
3675 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3676 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
3677 $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);
3678 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
3679 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3680 }
3681 } elseif (strtoupper($countrycode) == "ML") {//Mali
3682 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
3683 $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);
3684 }
3685 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
3686 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
3687 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3688 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
3689 $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);
3690 }
3691 } elseif (strtoupper($countrycode) == "MU") {
3692 //Maurice
3693 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
3694 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3695 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
3696 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3697 }
3698 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
3699 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
3700 $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);
3701 }
3702 } elseif (strtoupper($countrycode) == "SY") {//Syrie
3703 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
3704 $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);
3705 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
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, 3);
3707 }
3708 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
3709 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
3710 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3711 } elseif (dol_strlen($phone) == 13) {//ex: +971_ABC_DEF_GHI
3712 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3713 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
3714 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
3715 }
3716 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
3717 if (dol_strlen($phone) == 13) {//ex: +213_ABC_DEF_GHI
3718 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3719 }
3720 } elseif (strtoupper($countrycode) == "BE") {//Belgique
3721 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
3722 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3723 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
3724 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3725 }
3726 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
3727 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
3728 $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);
3729 }
3730 } elseif (strtoupper($countrycode) == "CO") {//Colombie
3731 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
3732 $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);
3733 }
3734 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
3735 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
3736 $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);
3737 }
3738 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
3739 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
3740 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3741 }
3742 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
3743 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
3744 $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);
3745 }
3746 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
3747 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
3748 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3749 }
3750 } elseif (strtoupper($countrycode) == "CH") {//Suisse
3751 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
3752 $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);
3753 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
3754 $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);
3755 }
3756 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
3757 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
3758 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3759 }
3760 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
3761 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
3762 $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);
3763 }
3764 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
3765 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
3766 $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);
3767 }
3768 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
3769 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
3770 $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);
3771 }
3772 } elseif (strtoupper($countrycode) == "IT") {//Italie
3773 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
3774 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3775 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
3776 $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);
3777 }
3778 } elseif (strtoupper($countrycode) == "AU") {
3779 //Australie
3780 if (dol_strlen($phone) == 12) {
3781 //ex: +61_A_BCDE_FGHI
3782 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
3783 }
3784 } elseif (strtoupper($countrycode) == "LU") {
3785 // Luxembourg
3786 if (dol_strlen($phone) == 10) {// fixe 6 chiffres +352_AA_BB_CC
3787 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3788 } elseif (dol_strlen($phone) == 11) {// fixe 7 chiffres +352_AA_BB_CC_D
3789 $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);
3790 } elseif (dol_strlen($phone) == 12) {// fixe 8 chiffres +352_AA_BB_CC_DD
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, 2);
3792 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
3793 $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);
3794 }
3795 }
3796
3797 $newphoneastart = $newphoneaend = '';
3798 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
3799 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
3800 $newphoneastart = '<a href="tel:'.$phone.'">';
3801 $newphoneaend .= '</a>';
3802 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
3803 if (empty($user->clicktodial_loaded)) {
3804 $user->fetch_clicktodial();
3805 }
3806
3807 // Define urlmask
3808 $urlmask = getDolGlobalString('CLICKTODIAL_URL', 'ErrorClickToDialModuleNotConfigured');
3809 if (!empty($user->clicktodial_url)) {
3810 $urlmask = $user->clicktodial_url;
3811 }
3812
3813 $clicktodial_poste = (!empty($user->clicktodial_poste) ? urlencode($user->clicktodial_poste) : '');
3814 $clicktodial_login = (!empty($user->clicktodial_login) ? urlencode($user->clicktodial_login) : '');
3815 $clicktodial_password = (!empty($user->clicktodial_password) ? urlencode($user->clicktodial_password) : '');
3816 // This line is for backward compatibility
3817 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
3818 // Thoose lines are for substitution
3819 $substitarray = array('__PHONEFROM__'=>$clicktodial_poste,
3820 '__PHONETO__'=>urlencode($phone),
3821 '__LOGIN__'=>$clicktodial_login,
3822 '__PASS__'=>$clicktodial_password);
3823 $url = make_substitutions($url, $substitarray);
3824 if (!getDolGlobalString('CLICKTODIAL_DO_NOT_USE_AJAX_CALL')) {
3825 // Default and recommended: New method using ajax without submiting a page making a javascript history.go(-1) back
3826 $newphoneastart = '<a href="'.$url.'" class="cssforclicktodial">'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
3827 $newphoneaend = '</a>';
3828 } else {
3829 // Old method
3830 $newphoneastart = '<a href="'.$url.'"';
3831 if (getDolGlobalString('CLICKTODIAL_FORCENEWTARGET')) {
3832 $newphoneastart .= ' target="_blank" rel="noopener noreferrer"';
3833 }
3834 $newphoneastart .= '>';
3835 $newphoneaend .= '</a>';
3836 }
3837 }
3838
3839 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
3840 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3841 $type = 'AC_TEL';
3842 $addlinktoagenda = '';
3843 if ($addlink == 'AC_FAX') {
3844 $type = 'AC_FAX';
3845 }
3846 if (getDolGlobalString('AGENDA_ADDACTIONFORPHONE')) {
3847 $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>';
3848 }
3849 if ($addlinktoagenda) {
3850 $newphone = '<span>'.$newphone.' '.$addlinktoagenda.'</span>';
3851 }
3852 }
3853 }
3854
3855 if (empty($titlealt)) {
3856 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
3857 }
3858 $rep = '';
3859
3860 if ($hookmanager) {
3861 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
3862 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
3863 $rep .= $hookmanager->resPrint;
3864 }
3865 if (empty($reshook)) {
3866 $picto = '';
3867 if ($withpicto) {
3868 if ($withpicto == 'fax') {
3869 $picto = 'phoning_fax';
3870 } elseif ($withpicto == 'phone') {
3871 $picto = 'phoning';
3872 } elseif ($withpicto == 'mobile') {
3873 $picto = 'phoning_mobile';
3874 } else {
3875 $picto = '';
3876 }
3877 }
3878 if ($adddivfloat == 1) {
3879 $rep .= '<div class="nospan float" style="margin-right: 10px">';
3880 } elseif (empty($adddivfloat)) {
3881 $rep .= '<span style="margin-right: 10px;">';
3882 }
3883
3884 $rep .= $newphoneastart;
3885 $rep .= ($withpicto ? img_picto($titlealt, 'object_'.$picto.'.png') : '');
3886 if ($separ != 'hidenum') {
3887 $rep .= ($withpicto ? ' ' : '').$newphone;
3888 }
3889 $rep .= $newphoneaend;
3890
3891 if ($adddivfloat == 1) {
3892 $rep .= '</div>';
3893 } elseif (empty($adddivfloat)) {
3894 $rep .= '</span>';
3895 }
3896 }
3897
3898 return $rep;
3899}
3900
3908function dol_print_ip($ip, $mode = 0)
3909{
3910 global $langs;
3911
3912 $ret = '';
3913
3914 if (empty($mode)) {
3915 $ret .= $ip;
3916 }
3917
3918 if ($mode != 2) {
3919 $countrycode = dolGetCountryCodeFromIp($ip);
3920 if ($countrycode) { // If success, countrycode is us, fr, ...
3921 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
3922 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
3923 } else {
3924 $ret .= ' ('.$countrycode.')';
3925 }
3926 } else {
3927 // Nothing
3928 }
3929 }
3930
3931 return $ret;
3932}
3933
3943{
3944 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
3945 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
3946 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
3947 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
3948 } else {
3949 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
3950 }
3951 } else {
3952 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
3953 }
3954 } else {
3955 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
3956 }
3957 return $ip;
3958}
3959
3968function isHTTPS()
3969{
3970 $isSecure = false;
3971 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
3972 $isSecure = true;
3973 } 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') {
3974 $isSecure = true;
3975 }
3976 return $isSecure;
3977}
3978
3986{
3987 global $conf;
3988
3989 $countrycode = '';
3990
3991 if (!empty($conf->geoipmaxmind->enabled)) {
3992 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3993 //$ip='24.24.24.24';
3994 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
3995 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3996 $geoip = new DolGeoIP('country', $datafile);
3997 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
3998 $countrycode = $geoip->getCountryCodeFromIP($ip);
3999 }
4000
4001 return $countrycode;
4002}
4003
4004
4012{
4013 global $conf, $langs, $user;
4014
4015 //$ret=$user->xxx;
4016 $ret = '';
4017 if (!empty($conf->geoipmaxmind->enabled)) {
4018 $ip = getUserRemoteIP();
4019 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
4020 //$ip='24.24.24.24';
4021 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
4022 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
4023 $geoip = new DolGeoIP('country', $datafile);
4024 $countrycode = $geoip->getCountryCodeFromIP($ip);
4025 $ret = $countrycode;
4026 }
4027 return $ret;
4028}
4029
4042function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
4043{
4044 global $conf, $user, $langs, $hookmanager;
4045
4046 $out = '';
4047
4048 if ($address) {
4049 if ($hookmanager) {
4050 $parameters = array('element' => $element, 'id' => $id);
4051 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
4052 $out .= $hookmanager->resPrint;
4053 }
4054 if (empty($reshook)) {
4055 if (empty($charfornl)) {
4056 $out .= nl2br($address);
4057 } else {
4058 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
4059 }
4060
4061 // TODO Remove this block, we can add this using the hook now
4062 $showgmap = $showomap = 0;
4063 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS')) {
4064 $showgmap = 1;
4065 }
4066 if ($element == 'contact' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_CONTACTS')) {
4067 $showgmap = 1;
4068 }
4069 if ($element == 'member' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_MEMBERS')) {
4070 $showgmap = 1;
4071 }
4072 if ($element == 'user' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_USERS')) {
4073 $showgmap = 1;
4074 }
4075 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS')) {
4076 $showomap = 1;
4077 }
4078 if ($element == 'contact' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_CONTACTS')) {
4079 $showomap = 1;
4080 }
4081 if ($element == 'member' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_MEMBERS')) {
4082 $showomap = 1;
4083 }
4084 if ($element == 'user' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_USERS')) {
4085 $showomap = 1;
4086 }
4087 if ($showgmap) {
4088 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
4089 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4090 }
4091 if ($showomap) {
4092 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
4093 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4094 }
4095 }
4096 }
4097 if ($noprint) {
4098 return $out;
4099 } else {
4100 print $out;
4101 }
4102}
4103
4104
4114function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
4115{
4116 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
4117 return true;
4118 }
4119 if ($acceptuserkey && $address == '__USER_EMAIL__') {
4120 return true;
4121 }
4122 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
4123 return true;
4124 }
4125
4126 return false;
4127}
4128
4137function isValidMXRecord($domain)
4138{
4139 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
4140 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
4141 return 0;
4142 }
4143 if (function_exists('getmxrr')) {
4144 $mxhosts = array();
4145 $weight = array();
4146 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
4147 if (count($mxhosts) > 1) {
4148 return 1;
4149 }
4150 if (count($mxhosts) == 1 && !empty($mxhosts[0])) {
4151 return 1;
4152 }
4153
4154 return 0;
4155 }
4156 }
4157
4158 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4159 return -1;
4160}
4161
4169function isValidPhone($phone)
4170{
4171 return true;
4172}
4173
4174
4184function dolGetFirstLetters($s, $nbofchar = 1)
4185{
4186 $ret = '';
4187 $tmparray = explode(' ', $s);
4188 foreach ($tmparray as $tmps) {
4189 $ret .= dol_substr($tmps, 0, $nbofchar);
4190 }
4191
4192 return $ret;
4193}
4194
4195
4203function dol_strlen($string, $stringencoding = 'UTF-8')
4204{
4205 if (is_null($string)) {
4206 return 0;
4207 }
4208
4209 if (function_exists('mb_strlen')) {
4210 return mb_strlen($string, $stringencoding);
4211 } else {
4212 return strlen($string);
4213 }
4214}
4215
4226function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4227{
4228 global $langs;
4229
4230 if (empty($stringencoding)) {
4231 $stringencoding = $langs->charset_output;
4232 }
4233
4234 $ret = '';
4235 if (empty($trunconbytes)) {
4236 if (function_exists('mb_substr')) {
4237 $ret = mb_substr($string, $start, $length, $stringencoding);
4238 } else {
4239 $ret = substr($string, $start, $length);
4240 }
4241 } else {
4242 if (function_exists('mb_strcut')) {
4243 $ret = mb_strcut($string, $start, $length, $stringencoding);
4244 } else {
4245 $ret = substr($string, $start, $length);
4246 }
4247 }
4248 return $ret;
4249}
4250
4251
4265function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4266{
4267 global $conf;
4268
4269 if (empty($size) || getDolGlobalString('MAIN_DISABLE_TRUNC')) {
4270 return $string;
4271 }
4272
4273 if (empty($stringencoding)) {
4274 $stringencoding = 'UTF-8';
4275 }
4276 // reduce for small screen
4277 if ($conf->dol_optimize_smallscreen == 1 && $display == 1) {
4278 $size = round($size / 3);
4279 }
4280
4281 // We go always here
4282 if ($trunc == 'right') {
4283 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4284 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4285 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4286 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4287 } else {
4288 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4289 return $string;
4290 }
4291 } elseif ($trunc == 'middle') {
4292 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4293 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4294 $size1 = round($size / 2);
4295 $size2 = round($size / 2);
4296 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4297 } else {
4298 return $string;
4299 }
4300 } elseif ($trunc == 'left') {
4301 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4302 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4303 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4304 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4305 } else {
4306 return $string;
4307 }
4308 } elseif ($trunc == 'wrap') {
4309 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4310 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4311 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4312 } else {
4313 return $string;
4314 }
4315 } else {
4316 return 'BadParam3CallingDolTrunc';
4317 }
4318}
4319
4326function getPictoForType($key)
4327{
4328 // Set array with type -> picto
4329 $type2picto = array(
4330 'varchar'=>'font',
4331 'text'=>'font',
4332 'html'=>'code',
4333 'int'=>'sort-numeric-down',
4334 'double'=>'sort-numeric-down',
4335 'price'=>'currency',
4336 'pricecy'=>'multicurrency',
4337 'password' => 'key',
4338 'boolean'=>'check-square',
4339 'date'=>'calendar',
4340 'datetime'=>'calendar',
4341 'phone'=> 'phone',
4342 'mail'=> 'email',
4343 'url'=> 'url',
4344 'ip'=> 'country',
4345 'select' => 'list',
4346 'sellist' => 'list',
4347 'radio' => 'check-circle',
4348 'checkbox' => 'check-square',
4349 'chkbxlst' => 'check-square',
4350 'link' => 'link',
4351 'separate'=> 'minus'
4352 );
4353
4354 if (!empty($type2picto[$key])) {
4355 return img_picto('', $type2picto[$key], 'class="pictofixedwidth"');
4356 }
4357
4358 return img_picto('', 'generic', 'class="pictofixedwidth"');
4359}
4360
4361
4383function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4384{
4385 global $conf, $langs;
4386
4387 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4388 $url = DOL_URL_ROOT;
4389 $theme = isset($conf->theme) ? $conf->theme : null;
4390 $path = 'theme/'.$theme;
4391 if (empty($picto)) {
4392 $picto = 'generic';
4393 }
4394
4395 // Define fullpathpicto to use into src
4396 if ($pictoisfullpath) {
4397 // Clean parameters
4398 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4399 $picto .= '.png';
4400 }
4401 $fullpathpicto = $picto;
4402 $reg = array();
4403 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4404 $morecss .= ($morecss ? ' ' : '').$reg[1];
4405 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4406 }
4407 } else {
4408 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', (is_null($picto) ? '' : $picto));
4409 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4410 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4411
4412 if (strpos($pictowithouttext, 'fontawesome_') === 0 || strpos($pictowithouttext, 'fa-') === 0) {
4413 // This is a font awesome image 'fontawesome_xxx' or 'fa-xxx'
4414 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4415 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4416
4417 // Compatibility with old fontawesome versions
4418 if ($pictowithouttext == 'file-o') {
4419 $pictowithouttext = 'file';
4420 }
4421
4422 $pictowithouttextarray = explode('_', $pictowithouttext);
4423 $marginleftonlyshort = 0;
4424
4425 if (!empty($pictowithouttextarray[1])) {
4426 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4427 $fakey = 'fa-'.$pictowithouttextarray[0];
4428 $faprefix = empty($pictowithouttextarray[1]) ? 'fas' : $pictowithouttextarray[1];
4429 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4430 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4431 } else {
4432 $fakey = 'fa-'.$pictowithouttext;
4433 $faprefix = 'fas';
4434 $facolor = '';
4435 $fasize = '';
4436 }
4437
4438 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4439 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4440 $morestyle = '';
4441 $reg = array();
4442 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4443 $morecss .= ($morecss ? ' ' : '').$reg[1];
4444 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4445 }
4446 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4447 $morestyle = $reg[1];
4448 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4449 }
4450 $moreatt = trim($moreatt);
4451
4452 $enabledisablehtml = '<span class="'.$faprefix.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4453 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4454 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4455 $enabledisablehtml .= $titlealt;
4456 }*/
4457 $enabledisablehtml .= '</span>';
4458
4459 return $enabledisablehtml;
4460 }
4461
4462 if (empty($srconly) && in_array($pictowithouttext, array(
4463 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4464 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'angle-double-down', 'angle-double-up', 'asset',
4465 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building',
4466 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4467 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'code', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4468 'check-circle', 'check-square', 'currency', 'multicurrency',
4469 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies',
4470 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4471 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4472 'filter', 'file', 'file-o', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus', 'font',
4473 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4474 'hands-helping', 'help', 'holiday',
4475 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4476 'key', 'knowledgemanagement',
4477 'label', 'language', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4478 'margin', 'map-marker-alt', 'member', 'meeting', 'minus', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4479 'off', 'on', 'order',
4480 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4481 'stock', 'resize', 'service', 'stats',
4482 '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',
4483 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4484 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4485 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4486 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4487 'technic', 'ticket',
4488 'error', 'warning',
4489 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4490 'shapes', 'skill', 'square', 'sort-numeric-down', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4491 'tick', 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda',
4492 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4493 'conferenceorbooth', 'eventorganization',
4494 'stamp', 'signature'
4495 ))) {
4496 $fakey = $pictowithouttext;
4497 $facolor = '';
4498 $fasize = '';
4499 $fa = getDolGlobalString('MAIN_FONTAWESOME_ICON_STYLE', 'fas');
4500 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'))) {
4501 $fa = 'far';
4502 }
4503 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4504 $fa = 'fab';
4505 }
4506
4507 $arrayconvpictotofa = array(
4508 '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',
4509 'bank_account'=>'university',
4510 'bill'=>'file-invoice-dollar', 'billa'=>'file-excel', 'billr'=>'file-invoice-dollar', 'billd'=>'file-medical',
4511 'supplier_invoice'=>'file-invoice-dollar', 'supplier_invoicea'=>'file-excel', 'supplier_invoicer'=>'file-invoice-dollar', 'supplier_invoiced'=>'file-medical',
4512 'bom'=>'shapes',
4513 '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',
4514 'donation'=>'file-alt', 'dynamicprice'=>'hand-holding-usd',
4515 'setup'=>'cog', 'companies'=>'building', 'products'=>'cube', 'commercial'=>'suitcase', 'invoicing'=>'coins',
4516 'accounting'=>'search-dollar', 'category'=>'tag', 'dollyrevert'=>'dolly',
4517 'file-o'=>'file', 'generate'=>'plus-square', 'hrm'=>'user-tie', 'incoterm'=>'truck-loading',
4518 'margin'=>'calculator', 'members'=>'user-friends', 'ticket'=>'ticket-alt', 'globe'=>'external-link-alt', 'lot'=>'barcode',
4519 'email'=>'at', 'establishment'=>'building', 'edit'=>'pencil-alt', 'entity'=>'globe',
4520 'graph'=>'chart-line', 'grip_title'=>'arrows-alt', 'grip'=>'arrows-alt', 'help'=>'question-circle',
4521 'generic'=>'file', 'holiday'=>'umbrella-beach',
4522 'info'=>'info-circle', 'inventory'=>'boxes', 'intracommreport'=>'globe-europe', 'jobprofile'=>'cogs',
4523 'knowledgemanagement'=>'ticket-alt', 'label'=>'layer-group', 'line'=>'bars', 'loan'=>'money-bill-alt',
4524 'member'=>'user-alt', 'meeting'=>'chalkboard-teacher', 'mrp'=>'cubes', 'next'=>'arrow-alt-circle-right',
4525 'trip'=>'wallet', 'expensereport'=>'wallet', 'group'=>'users', 'movement'=>'people-carry',
4526 'sign-out'=>'sign-out-alt',
4527 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_warning'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star',
4528 'bank'=>'university', 'close_title'=>'times', 'delete'=>'trash', 'filter'=>'filter',
4529 'list-alt'=>'list-alt', 'calendarlist'=>'bars', 'calendar'=>'calendar-alt', 'calendarmonth'=>'calendar-alt', 'calendarweek'=>'calendar-week', 'calendarday'=>'calendar-day', 'calendarperuser'=>'table',
4530 'intervention'=>'ambulance', 'invoice'=>'file-invoice-dollar', 'order'=>'file-invoice',
4531 'error'=>'exclamation-triangle', 'warning'=>'exclamation-triangle',
4532 'other'=>'square',
4533 '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',
4534 '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',
4535 'recent' => 'check-square', 'reception'=>'dolly', 'recruitmentjobposition'=>'id-card-alt', 'recruitmentcandidature'=>'id-badge',
4536 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature',
4537 'refresh'=>'redo', 'region'=>'map-marked', 'replacement'=>'exchange-alt', 'resource'=>'laptop-house', 'recurring'=>'history',
4538 'service'=>'concierge-bell',
4539 'skill'=>'shapes', 'state'=>'map-marked-alt', 'security'=>'key', 'salary'=>'wallet', 'shipment'=>'dolly', 'stock'=>'box-open', 'stats' => 'chart-bar', 'split'=>'code-branch', 'stripe'=>'stripe-s',
4540 'supplier'=>'building', 'technic'=>'cogs',
4541 'timespent'=>'clock', 'tick' => 'check', 'title_setup'=>'tools', 'title_accountancy'=>'money-check-alt', 'title_bank'=>'university', 'title_hrm'=>'umbrella-beach',
4542 'title_agenda'=>'calendar-alt',
4543 'uncheck'=>'times', 'uparrow'=>'share', 'url'=>'external-link-alt', 'vat'=>'money-check-alt', 'vcard'=>'arrow-alt-circle-down',
4544 'jabber'=>'comment-o',
4545 'website'=>'globe-americas', 'workstation'=>'pallet', 'webhook'=>'bullseye', 'world'=>'globe', 'private'=>'user-lock',
4546 'conferenceorbooth'=>'chalkboard-teacher', 'eventorganization'=>'project-diagram'
4547 );
4548 if ($conf->currency == 'EUR') {
4549 $arrayconvpictotofa['currency'] = 'euro-sign';
4550 $arrayconvpictotofa['multicurrency'] = 'dollar-sign';
4551 } else {
4552 $arrayconvpictotofa['currency'] = 'dollar-sign';
4553 $arrayconvpictotofa['multicurrency'] = 'euro-sign';
4554 }
4555 if ($pictowithouttext == 'off') {
4556 $fakey = 'fa-square';
4557 $fasize = '1.3em';
4558 } elseif ($pictowithouttext == 'on') {
4559 $fakey = 'fa-check-square';
4560 $fasize = '1.3em';
4561 } elseif ($pictowithouttext == 'listlight') {
4562 $fakey = 'fa-download';
4563 $marginleftonlyshort = 1;
4564 } elseif ($pictowithouttext == 'printer') {
4565 $fakey = 'fa-print';
4566 $fasize = '1.2em';
4567 } elseif ($pictowithouttext == 'note') {
4568 $fakey = 'fa-sticky-note';
4569 $marginleftonlyshort = 1;
4570 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
4571 $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');
4572 $fakey = 'fa-'.$convertarray[$pictowithouttext];
4573 if (preg_match('/selected/', $pictowithouttext)) {
4574 $facolor = '#888';
4575 }
4576 $marginleftonlyshort = 1;
4577 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
4578 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
4579 } else {
4580 $fakey = 'fa-'.$pictowithouttext;
4581 }
4582
4583 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment'))) {
4584 $morecss .= ' em092';
4585 }
4586 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
4587 $morecss .= ' em088';
4588 }
4589 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
4590 $morecss .= ' em080';
4591 }
4592
4593 // Define $marginleftonlyshort
4594 $arrayconvpictotomarginleftonly = array(
4595 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
4596 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
4597 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
4598 );
4599 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
4600 $marginleftonlyshort = 0;
4601 }
4602
4603 // Add CSS
4604 $arrayconvpictotomorcess = array(
4605 'action'=>'infobox-action', 'account'=>'infobox-bank_account', 'accounting_account'=>'infobox-bank_account', 'accountline'=>'infobox-bank_account', 'accountancy'=>'infobox-bank_account', 'asset'=>'infobox-bank_account',
4606 'bank_account'=>'infobox-bank_account',
4607 'bill'=>'infobox-commande', 'billa'=>'infobox-commande', 'billr'=>'infobox-commande', 'billd'=>'infobox-commande',
4608 'margin'=>'infobox-bank_account', 'conferenceorbooth'=>'infobox-project',
4609 'cash-register'=>'infobox-bank_account', 'contract'=>'infobox-contrat', 'check'=>'font-status4', 'collab'=>'infobox-action', 'conversation'=>'infobox-contrat',
4610 'donation'=>'infobox-commande', 'dolly'=>'infobox-commande', 'dollyrevert'=>'flip infobox-order_supplier',
4611 'ecm'=>'infobox-action', 'eventorganization'=>'infobox-project',
4612 'hrm'=>'infobox-adherent', 'group'=>'infobox-adherent', 'intervention'=>'infobox-contrat',
4613 'incoterm'=>'infobox-supplier_proposal',
4614 'currency'=>'infobox-bank_account', 'multicurrency'=>'infobox-bank_account',
4615 'members'=>'infobox-adherent', 'member'=>'infobox-adherent', 'money-bill-alt'=>'infobox-bank_account',
4616 'order'=>'infobox-commande',
4617 'user'=>'infobox-adherent', 'users'=>'infobox-adherent',
4618 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_warning'=>'font-status4 warning', 'switch_on_red'=>'font-status8',
4619 'holiday'=>'infobox-holiday', 'info'=>'opacityhigh', 'invoice'=>'infobox-commande',
4620 'knowledgemanagement'=>'infobox-contrat rotate90', 'loan'=>'infobox-bank_account',
4621 'payment'=>'infobox-bank_account', 'payment_vat'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'pos'=>'infobox-bank_account', 'project'=>'infobox-project', 'projecttask'=>'infobox-project',
4622 'propal'=>'infobox-propal', 'proposal'=>'infobox-propal','private'=>'infobox-project',
4623 'reception'=>'flip', 'recruitmentjobposition'=>'infobox-adherent', 'recruitmentcandidature'=>'infobox-adherent',
4624 'resource'=>'infobox-action',
4625 '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',
4626 'supplier'=>'infobox-order_supplier', 'supplier_order'=>'infobox-order_supplier', 'supplier_proposal'=>'infobox-supplier_proposal',
4627 'ticket'=>'infobox-contrat', 'title_accountancy'=>'infobox-bank_account', 'title_hrm'=>'infobox-holiday', 'expensereport'=>'infobox-expensereport', 'trip'=>'infobox-expensereport', 'title_agenda'=>'infobox-action',
4628 'vat'=>'infobox-bank_account',
4629 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
4630 'list-alt'=>'imgforviewmode', 'calendar'=>'imgforviewmode', 'calendarweek'=>'imgforviewmode', 'calendarmonth'=>'imgforviewmode', 'calendarday'=>'imgforviewmode', 'calendarperuser'=>'imgforviewmode'
4631 );
4632 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4633 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
4634 }
4635
4636 // Define $color
4637 $arrayconvpictotocolor = array(
4638 'address'=>'#6c6aa8', 'building'=>'#6c6aa8', 'bom'=>'#a69944',
4639 'clone'=>'#999', 'cog'=>'#999', 'companies'=>'#6c6aa8', 'company'=>'#6c6aa8', 'contact'=>'#6c6aa8', 'cron'=>'#555',
4640 'dynamicprice'=>'#a69944',
4641 'edit'=>'#444', 'note'=>'#999', 'error'=>'', 'help'=>'#bbb', 'listlight'=>'#999', 'language'=>'#555',
4642 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
4643 'lock'=>'#ddd', 'lot'=>'#a69944',
4644 'map-marker-alt'=>'#aaa', 'mrp'=>'#a69944', 'product'=>'#a69944', 'service'=>'#a69944', 'inventory'=>'#a69944', 'stock'=>'#a69944', 'movement'=>'#a69944',
4645 'other'=>'#ddd', 'world'=>'#986c6a',
4646 'partnership'=>'#6c6aa8', 'playdisabled'=>'#ccc', 'printer'=>'#444', 'projectpub'=>'#986c6a', 'reception'=>'#a69944', 'resize'=>'#444', 'rss'=>'#cba',
4647 //'shipment'=>'#a69944',
4648 'security'=>'#999', 'square'=>'#888', 'stop-circle'=>'#888', 'stats'=>'#444', 'switch_off'=>'#999',
4649 'technic' => '#999', 'tick' => '#282', 'timespent' => '#555',
4650 'uncheck'=>'#800', 'uparrow'=>'#555', 'user-cog'=>'#999', 'country'=>'#aaa', 'globe-americas'=>'#aaa', 'region'=>'#aaa', 'state'=>'#aaa',
4651 'website'=>'#304', 'workstation'=>'#a69944'
4652 );
4653 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4654 $facolor = $arrayconvpictotocolor[$pictowithouttext];
4655 }
4656
4657 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4658 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4659 $morestyle = '';
4660 $reg = array();
4661 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4662 $morecss .= ($morecss ? ' ' : '').$reg[1];
4663 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4664 }
4665 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4666 $morestyle = $reg[1];
4667 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4668 }
4669 $moreatt = trim($moreatt);
4670
4671 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4672 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4673 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4674 $enabledisablehtml .= $titlealt;
4675 }*/
4676 $enabledisablehtml .= '</span>';
4677
4678 return $enabledisablehtml;
4679 }
4680
4681 if (getDolGlobalString('MAIN_OVERWRITE_THEME_PATH')) {
4682 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_PATH') . '/theme/'.$theme; // If the theme does not have the same name as the module
4683 } elseif (getDolGlobalString('MAIN_OVERWRITE_THEME_RES')) {
4684 $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
4685 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
4686 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
4687 }
4688
4689 // If we ask an image into $url/$mymodule/img (instead of default path)
4690 $regs = array();
4691 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
4692 $picto = $regs[1];
4693 $path = $regs[2]; // $path is $mymodule
4694 }
4695
4696 // Clean parameters
4697 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4698 $picto .= '.png';
4699 }
4700 // If alt path are defined, define url where img file is, according to physical path
4701 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
4702 foreach ($conf->file->dol_document_root as $type => $dirroot) {
4703 if ($type == 'main') {
4704 continue;
4705 }
4706 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommanded
4707 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
4708 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
4709 break;
4710 }
4711 }
4712
4713 // $url is '' or '/custom', $path is current theme or
4714 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
4715 }
4716
4717 if ($srconly) {
4718 return $fullpathpicto;
4719 }
4720
4721 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
4722 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
4723}
4724
4738function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0)
4739{
4740 if (strpos($picto, '^') === 0) {
4741 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
4742 } else {
4743 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
4744 }
4745}
4746
4758function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
4759{
4760 global $conf;
4761
4762 if (is_numeric($picto)) {
4763 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
4764 //$picto = $leveltopicto[$picto];
4765 return '<i class="fa fa-weather-level'.$picto.'"></i>';
4766 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4767 $picto .= '.png';
4768 }
4769
4770 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
4771
4772 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
4773}
4774
4786function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
4787{
4788 global $conf;
4789
4790 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4791 $picto .= '.png';
4792 }
4793
4794 if ($pictoisfullpath) {
4795 $path = $picto;
4796 } else {
4797 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
4798
4799 if (getDolGlobalInt('MAIN_MODULE_CAN_OVERWRITE_COMMONICONS')) {
4800 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
4801
4802 if (file_exists($themepath)) {
4803 $path = $themepath;
4804 }
4805 }
4806 }
4807
4808 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
4809}
4810
4824function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
4825{
4826 global $langs;
4827
4828 if (empty($titlealt) || $titlealt == 'default') {
4829 if ($numaction == '-1' || $numaction == 'ST_NO') {
4830 $numaction = -1;
4831 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
4832 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
4833 $numaction = 0;
4834 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
4835 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
4836 $numaction = 1;
4837 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
4838 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
4839 $numaction = 2;
4840 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
4841 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
4842 $numaction = 3;
4843 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
4844 } else {
4845 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
4846 $numaction = 0;
4847 }
4848 }
4849 if (!is_numeric($numaction)) {
4850 $numaction = 0;
4851 }
4852
4853 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
4854}
4855
4863function img_pdf($titlealt = 'default', $size = 3)
4864{
4865 global $langs;
4866
4867 if ($titlealt == 'default') {
4868 $titlealt = $langs->trans('Show');
4869 }
4870
4871 return img_picto($titlealt, 'pdf'.$size.'.png');
4872}
4873
4881function img_edit_add($titlealt = 'default', $other = '')
4882{
4883 global $langs;
4884
4885 if ($titlealt == 'default') {
4886 $titlealt = $langs->trans('Add');
4887 }
4888
4889 return img_picto($titlealt, 'edit_add.png', $other);
4890}
4898function img_edit_remove($titlealt = 'default', $other = '')
4899{
4900 global $langs;
4901
4902 if ($titlealt == 'default') {
4903 $titlealt = $langs->trans('Remove');
4904 }
4905
4906 return img_picto($titlealt, 'edit_remove.png', $other);
4907}
4908
4917function img_edit($titlealt = 'default', $float = 0, $other = '')
4918{
4919 global $langs;
4920
4921 if ($titlealt == 'default') {
4922 $titlealt = $langs->trans('Modify');
4923 }
4924
4925 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
4926}
4927
4936function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
4937{
4938 global $langs;
4939
4940 if ($titlealt == 'default') {
4941 $titlealt = $langs->trans('View');
4942 }
4943
4944 $moreatt = ($float ? 'style="float: right" ' : '').$other;
4945
4946 return img_picto($titlealt, 'eye', $moreatt);
4947}
4948
4957function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
4958{
4959 global $langs;
4960
4961 if ($titlealt == 'default') {
4962 $titlealt = $langs->trans('Delete');
4963 }
4964
4965 return img_picto($titlealt, 'delete.png', $other, false, 0, 0, '', $morecss);
4966}
4967
4975function img_printer($titlealt = "default", $other = '')
4976{
4977 global $langs;
4978 if ($titlealt == "default") {
4979 $titlealt = $langs->trans("Print");
4980 }
4981 return img_picto($titlealt, 'printer.png', $other);
4982}
4983
4991function img_split($titlealt = 'default', $other = 'class="pictosplit"')
4992{
4993 global $langs;
4994
4995 if ($titlealt == 'default') {
4996 $titlealt = $langs->trans('Split');
4997 }
4998
4999 return img_picto($titlealt, 'split.png', $other);
5000}
5001
5009function img_help($usehelpcursor = 1, $usealttitle = 1)
5010{
5011 global $langs;
5012
5013 if ($usealttitle) {
5014 if (is_string($usealttitle)) {
5015 $usealttitle = dol_escape_htmltag($usealttitle);
5016 } else {
5017 $usealttitle = $langs->trans('Info');
5018 }
5019 }
5020
5021 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
5022}
5023
5030function img_info($titlealt = 'default')
5031{
5032 global $langs;
5033
5034 if ($titlealt == 'default') {
5035 $titlealt = $langs->trans('Informations');
5036 }
5037
5038 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
5039}
5040
5049function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
5050{
5051 global $langs;
5052
5053 if ($titlealt == 'default') {
5054 $titlealt = $langs->trans('Warning');
5055 }
5056
5057 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
5058 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
5059}
5060
5067function img_error($titlealt = 'default')
5068{
5069 global $langs;
5070
5071 if ($titlealt == 'default') {
5072 $titlealt = $langs->trans('Error');
5073 }
5074
5075 return img_picto($titlealt, 'error.png');
5076}
5077
5085function img_next($titlealt = 'default', $moreatt = '')
5086{
5087 global $langs;
5088
5089 if ($titlealt == 'default') {
5090 $titlealt = $langs->trans('Next');
5091 }
5092
5093 //return img_picto($titlealt, 'next.png', $moreatt);
5094 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5095}
5096
5104function img_previous($titlealt = 'default', $moreatt = '')
5105{
5106 global $langs;
5107
5108 if ($titlealt == 'default') {
5109 $titlealt = $langs->trans('Previous');
5110 }
5111
5112 //return img_picto($titlealt, 'previous.png', $moreatt);
5113 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5114}
5115
5124function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
5125{
5126 global $langs;
5127
5128 if ($titlealt == 'default') {
5129 $titlealt = $langs->trans('Down');
5130 }
5131
5132 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
5133}
5134
5143function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
5144{
5145 global $langs;
5146
5147 if ($titlealt == 'default') {
5148 $titlealt = $langs->trans('Up');
5149 }
5150
5151 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
5152}
5153
5162function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
5163{
5164 global $langs;
5165
5166 if ($titlealt == 'default') {
5167 $titlealt = $langs->trans('Left');
5168 }
5169
5170 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
5171}
5172
5181function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
5182{
5183 global $langs;
5184
5185 if ($titlealt == 'default') {
5186 $titlealt = $langs->trans('Right');
5187 }
5188
5189 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
5190}
5191
5199function img_allow($allow, $titlealt = 'default')
5200{
5201 global $langs;
5202
5203 if ($titlealt == 'default') {
5204 $titlealt = $langs->trans('Active');
5205 }
5206
5207 if ($allow == 1) {
5208 return img_picto($titlealt, 'tick.png');
5209 }
5210
5211 return '-';
5212}
5213
5221function img_credit_card($brand, $morecss = null)
5222{
5223 if (is_null($morecss)) {
5224 $morecss = 'fa-2x';
5225 }
5226
5227 if ($brand == 'visa' || $brand == 'Visa') {
5228 $brand = 'cc-visa';
5229 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5230 $brand = 'cc-mastercard';
5231 } elseif ($brand == 'amex' || $brand == 'American Express') {
5232 $brand = 'cc-amex';
5233 } elseif ($brand == 'discover' || $brand == 'Discover') {
5234 $brand = 'cc-discover';
5235 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5236 $brand = 'cc-jcb';
5237 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5238 $brand = 'cc-diners-club';
5239 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5240 $brand = 'credit-card';
5241 }
5242
5243 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5244}
5245
5254function img_mime($file, $titlealt = '', $morecss = '')
5255{
5256 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5257
5258 $mimetype = dol_mimetype($file, '', 1);
5259 $mimeimg = dol_mimetype($file, '', 2);
5260 $mimefa = dol_mimetype($file, '', 4);
5261
5262 if (empty($titlealt)) {
5263 $titlealt = 'Mime type: '.$mimetype;
5264 }
5265
5266 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5267 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5268}
5269
5270
5278function img_search($titlealt = 'default', $other = '')
5279{
5280 global $conf, $langs;
5281
5282 if ($titlealt == 'default') {
5283 $titlealt = $langs->trans('Search');
5284 }
5285
5286 $img = img_picto($titlealt, 'search.png', $other, false, 1);
5287
5288 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5289 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5290
5291 return $input;
5292}
5293
5301function img_searchclear($titlealt = 'default', $other = '')
5302{
5303 global $conf, $langs;
5304
5305 if ($titlealt == 'default') {
5306 $titlealt = $langs->trans('Search');
5307 }
5308
5309 $img = img_picto($titlealt, 'searchclear.png', $other, false, 1);
5310
5311 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5312 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5313
5314 return $input;
5315}
5316
5328function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '')
5329{
5330 global $conf, $langs;
5331
5332 if ($infoonimgalt) {
5333 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5334 } else {
5335 if (empty($conf->use_javascript_ajax)) {
5336 $textfordropdown = '';
5337 }
5338
5339 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5340 $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>');
5341
5342 if ($textfordropdown) {
5343 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5344 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5345 jQuery(document).ready(function() {
5346 jQuery(".'.$class.'text").click(function() {
5347 console.log("toggle text");
5348 jQuery(".'.$class.'").toggle();
5349 });
5350 });
5351 </script>';
5352
5353 $result = $tmpresult.$result;
5354 }
5355 }
5356
5357 return $result;
5358}
5359
5360
5372function dol_print_error($db = '', $error = '', $errors = null)
5373{
5374 global $conf, $langs, $argv;
5375 global $dolibarr_main_prod;
5376
5377 $out = '';
5378 $syslog = '';
5379
5380 // If error occurs before the $lang object was loaded
5381 if (!$langs) {
5382 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5383 $langs = new Translate('', $conf);
5384 $langs->load("main");
5385 }
5386
5387 // Load translation files required by the error messages
5388 $langs->loadLangs(array('main', 'errors'));
5389
5390 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5391 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5392 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5393 $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";
5394 }
5395 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5396
5397 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5398 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5399 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5400 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5401 }
5402 if (function_exists("phpversion")) {
5403 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5404 }
5405 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5406 if (function_exists("php_uname")) {
5407 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5408 }
5409 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5410 $out .= "<br>\n";
5411 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5412 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5413 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5414 $out .= "<br>\n";
5415 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5416 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5417 } else { // Mode CLI
5418 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5419 $syslog .= "pid=".dol_getmypid();
5420 }
5421
5422 if (!empty($conf->modules)) {
5423 $out .= "<b>".$langs->trans("Modules").":</b> ".join(', ', $conf->modules)."<br>\n";
5424 }
5425
5426 if (is_object($db)) {
5427 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5428 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5429 $lastqueryerror = $db->lastqueryerror();
5430 if (!utf8_check($lastqueryerror)) {
5431 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5432 }
5433 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5434 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5435 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5436 $out .= "<br>\n";
5437 } else { // Mode CLI
5438 // No dol_escape_htmltag for output, we are in CLI mode
5439 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5440 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5441 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5442 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5443 }
5444 $syslog .= ", sql=".$db->lastquery();
5445 $syslog .= ", db_error=".$db->lasterror();
5446 }
5447
5448 if ($error || $errors) {
5449 $langs->load("errors");
5450
5451 // Merge all into $errors array
5452 if (is_array($error) && is_array($errors)) {
5453 $errors = array_merge($error, $errors);
5454 } elseif (is_array($error)) {
5455 $errors = $error;
5456 } elseif (is_array($errors)) {
5457 $errors = array_merge(array($error), $errors);
5458 } else {
5459 $errors = array_merge(array($error), array($errors));
5460 }
5461
5462 foreach ($errors as $msg) {
5463 if (empty($msg)) {
5464 continue;
5465 }
5466 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5467 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5468 } else { // Mode CLI
5469 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5470 }
5471 $syslog .= ", msg=".$msg;
5472 }
5473 }
5474 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5475 xdebug_print_function_stack();
5476 $out .= '<b>XDebug informations:</b>'."<br>\n";
5477 $out .= 'File: '.xdebug_call_file()."<br>\n";
5478 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5479 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5480 $out .= "<br>\n";
5481 }
5482
5483 // Return a http header with error code if possible
5484 if (!headers_sent()) {
5485 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5486 top_httphead();
5487 }
5488 //http_response_code(500); // If we use 500, message is not ouput with some command line tools
5489 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
5490 }
5491
5492 if (empty($dolibarr_main_prod)) {
5493 print $out;
5494 } else {
5495 if (empty($langs->defaultlang)) {
5496 $langs->setDefaultLang();
5497 }
5498 $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.
5499 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5500 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";
5501 print $langs->trans("DolibarrHasDetectedError").'. ';
5502 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5503 if (!defined("MAIN_CORE_ERROR")) {
5504 define("MAIN_CORE_ERROR", 1);
5505 }
5506 }
5507
5508 dol_syslog("Error ".$syslog, LOG_ERR);
5509}
5510
5521function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5522{
5523 global $langs, $conf;
5524
5525 if (empty($email)) {
5526 $email = $conf->global->MAIN_INFO_SOCIETE_MAIL;
5527 }
5528
5529 $langs->load("errors");
5530 $now = dol_now();
5531
5532 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5533 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5534 if ($errormessage) {
5535 print '<br><br>'.$errormessage;
5536 }
5537 if (is_array($errormessages) && count($errormessages)) {
5538 foreach ($errormessages as $mesgtoshow) {
5539 print '<br><br>'.$mesgtoshow;
5540 }
5541 }
5542 print '</div></div>';
5543}
5544
5561function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
5562{
5563 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
5564}
5565
5584function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
5585{
5586 global $conf, $langs, $form;
5587 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
5588
5589 if ($moreattrib == 'class="right"') {
5590 $prefix .= 'right '; // For backward compatibility
5591 }
5592
5593 $sortorder = strtoupper($sortorder);
5594 $out = '';
5595 $sortimg = '';
5596
5597 $tag = 'th';
5598 if ($thead == 2) {
5599 $tag = 'div';
5600 }
5601
5602 $tmpsortfield = explode(',', $sortfield);
5603 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
5604 $tmpfield = explode(',', $field);
5605 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
5606
5607 if (!getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle)) {
5608 $prefix = 'wrapcolumntitle '.$prefix;
5609 }
5610
5611 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
5612 // If field is used as sort criteria we use a specific css class liste_titre_sel
5613 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
5614 $liste_titre = 'liste_titre';
5615 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
5616 $liste_titre = 'liste_titre_sel';
5617 }
5618
5619 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
5620 //$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)).'"' : '');
5621 $tagstart .= ($name && !getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
5622 $tagstart .= '>';
5623
5624 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5625 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5626 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5627 $options = preg_replace('/&+/i', '&', $options);
5628 if (!preg_match('/^&/', $options)) {
5629 $options = '&'.$options;
5630 }
5631
5632 $sortordertouseinlink = '';
5633 if ($field1 != $sortfield1) { // We are on another field than current sorted field
5634 if (preg_match('/^DESC/i', $sortorder)) {
5635 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5636 } else { // We reverse the var $sortordertouseinlink
5637 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5638 }
5639 } else { // We are on field that is the first current sorting criteria
5640 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
5641 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5642 } else {
5643 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5644 }
5645 }
5646 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
5647 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
5648 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5649 $out .= '>';
5650 }
5651 if ($tooltip) {
5652 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
5653 if (preg_match('/:\w+$/', $tooltip)) {
5654 $tmptooltip = explode(':', $tooltip);
5655 } else {
5656 $tmptooltip = array($tooltip);
5657 }
5658 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
5659 } else {
5660 $out .= $langs->trans($name);
5661 }
5662
5663 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5664 $out .= '</a>';
5665 }
5666
5667 if (empty($thead) && $field) { // If this is a sort field
5668 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5669 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5670 $options = preg_replace('/&+/i', '&', $options);
5671 if (!preg_match('/^&/', $options)) {
5672 $options = '&'.$options;
5673 }
5674
5675 if (!$sortorder || ($field1 != $sortfield1)) {
5676 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5677 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5678 } else {
5679 if (preg_match('/^DESC/', $sortorder)) {
5680 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5681 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
5682 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
5683 }
5684 if (preg_match('/^ASC/', $sortorder)) {
5685 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
5686 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5687 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
5688 }
5689 }
5690 }
5691
5692 $tagend = '</'.$tag.'>';
5693
5694 $out = $tagstart.$sortimg.$out.$tagend;
5695
5696 return $out;
5697}
5698
5707function print_titre($title)
5708{
5709 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
5710
5711 print '<div class="titre">'.$title.'</div>';
5712}
5713
5725function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
5726{
5727 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
5728}
5729
5743function load_fiche_titre($titre, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
5744{
5745 global $conf;
5746
5747 $return = '';
5748
5749 if ($picto == 'setup') {
5750 $picto = 'generic';
5751 }
5752
5753 $return .= "\n";
5754 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
5755 $return .= '<tr class="titre">';
5756 if ($picto) {
5757 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
5758 }
5759 $return .= '<td class="nobordernopadding valignmiddle col-title">';
5760 $return .= '<div class="titre inline-block">'.$titre.'</div>';
5761 $return .= '</td>';
5762 if (dol_strlen($morehtmlcenter)) {
5763 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5764 }
5765 if (dol_strlen($morehtmlright)) {
5766 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
5767 }
5768 $return .= '</tr></table>'."\n";
5769
5770 return $return;
5771}
5772
5796function 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 = '')
5797{
5798 global $conf;
5799
5800 $savlimit = $limit;
5801 $savtotalnboflines = $totalnboflines;
5802 $totalnboflines = abs((int) $totalnboflines);
5803
5804 $page = (int) $page;
5805
5806 if ($picto == 'setup') {
5807 $picto = 'title_setup.png';
5808 }
5809 if (($conf->browser->name == 'ie') && $picto == 'generic') {
5810 $picto = 'title.gif';
5811 }
5812 if ($limit < 0) {
5813 $limit = $conf->liste_limit;
5814 }
5815
5816 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
5817 $nextpage = 1;
5818 } else {
5819 $nextpage = 0;
5820 }
5821 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
5822
5823 print "\n";
5824 print "<!-- Begin title -->\n";
5825 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
5826
5827 // Left
5828
5829 if ($picto && $titre) {
5830 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
5831 }
5832
5833 print '<td class="nobordernopadding valignmiddle col-title">';
5834 print '<div class="titre inline-block">'.$titre;
5835 if (!empty($titre) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
5836 print '<span class="opacitymedium colorblack paddingleft">('.$totalnboflines.')</span>';
5837 }
5838 print '</div></td>';
5839
5840 // Center
5841 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
5842 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5843 }
5844
5845 // Right
5846 print '<td class="nobordernopadding valignmiddle right col-right">';
5847 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
5848 if ($sortfield) {
5849 $options .= "&sortfield=".urlencode($sortfield);
5850 }
5851 if ($sortorder) {
5852 $options .= "&sortorder=".urlencode($sortorder);
5853 }
5854 // Show navigation bar
5855 $pagelist = '';
5856 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
5857 if ($totalnboflines) { // If we know total nb of lines
5858 // Define nb of extra page links before and after selected page + ... + first or last
5859 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
5860
5861 if ($limit > 0) {
5862 $nbpages = ceil($totalnboflines / $limit);
5863 } else {
5864 $nbpages = 1;
5865 }
5866 $cpt = ($page - $maxnbofpage);
5867 if ($cpt < 0) {
5868 $cpt = 0;
5869 }
5870
5871 if ($cpt >= 1) {
5872 if (empty($pagenavastextinput)) {
5873 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=0'.$options.'">1</a></li>';
5874 if ($cpt > 2) {
5875 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5876 } elseif ($cpt == 2) {
5877 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=1'.$options.'">2</a></li>';
5878 }
5879 }
5880 }
5881
5882 do {
5883 if ($pagenavastextinput) {
5884 if ($cpt == $page) {
5885 $pagelist .= '<li class="pagination"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
5886 $pagelist .= '/';
5887 }
5888 } else {
5889 if ($cpt == $page) {
5890 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
5891 } else {
5892 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
5893 }
5894 }
5895 $cpt++;
5896 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
5897
5898 if (empty($pagenavastextinput)) {
5899 if ($cpt < $nbpages) {
5900 if ($cpt < $nbpages - 2) {
5901 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5902 } elseif ($cpt == $nbpages - 2) {
5903 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
5904 }
5905 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5906 }
5907 } else {
5908 //var_dump($page.' '.$cpt.' '.$nbpages);
5909 $pagelist .= '<li class="pagination paginationlastpage"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5910 }
5911 } else {
5912 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
5913 }
5914 }
5915
5916 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
5917 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
5918 }
5919
5920 // js to autoselect page field on focus
5921 if ($pagenavastextinput) {
5922 print ajax_autoselect('.pageplusone');
5923 }
5924
5925 print '</td>';
5926 print '</tr>';
5927
5928 print '</table>'."\n";
5929
5930 // Center
5931 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
5932 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
5933 }
5934
5935 print "<!-- End title -->\n\n";
5936}
5937
5954function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
5955{
5956 global $conf, $langs;
5957
5958 print '<div class="pagination"><ul>';
5959 if ($beforearrows) {
5960 print '<li class="paginationbeforearrows">';
5961 print $beforearrows;
5962 print '</li>';
5963 }
5964
5965 if (empty($hidenavigation)) {
5966 if ((int) $limit > 0 && empty($hideselectlimit)) {
5967 $pagesizechoices = '10:10,15:15,20:20,30:30,40:40,50:50,100:100,250:250,500:500,1000:1000';
5968 $pagesizechoices .= ',5000:5000,10000:10000,20000:20000';
5969 //$pagesizechoices.=',0:'.$langs->trans("All"); // Not yet supported
5970 //$pagesizechoices.=',2:2';
5971 if (getDolGlobalString('MAIN_PAGESIZE_CHOICES')) {
5972 $pagesizechoices = $conf->global->MAIN_PAGESIZE_CHOICES;
5973 }
5974
5975 print '<li class="pagination">';
5976 print '<select class="flat selectlimit" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
5977 $tmpchoice = explode(',', $pagesizechoices);
5978 $tmpkey = $limit.':'.$limit;
5979 if (!in_array($tmpkey, $tmpchoice)) {
5980 $tmpchoice[] = $tmpkey;
5981 }
5982 $tmpkey = $conf->liste_limit.':'.$conf->liste_limit;
5983 if (!in_array($tmpkey, $tmpchoice)) {
5984 $tmpchoice[] = $tmpkey;
5985 }
5986 asort($tmpchoice, SORT_NUMERIC);
5987 foreach ($tmpchoice as $val) {
5988 $selected = '';
5989 $tmp = explode(':', $val);
5990 $key = $tmp[0];
5991 $val = $tmp[1];
5992 if ($key != '' && $val != '') {
5993 if ((int) $key == (int) $limit) {
5994 $selected = ' selected="selected"';
5995 }
5996 print '<option name="'.$key.'"'.$selected.'>'.dol_escape_htmltag($val).'</option>'."\n";
5997 }
5998 }
5999 print '</select>';
6000 if ($conf->use_javascript_ajax) {
6001 print '<!-- JS CODE TO ENABLE select limit to launch submit of page -->
6002 <script>
6003 jQuery(document).ready(function () {
6004 jQuery(".selectlimit").change(function() {
6005 console.log("Change limit. Send submit");
6006 $(this).parents(\'form:first\').submit();
6007 });
6008 });
6009 </script>
6010 ';
6011 }
6012 print '</li>';
6013 }
6014 if ($page > 0) {
6015 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>';
6016 }
6017 if ($betweenarrows) {
6018 print '<!--<div class="betweenarrows nowraponall inline-block">-->';
6019 print $betweenarrows;
6020 print '<!--</div>-->';
6021 }
6022 if ($nextpage > 0) {
6023 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>';
6024 }
6025 if ($afterarrows) {
6026 print '<li class="paginationafterarrows">';
6027 print $afterarrows;
6028 print '</li>';
6029 }
6030 }
6031 print '</ul></div>'."\n";
6032}
6033
6034
6046function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, $html = 0)
6047{
6048 $morelabel = '';
6049
6050 if (preg_match('/%/', $rate)) {
6051 $rate = str_replace('%', '', $rate);
6052 $addpercent = true;
6053 }
6054 $reg = array();
6055 if (preg_match('/\‍((.*)\‍)/', $rate, $reg)) {
6056 $morelabel = ' ('.$reg[1].')';
6057 $rate = preg_replace('/\s*'.preg_quote($morelabel, '/').'/', '', $rate);
6058 $morelabel = ' '.($html ? '<span class="opacitymedium">' : '').'('.$reg[1].')'.($html ? '</span>' : '');
6059 }
6060 if (preg_match('/\*/', $rate)) {
6061 $rate = str_replace('*', '', $rate);
6062 $info_bits |= 1;
6063 }
6064
6065 // If rate is '9/9/9' we don't change it. If rate is '9.000' we apply price()
6066 if (!preg_match('/\//', $rate)) {
6067 $ret = price($rate, 0, '', 0, 0).($addpercent ? '%' : '');
6068 } else {
6069 // TODO Split on / and output with a price2num to have clean numbers without ton of 000.
6070 $ret = $rate.($addpercent ? '%' : '');
6071 }
6072 if (($info_bits & 1) && $usestarfornpr >= 0) {
6073 $ret .= ' *';
6074 }
6075 $ret .= $morelabel;
6076 return $ret;
6077}
6078
6079
6095function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1, $currency_code = '')
6096{
6097 global $langs, $conf;
6098
6099 // Clean parameters
6100 if (empty($amount)) {
6101 $amount = 0; // To have a numeric value if amount not defined or = ''
6102 }
6103 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number)
6104 if ($rounding == -1) {
6105 $rounding = min(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), getDolGlobalString('MAIN_MAX_DECIMALS_TOT'));
6106 }
6107 $nbdecimal = $rounding;
6108
6109 if ($outlangs === 'none') {
6110 // Use international separators
6111 $dec = '.';
6112 $thousand = '';
6113 } else {
6114 // Output separators by default (french)
6115 $dec = ',';
6116 $thousand = ' ';
6117
6118 // If $outlangs not forced, we use use language
6119 if (!is_object($outlangs)) {
6120 $outlangs = $langs;
6121 }
6122
6123 if ($outlangs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6124 $dec = $outlangs->transnoentitiesnoconv("SeparatorDecimal");
6125 }
6126 if ($outlangs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6127 $thousand = $outlangs->transnoentitiesnoconv("SeparatorThousand");
6128 }
6129 if ($thousand == 'None') {
6130 $thousand = '';
6131 } elseif ($thousand == 'Space') {
6132 $thousand = ' ';
6133 }
6134 }
6135 //print "outlangs=".$outlangs->defaultlang." amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6136
6137 //print "amount=".$amount."-";
6138 $amount = str_replace(',', '.', $amount); // should be useless
6139 //print $amount."-";
6140 $datas = explode('.', $amount);
6141 $decpart = isset($datas[1]) ? $datas[1] : '';
6142 $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
6143 //print "decpart=".$decpart."<br>";
6144 $end = '';
6145
6146 // We increase nbdecimal if there is more decimal than asked (to not loose information)
6147 if (dol_strlen($decpart) > $nbdecimal) {
6148 $nbdecimal = dol_strlen($decpart);
6149 }
6150
6151 // If nbdecimal is higher than max to show
6152 $nbdecimalmaxshown = (int) str_replace('...', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'));
6153 if ($trunc && $nbdecimal > $nbdecimalmaxshown) {
6154 $nbdecimal = $nbdecimalmaxshown;
6155 if (preg_match('/\.\.\./i', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'))) {
6156 // If output is truncated, we show ...
6157 $end = '...';
6158 }
6159 }
6160
6161 // If force rounding
6162 if ((string) $forcerounding != '-1') {
6163 if ($forcerounding === 'MU') {
6164 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_UNIT');
6165 } elseif ($forcerounding === 'MT') {
6166 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_TOT');
6167 } elseif ($forcerounding >= 0) {
6168 $nbdecimal = $forcerounding;
6169 }
6170 }
6171
6172 // Format number
6173 $output = number_format($amount, $nbdecimal, $dec, $thousand);
6174 if ($form) {
6175 $output = preg_replace('/\s/', '&nbsp;', $output);
6176 $output = preg_replace('/\'/', '&#039;', $output);
6177 }
6178 // Add symbol of currency if requested
6179 $cursymbolbefore = $cursymbolafter = '';
6180 if ($currency_code && is_object($outlangs)) {
6181 if ($currency_code == 'auto') {
6182 $currency_code = $conf->currency;
6183 }
6184
6185 $listofcurrenciesbefore = array('AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD', 'CRC', 'ZAR');
6186 $listoflanguagesbefore = array('nl_NL');
6187 if (in_array($currency_code, $listofcurrenciesbefore) || in_array($outlangs->defaultlang, $listoflanguagesbefore)) {
6188 $cursymbolbefore .= $outlangs->getCurrencySymbol($currency_code);
6189 } else {
6190 $tmpcur = $outlangs->getCurrencySymbol($currency_code);
6191 $cursymbolafter .= ($tmpcur == $currency_code ? ' '.$tmpcur : $tmpcur);
6192 }
6193 }
6194 $output = $cursymbolbefore.$output.$end.($cursymbolafter ? ' ' : '').$cursymbolafter;
6195
6196 return $output;
6197}
6198
6223function price2num($amount, $rounding = '', $option = 0)
6224{
6225 global $langs, $conf;
6226
6227 // Clean parameters
6228 if (is_null($amount)) {
6229 $amount = '';
6230 }
6231
6232 // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
6233 // Numbers must be '1234.56'
6234 // Decimal delimiter for PHP and database SQL requests must be '.'
6235 $dec = ',';
6236 $thousand = ' ';
6237 if (is_null($langs)) { // $langs is not defined, we use english values.
6238 $dec = '.';
6239 $thousand = ',';
6240 } else {
6241 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6242 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
6243 }
6244 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6245 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
6246 }
6247 }
6248 if ($thousand == 'None') {
6249 $thousand = '';
6250 } elseif ($thousand == 'Space') {
6251 $thousand = ' ';
6252 }
6253 //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6254
6255 // Convert value to universal number format (no thousand separator, '.' as decimal separator)
6256 if ($option != 1) { // If not a PHP number or unknown, we change or clean format
6257 //print "\n".'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'<br>';
6258 if (!is_numeric($amount)) {
6259 $amount = preg_replace('/[a-zA-Z\/\\\*\‍(\‍)<>\_]/', '', $amount);
6260 }
6261
6262 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
6263 $amount = str_replace($thousand, '', $amount);
6264 }
6265
6266 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6267 // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
6268 // So if number was already a good number, it is converted into local Dolibarr setup.
6269 if (is_numeric($amount)) {
6270 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6271 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6272 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6273 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6274 $amount = number_format($amount, $nbofdec, $dec, $thousand);
6275 }
6276 //print "QQ".$amount."<br>\n";
6277
6278 // Now make replace (the main goal of function)
6279 if ($thousand != ',' && $thousand != '.') {
6280 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6281 }
6282
6283 $amount = str_replace(' ', '', $amount); // To avoid spaces
6284 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6285 $amount = str_replace($dec, '.', $amount);
6286
6287 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6288 }
6289 //print ' XX'.$amount.' '.$rounding;
6290
6291 // Now, $amount is a real PHP float number. We make a rounding if required.
6292 if ($rounding) {
6293 $nbofdectoround = '';
6294 if ($rounding == 'MU') {
6295 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_UNIT;
6296 } elseif ($rounding == 'MT') {
6297 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_TOT;
6298 } elseif ($rounding == 'MS') {
6299 $nbofdectoround = isset($conf->global->MAIN_MAX_DECIMALS_STOCK) ? $conf->global->MAIN_MAX_DECIMALS_STOCK : 5;
6300 } elseif ($rounding == 'CU') {
6301 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), 8); // TODO Use param of currency
6302 } elseif ($rounding == 'CT') {
6303 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_TOT'), 8); // TODO Use param of currency
6304 } elseif (is_numeric($rounding)) {
6305 $nbofdectoround = (int) $rounding;
6306 }
6307
6308 //print " RR".$amount.' - '.$nbofdectoround.'<br>';
6309 if (dol_strlen($nbofdectoround)) {
6310 $amount = round(is_string($amount) ? (float) $amount : $amount, $nbofdectoround); // $nbofdectoround can be 0.
6311 } else {
6312 return 'ErrorBadParameterProvidedToFunction';
6313 }
6314 //print ' SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
6315
6316 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6317 // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
6318 if (is_numeric($amount)) {
6319 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6320 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6321 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6322 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6323 $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
6324 }
6325 //print "TT".$amount.'<br>';
6326
6327 // Always make replace because each math function (like round) replace
6328 // with local values and we want a number that has a SQL string format x.y
6329 if ($thousand != ',' && $thousand != '.') {
6330 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6331 }
6332
6333 $amount = str_replace(' ', '', $amount); // To avoid spaces
6334 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6335 $amount = str_replace($dec, '.', $amount);
6336
6337 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6338 }
6339
6340 return $amount;
6341}
6342
6355function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round = -1, $forceunitoutput = 'no', $use_short_label = 0)
6356{
6357 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
6358
6359 if (($forceunitoutput == 'no' && $dimension < 1 / 10000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -6)) {
6360 $dimension = $dimension * 1000000;
6361 $unit = $unit - 6;
6362 } elseif (($forceunitoutput == 'no' && $dimension < 1 / 10 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -3)) {
6363 $dimension = $dimension * 1000;
6364 $unit = $unit - 3;
6365 } elseif (($forceunitoutput == 'no' && $dimension > 100000000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 6)) {
6366 $dimension = $dimension / 1000000;
6367 $unit = $unit + 6;
6368 } elseif (($forceunitoutput == 'no' && $dimension > 100000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 3)) {
6369 $dimension = $dimension / 1000;
6370 $unit = $unit + 3;
6371 }
6372 // Special case when we want output unit into pound or ounce
6373 /* TODO
6374 if ($unit < 90 && $type == 'weight' && is_numeric($forceunitoutput) && (($forceunitoutput == 98) || ($forceunitoutput == 99))
6375 {
6376 $dimension = // convert dimension from standard unit into ounce or pound
6377 $unit = $forceunitoutput;
6378 }
6379 if ($unit > 90 && $type == 'weight' && is_numeric($forceunitoutput) && $forceunitoutput < 90)
6380 {
6381 $dimension = // convert dimension from standard unit into ounce or pound
6382 $unit = $forceunitoutput;
6383 }*/
6384
6385 $ret = price($dimension, 0, $outputlangs, 0, 0, $round);
6386 $ret .= ' '.measuringUnitString(0, $type, $unit, $use_short_label, $outputlangs);
6387
6388 return $ret;
6389}
6390
6391
6404function get_localtax($vatrate, $local, $thirdparty_buyer = "", $thirdparty_seller = "", $vatnpr = 0)
6405{
6406 global $db, $conf, $mysoc;
6407
6408 if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
6409 $thirdparty_seller = $mysoc;
6410 }
6411
6412 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);
6413
6414 $vatratecleaned = $vatrate;
6415 $reg = array();
6416 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6417 $vatratecleaned = trim($reg[1]);
6418 $vatratecode = $reg[2];
6419 }
6420
6421 /*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
6422 {
6423 return 0;
6424 }*/
6425
6426 // Some test to guess with no need to make database access
6427 if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
6428 if ($local == 1) {
6429 if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
6430 return 0;
6431 }
6432 if ($thirdparty_seller->id == $mysoc->id) {
6433 if (!$thirdparty_buyer->localtax1_assuj) {
6434 return 0;
6435 }
6436 } else {
6437 if (!$thirdparty_seller->localtax1_assuj) {
6438 return 0;
6439 }
6440 }
6441 }
6442
6443 if ($local == 2) {
6444 //if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
6445 if (!$mysoc->localtax2_assuj) {
6446 return 0; // If main vat is 0, IRPF may be different than 0.
6447 }
6448 if ($thirdparty_seller->id == $mysoc->id) {
6449 if (!$thirdparty_buyer->localtax2_assuj) {
6450 return 0;
6451 }
6452 } else {
6453 if (!$thirdparty_seller->localtax2_assuj) {
6454 return 0;
6455 }
6456 }
6457 }
6458 } else {
6459 if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
6460 return 0;
6461 }
6462 if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
6463 return 0;
6464 }
6465 }
6466
6467 // For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
6468 if (in_array($mysoc->country_code, array('ES'))) {
6469 $conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
6470 }
6471
6472 // Search local taxes
6473 if (getDolGlobalString('MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY')) {
6474 if ($local == 1) {
6475 if ($thirdparty_seller != $mysoc) {
6476 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6477 return $thirdparty_seller->localtax1_value;
6478 }
6479 } else { // i am the seller
6480 if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
6481 return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
6482 }
6483 }
6484 }
6485 if ($local == 2) {
6486 if ($thirdparty_seller != $mysoc) {
6487 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6488 // TODO We should also return value defined on thirdparty only if defined
6489 return $thirdparty_seller->localtax2_value;
6490 }
6491 } else { // i am the seller
6492 if (in_array($mysoc->country_code, array('ES'))) {
6493 return $thirdparty_buyer->localtax2_value;
6494 } else {
6495 return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
6496 }
6497 }
6498 }
6499 }
6500
6501 // By default, search value of local tax on line of common tax
6502 $sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
6503 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6504 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
6505 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6506 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6507 if (!empty($vatratecode)) {
6508 $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
6509 } else {
6510 $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
6511 }
6512
6513 $resql = $db->query($sql);
6514
6515 if ($resql) {
6516 $obj = $db->fetch_object($resql);
6517 if ($obj) {
6518 if ($local == 1) {
6519 return $obj->localtax1;
6520 } elseif ($local == 2) {
6521 return $obj->localtax2;
6522 }
6523 }
6524 }
6525
6526 return 0;
6527}
6528
6529
6538function isOnlyOneLocalTax($local)
6539{
6540 $tax = get_localtax_by_third($local);
6541
6542 $valors = explode(":", $tax);
6543
6544 if (count($valors) > 1) {
6545 return false;
6546 } else {
6547 return true;
6548 }
6549}
6550
6558{
6559 global $db, $mysoc;
6560
6561 $sql = " SELECT t.localtax".$local." as localtax";
6562 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_pays";
6563 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.active = 1 AND t.entity IN (".getEntity('c_tva').") AND t.taux = (";
6564 $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";
6565 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.entity IN (".getEntity('c_tva').") AND tt.active = 1)";
6566 $sql .= " AND t.localtax".$local."_type <> '0'";
6567 $sql .= " ORDER BY t.rowid DESC";
6568
6569 $resql = $db->query($sql);
6570 if ($resql) {
6571 $obj = $db->fetch_object($resql);
6572 if ($obj) {
6573 return $obj->localtax;
6574 } else {
6575 return '0';
6576 }
6577 }
6578
6579 return 'Error';
6580}
6581
6582
6594function getTaxesFromId($vatrate, $buyer = null, $seller = null, $firstparamisid = 1)
6595{
6596 global $db, $mysoc;
6597
6598 dol_syslog("getTaxesFromId vat id or rate = ".$vatrate);
6599
6600 // Search local taxes
6601 $sql = "SELECT t.rowid, t.code, t.taux as rate, t.recuperableonly as npr, t.accountancy_code_sell, t.accountancy_code_buy,";
6602 $sql .= " t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type";
6603 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6604 if ($firstparamisid) {
6605 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6606 } else {
6607 $vatratecleaned = $vatrate;
6608 $vatratecode = '';
6609 $reg = array();
6610 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6611 $vatratecleaned = $reg[1];
6612 $vatratecode = $reg[2];
6613 }
6614
6615 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6616 /*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 ??
6617 else $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";*/
6618 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";
6619 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6620 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6621 if ($vatratecode) {
6622 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6623 }
6624 }
6625
6626 $resql = $db->query($sql);
6627 if ($resql) {
6628 $obj = $db->fetch_object($resql);
6629 if ($obj) {
6630 return array(
6631 'rowid'=>$obj->rowid,
6632 'code'=>$obj->code,
6633 'rate'=>$obj->rate,
6634 'localtax1'=>$obj->localtax1,
6635 'localtax1_type'=>$obj->localtax1_type,
6636 'localtax2'=>$obj->localtax2,
6637 'localtax2_type'=>$obj->localtax2_type,
6638 'npr'=>$obj->npr,
6639 'accountancy_code_sell'=>$obj->accountancy_code_sell,
6640 'accountancy_code_buy'=>$obj->accountancy_code_buy
6641 );
6642 } else {
6643 return array();
6644 }
6645 } else {
6646 dol_print_error($db);
6647 }
6648
6649 return array();
6650}
6651
6668function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid = 0)
6669{
6670 global $db, $mysoc;
6671
6672 dol_syslog("getLocalTaxesFromRate vatrate=".$vatrate." local=".$local);
6673
6674 // Search local taxes
6675 $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";
6676 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6677 if ($firstparamisid) {
6678 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6679 } else {
6680 $vatratecleaned = $vatrate;
6681 $vatratecode = '';
6682 $reg = array();
6683 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "x.x (yy)"
6684 $vatratecleaned = $reg[1];
6685 $vatratecode = $reg[2];
6686 }
6687
6688 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6689 if (!empty($mysoc) && $mysoc->country_code == 'ES') {
6690 $countrycodetouse = ((empty($buyer) || empty($buyer->country_code)) ? $mysoc->country_code : $buyer->country_code);
6691 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'"; // local tax in spain use the buyer country ??
6692 } else {
6693 $countrycodetouse = ((empty($seller) || empty($seller->country_code)) ? $mysoc->country_code : $seller->country_code);
6694 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'";
6695 }
6696 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6697 if ($vatratecode) {
6698 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6699 }
6700 }
6701
6702 $resql = $db->query($sql);
6703 if ($resql) {
6704 $obj = $db->fetch_object($resql);
6705
6706 if ($obj) {
6707 $vateratestring = $obj->rate.($obj->code ? ' ('.$obj->code.')' : '');
6708
6709 if ($local == 1) {
6710 return array($obj->localtax1_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6711 } elseif ($local == 2) {
6712 return array($obj->localtax2_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6713 } else {
6714 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);
6715 }
6716 }
6717 }
6718
6719 return array();
6720}
6721
6732function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice = 0)
6733{
6734 global $db, $conf, $mysoc;
6735
6736 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6737
6738 $ret = 0;
6739 $found = 0;
6740
6741 if ($idprod > 0) {
6742 // Load product
6743 $product = new Product($db);
6744 $product->fetch($idprod);
6745
6746 if ($mysoc->country_code == $thirdpartytouse->country_code) {
6747 // If country to consider is ours
6748 if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object
6749 $result = $product->get_buyprice($idprodfournprice, 0, 0, 0);
6750 if ($result > 0) {
6751 $ret = $product->vatrate_supplier;
6752 if ($product->default_vat_code_supplier) {
6753 $ret .= ' ('.$product->default_vat_code_supplier.')';
6754 }
6755 $found = 1;
6756 }
6757 }
6758 if (!$found) {
6759 $ret = $product->tva_tx; // Default sales vat of product
6760 if ($product->default_vat_code) {
6761 $ret .= ' ('.$product->default_vat_code.')';
6762 }
6763 $found = 1;
6764 }
6765 } else {
6766 // TODO Read default product vat according to product and an other countrycode.
6767 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6768 }
6769 }
6770
6771 if (!$found) {
6772 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
6773 // 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).
6774 $sql = "SELECT t.taux as vat_rate, t.code as default_vat_code";
6775 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6776 $sql .= " WHERE t.active = 1 AND t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdpartytouse->country_code)."'";
6777 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6778 $sql .= " ORDER BY t.use_default DESC, t.taux DESC, t.code ASC, t.recuperableonly ASC";
6779 $sql .= $db->plimit(1);
6780
6781 $resql = $db->query($sql);
6782 if ($resql) {
6783 $obj = $db->fetch_object($resql);
6784 if ($obj) {
6785 $ret = $obj->vat_rate;
6786 if ($obj->default_vat_code) {
6787 $ret .= ' ('.$obj->default_vat_code.')';
6788 }
6789 }
6790 $db->free($resql);
6791 } else {
6792 dol_print_error($db);
6793 }
6794 } else {
6795 // Forced value if autodetect fails. MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS can be
6796 // '1.23'
6797 // or '1.23 (CODE)'
6798 $defaulttx = '';
6799 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
6800 $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6801 }
6802 /*if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6803 $defaultcode = $reg[1];
6804 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6805 }*/
6806
6807 $ret = $defaulttx;
6808 }
6809 }
6810
6811 dol_syslog("get_product_vat_for_country: ret=".$ret);
6812 return $ret;
6813}
6814
6824function get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
6825{
6826 global $db, $mysoc;
6827
6828 if (!class_exists('Product')) {
6829 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6830 }
6831
6832 $ret = 0;
6833 $found = 0;
6834
6835 if ($idprod > 0) {
6836 // Load product
6837 $product = new Product($db);
6838 $result = $product->fetch($idprod);
6839
6840 if ($mysoc->country_code == $thirdpartytouse->country_code) { // If selling country is ours
6841 /* Not defined yet, so we don't use this
6842 if ($local==1) $ret=$product->localtax1_tx;
6843 elseif ($local==2) $ret=$product->localtax2_tx;
6844 $found=1;
6845 */
6846 } else {
6847 // TODO Read default product vat according to product and another countrycode.
6848 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6849 }
6850 }
6851
6852 if (!$found) {
6853 // If vat of product for the country not found or not defined, we return higher vat of country.
6854 $sql = "SELECT taux as vat_rate, localtax1, localtax2";
6855 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6856 $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code='".$db->escape($thirdpartytouse->country_code)."'";
6857 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6858 $sql .= " ORDER BY t.taux DESC, t.recuperableonly ASC";
6859 $sql .= $db->plimit(1);
6860
6861 $resql = $db->query($sql);
6862 if ($resql) {
6863 $obj = $db->fetch_object($resql);
6864 if ($obj) {
6865 if ($local == 1) {
6866 $ret = $obj->localtax1;
6867 } elseif ($local == 2) {
6868 $ret = $obj->localtax2;
6869 }
6870 }
6871 } else {
6872 dol_print_error($db);
6873 }
6874 }
6875
6876 dol_syslog("get_product_localtax_for_country: ret=".$ret);
6877 return $ret;
6878}
6879
6896function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6897{
6898 global $conf;
6899
6900 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6901
6902 // Note: possible values for tva_assuj are 0/1 or franchise/reel
6903 $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;
6904
6905 $seller_country_code = $thirdparty_seller->country_code;
6906 $seller_in_cee = isInEEC($thirdparty_seller);
6907
6908 $buyer_country_code = $thirdparty_buyer->country_code;
6909 $buyer_in_cee = isInEEC($thirdparty_buyer);
6910
6911 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 : ''));
6912
6913 // 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)
6914 // we use the buyer VAT.
6915 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) {
6916 if ($seller_in_cee && $buyer_in_cee) {
6917 $isacompany = $thirdparty_buyer->isACompany();
6918 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6919 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6920 if (!isValidVATID($thirdparty_buyer)) {
6921 $isacompany = 0;
6922 }
6923 }
6924
6925 if (!$isacompany) {
6926 //print 'VATRULE 0';
6927 return get_product_vat_for_country($idprod, $thirdparty_buyer, $idprodfournprice);
6928 }
6929 }
6930 }
6931
6932 // If seller does not use VAT, default VAT is 0. End of rule.
6933 if (!$seller_use_vat) {
6934 //print 'VATRULE 1';
6935 return 0;
6936 }
6937
6938 // If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule.
6939 if (($seller_country_code == $buyer_country_code)
6940 || (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC')))) { // Warning ->country_code not always defined
6941 //print 'VATRULE 2';
6942 $tmpvat = get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6943
6944 if ($seller_country_code == 'IN' && getDolGlobalString('MAIN_SALETAX_AUTOSWITCH_I_CS_FOR_INDIA')) {
6945 // Special case for india.
6946 //print 'VATRULE 2b';
6947 $reg = array();
6948 if (preg_match('/C+S-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id != $thirdparty_buyer->state_id) {
6949 // we must revert the C+S into I
6950 $tmpvat = str_replace("C+S", "I", $tmpvat);
6951 } elseif (preg_match('/I-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id == $thirdparty_buyer->state_id) {
6952 // we must revert the I into C+S
6953 $tmpvat = str_replace("I", "C+S", $tmpvat);
6954 }
6955 }
6956
6957 return $tmpvat;
6958 }
6959
6960 // 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.
6961 // 'VATRULE 3' - Not supported
6962
6963 // If (seller and buyer in the European Community) and (buyer = individual) then VAT by default = VAT of the product sold. End of rule
6964 // If (seller and buyer in European Community) and (buyer = company) then VAT by default=0. End of rule
6965 if (($seller_in_cee && $buyer_in_cee)) {
6966 $isacompany = $thirdparty_buyer->isACompany();
6967 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6968 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6969 if (!isValidVATID($thirdparty_buyer)) {
6970 $isacompany = 0;
6971 }
6972 }
6973
6974 if (!$isacompany) {
6975 //print 'VATRULE 4';
6976 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6977 } else {
6978 //print 'VATRULE 5';
6979 return 0;
6980 }
6981 }
6982
6983 // 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
6984 // I don't see any use case that need this rule.
6985 if (getDolGlobalString('MAIN_USE_VAT_OF_PRODUCT_FOR_INDIVIDUAL_CUSTOMER_OUT_OF_EEC') && empty($buyer_in_cee)) {
6986 $isacompany = $thirdparty_buyer->isACompany();
6987 if (!$isacompany) {
6988 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6989 //print 'VATRULE extra';
6990 }
6991 }
6992
6993 // Otherwise the VAT proposed by default=0. End of rule.
6994 // Rem: This means that at least one of the 2 is outside the European Community and the country differs
6995 //print 'VATRULE 6';
6996 return 0;
6997}
6998
6999
7010function get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
7011{
7012 global $db;
7013
7014 if ($idprodfournprice > 0) {
7015 if (!class_exists('ProductFournisseur')) {
7016 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
7017 }
7018 $prodprice = new ProductFournisseur($db);
7019 $prodprice->fetch_product_fournisseur_price($idprodfournprice);
7020 return $prodprice->fourn_tva_npr;
7021 } elseif ($idprod > 0) {
7022 if (!class_exists('Product')) {
7023 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
7024 }
7025 $prod = new Product($db);
7026 $prod->fetch($idprod);
7027 return $prod->tva_npr;
7028 }
7029
7030 return 0;
7031}
7032
7046function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod = 0)
7047{
7048 global $mysoc;
7049
7050 if (!is_object($thirdparty_seller)) {
7051 return -1;
7052 }
7053 if (!is_object($thirdparty_buyer)) {
7054 return -1;
7055 }
7056
7057 if ($local == 1) { // Localtax 1
7058 if ($mysoc->country_code == 'ES') {
7059 if (is_numeric($thirdparty_buyer->localtax1_assuj) && !$thirdparty_buyer->localtax1_assuj) {
7060 return 0;
7061 }
7062 } else {
7063 // Si vendeur non assujeti a Localtax1, localtax1 par default=0
7064 if (is_numeric($thirdparty_seller->localtax1_assuj) && !$thirdparty_seller->localtax1_assuj) {
7065 return 0;
7066 }
7067 if (!is_numeric($thirdparty_seller->localtax1_assuj) && $thirdparty_seller->localtax1_assuj == 'localtax1off') {
7068 return 0;
7069 }
7070 }
7071 } elseif ($local == 2) { //I Localtax 2
7072 // Si vendeur non assujeti a Localtax2, localtax2 par default=0
7073 if (is_numeric($thirdparty_seller->localtax2_assuj) && !$thirdparty_seller->localtax2_assuj) {
7074 return 0;
7075 }
7076 if (!is_numeric($thirdparty_seller->localtax2_assuj) && $thirdparty_seller->localtax2_assuj == 'localtax2off') {
7077 return 0;
7078 }
7079 }
7080
7081 if ($thirdparty_seller->country_code == $thirdparty_buyer->country_code) {
7082 return get_product_localtax_for_country($idprod, $local, $thirdparty_seller);
7083 }
7084
7085 return 0;
7086}
7087
7096function yn($yesno, $case = 1, $color = 0)
7097{
7098 global $langs;
7099
7100 $result = 'unknown';
7101 $classname = '';
7102 if ($yesno == 1 || (isset($yesno) && (strtolower($yesno) == 'yes' || strtolower($yesno) == 'true'))) { // A mettre avant test sur no a cause du == 0
7103 $result = $langs->trans('yes');
7104 if ($case == 1 || $case == 3) {
7105 $result = $langs->trans("Yes");
7106 }
7107 if ($case == 2) {
7108 $result = '<input type="checkbox" value="1" checked disabled>';
7109 }
7110 if ($case == 3) {
7111 $result = '<input type="checkbox" value="1" checked disabled> '.$result;
7112 }
7113
7114 $classname = 'ok';
7115 } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') {
7116 $result = $langs->trans("no");
7117 if ($case == 1 || $case == 3) {
7118 $result = $langs->trans("No");
7119 }
7120 if ($case == 2) {
7121 $result = '<input type="checkbox" value="0" disabled>';
7122 }
7123 if ($case == 3) {
7124 $result = '<input type="checkbox" value="0" disabled> '.$result;
7125 }
7126
7127 if ($color == 2) {
7128 $classname = 'ok';
7129 } else {
7130 $classname = 'error';
7131 }
7132 }
7133 if ($color) {
7134 return '<span class="'.$classname.'">'.$result.'</span>';
7135 }
7136 return $result;
7137}
7138
7154function get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart = '')
7155{
7156 global $conf;
7157
7158 if (empty($modulepart) && !empty($object->module)) {
7159 $modulepart = $object->module;
7160 }
7161
7162 $path = '';
7163
7164 $arrayforoldpath = array('cheque', 'category', 'holiday', 'supplier_invoice', 'invoice_supplier', 'mailing', 'supplier_payment');
7165 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
7166 $arrayforoldpath[] = 'product';
7167 }
7168 if (!empty($level) && in_array($modulepart, $arrayforoldpath)) {
7169 // This part should be removed once all code is using "get_exdir" to forge path, with parameter $object and $modulepart provided.
7170 if (empty($alpha)) {
7171 $num = preg_replace('/([^0-9])/i', '', $num);
7172 } else {
7173 $num = preg_replace('/^.*\-/i', '', $num);
7174 }
7175 $num = substr("000".$num, -$level);
7176 if ($level == 1) {
7177 $path = substr($num, 0, 1);
7178 }
7179 if ($level == 2) {
7180 $path = substr($num, 1, 1).'/'.substr($num, 0, 1);
7181 }
7182 if ($level == 3) {
7183 $path = substr($num, 2, 1).'/'.substr($num, 1, 1).'/'.substr($num, 0, 1);
7184 }
7185 } else {
7186 // We will enhance here a common way of forging path for document storage.
7187 // In a future, we may distribute directories on several levels depending on setup and object.
7188 // Here, $object->id, $object->ref and $modulepart are required.
7189 //var_dump($modulepart);
7190 $path = dol_sanitizeFileName(empty($object->ref) ? (string) $object->id : $object->ref);
7191 }
7192
7193 if (empty($withoutslash) && !empty($path)) {
7194 $path .= '/';
7195 }
7196
7197 return $path;
7198}
7199
7208function dol_mkdir($dir, $dataroot = '', $newmask = '')
7209{
7210 global $conf;
7211
7212 dol_syslog("functions.lib::dol_mkdir: dir=".$dir, LOG_INFO);
7213
7214 $dir_osencoded = dol_osencode($dir);
7215 if (@is_dir($dir_osencoded)) {
7216 return 0;
7217 }
7218
7219 $nberr = 0;
7220 $nbcreated = 0;
7221
7222 $ccdir = '';
7223 if (!empty($dataroot)) {
7224 // Remove data root from loop
7225 $dir = str_replace($dataroot.'/', '', $dir);
7226 $ccdir = $dataroot.'/';
7227 }
7228
7229 $cdir = explode("/", $dir);
7230 $num = count($cdir);
7231 for ($i = 0; $i < $num; $i++) {
7232 if ($i > 0) {
7233 $ccdir .= '/'.$cdir[$i];
7234 } else {
7235 $ccdir .= $cdir[$i];
7236 }
7237 $regs = array();
7238 if (preg_match("/^.:$/", $ccdir, $regs)) {
7239 continue; // Si chemin Windows incomplet, on poursuit par rep suivant
7240 }
7241
7242 // Attention, le is_dir() peut echouer bien que le rep existe.
7243 // (ex selon config de open_basedir)
7244 if ($ccdir) {
7245 $ccdir_osencoded = dol_osencode($ccdir);
7246 if (!@is_dir($ccdir_osencoded)) {
7247 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.", LOG_DEBUG);
7248
7249 umask(0);
7250 $dirmaskdec = octdec((string) $newmask);
7251 if (empty($newmask)) {
7252 $dirmaskdec = !getDolGlobalString('MAIN_UMASK') ? octdec('0755') : octdec($conf->global->MAIN_UMASK);
7253 }
7254 $dirmaskdec |= octdec('0111'); // Set x bit required for directories
7255 if (!@mkdir($ccdir_osencoded, $dirmaskdec)) {
7256 // Si le is_dir a renvoye une fausse info, alors on passe ici.
7257 dol_syslog("functions.lib::dol_mkdir: Fails to create directory '".$ccdir."' or directory already exists.", LOG_WARNING);
7258 $nberr++;
7259 } else {
7260 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' created", LOG_DEBUG);
7261 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignore
7262 $nbcreated++;
7263 }
7264 } else {
7265 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignores
7266 }
7267 }
7268 }
7269 return ($nberr ? -$nberr : $nbcreated);
7270}
7271
7272
7280function dolChmod($filepath, $newmask = '')
7281{
7282 global $conf;
7283
7284 if (!empty($newmask)) {
7285 @chmod($filepath, octdec($newmask));
7286 } elseif (getDolGlobalString('MAIN_UMASK')) {
7287 @chmod($filepath, octdec($conf->global->MAIN_UMASK));
7288 }
7289}
7290
7291
7298{
7299 return '<span class="fieldrequired">*</span>';
7300}
7301
7302
7319function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = 'UTF-8', $strip_tags = 0, $removedoublespaces = 1)
7320{
7321 if (is_null($stringtoclean)) {
7322 return '';
7323 }
7324
7325 if ($removelinefeed == 2) {
7326 $stringtoclean = preg_replace('/<br[^>]*>(\n|\r)+/ims', '<br>', $stringtoclean);
7327 }
7328 $temp = preg_replace('/<br[^>]*>/i', "\n", $stringtoclean);
7329
7330 // 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)
7331 $temp = dol_html_entity_decode($temp, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7332
7333 $temp = str_replace('< ', '__ltspace__', $temp);
7334
7335 if ($strip_tags) {
7336 $temp = strip_tags($temp);
7337 } else {
7338 // 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).
7339 $pattern = "/<[^<>]+>/";
7340 // Example of $temp: <a href="/myurl" title="<u>A title</u>">0000-021</a>
7341 // pass 1 - $temp after pass 1: <a href="/myurl" title="A title">0000-021
7342 // pass 2 - $temp after pass 2: 0000-021
7343 $tempbis = $temp;
7344 do {
7345 $temp = $tempbis;
7346 $tempbis = str_replace('<>', '', $temp); // No reason to have this into a text, except if value is to try bypass the next html cleaning
7347 $tempbis = preg_replace($pattern, '', $tempbis);
7348 //$idowhile++; print $temp.'-'.$tempbis."\n"; if ($idowhile > 100) break;
7349 } while ($tempbis != $temp);
7350
7351 $temp = $tempbis;
7352
7353 // 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).
7354 $temp = preg_replace('/<+([a-z]+)/i', '\1', $temp);
7355 }
7356
7357 $temp = dol_html_entity_decode($temp, ENT_COMPAT, $pagecodeto);
7358
7359 // Remove also carriage returns
7360 if ($removelinefeed == 1) {
7361 $temp = str_replace(array("\r\n", "\r", "\n"), " ", $temp);
7362 }
7363
7364 // And double quotes
7365 if ($removedoublespaces) {
7366 while (strpos($temp, " ")) {
7367 $temp = str_replace(" ", " ", $temp);
7368 }
7369 }
7370
7371 $temp = str_replace('__ltspace__', '< ', $temp);
7372
7373 return trim($temp);
7374}
7375
7391function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1, $cleanalsojavascript = 0, $allowiframe = 0, $allowed_tags = array(), $allowlink = 0)
7392{
7393 if (empty($allowed_tags)) {
7394 $allowed_tags = array(
7395 "html", "head", "meta", "body", "article", "a", "abbr", "b", "blockquote", "br", "cite", "div", "dl", "dd", "dt", "em", "font", "img", "ins", "hr", "i", "li",
7396 "ol", "p", "q", "s", "span", "strike", "strong", "title", "table", "tr", "th", "td", "u", "ul", "sup", "sub", "blockquote", "pre", "h1", "h2", "h3", "h4", "h5", "h6",
7397 "header", "footer", "nav", "section", "menu", "menuitem" // html5 tags
7398 );
7399 }
7400 $allowed_tags[] = "comment"; // this tags is added to manage comment <!--...--> that are replaced into <comment>...</comment>
7401 if ($allowiframe) {
7402 if (!in_array('iframe', $allowed_tags)) {
7403 $allowed_tags[] = "iframe";
7404 }
7405 }
7406 if ($allowlink) {
7407 if (!in_array('link', $allowed_tags)) {
7408 $allowed_tags[] = "link";
7409 }
7410 }
7411
7412 $allowed_tags_string = join("><", $allowed_tags);
7413 $allowed_tags_string = '<'.$allowed_tags_string.'>';
7414
7415 $stringtoclean = str_replace('<!DOCTYPE html>', '__!DOCTYPE_HTML__', $stringtoclean); // Replace DOCTYPE to avoid to have it removed by the strip_tags
7416
7417 $stringtoclean = dol_string_nounprintableascii($stringtoclean, 0);
7418
7419 //$stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
7420 $stringtoclean = preg_replace('/<!--([^>]*)-->/', '<comment>\1</comment>', $stringtoclean);
7421
7422 $stringtoclean = preg_replace('/&colon;/i', ':', $stringtoclean);
7423 $stringtoclean = preg_replace('/&#58;|&#0+58|&#x3A/i', '', $stringtoclean); // refused string ':' encoded (no reason to have a : encoded like this) to disable 'javascript:...'
7424
7425 $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
7426
7427 if ($cleanalsosomestyles) { // Clean for remaining html tags
7428 $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
7429 }
7430 if ($removeclassattribute) { // Clean for remaining html tags
7431 $temp = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $temp);
7432 }
7433
7434 // Remove 'javascript:' that we should not find into a text with
7435 // 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)).
7436 if ($cleanalsojavascript) {
7437 $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);
7438 }
7439
7440 $temp = str_replace('__!DOCTYPE_HTML__', '<!DOCTYPE html>', $temp); // Restore the DOCTYPE
7441
7442 $temp = preg_replace('/<comment>([^>]*)<\/comment>/', '<!--\1-->', $temp); // Restore html comments
7443
7444
7445 return $temp;
7446}
7447
7448
7460function dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes = null)
7461{
7462 if (is_null($allowed_attributes)) {
7463 $allowed_attributes = array(
7464 "allow", "allowfullscreen", "alt", "class", "contenteditable", "data-html", "frameborder", "height", "href", "id", "name", "src", "style", "target", "title", "width",
7465 // HTML5
7466 "header", "footer", "nav", "section", "menu", "menuitem"
7467 );
7468 }
7469
7470 if (class_exists('DOMDocument') && !empty($stringtoclean)) {
7471 $stringtoclean = '<?xml encoding="UTF-8"><html><body>'.$stringtoclean.'</body></html>';
7472
7473 // Warning: loadHTML does not support HTML5 on old libxml versions.
7474 $dom = new DOMDocument(null, 'UTF-8');
7475 $dom->loadHTML($stringtoclean, LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7476
7477 if (is_object($dom)) {
7478 for ($els = $dom->getElementsByTagname('*'), $i = $els->length - 1; $i >= 0; $i--) {
7479 for ($attrs = $els->item($i)->attributes, $ii = $attrs->length - 1; $ii >= 0; $ii--) {
7480 //var_dump($attrs->item($ii));
7481 if (!empty($attrs->item($ii)->name)) {
7482 if (! in_array($attrs->item($ii)->name, $allowed_attributes)) {
7483 // Delete attribute if not into allowed_attributes
7484 $els->item($i)->removeAttribute($attrs->item($ii)->name);
7485 } elseif (in_array($attrs->item($ii)->name, array('style'))) {
7486 // If attribute is 'style'
7487 $valuetoclean = $attrs->item($ii)->value;
7488
7489 if (isset($valuetoclean)) {
7490 do {
7491 $oldvaluetoclean = $valuetoclean;
7492 $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments
7493 $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean);
7494 if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags.
7495 $valuetoclean = preg_replace('/display\s*:/mi', '', $valuetoclean);
7496 $valuetoclean = preg_replace('/z-index\s*:/mi', '', $valuetoclean);
7497 $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*:/mi', '', $valuetoclean);
7498 }
7499
7500 // We do not allow logout|passwordforgotten.php and action= into the content of a "style" tag
7501 $valuetoclean = preg_replace('/(logout|passwordforgotten)\.php/mi', '', $valuetoclean);
7502 $valuetoclean = preg_replace('/action=/mi', '', $valuetoclean);
7503 } while ($oldvaluetoclean != $valuetoclean);
7504 }
7505
7506 $attrs->item($ii)->value = $valuetoclean;
7507 }
7508 }
7509 }
7510 }
7511 }
7512
7513 $return = $dom->saveHTML(); // This may add a LF at end of lines, so we will trim later
7514 //$return = '<html><body>aaaa</p>bb<p>ssdd</p>'."\n<p>aaa</p>aa<p>bb</p>";
7515
7516 $return = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $return);
7517 $return = preg_replace('/^'.preg_quote('<html><body>', '/').'/', '', $return);
7518 $return = preg_replace('/'.preg_quote('</body></html>', '/').'$/', '', $return);
7519 return trim($return);
7520 } else {
7521 return $stringtoclean;
7522 }
7523}
7524
7536function dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags = array('textarea'), $cleanalsosomestyles = 0)
7537{
7538 $temp = $stringtoclean;
7539 foreach ($disallowed_tags as $tagtoremove) {
7540 $temp = preg_replace('/<\/?'.$tagtoremove.'>/', '', $temp);
7541 $temp = preg_replace('/<\/?'.$tagtoremove.'\s+[^>]*>/', '', $temp);
7542 }
7543
7544 if ($cleanalsosomestyles) {
7545 $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
7546 }
7547
7548 return $temp;
7549}
7550
7551
7561function dolGetFirstLineOfText($text, $nboflines = 1, $charset = 'UTF-8')
7562{
7563 if ($nboflines == 1) {
7564 if (dol_textishtml($text)) {
7565 $firstline = preg_replace('/<br[^>]*>.*$/s', '', $text); // The s pattern modifier means the . can match newline characters
7566 $firstline = preg_replace('/<div[^>]*>.*$/s', '', $firstline); // The s pattern modifier means the . can match newline characters
7567 } else {
7568 if (isset($text)) {
7569 $firstline = preg_replace('/[\n\r].*/', '', $text);
7570 } else {
7571 $firstline = '';
7572 }
7573 }
7574 return $firstline.(isset($firstline) && isset($text) && (strlen($firstline) != strlen($text)) ? '...' : '');
7575 } else {
7576 $ishtml = 0;
7577 if (dol_textishtml($text)) {
7578 $text = preg_replace('/\n/', '', $text);
7579 $ishtml = 1;
7580 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7581 } else {
7582 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7583 }
7584
7585 $text = strtr($text, $repTable);
7586 if ($charset == 'UTF-8') {
7587 $pattern = '/(<br[^>]*>)/Uu';
7588 } else {
7589 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7590 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7591 }
7592 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7593
7594 $firstline = '';
7595 $i = 0;
7596 $countline = 0;
7597 $lastaddediscontent = 1;
7598 while ($countline < $nboflines && isset($a[$i])) {
7599 if (preg_match('/<br[^>]*>/', $a[$i])) {
7600 if (array_key_exists($i+1, $a) && !empty($a[$i+1])) {
7601 $firstline .= ($ishtml ? "<br>\n" : "\n");
7602 // Is it a br for a new line of after a printed line ?
7603 if (!$lastaddediscontent) {
7604 $countline++;
7605 }
7606 $lastaddediscontent = 0;
7607 }
7608 } else {
7609 $firstline .= $a[$i];
7610 $lastaddediscontent = 1;
7611 $countline++;
7612 }
7613 $i++;
7614 }
7615
7616 $adddots = (isset($a[$i]) && (!preg_match('/<br[^>]*>/', $a[$i]) || (array_key_exists($i+1, $a) && !empty($a[$i+1]))));
7617 //unset($a);
7618 $ret = $firstline.($adddots ? '...' : '');
7619 //exit;
7620 return $ret;
7621 }
7622}
7623
7624
7636function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false)
7637{
7638 if (is_null($stringtoencode)) {
7639 return '';
7640 }
7641
7642 if (!$nl2brmode) {
7643 return nl2br($stringtoencode, $forxml);
7644 } else {
7645 $ret = preg_replace('/(\r\n|\r|\n)/i', ($forxml ? '<br />' : '<br>'), $stringtoencode);
7646 return $ret;
7647 }
7648}
7649
7659function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = 'restricthtml')
7660{
7661 if (empty($nouseofiframesandbox) && getDolGlobalString('MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS')) {
7662 // TODO using sandbox on inline html content is not possible yet with current browsers
7663 //$s = '<iframe class="iframewithsandbox" sandbox><html><body>';
7664 //$s .= $stringtoencode;
7665 //$s .= '</body></html></iframe>';
7666 return $stringtoencode;
7667 } else {
7668 $out = $stringtoencode;
7669
7670 do {
7671 $oldstringtoclean = $out;
7672
7673 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML') && $check != 'restricthtmlallowunvalid') {
7674 try {
7675 libxml_use_internal_errors(false); // Avoid to fill memory with xml errors
7676 if (LIBXML_VERSION < 20900) {
7677 // Avoid load of external entities (security problem).
7678 // Required only if LIBXML_VERSION < 20900
7679 libxml_disable_entity_loader(true);
7680 }
7681
7682 $dom = new DOMDocument();
7683 // Add a trick to solve pb with text without parent tag
7684 // like '<h1>Foo</h1><p>bar</p>' that wrongly ends up, without the trick, with '<h1>Foo<p>bar</p></h1>'
7685 // like 'abc' that wrongly ends up, without the trick, with '<p>abc</p>'
7686
7687 if (dol_textishtml($out)) {
7688 $out = '<?xml encoding="UTF-8"><div class="tricktoremove">'.$out.'</div>';
7689 } else {
7690 $out = '<?xml encoding="UTF-8"><div class="tricktoremove">'.dol_nl2br($out).'</div>';
7691 }
7692 $dom->loadHTML($out, LIBXML_HTML_NODEFDTD | LIBXML_ERR_NONE | LIBXML_HTML_NOIMPLIED | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_NOERROR | LIBXML_NOXMLDECL);
7693 $out = trim($dom->saveHTML());
7694
7695 // Remove the trick added to solve pb with text without parent tag
7696 $out = preg_replace('/^<\?xml encoding="UTF-8"><div class="tricktoremove">/', '', $out);
7697 $out = preg_replace('/<\/div>$/', '', $out);
7698 } catch (Exception $e) {
7699 // If error, invalid HTML string with no way to clean it
7700 //print $e->getMessage();
7701 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
7702 }
7703 }
7704
7705 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY') && $check != 'restricthtmlallowunvalid') {
7706 try {
7707 // Try cleaning using tidy
7708 if (extension_loaded('tidy') && class_exists("tidy")) {
7709 //print "aaa".$out."\n";
7710
7711 // See options at https://tidy.sourceforge.net/docs/quickref.html
7712 $config = array(
7713 'clean' => false,
7714 'quote-marks' => false, // do not replace " that are used for real text content (not a string symbol for html attribute) into &quot;
7715 'doctype' => 'strict',
7716 'show-body-only' => true,
7717 "indent-attributes" => false,
7718 "vertical-space" => false,
7719 'ident' => false,
7720 "wrap" => 0
7721 // HTML5 tags
7722 //'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',
7723 //'new-blocklevel-tags' => 'footer header section menu menuitem'
7724 //'new-empty-tags' => 'command embed keygen source track wbr',
7725 //'new-inline-tags' => 'audio command datalist embed keygen mark menuitem meter output progress source time video wbr',
7726 );
7727
7728 // Tidy
7729 $tidy = new tidy();
7730 $out = $tidy->repairString($out, $config, 'utf8');
7731
7732 //print "xxx".$out;exit;
7733 }
7734 } catch (Exception $e) {
7735 // If error, invalid HTML string with no way to clean it
7736 //print $e->getMessage();
7737 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
7738 }
7739 }
7740
7741 //Clear ZERO WIDTH NO-BREAK SPACE, ZERO WIDTH SPACE, ZERO WIDTH JOINER
7742 $out = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $out);
7743
7744 // Clean some html entities that are useless so text is cleaner
7745 $out = preg_replace('/&(tab|newline);/i', ' ', $out);
7746
7747 // Ckeditor use the numeric entitic for apostrophe so we force it to text entity (all other special chars are
7748 // encoded using text entities) so we can then exclude all numeric entities.
7749 $out = preg_replace('/&#39;/i', '&apos;', $out);
7750
7751 // 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).
7752 // 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
7753 // using a non coventionnel way to be encoded, to not have them sanitized just after)
7754 $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) {
7755 return realCharForNumericEntities($m);
7756 }, $out);
7757
7758
7759 // Now we remove all remaining HTML entities starting with a number. We don't want such entities.
7760 $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'.
7761
7762 // Keep only some html tags and remove also some 'javascript:' strings
7763 $out = dol_string_onlythesehtmltags($out, 0, ($check == 'restricthtmlallowclass' ? 0 : 1), 1);
7764
7765 // Keep only some html attributes and exclude non expected HTML attributes and clean content of some attributes (keep only alt=, title=...).
7766 if (getDolGlobalString('MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES')) {
7768 }
7769
7770 // Restore entity &apos; into &#39; (restricthtml is for html content so we can use html entity)
7771 $out = preg_replace('/&apos;/i', "&#39;", $out);
7772 } while ($oldstringtoclean != $out);
7773
7774 // Check the limit of external links that are automatically executed in a Rich text content. We count:
7775 // '<img' to avoid <img src="http...">, we can only accept "<img src="data:..."
7776 // 'url(' to avoid inline style like background: url(http...
7777 // '<link' to avoid <link href="http...">
7778 $reg = array();
7779 $tmpout = preg_replace('/<img src="data:/mi', '<__IMG_SRC_DATA__ src="data:', $out);
7780 preg_match_all('/(<img|url\‍(|<link)/i', $tmpout, $reg);
7781 $nblinks = count($reg[0]);
7782 if ($nblinks > getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) {
7783 $out = 'ErrorTooManyLinksIntoHTMLString';
7784 }
7785
7786 if (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 2 || $check == 'restricthtmlnolink') {
7787 if ($nblinks > 0) {
7788 $out = 'ErrorHTMLLinksNotAllowed';
7789 }
7790 } elseif (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 1) {
7791 $nblinks = 0;
7792 // Loop on each url in src= and url(
7793 $pattern = '/src=["\']?(http[^"\']+)|url\‍(["\']?(http[^\‍)]+)/';
7794
7795 $matches = array();
7796 if (preg_match_all($pattern, $out, $matches)) {
7797 // URLs are into $matches[1]
7798 $urls = $matches[1];
7799
7800 // Affiche les URLs
7801 foreach ($urls as $url) {
7802 $nblinks++;
7803 echo "Found url = ".$url . "\n";
7804 }
7805 if ($nblinks > 0) {
7806 $out = 'ErrorHTMLExternalLinksNotAllowed';
7807 }
7808 }
7809 }
7810
7811 return $out;
7812 }
7813}
7814
7836function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UTF-8', $removelasteolbr = 1)
7837{
7838 if (is_null($stringtoencode)) {
7839 return '';
7840 }
7841
7842 $newstring = $stringtoencode;
7843 if (dol_textishtml($stringtoencode)) { // Check if text is already HTML or not
7844 $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.
7845 if ($removelasteolbr) {
7846 $newstring = preg_replace('/<br>$/i', '', $newstring); // Remove last <br> (remove only last one)
7847 }
7848 $newstring = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $newstring);
7849 $newstring = strtr($newstring, array('&'=>'__and__', '<'=>'__lt__', '>'=>'__gt__', '"'=>'__dquot__'));
7850 $newstring = dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom); // Make entity encoding
7851 $newstring = strtr($newstring, array('__and__'=>'&', '__lt__'=>'<', '__gt__'=>'>', '__dquot__'=>'"'));
7852 } else {
7853 if ($removelasteolbr) {
7854 $newstring = preg_replace('/(\r\n|\r|\n)$/i', '', $newstring); // Remove last \n (may remove several)
7855 }
7856 $newstring = dol_nl2br(dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom), $nl2brmode);
7857 }
7858 // Other substitutions that htmlentities does not do
7859 //$newstring=str_replace(chr(128),'&euro;',$newstring); // 128 = 0x80. Not in html entity table. // Seems useles with TCPDF. Make bug with UTF8 languages
7860 return $newstring;
7861}
7862
7870function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8')
7871{
7872 $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7873 $ret = preg_replace('/'."\r\n".'<br(\s[\sa-zA-Z_="]*)?\/?>/i', "<br>", $ret);
7874 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\r\n".'/i', "\r\n", $ret);
7875 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\n".'/i', "\n", $ret);
7876 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', "\n", $ret);
7877 return $ret;
7878}
7879
7886function dol_htmlcleanlastbr($stringtodecode)
7887{
7888 $ret = preg_replace('/&nbsp;$/i', "", $stringtodecode); // Because wysiwyg editor may add a &nbsp; at end of last line
7889 $ret = preg_replace('/(<br>|<br(\s[\sa-zA-Z_="]*)?\/?>|'."\n".'|'."\r".')+$/i', "", $ret);
7890 return $ret;
7891}
7892
7902function dol_html_entity_decode($a, $b, $c = 'UTF-8', $keepsomeentities = 0)
7903{
7904 $newstring = $a;
7905 if ($keepsomeentities) {
7906 $newstring = strtr($newstring, array('&amp;'=>'__andamp__', '&lt;'=>'__andlt__', '&gt;'=>'__andgt__', '"'=>'__dquot__'));
7907 }
7908 $newstring = html_entity_decode((string) $newstring, (int) $b, (string) $c);
7909 if ($keepsomeentities) {
7910 $newstring = strtr($newstring, array('__andamp__'=>'&amp;', '__andlt__'=>'&lt;', '__andgt__'=>'&gt;', '__dquot__'=>'"'));
7911 }
7912 return $newstring;
7913}
7914
7926function dol_htmlentities($string, $flags = ENT_QUOTES|ENT_SUBSTITUTE, $encoding = 'UTF-8', $double_encode = false)
7927{
7928 return htmlentities($string, $flags, $encoding, $double_encode);
7929}
7930
7942function dol_string_is_good_iso($s, $clean = 0)
7943{
7944 $len = dol_strlen($s);
7945 $out = '';
7946 $ok = 1;
7947 for ($scursor = 0; $scursor < $len; $scursor++) {
7948 $ordchar = ord($s[$scursor]);
7949 //print $scursor.'-'.$ordchar.'<br>';
7950 if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) {
7951 $ok = 0;
7952 break;
7953 } elseif ($ordchar > 126 && $ordchar < 160) {
7954 $ok = 0;
7955 break;
7956 } elseif ($clean) {
7957 $out .= $s[$scursor];
7958 }
7959 }
7960 if ($clean) {
7961 return $out;
7962 }
7963 return $ok;
7964}
7965
7974function dol_nboflines($s, $maxchar = 0)
7975{
7976 if ($s == '') {
7977 return 0;
7978 }
7979 $arraystring = explode("\n", $s);
7980 $nb = count($arraystring);
7981
7982 return $nb;
7983}
7984
7985
7995function dol_nboflines_bis($text, $maxlinesize = 0, $charset = 'UTF-8')
7996{
7997 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7998 if (dol_textishtml($text)) {
7999 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
8000 }
8001
8002 $text = strtr($text, $repTable);
8003 if ($charset == 'UTF-8') {
8004 $pattern = '/(<br[^>]*>)/Uu';
8005 } else {
8006 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
8007 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
8008 }
8009 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
8010
8011 $nblines = (int) floor((count($a) + 1) / 2);
8012 // count possible auto line breaks
8013 if ($maxlinesize) {
8014 foreach ($a as $line) {
8015 if (dol_strlen($line) > $maxlinesize) {
8016 //$line_dec = html_entity_decode(strip_tags($line));
8017 $line_dec = html_entity_decode($line);
8018 if (dol_strlen($line_dec) > $maxlinesize) {
8019 $line_dec = wordwrap($line_dec, $maxlinesize, '\n', true);
8020 $nblines += substr_count($line_dec, '\n');
8021 }
8022 }
8023 }
8024 }
8025
8026 unset($a);
8027 return $nblines;
8028}
8029
8038function dol_textishtml($msg, $option = 0)
8039{
8040 if (is_null($msg)) {
8041 return false;
8042 }
8043
8044 if ($option == 1) {
8045 if (preg_match('/<html/i', $msg)) {
8046 return true;
8047 } elseif (preg_match('/<body/i', $msg)) {
8048 return true;
8049 } elseif (preg_match('/<\/textarea/i', $msg)) {
8050 return true;
8051 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8052 return true;
8053 } elseif (preg_match('/<br/i', $msg)) {
8054 return true;
8055 }
8056 return false;
8057 } else {
8058 // Remove all urls because 'http://aa?param1=abc&amp;param2=def' must not be used inside detection
8059 $msg = preg_replace('/https?:\/\/[^"\'\s]+/i', '', $msg);
8060 if (preg_match('/<html/i', $msg)) {
8061 return true;
8062 } elseif (preg_match('/<body/i', $msg)) {
8063 return true;
8064 } elseif (preg_match('/<\/textarea/i', $msg)) {
8065 return true;
8066 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8067 return true;
8068 } elseif (preg_match('/<(br|hr)\/>/i', $msg)) {
8069 return true;
8070 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)>/i', $msg)) {
8071 return true;
8072 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)\s+[^<>\/]*\/?>/i', $msg)) {
8073 return true;
8074 } elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i', $msg)) {
8075 return true; // must accept <img src="http://example.com/aaa.png" />
8076 } elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i', $msg)) {
8077 return true; // must accept <a href="http://example.com/aaa.png" />
8078 } elseif (preg_match('/<h[0-9]>/i', $msg)) {
8079 return true;
8080 } elseif (preg_match('/&[A-Z0-9]{1,6};/i', $msg)) {
8081 // TODO If content is 'A link https://aaa?param=abc&amp;param2=def', it return true but must be false
8082 return true; // Html entities names (http://www.w3schools.com/tags/ref_entities.asp)
8083 } elseif (preg_match('/&#[0-9]{2,3};/i', $msg)) {
8084 return true; // Html entities numbers (http://www.w3schools.com/tags/ref_entities.asp)
8085 }
8086
8087 return false;
8088 }
8089}
8090
8105function dol_concatdesc($text1, $text2, $forxml = false, $invert = false)
8106{
8107 if (!empty($invert)) {
8108 $tmp = $text1;
8109 $text1 = $text2;
8110 $text2 = $tmp;
8111 }
8112
8113 $ret = '';
8114 $ret .= (!dol_textishtml($text1) && dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text1, 0, 1, '', 1), 0, $forxml) : $text1;
8115 $ret .= (!empty($text1) && !empty($text2)) ? ((dol_textishtml($text1) || dol_textishtml($text2)) ? ($forxml ? "<br >\n" : "<br>\n") : "\n") : "";
8116 $ret .= (dol_textishtml($text1) && !dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text2, 0, 1, '', 1), 0, $forxml) : $text2;
8117 return $ret;
8118}
8119
8120
8121
8133function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null)
8134{
8135 global $db, $conf, $mysoc, $user, $extrafields;
8136
8137 $substitutionarray = array();
8138
8139 if ((empty($exclude) || !in_array('user', $exclude)) && (empty($include) || in_array('user', $include))) {
8140 // Add SIGNATURE into substitutionarray first, so, when we will make the substitution,
8141 // this will include signature content first and then replace var found into content of signature
8142 //var_dump($onlykey);
8143 $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()
8144 $usersignature = $user->signature;
8145 $substitutionarray = array_merge($substitutionarray, array(
8146 '__SENDEREMAIL_SIGNATURE__' => (string) ((!getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc('SignatureFromTheSelectedSenderProfile', 30) : $emailsendersignature) : ''),
8147 '__USER_SIGNATURE__' => (string) (($usersignature && !getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc(dol_string_nohtmltag($usersignature), 30) : $usersignature) : '')
8148 ));
8149
8150 if (is_object($user)) {
8151 $substitutionarray = array_merge($substitutionarray, array(
8152 '__USER_ID__' => (string) $user->id,
8153 '__USER_LOGIN__' => (string) $user->login,
8154 '__USER_EMAIL__' => (string) $user->email,
8155 '__USER_PHONE__' => (string) dol_print_phone($user->office_phone, '', 0, 0, '', " ", '', '', -1),
8156 '__USER_PHONEPRO__' => (string) dol_print_phone($user->user_mobile, '', 0, 0, '', " ", '', '', -1),
8157 '__USER_PHONEMOBILE__' => (string) dol_print_phone($user->personal_mobile, '', 0, 0, '', " ", '', '', -1),
8158 '__USER_FAX__' => (string) $user->office_fax,
8159 '__USER_LASTNAME__' => (string) $user->lastname,
8160 '__USER_FIRSTNAME__' => (string) $user->firstname,
8161 '__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
8162 '__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
8163 '__USER_JOB__' => (string) $user->job,
8164 '__USER_REMOTE_IP__' => (string) getUserRemoteIP(),
8165 '__USER_VCARD_URL__' => (string) $user->getOnlineVirtualCardUrl('', 'external')
8166 ));
8167 }
8168 }
8169 if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc) && (empty($include) || in_array('mycompany', $include))) {
8170 $substitutionarray = array_merge($substitutionarray, array(
8171 '__MYCOMPANY_NAME__' => $mysoc->name,
8172 '__MYCOMPANY_EMAIL__' => $mysoc->email,
8173 '__MYCOMPANY_PHONE__' => dol_print_phone($mysoc->phone, '', 0, 0, '', " ", '', '', -1),
8174 '__MYCOMPANY_FAX__' => dol_print_phone($mysoc->fax, '', 0, 0, '', " ", '', '', -1),
8175 '__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
8176 '__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
8177 '__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
8178 '__MYCOMPANY_PROFID4__' => $mysoc->idprof4,
8179 '__MYCOMPANY_PROFID5__' => $mysoc->idprof5,
8180 '__MYCOMPANY_PROFID6__' => $mysoc->idprof6,
8181 '__MYCOMPANY_CAPITAL__' => $mysoc->capital,
8182 '__MYCOMPANY_FULLADDRESS__' => (method_exists($mysoc, 'getFullAddress') ? $mysoc->getFullAddress(1, ', ') : ''), // $mysoc may be stdClass
8183 '__MYCOMPANY_ADDRESS__' => $mysoc->address,
8184 '__MYCOMPANY_ZIP__' => $mysoc->zip,
8185 '__MYCOMPANY_TOWN__' => $mysoc->town,
8186 '__MYCOMPANY_COUNTRY__' => $mysoc->country,
8187 '__MYCOMPANY_COUNTRY_ID__' => $mysoc->country_id,
8188 '__MYCOMPANY_COUNTRY_CODE__' => $mysoc->country_code,
8189 '__MYCOMPANY_CURRENCY_CODE__' => $conf->currency
8190 ));
8191 }
8192
8193 if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude)) && (empty($include) || in_array('object', $include))) {
8194 if ($onlykey) {
8195 $substitutionarray['__ID__'] = '__ID__';
8196 $substitutionarray['__REF__'] = '__REF__';
8197 $substitutionarray['__NEWREF__'] = '__NEWREF__';
8198 $substitutionarray['__LABEL__'] = '__LABEL__';
8199 $substitutionarray['__REF_CLIENT__'] = '__REF_CLIENT__';
8200 $substitutionarray['__REF_SUPPLIER__'] = '__REF_SUPPLIER__';
8201 $substitutionarray['__NOTE_PUBLIC__'] = '__NOTE_PUBLIC__';
8202 $substitutionarray['__NOTE_PRIVATE__'] = '__NOTE_PRIVATE__';
8203 $substitutionarray['__EXTRAFIELD_XXX__'] = '__EXTRAFIELD_XXX__';
8204
8205 if (isModEnabled("societe")) { // Most objects are concerned
8206 $substitutionarray['__THIRDPARTY_ID__'] = '__THIRDPARTY_ID__';
8207 $substitutionarray['__THIRDPARTY_NAME__'] = '__THIRDPARTY_NAME__';
8208 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = '__THIRDPARTY_NAME_ALIAS__';
8209 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = '__THIRDPARTY_CODE_CLIENT__';
8210 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = '__THIRDPARTY_CODE_FOURNISSEUR__';
8211 $substitutionarray['__THIRDPARTY_EMAIL__'] = '__THIRDPARTY_EMAIL__';
8212 $substitutionarray['__THIRDPARTY_PHONE__'] = '__THIRDPARTY_PHONE__';
8213 $substitutionarray['__THIRDPARTY_FAX__'] = '__THIRDPARTY_FAX__';
8214 $substitutionarray['__THIRDPARTY_ADDRESS__'] = '__THIRDPARTY_ADDRESS__';
8215 $substitutionarray['__THIRDPARTY_ZIP__'] = '__THIRDPARTY_ZIP__';
8216 $substitutionarray['__THIRDPARTY_TOWN__'] = '__THIRDPARTY_TOWN__';
8217 $substitutionarray['__THIRDPARTY_IDPROF1__'] = '__THIRDPARTY_IDPROF1__';
8218 $substitutionarray['__THIRDPARTY_IDPROF2__'] = '__THIRDPARTY_IDPROF2__';
8219 $substitutionarray['__THIRDPARTY_IDPROF3__'] = '__THIRDPARTY_IDPROF3__';
8220 $substitutionarray['__THIRDPARTY_IDPROF4__'] = '__THIRDPARTY_IDPROF4__';
8221 $substitutionarray['__THIRDPARTY_IDPROF5__'] = '__THIRDPARTY_IDPROF5__';
8222 $substitutionarray['__THIRDPARTY_IDPROF6__'] = '__THIRDPARTY_IDPROF6__';
8223 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = '__THIRDPARTY_TVAINTRA__';
8224 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = '__THIRDPARTY_NOTE_PUBLIC__';
8225 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = '__THIRDPARTY_NOTE_PRIVATE__';
8226 }
8227 if (isModEnabled('adherent') && (!is_object($object) || $object->element == 'adherent') && (empty($exclude) || !in_array('member', $exclude)) && (empty($include) || in_array('member', $include))) {
8228 $substitutionarray['__MEMBER_ID__'] = '__MEMBER_ID__';
8229 $substitutionarray['__MEMBER_CIVILITY__'] = '__MEMBER_CIVILITY__';
8230 $substitutionarray['__MEMBER_FIRSTNAME__'] = '__MEMBER_FIRSTNAME__';
8231 $substitutionarray['__MEMBER_LASTNAME__'] = '__MEMBER_LASTNAME__';
8232 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = 'Login and pass of the external user account';
8233 /*$substitutionarray['__MEMBER_NOTE_PUBLIC__'] = '__MEMBER_NOTE_PUBLIC__';
8234 $substitutionarray['__MEMBER_NOTE_PRIVATE__'] = '__MEMBER_NOTE_PRIVATE__';*/
8235 }
8236 // add variables subtitutions ticket
8237 if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket') && (empty($exclude) || !in_array('ticket', $exclude)) && (empty($include) || in_array('ticket', $include))) {
8238 $substitutionarray['__TICKET_TRACKID__'] = '__TICKET_TRACKID__';
8239 $substitutionarray['__TICKET_SUBJECT__'] = '__TICKET_SUBJECT__';
8240 $substitutionarray['__TICKET_TYPE__'] = '__TICKET_TYPE__';
8241 $substitutionarray['__TICKET_SEVERITY__'] = '__TICKET_SEVERITY__';
8242 $substitutionarray['__TICKET_CATEGORY__'] = '__TICKET_CATEGORY__';
8243 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = '__TICKET_ANALYTIC_CODE__';
8244 $substitutionarray['__TICKET_MESSAGE__'] = '__TICKET_MESSAGE__';
8245 $substitutionarray['__TICKET_PROGRESSION__'] = '__TICKET_PROGRESSION__';
8246 $substitutionarray['__TICKET_USER_ASSIGN__'] = '__TICKET_USER_ASSIGN__';
8247 }
8248
8249 if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature') && (empty($exclude) || !in_array('recruitment', $exclude)) && (empty($include) || in_array('recruitment', $include))) {
8250 $substitutionarray['__CANDIDATE_FULLNAME__'] = '__CANDIDATE_FULLNAME__';
8251 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = '__CANDIDATE_FIRSTNAME__';
8252 $substitutionarray['__CANDIDATE_LASTNAME__'] = '__CANDIDATE_LASTNAME__';
8253 }
8254 if (isModEnabled('project') && (empty($exclude) || !in_array('project', $exclude)) && (empty($include) || in_array('project', $include))) { // Most objects
8255 $substitutionarray['__PROJECT_ID__'] = '__PROJECT_ID__';
8256 $substitutionarray['__PROJECT_REF__'] = '__PROJECT_REF__';
8257 $substitutionarray['__PROJECT_NAME__'] = '__PROJECT_NAME__';
8258 /*$substitutionarray['__PROJECT_NOTE_PUBLIC__'] = '__PROJECT_NOTE_PUBLIC__';
8259 $substitutionarray['__PROJECT_NOTE_PRIVATE__'] = '__PROJECT_NOTE_PRIVATE__';*/
8260 }
8261 if (isModEnabled('contrat') && (!is_object($object) || $object->element == 'contract') && (empty($exclude) || !in_array('contract', $exclude)) && (empty($include) || in_array('contract', $include))) {
8262 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = 'Highest date planned for a service start';
8263 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = 'Highest date and hour planned for service start';
8264 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = 'Lowest data for planned expiration of service';
8265 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = 'Lowest date and hour for planned expiration of service';
8266 }
8267 if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal') && (empty($exclude) || !in_array('propal', $exclude)) && (empty($include) || in_array('propal', $include))) {
8268 $substitutionarray['__ONLINE_SIGN_URL__'] = 'ToOfferALinkForOnlineSignature';
8269 }
8270 if (isModEnabled("ficheinter") && (!is_object($object) || $object->element == 'fichinter') && (empty($exclude) || !in_array('intervention', $exclude)) && (empty($include) || in_array('intervention', $include))) {
8271 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = 'ToOfferALinkForOnlineSignature';
8272 }
8273 $substitutionarray['__ONLINE_PAYMENT_URL__'] = 'UrlToPayOnlineIfApplicable';
8274 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = 'TextAndUrlToPayOnlineIfApplicable';
8275 $substitutionarray['__SECUREKEYPAYMENT__'] = 'Security key (if key is not unique per record)';
8276 $substitutionarray['__SECUREKEYPAYMENT_MEMBER__'] = 'Security key for payment on a member subscription (one key per member)';
8277 $substitutionarray['__SECUREKEYPAYMENT_ORDER__'] = 'Security key for payment on an order';
8278 $substitutionarray['__SECUREKEYPAYMENT_INVOICE__'] = 'Security key for payment on an invoice';
8279 $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'Security key for payment on a service of a contract';
8280
8281 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = 'Direct download url of a proposal';
8282 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = 'Direct download url of an order';
8283 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = 'Direct download url of an invoice';
8284 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = 'Direct download url of a contract';
8285 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = 'Direct download url of a supplier proposal';
8286
8287 if (isModEnabled("expedition") && (!is_object($object) || $object->element == 'shipping')) {
8288 $substitutionarray['__SHIPPINGTRACKNUM__'] = 'Shipping tracking number';
8289 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = 'Shipping tracking url';
8290 $substitutionarray['__SHIPPINGMETHOD__'] = 'Shipping method';
8291 }
8292 if (isModEnabled("reception") && (!is_object($object) || $object->element == 'reception')) {
8293 $substitutionarray['__RECEPTIONTRACKNUM__'] = 'Shippin tracking number of shipment';
8294 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = 'Shipping tracking url';
8295 }
8296 } else {
8297 $substitutionarray['__ID__'] = $object->id;
8298 $substitutionarray['__REF__'] = $object->ref;
8299 $substitutionarray['__NEWREF__'] = $object->newref;
8300 $substitutionarray['__LABEL__'] = (isset($object->label) ? $object->label : (isset($object->title) ? $object->title : null));
8301 $substitutionarray['__REF_CLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8302 $substitutionarray['__REF_SUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8303 $substitutionarray['__NOTE_PUBLIC__'] = (isset($object->note_public) ? $object->note_public : null);
8304 $substitutionarray['__NOTE_PRIVATE__'] = (isset($object->note_private) ? $object->note_private : null);
8305 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, 'day', 0, $outputlangs) : '');
8306 $substitutionarray['__DATE_DELIVERY_DAY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%d") : '');
8307 $substitutionarray['__DATE_DELIVERY_DAY_TEXT__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%A") : '');
8308 $substitutionarray['__DATE_DELIVERY_MON__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%m") : '');
8309 $substitutionarray['__DATE_DELIVERY_MON_TEXT__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%b") : '');
8310 $substitutionarray['__DATE_DELIVERY_YEAR__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%Y") : '');
8311 $substitutionarray['__DATE_DELIVERY_HH__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%H") : '');
8312 $substitutionarray['__DATE_DELIVERY_MM__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%M") : '');
8313 $substitutionarray['__DATE_DELIVERY_SS__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%S") : '');
8314
8315 // For backward compatibility (deprecated)
8316 $substitutionarray['__REFCLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8317 $substitutionarray['__REFSUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8318 $substitutionarray['__SUPPLIER_ORDER_DATE_DELIVERY__'] = (isset($object->delivery_date) ? dol_print_date($object->delivery_date, 'day', 0, $outputlangs) : '');
8319 $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 : '')) : '');
8320 $substitutionarray['__EXPIRATION_DATE__'] = (isset($object->fin_validite) ? dol_print_date($object->fin_validite, 'daytext') : '');
8321
8322 if (is_object($object) && ($object->element == 'adherent' || $object->element == 'member') && $object->id > 0) {
8323 $birthday = (empty($object->birth) ? '' : dol_print_date($object->birth, 'day'));
8324
8325 $substitutionarray['__MEMBER_ID__'] = (isset($object->id) ? $object->id : '');
8326 if (method_exists($object, 'getCivilityLabel')) {
8327 $substitutionarray['__MEMBER_CIVILITY__'] = $object->getCivilityLabel();
8328 }
8329 $substitutionarray['__MEMBER_FIRSTNAME__'] = (isset($object->firstname) ? $object->firstname : '');
8330 $substitutionarray['__MEMBER_LASTNAME__'] = (isset($object->lastname) ? $object->lastname : '');
8331 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = '';
8332 if (method_exists($object, 'getFullName')) {
8333 $substitutionarray['__MEMBER_FULLNAME__'] = $object->getFullName($outputlangs);
8334 }
8335 $substitutionarray['__MEMBER_COMPANY__'] = (isset($object->societe) ? $object->societe : '');
8336 $substitutionarray['__MEMBER_ADDRESS__'] = (isset($object->address) ? $object->address : '');
8337 $substitutionarray['__MEMBER_ZIP__'] = (isset($object->zip) ? $object->zip : '');
8338 $substitutionarray['__MEMBER_TOWN__'] = (isset($object->town) ? $object->town : '');
8339 $substitutionarray['__MEMBER_COUNTRY__'] = (isset($object->country) ? $object->country : '');
8340 $substitutionarray['__MEMBER_EMAIL__'] = (isset($object->email) ? $object->email : '');
8341 $substitutionarray['__MEMBER_BIRTH__'] = (isset($birthday) ? $birthday : '');
8342 $substitutionarray['__MEMBER_PHOTO__'] = (isset($object->photo) ? $object->photo : '');
8343 $substitutionarray['__MEMBER_LOGIN__'] = (isset($object->login) ? $object->login : '');
8344 $substitutionarray['__MEMBER_PASSWORD__'] = (isset($object->pass) ? $object->pass : '');
8345 $substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? dol_print_phone($object->phone) : '');
8346 $substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? dol_print_phone($object->phone_perso) : '');
8347 $substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? dol_print_phone($object->phone_mobile) : '');
8348 $substitutionarray['__MEMBER_TYPE__'] = (isset($object->type) ? $object->type : '');
8349 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__'] = dol_print_date($object->first_subscription_date, 'day');
8350 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = (isset($object->first_subscription_date_start) ? dol_print_date($object->first_subscription_date_start, 'day') : '');
8351 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END__'] = (isset($object->first_subscription_date_end) ? dol_print_date($object->first_subscription_date_end, 'day') : '');
8352 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE__'] = dol_print_date($object->last_subscription_date, 'day');
8353 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->last_subscription_date_start, 'day');
8354 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END__'] = dol_print_date($object->last_subscription_date_end, 'day');
8355 }
8356
8357 if (is_object($object) && $object->element == 'societe') {
8358 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object) ? $object->id : '');
8359 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object) ? $object->name : '');
8360 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object) ? $object->name_alias : '');
8361 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object) ? $object->code_client : '');
8362 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object) ? $object->code_fournisseur : '');
8363 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object) ? $object->email : '');
8364 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? dol_print_phone($object->phone) : '');
8365 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? dol_print_phone($object->fax) : '');
8366 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object) ? $object->address : '');
8367 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object) ? $object->zip : '');
8368 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object) ? $object->town : '');
8369 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object) ? $object->country_id : '');
8370 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object) ? $object->country_code : '');
8371 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object) ? $object->idprof1 : '');
8372 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object) ? $object->idprof2 : '');
8373 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object) ? $object->idprof3 : '');
8374 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object) ? $object->idprof4 : '');
8375 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object) ? $object->idprof5 : '');
8376 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object) ? $object->idprof6 : '');
8377 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object) ? $object->tva_intra : '');
8378 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_public) : '');
8379 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_private) : '');
8380 } elseif (is_object($object->thirdparty)) {
8381 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->id : '');
8382 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object->thirdparty) ? $object->thirdparty->name : '');
8383 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object->thirdparty) ? $object->thirdparty->name_alias : '');
8384 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_client : '');
8385 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_fournisseur : '');
8386 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object->thirdparty) ? $object->thirdparty->email : '');
8387 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->phone) : '');
8388 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->fax) : '');
8389 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object->thirdparty) ? $object->thirdparty->address : '');
8390 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object->thirdparty) ? $object->thirdparty->zip : '');
8391 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object->thirdparty) ? $object->thirdparty->town : '');
8392 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_id : '');
8393 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_code : '');
8394 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof1 : '');
8395 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof2 : '');
8396 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof3 : '');
8397 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof4 : '');
8398 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof5 : '');
8399 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof6 : '');
8400 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object->thirdparty) ? $object->thirdparty->tva_intra : '');
8401 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_public) : '');
8402 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_private) : '');
8403 }
8404
8405 if (is_object($object) && $object->element == 'recruitmentcandidature') {
8406 $substitutionarray['__CANDIDATE_FULLNAME__'] = $object->getFullName($outputlangs);
8407 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8408 $substitutionarray['__CANDIDATE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8409 }
8410 if (is_object($object) && $object->element == 'conferenceorboothattendee') {
8411 $substitutionarray['__ATTENDEE_FULLNAME__'] = $object->getFullName($outputlangs);
8412 $substitutionarray['__ATTENDEE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8413 $substitutionarray['__ATTENDEE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8414 }
8415
8416 if (is_object($object) && $object->element == 'project') {
8417 $substitutionarray['__PROJECT_ID__'] = $object->id;
8418 $substitutionarray['__PROJECT_REF__'] = $object->ref;
8419 $substitutionarray['__PROJECT_NAME__'] = $object->title;
8420 } elseif (is_object($object)) {
8421 $project = null;
8422 if (!empty($object->project)) {
8423 $project = $object->project;
8424 } elseif (!empty($object->projet)) { // Deprecated, for backward compatibility
8425 $project = $object->projet;
8426 }
8427 if (!is_null($project) && is_object($project)) {
8428 $substitutionarray['__PROJECT_ID__'] = $project->id;
8429 $substitutionarray['__PROJECT_REF__'] = $project->ref;
8430 $substitutionarray['__PROJECT_NAME__'] = $project->title;
8431 } else {
8432 // can substitute variables for project : uses lazy load in "make_substitutions" method
8433 $project_id = 0;
8434 if (!empty($object->fk_project) && $object->fk_project > 0) {
8435 $project_id = $object->fk_project;
8436 } elseif (!empty($object->fk_projet) && $object->fk_projet > 0) {
8437 $project_id = $object->fk_project;
8438 }
8439 if ($project_id > 0) {
8440 // path:class:method:id
8441 $substitutionarray['__PROJECT_ID__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8442 $substitutionarray['__PROJECT_REF__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8443 $substitutionarray['__PROJECT_NAME__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8444 }
8445 }
8446 }
8447
8448 if (is_object($object) && $object->element == 'shipping') {
8449 $substitutionarray['__SHIPPINGTRACKNUM__'] = $object->tracking_number;
8450 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = $object->tracking_url;
8451 $substitutionarray['__SHIPPINGMETHOD__'] = $object->shipping_method;
8452 }
8453 if (is_object($object) && $object->element == 'reception') {
8454 $substitutionarray['__RECEPTIONTRACKNUM__'] = $object->tracking_number;
8455 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = $object->tracking_url;
8456 }
8457
8458 if (is_object($object) && $object->element == 'contrat' && $object->id > 0 && is_array($object->lines)) {
8459 $dateplannedstart = '';
8460 $datenextexpiration = '';
8461 foreach ($object->lines as $line) {
8462 if ($line->date_start > $dateplannedstart) {
8463 $dateplannedstart = $line->date_start;
8464 }
8465 if ($line->statut == 4 && $line->date_end && (!$datenextexpiration || $line->date_end < $datenextexpiration)) {
8466 $datenextexpiration = $line->date_end;
8467 }
8468 }
8469 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = dol_print_date($dateplannedstart, 'day');
8470 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = dol_print_date($dateplannedstart, 'standard');
8471 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = dol_print_date($datenextexpiration, 'day');
8472 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = dol_print_date($datenextexpiration, 'standard');
8473 }
8474 // add substition variable for ticket
8475 if (is_object($object) && $object->element == 'ticket') {
8476 $substitutionarray['__TICKET_TRACKID__'] = $object->track_id;
8477 $substitutionarray['__REF__'] = $object->ref;
8478 $substitutionarray['__TICKET_SUBJECT__'] = $object->subject;
8479 $substitutionarray['__TICKET_TYPE__'] = $object->type_code;
8480 $substitutionarray['__TICKET_SEVERITY__'] = $object->severity_code;
8481 $substitutionarray['__TICKET_CATEGORY__'] = $object->category_code; // For backward compatibility
8482 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = $object->category_code;
8483 $substitutionarray['__TICKET_MESSAGE__'] = $object->message;
8484 $substitutionarray['__TICKET_PROGRESSION__'] = $object->progress;
8485 $userstat = new User($db);
8486 if ($object->fk_user_assign > 0) {
8487 $userstat->fetch($object->fk_user_assign);
8488 $substitutionarray['__TICKET_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8489 }
8490
8491 if ($object->fk_user_create > 0) {
8492 $userstat->fetch($object->fk_user_create);
8493 $substitutionarray['__USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8494 }
8495 }
8496
8497 // Create dynamic tags for __EXTRAFIELD_FIELD__
8498 if ($object->table_element && $object->id > 0) {
8499 if (!is_object($extrafields)) {
8500 $extrafields = new ExtraFields($db);
8501 }
8502 $extrafields->fetch_name_optionals_label($object->table_element, true);
8503
8504 if ($object->fetch_optionals() > 0) {
8505 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) {
8506 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
8507 if ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
8508 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_date($object->array_options['options_'.$key], 'day');
8509 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = dol_print_date($object->array_options['options_'.$key], 'day', 'tzserver', $outputlangs);
8510 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = dol_print_date($object->array_options['options_'.$key], 'dayrfc');
8511 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'datetime') {
8512 $datetime = $object->array_options['options_'.$key];
8513 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour') : '');
8514 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : '');
8515 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_DAY_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'day', 'tzserver', $outputlangs) : '');
8516 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : '');
8517 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'phone') {
8518 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_phone($object->array_options['options_'.$key]);
8519 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
8520 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = $object->array_options['options_'.$key];
8521 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATED__'] = price($object->array_options['options_'.$key]);
8522 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] != 'separator') {
8523 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = !empty($object->array_options['options_'.$key]) ? $object->array_options['options_'.$key] : '';
8524 }
8525 }
8526 }
8527 }
8528 }
8529
8530 // Complete substitution array with the url to make online payment
8531 $paymenturl = '';
8532 if (empty($substitutionarray['__REF__'])) {
8533 $paymenturl = '';
8534 } else {
8535 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
8536 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
8537 $outputlangs->loadLangs(array('paypal', 'other'));
8538
8539 $amounttouse = 0;
8540 $typeforonlinepayment = 'free';
8541 if (is_object($object) && $object->element == 'commande') {
8542 $typeforonlinepayment = 'order';
8543 }
8544 if (is_object($object) && $object->element == 'facture') {
8545 $typeforonlinepayment = 'invoice';
8546 }
8547 if (is_object($object) && $object->element == 'member') {
8548 $typeforonlinepayment = 'member';
8549 if (!empty($object->last_subscription_amount)) {
8550 $amounttouse = $object->last_subscription_amount;
8551 }
8552 }
8553 if (is_object($object) && $object->element == 'contrat') {
8554 $typeforonlinepayment = 'contract';
8555 }
8556 if (is_object($object) && $object->element == 'fichinter') {
8557 $typeforonlinepayment = 'ficheinter';
8558 }
8559
8560 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__'], $amounttouse);
8561 $paymenturl = $url;
8562 }
8563
8564 if ($object->id > 0) {
8565 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ? str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : '');
8566 $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl;
8567
8568 if (getDolGlobalString('PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'propal') {
8569 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8570 } else {
8571 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = '';
8572 }
8573 if (getDolGlobalString('ORDER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'commande') {
8574 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = $object->getLastMainDocLink($object->element);
8575 } else {
8576 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = '';
8577 }
8578 if (getDolGlobalString('INVOICE_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'facture') {
8579 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = $object->getLastMainDocLink($object->element);
8580 } else {
8581 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = '';
8582 }
8583 if (getDolGlobalString('CONTRACT_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'contrat') {
8584 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = $object->getLastMainDocLink($object->element);
8585 } else {
8586 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = '';
8587 }
8588 if (getDolGlobalString('FICHINTER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'fichinter') {
8589 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = $object->getLastMainDocLink($object->element);
8590 } else {
8591 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = '';
8592 }
8593 if (getDolGlobalString('SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'supplier_proposal') {
8594 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8595 } else {
8596 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = '';
8597 }
8598
8599 if (is_object($object) && $object->element == 'propal') {
8600 $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id;
8601 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8602 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref);
8603 }
8604 if (is_object($object) && $object->element == 'commande') {
8605 $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id;
8606 }
8607 if (is_object($object) && $object->element == 'facture') {
8608 $substitutionarray['__URL_INVOICE__'] = DOL_MAIN_URL_ROOT."/compta/facture/card.php?id=".$object->id;
8609 }
8610 if (is_object($object) && $object->element == 'contrat') {
8611 $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id;
8612 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8613 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref);
8614 }
8615 if (is_object($object) && $object->element == 'fichinter') {
8616 $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id;
8617 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8618 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref);
8619 }
8620 if (is_object($object) && $object->element == 'supplier_proposal') {
8621 $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id;
8622 }
8623 if (is_object($object) && $object->element == 'shipping') {
8624 $substitutionarray['__URL_SHIPMENT__'] = DOL_MAIN_URL_ROOT."/expedition/card.php?id=".$object->id;
8625 }
8626 }
8627
8628 if (is_object($object) && $object->element == 'action') {
8629 $substitutionarray['__EVENT_LABEL__'] = $object->label;
8630 $substitutionarray['__EVENT_TYPE__'] = $outputlangs->trans("Action".$object->type_code);
8631 $substitutionarray['__EVENT_DATE__'] = dol_print_date($object->datep, 'day', 'auto', $outputlangs);
8632 $substitutionarray['__EVENT_TIME__'] = dol_print_date($object->datep, 'hour', 'auto', $outputlangs);
8633 }
8634 }
8635 }
8636 if ((empty($exclude) || !in_array('objectamount', $exclude)) && (empty($include) || in_array('objectamount', $include))) {
8637 include_once DOL_DOCUMENT_ROOT.'/core/lib/functionsnumtoword.lib.php';
8638
8639 $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : '';
8640 $substitutionarray['__DATE_DUE_YMD__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs) : null) : '';
8641
8642 $already_payed_all = 0;
8643 if (is_object($object) && ($object instanceof Facture)) {
8644 $already_payed_all = $object->sumpayed + $object->sumdeposit + $object->sumcreditnote;
8645 }
8646
8647 $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : '';
8648
8649 $substitutionarray['__AMOUNT__'] = is_object($object) ? $object->total_ttc : '';
8650 $substitutionarray['__AMOUNT_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, '', true) : '';
8651 $substitutionarray['__AMOUNT_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, $conf->currency, true) : '';
8652
8653 $substitutionarray['__AMOUNT_REMAIN__'] = is_object($object) ? price2num($object->total_ttc - $already_payed_all, 'MT') : '';
8654
8655 $substitutionarray['__AMOUNT_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8656 $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)) : '';
8657 $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)) : '';
8658
8659 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8660 $substitutionarray['__AMOUNT_TAX2__'] = is_object($object) ? $object->total_localtax1 : '';
8661 }
8662 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8663 $substitutionarray['__AMOUNT_TAX3__'] = is_object($object) ? $object->total_localtax2 : '';
8664 }
8665
8666 // Amount keys formated in a currency
8667 $substitutionarray['__AMOUNT_EXCL_TAX_FORMATED__'] = is_object($object) ? ($object->total_ht ? price($object->total_ht, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8668 $substitutionarray['__AMOUNT_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8669 $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) : '';
8670 $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)) : '';
8671 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8672 $substitutionarray['__AMOUNT_TAX2_FORMATED__'] = is_object($object) ? ($object->total_localtax1 ? price($object->total_localtax1, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8673 }
8674 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8675 $substitutionarray['__AMOUNT_TAX3_FORMATED__'] = is_object($object) ? ($object->total_localtax2 ? price($object->total_localtax2, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8676 }
8677
8678 $substitutionarray['__AMOUNT_MULTICURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? $object->multicurrency_total_ttc : '';
8679 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXT__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, '', true) : '';
8680 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXTCURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, $object->multicurrency_code, true) : '';
8681 // TODO Add other keys for foreign multicurrency
8682
8683 // For backward compatibility
8684 if ($onlykey != 2) {
8685 $substitutionarray['__TOTAL_TTC__'] = is_object($object) ? $object->total_ttc : '';
8686 $substitutionarray['__TOTAL_HT__'] = is_object($object) ? $object->total_ht : '';
8687 $substitutionarray['__TOTAL_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8688 }
8689 }
8690
8691 //var_dump($substitutionarray['__AMOUNT_FORMATED__']);
8692 if ((empty($exclude) || !in_array('date', $exclude)) && (empty($include) || in_array('date', $include))) {
8693 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
8694
8695 $now = dol_now();
8696
8697 $tmp = dol_getdate($now, true);
8698 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8699 $tmp3 = dol_get_prev_month($tmp['mon'], $tmp['year']);
8700 $tmp4 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8701 $tmp5 = dol_get_next_month($tmp['mon'], $tmp['year']);
8702
8703 $daytext = $outputlangs->trans('Day'.$tmp['wday']);
8704
8705 $substitutionarray = array_merge($substitutionarray, array(
8706 '__NOW_TMS__' => (string) $now, // Must be the string that represent the int
8707 '__NOW_TMS_YMD__' => dol_print_date($now, 'day', 'auto', $outputlangs),
8708 '__DAY__' => (string) $tmp['mday'],
8709 '__DAY_TEXT__' => $daytext, // Monday
8710 '__DAY_TEXT_SHORT__' => dol_trunc($daytext, 3, 'right', 'UTF-8', 1), // Mon
8711 '__DAY_TEXT_MIN__' => dol_trunc($daytext, 1, 'right', 'UTF-8', 1), // M
8712 '__MONTH__' => (string) $tmp['mon'],
8713 '__MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp['mon'])),
8714 '__MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp['mon'])),
8715 '__MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp['mon'])),
8716 '__YEAR__' => (string) $tmp['year'],
8717 '__PREVIOUS_DAY__' => (string) $tmp2['day'],
8718 '__PREVIOUS_MONTH__' => (string) $tmp3['month'],
8719 '__PREVIOUS_YEAR__' => (string) ($tmp['year'] - 1),
8720 '__NEXT_DAY__' => (string) $tmp4['day'],
8721 '__NEXT_MONTH__' => (string) $tmp5['month'],
8722 '__NEXT_MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp5['month'])),
8723 '__NEXT_MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp5['month'])),
8724 '__NEXT_MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp5['month'])),
8725 '__NEXT_YEAR__' => (string) ($tmp['year'] + 1),
8726 ));
8727 }
8728
8729 if (isModEnabled('multicompany')) {
8730 $substitutionarray = array_merge($substitutionarray, array('__ENTITY_ID__' => $conf->entity));
8731 }
8732 if ((empty($exclude) || !in_array('system', $exclude)) && (empty($include) || in_array('user', $include))) {
8733 $substitutionarray['__DOL_MAIN_URL_ROOT__'] = DOL_MAIN_URL_ROOT;
8734 $substitutionarray['__(AnyTranslationKey)__'] = $outputlangs->trans('TranslationOfKey');
8735 $substitutionarray['__(AnyTranslationKey|langfile)__'] = $outputlangs->trans('TranslationOfKey').' (load also language file before)';
8736 $substitutionarray['__[AnyConstantKey]__'] = $outputlangs->trans('ValueOfConstantKey');
8737 }
8738
8739 // Note: The lazyload variables are replaced only during the call by make_substitutions, and only if necessary
8740
8741 return $substitutionarray;
8742}
8743
8760function make_substitutions($text, $substitutionarray, $outputlangs = null, $converttextinhtmlifnecessary = 0)
8761{
8762 global $conf, $db, $langs;
8763
8764 if (!is_array($substitutionarray)) {
8765 return 'ErrorBadParameterSubstitutionArrayWhenCalling_make_substitutions';
8766 }
8767
8768 if (empty($outputlangs)) {
8769 $outputlangs = $langs;
8770 }
8771
8772 // Is initial text HTML or simple text ?
8773 $msgishtml = 0;
8774 if (dol_textishtml($text, 1)) {
8775 $msgishtml = 1;
8776 }
8777
8778 // Make substitution for language keys: __(AnyTranslationKey)__ or __(AnyTranslationKey|langfile)__
8779 if (is_object($outputlangs)) {
8780 $reg = array();
8781 while (preg_match('/__\‍(([^\‍)]+)\‍)__/', $text, $reg)) {
8782 // If key is __(TranslationKey|langfile)__, then force load of langfile.lang
8783 $tmp = explode('|', $reg[1]);
8784 if (!empty($tmp[1])) {
8785 $outputlangs->load($tmp[1]);
8786 }
8787
8788 $value = $outputlangs->transnoentitiesnoconv($reg[1]);
8789
8790 if (empty($converttextinhtmlifnecessary)) {
8791 // convert $newval into HTML is necessary
8792 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8793 } else {
8794 if (! $msgishtml) {
8795 $valueishtml = dol_textishtml($value, 1);
8796 //var_dump("valueishtml=".$valueishtml);
8797
8798 if ($valueishtml) {
8799 $text = dol_htmlentitiesbr($text);
8800 $msgishtml = 1;
8801 }
8802 } else {
8803 $value = dol_nl2br("$value");
8804 }
8805
8806 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $value, $text);
8807 }
8808 }
8809 }
8810
8811 // Make substitution for constant keys.
8812 // Must be after the substitution of translation, so if the text of translation contains a string __[xxx]__, it is also converted.
8813 $reg = array();
8814 while (preg_match('/__\[([^\]]+)\]__/', $text, $reg)) {
8815 $keyfound = $reg[1];
8816 if (isASecretKey($keyfound)) {
8817 $value = '*****forbidden*****';
8818 } else {
8819 $value = empty($conf->global->$keyfound) ? '' : $conf->global->$keyfound;
8820 }
8821
8822 if (empty($converttextinhtmlifnecessary)) {
8823 // convert $newval into HTML is necessary
8824 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8825 } else {
8826 if (! $msgishtml) {
8827 $valueishtml = dol_textishtml($value, 1);
8828
8829 if ($valueishtml) {
8830 $text = dol_htmlentitiesbr($text);
8831 $msgishtml = 1;
8832 }
8833 } else {
8834 $value = dol_nl2br("$value");
8835 }
8836
8837 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $value, $text);
8838 }
8839 }
8840
8841 // Make substitution for array $substitutionarray
8842 foreach ($substitutionarray as $key => $value) {
8843 if (!isset($value)) {
8844 continue; // If value is null, it same than not having substitution key at all into array, we do not replace.
8845 }
8846
8847 if (($key == '__USER_SIGNATURE__' || $key == '__SENDEREMAIL_SIGNATURE__') && (getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN'))) {
8848 $value = ''; // Protection
8849 }
8850
8851 if (empty($converttextinhtmlifnecessary)) {
8852 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8853 } else {
8854 if (! $msgishtml) {
8855 $valueishtml = dol_textishtml($value, 1);
8856
8857 if ($valueishtml) {
8858 $text = dol_htmlentitiesbr($text);
8859 $msgishtml = 1;
8860 }
8861 } else {
8862 $value = dol_nl2br("$value");
8863 }
8864 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8865 }
8866 }
8867
8868 // TODO Implement the lazyload substitution
8869 /*
8870 add a loop to scan $substitutionarray:
8871 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.
8872 If no, we don't need to make replacement, so we do nothing.
8873 If yes, we can make the substitution:
8874
8875 include_once $path;
8876 $tmpobj = new $class($db);
8877 $valuetouseforsubstitution = $tmpobj->$method($id, '__XXX__');
8878 And make the replacement of "__XXX__@lazyload" with $valuetouseforsubstitution
8879 */
8880 $memory_object_list = array();
8881 foreach ($substitutionarray as $key => $value) {
8882 $lazy_load_arr = array();
8883 if (preg_match('/(__[A-Z\_]+__)@lazyload$/', $key, $lazy_load_arr)) {
8884 if (isset($lazy_load_arr[1]) && !empty($lazy_load_arr[1])) {
8885 $key_to_substitute = $lazy_load_arr[1];
8886 if (preg_match('/' . preg_quote($key_to_substitute, '/') . '/', $text)) {
8887 $param_arr = explode(':', $value);
8888 // path:class:method:id
8889 if (count($param_arr) == 4) {
8890 $path = $param_arr[0];
8891 $class = $param_arr[1];
8892 $method = $param_arr[2];
8893 $id = (int) $param_arr[3];
8894
8895 // load class file and init object list in memory
8896 if (!isset($memory_object_list[$class])) {
8897 if (dol_is_file(DOL_DOCUMENT_ROOT . $path)) {
8898 require_once DOL_DOCUMENT_ROOT . $path;
8899 if (class_exists($class)) {
8900 $memory_object_list[$class] = array(
8901 'list' => array(),
8902 );
8903 }
8904 }
8905 }
8906
8907 // fetch object and set substitution
8908 if (isset($memory_object_list[$class]) && isset($memory_object_list[$class]['list'])) {
8909 if (method_exists($class, $method)) {
8910 if (!isset($memory_object_list[$class]['list'][$id])) {
8911 $tmpobj = new $class($db);
8912 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute);
8913 $memory_object_list[$class]['list'][$id] = $tmpobj;
8914 } else {
8915 $tmpobj = $memory_object_list[$class]['list'][$id];
8916 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute, true);
8917 }
8918
8919 $text = str_replace("$key_to_substitute", "$valuetouseforsubstitution", $text); // We must keep the " to work when value is 123.5 for example
8920 }
8921 }
8922 }
8923 }
8924 }
8925 }
8926 }
8927
8928 return $text;
8929}
8930
8943function complete_substitutions_array(&$substitutionarray, $outputlangs, $object = null, $parameters = null, $callfunc = "completesubstitutionarray")
8944{
8945 global $conf, $user;
8946
8947 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
8948
8949 // Note: substitution key for each extrafields, using key __EXTRA_XXX__ is already available into the getCommonSubstitutionArray used to build the substitution array.
8950
8951 // Check if there is external substitution to do, requested by plugins
8952 $dirsubstitutions = array_merge(array(), (array) $conf->modules_parts['substitutions']);
8953
8954 foreach ($dirsubstitutions as $reldir) {
8955 $dir = dol_buildpath($reldir, 0);
8956
8957 // Check if directory exists
8958 if (!dol_is_dir($dir)) {
8959 continue;
8960 }
8961
8962 $substitfiles = dol_dir_list($dir, 'files', 0, 'functions_');
8963 foreach ($substitfiles as $substitfile) {
8964 $reg = array();
8965 if (preg_match('/functions_(.*)\.lib\.php/i', $substitfile['name'], $reg)) {
8966 $module = $reg[1];
8967
8968 dol_syslog("Library ".$substitfile['name']." found into ".$dir);
8969 // Include the user's functions file
8970 require_once $dir.$substitfile['name'];
8971 // Call the user's function, and only if it is defined
8972 $function_name = $module."_".$callfunc;
8973 if (function_exists($function_name)) {
8974 $function_name($substitutionarray, $outputlangs, $object, $parameters);
8975 }
8976 }
8977 }
8978 }
8979 if (getDolGlobalString('ODT_ENABLE_ALL_TAGS_IN_SUBSTITUTIONS')) {
8980 // to list all tags in odt template
8981 $tags = '';
8982 foreach ($substitutionarray as $key => $value) {
8983 $tags .= '{'.$key.'} => '.$value."\n";
8984 }
8985 $substitutionarray = array_merge($substitutionarray, array('__ALL_TAGS__' => $tags));
8986 }
8987}
8988
8998function print_date_range($date_start, $date_end, $format = '', $outputlangs = '')
8999{
9000 print get_date_range($date_start, $date_end, $format, $outputlangs);
9001}
9002
9013function get_date_range($date_start, $date_end, $format = '', $outputlangs = '', $withparenthesis = 1)
9014{
9015 global $langs;
9016
9017 $out = '';
9018
9019 if (!is_object($outputlangs)) {
9020 $outputlangs = $langs;
9021 }
9022
9023 if ($date_start && $date_end) {
9024 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFromTo', dol_print_date($date_start, $format, false, $outputlangs), dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9025 }
9026 if ($date_start && !$date_end) {
9027 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($date_start, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9028 }
9029 if (!$date_start && $date_end) {
9030 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9031 }
9032
9033 return $out;
9034}
9035
9044function dolGetFirstLastname($firstname, $lastname, $nameorder = -1)
9045{
9046 global $conf;
9047
9048 $ret = '';
9049 // If order not defined, we use the setup
9050 if ($nameorder < 0) {
9051 $nameorder = (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION') ? 1 : 0);
9052 }
9053 if ($nameorder == 1) {
9054 $ret .= $firstname;
9055 if ($firstname && $lastname) {
9056 $ret .= ' ';
9057 }
9058 $ret .= $lastname;
9059 } elseif ($nameorder == 2 || $nameorder == 3) {
9060 $ret .= $firstname;
9061 if (empty($ret) && $nameorder == 3) {
9062 $ret .= $lastname;
9063 }
9064 } else { // 0, 4 or 5
9065 $ret .= $lastname;
9066 if (empty($ret) && $nameorder == 5) {
9067 $ret .= $firstname;
9068 }
9069 if ($nameorder == 0) {
9070 if ($firstname && $lastname) {
9071 $ret .= ' ';
9072 }
9073 $ret .= $firstname;
9074 }
9075 }
9076 return $ret;
9077}
9078
9079
9091function setEventMessage($mesgs, $style = 'mesgs', $noduplicate = 0)
9092{
9093 //dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING); This is not deprecated, it is used by setEventMessages function
9094 if (!is_array($mesgs)) {
9095 $mesgs = trim((string) $mesgs);
9096 // If mesgs is a not an empty string
9097 if ($mesgs) {
9098 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesgs, $_SESSION['dol_events'][$style])) {
9099 return;
9100 }
9101 $_SESSION['dol_events'][$style][] = $mesgs;
9102 }
9103 } else {
9104 // If mesgs is an array
9105 foreach ($mesgs as $mesg) {
9106 $mesg = trim((string) $mesg);
9107 if ($mesg) {
9108 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesg, $_SESSION['dol_events'][$style])) {
9109 return;
9110 }
9111 $_SESSION['dol_events'][$style][] = $mesg;
9112 }
9113 }
9114 }
9115}
9116
9129function setEventMessages($mesg, $mesgs, $style = 'mesgs', $messagekey = '', $noduplicate = 0)
9130{
9131 if (empty($mesg) && empty($mesgs)) {
9132 dol_syslog("Try to add a message in stack, but value to add is empty message", LOG_WARNING);
9133 } else {
9134 if ($messagekey) {
9135 // Complete message with a js link to set a cookie "DOLHIDEMESSAGE".$messagekey;
9136 // TODO
9137 $mesg .= '';
9138 }
9139 if (empty($messagekey) || empty($_COOKIE["DOLHIDEMESSAGE".$messagekey])) {
9140 if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
9141 dol_print_error('', 'Bad parameter style='.$style.' for setEventMessages');
9142 }
9143 if (empty($mesgs)) {
9144 setEventMessage($mesg, $style, $noduplicate);
9145 } else {
9146 if (!empty($mesg) && !in_array($mesg, $mesgs)) {
9147 setEventMessage($mesg, $style, $noduplicate); // Add message string if not already into array
9148 }
9149 setEventMessage($mesgs, $style, $noduplicate);
9150 }
9151 }
9152 }
9153}
9154
9164function dol_htmloutput_events($disabledoutputofmessages = 0)
9165{
9166 // Show mesgs
9167 if (isset($_SESSION['dol_events']['mesgs'])) {
9168 if (empty($disabledoutputofmessages)) {
9169 dol_htmloutput_mesg('', $_SESSION['dol_events']['mesgs']);
9170 }
9171 unset($_SESSION['dol_events']['mesgs']);
9172 }
9173 // Show errors
9174 if (isset($_SESSION['dol_events']['errors'])) {
9175 if (empty($disabledoutputofmessages)) {
9176 dol_htmloutput_mesg('', $_SESSION['dol_events']['errors'], 'error');
9177 }
9178 unset($_SESSION['dol_events']['errors']);
9179 }
9180
9181 // Show warnings
9182 if (isset($_SESSION['dol_events']['warnings'])) {
9183 if (empty($disabledoutputofmessages)) {
9184 dol_htmloutput_mesg('', $_SESSION['dol_events']['warnings'], 'warning');
9185 }
9186 unset($_SESSION['dol_events']['warnings']);
9187 }
9188}
9189
9204function get_htmloutput_mesg($mesgstring = '', $mesgarray = '', $style = 'ok', $keepembedded = 0)
9205{
9206 global $conf, $langs;
9207
9208 $ret = 0;
9209 $return = '';
9210 $out = '';
9211 $divstart = $divend = '';
9212
9213 // If inline message with no format, we add it.
9214 if ((empty($conf->use_javascript_ajax) || getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') || $keepembedded) && !preg_match('/<div class=".*">/i', $out)) {
9215 $divstart = '<div class="'.$style.' clearboth">';
9216 $divend = '</div>';
9217 }
9218
9219 if ((is_array($mesgarray) && count($mesgarray)) || $mesgstring) {
9220 $langs->load("errors");
9221 $out .= $divstart;
9222 if (is_array($mesgarray) && count($mesgarray)) {
9223 foreach ($mesgarray as $message) {
9224 $ret++;
9225 $out .= $langs->trans($message);
9226 if ($ret < count($mesgarray)) {
9227 $out .= "<br>\n";
9228 }
9229 }
9230 }
9231 if ($mesgstring) {
9232 $ret++;
9233 $out .= $langs->trans($mesgstring);
9234 }
9235 $out .= $divend;
9236 }
9237
9238 if ($out) {
9239 if (!empty($conf->use_javascript_ajax) && !getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') && empty($keepembedded)) {
9240 $return = '<script nonce="'.getNonce().'">
9241 $(document).ready(function() {
9242 var block = '.(getDolGlobalString('MAIN_USE_JQUERY_BLOCKUI') ? "true" : "false").'
9243 if (block) {
9244 $.dolEventValid("","'.dol_escape_js($out).'");
9245 } else {
9246 /* jnotify(message, preset of message type, keepmessage) */
9247 $.jnotify("'.dol_escape_js($out).'",
9248 "'.($style == "ok" ? 3000 : $style).'",
9249 '.($style == "ok" ? "false" : "true").',
9250 { remove: function (){} } );
9251 }
9252 });
9253 </script>';
9254 } else {
9255 $return = $out;
9256 }
9257 }
9258
9259 return $return;
9260}
9261
9273function get_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9274{
9275 return get_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9276}
9277
9291function dol_htmloutput_mesg($mesgstring = '', $mesgarray = array(), $style = 'ok', $keepembedded = 0)
9292{
9293 if (empty($mesgstring) && (!is_array($mesgarray) || count($mesgarray) == 0)) {
9294 return;
9295 }
9296
9297 $iserror = 0;
9298 $iswarning = 0;
9299 if (is_array($mesgarray)) {
9300 foreach ($mesgarray as $val) {
9301 if ($val && preg_match('/class="error"/i', $val)) {
9302 $iserror++;
9303 break;
9304 }
9305 if ($val && preg_match('/class="warning"/i', $val)) {
9306 $iswarning++;
9307 break;
9308 }
9309 }
9310 } elseif ($mesgstring && preg_match('/class="error"/i', $mesgstring)) {
9311 $iserror++;
9312 } elseif ($mesgstring && preg_match('/class="warning"/i', $mesgstring)) {
9313 $iswarning++;
9314 }
9315 if ($style == 'error') {
9316 $iserror++;
9317 }
9318 if ($style == 'warning') {
9319 $iswarning++;
9320 }
9321
9322 if ($iserror || $iswarning) {
9323 // Remove div from texts
9324 $mesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $mesgstring);
9325 $mesgstring = preg_replace('/<div class="(error|warning)">/', '', $mesgstring);
9326 $mesgstring = preg_replace('/<\/div>/', '', $mesgstring);
9327 // Remove div from texts array
9328 if (is_array($mesgarray)) {
9329 $newmesgarray = array();
9330 foreach ($mesgarray as $val) {
9331 if (is_string($val)) {
9332 $tmpmesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $val);
9333 $tmpmesgstring = preg_replace('/<div class="(error|warning)">/', '', $tmpmesgstring);
9334 $tmpmesgstring = preg_replace('/<\/div>/', '', $tmpmesgstring);
9335 $newmesgarray[] = $tmpmesgstring;
9336 } else {
9337 dol_syslog("Error call of dol_htmloutput_mesg with an array with a value that is not a string", LOG_WARNING);
9338 }
9339 }
9340 $mesgarray = $newmesgarray;
9341 }
9342 print get_htmloutput_mesg($mesgstring, $mesgarray, ($iserror ? 'error' : 'warning'), $keepembedded);
9343 } else {
9344 print get_htmloutput_mesg($mesgstring, $mesgarray, 'ok', $keepembedded);
9345 }
9346}
9347
9359function dol_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9360{
9361 dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9362}
9363
9378function dol_sort_array(&$array, $index, $order = 'asc', $natsort = 0, $case_sensitive = 0, $keepindex = 0)
9379{
9380 // Clean parameters
9381 $order = strtolower($order);
9382
9383 if (is_array($array)) {
9384 $sizearray = count($array);
9385 if ($sizearray > 0) {
9386 $temp = array();
9387 foreach (array_keys($array) as $key) {
9388 if (is_object($array[$key])) {
9389 $temp[$key] = empty($array[$key]->$index) ? 0 : $array[$key]->$index;
9390 } else {
9391 $temp[$key] = empty($array[$key][$index]) ? 0 : $array[$key][$index];
9392 }
9393 if ($natsort == -1) {
9394 $temp[$key] = '___'.$temp[$key]; // We add a string at begin of value to force an alpha order when using asort.
9395 }
9396 }
9397
9398 if (empty($natsort) || $natsort == -1) {
9399 if ($order == 'asc') {
9400 asort($temp);
9401 } else {
9402 arsort($temp);
9403 }
9404 } else {
9405 if ($case_sensitive) {
9406 natsort($temp);
9407 } else {
9408 natcasesort($temp); // natecasesort is not sensible to case
9409 }
9410 if ($order != 'asc') {
9411 $temp = array_reverse($temp, true);
9412 }
9413 }
9414
9415 $sorted = array();
9416
9417 foreach (array_keys($temp) as $key) {
9418 (is_numeric($key) && empty($keepindex)) ? $sorted[] = $array[$key] : $sorted[$key] = $array[$key];
9419 }
9420
9421 return $sorted;
9422 }
9423 }
9424 return $array;
9425}
9426
9427
9435function utf8_check($str)
9436{
9437 $str = (string) $str; // Sometimes string is an int.
9438
9439 // We must use here a binary strlen function (so not dol_strlen)
9440 $strLength = strlen($str);
9441 for ($i = 0; $i < $strLength; $i++) {
9442 if (ord($str[$i]) < 0x80) {
9443 continue; // 0bbbbbbb
9444 } elseif ((ord($str[$i]) & 0xE0) == 0xC0) {
9445 $n = 1; // 110bbbbb
9446 } elseif ((ord($str[$i]) & 0xF0) == 0xE0) {
9447 $n = 2; // 1110bbbb
9448 } elseif ((ord($str[$i]) & 0xF8) == 0xF0) {
9449 $n = 3; // 11110bbb
9450 } elseif ((ord($str[$i]) & 0xFC) == 0xF8) {
9451 $n = 4; // 111110bb
9452 } elseif ((ord($str[$i]) & 0xFE) == 0xFC) {
9453 $n = 5; // 1111110b
9454 } else {
9455 return false; // Does not match any model
9456 }
9457 for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
9458 if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80)) {
9459 return false;
9460 }
9461 }
9462 }
9463 return true;
9464}
9465
9473function utf8_valid($str)
9474{
9475 /* 2 other methods to test if string is utf8
9476 $validUTF8 = mb_check_encoding($messagetext, 'UTF-8');
9477 $validUTF8b = ! (false === mb_detect_encoding($messagetext, 'UTF-8', true));
9478 */
9479 return preg_match('//u', $str) ? true : false;
9480}
9481
9482
9489function ascii_check($str)
9490{
9491 if (function_exists('mb_check_encoding')) {
9492 //if (mb_detect_encoding($str, 'ASCII', true) return false;
9493 if (!mb_check_encoding($str, 'ASCII')) {
9494 return false;
9495 }
9496 } else {
9497 if (preg_match('/[^\x00-\x7f]/', $str)) {
9498 return false; // Contains a byte > 7f
9499 }
9500 }
9501
9502 return true;
9503}
9504
9505
9513function dol_osencode($str)
9514{
9515 global $conf;
9516
9517 $tmp = ini_get("unicode.filesystem_encoding"); // Disponible avec PHP 6.0
9518 if (empty($tmp) && !empty($_SERVER["WINDIR"])) {
9519 $tmp = 'iso-8859-1'; // By default for windows
9520 }
9521 if (empty($tmp)) {
9522 $tmp = 'utf-8'; // By default for other
9523 }
9524 if (getDolGlobalString('MAIN_FILESYSTEM_ENCODING')) {
9525 $tmp = $conf->global->MAIN_FILESYSTEM_ENCODING;
9526 }
9527
9528 if ($tmp == 'iso-8859-1') {
9529 return mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8');
9530 }
9531 return $str;
9532}
9533
9534
9549function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '')
9550{
9551 global $cache_codes;
9552
9553 // If key empty
9554 if ($key == '') {
9555 return '';
9556 }
9557
9558 // Check in cache
9559 if (isset($cache_codes[$tablename][$key][$fieldid])) { // Can be defined to 0 or ''
9560 return $cache_codes[$tablename][$key][$fieldid]; // Found in cache
9561 }
9562
9563 dol_syslog('dol_getIdFromCode (value for field '.$fieldid.' from key '.$key.' not found into cache)', LOG_DEBUG);
9564
9565 $sql = "SELECT ".$fieldid." as valuetoget";
9566 $sql .= " FROM ".MAIN_DB_PREFIX.$tablename;
9567 $sql .= " WHERE ".$fieldkey." = '".$db->escape($key)."'";
9568 if (!empty($entityfilter)) {
9569 $sql .= " AND entity IN (".getEntity($tablename).")";
9570 }
9571 if ($filters) {
9572 $sql .= $filters;
9573 }
9574
9575 $resql = $db->query($sql);
9576 if ($resql) {
9577 $obj = $db->fetch_object($resql);
9578 if ($obj) {
9579 $cache_codes[$tablename][$key][$fieldid] = $obj->valuetoget;
9580 } else {
9581 $cache_codes[$tablename][$key][$fieldid] = '';
9582 }
9583 $db->free($resql);
9584 return $cache_codes[$tablename][$key][$fieldid];
9585 } else {
9586 return -1;
9587 }
9588}
9589
9599function isStringVarMatching($var, $regextext, $matchrule = 1)
9600{
9601 if ($matchrule == 1) {
9602 if ($var == 'mainmenu') {
9603 global $mainmenu;
9604 return (preg_match('/^'.$regextext.'/', $mainmenu));
9605 } elseif ($var == 'leftmenu') {
9606 global $leftmenu;
9607 return (preg_match('/^'.$regextext.'/', $leftmenu));
9608 } else {
9609 return 'This variable is not accessible with dol_eval';
9610 }
9611 } else {
9612 return 'This value for matchrule is not implemented';
9613 }
9614}
9615
9616
9623function verifCond($strToEvaluate)
9624{
9625 //print $strToEvaluate."<br>\n";
9626 $rights = true;
9627 if (isset($strToEvaluate) && $strToEvaluate !== '') {
9628 //var_dump($strToEvaluate);
9629 //$rep = dol_eval($strToEvaluate, 1, 0, '1'); // to show the error
9630 $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
9631 $rights = $rep && (!is_string($rep) || strpos($rep, 'Bad string syntax to evaluate') === false);
9632 //var_dump($rights);
9633 }
9634 return $rights;
9635}
9636
9650function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1')
9651{
9652 // Only this global variables can be read by eval function and returned to caller
9653 global $conf; // Read of const is done with getDolGlobalString() but we need $conf->currency for example
9654 global $db, $langs, $user, $website, $websitepage;
9655 global $action, $mainmenu, $leftmenu;
9656 global $mysoc;
9657 global $objectoffield; // To allow the use of $objectoffield in computed fields
9658
9659 // Old variables used
9660 global $object;
9661 global $obj; // To get $obj used into list when dol_eval() is used for computed fields and $obj is not yet $object
9662
9663 if (!in_array($onlysimplestring, array('0', '1', '2'))) {
9664 return "Bad call of dol_eval. Parameter onlysimplestring must be '0' (deprecated), '1' or '2'";
9665 }
9666
9667 try {
9668 // Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing
9669 if ($onlysimplestring == '1') {
9670 // We must accept: '1 && getDolGlobalInt("doesnotexist1") && getDolGlobalString("MAIN_FEATURES_LEVEL")'
9671 // We must accept: '$user->hasRight("cabinetmed", "read") && !$object->canvas=="patient@cabinetmed"'
9672 $specialcharsallowed = '^$_+-.*>&|=!?():"\',/@';
9673 if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
9674 $specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
9675 }
9676 if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
9677 if ($returnvalue) {
9678 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9679 } else {
9680 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9681 return '';
9682 }
9683 }
9684 $savescheck = '';
9685 $scheck = $s;
9686 while ($scheck && $savescheck != $scheck) {
9687 $savescheck = $scheck;
9688 $scheck = preg_replace('/->[a-zA-Z0-9_]+\‍(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
9689 $scheck = preg_replace('/^\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9690 $scheck = preg_replace('/\s\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9691 $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
9692 $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
9693 $scheck = preg_replace('/(\^|\')\‍(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
9694 }
9695 //print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
9696 if (strpos($scheck, '(') !== false) {
9697 if ($returnvalue) {
9698 return 'Bad string syntax to evaluate (mode 1, found call of a function or method without using the direct name of the function): '.$s;
9699 } else {
9700 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);
9701 return '';
9702 }
9703 }
9704 // TODO
9705 // We can exclude $ char that are not: $db, $langs, $leftmenu, $topmenu, $user, $langs, $objectoffield, $object...,
9706 } elseif ($onlysimplestring == '2') {
9707 // 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"
9708 $specialcharsallowed = '^$_+-.*>&|=!?():"\',/@[]';
9709 if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
9710 $specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
9711 }
9712 if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
9713 if ($returnvalue) {
9714 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9715 } else {
9716 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9717 return '';
9718 }
9719 }
9720 $savescheck = '';
9721 $scheck = $s;
9722 while ($scheck && $savescheck != $scheck) {
9723 $savescheck = $scheck;
9724 $scheck = preg_replace('/->[a-zA-Z0-9_]+\‍(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
9725 $scheck = preg_replace('/^\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9726 $scheck = preg_replace('/\s\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9727 $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
9728 $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
9729 $scheck = preg_replace('/(\^|\')\‍(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
9730 }
9731 //print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
9732 if (strpos($scheck, '(') !== false) {
9733 if ($returnvalue) {
9734 return 'Bad string syntax to evaluate (mode 2, found call of a function or method without using the direct name of the function): '.$s;
9735 } else {
9736 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);
9737 return '';
9738 }
9739 }
9740 // TODO
9741 // We can exclude $ char that are not: $db, $leftmenu, $topmenu, $user, $langs, $object...,
9742 }
9743 if (is_array($s) || $s === 'Array') {
9744 return 'Bad string syntax to evaluate (value is Array) '.var_export($s, true);
9745 }
9746 if (strpos($s, '::') !== false) {
9747 if ($returnvalue) {
9748 return 'Bad string syntax to evaluate (double : char is forbidden): '.$s;
9749 } else {
9750 dol_syslog('Bad string syntax to evaluate (double : char is forbidden): '.$s);
9751 return '';
9752 }
9753 }
9754 if (strpos($s, '`') !== false) {
9755 if ($returnvalue) {
9756 return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
9757 } else {
9758 dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s);
9759 return '';
9760 }
9761 }
9762 if (preg_match('/[^0-9]+\.[^0-9]+/', $s)) { // We refuse . if not between 2 numbers
9763 if ($returnvalue) {
9764 return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
9765 } else {
9766 dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s);
9767 return '';
9768 }
9769 }
9770
9771 // We block use of php exec or php file functions
9772 $forbiddenphpstrings = array('$$');
9773 $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
9774
9775 $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen");
9776 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
9777 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64_decode", "rawurldecode", "urldecode", "str_rot13", "hex2bin")); // decode string functions used to obfuscated function name
9778 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
9779 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
9780 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));
9781 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
9782 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
9783
9784 $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
9785
9786 $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
9787
9788 $forbiddenphpmethodsregex = '->('.implode('|', $forbiddenphpmethods).')';
9789
9790 do {
9791 $oldstringtoclean = $s;
9792 $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);
9793 $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);
9794 $s = preg_replace('/'.$forbiddenphpmethodsregex.'/i', '__forbiddenstring__', $s);
9795 //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\‍(/i', '', $s); // Remove $function( call and $mycall->mymethod(
9796 } while ($oldstringtoclean != $s);
9797
9798 if (strpos($s, '__forbiddenstring__') !== false) {
9799 dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
9800 if ($returnvalue) {
9801 return 'Bad string syntax to evaluate: '.$s;
9802 } else {
9803 dol_syslog('Bad string syntax to evaluate: '.$s);
9804 return '';
9805 }
9806 }
9807
9808 //print $s."<br>\n";
9809 if ($returnvalue) {
9810 if ($hideerrors) {
9811 return @eval('return '.$s.';');
9812 } else {
9813 return eval('return '.$s.';');
9814 }
9815 } else {
9816 if ($hideerrors) {
9817 @eval($s);
9818 } else {
9819 eval($s);
9820 }
9821 }
9822 } catch (Error $e) {
9823 $error = 'dol_eval try/catch error : ';
9824 $error .= $e->getMessage();
9825 dol_syslog($error, LOG_WARNING);
9826 }
9827}
9828
9836function dol_validElement($element)
9837{
9838 return (trim($element) != '');
9839}
9840
9849function picto_from_langcode($codelang, $moreatt = '', $notitlealt = 0)
9850{
9851 if (empty($codelang)) {
9852 return '';
9853 }
9854
9855 if ($codelang == 'auto') {
9856 return '<span class="fa fa-language"></span>';
9857 }
9858
9859 $langtocountryflag = array(
9860 'ar_AR' => '',
9861 'ca_ES' => 'catalonia',
9862 'da_DA' => 'dk',
9863 'fr_CA' => 'mq',
9864 'sv_SV' => 'se',
9865 'sw_SW' => 'unknown',
9866 'AQ' => 'unknown',
9867 'CW' => 'unknown',
9868 'IM' => 'unknown',
9869 'JE' => 'unknown',
9870 'MF' => 'unknown',
9871 'BL' => 'unknown',
9872 'SX' => 'unknown'
9873 );
9874
9875 if (isset($langtocountryflag[$codelang])) {
9876 $flagImage = $langtocountryflag[$codelang];
9877 } else {
9878 $tmparray = explode('_', $codelang);
9879 $flagImage = empty($tmparray[1]) ? $tmparray[0] : $tmparray[1];
9880 }
9881
9882 $morecss = '';
9883 $reg = array();
9884 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
9885 $morecss = $reg[1];
9886 $moreatt = "";
9887 }
9888
9889 // return img_picto_common($codelang, 'flags/'.strtolower($flagImage).'.png', $moreatt, 0, $notitlealt);
9890 return '<span class="flag-sprite '.strtolower($flagImage).($morecss ? ' '.$morecss : '').'"'.($moreatt ? ' '.$moreatt : '').(!$notitlealt ? ' title="'.$codelang.'"' : '').'></span>';
9891}
9892
9901{
9902 global $mysoc;
9903
9904 if (empty($countrycode)) {
9905 return null;
9906 }
9907
9908 if (strtoupper($countrycode) == 'MQ') {
9909 return 'fr_CA';
9910 }
9911 if (strtoupper($countrycode) == 'SE') {
9912 return 'sv_SE'; // se_SE is Sami/Sweden, and we want in priority sv_SE for SE country
9913 }
9914 if (strtoupper($countrycode) == 'CH') {
9915 if ($mysoc->country_code == 'FR') {
9916 return 'fr_CH';
9917 }
9918 if ($mysoc->country_code == 'DE') {
9919 return 'de_CH';
9920 }
9921 if ($mysoc->country_code == 'IT') {
9922 return 'it_CH';
9923 }
9924 }
9925
9926 // Locale list taken from:
9927 // http://stackoverflow.com/questions/3191664/
9928 // list-of-all-locales-and-their-short-codes
9929 $locales = array(
9930 'af-ZA',
9931 'am-ET',
9932 'ar-AE',
9933 'ar-BH',
9934 'ar-DZ',
9935 'ar-EG',
9936 'ar-IQ',
9937 'ar-JO',
9938 'ar-KW',
9939 'ar-LB',
9940 'ar-LY',
9941 'ar-MA',
9942 'ar-OM',
9943 'ar-QA',
9944 'ar-SA',
9945 'ar-SY',
9946 'ar-TN',
9947 'ar-YE',
9948 //'as-IN', // Moved after en-IN
9949 'ba-RU',
9950 'be-BY',
9951 'bg-BG',
9952 'bn-BD',
9953 //'bn-IN', // Moved after en-IN
9954 'bo-CN',
9955 'br-FR',
9956 'ca-ES',
9957 'co-FR',
9958 'cs-CZ',
9959 'cy-GB',
9960 'da-DK',
9961 'de-AT',
9962 'de-CH',
9963 'de-DE',
9964 'de-LI',
9965 'de-LU',
9966 'dv-MV',
9967 'el-GR',
9968 'en-AU',
9969 'en-BZ',
9970 'en-CA',
9971 'en-GB',
9972 'en-IE',
9973 'en-IN',
9974 'as-IN', // as-IN must be after en-IN (en in priority if country is IN)
9975 'bn-IN', // bn-IN must be after en-IN (en in priority if country is IN)
9976 'en-JM',
9977 'en-MY',
9978 'en-NZ',
9979 'en-PH',
9980 'en-SG',
9981 'en-TT',
9982 'en-US',
9983 'en-ZA',
9984 'en-ZW',
9985 'es-AR',
9986 'es-BO',
9987 'es-CL',
9988 'es-CO',
9989 'es-CR',
9990 'es-DO',
9991 'es-EC',
9992 'es-ES',
9993 'es-GT',
9994 'es-HN',
9995 'es-MX',
9996 'es-NI',
9997 'es-PA',
9998 'es-PE',
9999 'es-PR',
10000 'es-PY',
10001 'es-SV',
10002 'es-US',
10003 'es-UY',
10004 'es-VE',
10005 'et-EE',
10006 'eu-ES',
10007 'fa-IR',
10008 'fi-FI',
10009 'fo-FO',
10010 'fr-BE',
10011 'fr-CA',
10012 'fr-CH',
10013 'fr-FR',
10014 'fr-LU',
10015 'fr-MC',
10016 'fy-NL',
10017 'ga-IE',
10018 'gd-GB',
10019 'gl-ES',
10020 'gu-IN',
10021 'he-IL',
10022 'hi-IN',
10023 'hr-BA',
10024 'hr-HR',
10025 'hu-HU',
10026 'hy-AM',
10027 'id-ID',
10028 'ig-NG',
10029 'ii-CN',
10030 'is-IS',
10031 'it-CH',
10032 'it-IT',
10033 'ja-JP',
10034 'ka-GE',
10035 'kk-KZ',
10036 'kl-GL',
10037 'km-KH',
10038 'kn-IN',
10039 'ko-KR',
10040 'ky-KG',
10041 'lb-LU',
10042 'lo-LA',
10043 'lt-LT',
10044 'lv-LV',
10045 'mi-NZ',
10046 'mk-MK',
10047 'ml-IN',
10048 'mn-MN',
10049 'mr-IN',
10050 'ms-BN',
10051 'ms-MY',
10052 'mt-MT',
10053 'nb-NO',
10054 'ne-NP',
10055 'nl-BE',
10056 'nl-NL',
10057 'nn-NO',
10058 'oc-FR',
10059 'or-IN',
10060 'pa-IN',
10061 'pl-PL',
10062 'ps-AF',
10063 'pt-BR',
10064 'pt-PT',
10065 'rm-CH',
10066 'ro-MD',
10067 'ro-RO',
10068 'ru-RU',
10069 'rw-RW',
10070 'sa-IN',
10071 'se-FI',
10072 'se-NO',
10073 'se-SE',
10074 'si-LK',
10075 'sk-SK',
10076 'sl-SI',
10077 'sq-AL',
10078 'sv-FI',
10079 'sv-SE',
10080 'sw-KE',
10081 'ta-IN',
10082 'te-IN',
10083 'th-TH',
10084 'tk-TM',
10085 'tn-ZA',
10086 'tr-TR',
10087 'tt-RU',
10088 'ug-CN',
10089 'uk-UA',
10090 'ur-PK',
10091 'vi-VN',
10092 'wo-SN',
10093 'xh-ZA',
10094 'yo-NG',
10095 'zh-CN',
10096 'zh-HK',
10097 'zh-MO',
10098 'zh-SG',
10099 'zh-TW',
10100 'zu-ZA',
10101 );
10102
10103 $buildprimarykeytotest = strtolower($countrycode).'-'.strtoupper($countrycode);
10104 if (in_array($buildprimarykeytotest, $locales)) {
10105 return strtolower($countrycode).'_'.strtoupper($countrycode);
10106 }
10107
10108 if (function_exists('locale_get_primary_language') && function_exists('locale_get_region')) { // Need extension php-intl
10109 foreach ($locales as $locale) {
10110 $locale_language = locale_get_primary_language($locale);
10111 $locale_region = locale_get_region($locale);
10112 if (strtoupper($countrycode) == $locale_region) {
10113 //var_dump($locale.' - '.$locale_language.' - '.$locale_region);
10114 return strtolower($locale_language).'_'.strtoupper($locale_region);
10115 }
10116 }
10117 } else {
10118 dol_syslog("Warning Exention php-intl is not available", LOG_WARNING);
10119 }
10120
10121 return null;
10122}
10123
10154function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode = 'add', $filterorigmodule = '')
10155{
10156 global $hookmanager, $db;
10157
10158 if (isset($conf->modules_parts['tabs'][$type]) && is_array($conf->modules_parts['tabs'][$type])) {
10159 foreach ($conf->modules_parts['tabs'][$type] as $value) {
10160 $values = explode(':', $value);
10161
10162 $reg = array();
10163 if ($mode == 'add' && !preg_match('/^\-/', $values[1])) {
10164 $newtab = array();
10165 $postab = $h;
10166 // detect if position set in $values[1] ie : +(2)mytab@mymodule (first tab is 0, second is one, ...)
10167 $str = $values[1];
10168 $posstart = strpos($str, '(');
10169 if ($posstart > 0) {
10170 $posend = strpos($str, ')');
10171 if ($posstart > 0) {
10172 $res1 = substr($str, $posstart + 1, $posend - $posstart -1);
10173 if (is_numeric($res1)) {
10174 $postab = (int) $res1;
10175 $values[1] = '+' . substr($str, $posend + 1);
10176 }
10177 }
10178 }
10179 if (count($values) == 6) {
10180 // new declaration with permissions:
10181 // $value='objecttype:+tabname1:Title1:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10182 // $value='objecttype:+tabname1:Title1,class,pathfile,method:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10183 if ($values[0] != $type) {
10184 continue;
10185 }
10186
10187 if (verifCond($values[4])) {
10188 if ($values[3]) {
10189 if ($filterorigmodule) { // If a filter of module origin has been requested
10190 if (strpos($values[3], '@')) { // This is an external module
10191 if ($filterorigmodule != 'external') {
10192 continue;
10193 }
10194 } else { // This looks a core module
10195 if ($filterorigmodule != 'core') {
10196 continue;
10197 }
10198 }
10199 }
10200 $langs->load($values[3]);
10201 }
10202 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10203 // If label is "SUBSTITUION_..."
10204 $substitutionarray = array();
10205 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
10206 $label = make_substitutions($reg[1], $substitutionarray);
10207 } else {
10208 // If label is "Label,Class,File,Method", we call the method to show content inside the badge
10209 $labeltemp = explode(',', $values[2]);
10210 $label = $langs->trans($labeltemp[0]);
10211
10212 if (!empty($labeltemp[1]) && is_object($object) && !empty($object->id)) {
10213 dol_include_once($labeltemp[2]);
10214 $classtoload = $labeltemp[1];
10215 if (class_exists($classtoload)) {
10216 $obj = new $classtoload($db);
10217 $function = $labeltemp[3];
10218 if ($obj && $function && method_exists($obj, $function)) {
10219 $nbrec = $obj->$function($object->id, $obj);
10220 if (!empty($nbrec)) {
10221 $label .= '<span class="badge marginleftonlyshort">'.$nbrec.'</span>';
10222 }
10223 }
10224 }
10225 }
10226 }
10227
10228 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[5]), 1);
10229 $newtab[1] = $label;
10230 $newtab[2] = str_replace('+', '', $values[1]);
10231 $h++;
10232 } else {
10233 continue;
10234 }
10235 } elseif (count($values) == 5) { // case deprecated
10236 dol_syslog('Passing 5 values in tabs module_parts is deprecated. Please update to 6 with permissions.', LOG_WARNING);
10237
10238 if ($values[0] != $type) {
10239 continue;
10240 }
10241 if ($values[3]) {
10242 if ($filterorigmodule) { // If a filter of module origin has been requested
10243 if (strpos($values[3], '@')) { // This is an external module
10244 if ($filterorigmodule != 'external') {
10245 continue;
10246 }
10247 } else { // This looks a core module
10248 if ($filterorigmodule != 'core') {
10249 continue;
10250 }
10251 }
10252 }
10253 $langs->load($values[3]);
10254 }
10255 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10256 $substitutionarray = array();
10257 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
10258 $label = make_substitutions($reg[1], $substitutionarray);
10259 } else {
10260 $label = $langs->trans($values[2]);
10261 }
10262
10263 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[4]), 1);
10264 $newtab[1] = $label;
10265 $newtab[2] = str_replace('+', '', $values[1]);
10266 $h++;
10267 }
10268 // set tab at its position
10269 $head = array_merge(array_slice($head, 0, $postab), array($newtab), array_slice($head, $postab));
10270 } elseif ($mode == 'remove' && preg_match('/^\-/', $values[1])) {
10271 if ($values[0] != $type) {
10272 continue;
10273 }
10274 $tabname = str_replace('-', '', $values[1]);
10275 foreach ($head as $key => $val) {
10276 $condition = (!empty($values[3]) ? verifCond($values[3]) : 1);
10277 //var_dump($key.' - '.$tabname.' - '.$head[$key][2].' - '.$values[3].' - '.$condition);
10278 if ($head[$key][2] == $tabname && $condition) {
10279 unset($head[$key]);
10280 break;
10281 }
10282 }
10283 }
10284 }
10285 }
10286
10287 // No need to make a return $head. Var is modified as a reference
10288 if (!empty($hookmanager)) {
10289 $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule);
10290 $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters, $object);
10291 if ($reshook > 0) { // Hook ask to replace completely the array
10292 $head = $hookmanager->resArray;
10293 } else { // Hook
10294 $head = array_merge($head, $hookmanager->resArray);
10295 }
10296 $h = count($head);
10297 }
10298}
10299
10311function printCommonFooter($zone = 'private')
10312{
10313 global $conf, $hookmanager, $user, $debugbar;
10314 global $action;
10315 global $micro_start_time;
10316
10317 if ($zone == 'private') {
10318 print "\n".'<!-- Common footer for private page -->'."\n";
10319 } else {
10320 print "\n".'<!-- Common footer for public page -->'."\n";
10321 }
10322
10323 // A div to store page_y POST parameter so we can read it using javascript
10324 print "\n<!-- A div to store page_y POST parameter -->\n";
10325 print '<div id="page_y" style="display: none;">'.(GETPOST('page_y') ? GETPOST('page_y') : '').'</div>'."\n";
10326
10327 $parameters = array();
10328 $reshook = $hookmanager->executeHooks('printCommonFooter', $parameters); // Note that $action and $object may have been modified by some hooks
10329 if (empty($reshook)) {
10330 if (getDolGlobalString('MAIN_HTML_FOOTER')) {
10331 print getDolGlobalString('MAIN_HTML_FOOTER') . "\n";
10332 }
10333
10334 print "\n";
10335 if (!empty($conf->use_javascript_ajax)) {
10336 print "\n<!-- A script section to add menuhider handler on backoffice, manage focus and madatory fields, tuning info, ... -->\n";
10337 print '<script>'."\n";
10338 print 'jQuery(document).ready(function() {'."\n";
10339
10340 if ($zone == 'private' && empty($conf->dol_use_jmobile)) {
10341 print "\n";
10342 print '/* JS CODE TO ENABLE to manage handler to switch left menu page (menuhider) */'."\n";
10343 print 'jQuery("li.menuhider").click(function(event) {';
10344 print ' if (!$( "body" ).hasClass( "sidebar-collapse" )){ event.preventDefault(); }'."\n";
10345 print ' console.log("We click on .menuhider");'."\n";
10346 print ' $("body").toggleClass("sidebar-collapse")'."\n";
10347 print '});'."\n";
10348 }
10349
10350 // Management of focus and mandatory for fields
10351 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"])))) {
10352 print '/* JS CODE TO ENABLE to manage focus and mandatory form fields */'."\n";
10353 $relativepathstring = $_SERVER["PHP_SELF"];
10354 // Clean $relativepathstring
10355 if (constant('DOL_URL_ROOT')) {
10356 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
10357 }
10358 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
10359 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
10360 //$tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
10361 if (!empty($user->default_values[$relativepathstring]['focus'])) {
10362 foreach ($user->default_values[$relativepathstring]['focus'] as $defkey => $defval) {
10363 $qualified = 0;
10364 if ($defkey != '_noquery_') {
10365 $tmpqueryarraytohave = explode('&', $defkey);
10366 $foundintru = 0;
10367 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
10368 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
10369 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
10370 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
10371 $foundintru = 1;
10372 }
10373 }
10374 if (!$foundintru) {
10375 $qualified = 1;
10376 }
10377 //var_dump($defkey.'-'.$qualified);
10378 } else {
10379 $qualified = 1;
10380 }
10381
10382 if ($qualified) {
10383 foreach ($defval as $paramkey => $paramval) {
10384 // Set focus on field
10385 print 'jQuery("input[name=\''.$paramkey.'\']").focus();'."\n";
10386 print 'jQuery("textarea[name=\''.$paramkey.'\']").focus();'."\n";
10387 print 'jQuery("select[name=\''.$paramkey.'\']").focus();'."\n"; // Not really usefull, but we keep it in case of.
10388 }
10389 }
10390 }
10391 }
10392 if (!empty($user->default_values[$relativepathstring]['mandatory'])) {
10393 foreach ($user->default_values[$relativepathstring]['mandatory'] as $defkey => $defval) {
10394 $qualified = 0;
10395 if ($defkey != '_noquery_') {
10396 $tmpqueryarraytohave = explode('&', $defkey);
10397 $foundintru = 0;
10398 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
10399 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
10400 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
10401 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
10402 $foundintru = 1;
10403 }
10404 }
10405 if (!$foundintru) {
10406 $qualified = 1;
10407 }
10408 //var_dump($defkey.'-'.$qualified);
10409 } else {
10410 $qualified = 1;
10411 }
10412
10413 if ($qualified) {
10414 foreach ($defval as $paramkey => $paramval) {
10415 // Add property 'required' on input
10416 print 'jQuery("input[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10417 print 'jQuery("textarea[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10418 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";
10419 print 'jQuery("select[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10420 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'-1\']").prop(\'value\', \'\');'."\n";
10421 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'0\']").prop(\'value\', \'\');'."\n";
10422
10423 // Add 'field required' class on closest td for all input elements : input, textarea and select
10424 print 'jQuery(":input[name=\'' . $paramkey . '\']").closest("tr").find("td:first").addClass("fieldrequired");' . "\n";
10425 }
10426 // If we submit the cancel button we remove the required attributes
10427 print 'jQuery("input[name=\'cancel\']").click(function() {
10428 console.log("We click on cancel button so removed all required attribute");
10429 jQuery("input, textarea, select").each(function(){this.removeAttribute(\'required\');});
10430 });'."\n";
10431 }
10432 }
10433 }
10434 }
10435
10436 print '});'."\n";
10437
10438 // End of tuning
10439 if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO']) || getDolGlobalString('MAIN_SHOW_TUNING_INFO')) {
10440 print "\n";
10441 print "/* JS CODE TO ENABLE to add memory info */\n";
10442 print 'window.console && console.log("';
10443 if (getDolGlobalString('MEMCACHED_SERVER')) {
10444 print 'MEMCACHED_SERVER=' . getDolGlobalString('MEMCACHED_SERVER').' - ';
10445 }
10446 print 'MAIN_OPTIMIZE_SPEED='.(isset($conf->global->MAIN_OPTIMIZE_SPEED) ? $conf->global->MAIN_OPTIMIZE_SPEED : 'off');
10447 if (!empty($micro_start_time)) { // Works only if MAIN_SHOW_TUNING_INFO is defined at $_SERVER level. Not in global variable.
10448 $micro_end_time = microtime(true);
10449 print ' - Build time: '.ceil(1000 * ($micro_end_time - $micro_start_time)).' ms';
10450 }
10451
10452 if (function_exists("memory_get_usage")) {
10453 print ' - Mem: '.memory_get_usage(); // Do not use true here, it seems it takes the peak amount
10454 }
10455 if (function_exists("memory_get_peak_usage")) {
10456 print ' - Real mem peak: '.memory_get_peak_usage(true);
10457 }
10458 if (function_exists("zend_loader_file_encoded")) {
10459 print ' - Zend encoded file: '.(zend_loader_file_encoded() ? 'yes' : 'no');
10460 }
10461 print '");'."\n";
10462 }
10463
10464 print "\n".'</script>'."\n";
10465
10466 // Google Analytics
10467 // TODO Add a hook here
10468 if (isModEnabled('google') && getDolGlobalString('MAIN_GOOGLE_AN_ID')) {
10469 $tmptagarray = explode(',', getDolGlobalString('MAIN_GOOGLE_AN_ID'));
10470 foreach ($tmptagarray as $tmptag) {
10471 print "\n";
10472 print "<!-- JS CODE TO ENABLE for google analtics tag -->\n";
10473 print '
10474 <!-- Global site tag (gtag.js) - Google Analytics -->
10475 <script nonce="'.getNonce().'" async src="https://www.googletagmanager.com/gtag/js?id='.trim($tmptag).'"></script>
10476 <script>
10477 window.dataLayer = window.dataLayer || [];
10478 function gtag(){dataLayer.push(arguments);}
10479 gtag(\'js\', new Date());
10480
10481 gtag(\'config\', \''.trim($tmptag).'\');
10482 </script>';
10483 print "\n";
10484 }
10485 }
10486 }
10487
10488 // Add Xdebug coverage of code
10489 if (defined('XDEBUGCOVERAGE')) {
10490 print_r(xdebug_get_code_coverage());
10491 }
10492
10493 // Add DebugBar data
10494 if ($user->hasRight('debugbar', 'read') && is_object($debugbar)) {
10495 $debugbar['time']->stopMeasure('pageaftermaster');
10496 print '<!-- Output debugbar data -->'."\n";
10497 $renderer = $debugbar->getRenderer();
10498 print $debugbar->getRenderer()->render();
10499 } elseif (count($conf->logbuffer)) { // If there is some logs in buffer to show
10500 print "\n";
10501 print "<!-- Start of log output\n";
10502 //print '<div class="hidden">'."\n";
10503 foreach ($conf->logbuffer as $logline) {
10504 print $logline."<br>\n";
10505 }
10506 //print '</div>'."\n";
10507 print "End of log output -->\n";
10508 }
10509 }
10510}
10511
10521function dolExplodeIntoArray($string, $delimiter = ';', $kv = '=')
10522{
10523 if (is_null($string)) {
10524 return array();
10525 }
10526
10527 if (preg_match('/^\[.*\]$/sm', $delimiter) || preg_match('/^\‍(.*\‍)$/sm', $delimiter)) {
10528 // This is a regex string
10529 $newdelimiter = $delimiter;
10530 } else {
10531 // This is a simple string
10532 $newdelimiter = preg_quote($delimiter, '/');
10533 }
10534
10535 if ($a = preg_split('/'.$newdelimiter.'/', $string)) {
10536 $ka = array();
10537 foreach ($a as $s) { // each part
10538 if ($s) {
10539 if ($pos = strpos($s, $kv)) { // key/value delimiter
10540 $ka[trim(substr($s, 0, $pos))] = trim(substr($s, $pos + strlen($kv)));
10541 } else { // key delimiter not found
10542 $ka[] = trim($s);
10543 }
10544 }
10545 }
10546 return $ka;
10547 }
10548
10549 return array();
10550}
10551
10552
10559function dol_set_focus($selector)
10560{
10561 print "\n".'<!-- Set focus onto a specific field -->'."\n";
10562 print '<script nonce="'.getNonce().'">jQuery(document).ready(function() { jQuery("'.dol_escape_js($selector).'").focus(); });</script>'."\n";
10563}
10564
10565
10573function dol_getmypid()
10574{
10575 if (!function_exists('getmypid')) {
10576 return mt_rand(99900000, 99965535);
10577 } else {
10578 return getmypid(); // May be a number on 64 bits (depending on OS)
10579 }
10580}
10581
10582
10600function natural_search($fields, $value, $mode = 0, $nofirstand = 0)
10601{
10602 global $db, $langs;
10603
10604 $value = trim($value);
10605
10606 if ($mode == 0) {
10607 $value = preg_replace('/\*/', '%', $value); // Replace * with %
10608 }
10609 if ($mode == 1) {
10610 $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
10611 }
10612
10613 $value = preg_replace('/\s*\|\s*/', '|', $value);
10614
10615 $crits = explode(' ', $value);
10616 $res = '';
10617 if (!is_array($fields)) {
10618 $fields = array($fields);
10619 }
10620
10621 $i1 = 0; // count the nb of and criteria added (all fields / criterias)
10622 foreach ($crits as $crit) { // Loop on each AND criteria
10623 $crit = trim($crit);
10624 $i2 = 0; // count the nb of valid criteria added for this this first criteria
10625 $newres = '';
10626 foreach ($fields as $field) {
10627 if ($mode == 1) {
10628 $tmpcrits = explode('|', $crit);
10629 $i3 = 0; // count the nb of valid criteria added for this current field
10630 foreach ($tmpcrits as $tmpcrit) {
10631 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10632 continue;
10633 }
10634 $tmpcrit = trim($tmpcrit);
10635
10636 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10637
10638 $operator = '=';
10639 $newcrit = preg_replace('/([!<>=]+)/', '', $tmpcrit);
10640
10641 $reg = array();
10642 preg_match('/([!<>=]+)/', $tmpcrit, $reg);
10643 if (!empty($reg[1])) {
10644 $operator = $reg[1];
10645 }
10646 if ($newcrit != '') {
10647 $numnewcrit = price2num($newcrit);
10648 if (is_numeric($numnewcrit)) {
10649 $newres .= $field.' '.$operator.' '.((float) $numnewcrit); // should be a numeric
10650 } else {
10651 $newres .= '1 = 2'; // force false, we received a corrupted data
10652 }
10653 $i3++; // a criteria was added to string
10654 }
10655 }
10656 $i2++; // a criteria for 1 more field was added to string
10657 } elseif ($mode == 2 || $mode == -2) {
10658 $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer
10659 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -2 ? 'NOT ' : '');
10660 $newres .= $crit ? "IN (".$db->sanitize($db->escape($crit)).")" : "IN (0)";
10661 if ($mode == -2) {
10662 $newres .= ' OR '.$field.' IS NULL';
10663 }
10664 $i2++; // a criteria for 1 more field was added to string
10665 } elseif ($mode == 3 || $mode == -3) {
10666 $tmparray = explode(',', $crit);
10667 if (count($tmparray)) {
10668 $listofcodes = '';
10669 foreach ($tmparray as $val) {
10670 $val = trim($val);
10671 if ($val) {
10672 $listofcodes .= ($listofcodes ? ',' : '');
10673 $listofcodes .= "'".$db->escape($val)."'";
10674 }
10675 }
10676 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -3 ? 'NOT ' : '')."IN (".$db->sanitize($listofcodes, 1).")";
10677 $i2++; // a criteria for 1 more field was added to string
10678 }
10679 if ($mode == -3) {
10680 $newres .= ' OR '.$field.' IS NULL';
10681 }
10682 } elseif ($mode == 4) {
10683 $tmparray = explode(',', $crit);
10684 if (count($tmparray)) {
10685 $listofcodes = '';
10686 foreach ($tmparray as $val) {
10687 $val = trim($val);
10688 if ($val) {
10689 $newres .= ($i2 > 0 ? " OR (" : "(").$field." LIKE '".$db->escape($val).",%'";
10690 $newres .= ' OR '.$field." = '".$db->escape($val)."'";
10691 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val)."'";
10692 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val).",%'";
10693 $newres .= ')';
10694 $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)
10695 }
10696 }
10697 }
10698 } else { // $mode=0
10699 $tmpcrits = explode('|', $crit);
10700 $i3 = 0; // count the nb of valid criteria added for the current couple criteria/field
10701 foreach ($tmpcrits as $tmpcrit) { // loop on each OR criteria
10702 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10703 continue;
10704 }
10705 $tmpcrit = trim($tmpcrit);
10706
10707 if ($tmpcrit == '^$' || strpos($crit, '!') === 0) { // If we search empty, we must combined different OR fields with AND
10708 $newres .= (($i2 > 0 || $i3 > 0) ? ' AND ' : '');
10709 } else {
10710 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10711 }
10712
10713 if (preg_match('/\.(id|rowid)$/', $field)) { // Special case for rowid that is sometimes a ref so used as a search field
10714 $newres .= $field." = ".(is_numeric($tmpcrit) ? ((float) $tmpcrit) : '0');
10715 } else {
10716 $tmpcrit2 = $tmpcrit;
10717 $tmpbefore = '%';
10718 $tmpafter = '%';
10719 $tmps = '';
10720
10721 if (preg_match('/^!/', $tmpcrit)) {
10722 $tmps .= $field." NOT LIKE "; // ! as exclude character
10723 $tmpcrit2 = preg_replace('/^!/', '', $tmpcrit2);
10724 } else {
10725 $tmps .= $field." LIKE ";
10726 }
10727 $tmps .= "'";
10728
10729 if (preg_match('/^[\^\$]/', $tmpcrit)) {
10730 $tmpbefore = '';
10731 $tmpcrit2 = preg_replace('/^[\^\$]/', '', $tmpcrit2);
10732 }
10733 if (preg_match('/[\^\$]$/', $tmpcrit)) {
10734 $tmpafter = '';
10735 $tmpcrit2 = preg_replace('/[\^\$]$/', '', $tmpcrit2);
10736 }
10737
10738 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10739 $tmps = "(".$tmps;
10740 }
10741 $newres .= $tmps;
10742 $newres .= $tmpbefore;
10743 $newres .= $db->escape($tmpcrit2);
10744 $newres .= $tmpafter;
10745 $newres .= "'";
10746 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10747 $newres .= " OR ".$field." IS NULL)";
10748 }
10749 }
10750
10751 $i3++;
10752 }
10753
10754 $i2++; // a criteria for 1 more field was added to string
10755 }
10756 }
10757
10758 if ($newres) {
10759 $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : '');
10760 }
10761 $i1++;
10762 }
10763 $res = ($nofirstand ? "" : " AND ")."(".$res.")";
10764
10765 return $res;
10766}
10767
10774function showDirectDownloadLink($object)
10775{
10776 global $conf, $langs;
10777
10778 $out = '';
10779 $url = $object->getLastMainDocLink($object->element);
10780
10781 $out .= img_picto($langs->trans("PublicDownloadLinkDesc"), 'globe').' <span class="opacitymedium">'.$langs->trans("DirectDownloadLink").'</span><br>';
10782 if ($url) {
10783 $out .= '<div class="urllink"><input type="text" id="directdownloadlink" class="quatrevingtpercent" value="'.$url.'"></div>';
10784 $out .= ajax_autoselect("directdownloadlink", 0);
10785 } else {
10786 $out .= '<div class="urllink">'.$langs->trans("FileNotShared").'</div>';
10787 }
10788
10789 return $out;
10790}
10791
10800function getImageFileNameForSize($file, $extName, $extImgTarget = '')
10801{
10802 $dirName = dirname($file);
10803 if ($dirName == '.') {
10804 $dirName = '';
10805 }
10806
10807 $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.webp)$/i', '', $file); // We remove extension, whatever is its case
10808 $fileName = basename($fileName);
10809
10810 if (empty($extImgTarget)) {
10811 $extImgTarget = (preg_match('/\.jpg$/i', $file) ? '.jpg' : '');
10812 }
10813 if (empty($extImgTarget)) {
10814 $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '');
10815 }
10816 if (empty($extImgTarget)) {
10817 $extImgTarget = (preg_match('/\.gif$/i', $file) ? '.gif' : '');
10818 }
10819 if (empty($extImgTarget)) {
10820 $extImgTarget = (preg_match('/\.png$/i', $file) ? '.png' : '');
10821 }
10822 if (empty($extImgTarget)) {
10823 $extImgTarget = (preg_match('/\.bmp$/i', $file) ? '.bmp' : '');
10824 }
10825 if (empty($extImgTarget)) {
10826 $extImgTarget = (preg_match('/\.webp$/i', $file) ? '.webp' : '');
10827 }
10828
10829 if (!$extImgTarget) {
10830 return $file;
10831 }
10832
10833 $subdir = '';
10834 if ($extName) {
10835 $subdir = 'thumbs/';
10836 }
10837
10838 return ($dirName ? $dirName.'/' : '').$subdir.$fileName.$extName.$extImgTarget; // New filename for thumb
10839}
10840
10841
10851function getAdvancedPreviewUrl($modulepart, $relativepath, $alldata = 0, $param = '')
10852{
10853 global $conf, $langs;
10854
10855 if (empty($conf->use_javascript_ajax)) {
10856 return '';
10857 }
10858
10859 $isAllowedForPreview = dolIsAllowedForPreview($relativepath);
10860
10861 if ($alldata == 1) {
10862 if ($isAllowedForPreview) {
10863 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));
10864 } else {
10865 return array();
10866 }
10867 }
10868
10869 // old behavior, return a string
10870 if ($isAllowedForPreview) {
10871 $tmpurl = DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : '');
10872 $title = $langs->trans("Preview");
10873 //$title = '%27-alert(document.domain)-%27';
10874 //$tmpurl = 'file='.urlencode("'-alert(document.domain)-'_small.jpg");
10875
10876 // 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.
10877 // and when we click on href with this javascript string, a urlcode is done by browser, converted the %27 of file param
10878 return 'javascript:document_preview(\''.urlencode(dol_escape_js($tmpurl)).'\', \''.urlencode(dol_mimetype($relativepath)).'\', \''.urlencode(dol_escape_js($title)).'\')';
10879 } else {
10880 return '';
10881 }
10882}
10883
10884
10893function ajax_autoselect($htmlname, $addlink = '', $textonlink = 'Link')
10894{
10895 global $langs;
10896 $out = '<script nonce="'.getNonce().'">
10897 jQuery(document).ready(function () {
10898 jQuery("'.((strpos($htmlname, '.') === 0 ? '' : '#').$htmlname).'").click(function() { jQuery(this).select(); } );
10899 });
10900 </script>';
10901 if ($addlink) {
10902 if ($textonlink === 'image') {
10903 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.img_picto('', 'globe').'</a>';
10904 } else {
10905 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.$langs->trans("Link").'</a>';
10906 }
10907 }
10908 return $out;
10909}
10910
10918function dolIsAllowedForPreview($file)
10919{
10920 global $conf;
10921
10922 // Check .noexe extension in filename
10923 if (preg_match('/\.noexe$/i', $file)) {
10924 return 0;
10925 }
10926
10927 // Check mime types
10928 $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'webp');
10929 if (getDolGlobalString('MAIN_ALLOW_SVG_FILES_AS_IMAGES')) {
10930 $mime_preview[] = 'svg+xml';
10931 }
10932 //$mime_preview[]='vnd.oasis.opendocument.presentation';
10933 //$mime_preview[]='archive';
10934 $num_mime = array_search(dol_mimetype($file, '', 1), $mime_preview);
10935 if ($num_mime !== false) {
10936 return 1;
10937 }
10938
10939 // By default, not allowed for preview
10940 return 0;
10941}
10942
10943
10953function dol_mimetype($file, $default = 'application/octet-stream', $mode = 0)
10954{
10955 $mime = $default;
10956 $imgmime = 'other.png';
10957 $famime = 'file-o';
10958 $srclang = '';
10959
10960 $tmpfile = preg_replace('/\.noexe$/', '', $file);
10961
10962 // Plain text files
10963 if (preg_match('/\.txt$/i', $tmpfile)) {
10964 $mime = 'text/plain';
10965 $imgmime = 'text.png';
10966 $famime = 'file-alt';
10967 } elseif (preg_match('/\.rtx$/i', $tmpfile)) {
10968 $mime = 'text/richtext';
10969 $imgmime = 'text.png';
10970 $famime = 'file-alt';
10971 } elseif (preg_match('/\.csv$/i', $tmpfile)) {
10972 $mime = 'text/csv';
10973 $imgmime = 'text.png';
10974 $famime = 'file-csv';
10975 } elseif (preg_match('/\.tsv$/i', $tmpfile)) {
10976 $mime = 'text/tab-separated-values';
10977 $imgmime = 'text.png';
10978 $famime = 'file-alt';
10979 } elseif (preg_match('/\.(cf|conf|log)$/i', $tmpfile)) {
10980 $mime = 'text/plain';
10981 $imgmime = 'text.png';
10982 $famime = 'file-alt';
10983 } elseif (preg_match('/\.ini$/i', $tmpfile)) {
10984 $mime = 'text/plain';
10985 $imgmime = 'text.png';
10986 $srclang = 'ini';
10987 $famime = 'file-alt';
10988 } elseif (preg_match('/\.md$/i', $tmpfile)) {
10989 $mime = 'text/plain';
10990 $imgmime = 'text.png';
10991 $srclang = 'md';
10992 $famime = 'file-alt';
10993 } elseif (preg_match('/\.css$/i', $tmpfile)) {
10994 $mime = 'text/css';
10995 $imgmime = 'css.png';
10996 $srclang = 'css';
10997 $famime = 'file-alt';
10998 } elseif (preg_match('/\.lang$/i', $tmpfile)) {
10999 $mime = 'text/plain';
11000 $imgmime = 'text.png';
11001 $srclang = 'lang';
11002 $famime = 'file-alt';
11003 } elseif (preg_match('/\.(crt|cer|key|pub)$/i', $tmpfile)) { // Certificate files
11004 $mime = 'text/plain';
11005 $imgmime = 'text.png';
11006 $famime = 'file-alt';
11007 } elseif (preg_match('/\.(html|htm|shtml)$/i', $tmpfile)) { // XML based (HTML/XML/XAML)
11008 $mime = 'text/html';
11009 $imgmime = 'html.png';
11010 $srclang = 'html';
11011 $famime = 'file-alt';
11012 } elseif (preg_match('/\.(xml|xhtml)$/i', $tmpfile)) {
11013 $mime = 'text/xml';
11014 $imgmime = 'other.png';
11015 $srclang = 'xml';
11016 $famime = 'file-alt';
11017 } elseif (preg_match('/\.xaml$/i', $tmpfile)) {
11018 $mime = 'text/xml';
11019 $imgmime = 'other.png';
11020 $srclang = 'xaml';
11021 $famime = 'file-alt';
11022 } elseif (preg_match('/\.bas$/i', $tmpfile)) { // Languages
11023 $mime = 'text/plain';
11024 $imgmime = 'text.png';
11025 $srclang = 'bas';
11026 $famime = 'file-code';
11027 } elseif (preg_match('/\.(c)$/i', $tmpfile)) {
11028 $mime = 'text/plain';
11029 $imgmime = 'text.png';
11030 $srclang = 'c';
11031 $famime = 'file-code';
11032 } elseif (preg_match('/\.(cpp)$/i', $tmpfile)) {
11033 $mime = 'text/plain';
11034 $imgmime = 'text.png';
11035 $srclang = 'cpp';
11036 $famime = 'file-code';
11037 } elseif (preg_match('/\.cs$/i', $tmpfile)) {
11038 $mime = 'text/plain';
11039 $imgmime = 'text.png';
11040 $srclang = 'cs';
11041 $famime = 'file-code';
11042 } elseif (preg_match('/\.(h)$/i', $tmpfile)) {
11043 $mime = 'text/plain';
11044 $imgmime = 'text.png';
11045 $srclang = 'h';
11046 $famime = 'file-code';
11047 } elseif (preg_match('/\.(java|jsp)$/i', $tmpfile)) {
11048 $mime = 'text/plain';
11049 $imgmime = 'text.png';
11050 $srclang = 'java';
11051 $famime = 'file-code';
11052 } elseif (preg_match('/\.php([0-9]{1})?$/i', $tmpfile)) {
11053 $mime = 'text/plain';
11054 $imgmime = 'php.png';
11055 $srclang = 'php';
11056 $famime = 'file-code';
11057 } elseif (preg_match('/\.phtml$/i', $tmpfile)) {
11058 $mime = 'text/plain';
11059 $imgmime = 'php.png';
11060 $srclang = 'php';
11061 $famime = 'file-code';
11062 } elseif (preg_match('/\.(pl|pm)$/i', $tmpfile)) {
11063 $mime = 'text/plain';
11064 $imgmime = 'pl.png';
11065 $srclang = 'perl';
11066 $famime = 'file-code';
11067 } elseif (preg_match('/\.sql$/i', $tmpfile)) {
11068 $mime = 'text/plain';
11069 $imgmime = 'text.png';
11070 $srclang = 'sql';
11071 $famime = 'file-code';
11072 } elseif (preg_match('/\.js$/i', $tmpfile)) {
11073 $mime = 'text/x-javascript';
11074 $imgmime = 'jscript.png';
11075 $srclang = 'js';
11076 $famime = 'file-code';
11077 } elseif (preg_match('/\.odp$/i', $tmpfile)) { // Open office
11078 $mime = 'application/vnd.oasis.opendocument.presentation';
11079 $imgmime = 'ooffice.png';
11080 $famime = 'file-powerpoint';
11081 } elseif (preg_match('/\.ods$/i', $tmpfile)) {
11082 $mime = 'application/vnd.oasis.opendocument.spreadsheet';
11083 $imgmime = 'ooffice.png';
11084 $famime = 'file-excel';
11085 } elseif (preg_match('/\.odt$/i', $tmpfile)) {
11086 $mime = 'application/vnd.oasis.opendocument.text';
11087 $imgmime = 'ooffice.png';
11088 $famime = 'file-word';
11089 } elseif (preg_match('/\.mdb$/i', $tmpfile)) { // MS Office
11090 $mime = 'application/msaccess';
11091 $imgmime = 'mdb.png';
11092 $famime = 'file';
11093 } elseif (preg_match('/\.doc[xm]?$/i', $tmpfile)) {
11094 $mime = 'application/msword';
11095 $imgmime = 'doc.png';
11096 $famime = 'file-word';
11097 } elseif (preg_match('/\.dot[xm]?$/i', $tmpfile)) {
11098 $mime = 'application/msword';
11099 $imgmime = 'doc.png';
11100 $famime = 'file-word';
11101 } elseif (preg_match('/\.xlt(x)?$/i', $tmpfile)) {
11102 $mime = 'application/vnd.ms-excel';
11103 $imgmime = 'xls.png';
11104 $famime = 'file-excel';
11105 } elseif (preg_match('/\.xla(m)?$/i', $tmpfile)) {
11106 $mime = 'application/vnd.ms-excel';
11107 $imgmime = 'xls.png';
11108 $famime = 'file-excel';
11109 } elseif (preg_match('/\.xls$/i', $tmpfile)) {
11110 $mime = 'application/vnd.ms-excel';
11111 $imgmime = 'xls.png';
11112 $famime = 'file-excel';
11113 } elseif (preg_match('/\.xls[bmx]$/i', $tmpfile)) {
11114 $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
11115 $imgmime = 'xls.png';
11116 $famime = 'file-excel';
11117 } elseif (preg_match('/\.pps[mx]?$/i', $tmpfile)) {
11118 $mime = 'application/vnd.ms-powerpoint';
11119 $imgmime = 'ppt.png';
11120 $famime = 'file-powerpoint';
11121 } elseif (preg_match('/\.ppt[mx]?$/i', $tmpfile)) {
11122 $mime = 'application/x-mspowerpoint';
11123 $imgmime = 'ppt.png';
11124 $famime = 'file-powerpoint';
11125 } elseif (preg_match('/\.pdf$/i', $tmpfile)) { // Other
11126 $mime = 'application/pdf';
11127 $imgmime = 'pdf.png';
11128 $famime = 'file-pdf';
11129 } elseif (preg_match('/\.bat$/i', $tmpfile)) { // Scripts
11130 $mime = 'text/x-bat';
11131 $imgmime = 'script.png';
11132 $srclang = 'dos';
11133 $famime = 'file-code';
11134 } elseif (preg_match('/\.sh$/i', $tmpfile)) {
11135 $mime = 'text/x-sh';
11136 $imgmime = 'script.png';
11137 $srclang = 'bash';
11138 $famime = 'file-code';
11139 } elseif (preg_match('/\.ksh$/i', $tmpfile)) {
11140 $mime = 'text/x-ksh';
11141 $imgmime = 'script.png';
11142 $srclang = 'bash';
11143 $famime = 'file-code';
11144 } elseif (preg_match('/\.bash$/i', $tmpfile)) {
11145 $mime = 'text/x-bash';
11146 $imgmime = 'script.png';
11147 $srclang = 'bash';
11148 $famime = 'file-code';
11149 } elseif (preg_match('/\.ico$/i', $tmpfile)) { // Images
11150 $mime = 'image/x-icon';
11151 $imgmime = 'image.png';
11152 $famime = 'file-image';
11153 } elseif (preg_match('/\.(jpg|jpeg)$/i', $tmpfile)) {
11154 $mime = 'image/jpeg';
11155 $imgmime = 'image.png';
11156 $famime = 'file-image';
11157 } elseif (preg_match('/\.png$/i', $tmpfile)) {
11158 $mime = 'image/png';
11159 $imgmime = 'image.png';
11160 $famime = 'file-image';
11161 } elseif (preg_match('/\.gif$/i', $tmpfile)) {
11162 $mime = 'image/gif';
11163 $imgmime = 'image.png';
11164 $famime = 'file-image';
11165 } elseif (preg_match('/\.bmp$/i', $tmpfile)) {
11166 $mime = 'image/bmp';
11167 $imgmime = 'image.png';
11168 $famime = 'file-image';
11169 } elseif (preg_match('/\.(tif|tiff)$/i', $tmpfile)) {
11170 $mime = 'image/tiff';
11171 $imgmime = 'image.png';
11172 $famime = 'file-image';
11173 } elseif (preg_match('/\.svg$/i', $tmpfile)) {
11174 $mime = 'image/svg+xml';
11175 $imgmime = 'image.png';
11176 $famime = 'file-image';
11177 } elseif (preg_match('/\.webp$/i', $tmpfile)) {
11178 $mime = 'image/webp';
11179 $imgmime = 'image.png';
11180 $famime = 'file-image';
11181 } elseif (preg_match('/\.vcs$/i', $tmpfile)) { // Calendar
11182 $mime = 'text/calendar';
11183 $imgmime = 'other.png';
11184 $famime = 'file-alt';
11185 } elseif (preg_match('/\.ics$/i', $tmpfile)) {
11186 $mime = 'text/calendar';
11187 $imgmime = 'other.png';
11188 $famime = 'file-alt';
11189 } elseif (preg_match('/\.torrent$/i', $tmpfile)) { // Other
11190 $mime = 'application/x-bittorrent';
11191 $imgmime = 'other.png';
11192 $famime = 'file-o';
11193 } elseif (preg_match('/\.(mp3|ogg|au|wav|wma|mid)$/i', $tmpfile)) { // Audio
11194 $mime = 'audio';
11195 $imgmime = 'audio.png';
11196 $famime = 'file-audio';
11197 } elseif (preg_match('/\.mp4$/i', $tmpfile)) { // Video
11198 $mime = 'video/mp4';
11199 $imgmime = 'video.png';
11200 $famime = 'file-video';
11201 } elseif (preg_match('/\.ogv$/i', $tmpfile)) {
11202 $mime = 'video/ogg';
11203 $imgmime = 'video.png';
11204 $famime = 'file-video';
11205 } elseif (preg_match('/\.webm$/i', $tmpfile)) {
11206 $mime = 'video/webm';
11207 $imgmime = 'video.png';
11208 $famime = 'file-video';
11209 } elseif (preg_match('/\.avi$/i', $tmpfile)) {
11210 $mime = 'video/x-msvideo';
11211 $imgmime = 'video.png';
11212 $famime = 'file-video';
11213 } elseif (preg_match('/\.divx$/i', $tmpfile)) {
11214 $mime = 'video/divx';
11215 $imgmime = 'video.png';
11216 $famime = 'file-video';
11217 } elseif (preg_match('/\.xvid$/i', $tmpfile)) {
11218 $mime = 'video/xvid';
11219 $imgmime = 'video.png';
11220 $famime = 'file-video';
11221 } elseif (preg_match('/\.(wmv|mpg|mpeg)$/i', $tmpfile)) {
11222 $mime = 'video';
11223 $imgmime = 'video.png';
11224 $famime = 'file-video';
11225 } elseif (preg_match('/\.(zip|rar|gz|tgz|z|cab|bz2|7z|tar|lzh|zst)$/i', $tmpfile)) { // Archive
11226 // application/xxx where zzz is zip, ...
11227 $mime = 'archive';
11228 $imgmime = 'archive.png';
11229 $famime = 'file-archive';
11230 } elseif (preg_match('/\.(exe|com)$/i', $tmpfile)) { // Exe
11231 $mime = 'application/octet-stream';
11232 $imgmime = 'other.png';
11233 $famime = 'file-o';
11234 } elseif (preg_match('/\.(dll|lib|o|so|a)$/i', $tmpfile)) { // Lib
11235 $mime = 'library';
11236 $imgmime = 'library.png';
11237 $famime = 'file-o';
11238 } elseif (preg_match('/\.err$/i', $tmpfile)) { // phpcs:ignore
11239 $mime = 'error';
11240 $imgmime = 'error.png';
11241 $famime = 'file-alt';
11242 }
11243
11244 // Return mimetype string
11245 switch ((int) $mode) {
11246 case 1:
11247 $tmp = explode('/', $mime);
11248 return (!empty($tmp[1]) ? $tmp[1] : $tmp[0]);
11249 case 2:
11250 return $imgmime;
11251 case 3:
11252 return $srclang;
11253 case 4:
11254 return $famime;
11255 }
11256 return $mime;
11257}
11258
11270function getDictionaryValue($tablename, $field, $id, $checkentity = false, $rowidfield = 'rowid')
11271{
11272 global $conf, $db;
11273
11274 $tablename = preg_replace('/^'.preg_quote(MAIN_DB_PREFIX, '/').'/', '', $tablename); // Clean name of table for backward compatibility.
11275
11276 $dictvalues = (isset($conf->cache['dictvalues_'.$tablename]) ? $conf->cache['dictvalues_'.$tablename] : null);
11277
11278 if (is_null($dictvalues)) {
11279 $dictvalues = array();
11280
11281 $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
11282 if ($checkentity) {
11283 $sql .= ' AND entity IN (0,'.getEntity($tablename).')';
11284 }
11285
11286 $resql = $db->query($sql);
11287 if ($resql) {
11288 while ($obj = $db->fetch_object($resql)) {
11289 $dictvalues[$obj->$rowidfield] = $obj; // $obj is stdClass
11290 }
11291 } else {
11292 dol_print_error($db);
11293 }
11294
11295 $conf->cache['dictvalues_'.$tablename] = $dictvalues;
11296 }
11297
11298 if (!empty($dictvalues[$id])) {
11299 // Found
11300 $tmp = $dictvalues[$id];
11301 return (property_exists($tmp, $field) ? $tmp->$field : '');
11302 } else {
11303 // Not found
11304 return '';
11305 }
11306}
11307
11314function colorIsLight($stringcolor)
11315{
11316 $stringcolor = str_replace('#', '', $stringcolor);
11317 $res = -1;
11318 if (!empty($stringcolor)) {
11319 $res = 0;
11320 $tmp = explode(',', $stringcolor);
11321 if (count($tmp) > 1) { // This is a comma RGB ('255','255','255')
11322 $r = $tmp[0];
11323 $g = $tmp[1];
11324 $b = $tmp[2];
11325 } else {
11326 $hexr = $stringcolor[0].$stringcolor[1];
11327 $hexg = $stringcolor[2].$stringcolor[3];
11328 $hexb = $stringcolor[4].$stringcolor[5];
11329 $r = hexdec($hexr);
11330 $g = hexdec($hexg);
11331 $b = hexdec($hexb);
11332 }
11333 $bright = (max($r, $g, $b) + min($r, $g, $b)) / 510.0; // HSL algorithm
11334 if ($bright > 0.6) {
11335 $res = 1;
11336 }
11337 }
11338 return $res;
11339}
11340
11349function isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
11350{
11351 global $conf;
11352
11353 //print 'type_user='.$type_user.' module='.$menuentry['module'].' enabled='.$menuentry['enabled'].' perms='.$menuentry['perms'];
11354 //print 'ok='.in_array($menuentry['module'], $listofmodulesforexternal);
11355 if (empty($menuentry['enabled'])) {
11356 return 0; // Entry disabled by condition
11357 }
11358 if ($type_user && $menuentry['module']) {
11359 $tmploops = explode('|', $menuentry['module']);
11360 $found = 0;
11361 foreach ($tmploops as $tmploop) {
11362 if (in_array($tmploop, $listofmodulesforexternal)) {
11363 $found++;
11364 break;
11365 }
11366 }
11367 if (!$found) {
11368 return 0; // Entry is for menus all excluded to external users
11369 }
11370 }
11371 if (!$menuentry['perms'] && $type_user) {
11372 return 0; // No permissions and user is external
11373 }
11374 if (!$menuentry['perms'] && getDolGlobalString('MAIN_MENU_HIDE_UNAUTHORIZED')) {
11375 return 0; // No permissions and option to hide when not allowed, even for internal user, is on
11376 }
11377 if (!$menuentry['perms']) {
11378 return 2; // No permissions and user is external
11379 }
11380 return 1;
11381}
11382
11390function roundUpToNextMultiple($n, $x = 5)
11391{
11392 return (ceil($n) % $x === 0) ? ceil($n) : round(($n + $x / 2) / $x) * $x;
11393}
11394
11406function dolGetBadge($label, $html = '', $type = 'primary', $mode = '', $url = '', $params = array())
11407{
11408 $attr = array(
11409 'class'=>'badge '.(!empty($mode) ? ' badge-'.$mode : '').(!empty($type) ? ' badge-'.$type : '').(empty($params['css']) ? '' : ' '.$params['css'])
11410 );
11411
11412 if (empty($html)) {
11413 $html = $label;
11414 }
11415
11416 if (!empty($url)) {
11417 $attr['href'] = $url;
11418 }
11419
11420 if ($mode === 'dot') {
11421 $attr['class'] .= ' classfortooltip';
11422 $attr['title'] = $html;
11423 $attr['aria-label'] = $label;
11424 $html = '';
11425 }
11426
11427 // Override attr
11428 if (!empty($params['attr']) && is_array($params['attr'])) {
11429 foreach ($params['attr'] as $key => $value) {
11430 if ($key == 'class') {
11431 $attr['class'] .= ' '.$value;
11432 } elseif ($key == 'classOverride') {
11433 $attr['class'] = $value;
11434 } else {
11435 $attr[$key] = $value;
11436 }
11437 }
11438 }
11439
11440 // TODO: add hook
11441
11442 // escape all attribute
11443 $attr = array_map('dol_escape_htmltag', $attr);
11444
11445 $TCompiledAttr = array();
11446 foreach ($attr as $key => $value) {
11447 $TCompiledAttr[] = $key.'="'.$value.'"';
11448 }
11449
11450 $compiledAttributes = !empty($TCompiledAttr) ? implode(' ', $TCompiledAttr) : '';
11451
11452 $tag = !empty($url) ? 'a' : 'span';
11453
11454 return '<'.$tag.' '.$compiledAttributes.'>'.$html.'</'.$tag.'>';
11455}
11456
11457
11470function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $statusType = 'status0', $displayMode = 0, $url = '', $params = array())
11471{
11472 global $conf;
11473
11474 $return = '';
11475 $dolGetBadgeParams = array();
11476
11477 if (!empty($params['badgeParams'])) {
11478 $dolGetBadgeParams = $params['badgeParams'];
11479 }
11480
11481 // TODO : add a hook
11482 if ($displayMode == 0) {
11483 $return = !empty($html) ? $html : (empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort));
11484 } elseif ($displayMode == 1) {
11485 $return = !empty($html) ? $html : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11486 } elseif (getDolGlobalString('MAIN_STATUS_USES_IMAGES')) {
11487 // Use status with images (for backward compatibility)
11488 $return = '';
11489 $htmlLabel = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : $statusLabel).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
11490 $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>' : '');
11491
11492 // For small screen, we always use the short label instead of long label.
11493 if (!empty($conf->dol_optimize_smallscreen)) {
11494 if ($displayMode == 0) {
11495 $displayMode = 1;
11496 } elseif ($displayMode == 4) {
11497 $displayMode = 2;
11498 } elseif ($displayMode == 6) {
11499 $displayMode = 5;
11500 }
11501 }
11502
11503 // For backward compatibility. Image's filename are still in French, so we use this array to convert
11504 $statusImg = array(
11505 'status0' => 'statut0',
11506 'status1' => 'statut1',
11507 'status2' => 'statut2',
11508 'status3' => 'statut3',
11509 'status4' => 'statut4',
11510 'status5' => 'statut5',
11511 'status6' => 'statut6',
11512 'status7' => 'statut7',
11513 'status8' => 'statut8',
11514 'status9' => 'statut9'
11515 );
11516
11517 if (!empty($statusImg[$statusType])) {
11518 $htmlImg = img_picto($statusLabel, $statusImg[$statusType]);
11519 } else {
11520 $htmlImg = img_picto($statusLabel, $statusType);
11521 }
11522
11523 if ($displayMode === 2) {
11524 $return = $htmlImg.' '.$htmlLabelShort;
11525 } elseif ($displayMode === 3) {
11526 $return = $htmlImg;
11527 } elseif ($displayMode === 4) {
11528 $return = $htmlImg.' '.$htmlLabel;
11529 } elseif ($displayMode === 5) {
11530 $return = $htmlLabelShort.' '.$htmlImg;
11531 } else { // $displayMode >= 6
11532 $return = $htmlLabel.' '.$htmlImg;
11533 }
11534 } elseif (!getDolGlobalString('MAIN_STATUS_USES_IMAGES') && !empty($displayMode)) {
11535 // Use new badge
11536 $statusLabelShort = (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11537
11538 $dolGetBadgeParams['attr']['class'] = 'badge-status';
11539 $dolGetBadgeParams['attr']['title'] = empty($params['tooltip']) ? $statusLabel : ($params['tooltip'] != 'no' ? $params['tooltip'] : '');
11540
11541 if ($displayMode == 3) {
11542 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), '', $statusType, 'dot', $url, $dolGetBadgeParams);
11543 } elseif ($displayMode === 5) {
11544 $return = dolGetBadge($statusLabelShort, $html, $statusType, '', $url, $dolGetBadgeParams);
11545 } else {
11546 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), $html, $statusType, '', $url, $dolGetBadgeParams);
11547 }
11548 }
11549
11550 return $return;
11551}
11552
11553
11588function dolGetButtonAction($label, $text = '', $actionType = 'default', $url = '', $id = '', $userRight = 1, $params = array())
11589{
11590 global $hookmanager, $action, $object, $langs;
11591
11592 // If $url is an array, we must build a dropdown button
11593 if (is_array($url)) {
11594 // Loop on $url array to remove entries of disabled modules
11595 foreach ($url as $key => $subbutton) {
11596 if (isset($subbutton['enabled']) && empty($subbutton['enabled'])) {
11597 unset($url[$key]);
11598 }
11599 }
11600
11601 $out = '';
11602
11603 if (count($url) > 1) {
11604 $out .= '<div class="dropdown inline-block dropdown-holder">';
11605 $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>';
11606 $out .= '<div class="dropdown-content">';
11607 foreach ($url as $subbutton) {
11608 if (!empty($subbutton['lang'])) {
11609 $langs->load($subbutton['lang']);
11610 }
11611 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
11612 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm'], array('isDropDown' => true));
11613 }
11614 $out .= "</div>";
11615 $out .= "</div>";
11616 } else {
11617 foreach ($url as $subbutton) { // Should loop on 1 record only
11618 if (!empty($subbutton['lang'])) {
11619 $langs->load($subbutton['lang']);
11620 }
11621 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
11622 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm']);
11623 }
11624 }
11625
11626 return $out;
11627 }
11628
11629 // Here, $url is a simple link
11630
11631 if (!empty($params['isDropdown'])) {
11632 $class = "dropdown-item";
11633 } else {
11634 $class = 'butAction';
11635 if ($actionType == 'danger' || $actionType == 'delete') {
11636 $class = 'butActionDelete';
11637 if (!empty($url) && strpos($url, 'token=') === false) {
11638 $url .= '&token='.newToken();
11639 }
11640 }
11641 }
11642 $attr = array(
11643 'class' => $class,
11644 'href' => empty($url) ? '' : $url,
11645 'title' => $label
11646 );
11647
11648 if (empty($text)) {
11649 $text = $label;
11650 $attr['title'] = ''; // if html not set, leave label on title is redundant
11651 } else {
11652 $attr['title'] = $label;
11653 $attr['aria-label'] = $label;
11654 }
11655
11656 if (empty($userRight)) {
11657 $attr['class'] = 'butActionRefused';
11658 $attr['href'] = '';
11659 $attr['title'] = (($label && $text && $label != $text) ? $label : $langs->trans('NotEnoughPermissions'));
11660 }
11661
11662 if (!empty($id)) {
11663 $attr['id'] = $id;
11664 }
11665
11666 // Override attr
11667 if (!empty($params['attr']) && is_array($params['attr'])) {
11668 foreach ($params['attr'] as $key => $value) {
11669 if ($key == 'class') {
11670 $attr['class'] .= ' '.$value;
11671 } elseif ($key == 'classOverride') {
11672 $attr['class'] = $value;
11673 } else {
11674 $attr[$key] = $value;
11675 }
11676 }
11677 }
11678
11679 // automatic add tooltip when title is detected
11680 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
11681 $attr['class'].= ' classfortooltip';
11682 }
11683
11684 // Js Confirm button
11685 if ($userRight && !empty($params['confirm'])) {
11686 if (!is_array($params['confirm'])) {
11687 $params['confirm'] = array();
11688 }
11689
11690 if (empty($params['confirm']['url'])) {
11691 $params['confirm']['url'] = $url . (strpos($url, '?') > 0 ? '&' : '?') . 'confirm=yes';
11692 }
11693
11694 // for js desabled compatibility set $url as call to confirm action and $params['confirm']['url'] to confirmed action
11695 $attr['data-confirm-url'] = $params['confirm']['url'];
11696 $attr['data-confirm-title'] = !empty($params['confirm']['title']) ? $params['confirm']['title'] : $langs->trans('ConfirmBtnCommonTitle', $label);
11697 $attr['data-confirm-content'] = !empty($params['confirm']['content']) ? $params['confirm']['content'] : $langs->trans('ConfirmBtnCommonContent', $label);
11698 $attr['data-confirm-content'] = preg_replace("/\r|\n/", "", $attr['data-confirm-content']);
11699 $attr['data-confirm-action-btn-label'] = !empty($params['confirm']['action-btn-label']) ? $params['confirm']['action-btn-label'] : $langs->trans('Confirm');
11700 $attr['data-confirm-cancel-btn-label'] = !empty($params['confirm']['cancel-btn-label']) ? $params['confirm']['cancel-btn-label'] : $langs->trans('CloseDialog');
11701 $attr['data-confirm-modal'] = !empty($params['confirm']['modal']) ? $params['confirm']['modal'] : true;
11702
11703 $attr['class'].= ' butActionConfirm';
11704 }
11705
11706 if (isset($attr['href']) && empty($attr['href'])) {
11707 unset($attr['href']);
11708 }
11709
11710 // escape all attribute
11711 $attr = array_map('dol_escape_htmltag', $attr);
11712
11713 $TCompiledAttr = array();
11714 foreach ($attr as $key => $value) {
11715 $TCompiledAttr[] = $key.'= "'.$value.'"';
11716 }
11717
11718 $compiledAttributes = empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr);
11719
11720 $tag = !empty($attr['href']) ? 'a' : 'span';
11721
11722
11723 $parameters = array(
11724 'TCompiledAttr' => $TCompiledAttr, // array
11725 'compiledAttributes' => $compiledAttributes, // string
11726 'attr' => $attr,
11727 'tag' => $tag,
11728 'label' => $label,
11729 'html' => $text,
11730 'actionType' => $actionType,
11731 'url' => $url,
11732 'id' => $id,
11733 'userRight' => $userRight,
11734 'params' => $params
11735 );
11736
11737 $reshook = $hookmanager->executeHooks('dolGetButtonAction', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
11738 if ($reshook < 0) {
11739 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
11740 }
11741
11742 if (empty($reshook)) {
11743 if (dol_textishtml($text)) { // If content already HTML encoded
11744 return '<' . $tag . ' ' . $compiledAttributes . '>' . $text . '</' . $tag . '>';
11745 } else {
11746 return '<' . $tag . ' ' . $compiledAttributes . '>' . dol_escape_htmltag($text) . '</' . $tag . '>';
11747 }
11748 } else {
11749 return $hookmanager->resPrint;
11750 }
11751}
11752
11759function dolGetButtonTitleSeparator($moreClass = "")
11760{
11761 return '<span class="button-title-separator '.$moreClass.'" ></span>';
11762}
11763
11770function getFieldErrorIcon($fieldValidationErrorMsg)
11771{
11772 $out = '';
11773 if (!empty($fieldValidationErrorMsg)) {
11774 $out.= '<span class="field-error-icon classfortooltip" title="'.dol_escape_htmltag($fieldValidationErrorMsg, 1).'" role="alert" >'; // role alert is used for accessibility
11775 $out.= '<span class="fa fa-exclamation-circle" aria-hidden="true" ></span>'; // For accessibility icon is separated and aria-hidden
11776 $out.= '</span>';
11777 }
11778
11779 return $out;
11780}
11781
11794function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $url = '', $id = '', $status = 1, $params = array())
11795{
11796 global $langs, $conf, $user;
11797
11798 // Actually this conf is used in css too for external module compatibility and smooth transition to this function
11799 if (getDolGlobalString('MAIN_BUTTON_HIDE_UNAUTHORIZED') && (!$user->admin) && $status <= 0) {
11800 return '';
11801 }
11802
11803 $class = 'btnTitle';
11804 if (in_array($iconClass, array('fa fa-plus-circle', 'fa fa-plus-circle size15x', 'fa fa-comment-dots', 'fa fa-paper-plane'))) {
11805 $class .= ' btnTitlePlus';
11806 }
11807 $useclassfortooltip = 1;
11808
11809 if (!empty($params['morecss'])) {
11810 $class .= ' '.$params['morecss'];
11811 }
11812
11813 $attr = array(
11814 'class' => $class,
11815 'href' => empty($url) ? '' : $url
11816 );
11817
11818 if (!empty($helpText)) {
11819 $attr['title'] = dol_escape_htmltag($helpText);
11820 } elseif (empty($attr['title']) && $label) {
11821 $attr['title'] = $label;
11822 $useclassfortooltip = 0;
11823 }
11824
11825 if ($status == 2) {
11826 $attr['class'] .= ' btnTitleSelected';
11827 } elseif ($status <= 0) {
11828 $attr['class'] .= ' refused';
11829
11830 $attr['href'] = '';
11831
11832 if ($status == -1) { // disable
11833 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("FeatureDisabled"));
11834 } elseif ($status == 0) { // Not enough permissions
11835 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions"));
11836 }
11837 }
11838
11839 if (!empty($attr['title']) && $useclassfortooltip) {
11840 $attr['class'] .= ' classfortooltip';
11841 }
11842
11843 if (!empty($id)) {
11844 $attr['id'] = $id;
11845 }
11846
11847 // Override attr
11848 if (!empty($params['attr']) && is_array($params['attr'])) {
11849 foreach ($params['attr'] as $key => $value) {
11850 if ($key == 'class') {
11851 $attr['class'] .= ' '.$value;
11852 } elseif ($key == 'classOverride') {
11853 $attr['class'] = $value;
11854 } else {
11855 $attr[$key] = $value;
11856 }
11857 }
11858 }
11859
11860 if (isset($attr['href']) && empty($attr['href'])) {
11861 unset($attr['href']);
11862 }
11863
11864 // TODO : add a hook
11865
11866 // escape all attribute
11867 $attr = array_map('dol_escape_htmltag', $attr);
11868
11869 $TCompiledAttr = array();
11870 foreach ($attr as $key => $value) {
11871 $TCompiledAttr[] = $key.'="'.$value.'"';
11872 }
11873
11874 $compiledAttributes = (empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr));
11875
11876 $tag = (empty($attr['href']) ? 'span' : 'a');
11877
11878 $button = '<'.$tag.' '.$compiledAttributes.'>';
11879 $button .= '<span class="'.$iconClass.' valignmiddle btnTitle-icon"></span>';
11880 if (!empty($params['forcenohideoftext'])) {
11881 $button .= '<span class="valignmiddle text-plus-circle btnTitle-label'.(empty($params['forcenohideoftext']) ? ' hideonsmartphone' : '').'">'.$label.'</span>';
11882 }
11883 $button .= '</'.$tag.'>';
11884
11885 return $button;
11886}
11887
11898function getElementProperties($element_type)
11899{
11900 global $conf, $db, $hookmanager;
11901
11902 $regs = array();
11903
11904 //$element_type='facture';
11905
11906 $classfile = $classname = $classpath = $subdir = $dir_output = '';
11907
11908 // Parse element/subelement
11909 $module = $element_type;
11910 $element = $element_type;
11911 $subelement = $element_type;
11912 $table_element = $element_type;
11913
11914 // If we ask a resource form external module (instead of default path)
11915 if (preg_match('/^([^@]+)@([^@]+)$/i', $element_type, $regs)) { // 'myobject@mymodule'
11916 $element = $subelement = $regs[1];
11917 $module = $regs[2];
11918 }
11919
11920 // If we ask a resource for a string with an element and a subelement
11921 // Example 'project_task'
11922 if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { // 'myobject_mysubobject' with myobject=mymodule
11923 $module = $element = $regs[1];
11924 $subelement = $regs[2];
11925 }
11926
11927 // For compatibility and to work with non standard path
11928 if ($element_type == "action" || $element_type == "actioncomm") {
11929 $classpath = 'comm/action/class';
11930 $subelement = 'Actioncomm';
11931 $module = 'agenda';
11932 $table_element = 'actioncomm';
11933 } elseif ($element_type == 'cronjob') {
11934 $classpath = 'cron/class';
11935 $module = 'cron';
11936 $table_element = 'cron';
11937 } elseif ($element_type == 'adherent_type') {
11938 $classpath = 'adherents/class';
11939 $classfile = 'adherent_type';
11940 $module = 'adherent';
11941 $subelement = 'adherent_type';
11942 $classname = 'AdherentType';
11943 $table_element = 'adherent_type';
11944 } elseif ($element_type == 'bank_account') {
11945 $classpath = 'compta/bank/class';
11946 $module = 'bank'; // We need $conf->bank->dir_output and not $conf->banque->dir_output
11947 $classfile = 'account';
11948 $classname = 'Account';
11949 } elseif ($element_type == 'category') {
11950 $classpath = 'categories/class';
11951 $module = 'categorie';
11952 $subelement = 'categorie';
11953 $table_element = 'categorie';
11954 } elseif ($element_type == 'contact') {
11955 $classpath = 'contact/class';
11956 $classfile = 'contact';
11957 $module = 'societe';
11958 $subelement = 'contact';
11959 $table_element = 'socpeople';
11960 } elseif ($element_type == 'inventory') {
11961 $module = 'product';
11962 $classpath = 'product/inventory/class';
11963 } elseif ($element_type == 'stock' || $element_type == 'entrepot') {
11964 $module = 'stock';
11965 $classpath = 'product/stock/class';
11966 $classfile = 'entrepot';
11967 $classname = 'Entrepot';
11968 $table_element = 'entrepot';
11969 } elseif ($element_type == 'project') {
11970 $classpath = 'projet/class';
11971 $module = 'projet';
11972 $table_element = 'projet';
11973 } elseif ($element_type == 'project_task') {
11974 $classpath = 'projet/class';
11975 $module = 'projet';
11976 $subelement = 'task';
11977 $table_element = 'projet_task';
11978 } elseif ($element_type == 'facture' || $element_type == 'invoice') {
11979 $classpath = 'compta/facture/class';
11980 $module = 'facture';
11981 $subelement = 'facture';
11982 $table_element = 'facture';
11983 } elseif ($element_type == 'commande' || $element_type == 'order') {
11984 $classpath = 'commande/class';
11985 $module = 'commande';
11986 $subelement = 'commande';
11987 $table_element = 'commande';
11988 } elseif ($element_type == 'propal') {
11989 $classpath = 'comm/propal/class';
11990 $table_element = 'propal';
11991 } elseif ($element_type == 'shipping') {
11992 $classpath = 'expedition/class';
11993 $classfile = 'expedition';
11994 $classname = 'Expedition';
11995 $module = 'expedition';
11996 $table_element = 'expedition';
11997 } elseif ($element_type == 'supplier_proposal') {
11998 $classpath = 'supplier_proposal/class';
11999 $module = 'supplier_proposal';
12000 $element = 'supplierproposal';
12001 $classfile = 'supplier_proposal';
12002 $subelement = 'supplierproposal';
12003 } elseif ($element_type == 'shipping') {
12004 $classpath = 'expedition/class';
12005 $subelement = 'expedition';
12006 $module = 'expedition_bon';
12007 } elseif ($element_type == 'delivery') {
12008 $classpath = 'delivery/class';
12009 $subelement = 'delivery';
12010 $module = 'expedition';
12011 } elseif ($element_type == 'contract') {
12012 $classpath = 'contrat/class';
12013 $module = 'contrat';
12014 $subelement = 'contrat';
12015 $table_element = 'contract';
12016 } elseif ($element_type == 'mailing') {
12017 $classpath = 'comm/mailing/class';
12018 $module = 'mailing';
12019 $classfile = 'mailing';
12020 $classname = 'Mailing';
12021 $subelement = '';
12022 } elseif ($element_type == 'member') {
12023 $classpath = 'adherents/class';
12024 $module = 'adherent';
12025 $subelement = 'adherent';
12026 $table_element = 'adherent';
12027 } elseif ($element_type == 'usergroup') {
12028 $classpath = 'user/class';
12029 $module = 'user';
12030 } elseif ($element_type == 'mo') {
12031 $classpath = 'mrp/class';
12032 $classfile = 'mo';
12033 $classname = 'Mo';
12034 $module = 'mrp';
12035 $subelement = '';
12036 $table_element = 'mrp_mo';
12037 } elseif ($element_type == 'cabinetmed_cons') {
12038 $classpath = 'cabinetmed/class';
12039 $module = 'cabinetmed';
12040 $subelement = 'cabinetmedcons';
12041 $table_element = 'cabinetmedcons';
12042 } elseif ($element_type == 'fichinter') {
12043 $classpath = 'fichinter/class';
12044 $module = 'ficheinter';
12045 $subelement = 'fichinter';
12046 $table_element = 'fichinter';
12047 } elseif ($element_type == 'dolresource' || $element_type == 'resource') {
12048 $classpath = 'resource/class';
12049 $module = 'resource';
12050 $subelement = 'dolresource';
12051 $table_element = 'resource';
12052 } elseif ($element_type == 'propaldet') {
12053 $classpath = 'comm/propal/class';
12054 $module = 'propal';
12055 $subelement = 'propaleligne';
12056 } elseif ($element_type == 'opensurvey_sondage') {
12057 $classpath = 'opensurvey/class';
12058 $module = 'opensurvey';
12059 $subelement = 'opensurveysondage';
12060 } elseif ($element_type == 'order_supplier') {
12061 $classpath = 'fourn/class';
12062 $module = 'fournisseur';
12063 $classfile = 'fournisseur.commande';
12064 $element = 'order_supplier';
12065 $subelement = '';
12066 $classname = 'CommandeFournisseur';
12067 $table_element = 'commande_fournisseur';
12068 } elseif ($element_type == 'commande_fournisseurdet') {
12069 $classpath = 'fourn/class';
12070 $module = 'fournisseur';
12071 $classfile = 'fournisseur.commande';
12072 $element = 'commande_fournisseurdet';
12073 $subelement = '';
12074 $classname = 'CommandeFournisseurLigne';
12075 $table_element = 'commande_fournisseurdet';
12076 } elseif ($element_type == 'invoice_supplier') {
12077 $classpath = 'fourn/class';
12078 $module = 'fournisseur';
12079 $classfile = 'fournisseur.facture';
12080 $element = 'invoice_supplier';
12081 $subelement = '';
12082 $classname = 'FactureFournisseur';
12083 $table_element = 'facture_fourn';
12084 } elseif ($element_type == "service") {
12085 $classpath = 'product/class';
12086 $subelement = 'product';
12087 $table_element = 'product';
12088 } elseif ($element_type == 'salary') {
12089 $classpath = 'salaries/class';
12090 $module = 'salaries';
12091 } elseif ($element_type == 'payment_salary') {
12092 $classpath = 'salaries/class';
12093 $classfile = 'paymentsalary';
12094 $classname = 'PaymentSalary';
12095 $module = 'salaries';
12096 } elseif ($element_type == 'productlot') {
12097 $module = 'productbatch';
12098 $classpath = 'product/stock/class';
12099 $classfile = 'productlot';
12100 $classname = 'Productlot';
12101 $element = 'productlot';
12102 $subelement = '';
12103 $table_element = 'product_lot';
12104 } elseif ($element_type == 'websitepage') {
12105 $classpath = 'website/class';
12106 $classfile = 'websitepage';
12107 $classname = 'Websitepage';
12108 $module = 'website';
12109 $subelement = 'websitepage';
12110 $table_element = 'website_page';
12111 } elseif ($element_type == 'fiscalyear') {
12112 $classpath = 'core/class';
12113 $module = 'accounting';
12114 $subelement = 'fiscalyear';
12115 } elseif ($element_type == 'chargesociales') {
12116 $classpath = 'compta/sociales/class';
12117 $module = 'tax';
12118 $table_element = 'chargesociales';
12119 } elseif ($element_type == 'tva') {
12120 $classpath = 'compta/tva/class';
12121 $module = 'tax';
12122 $subdir = '/vat';
12123 $table_element = 'tva';
12124 } elseif ($element_type == 'emailsenderprofile') {
12125 $module = '';
12126 $classpath = 'core/class';
12127 $classfile = 'emailsenderprofile';
12128 $classname = 'EmailSenderProfile';
12129 $table_element = 'c_email_senderprofile';
12130 $subelement = '';
12131 } elseif ($element_type == 'ccountry') {
12132 $module = '';
12133 $classpath = 'core/class';
12134 $classfile = 'ccountry';
12135 $classname = 'Ccountry';
12136 $table_element = 'c_country';
12137 $subelement = '';
12138 }
12139
12140 if (empty($classfile)) {
12141 $classfile = strtolower($subelement);
12142 }
12143 if (empty($classname)) {
12144 $classname = ucfirst($subelement);
12145 }
12146 if (empty($classpath)) {
12147 $classpath = $module.'/class';
12148 }
12149
12150 //print 'getElementProperties subdir='.$subdir;
12151
12152 // Set dir_output
12153 if ($module && isset($conf->$module)) { // The generic case
12154 if (!empty($conf->$module->multidir_output[$conf->entity])) {
12155 $dir_output = $conf->$module->multidir_output[$conf->entity];
12156 } elseif (!empty($conf->$module->output[$conf->entity])) {
12157 $dir_output = $conf->$module->output[$conf->entity];
12158 } elseif (!empty($conf->$module->dir_output)) {
12159 $dir_output = $conf->$module->dir_output;
12160 }
12161 }
12162
12163 // Overwrite value for special cases
12164 if ($element == 'order_supplier') {
12165 $dir_output = $conf->fournisseur->commande->dir_output;
12166 } elseif ($element == 'invoice_supplier') {
12167 $dir_output = $conf->fournisseur->facture->dir_output;
12168 }
12169 $dir_output .= $subdir;
12170
12171 $elementProperties = array(
12172 'module' => $module,
12173 'element' => $element,
12174 'table_element' => $table_element,
12175 'subelement' => $subelement,
12176 'classpath' => $classpath,
12177 'classfile' => $classfile,
12178 'classname' => $classname,
12179 'dir_output' => $dir_output
12180 );
12181
12182
12183 // Add hook
12184 if (!is_object($hookmanager)) {
12185 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
12186 $hookmanager = new HookManager($db);
12187 }
12188 $hookmanager->initHooks(array('elementproperties'));
12189
12190
12191 // Hook params
12192 $parameters = array(
12193 'elementType' => $element_type,
12194 'elementProperties' => $elementProperties
12195 );
12196
12197 $reshook = $hookmanager->executeHooks('getElementProperties', $parameters);
12198
12199 if ($reshook) {
12200 $elementProperties = $hookmanager->resArray;
12201 } elseif (!empty($hookmanager->resArray) && is_array($hookmanager->resArray)) { // resArray is always an array but for sécurity against misconfigured external modules
12202 $elementProperties = array_replace($elementProperties, $hookmanager->resArray);
12203 }
12204
12205 // context of elementproperties doesn't need to exist out of this function so delete it to avoid elementproperties context is equal to all
12206 if (($key = array_search('elementproperties', $hookmanager->contextarray)) !== false) {
12207 unset($hookmanager->contextarray[$key]);
12208 }
12209
12210 return $elementProperties;
12211}
12212
12223function fetchObjectByElement($element_id, $element_type, $element_ref = '')
12224{
12225 global $db;
12226
12227 $ret = 0;
12228
12229 $element_prop = getElementProperties($element_type);
12230
12231 if ($element_prop['module'] == 'product' || $element_prop['module'] == 'service') {
12232 // For example, for an extrafield 'product' (shared for both product and service) that is a link to an object,
12233 // this is called with $element_type = 'product' when we need element properties of a service, we must return a product. If we create the
12234 // extrafield for a service, it is not supported and not found when editing the product/service card. So we must keep 'product' for extrafields
12235 // of service and we will return properties of a product.
12236 $ismodenabled = (isModEnabled('product') || isModEnabled('service'));
12237 } else {
12238 $ismodenabled = isModEnabled($element_prop['module']);
12239 }
12240 //var_dump('element_type='.$element_type);
12241 //var_dump($element_prop);
12242 //var_dump($element_prop['module'].' '.$ismodenabled);
12243 if (is_array($element_prop) && (empty($element_prop['module']) || $ismodenabled)) {
12244 dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php');
12245
12246 if (class_exists($element_prop['classname'])) {
12247 $classname = $element_prop['classname'];
12248 $objecttmp = new $classname($db);
12249
12250 if ($element_id > 0 || !empty($element_ref)) {
12251 $ret = $objecttmp->fetch($element_id, $element_ref);
12252 if ($ret >= 0) {
12253 if (empty($objecttmp->module)) {
12254 $objecttmp->module = $element_prop['module'];
12255 }
12256 return $objecttmp;
12257 }
12258 } else {
12259 return $objecttmp; // returned an object without fetch
12260 }
12261 } else {
12262 return -1;
12263 }
12264 }
12265
12266 return $ret;
12267}
12268
12276{
12277 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)) {
12278 return true;
12279 }
12280
12281 return false;
12282}
12283
12291function newToken()
12292{
12293 return empty($_SESSION['newtoken']) ? '' : $_SESSION['newtoken'];
12294}
12295
12304{
12305 return isset($_SESSION['token']) ? $_SESSION['token'] : '';
12306}
12307
12313function getNonce()
12314{
12315 global $conf;
12316
12317 if (empty($conf->cache['nonce'])) {
12318 $conf->cache['nonce'] = dolGetRandomBytes(8);
12319 }
12320
12321 return $conf->cache['nonce'];
12322}
12323
12324
12337function startSimpleTable($header, $link = "", $arguments = "", $emptyRows = 0, $number = -1)
12338{
12339 global $langs;
12340
12341 print '<div class="div-table-responsive-no-min">';
12342 print '<table class="noborder centpercent">';
12343 print '<tr class="liste_titre">';
12344
12345 print $emptyRows < 1 ? '<th>' : '<th colspan="'.($emptyRows + 1).'">';
12346
12347 print $langs->trans($header);
12348
12349 // extra space between the first header and the number
12350 if ($number > -1) {
12351 print ' ';
12352 }
12353
12354 if (!empty($link)) {
12355 if (!empty($arguments)) {
12356 print '<a href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
12357 } else {
12358 print '<a href="'.DOL_URL_ROOT.'/'.$link.'">';
12359 }
12360 }
12361
12362 if ($number > -1) {
12363 print '<span class="badge">'.$number.'</span>';
12364 }
12365
12366 if (!empty($link)) {
12367 print '</a>';
12368 }
12369
12370 print '</th>';
12371
12372 if ($number < 0 && !empty($link)) {
12373 print '<th class="right">';
12374
12375 if (!empty($arguments)) {
12376 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
12377 } else {
12378 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'">';
12379 }
12380
12381 print $langs->trans("FullList");
12382 print '</a>';
12383 print '</th>';
12384 }
12385
12386 print '</tr>';
12387}
12388
12397function finishSimpleTable($addLineBreak = false)
12398{
12399 print '</table>';
12400 print '</div>';
12401
12402 if ($addLineBreak) {
12403 print '<br>';
12404 }
12405}
12406
12418function addSummaryTableLine($tableColumnCount, $num, $nbofloop = 0, $total = 0, $noneWord = "None", $extraRightColumn = false)
12419{
12420 global $langs;
12421
12422 if ($num === 0) {
12423 print '<tr class="oddeven">';
12424 print '<td colspan="'.$tableColumnCount.'"><span class="opacitymedium">'.$langs->trans($noneWord).'</span></td>';
12425 print '</tr>';
12426 return;
12427 }
12428
12429 if ($nbofloop === 0) {
12430 // don't show a summary line
12431 return;
12432 }
12433
12434 if ($num === 0) {
12435 $colspan = $tableColumnCount;
12436 } elseif ($num > $nbofloop) {
12437 $colspan = $tableColumnCount;
12438 } else {
12439 $colspan = $tableColumnCount - 1;
12440 }
12441
12442 if ($extraRightColumn) {
12443 $colspan--;
12444 }
12445
12446 print '<tr class="liste_total">';
12447
12448 if ($nbofloop > 0 && $num > $nbofloop) {
12449 print '<td colspan="'.$colspan.'" class="right">'.$langs->trans("XMoreLines", ($num - $nbofloop)).'</td>';
12450 } else {
12451 print '<td colspan="'.$colspan.'" class="right"> '.$langs->trans("Total").'</td>';
12452 print '<td class="right centpercent">'.price($total).'</td>';
12453 }
12454
12455 if ($extraRightColumn) {
12456 print '<td></td>';
12457 }
12458
12459 print '</tr>';
12460}
12461
12470function readfileLowMemory($fullpath_original_file_osencoded, $method = -1)
12471{
12472 if ($method == -1) {
12473 $method = 0;
12474 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_FREAD')) {
12475 $method = 1;
12476 }
12477 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_STREAM_COPY')) {
12478 $method = 2;
12479 }
12480 }
12481
12482 // Be sure we don't have output buffering enabled to have readfile working correctly
12483 while (ob_get_level()) {
12484 ob_end_flush();
12485 }
12486
12487 // Solution 0
12488 if ($method == 0) {
12489 readfile($fullpath_original_file_osencoded);
12490 } elseif ($method == 1) {
12491 // Solution 1
12492 $handle = fopen($fullpath_original_file_osencoded, "rb");
12493 while (!feof($handle)) {
12494 print fread($handle, 8192);
12495 }
12496 fclose($handle);
12497 } elseif ($method == 2) {
12498 // Solution 2
12499 $handle1 = fopen($fullpath_original_file_osencoded, "rb");
12500 $handle2 = fopen("php://output", "wb");
12501 stream_copy_to_stream($handle1, $handle2);
12502 fclose($handle1);
12503 fclose($handle2);
12504 }
12505}
12506
12516function showValueWithClipboardCPButton($valuetocopy, $showonlyonhover = 1, $texttoshow = '')
12517{
12518 /*
12519 global $conf;
12520
12521 if (!empty($conf->dol_no_mouse_hover)) {
12522 $showonlyonhover = 0;
12523 }*/
12524
12525 $tag = 'span'; // Using div (like any style of type 'block') does not work when using the js copy code.
12526 if ($texttoshow === 'none') {
12527 $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>';
12528 } elseif ($texttoshow) {
12529 $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>';
12530 } else {
12531 $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>';
12532 }
12533
12534 return $result;
12535}
12536
12537
12544function jsonOrUnserialize($stringtodecode)
12545{
12546 $result = json_decode($stringtodecode);
12547 if ($result === null) {
12548 $result = unserialize($stringtodecode);
12549 }
12550
12551 return $result;
12552}
12553
12554
12568function forgeSQLFromUniversalSearchCriteria($filter, &$errorstr = '', $noand = 0, $nopar = 0, $noerror = 0)
12569{
12570 if (empty($filter)) {
12571 return ''; // to avoid the return "AND (())"
12572 }
12573
12574 if (!preg_match('/^\‍(.*\‍)$/', $filter)) { // If $filter does not start and end with ()
12575 $filter = '(' . $filter . ')';
12576 }
12577
12578 $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'
12579
12580 if (!dolCheckFilters($filter, $errorstr)) {
12581 if ($noerror) {
12582 return '1 = 2';
12583 } else {
12584 return 'Filter syntax error - '.$errorstr; // Bad balance of parenthesis, we return an error message or force a SQL not found
12585 }
12586 }
12587
12588 // Test the filter syntax
12589 $t = preg_replace_callback('/'.$regexstring.'/i', 'dolForgeDummyCriteriaCallback', $filter);
12590 $t = str_replace(array('and','or','AND','OR',' '), '', $t); // Remove the only strings allowed between each () criteria
12591 // If the string result contains something else than '()', the syntax was wrong
12592 if (preg_match('/[^\‍(\‍)]/', $t)) {
12593 $errorstr = 'Bad syntax of the search string';
12594 if ($noerror) {
12595 return '1 = 2';
12596 } else {
12597 return 'Filter syntax error - '.$errorstr; // Bad syntax of the search string, we return an error message or force a SQL not found
12598 }
12599 }
12600
12601 return ($noand ? "" : " AND ").($nopar ? "" : '(').preg_replace_callback('/'.$regexstring.'/i', 'dolForgeCriteriaCallback', $filter).($nopar ? "" : ')');
12602}
12603
12611function dolCheckFilters($sqlfilters, &$error = '')
12612{
12613 //$regexstring='\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^:\‍(\‍)]+)\‍)';
12614 //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
12615 $tmp = $sqlfilters;
12616 $i = 0;
12617 $nb = strlen($tmp);
12618 $counter = 0;
12619 while ($i < $nb) {
12620 if ($tmp[$i] == '(') {
12621 $counter++;
12622 }
12623 if ($tmp[$i] == ')') {
12624 $counter--;
12625 }
12626 if ($counter < 0) {
12627 $error = "Wrond balance of parenthesis in sqlfilters=".$sqlfilters;
12628 dol_syslog($error, LOG_WARNING);
12629 return false;
12630 }
12631 $i++;
12632 }
12633 return true;
12634}
12635
12644{
12645 //dol_syslog("Convert matches ".$matches[1]);
12646 if (empty($matches[1])) {
12647 return '';
12648 }
12649 $tmp = explode(':', $matches[1]);
12650 if (count($tmp) < 3) {
12651 return '';
12652 }
12653
12654 return '()'; // An empty criteria
12655}
12656
12666{
12667 global $db;
12668
12669 //dol_syslog("Convert matches ".$matches[1]);
12670 if (empty($matches[1])) {
12671 return '';
12672 }
12673 $tmp = explode(':', $matches[1]);
12674 if (count($tmp) < 3) {
12675 return '';
12676 }
12677
12678 $operand = preg_replace('/[^a-z0-9\._]/i', '', trim($tmp[0]));
12679
12680 $operator = strtoupper(preg_replace('/[^a-z<>!=]/i', '', trim($tmp[1])));
12681
12682 $realOperator = [
12683 'NOTLIKE' => 'NOT LIKE',
12684 'ISNOT' => 'IS NOT',
12685 'NOTIN' => 'NOT IN',
12686 '!=' => '<>',
12687 ];
12688
12689 if (array_key_exists($operator, $realOperator)) {
12690 $operator = $realOperator[$operator];
12691 }
12692
12693
12694 $tmpescaped = $tmp[2];
12695 $regbis = array();
12696
12697 if ($operator == 'IN' || $operator == 'NOT IN') { // IN is allowed for list of ID or code only
12698 //if (!preg_match('/^\‍(.*\‍)$/', $tmpescaped)) {
12699 $tmpescaped2 = '(';
12700 // Explode and sanitize each element in list
12701 $tmpelemarray = explode(',', $tmpescaped);
12702 foreach ($tmpelemarray as $tmpkey => $tmpelem) {
12703 $reg = array();
12704 if (preg_match('/^\'(.*)\'$/', $tmpelem, $reg)) {
12705 $tmpelemarray[$tmpkey] = "'".$db->escape($db->sanitize($reg[1], 1, 1, 1))."'";
12706 } else {
12707 $tmpelemarray[$tmpkey] = $db->escape($db->sanitize($tmpelem, 1, 1, 1));
12708 }
12709 }
12710 $tmpescaped2 .= join(',', $tmpelemarray);
12711 $tmpescaped2 .= ')';
12712
12713 $tmpescaped = $tmpescaped2;
12714 } elseif ($operator == 'LIKE' || $operator == 'NOT LIKE') {
12715 if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12716 $tmpescaped = $regbis[1];
12717 }
12718 //$tmpescaped = "'".$db->escape($db->escapeforlike($regbis[1]))."'";
12719 $tmpescaped = "'".$db->escape($tmpescaped)."'"; // We do not escape the _ and % so the like will works
12720 } elseif (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12721 $tmpescaped = "'".$db->escape($regbis[1])."'";
12722 } else {
12723 if (strtoupper($tmpescaped) == 'NULL') {
12724 $tmpescaped = 'NULL';
12725 } elseif (is_int($tmpescaped)) {
12726 $tmpescaped = (int) $tmpescaped;
12727 } else {
12728 $tmpescaped = (float) $tmpescaped;
12729 }
12730 }
12731
12732 return '('.$db->escape($operand).' '.strtoupper($operator).' '.$tmpescaped.')';
12733}
12734
12735
12745function getTimelineIcon($actionstatic, &$histo, $key)
12746{
12747 global $conf, $langs;
12748
12749 $out = '<!-- timeline icon -->'."\n";
12750 $iconClass = 'fa fa-comments';
12751 $img_picto = '';
12752 $colorClass = '';
12753 $pictoTitle = '';
12754
12755 if ($histo[$key]['percent'] == -1) {
12756 $colorClass = 'timeline-icon-not-applicble';
12757 $pictoTitle = $langs->trans('StatusNotApplicable');
12758 } elseif ($histo[$key]['percent'] == 0) {
12759 $colorClass = 'timeline-icon-todo';
12760 $pictoTitle = $langs->trans('StatusActionToDo').' (0%)';
12761 } elseif ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100) {
12762 $colorClass = 'timeline-icon-in-progress';
12763 $pictoTitle = $langs->trans('StatusActionInProcess').' ('.$histo[$key]['percent'].'%)';
12764 } elseif ($histo[$key]['percent'] >= 100) {
12765 $colorClass = 'timeline-icon-done';
12766 $pictoTitle = $langs->trans('StatusActionDone').' (100%)';
12767 }
12768
12769 if ($actionstatic->code == 'AC_TICKET_CREATE') {
12770 $iconClass = 'fa fa-ticket';
12771 } elseif ($actionstatic->code == 'AC_TICKET_MODIFY') {
12772 $iconClass = 'fa fa-pencilxxx';
12773 } elseif (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12774 $iconClass = 'fa fa-comments';
12775 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12776 $iconClass = 'fa fa-mask';
12777 } elseif (getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
12778 if ($actionstatic->type_picto) {
12779 $img_picto = img_picto('', $actionstatic->type_picto);
12780 } else {
12781 if ($actionstatic->type_code == 'AC_RDV') {
12782 $iconClass = 'fa fa-handshake';
12783 } elseif ($actionstatic->type_code == 'AC_TEL') {
12784 $iconClass = 'fa fa-phone';
12785 } elseif ($actionstatic->type_code == 'AC_FAX') {
12786 $iconClass = 'fa fa-fax';
12787 } elseif ($actionstatic->type_code == 'AC_EMAIL') {
12788 $iconClass = 'fa fa-envelope';
12789 } elseif ($actionstatic->type_code == 'AC_INT') {
12790 $iconClass = 'fa fa-shipping-fast';
12791 } elseif ($actionstatic->type_code == 'AC_OTH_AUTO') {
12792 $iconClass = 'fa fa-robot';
12793 } elseif (!preg_match('/_AUTO/', $actionstatic->type_code)) {
12794 $iconClass = 'fa fa-robot';
12795 }
12796 }
12797 }
12798
12799 $out .= '<i class="'.$iconClass.' '.$colorClass.'" title="'.$pictoTitle.'">'.$img_picto.'</i>'."\n";
12800 return $out;
12801}
12802
12809function getActionCommEcmList($object)
12810{
12811 global $conf, $db;
12812
12813 $documents = array();
12814
12815 $sql = 'SELECT ecm.rowid as id, ecm.src_object_type, ecm.src_object_id, ecm.filepath, ecm.filename';
12816 $sql .= ' FROM '.MAIN_DB_PREFIX.'ecm_files ecm';
12817 $sql .= " WHERE ecm.filepath = 'agenda/".((int) $object->id)."'";
12818 //$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
12819 $sql .= ' ORDER BY ecm.position ASC';
12820
12821 $resql = $db->query($sql);
12822 if ($resql) {
12823 if ($db->num_rows($resql)) {
12824 while ($obj = $db->fetch_object($resql)) {
12825 $documents[$obj->id] = $obj;
12826 }
12827 }
12828 }
12829
12830 return $documents;
12831}
12832
12833
12834
12852function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
12853{
12854 global $user, $conf;
12855 global $form;
12856
12857 global $param, $massactionbutton;
12858
12859 dol_include_once('/comm/action/class/actioncomm.class.php');
12860
12861 // Check parameters
12862 if (!is_object($filterobj) && !is_object($objcon)) {
12863 dol_print_error('', 'BadParameter');
12864 }
12865
12866 $histo = array();
12867 $numaction = 0;
12868 $now = dol_now();
12869
12870 $sortfield_list = explode(',', $sortfield);
12871 $sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent');
12872 $sortfield_new_list = array();
12873 foreach ($sortfield_list as $sortfield_value) {
12874 $sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)];
12875 }
12876 $sortfield_new = implode(',', $sortfield_new_list);
12877
12878 if (isModEnabled('agenda')) {
12879 // Search histo on actioncomm
12880 if (is_object($objcon) && $objcon->id > 0) {
12881 $sql = "SELECT DISTINCT a.id, a.label as label,";
12882 } else {
12883 $sql = "SELECT a.id, a.label as label,";
12884 }
12885 $sql .= " a.datep as dp,";
12886 $sql .= " a.note as message,";
12887 $sql .= " a.datep2 as dp2,";
12888 $sql .= " a.percent as percent, 'action' as type,";
12889 $sql .= " a.fk_element, a.elementtype,";
12890 $sql .= " a.fk_contact,";
12891 $sql .= " a.email_from as msg_from,";
12892 $sql .= " c.code as acode, c.libelle as alabel, c.picto as apicto,";
12893 $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";
12894 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12895 $sql .= ", sp.lastname, sp.firstname";
12896 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12897 $sql .= ", m.lastname, m.firstname";
12898 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12899 $sql .= ", o.ref";
12900 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12901 $sql .= ", o.ref";
12902 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12903 $sql .= ", o.ref";
12904 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12905 $sql .= ", o.ref";
12906 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12907 $sql .= ", o.ref";
12908 }
12909 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
12910 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
12911 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
12912
12913 $force_filter_contact = false;
12914 if (is_object($objcon) && $objcon->id > 0) {
12915 $force_filter_contact = true;
12916 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
12917 $sql .= " AND r.element_type = '".$db->escape($objcon->table_element)."' AND r.fk_element = ".((int) $objcon->id);
12918 }
12919
12920 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12921 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
12922 } elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
12923 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er";
12924 $sql .= " ON er.resource_type = 'dolresource'";
12925 $sql .= " AND er.element_id = a.id";
12926 $sql .= " AND er.resource_id = ".((int) $filterobj->id);
12927 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12928 $sql .= ", ".MAIN_DB_PREFIX."adherent as m";
12929 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12930 $sql .= ", ".MAIN_DB_PREFIX."commande_fournisseur as o";
12931 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12932 $sql .= ", ".MAIN_DB_PREFIX."product as o";
12933 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12934 $sql .= ", ".MAIN_DB_PREFIX."ticket as o";
12935 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12936 $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o";
12937 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12938 $sql .= ", ".MAIN_DB_PREFIX."contrat as o";
12939 }
12940
12941 $sql .= " WHERE a.entity IN (".getEntity('agenda').")";
12942 if ($force_filter_contact === false) {
12943 if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) {
12944 $sql .= " AND a.fk_soc = ".((int) $filterobj->id);
12945 } elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) {
12946 $sql .= " AND a.fk_project = ".((int) $filterobj->id);
12947 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12948 $sql .= " AND a.fk_element = m.rowid AND a.elementtype = 'member'";
12949 if ($filterobj->id) {
12950 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12951 }
12952 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12953 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'order_supplier'";
12954 if ($filterobj->id) {
12955 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12956 }
12957 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12958 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
12959 if ($filterobj->id) {
12960 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12961 }
12962 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12963 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'ticket'";
12964 if ($filterobj->id) {
12965 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12966 }
12967 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12968 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'bom'";
12969 if ($filterobj->id) {
12970 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12971 }
12972 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12973 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'contract'";
12974 if ($filterobj->id) {
12975 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12976 }
12977 }
12978 }
12979
12980 // Condition on actioncode
12981 if (!empty($actioncode)) {
12982 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
12983 if ($actioncode == 'AC_NON_AUTO') {
12984 $sql .= " AND c.type != 'systemauto'";
12985 } elseif ($actioncode == 'AC_ALL_AUTO') {
12986 $sql .= " AND c.type = 'systemauto'";
12987 } else {
12988 if ($actioncode == 'AC_OTH') {
12989 $sql .= " AND c.type != 'systemauto'";
12990 } elseif ($actioncode == 'AC_OTH_AUTO') {
12991 $sql .= " AND c.type = 'systemauto'";
12992 }
12993 }
12994 } else {
12995 if ($actioncode == 'AC_NON_AUTO') {
12996 $sql .= " AND c.type != 'systemauto'";
12997 } elseif ($actioncode == 'AC_ALL_AUTO') {
12998 $sql .= " AND c.type = 'systemauto'";
12999 } else {
13000 $sql .= " AND c.code = '".$db->escape($actioncode)."'";
13001 }
13002 }
13003 }
13004 if ($donetodo == 'todo') {
13005 $sql .= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
13006 } elseif ($donetodo == 'done') {
13007 $sql .= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
13008 }
13009 if (is_array($filters) && $filters['search_agenda_label']) {
13010 $sql .= natural_search('a.label', $filters['search_agenda_label']);
13011 }
13012 }
13013
13014 // Add also event from emailings. TODO This should be replaced by an automatic event ? May be it's too much for very large emailing.
13015 if (isModEnabled('mailing') && !empty($objcon->email)
13016 && (empty($actioncode) || $actioncode == 'AC_OTH_AUTO' || $actioncode == 'AC_EMAILING')) {
13017 $langs->load("mails");
13018
13019 $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";
13020 $sql2 .= ", null as fk_element, '' as elementtype, null as contact_id";
13021 $sql2 .= ", 'AC_EMAILING' as acode, '' as alabel, '' as apicto";
13022 $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
13023 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
13024 $sql2 .= ", '' as lastname, '' as firstname";
13025 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
13026 $sql2 .= ", '' as lastname, '' as firstname";
13027 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
13028 $sql2 .= ", '' as ref";
13029 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
13030 $sql2 .= ", '' as ref";
13031 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
13032 $sql2 .= ", '' as ref";
13033 }
13034 $sql2 .= " FROM ".MAIN_DB_PREFIX."mailing as m, ".MAIN_DB_PREFIX."mailing_cibles as mc, ".MAIN_DB_PREFIX."user as u";
13035 $sql2 .= " WHERE mc.email = '".$db->escape($objcon->email)."'"; // Search is done on email.
13036 $sql2 .= " AND mc.statut = 1";
13037 $sql2 .= " AND u.rowid = m.fk_user_valid";
13038 $sql2 .= " AND mc.fk_mailing=m.rowid";
13039 }
13040
13041 if (!empty($sql) && !empty($sql2)) {
13042 $sql = $sql." UNION ".$sql2;
13043 } elseif (empty($sql) && !empty($sql2)) {
13044 $sql = $sql2;
13045 }
13046
13047 // TODO Add limit in nb of results
13048 if ($sql) { // May not be defined if module Agenda is not enabled and mailing module disabled too
13049 $sql .= $db->order($sortfield_new, $sortorder);
13050
13051 dol_syslog("function.lib::show_actions_messaging", LOG_DEBUG);
13052 $resql = $db->query($sql);
13053 if ($resql) {
13054 $i = 0;
13055 $num = $db->num_rows($resql);
13056
13057 while ($i < $num) {
13058 $obj = $db->fetch_object($resql);
13059
13060 if ($obj->type == 'action') {
13061 $contactaction = new ActionComm($db);
13062 $contactaction->id = $obj->id;
13063 $result = $contactaction->fetchResources();
13064 if ($result < 0) {
13065 dol_print_error($db);
13066 setEventMessage("actions.lib::show_actions_messaging Error fetch ressource", 'errors');
13067 }
13068
13069 //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
13070 //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
13071 $tododone = '';
13072 if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && $obj->dp > $now)) {
13073 $tododone = 'todo';
13074 }
13075
13076 $histo[$numaction] = array(
13077 'type'=>$obj->type,
13078 'tododone'=>$tododone,
13079 'id'=>$obj->id,
13080 'datestart'=>$db->jdate($obj->dp),
13081 'dateend'=>$db->jdate($obj->dp2),
13082 'note'=>$obj->label,
13083 'message'=>$obj->message,
13084 'percent'=>$obj->percent,
13085
13086 'userid'=>$obj->user_id,
13087 'login'=>$obj->user_login,
13088 'userfirstname'=>$obj->user_firstname,
13089 'userlastname'=>$obj->user_lastname,
13090 'userphoto'=>$obj->user_photo,
13091 'msg_from'=>$obj->msg_from,
13092
13093 'contact_id'=>$obj->fk_contact,
13094 'socpeopleassigned' => $contactaction->socpeopleassigned,
13095 'lastname' => (empty($obj->lastname) ? '' : $obj->lastname),
13096 'firstname' => (empty($obj->firstname) ? '' : $obj->firstname),
13097 'fk_element'=>$obj->fk_element,
13098 'elementtype'=>$obj->elementtype,
13099 // Type of event
13100 'acode'=>$obj->acode,
13101 'alabel'=>$obj->alabel,
13102 'libelle'=>$obj->alabel, // deprecated
13103 'apicto'=>$obj->apicto
13104 );
13105 } else {
13106 $histo[$numaction] = array(
13107 'type'=>$obj->type,
13108 'tododone'=>'done',
13109 'id'=>$obj->id,
13110 'datestart'=>$db->jdate($obj->dp),
13111 'dateend'=>$db->jdate($obj->dp2),
13112 'note'=>$obj->label,
13113 'message'=>$obj->message,
13114 'percent'=>$obj->percent,
13115 'acode'=>$obj->acode,
13116
13117 'userid'=>$obj->user_id,
13118 'login'=>$obj->user_login,
13119 'userfirstname'=>$obj->user_firstname,
13120 'userlastname'=>$obj->user_lastname,
13121 'userphoto'=>$obj->user_photo
13122 );
13123 }
13124
13125 $numaction++;
13126 $i++;
13127 }
13128 } else {
13129 dol_print_error($db);
13130 }
13131 }
13132
13133 // Set $out to show events
13134 $out = '';
13135
13136 if (!isModEnabled('agenda')) {
13137 $langs->loadLangs(array("admin", "errors"));
13138 $out = info_admin($langs->trans("WarningModuleXDisabledSoYouMayMissEventHere", $langs->transnoentitiesnoconv("Module2400Name")), 0, 0, 'warning');
13139 }
13140
13141 if (isModEnabled('agenda') || (isModEnabled('mailing') && !empty($objcon->email))) {
13142 $delay_warning = $conf->global->MAIN_DELAY_ACTIONS_TODO * 24 * 60 * 60;
13143
13144 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
13145 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
13146 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
13147 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
13148
13149 $formactions = new FormActions($db);
13150
13151 $actionstatic = new ActionComm($db);
13152 $userstatic = new User($db);
13153 $contactstatic = new Contact($db);
13154 $userGetNomUrlCache = array();
13155 $contactGetNomUrlCache = array();
13156
13157 $out .= '<div class="filters-container" >';
13158 $out .= '<form name="listactionsfilter" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
13159 $out .= '<input type="hidden" name="token" value="'.newToken().'">';
13160
13161 if ($objcon && get_class($objcon) == 'Contact' &&
13162 (is_null($filterobj) || get_class($filterobj) == 'Societe')) {
13163 $out .= '<input type="hidden" name="id" value="'.$objcon->id.'" />';
13164 } else {
13165 $out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
13166 }
13167 if ($filterobj && get_class($filterobj) == 'Societe') {
13168 $out .= '<input type="hidden" name="socid" value="'.$filterobj->id.'" />';
13169 }
13170
13171 $out .= "\n";
13172
13173 $out .= '<div class="div-table-responsive-no-min">';
13174 $out .= '<table class="noborder borderbottom centpercent">';
13175
13176 $out .= '<tr class="liste_titre">';
13177
13178 // Action column
13179 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
13180 $out .= '<th class="liste_titre width50 middle">';
13181 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
13182 $out .= $searchpicto;
13183 $out .= '</th>';
13184 }
13185
13186 $out .= getTitleFieldOfList('Date', 0, $_SERVER["PHP_SELF"], 'a.datep', '', $param, '', $sortfield, $sortorder, '')."\n";
13187
13188 $out .= '<th class="liste_titre"><strong class="hideonsmartphone">'.$langs->trans("Search").' : </strong></th>';
13189 if ($donetodo) {
13190 $out .= '<th class="liste_titre"></th>';
13191 }
13192 $out .= '<th class="liste_titre">';
13193 $out .= '<span class="fas fa-square inline-block fawidth30" style=" color: #ddd;" title="'.$langs->trans("ActionType").'"></span>';
13194 //$out .= img_picto($langs->trans("Type"), 'type');
13195 $out .= $formactions->select_type_actions($actioncode, "actioncode", '', !getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : -1, 0, 0, 1, 'minwidth200imp');
13196 $out .= '</th>';
13197 $out .= '<th class="liste_titre maxwidth100onsmartphone">';
13198 $out .= '<input type="text" class="maxwidth100onsmartphone" name="search_agenda_label" value="'.$filters['search_agenda_label'].'" placeholder="'.$langs->trans("Label").'">';
13199 $out .= '</th>';
13200
13201 // Action column
13202 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
13203 $out .= '<th class="liste_titre width50 middle">';
13204 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
13205 $out .= $searchpicto;
13206 $out .= '</th>';
13207 }
13208
13209 $out .= '</tr>';
13210
13211
13212 $out .= '</table>';
13213
13214 $out .= '</form>';
13215 $out .= '</div>';
13216
13217 $out .= "\n";
13218
13219 $out .= '<ul class="timeline">';
13220
13221 if ($donetodo) {
13222 $tmp = '';
13223 if (get_class($filterobj) == 'Societe') {
13224 $tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&socid='.$filterobj->id.'&status=done">';
13225 }
13226 $tmp .= ($donetodo != 'done' ? $langs->trans("ActionsToDoShort") : '');
13227 $tmp .= ($donetodo != 'done' && $donetodo != 'todo' ? ' / ' : '');
13228 $tmp .= ($donetodo != 'todo' ? $langs->trans("ActionsDoneShort") : '');
13229 //$out.=$langs->trans("ActionsToDoShort").' / '.$langs->trans("ActionsDoneShort");
13230 if (get_class($filterobj) == 'Societe') {
13231 $tmp .= '</a>';
13232 }
13233 $out .= getTitleFieldOfList($tmp);
13234 }
13235
13236 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
13237 $caction = new CActionComm($db);
13238 $arraylist = $caction->liste_array(1, 'code', '', (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : 0), '', 1);
13239
13240 $actualCycleDate = false;
13241
13242 // Loop on each event to show it
13243 foreach ($histo as $key => $value) {
13244 $actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo
13245
13246 $actionstatic->type_picto = $histo[$key]['apicto'];
13247 $actionstatic->type_code = $histo[$key]['acode'];
13248
13249 $labeltype = $actionstatic->type_code;
13250 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') && empty($arraylist[$labeltype])) {
13251 $labeltype = 'AC_OTH';
13252 }
13253 if (!empty($actionstatic->code) && preg_match('/^TICKET_MSG/', $actionstatic->code)) {
13254 $labeltype = $langs->trans("Message");
13255 } else {
13256 if (!empty($arraylist[$labeltype])) {
13257 $labeltype = $arraylist[$labeltype];
13258 }
13259 if ($actionstatic->type_code == 'AC_OTH_AUTO' && ($actionstatic->type_code != $actionstatic->code) && $labeltype && !empty($arraylist[$actionstatic->code])) {
13260 $labeltype .= ' - '.$arraylist[$actionstatic->code]; // Use code in priority on type_code
13261 }
13262 }
13263
13264 $url = DOL_URL_ROOT.'/comm/action/card.php?id='.$histo[$key]['id'];
13265
13266 $tmpa = dol_getdate($histo[$key]['datestart'], false);
13267
13268 if (isset($tmpa['year']) && isset($tmpa['yday']) && $actualCycleDate !== $tmpa['year'].'-'.$tmpa['yday']) {
13269 $actualCycleDate = $tmpa['year'].'-'.$tmpa['yday'];
13270 $out .= '<!-- timeline time label -->';
13271 $out .= '<li class="time-label">';
13272 $out .= '<span class="timeline-badge-date">';
13273 $out .= dol_print_date($histo[$key]['datestart'], 'daytext', 'tzuserrel', $langs);
13274 $out .= '</span>';
13275 $out .= '</li>';
13276 $out .= '<!-- /.timeline-label -->';
13277 }
13278
13279
13280 $out .= '<!-- timeline item -->'."\n";
13281 $out .= '<li class="timeline-code-'.strtolower($actionstatic->code).'">';
13282
13283 //$timelineicon = getTimelineIcon($actionstatic, $histo, $key);
13284 $typeicon = $actionstatic->getTypePicto('pictofixedwidth timeline-icon-not-applicble', $labeltype);
13285 //$out .= $timelineicon;
13286 //var_dump($timelineicon);
13287 $out .= $typeicon;
13288
13289 $out .= '<div class="timeline-item">'."\n";
13290
13291 $out .= '<span class="time timeline-header-action2">';
13292
13293 if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
13294 $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").' ';
13295 $out .= $histo[$key]['id'];
13296 $out .= '</a> ';
13297 } else {
13298 $out .= $actionstatic->getNomUrl(1, -1, 'valignmiddle').' ';
13299 }
13300
13301 if ($user->hasRight('agenda', 'allactions', 'create') ||
13302 (($actionstatic->authorid == $user->id || $actionstatic->userownerid == $user->id) && $user->hasRight('agenda', 'myactions', 'create'))) {
13303 $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).'">';
13304 //$out .= '<i class="fa fa-pencil" title="'.$langs->trans("Modify").'" ></i>';
13305 $out .= img_picto($langs->trans("Modify"), 'edit', 'class="edita"');
13306 $out .= '</a>';
13307 }
13308
13309 $out .= '</span>';
13310
13311 // Date
13312 $out .= '<span class="time"><i class="fa fa-clock-o valignmiddle"></i> <span class="valignmiddle">';
13313 $out .= dol_print_date($histo[$key]['datestart'], 'dayhour', 'tzuserrel');
13314 if ($histo[$key]['dateend'] && $histo[$key]['dateend'] != $histo[$key]['datestart']) {
13315 $tmpa = dol_getdate($histo[$key]['datestart'], true);
13316 $tmpb = dol_getdate($histo[$key]['dateend'], true);
13317 if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
13318 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'hour', 'tzuserrel');
13319 } else {
13320 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'dayhour', 'tzuserrel');
13321 }
13322 }
13323 $late = 0;
13324 if ($histo[$key]['percent'] == 0 && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13325 $late = 1;
13326 }
13327 if ($histo[$key]['percent'] == 0 && !$histo[$key]['datestart'] && $histo[$key]['dateend'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13328 $late = 1;
13329 }
13330 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && $histo[$key]['dateend'] && $histo[$key]['dateend'] < ($now - $delay_warning)) {
13331 $late = 1;
13332 }
13333 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && !$histo[$key]['dateend'] && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13334 $late = 1;
13335 }
13336 if ($late) {
13337 $out .= img_warning($langs->trans("Late")).' ';
13338 }
13339 $out .= "</span></span>\n";
13340
13341 // Ref
13342 $out .= '<h3 class="timeline-header">';
13343
13344 // Author of event
13345 $out .= '<div class="messaging-author inline-block tdoverflowmax150 valignmiddle marginrightonly">';
13346 if ($histo[$key]['userid'] > 0) {
13347 if (!isset($userGetNomUrlCache[$histo[$key]['userid']])) { // is in cache ?
13348 $userstatic->fetch($histo[$key]['userid']);
13349 $userGetNomUrlCache[$histo[$key]['userid']] = $userstatic->getNomUrl(-1, '', 0, 0, 16, 0, 'firstelselast', '');
13350 }
13351 $out .= $userGetNomUrlCache[$histo[$key]['userid']];
13352 } elseif (!empty($histo[$key]['msg_from']) && $actionstatic->code == 'TICKET_MSG') {
13353 if (!isset($contactGetNomUrlCache[$histo[$key]['msg_from']])) {
13354 if ($contactstatic->fetch(0, null, '', $histo[$key]['msg_from']) > 0) {
13355 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $contactstatic->getNomUrl(-1, '', 16);
13356 } else {
13357 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $histo[$key]['msg_from'];
13358 }
13359 }
13360 $out .= $contactGetNomUrlCache[$histo[$key]['msg_from']];
13361 }
13362 $out .= '</div>';
13363
13364 // Title
13365 $out .= ' <div class="messaging-title inline-block">';
13366 //$out .= $actionstatic->getTypePicto();
13367 if (empty($conf->dol_optimize_smallscreen) && $actionstatic->type_code != 'AC_OTH_AUTO') {
13368 $out .= $labeltype.' - ';
13369 }
13370
13371 $libelle = '';
13372 if (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
13373 $out .= $langs->trans('TicketNewMessage');
13374 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
13375 $out .= $langs->trans('TicketNewMessage').' <em>('.$langs->trans('Private').')</em>';
13376 } elseif (isset($histo[$key]['type'])) {
13377 if ($histo[$key]['type'] == 'action') {
13378 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
13379 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : $histo[$key]['alabel']);
13380 $libelle = $histo[$key]['note'];
13381 $actionstatic->id = $histo[$key]['id'];
13382 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13383 } elseif ($histo[$key]['type'] == 'mailing') {
13384 $out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
13385 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
13386 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : 'Send mass mailing');
13387 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13388 } else {
13389 $libelle .= $histo[$key]['note'];
13390 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13391 }
13392 }
13393
13394 if (isset($histo[$key]['elementtype']) && !empty($histo[$key]['fk_element'])) {
13395 if (isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']]) && isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']])) {
13396 $link = $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']];
13397 } else {
13398 if (!isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']])) {
13399 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']] = array();
13400 }
13401 $link = dolGetElementUrl($histo[$key]['fk_element'], $histo[$key]['elementtype'], 1);
13402 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']] = $link;
13403 }
13404 if ($link) {
13405 $out .= ' - '.$link;
13406 }
13407 }
13408
13409 $out .= '</div>';
13410
13411 $out .= '</h3>';
13412
13413 // Message
13414 if (!empty($histo[$key]['message'] && $histo[$key]['message'] != $libelle)
13415 && $actionstatic->code != 'AC_TICKET_CREATE'
13416 && $actionstatic->code != 'AC_TICKET_MODIFY'
13417 ) {
13418 $out .= '<div class="timeline-body wordbreak">';
13419 $truncateLines = getDolGlobalInt('MAIN_TRUNCATE_TIMELINE_MESSAGE', 3);
13420 $truncatedText = dolGetFirstLineOfText($histo[$key]['message'], $truncateLines);
13421 if ($truncateLines > 0 && strlen($histo[$key]['message']) > strlen($truncatedText)) {
13422 $out .= '<div class="readmore-block --closed" >';
13423 $out .= ' <div class="readmore-block__excerpt" >';
13424 $out .= $truncatedText ;
13425 $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>';
13426 $out .= ' </div>';
13427 $out .= ' <div class="readmore-block__full-text" >';
13428 $out .= $histo[$key]['message'];
13429 $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>';
13430 $out .= ' </div>';
13431 $out .= '</div>';
13432 } else {
13433 $out .= $histo[$key]['message'];
13434 }
13435
13436 $out .= '</div>';
13437 }
13438
13439 // Timeline footer
13440 $footer = '';
13441
13442 // Contact for this action
13443 if (isset($histo[$key]['socpeopleassigned']) && is_array($histo[$key]['socpeopleassigned']) && count($histo[$key]['socpeopleassigned']) > 0) {
13444 $contactList = '';
13445 foreach ($histo[$key]['socpeopleassigned'] as $cid => $Tab) {
13446 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
13447 $contact = new Contact($db);
13448 $contact->fetch($cid);
13449 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
13450 } else {
13451 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
13452 }
13453
13454 if ($contact) {
13455 $contactList .= !empty($contactList) ? ', ' : '';
13456 $contactList .= $contact->getNomUrl(1);
13457 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
13458 if (!empty($contact->phone_pro)) {
13459 $contactList .= '('.dol_print_phone($contact->phone_pro).')';
13460 }
13461 }
13462 }
13463 }
13464
13465 $footer .= $langs->trans('ActionOnContact').' : '.$contactList;
13466 } elseif (empty($objcon->id) && isset($histo[$key]['contact_id']) && $histo[$key]['contact_id'] > 0) {
13467 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
13468 $contact = new Contact($db);
13469 $result = $contact->fetch($histo[$key]['contact_id']);
13470 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
13471 } else {
13472 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
13473 }
13474
13475 if ($result > 0) {
13476 $footer .= $contact->getNomUrl(1);
13477 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
13478 if (!empty($contact->phone_pro)) {
13479 $footer .= '('.dol_print_phone($contact->phone_pro).')';
13480 }
13481 }
13482 }
13483 }
13484
13485 $documents = getActionCommEcmList($actionstatic);
13486 if (!empty($documents)) {
13487 $footer .= '<div class="timeline-documents-container">';
13488 foreach ($documents as $doc) {
13489 $footer .= '<span id="document_'.$doc->id.'" class="timeline-documents" ';
13490 $footer .= ' data-id="'.$doc->id.'" ';
13491 $footer .= ' data-path="'.$doc->filepath.'"';
13492 $footer .= ' data-filename="'.dol_escape_htmltag($doc->filename).'" ';
13493 $footer .= '>';
13494
13495 $filePath = DOL_DATA_ROOT.'/'.$doc->filepath.'/'.$doc->filename;
13496 $mime = dol_mimetype($filePath);
13497 $file = $actionstatic->id.'/'.$doc->filename;
13498 $thumb = $actionstatic->id.'/thumbs/'.substr($doc->filename, 0, strrpos($doc->filename, '.')).'_mini'.substr($doc->filename, strrpos($doc->filename, '.'));
13499 $doclink = dol_buildpath('document.php', 1).'?modulepart=actions&attachment=0&file='.urlencode($file).'&entity='.$conf->entity;
13500 $viewlink = dol_buildpath('viewimage.php', 1).'?modulepart=actions&file='.urlencode($thumb).'&entity='.$conf->entity;
13501
13502 $mimeAttr = ' mime="'.$mime.'" ';
13503 $class = '';
13504 if (in_array($mime, array('image/png', 'image/jpeg', 'application/pdf'))) {
13505 $class .= ' documentpreview';
13506 }
13507
13508 $footer .= '<a href="'.$doclink.'" class="btn-link '.$class.'" target="_blank" rel="noopener noreferrer" '.$mimeAttr.' >';
13509 $footer .= img_mime($filePath).' '.$doc->filename;
13510 $footer .= '</a>';
13511
13512 $footer .= '</span>';
13513 }
13514 $footer .= '</div>';
13515 }
13516
13517 if (!empty($footer)) {
13518 $out .= '<div class="timeline-footer">'.$footer.'</div>';
13519 }
13520
13521 $out .= '</div>'."\n"; // end timeline-item
13522
13523 $out .= '</li>';
13524 $out .= '<!-- END timeline item -->';
13525
13526 $i++;
13527 }
13528
13529 $out .= "</ul>\n";
13530
13531 $out .= '<script>
13532 jQuery(document).ready(function () {
13533 $(document).on("click", "[data-read-more-action]", function(e){
13534 let readMoreBloc = $(this).closest(".readmore-block");
13535 if(readMoreBloc.length > 0){
13536 e.preventDefault();
13537 if($(this).attr("data-read-more-action") == "close"){
13538 readMoreBloc.addClass("--closed").removeClass("--open");
13539 $("html, body").animate({
13540 scrollTop: readMoreBloc.offset().top - 200
13541 }, 100);
13542 }else{
13543 readMoreBloc.addClass("--open").removeClass("--closed");
13544 }
13545 }
13546 });
13547 });
13548 </script>';
13549
13550
13551 if (empty($histo)) {
13552 $out .= '<span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span>';
13553 }
13554 }
13555
13556 if ($noprint) {
13557 return $out;
13558 } else {
13559 print $out;
13560 }
13561}
13562
13573function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto')
13574{
13575 if ($hourTime === 'getpost') {
13576 $hour = GETPOSTINT($prefix . 'hour');
13577 $minute = GETPOSTINT($prefix . 'minute');
13578 $second = GETPOSTINT($prefix . 'second');
13579 } elseif (preg_match('/^(\d\d):(\d\d):(\d\d)$/', $hourTime, $m)) {
13580 $hour = intval($m[1]);
13581 $minute = intval($m[2]);
13582 $second = intval($m[3]);
13583 } else {
13584 $hour = $minute = $second = 0;
13585 }
13586 // normalize out of range values
13587 $hour = min($hour, 23);
13588 $minute = min($minute, 59);
13589 $second = min($second, 59);
13590 return dol_mktime($hour, $minute, $second, GETPOSTINT($prefix . 'month'), GETPOSTINT($prefix . 'day'), GETPOSTINT($prefix . 'year'), $gm);
13591}
13592
13604function buildParamDate($prefix, $timestamp = null, $hourTime = '', $gm = 'auto')
13605{
13606 if ($timestamp === null) {
13607 $timestamp = GETPOSTDATE($prefix, $hourTime, $gm);
13608 }
13609 $TParam = array(
13610 $prefix . 'day' => intval(dol_print_date($timestamp, '%d')),
13611 $prefix . 'month' => intval(dol_print_date($timestamp, '%m')),
13612 $prefix . 'year' => intval(dol_print_date($timestamp, '%Y')),
13613 );
13614 if ($hourTime === 'getpost' || ($timestamp !== null && dol_print_date($timestamp, '%H:%M:%S') !== '00:00:00')) {
13615 $TParam = array_merge($TParam, array(
13616 $prefix . 'hour' => intval(dol_print_date($timestamp, '%H')),
13617 $prefix . 'minute' => intval(dol_print_date($timestamp, '%M')),
13618 $prefix . 'second' => intval(dol_print_date($timestamp, '%S'))
13619 ));
13620 }
13621
13622 return '&' . http_build_query($TParam);
13623}
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.
finishSimpleTable($addLineBreak=false)
Add the correct HTML close tags for "startSimpleTable(...)" (use after the last table line)
startSimpleTable($header, $link="", $arguments="", $emptyRows=0, $number=-1)
Start a table with headers and a optinal clickable number (don't forget to use "finishSimpleTable()" ...
getLanguageCodeFromCountryCode($countrycode)
Return default language from country code.
setEntity($currentobject)
Set entity id to use when to create an object.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks=array())
Show social network link.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
dol_ucfirst($string, $encoding="UTF-8")
Convert first character of the first word of a string to upper.
img_right($titlealt='default', $selected=0, $moreatt='')
Show right arrow logo.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
dol_strtolower($string, $encoding="UTF-8")
Convert a string to lower.
showValueWithClipboardCPButton($valuetocopy, $showonlyonhover=1, $texttoshow='')
Create a button to copy $valuetocopy in the clipboard (for copy and paste feature).
dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto='UTF-8')
This function is called to decode a HTML string (it decodes entities and br tags)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_left($titlealt='default', $selected=0, $moreatt='')
Show left arrow logo.
dol_print_ip($ip, $mode=0)
Return an IP formated to be shown on screen.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
GETPOSTINT($paramname, $method=0)
Return value of a param into GET or POST supervariable.
isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
Function to test if an entry is enabled or not.
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
getDolUserInt($key, $default=0, $tmpuser=null)
Return Dolibarr user constant int value.
yn($yesno, $case=1, $color=0)
Return yes or no in current language.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dolPrintHTML($s, $allowiframe=0)
Return a string ready to be output on HTML page To use text inside an attribute, you can simply use d...
isASecretKey($keyname)
Return if string has a name dedicated to store a secret.
dolPrintHTMLForTextArea($s, $allowiframe=0)
Return a string ready to be output on input textarea To use text inside an attribute,...
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
print_fleche_navigation($page, $file, $options='', $nextpage=0, $betweenarrows='', $afterarrows='', $limit=-1, $totalnboflines=0, $hideselectlimit=0, $beforearrows='', $hidenavigation=0)
Function to show navigation arrows into lists.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
get_date_range($date_start, $date_end, $format='', $outputlangs='', $withparenthesis=1)
Format output for start and end date.
get_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Get formated error messages to output (Used to show messages on html output).
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
roundUpToNextMultiple($n, $x=5)
Round to next multiple.
dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled='', $morecss='classlink button bordertransp', $jsonopen='', $backtopagejsfields='', $accesskey='')
Return HTML code to output a button to open a dialog popup box.
dol_user_country()
Return country code for current user.
dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes=null)
Clean a string from some undesirable HTML tags.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_format_address($object, $withcountry=0, $sep="\n", $outputlangs='', $mode=0, $extralangcode='')
Return a formated address (part address/zip/town/state) according to country rules.
isHTTPS()
Return if we are using a HTTPS connexion Check HTTPS (no way to be modified by user but may be empty ...
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
picto_required()
Return picto saying a field is required.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
img_action($titlealt, $numaction, $picto='', $moreatt='')
Show logo action.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0)
Set event message in dol_events session object.
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
GETPOSTDATE($prefix, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
printCommonFooter($zone='private')
Print common footer : conf->global->MAIN_HTML_FOOTER js for switch of menu hider js for conf->global-...
checkVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
img_down($titlealt='default', $selected=0, $moreclass='')
Show down arrow logo.
getTaxesFromId($vatrate, $buyer=null, $seller=null, $firstparamisid=1)
Get tax (VAT) main information from Id.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
utf8_valid($str)
Check if a string is in UTF8.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
getDolUserString($key, $default='', $tmpuser=null)
Return Dolibarr user constant string value.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
img_allow($allow, $titlealt='default')
Show tick logo if allowed.
isValidMXRecord($domain)
Return if the domain name has a valid MX record.
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
get_htmloutput_mesg($mesgstring='', $mesgarray='', $style='ok', $keepembedded=0)
Get formated messages to output (Used to show messages on html output).
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0)
Format phone numbers according to country.
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
dol_fiche_head($links=array(), $active='0', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tab header of a card.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
get_localtax_by_third($local)
Get values of localtaxes (1 or 2) for company country for the common vat with the highest value.
dol_escape_php($stringtoescape, $stringforquotes=2)
Returns text escaped for inclusion into a php string, build with double quotes " or '.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0)
Clean a string to keep only desirable HTML tags.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
ajax_autoselect($htmlname, $addlink='', $textonlink='Link')
Make content of an input box selected when we click into input field.
img_view($titlealt='default', $float=0, $other='class="valignmiddle"')
Show logo view card.
dolPrintHTMLForAttribute($s)
Return a string ready to be output on an HTML attribute (alt, title, data-html, .....
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_eval($s, $returnvalue=0, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_strftime($fmt, $ts=false, $is_gmt=false)
Format a string.
img_picto_common($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $notitle=0)
Show picto (generic function)
img_search($titlealt='default', $other='')
Show search logo.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
isValidPhone($phone)
Return true if phone number syntax is ok TODO Decide what to do with this.
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
img_previous($titlealt='default', $moreatt='')
Show previous logo.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
fieldLabel($langkey, $fieldkey, $fieldrequired=0)
Show a string with the label tag dedicated to the HTML edit field.
getBrowserInfo($user_agent)
Return information about user browser.
dolGetFirstLetters($s, $nbofchar=1)
Return first letters of a strings.
dol_strtoupper($string, $encoding="UTF-8")
Convert a string to upper.
dol_sanitizeUrl($stringtoclean, $type=1)
Clean a string to use it as an URL (into a href or src attribute)
img_printer($titlealt="default", $other='')
Show printer logo.
dol_htmloutput_events($disabledoutputofmessages=0)
Print formated messages to output (Used to show messages on html output).
getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $disablesortlink=0, $tooltip='', $forcenowrapcolumntitle=0)
Get title line of an array.
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
ascii_check($str)
Check if a string is in ASCII.
getPictoForType($key)
Return the picto for a data type.
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
getArrayOfSocialNetworks()
Get array of social network dictionary.
dolGetButtonTitleSeparator($moreClass="")
Add space between dolGetButtonTitle.
num2Alpha($n)
Return a numeric value into an Excel like column number.
dol_size($size, $type='')
Optimize a size for some browsers (phone, smarphone, ...)
img_split($titlealt='default', $other='class="pictosplit"')
Show split logo.
img_pdf($titlealt='default', $size=3)
Show pdf logo.
dolGetCountryCodeFromIp($ip)
Return a country code from IP.
dol_textishtml($msg, $option=0)
Return if a text is a html content.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolPrintPassword($s)
Return a string ready to be output on an HTML attribute (alt, title, ...)
colorIsLight($stringcolor)
Return true if the color is light.
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:1926
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