dolibarr 19.0.4
functions.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2000-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2003 Jean-Louis Bergamo <jlb@j1b.org>
4 * Copyright (C) 2004-2022 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
7 * Copyright (C) 2004 Christophe Combelles <ccomb@free.fr>
8 * Copyright (C) 2005-2019 Regis Houssin <regis.houssin@inodbox.com>
9 * Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr>
10 * Copyright (C) 2010-2018 Juanjo Menent <jmenent@2byte.es>
11 * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
12 * Copyright (C) 2013-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
13 * Copyright (C) 2014 Cédric GROSS <c.gross@kreiz-it.fr>
14 * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
15 * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
16 * Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
17 * Copyright (C) 2019-2023 Thibault Foucart <support@ptibogxiv.net>
18 * Copyright (C) 2020 Open-Dsi <support@open-dsi.fr>
19 * Copyright (C) 2021 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
20 * Copyright (C) 2022 Anthony Berton <anthony.berton@bb2a.fr>
21 * Copyright (C) 2022 Ferran Marcet <fmarcet@2byte.es>
22 * Copyright (C) 2022 Charlene Benke <charlene@patas-monkey.com>
23 * Copyright (C) 2023-2024 Joachim Kueter <git-jk@bloxera.com>
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 3 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program. If not, see <https://www.gnu.org/licenses/>.
37 * or see https://www.gnu.org/
38 */
39
46include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
47
48// Function for better PHP x compatibility
49if (!function_exists('utf8_encode')) {
56 function utf8_encode($elements)
57 {
58 return mb_convert_encoding($elements, 'UTF-8', 'ISO-8859-1');
59 }
60}
61
62if (!function_exists('utf8_decode')) {
69 function utf8_decode($elements)
70 {
71 return mb_convert_encoding($elements, 'ISO-8859-1', 'UTF-8');
72 }
73}
74if (!function_exists('str_starts_with')) {
82 function str_starts_with($haystack, $needle)
83 {
84 return (string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0;
85 }
86}
87if (!function_exists('str_ends_with')) {
95 function str_ends_with($haystack, $needle)
96 {
97 return $needle !== '' && substr($haystack, -strlen($needle)) === (string) $needle;
98 }
99}
100if (!function_exists('str_contains')) {
108 function str_contains($haystack, $needle)
109 {
110 return $needle !== '' && mb_strpos($haystack, $needle) !== false;
111 }
112}
113
114
123function getMultidirOutput($object, $module = '')
124{
125 global $conf;
126
127 if (!is_object($object) && empty($module)) {
128 return null;
129 }
130 if (empty($module) && !empty($object->element)) {
131 $module = $object->element;
132 }
133 // Special case for backward compatibility
134 if ($module == 'fichinter') {
135 $module = 'ficheinter';
136 }
137 if (isset($conf->$module) && property_exists($conf->$module, 'multidir_output')) {
138 return $conf->$module->multidir_output[(empty($object->entity) ? $conf->entity : $object->entity)];
139 } else {
140 return 'error-diroutput-not-defined-for-this-object='.$module;
141 }
142}
143
151function getDolGlobalString($key, $default = '')
152{
153 global $conf;
154 return (string) (isset($conf->global->$key) ? $conf->global->$key : $default);
155}
156
165function getDolGlobalInt($key, $default = 0)
166{
167 global $conf;
168 return (int) (isset($conf->global->$key) ? $conf->global->$key : $default);
169}
170
179function getDolUserString($key, $default = '', $tmpuser = null)
180{
181 if (empty($tmpuser)) {
182 global $user;
183 $tmpuser = $user;
184 }
185
186 return (string) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
187}
188
197function getDolUserInt($key, $default = 0, $tmpuser = null)
198{
199 if (empty($tmpuser)) {
200 global $user;
201 $tmpuser = $user;
202 }
203
204 return (int) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
205}
206
213function isModEnabled($module)
214{
215 global $conf;
216
217 // Fix special cases
218 $arrayconv = array(
219 'bank' => 'banque',
220 'category' => 'categorie',
221 'contract' => 'contrat',
222 'project' => 'projet',
223 'delivery_note' => 'expedition'
224 );
225 if (!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD')) {
226 $arrayconv['supplier_order'] = 'fournisseur';
227 $arrayconv['supplier_invoice'] = 'fournisseur';
228 }
229 if (!empty($arrayconv[$module])) {
230 $module = $arrayconv[$module];
231 }
232
233 return !empty($conf->modules[$module]);
234 //return !empty($conf->$module->enabled);
235}
236
248function getDoliDBInstance($type, $host, $user, $pass, $name, $port)
249{
250 require_once DOL_DOCUMENT_ROOT."/core/db/".$type.'.class.php';
251
252 $class = 'DoliDB'.ucfirst($type);
253 $dolidb = new $class($type, $host, $user, $pass, $name, $port);
254 return $dolidb;
255}
256
274function getEntity($element, $shared = 1, $currentobject = null)
275{
276 global $conf, $mc, $hookmanager, $object, $action, $db;
277
278 if (!is_object($hookmanager)) {
279 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
280 $hookmanager = new HookManager($db);
281 }
282
283 // fix different element names (France to English)
284 switch ($element) {
285 case 'projet':
286 $element = 'project';
287 break;
288 case 'contrat':
289 $element = 'contract';
290 break; // "/contrat/class/contrat.class.php"
291 case 'order_supplier':
292 $element = 'supplier_order';
293 break; // "/fourn/class/fournisseur.commande.class.php"
294 case 'invoice_supplier':
295 $element = 'supplier_invoice';
296 break; // "/fourn/class/fournisseur.facture.class.php"
297 }
298
299 if (is_object($mc)) {
300 $out = $mc->getEntity($element, $shared, $currentobject);
301 } else {
302 $out = '';
303 $addzero = array('user', 'usergroup', 'cronjob', 'c_email_templates', 'email_template', 'default_values', 'overwrite_trans');
304 if (in_array($element, $addzero)) {
305 $out .= '0,';
306 }
307 $out .= ((int) $conf->entity);
308 }
309
310 // Manipulate entities to query on the fly
311 $parameters = array(
312 'element' => $element,
313 'shared' => $shared,
314 'object' => $object,
315 'currentobject' => $currentobject,
316 'out' => $out
317 );
318 $reshook = $hookmanager->executeHooks('hookGetEntity', $parameters, $currentobject, $action); // Note that $action and $object may have been modified by some hooks
319
320 if (is_numeric($reshook)) {
321 if ($reshook == 0 && !empty($hookmanager->resPrint)) {
322 $out .= ','.$hookmanager->resPrint; // add
323 } elseif ($reshook == 1) {
324 $out = $hookmanager->resPrint; // replace
325 }
326 }
327
328 return $out;
329}
330
337function setEntity($currentobject)
338{
339 global $conf, $mc;
340
341 if (is_object($mc) && method_exists($mc, 'setEntity')) {
342 return $mc->setEntity($currentobject);
343 } else {
344 return ((is_object($currentobject) && $currentobject->id > 0 && $currentobject->entity > 0) ? $currentobject->entity : $conf->entity);
345 }
346}
347
354function isASecretKey($keyname)
355{
356 return preg_match('/(_pass|password|_pw|_key|securekey|serverkey|secret\d?|p12key|exportkey|_PW_[a-z]+|token)$/i', $keyname);
357}
358
359
366function num2Alpha($n)
367{
368 for ($r = ""; $n >= 0; $n = intval($n / 26) - 1) {
369 $r = chr($n % 26 + 0x41) . $r;
370 }
371 return $r;
372}
373
374
391function getBrowserInfo($user_agent)
392{
393 include_once DOL_DOCUMENT_ROOT.'/includes/mobiledetect/mobiledetectlib/Mobile_Detect.php';
394
395 $name = 'unknown';
396 $version = '';
397 $os = 'unknown';
398 $phone = '';
399
400 $user_agent = substr($user_agent, 0, 512); // Avoid to process too large user agent
401
402 $detectmobile = new Mobile_Detect(null, $user_agent);
403 $tablet = $detectmobile->isTablet();
404
405 if ($detectmobile->isMobile()) {
406 $phone = 'unknown';
407
408 // If phone/smartphone, we set phone os name.
409 if ($detectmobile->is('AndroidOS')) {
410 $os = $phone = 'android';
411 } elseif ($detectmobile->is('BlackBerryOS')) {
412 $os = $phone = 'blackberry';
413 } elseif ($detectmobile->is('iOS')) {
414 $os = 'ios';
415 $phone = 'iphone';
416 } elseif ($detectmobile->is('PalmOS')) {
417 $os = $phone = 'palm';
418 } elseif ($detectmobile->is('SymbianOS')) {
419 $os = 'symbian';
420 } elseif ($detectmobile->is('webOS')) {
421 $os = 'webos';
422 } elseif ($detectmobile->is('MaemoOS')) {
423 $os = 'maemo';
424 } elseif ($detectmobile->is('WindowsMobileOS') || $detectmobile->is('WindowsPhoneOS')) {
425 $os = 'windows';
426 }
427 }
428
429 // OS
430 if (preg_match('/linux/i', $user_agent)) {
431 $os = 'linux';
432 } elseif (preg_match('/macintosh/i', $user_agent)) {
433 $os = 'macintosh';
434 } elseif (preg_match('/windows/i', $user_agent)) {
435 $os = 'windows';
436 }
437
438 // Name
439 $reg = array();
440 if (preg_match('/firefox(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
441 $name = 'firefox';
442 $version = empty($reg[2]) ? '' : $reg[2];
443 } elseif (preg_match('/edge(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
444 $name = 'edge';
445 $version = empty($reg[2]) ? '' : $reg[2];
446 } elseif (preg_match('/chrome(\/|\s)([\d\.]+)/i', $user_agent, $reg)) {
447 $name = 'chrome';
448 $version = empty($reg[2]) ? '' : $reg[2];
449 } elseif (preg_match('/chrome/i', $user_agent, $reg)) {
450 // we can have 'chrome (Mozilla...) chrome x.y' in one string
451 $name = 'chrome';
452 } elseif (preg_match('/iceweasel/i', $user_agent)) {
453 $name = 'iceweasel';
454 } elseif (preg_match('/epiphany/i', $user_agent)) {
455 $name = 'epiphany';
456 } elseif (preg_match('/safari(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
457 $name = 'safari';
458 $version = empty($reg[2]) ? '' : $reg[2];
459 } elseif (preg_match('/opera(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
460 // Safari is often present in string for mobile but its not.
461 $name = 'opera';
462 $version = empty($reg[2]) ? '' : $reg[2];
463 } elseif (preg_match('/(MSIE\s([0-9]+\.[0-9]))|.*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
464 $name = 'ie';
465 $version = end($reg);
466 } elseif (preg_match('/(Windows NT\s([0-9]+\.[0-9])).*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
467 // MS products at end
468 $name = 'ie';
469 $version = end($reg);
470 } elseif (preg_match('/l[iy]n(x|ks)(\‍(|\/|\s)*([\d\.]+)/i', $user_agent, $reg)) {
471 // MS products at end
472 $name = 'lynxlinks';
473 $version = empty($reg[3]) ? '' : $reg[3];
474 }
475
476 if ($tablet) {
477 $layout = 'tablet';
478 } elseif ($phone) {
479 $layout = 'phone';
480 } else {
481 $layout = 'classic';
482 }
483
484 return array(
485 'browsername' => $name,
486 'browserversion' => $version,
487 'browseros' => $os,
488 'browserua' => $user_agent,
489 'layout' => $layout, // tablet, phone, classic
490 'phone' => $phone, // deprecated
491 'tablet' => $tablet // deprecated
492 );
493}
494
500function dol_shutdown()
501{
502 global $db;
503 $disconnectdone = false;
504 $depth = 0;
505 if (is_object($db) && !empty($db->connected)) {
506 $depth = $db->transaction_opened;
507 $disconnectdone = $db->close();
508 }
509 dol_syslog("--- End access to ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]).(($disconnectdone && $depth) ? ' (Warn: db disconnection forced, transaction depth was '.$depth.')' : ''), (($disconnectdone && $depth) ? LOG_WARNING : LOG_INFO));
510}
511
521function GETPOSTISSET($paramname)
522{
523 $isset = false;
524
525 $relativepathstring = $_SERVER["PHP_SELF"];
526 // Clean $relativepathstring
527 if (constant('DOL_URL_ROOT')) {
528 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
529 }
530 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
531 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
532 //var_dump($relativepathstring);
533 //var_dump($user->default_values);
534
535 // Code for search criteria persistence.
536 // Retrieve values if restore_lastsearch_values
537 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
538 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
539 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
540 if (is_array($tmp)) {
541 foreach ($tmp as $key => $val) {
542 if ($key == $paramname) { // We are on the requested parameter
543 $isset = true;
544 break;
545 }
546 }
547 }
548 }
549 // If there is saved contextpage, limit, page or mode
550 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
551 $isset = true;
552 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
553 $isset = true;
554 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
555 $isset = true;
556 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
557 $isset = true;
558 }
559 } else {
560 $isset = (isset($_POST[$paramname]) || isset($_GET[$paramname])); // We must keep $_POST and $_GET here
561 }
562
563 return $isset;
564}
565
574function GETPOSTISARRAY($paramname, $method = 0)
575{
576 // for $method test need return the same $val as GETPOST
577 if (empty($method)) {
578 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
579 } elseif ($method == 1) {
580 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
581 } elseif ($method == 2) {
582 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
583 } elseif ($method == 3) {
584 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
585 } else {
586 $val = 'BadFirstParameterForGETPOST';
587 }
588
589 return is_array($val);
590}
591
621function GETPOST($paramname, $check = 'alphanohtml', $method = 0, $filter = null, $options = null, $noreplace = 0)
622{
623 global $mysoc, $user, $conf;
624
625 if (empty($paramname)) {
626 return 'BadFirstParameterForGETPOST';
627 }
628 if (empty($check)) {
629 dol_syslog("Deprecated use of GETPOST, called with 1st param = ".$paramname." and a 2nd param that is '', when calling page ".$_SERVER["PHP_SELF"], LOG_WARNING);
630 // Enable this line to know who call the GETPOST with '' $check parameter.
631 //var_dump(debug_backtrace()[0]);
632 }
633
634 if (empty($method)) {
635 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
636 } elseif ($method == 1) {
637 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
638 } elseif ($method == 2) {
639 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
640 } elseif ($method == 3) {
641 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
642 } else {
643 return 'BadThirdParameterForGETPOST';
644 }
645
646 if (empty($method) || $method == 3 || $method == 4) {
647 $relativepathstring = (empty($_SERVER["PHP_SELF"]) ? '' : $_SERVER["PHP_SELF"]);
648 // Clean $relativepathstring
649 if (constant('DOL_URL_ROOT')) {
650 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
651 }
652 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
653 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
654 //var_dump($relativepathstring);
655 //var_dump($user->default_values);
656
657 // Code for search criteria persistence.
658 // Retrieve saved values if restore_lastsearch_values is set
659 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
660 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
661 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
662 if (is_array($tmp)) {
663 foreach ($tmp as $key => $val) {
664 if ($key == $paramname) { // We are on the requested parameter
665 $out = $val;
666 break;
667 }
668 }
669 }
670 }
671 // If there is saved contextpage, page or limit
672 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
673 $out = $_SESSION['lastsearch_contextpage_'.$relativepathstring];
674 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
675 $out = $_SESSION['lastsearch_limit_'.$relativepathstring];
676 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
677 $out = $_SESSION['lastsearch_page_'.$relativepathstring];
678 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
679 $out = $_SESSION['lastsearch_mode_'.$relativepathstring];
680 }
681 } elseif (!isset($_GET['sortfield'])) {
682 // Else, retrieve default values if we are not doing a sort
683 // If we did a click on a field to sort, we do no apply default values. Same if option MAIN_ENABLE_DEFAULT_VALUES is not set
684 if (!empty($_GET['action']) && $_GET['action'] == 'create' && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
685 // Search default value from $object->field
686 global $object;
687 if (is_object($object) && isset($object->fields[$paramname]['default'])) {
688 $out = $object->fields[$paramname]['default'];
689 }
690 }
691 if (getDolGlobalString('MAIN_ENABLE_DEFAULT_VALUES')) {
692 if (!empty($_GET['action']) && (preg_match('/^create/', $_GET['action']) || preg_match('/^presend/', $_GET['action'])) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
693 // Now search in setup to overwrite default values
694 if (!empty($user->default_values)) { // $user->default_values defined from menu 'Setup - Default values'
695 if (isset($user->default_values[$relativepathstring]['createform'])) {
696 foreach ($user->default_values[$relativepathstring]['createform'] as $defkey => $defval) {
697 $qualified = 0;
698 if ($defkey != '_noquery_') {
699 $tmpqueryarraytohave = explode('&', $defkey);
700 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
701 $foundintru = 0;
702 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
703 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
704 $foundintru = 1;
705 }
706 }
707 if (!$foundintru) {
708 $qualified = 1;
709 }
710 //var_dump($defkey.'-'.$qualified);
711 } else {
712 $qualified = 1;
713 }
714
715 if ($qualified) {
716 if (isset($user->default_values[$relativepathstring]['createform'][$defkey][$paramname])) {
717 $out = $user->default_values[$relativepathstring]['createform'][$defkey][$paramname];
718 break;
719 }
720 }
721 }
722 }
723 }
724 } elseif (!empty($paramname) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
725 // Management of default search_filters and sort order
726 if (!empty($user->default_values)) {
727 // $user->default_values defined from menu 'Setup - Default values'
728 //var_dump($user->default_values[$relativepathstring]);
729 if ($paramname == 'sortfield' || $paramname == 'sortorder') {
730 // Sorted on which fields ? ASC or DESC ?
731 if (isset($user->default_values[$relativepathstring]['sortorder'])) {
732 // Even if paramname is sortfield, data are stored into ['sortorder...']
733 foreach ($user->default_values[$relativepathstring]['sortorder'] as $defkey => $defval) {
734 $qualified = 0;
735 if ($defkey != '_noquery_') {
736 $tmpqueryarraytohave = explode('&', $defkey);
737 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
738 $foundintru = 0;
739 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
740 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
741 $foundintru = 1;
742 }
743 }
744 if (!$foundintru) {
745 $qualified = 1;
746 }
747 //var_dump($defkey.'-'.$qualified);
748 } else {
749 $qualified = 1;
750 }
751
752 if ($qualified) {
753 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
754 foreach ($user->default_values[$relativepathstring]['sortorder'][$defkey] as $key => $val) {
755 if ($out) {
756 $out .= ', ';
757 }
758 if ($paramname == 'sortfield') {
759 $out .= dol_string_nospecial($key, '', $forbidden_chars_to_replace);
760 }
761 if ($paramname == 'sortorder') {
762 $out .= dol_string_nospecial($val, '', $forbidden_chars_to_replace);
763 }
764 }
765 //break; // No break for sortfield and sortorder so we can cumulate fields (is it realy usefull ?)
766 }
767 }
768 }
769 } elseif (isset($user->default_values[$relativepathstring]['filters'])) {
770 foreach ($user->default_values[$relativepathstring]['filters'] as $defkey => $defval) { // $defkey is a querystring like 'a=b&c=d', $defval is key of user
771 if (!empty($_GET['disabledefaultvalues'])) { // If set of default values has been disabled by a request parameter
772 continue;
773 }
774 $qualified = 0;
775 if ($defkey != '_noquery_') {
776 $tmpqueryarraytohave = explode('&', $defkey);
777 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
778 $foundintru = 0;
779 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
780 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
781 $foundintru = 1;
782 }
783 }
784 if (!$foundintru) {
785 $qualified = 1;
786 }
787 //var_dump($defkey.'-'.$qualified);
788 } else {
789 $qualified = 1;
790 }
791
792 if ($qualified && isset($user->default_values[$relativepathstring]['filters'][$defkey][$paramname])) {
793 // We must keep $_POST and $_GET here
794 if (isset($_POST['sall']) || isset($_POST['search_all']) || isset($_GET['sall']) || isset($_GET['search_all'])) {
795 // We made a search from quick search menu, do we still use default filter ?
796 if (!getDolGlobalString('MAIN_DISABLE_DEFAULT_FILTER_FOR_QUICK_SEARCH')) {
797 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
798 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
799 }
800 } else {
801 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
802 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
803 }
804 break;
805 }
806 }
807 }
808 }
809 }
810 }
811 }
812 }
813
814 // Substitution variables for GETPOST (used to get final url with variable parameters or final default value, when using variable parameters __XXX__ in the GET URL)
815 // Example of variables: __DAY__, __MONTH__, __YEAR__, __MYCOMPANY_COUNTRY_ID__, __USER_ID__, ...
816 // We do this only if var is a GET. If it is a POST, may be we want to post the text with vars as the setup text.
817 if (!is_array($out) && empty($_POST[$paramname]) && empty($noreplace)) {
818 $reg = array();
819 $maxloop = 20;
820 $loopnb = 0; // Protection against infinite loop
821 while (preg_match('/__([A-Z0-9]+_?[A-Z0-9]+)__/i', $out, $reg) && ($loopnb < $maxloop)) { // Detect '__ABCDEF__' as key 'ABCDEF' and '__ABC_DEF__' as key 'ABC_DEF'. Detection is also correct when 2 vars are side by side.
822 $loopnb++;
823 $newout = '';
824
825 if ($reg[1] == 'DAY') {
826 $tmp = dol_getdate(dol_now(), true);
827 $newout = $tmp['mday'];
828 } elseif ($reg[1] == 'MONTH') {
829 $tmp = dol_getdate(dol_now(), true);
830 $newout = $tmp['mon'];
831 } elseif ($reg[1] == 'YEAR') {
832 $tmp = dol_getdate(dol_now(), true);
833 $newout = $tmp['year'];
834 } elseif ($reg[1] == 'PREVIOUS_DAY') {
835 $tmp = dol_getdate(dol_now(), true);
836 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
837 $newout = $tmp2['day'];
838 } elseif ($reg[1] == 'PREVIOUS_MONTH') {
839 $tmp = dol_getdate(dol_now(), true);
840 $tmp2 = dol_get_prev_month($tmp['mon'], $tmp['year']);
841 $newout = $tmp2['month'];
842 } elseif ($reg[1] == 'PREVIOUS_YEAR') {
843 $tmp = dol_getdate(dol_now(), true);
844 $newout = ($tmp['year'] - 1);
845 } elseif ($reg[1] == 'NEXT_DAY') {
846 $tmp = dol_getdate(dol_now(), true);
847 $tmp2 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
848 $newout = $tmp2['day'];
849 } elseif ($reg[1] == 'NEXT_MONTH') {
850 $tmp = dol_getdate(dol_now(), true);
851 $tmp2 = dol_get_next_month($tmp['mon'], $tmp['year']);
852 $newout = $tmp2['month'];
853 } elseif ($reg[1] == 'NEXT_YEAR') {
854 $tmp = dol_getdate(dol_now(), true);
855 $newout = ($tmp['year'] + 1);
856 } elseif ($reg[1] == 'MYCOMPANY_COUNTRY_ID' || $reg[1] == 'MYCOUNTRY_ID' || $reg[1] == 'MYCOUNTRYID') {
857 $newout = $mysoc->country_id;
858 } elseif ($reg[1] == 'USER_ID' || $reg[1] == 'USERID') {
859 $newout = $user->id;
860 } elseif ($reg[1] == 'USER_SUPERVISOR_ID' || $reg[1] == 'SUPERVISOR_ID' || $reg[1] == 'SUPERVISORID') {
861 $newout = $user->fk_user;
862 } elseif ($reg[1] == 'ENTITY_ID' || $reg[1] == 'ENTITYID') {
863 $newout = $conf->entity;
864 } else {
865 $newout = ''; // Key not found, we replace with empty string
866 }
867 //var_dump('__'.$reg[1].'__ -> '.$newout);
868 $out = preg_replace('/__'.preg_quote($reg[1], '/').'__/', $newout, $out);
869 }
870 }
871
872 // Check type of variable and make sanitization according to this
873 if (preg_match('/^array/', $check)) { // If 'array' or 'array:restricthtml' or 'array:aZ09' or 'array:intcomma'
874 if (!is_array($out) || empty($out)) {
875 $out = array();
876 } else {
877 $tmparray = explode(':', $check);
878 if (!empty($tmparray[1])) {
879 $tmpcheck = $tmparray[1];
880 } else {
881 $tmpcheck = 'alphanohtml';
882 }
883 foreach ($out as $outkey => $outval) {
884 $out[$outkey] = sanitizeVal($outval, $tmpcheck, $filter, $options);
885 }
886 }
887 } else {
888 // If field name is 'search_xxx' then we force the add of space after each < and > (when following char is numeric) because it means
889 // we use the < or > to make a search on a numeric value to do higher or lower so we can add a space to break html tags
890 if (strpos($paramname, 'search_') === 0) {
891 $out = preg_replace('/([<>])([-+]?\d)/', '\1 \2', $out);
892 }
893
894 $out = sanitizeVal($out, $check, $filter, $options);
895 }
896
897 // Sanitizing for special parameters.
898 // Note: There is no reason to allow the backtopage, backtolist or backtourl parameter to contains an external URL. Only relative URLs are allowed.
899 if ($paramname == 'backtopage' || $paramname == 'backtolist' || $paramname == 'backtourl') {
900 $out = str_replace('\\', '/', $out); // Can be before the loop because only 1 char is replaced. No risk to get it after other replacements.
901 $out = str_replace(array(':', ';', '@', "\t", ' '), '', $out); // Can be before the loop because only 1 char is replaced. No risk to retreive it after other replacements.
902 do {
903 $oldstringtoclean = $out;
904 $out = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $out);
905 $out = preg_replace(array('/^[^\?]*%/'), '', $out); // We remove any % chars before the ?. Example in url: '/product/stock/card.php?action=create&backtopage=%2Fdolibarr_dev%2Fhtdocs%2Fpro%25duct%2Fcard.php%3Fid%3Dabc'
906 $out = preg_replace(array('/^[a-z]*\/\s*\/+/i'), '', $out); // We remove schema*// to remove external URL
907 } while ($oldstringtoclean != $out);
908 }
909
910 // Code for search criteria persistence.
911 // Save data into session if key start with 'search_' or is 'smonth', 'syear', 'month', 'year'
912 if (empty($method) || $method == 3 || $method == 4) {
913 if (preg_match('/^search_/', $paramname) || in_array($paramname, array('sortorder', 'sortfield'))) {
914 //var_dump($paramname.' - '.$out.' '.$user->default_values[$relativepathstring]['filters'][$paramname]);
915
916 // We save search key only if $out not empty that means:
917 // - posted value not empty, or
918 // - if posted value is empty and a default value exists that is not empty (it means we did a filter to an empty value when default was not).
919
920 if ($out != '' && isset($user)) {// $out = '0' or 'abc', it is a search criteria to keep
921 $user->lastsearch_values_tmp[$relativepathstring][$paramname] = $out;
922 }
923 }
924 }
925
926 return $out;
927}
928
938function GETPOSTINT($paramname, $method = 0)
939{
940 return (int) GETPOST($paramname, 'int', $method, null, null, 0);
941}
942
943
954function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
955{
956 return sanitizeVal($out, $check, $filter, $options);
957}
958
968function sanitizeVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
969{
970 // TODO : use class "Validate" to perform tests (and add missing tests) if needed for factorize
971 // Check is done after replacement
972 switch ($check) {
973 case 'none':
974 break;
975 case 'int': // Check param is a numeric value (integer but also float or hexadecimal)
976 if (!is_numeric($out)) {
977 $out = '';
978 }
979 break;
980 case 'intcomma':
981 if (is_array($out)) {
982 $out = implode(',', $out);
983 }
984 if (preg_match('/[^0-9,-]+/i', $out)) {
985 $out = '';
986 }
987 break;
988 case 'san_alpha':
989 $out = filter_var($out, FILTER_SANITIZE_STRING);
990 break;
991 case 'email':
992 $out = filter_var($out, FILTER_SANITIZE_EMAIL);
993 break;
994 case 'aZ':
995 if (!is_array($out)) {
996 $out = trim($out);
997 if (preg_match('/[^a-z]+/i', $out)) {
998 $out = '';
999 }
1000 }
1001 break;
1002 case 'aZ09':
1003 if (!is_array($out)) {
1004 $out = trim($out);
1005 if (preg_match('/[^a-z0-9_\-\.]+/i', $out)) {
1006 $out = '';
1007 }
1008 }
1009 break;
1010 case 'aZ09arobase': // great to sanitize $objecttype parameter
1011 if (!is_array($out)) {
1012 $out = trim($out);
1013 if (preg_match('/[^a-z0-9_\-\.@]+/i', $out)) {
1014 $out = '';
1015 }
1016 }
1017 break;
1018 case 'aZ09comma': // great to sanitize $sortfield or $sortorder params that can be 't.abc,t.def_gh'
1019 if (!is_array($out)) {
1020 $out = trim($out);
1021 if (preg_match('/[^a-z0-9_\-\.,]+/i', $out)) {
1022 $out = '';
1023 }
1024 }
1025 break;
1026 case 'alpha': // No html and no ../ and "
1027 case 'alphanohtml': // Recommended for most scalar parameters and search parameters
1028 if (!is_array($out)) {
1029 $out = trim($out);
1030 do {
1031 $oldstringtoclean = $out;
1032 // Remove html tags
1033 $out = dol_string_nohtmltag($out, 0);
1034 // Remove also other dangerous string sequences
1035 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1036 // '../' or '..\' is dangerous because it allows dir transversals
1037 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1038 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1039 } while ($oldstringtoclean != $out);
1040 // keep lines feed
1041 }
1042 break;
1043 case 'alphawithlgt': // No " and no ../ but we keep balanced < > tags with no special chars inside. Can be used for email string like "Name <email>". Less secured than 'alphanohtml'
1044 if (!is_array($out)) {
1045 $out = trim($out);
1046 do {
1047 $oldstringtoclean = $out;
1048 // Remove html tags
1049 $out = dol_html_entity_decode($out, ENT_COMPAT | ENT_HTML5, 'UTF-8');
1050 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1051 // '../' or '..\' is dangerous because it allows dir transversals
1052 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1053 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1054 } while ($oldstringtoclean != $out);
1055 }
1056 break;
1057 case 'nohtml': // No html
1058 $out = dol_string_nohtmltag($out, 0);
1059 break;
1060 case 'restricthtmlnolink':
1061 case 'restricthtml': // Recommended for most html textarea
1062 case 'restricthtmlallowclass':
1063 case 'restricthtmlallowunvalid':
1064 $out = dol_htmlwithnojs($out, 1, $check);
1065 break;
1066 case 'custom':
1067 if (!empty($out)) {
1068 if (empty($filter)) {
1069 return 'BadParameterForGETPOST - Param 3 of sanitizeVal()';
1070 }
1071 /*if (empty($options)) {
1072 return 'BadParameterForGETPOST - Param 4 of sanitizeVal()';
1073 }*/
1074 $out = filter_var($out, $filter, $options);
1075 }
1076 break;
1077 default:
1078 dol_syslog("Error, you call sanitizeVal() with a bad value for the check type. Data can't be sanitized.", LOG_ERR);
1079 break;
1080 }
1081
1082 return $out;
1083}
1084
1085
1086if (!function_exists('dol_getprefix')) {
1096 function dol_getprefix($mode = '')
1097 {
1098 // If prefix is for email (we need to have $conf already loaded for this case)
1099 if ($mode == 'email') {
1100 global $conf;
1101
1102 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID')) { // If MAIL_PREFIX_FOR_EMAIL_ID is set
1103 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID') != 'SERVER_NAME') {
1104 return $conf->global->MAIL_PREFIX_FOR_EMAIL_ID;
1105 } elseif (isset($_SERVER["SERVER_NAME"])) { // If MAIL_PREFIX_FOR_EMAIL_ID is set to 'SERVER_NAME'
1106 return $_SERVER["SERVER_NAME"];
1107 }
1108 }
1109
1110 // The recommended value if MAIL_PREFIX_FOR_EMAIL_ID is not defined (may be not defined for old versions)
1111 if (!empty($conf->file->instance_unique_id)) {
1112 return sha1('dolibarr'.$conf->file->instance_unique_id);
1113 }
1114
1115 // For backward compatibility when instance_unique_id is not set
1116 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1117 }
1118
1119 // If prefix is for session (no need to have $conf loaded)
1120 global $dolibarr_main_instance_unique_id, $dolibarr_main_cookie_cryptkey; // This is loaded by filefunc.inc.php
1121 $tmp_instance_unique_id = empty($dolibarr_main_instance_unique_id) ? (empty($dolibarr_main_cookie_cryptkey) ? '' : $dolibarr_main_cookie_cryptkey) : $dolibarr_main_instance_unique_id; // Unique id of instance
1122
1123 // The recommended value (may be not defined for old versions)
1124 if (!empty($tmp_instance_unique_id)) {
1125 return sha1('dolibarr'.$tmp_instance_unique_id);
1126 }
1127
1128 // For backward compatibility when instance_unique_id is not set
1129 if (isset($_SERVER["SERVER_NAME"]) && isset($_SERVER["DOCUMENT_ROOT"])) {
1130 return sha1($_SERVER["SERVER_NAME"].$_SERVER["DOCUMENT_ROOT"].DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1131 } else {
1132 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1133 }
1134 }
1135}
1136
1147function dol_include_once($relpath, $classname = '')
1148{
1149 global $conf, $langs, $user, $mysoc; // Do not remove this. They must be defined for files we include. Other globals var must be retrieved with $GLOBALS['var']
1150
1151 $fullpath = dol_buildpath($relpath);
1152
1153 if (!file_exists($fullpath)) {
1154 dol_syslog('functions::dol_include_once Tried to load unexisting file: '.$relpath, LOG_WARNING);
1155 return false;
1156 }
1157
1158 if (!empty($classname) && !class_exists($classname)) {
1159 return include $fullpath;
1160 } else {
1161 return include_once $fullpath;
1162 }
1163}
1164
1165
1176function dol_buildpath($path, $type = 0, $returnemptyifnotfound = 0)
1177{
1178 global $conf;
1179
1180 $path = preg_replace('/^\//', '', $path);
1181
1182 if (empty($type)) { // For a filesystem path
1183 $res = DOL_DOCUMENT_ROOT.'/'.$path; // Standard default path
1184 if (is_array($conf->file->dol_document_root)) {
1185 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array("main"=>"/home/main/htdocs", "alt0"=>"/home/dirmod/htdocs", ...)
1186 if ($key == 'main') {
1187 continue;
1188 }
1189 // if (@file_exists($dirroot.'/'.$path)) {
1190 if (@file_exists($dirroot.'/'.$path)) { // avoid [php:warn]
1191 $res = $dirroot.'/'.$path;
1192 return $res;
1193 }
1194 }
1195 }
1196 if ($returnemptyifnotfound) {
1197 // Not found into alternate dir
1198 if ($returnemptyifnotfound == 1 || !file_exists($res)) {
1199 return '';
1200 }
1201 }
1202 } else {
1203 // For an url path
1204 // We try to get local path of file on filesystem from url
1205 // Note that trying to know if a file on disk exist by forging path on disk from url
1206 // works only for some web server and some setup. This is bugged when
1207 // using proxy, rewriting, virtual path, etc...
1208 $res = '';
1209 if ($type == 1) {
1210 $res = DOL_URL_ROOT.'/'.$path; // Standard value
1211 }
1212 if ($type == 2) {
1213 $res = DOL_MAIN_URL_ROOT.'/'.$path; // Standard value
1214 }
1215 if ($type == 3) {
1216 $res = DOL_URL_ROOT.'/'.$path;
1217 }
1218
1219 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array(["main"]=>"/home/main/htdocs", ["alt0"]=>"/home/dirmod/htdocs", ...)
1220 if ($key == 'main') {
1221 if ($type == 3) {
1222 /*global $dolibarr_main_url_root;*/
1223
1224 // Define $urlwithroot
1225 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1226 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1227 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1228
1229 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).'/'.$path; // Test on start with http is for old conf syntax
1230 }
1231 continue;
1232 }
1233 $regs = array();
1234 preg_match('/^([^\?]+(\.css\.php|\.css|\.js\.php|\.js|\.png|\.jpg|\.php)?)/i', $path, $regs); // Take part before '?'
1235 if (!empty($regs[1])) {
1236 //print $key.'-'.$dirroot.'/'.$path.'-'.$conf->file->dol_url_root[$type].'<br>'."\n";
1237 //if (file_exists($dirroot.'/'.$regs[1])) {
1238 if (@file_exists($dirroot.'/'.$regs[1])) { // avoid [php:warn]
1239 if ($type == 1) {
1240 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1241 }
1242 if ($type == 2) {
1243 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_MAIN_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1244 }
1245 if ($type == 3) {
1246 /*global $dolibarr_main_url_root;*/
1247
1248 // Define $urlwithroot
1249 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1250 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1251 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1252
1253 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).$conf->file->dol_url_root[$key].'/'.$path; // Test on start with http is for old conf syntax
1254 }
1255 break;
1256 }
1257 }
1258 }
1259 }
1260
1261 return $res;
1262}
1263
1275function dol_clone($object, $native = 0)
1276{
1277 if ($native == 0) {
1278 // deprecated method, use the method with native = 2 instead
1279 $tmpsavdb = null;
1280 if (isset($object->db) && isset($object->db->db) && is_object($object->db->db) && get_class($object->db->db) == 'PgSql\Connection') {
1281 $tmpsavdb = $object->db;
1282 unset($object->db); // Such property can not be serialized with pgsl (when object->db->db = 'PgSql\Connection')
1283 }
1284
1285 $myclone = unserialize(serialize($object)); // serialize then unserialize is a hack to be sure to have a new object for all fields
1286
1287 if (!empty($tmpsavdb)) {
1288 $object->db = $tmpsavdb;
1289 }
1290 } elseif ($native == 2) {
1291 // recommended method to have a full isolated cloned object
1292 $myclone = new stdClass();
1293 $tmparray = get_object_vars($object); // return only public properties
1294
1295 if (is_array($tmparray)) {
1296 foreach ($tmparray as $propertykey => $propertyval) {
1297 if (is_scalar($propertyval) || is_array($propertyval)) {
1298 $myclone->$propertykey = $propertyval;
1299 }
1300 }
1301 }
1302 } else {
1303 $myclone = clone $object; // PHP clone is a shallow copy only, not a real clone, so properties of references will keep the reference (refering to the same target/variable)
1304 }
1305
1306 return $myclone;
1307}
1308
1318function dol_size($size, $type = '')
1319{
1320 global $conf;
1321 if (empty($conf->dol_optimize_smallscreen)) {
1322 return $size;
1323 }
1324 if ($type == 'width' && $size > 250) {
1325 return 250;
1326 } else {
1327 return 10;
1328 }
1329}
1330
1331
1343function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1)
1344{
1345 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1346 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1347 // Char '/' and '\' are file delimiters.
1348 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1349 $filesystem_forbidden_chars = array('<', '>', '/', '\\', '?', '*', '|', '"', ':', '°', '$', ';', '`');
1350 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1351 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1352 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1353 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1354 $tmp = str_replace('..', '', $tmp);
1355 return $tmp;
1356}
1357
1369function dol_sanitizePathName($str, $newstr = '_', $unaccent = 1)
1370{
1371 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1372 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1373 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1374 $filesystem_forbidden_chars = array('<', '>', '?', '*', '|', '"', '°', '$', ';', '`');
1375 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1376 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1377 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1378 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1379 $tmp = str_replace('..', '', $tmp);
1380 return $tmp;
1381}
1382
1390function dol_sanitizeUrl($stringtoclean, $type = 1)
1391{
1392 // We clean string because some hacks try to obfuscate evil strings by inserting non printable chars. Example: 'java(ascci09)scr(ascii00)ipt' is processed like 'javascript' (whatever is place of evil ascii char)
1393 // We should use dol_string_nounprintableascii but function may not be yet loaded/available
1394 $stringtoclean = preg_replace('/[\x00-\x1F\x7F]/u', '', $stringtoclean); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1395 // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: on<!-- -->error=alert(1)
1396 $stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
1397
1398 $stringtoclean = str_replace('\\', '/', $stringtoclean);
1399 if ($type == 1) {
1400 // removing : should disable links to external url like http:aaa)
1401 // removing ';' should disable "named" html entities encode into an url (we should not have this into an url)
1402 $stringtoclean = str_replace(array(':', ';', '@'), '', $stringtoclean);
1403 }
1404
1405 do {
1406 $oldstringtoclean = $stringtoclean;
1407 // removing '&colon' should disable links to external url like http:aaa)
1408 // removing '&#' should disable "numeric" html entities encode into an url (we should not have this into an url)
1409 $stringtoclean = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $stringtoclean);
1410 } while ($oldstringtoclean != $stringtoclean);
1411
1412 if ($type == 1) {
1413 // removing '//' should disable links to external url like //aaa or http//)
1414 $stringtoclean = preg_replace(array('/^[a-z]*\/\/+/i'), '', $stringtoclean);
1415 }
1416
1417 return $stringtoclean;
1418}
1419
1426function dol_sanitizeEmail($stringtoclean)
1427{
1428 do {
1429 $oldstringtoclean = $stringtoclean;
1430 $stringtoclean = str_ireplace(array('"', ':', '[', ']',"\n", "\r", '\\', '\/'), '', $stringtoclean);
1431 } while ($oldstringtoclean != $stringtoclean);
1432
1433 return $stringtoclean;
1434}
1435
1445{
1446 global $conf;
1447
1448 if (is_null($str)) {
1449 return '';
1450 }
1451
1452 if (utf8_check($str)) {
1453 if (extension_loaded('intl') && getDolGlobalString('MAIN_UNACCENT_USE_TRANSLITERATOR')) {
1454 $transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: NFC;', Transliterator::FORWARD);
1455 return $transliterator->transliterate($str);
1456 }
1457 // See http://www.utf8-chartable.de/
1458 $string = rawurlencode($str);
1459 $replacements = array(
1460 '%C3%80' => 'A', '%C3%81' => 'A', '%C3%82' => 'A', '%C3%83' => 'A', '%C3%84' => 'A', '%C3%85' => 'A',
1461 '%C3%87' => 'C',
1462 '%C3%88' => 'E', '%C3%89' => 'E', '%C3%8A' => 'E', '%C3%8B' => 'E',
1463 '%C3%8C' => 'I', '%C3%8D' => 'I', '%C3%8E' => 'I', '%C3%8F' => 'I',
1464 '%C3%91' => 'N',
1465 '%C3%92' => 'O', '%C3%93' => 'O', '%C3%94' => 'O', '%C3%95' => 'O', '%C3%96' => 'O',
1466 '%C5%A0' => 'S',
1467 '%C3%99' => 'U', '%C3%9A' => 'U', '%C3%9B' => 'U', '%C3%9C' => 'U',
1468 '%C3%9D' => 'Y', '%C5%B8' => 'y',
1469 '%C3%A0' => 'a', '%C3%A1' => 'a', '%C3%A2' => 'a', '%C3%A3' => 'a', '%C3%A4' => 'a', '%C3%A5' => 'a',
1470 '%C3%A7' => 'c',
1471 '%C3%A8' => 'e', '%C3%A9' => 'e', '%C3%AA' => 'e', '%C3%AB' => 'e',
1472 '%C3%AC' => 'i', '%C3%AD' => 'i', '%C3%AE' => 'i', '%C3%AF' => 'i',
1473 '%C3%B1' => 'n',
1474 '%C3%B2' => 'o', '%C3%B3' => 'o', '%C3%B4' => 'o', '%C3%B5' => 'o', '%C3%B6' => 'o',
1475 '%C5%A1' => 's',
1476 '%C3%B9' => 'u', '%C3%BA' => 'u', '%C3%BB' => 'u', '%C3%BC' => 'u',
1477 '%C3%BD' => 'y', '%C3%BF' => 'y'
1478 );
1479 $string = strtr($string, $replacements);
1480 return rawurldecode($string);
1481 } else {
1482 // See http://www.ascii-code.com/
1483 $string = strtr(
1484 $str,
1485 "\xC0\xC1\xC2\xC3\xC4\xC5\xC7
1486 \xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1
1487 \xD2\xD3\xD4\xD5\xD8\xD9\xDA\xDB\xDD
1488 \xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB
1489 \xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF8
1490 \xF9\xFA\xFB\xFC\xFD\xFF",
1491 "AAAAAAC
1492 EEEEIIIIDN
1493 OOOOOUUUY
1494 aaaaaaceeee
1495 iiiidnooooo
1496 uuuuyy"
1497 );
1498 $string = strtr($string, array("\xC4"=>"Ae", "\xC6"=>"AE", "\xD6"=>"Oe", "\xDC"=>"Ue", "\xDE"=>"TH", "\xDF"=>"ss", "\xE4"=>"ae", "\xE6"=>"ae", "\xF6"=>"oe", "\xFC"=>"ue", "\xFE"=>"th"));
1499 return $string;
1500 }
1501}
1502
1516function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '', $badcharstoremove = '', $keepspaces = 0)
1517{
1518 $forbidden_chars_to_replace = array("'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=", '°', '$', ';'); // more complete than dol_sanitizeFileName
1519 if (empty($keepspaces)) {
1520 $forbidden_chars_to_replace[] = " ";
1521 }
1522 $forbidden_chars_to_remove = array();
1523 //$forbidden_chars_to_remove=array("(",")");
1524
1525 if (is_array($badcharstoreplace)) {
1526 $forbidden_chars_to_replace = $badcharstoreplace;
1527 }
1528 if (is_array($badcharstoremove)) {
1529 $forbidden_chars_to_remove = $badcharstoremove;
1530 }
1531
1532 return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str));
1533}
1534
1535
1549function dol_string_nounprintableascii($str, $removetabcrlf = 1)
1550{
1551 if ($removetabcrlf) {
1552 return preg_replace('/[\x00-\x1F\x7F]/u', '', $str); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1553 } else {
1554 return preg_replace('/[\x00-\x08\x11-\x12\x14-\x1F\x7F]/u', '', $str); // /u operator should make UTF8 valid characters being ignored so are not included into the replace
1555 }
1556}
1557
1566function dol_escape_js($stringtoescape, $mode = 0, $noescapebackslashn = 0)
1567{
1568 if (is_null($stringtoescape)) {
1569 return '';
1570 }
1571
1572 // escape quotes and backslashes, newlines, etc.
1573 $substitjs = array("&#039;"=>"\\'", "\r"=>'\\r');
1574 //$substitjs['</']='<\/'; // We removed this. Should be useless.
1575 if (empty($noescapebackslashn)) {
1576 $substitjs["\n"] = '\\n';
1577 $substitjs['\\'] = '\\\\';
1578 }
1579 if (empty($mode)) {
1580 $substitjs["'"] = "\\'";
1581 $substitjs['"'] = "\\'";
1582 } elseif ($mode == 1) {
1583 $substitjs["'"] = "\\'";
1584 } elseif ($mode == 2) {
1585 $substitjs['"'] = '\\"';
1586 } elseif ($mode == 3) {
1587 $substitjs["'"] = "\\'";
1588 $substitjs['"'] = "\\\"";
1589 }
1590 return strtr($stringtoescape, $substitjs);
1591}
1592
1599function dol_escape_json($stringtoescape)
1600{
1601 return str_replace('"', '\"', $stringtoescape);
1602}
1603
1611function dol_escape_php($stringtoescape, $stringforquotes = 2)
1612{
1613 if (is_null($stringtoescape)) {
1614 return '';
1615 }
1616
1617 if ($stringforquotes == 2) {
1618 return str_replace('"', "'", $stringtoescape);
1619 }
1620 if ($stringforquotes == 1) {
1621 return str_replace("'", "\'", str_replace('"', "'", $stringtoescape));
1622 }
1623
1624 return 'Bad parameter for stringforquotes in dol_escape_php';
1625}
1626
1633function dol_escape_all($stringtoescape)
1634{
1635 return preg_replace('/[^a-z0-9_]/i', '', $stringtoescape);
1636}
1637
1644function dol_escape_xml($stringtoescape)
1645{
1646 return $stringtoescape;
1647}
1648
1656function dolPrintLabel($s)
1657{
1659}
1660
1669function dolPrintHTML($s, $allowiframe = 0)
1670{
1671 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, 'common', 0, 1);
1672}
1673
1681{
1682 // The dol_htmlentitiesbr will convert simple text into html
1683 // The dol_escape_htmltag will escape html chars.
1684 return dol_escape_htmltag(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 0, 0, 0, array('br', 'b', 'font', 'span')), 1, -1, '', 0, 1);
1685}
1686
1695function dolPrintHTMLForTextArea($s, $allowiframe = 0)
1696{
1697 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, '', 0, 1);
1698}
1699
1707{
1708 return htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
1709}
1710
1711
1728function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapetags = '', $escapeonlyhtmltags = 0, $cleanalsojavascript = 0)
1729{
1730 if ($noescapetags == 'common') {
1731 $noescapetags = 'html,body,a,b,em,hr,i,u,ul,li,br,div,img,font,p,span,strong,table,tr,td,th,tbody,h1,h2,h3,h4,h5,h6,h7,h8,h9';
1732 // Add also html5 tags
1733 $noescapetags .= ',header,footer,nav,section,menu,menuitem';
1734 }
1735 if ($cleanalsojavascript) {
1736 $stringtoescape = dol_string_onlythesehtmltags($stringtoescape, 0, 0, $cleanalsojavascript, 0, array(), 0);
1737 }
1738
1739 // escape quotes and backslashes, newlines, etc.
1740 if ($escapeonlyhtmltags) {
1741 $tmp = htmlspecialchars_decode((string) $stringtoescape, ENT_COMPAT);
1742 } else {
1743 $tmp = html_entity_decode((string) $stringtoescape, ENT_COMPAT, 'UTF-8');
1744 }
1745 if (!$keepb) {
1746 $tmp = strtr($tmp, array("<b>"=>'', '</b>'=>'', '<strong>'=>'', '</strong>'=>''));
1747 }
1748 if (!$keepn) {
1749 $tmp = strtr($tmp, array("\r"=>'\\r', "\n"=>'\\n'));
1750 } elseif ($keepn == -1) {
1751 $tmp = strtr($tmp, array("\r"=>'', "\n"=>''));
1752 }
1753
1754 if ($escapeonlyhtmltags) {
1755 return htmlspecialchars($tmp, ENT_COMPAT, 'UTF-8');
1756 } else {
1757 // Escape tags to keep
1758 $tmparrayoftags = array();
1759 if ($noescapetags) {
1760 $tmparrayoftags = explode(',', $noescapetags);
1761 }
1762 if (count($tmparrayoftags)) {
1763 // TODO Does not works yet when there is attributes into tag
1764 foreach ($tmparrayoftags as $tagtoreplace) {
1765 $tmp = str_ireplace('<'.$tagtoreplace.'>', '__BEGINTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1766 $tmp = str_ireplace('</'.$tagtoreplace.'>', '__ENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1767 $tmp = str_ireplace('<'.$tagtoreplace.' />', '__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1768 }
1769 }
1770
1771 $result = htmlentities($tmp, ENT_COMPAT, 'UTF-8');
1772
1773 if (count($tmparrayoftags)) {
1774 foreach ($tmparrayoftags as $tagtoreplace) {
1775 $result = str_ireplace('__BEGINTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.'>', $result);
1776 $result = str_ireplace('__ENDTAGTOREPLACE'.$tagtoreplace.'__', '</'.$tagtoreplace.'>', $result);
1777 $result = str_ireplace('__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.' />', $result);
1778 }
1779 }
1780
1781 return $result;
1782 }
1783}
1784
1792function dol_strtolower($string, $encoding = "UTF-8")
1793{
1794 if (function_exists('mb_strtolower')) {
1795 return mb_strtolower($string, $encoding);
1796 } else {
1797 return strtolower($string);
1798 }
1799}
1800
1809function dol_strtoupper($string, $encoding = "UTF-8")
1810{
1811 if (function_exists('mb_strtoupper')) {
1812 return mb_strtoupper($string, $encoding);
1813 } else {
1814 return strtoupper($string);
1815 }
1816}
1817
1826function dol_ucfirst($string, $encoding = "UTF-8")
1827{
1828 if (function_exists('mb_substr')) {
1829 return mb_strtoupper(mb_substr($string, 0, 1, $encoding), $encoding).mb_substr($string, 1, null, $encoding);
1830 } else {
1831 return ucfirst($string);
1832 }
1833}
1834
1843function dol_ucwords($string, $encoding = "UTF-8")
1844{
1845 if (function_exists('mb_convert_case')) {
1846 return mb_convert_case($string, MB_CASE_TITLE, $encoding);
1847 } else {
1848 return ucwords($string);
1849 }
1850}
1851
1873function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = '', $restricttologhandler = '', $logcontext = null)
1874{
1875 global $conf, $user, $debugbar;
1876
1877 // If syslog module enabled
1878 if (!isModEnabled('syslog')) {
1879 return;
1880 }
1881
1882 // Check if we are into execution of code of a website
1883 if (defined('USEEXTERNALSERVER') && !defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) {
1884 global $website, $websitekey;
1885 if (is_object($website) && !empty($website->ref)) {
1886 $suffixinfilename .= '_website_'.$website->ref;
1887 } elseif (!empty($websitekey)) {
1888 $suffixinfilename .= '_website_'.$websitekey;
1889 }
1890 }
1891
1892 // Check if we have a forced suffix
1893 if (defined('USESUFFIXINLOG')) {
1894 $suffixinfilename .= constant('USESUFFIXINLOG');
1895 }
1896
1897 if ($ident < 0) {
1898 foreach ($conf->loghandlers as $loghandlerinstance) {
1899 $loghandlerinstance->setIdent($ident);
1900 }
1901 }
1902
1903 if (!empty($message)) {
1904 // Test log level
1905 $logLevels = array(LOG_EMERG=>'EMERG', LOG_ALERT=>'ALERT', LOG_CRIT=>'CRITICAL', LOG_ERR=>'ERR', LOG_WARNING=>'WARN', LOG_NOTICE=>'NOTICE', LOG_INFO=>'INFO', LOG_DEBUG=>'DEBUG');
1906
1907 if (!array_key_exists($level, $logLevels)) {
1908 dol_syslog('Error Bad Log Level '.$level, LOG_ERR);
1909 $level = $logLevels[LOG_ERR];
1910 }
1911 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
1912 return;
1913 }
1914
1915 if (!getDolGlobalString('MAIN_SHOW_PASSWORD_INTO_LOG')) {
1916 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
1917 }
1918
1919 // If adding log inside HTML page is required
1920 if ((!empty($_REQUEST['logtohtml']) && getDolGlobalString('MAIN_ENABLE_LOG_TO_HTML'))
1921 || (is_object($user) && $user->hasRight('debugbar', 'read') && is_object($debugbar))) {
1922 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".$logLevels[$level]." ".$message;
1923 }
1924
1925 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
1926 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
1927 if (getDolGlobalString('MAIN_ENABLE_LOG_INLINE_HTML') && !empty($_GET["log"])) {
1928 print "\n\n<!-- Log start\n";
1929 print dol_escape_htmltag($message)."\n";
1930 print "Log end -->\n";
1931 }
1932
1933 $data = array(
1934 'message' => $message,
1935 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
1936 'level' => $level,
1937 'user' => ((is_object($user) && $user->id) ? $user->login : false),
1938 'ip' => false
1939 );
1940
1941 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
1942 if (!empty($remoteip)) {
1943 $data['ip'] = $remoteip;
1944 // This is when server run behind a reverse proxy
1945 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
1946 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
1947 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
1948 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
1949 }
1950 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
1951 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
1952 $data['ip'] = $_SERVER['SERVER_ADDR'];
1953 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
1954 // This is when PHP session is ran outside a web server, like from Windows command line (Not always defined, but useful if OS defined it).
1955 $data['ip'] = $_SERVER['COMPUTERNAME'].(empty($_SERVER['USERNAME']) ? '' : '@'.$_SERVER['USERNAME']);
1956 } elseif (!empty($_SERVER['LOGNAME'])) {
1957 // This is when PHP session is ran outside a web server, like from Linux command line (Not always defined, but usefull if OS defined it).
1958 $data['ip'] = '???@'.$_SERVER['LOGNAME'];
1959 }
1960
1961 // Loop on each log handler and send output
1962 foreach ($conf->loghandlers as $loghandlerinstance) {
1963 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
1964 continue;
1965 }
1966 $loghandlerinstance->export($data, $suffixinfilename);
1967 }
1968 unset($data);
1969 }
1970
1971 if ($ident > 0) {
1972 foreach ($conf->loghandlers as $loghandlerinstance) {
1973 $loghandlerinstance->setIdent($ident);
1974 }
1975 }
1976}
1977
1994function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
1995{
1996 global $conf;
1997
1998 if (strpos($url, '?') > 0) {
1999 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2000 } else {
2001 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2002 }
2003
2004 $out = '';
2005
2006 $backtopagejsfieldsid = '';
2007 $backtopagejsfieldslabel = '';
2008 if ($backtopagejsfields) {
2009 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
2010 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
2011 $backtopagejsfields = $name.":".$backtopagejsfields;
2012 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
2013 } else {
2014 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
2015 }
2016 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
2017 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
2018 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
2019 }
2020
2021 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
2022 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
2023 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
2024 if (empty($conf->use_javascript_ajax)) {
2025 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
2026 } elseif ($jsonopen) {
2027 $out .= ' href="#" onclick="'.$jsonopen.'"';
2028 } else {
2029 $out .= ' href="#"';
2030 }
2031 $out .= '>'.$buttonstring.'</a>';
2032
2033 if (!empty($conf->use_javascript_ajax)) {
2034 // Add code to open url using the popup. Add also hidden field to retreive the returned variables
2035 $out .= '<!-- code to open popup and variables to retreive returned variables -->';
2036 $out .= '<div id="idfordialog'.$name.'" class="hidden">div for dialog</div>';
2037 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">div for returned id</div>';
2038 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">div for returned label</div>';
2039 $out .= '<!-- Add js code to open dialog popup on dialog -->';
2040 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
2041 jQuery(document).ready(function () {
2042 jQuery(".button_'.$name.'").click(function () {
2043 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
2044 var $tmpdialog = $(\'#idfordialog'.$name.'\');
2045 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
2046 $tmpdialog.dialog({
2047 autoOpen: false,
2048 modal: true,
2049 height: (window.innerHeight - 150),
2050 width: \'80%\',
2051 title: \''.dol_escape_js($label).'\',
2052 open: function (event, ui) {
2053 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
2054 },
2055 close: function (event, ui) {
2056 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
2057 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
2058 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
2059 if (returnedid != "" && returnedid != "div for returned id") {
2060 jQuery("#'.(empty($backtopagejsfieldsid) ? "none" : $backtopagejsfieldsid).'").val(returnedid);
2061 }
2062 if (returnedlabel != "" && returnedlabel != "div for returned label") {
2063 jQuery("#'.(empty($backtopagejsfieldslabel) ? "none" : $backtopagejsfieldslabel).'").val(returnedlabel);
2064 }
2065 }
2066 });
2067
2068 $tmpdialog.dialog(\'open\');
2069 return false;
2070 });
2071 });
2072 </script>';
2073 }
2074 return $out;
2075}
2076
2093function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2094{
2095 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2096}
2097
2114function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2115{
2116 global $conf, $langs, $hookmanager;
2117
2118 // Show title
2119 $showtitle = 1;
2120 if (!empty($conf->dol_optimize_smallscreen)) {
2121 $showtitle = 0;
2122 }
2123
2124 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2125
2126 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2127 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2128 }
2129
2130 // Show right part
2131 if ($morehtmlright) {
2132 $out .= '<div class="inline-block floatright tabsElem">'.$morehtmlright.'</div>'; // Output right area first so when space is missing, text is in front of tabs and not under.
2133 }
2134
2135 // Show title
2136 if (!empty($title) && $showtitle && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2137 $limittitle = 30;
2138 $out .= '<a class="tabTitle">';
2139 if ($picto) {
2140 $noprefix = $pictoisfullpath;
2141 if (strpos($picto, 'fontawesome_') !== false) {
2142 $noprefix = 1;
2143 }
2144 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2145 }
2146 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2147 $out .= '</a>';
2148 }
2149
2150 // Show tabs
2151
2152 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2153 $maxkey = -1;
2154 if (is_array($links) && !empty($links)) {
2155 $keys = array_keys($links);
2156 if (count($keys)) {
2157 $maxkey = max($keys);
2158 }
2159 }
2160
2161 // Show tabs
2162 // if =0 we don't use the feature
2163 if (empty($limittoshow)) {
2164 $limittoshow = (!getDolGlobalString('MAIN_MAXTABS_IN_CARD') ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2165 }
2166 if (!empty($conf->dol_optimize_smallscreen)) {
2167 $limittoshow = 2;
2168 }
2169
2170 $displaytab = 0;
2171 $nbintab = 0;
2172 $popuptab = 0;
2173 $outmore = '';
2174 for ($i = 0; $i <= $maxkey; $i++) {
2175 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2176 // If active tab is already present
2177 if ($i >= $limittoshow) {
2178 $limittoshow--;
2179 }
2180 }
2181 }
2182
2183 for ($i = 0; $i <= $maxkey; $i++) {
2184 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2185 $isactive = true;
2186 } else {
2187 $isactive = false;
2188 }
2189
2190 if ($i < $limittoshow || $isactive) {
2191 // Output entry with a visible tab
2192 $out .= '<div class="inline-block tabsElem'.($isactive ? ' tabsElemActive' : '').((!$isactive && getDolGlobalString('MAIN_HIDE_INACTIVETAB_ON_PRINT')) ? ' hideonprint' : '').'"><!-- id tab = '.(empty($links[$i][2]) ? '' : dol_escape_htmltag($links[$i][2])).' -->';
2193
2194 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2195 if (!empty($links[$i][0])) {
2196 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2197 } else {
2198 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2199 }
2200 } elseif (!empty($links[$i][1])) {
2201 //print "x $i $active ".$links[$i][2]." z";
2202 $out .= '<div class="tab tab'.($isactive ? 'active' : 'unactive').'" style="margin: 0 !important">';
2203 if (!empty($links[$i][0])) {
2204 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2205 $out .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="tab inline-block valignmiddle'.($morecss ? ' '.$morecss : '').(!empty($links[$i][5]) ? ' '.$links[$i][5] : '').'" href="'.$links[$i][0].'" title="'.dol_escape_htmltag($titletoshow).'">';
2206 }
2207 $out .= $links[$i][1];
2208 if (!empty($links[$i][0])) {
2209 $out .= '</a>'."\n";
2210 }
2211 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2212 $out .= '</div>';
2213 }
2214
2215 $out .= '</div>';
2216 } else {
2217 // Add entry into the combo popup with the other tabs
2218 if (!$popuptab) {
2219 $popuptab = 1;
2220 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2221 }
2222 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2223 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2224 if (!empty($links[$i][0])) {
2225 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2226 } else {
2227 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2228 }
2229 } elseif (!empty($links[$i][1])) {
2230 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2231 $outmore .= preg_replace('/([a-z])\|([a-z])/i', '\\1 | \\2', $links[$i][1]); // Replace x|y with x | y to allow wrap on long composed texts.
2232 $outmore .= '</a>'."\n";
2233 }
2234 $outmore .= '</div>';
2235
2236 $nbintab++;
2237 }
2238 $displaytab = $i;
2239 }
2240 if ($popuptab) {
2241 $outmore .= '</div>';
2242 }
2243
2244 if ($popuptab) { // If there is some tabs not shown
2245 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2246 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2247 $widthofpopup = 200;
2248
2249 $tabsname = $moretabssuffix;
2250 if (empty($tabsname)) {
2251 $tabsname = str_replace("@", "", $picto);
2252 }
2253 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2254 $out .= '<div class="tab valignmiddle"><a href="#" class="tab moretab inline-block tabunactive valignmiddle"><span class="hideonsmartphone">'.$langs->trans("More").'</span>... ('.$nbintab.')</a></div>'; // Do not use "reposition" class in the "More".
2255 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2256 $out .= $outmore;
2257 $out .= '</div>';
2258 $out .= '<div></div>';
2259 $out .= "</div>\n";
2260
2261 $out .= '<script nonce="'.getNonce().'">';
2262 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2263 var x = this.offsetLeft, y = this.offsetTop;
2264 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2265 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2266 $('#moretabsList".$tabsname."').css('".$right."','8px');
2267 }
2268 $('#moretabsList".$tabsname."').css('".$left."','auto');
2269 });
2270 ";
2271 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2272 $out .= "</script>";
2273 }
2274
2275 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2276 $out .= "</div>\n";
2277 }
2278
2279 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2280 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom'))).'">'."\n";
2281 }
2282 if (!empty($dragdropfile)) {
2283 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2284 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2285 }
2286 $parameters = array('tabname' => $active, 'out' => $out);
2287 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2288 if ($reshook > 0) {
2289 $out = $hookmanager->resPrint;
2290 }
2291
2292 return $out;
2293}
2294
2302function dol_fiche_end($notab = 0)
2303{
2304 print dol_get_fiche_end($notab);
2305}
2306
2313function dol_get_fiche_end($notab = 0)
2314{
2315 if (!$notab || $notab == -1) {
2316 return "\n</div>\n";
2317 } else {
2318 return '';
2319 }
2320}
2321
2341function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2342{
2343 global $conf, $form, $user, $langs, $hookmanager, $action;
2344
2345 $error = 0;
2346
2347 $maxvisiblephotos = 1;
2348 $showimage = 1;
2349 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2350 $showbarcode = empty($conf->barcode->enabled) ? 0 : (empty($object->barcode) ? 0 : 1);
2351 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2352 $showbarcode = 0;
2353 }
2354 $modulepart = 'unknown';
2355
2356 if ($object->element == 'societe' || $object->element == 'contact' || $object->element == 'product' || $object->element == 'ticket') {
2357 $modulepart = $object->element;
2358 } elseif ($object->element == 'member') {
2359 $modulepart = 'memberphoto';
2360 } elseif ($object->element == 'user') {
2361 $modulepart = 'userphoto';
2362 }
2363
2364 if (class_exists("Imagick")) {
2365 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2366 $modulepart = $object->element;
2367 } elseif ($object->element == 'fichinter') {
2368 $modulepart = 'ficheinter';
2369 } elseif ($object->element == 'contrat') {
2370 $modulepart = 'contract';
2371 } elseif ($object->element == 'order_supplier') {
2372 $modulepart = 'supplier_order';
2373 } elseif ($object->element == 'invoice_supplier') {
2374 $modulepart = 'supplier_invoice';
2375 }
2376 }
2377
2378 if ($object->element == 'product') {
2379 $width = 80;
2380 $cssclass = 'photowithmargin photoref';
2381 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2382 $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : 5);
2383 if ($conf->browser->layout == 'phone') {
2384 $maxvisiblephotos = 1;
2385 }
2386 if ($showimage) {
2387 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$object->show_photos('product', $conf->product->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, 0, $width, 0, '').'</div>';
2388 } else {
2389 if (getDolGlobalString('PRODUCT_NODISPLAYIFNOPHOTO')) {
2390 $nophoto = '';
2391 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2392 } else { // Show no photo link
2393 $nophoto = '/public/theme/common/nophoto.png';
2394 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" title="'.dol_escape_htmltag($langs->trans("UploadAnImageToSeeAPhotoHere", $langs->transnoentitiesnoconv("Documents"))).'" alt="No photo"'.($width ? ' style="width: '.$width.'px"' : '').' src="'.DOL_URL_ROOT.$nophoto.'"></div>';
2395 }
2396 }
2397 } elseif ($object->element == 'ticket') {
2398 $width = 80;
2399 $cssclass = 'photoref';
2400 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2401 $maxvisiblephotos = (isset($conf->global->TICKET_MAX_VISIBLE_PHOTO) ? $conf->global->TICKET_MAX_VISIBLE_PHOTO : 2);
2402 if ($conf->browser->layout == 'phone') {
2403 $maxvisiblephotos = 1;
2404 }
2405
2406 if ($showimage) {
2407 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2408 if ($object->nbphoto > 0) {
2409 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2410 } else {
2411 $showimage = 0;
2412 }
2413 }
2414 if (!$showimage) {
2415 if (getDolGlobalString('TICKET_NODISPLAYIFNOPHOTO')) {
2416 $nophoto = '';
2417 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2418 } else { // Show no photo link
2419 $nophoto = img_picto('No photo', 'object_ticket');
2420 $morehtmlleft .= '<!-- No photo to show -->';
2421 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2422 $morehtmlleft .= $nophoto;
2423 $morehtmlleft .= '</div></div>';
2424 }
2425 }
2426 } else {
2427 if ($showimage) {
2428 if ($modulepart != 'unknown') {
2429 $phototoshow = '';
2430 // Check if a preview file is available
2431 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2432 $objectref = dol_sanitizeFileName($object->ref);
2433 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2434 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2435 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2436 $subdir .= ((!empty($subdir) && !preg_match('/\/$/', $subdir)) ? '/' : '').$objectref; // the objectref dir is not included into get_exdir when used with level=2, so we add it at end
2437 } else {
2438 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2439 }
2440 if (empty($subdir)) {
2441 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2442 }
2443
2444 $filepath = $dir_output.$subdir."/";
2445
2446 $filepdf = $filepath.$objectref.".pdf";
2447 $relativepath = $subdir.'/'.$objectref.'.pdf';
2448
2449 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2450 $fileimage = $filepdf.'_preview.png';
2451 $relativepathimage = $relativepath.'_preview.png';
2452
2453 $pdfexists = file_exists($filepdf);
2454
2455 // If PDF file exists
2456 if ($pdfexists) {
2457 // Conversion du PDF en image png si fichier png non existant
2458 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2459 if (!getDolGlobalString('MAIN_DISABLE_PDF_THUMBS')) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2460 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2461 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2462 if ($ret < 0) {
2463 $error++;
2464 }
2465 }
2466 }
2467 }
2468
2469 if ($pdfexists && !$error) {
2470 $heightforphotref = 80;
2471 if (!empty($conf->dol_optimize_smallscreen)) {
2472 $heightforphotref = 60;
2473 }
2474 // If the preview file is found
2475 if (file_exists($fileimage)) {
2476 $phototoshow = '<div class="photoref">';
2477 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2478 $phototoshow .= '</div>';
2479 }
2480 }
2481 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo'
2482 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2483 }
2484
2485 if ($phototoshow) {
2486 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2487 $morehtmlleft .= $phototoshow;
2488 $morehtmlleft .= '</div>';
2489 }
2490 }
2491
2492 if (empty($phototoshow)) { // Show No photo link (picto of object)
2493 if ($object->element == 'action') {
2494 $width = 80;
2495 $cssclass = 'photorefcenter';
2496 $nophoto = img_picto('No photo', 'title_agenda');
2497 } else {
2498 $width = 14;
2499 $cssclass = 'photorefcenter';
2500 $picto = $object->picto;
2501 $prefix = 'object_';
2502 if ($object->element == 'project' && !$object->public) {
2503 $picto = 'project'; // instead of projectpub
2504 }
2505 if (strpos($picto, 'fontawesome_') !== false) {
2506 $prefix = '';
2507 }
2508 $nophoto = img_picto('No photo', $prefix.$picto);
2509 }
2510 $morehtmlleft .= '<!-- No photo to show -->';
2511 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2512 $morehtmlleft .= $nophoto;
2513 $morehtmlleft .= '</div></div>';
2514 }
2515 }
2516 }
2517
2518 // Show barcode
2519 if ($showbarcode) {
2520 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2521 }
2522
2523 if ($object->element == 'societe') {
2524 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2525 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2526 } else {
2527 $morehtmlstatus .= $object->getLibStatut(6);
2528 }
2529 } elseif ($object->element == 'product') {
2530 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2531 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2532 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2533 } else {
2534 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2535 }
2536 $morehtmlstatus .= ' &nbsp; ';
2537 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2538 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2539 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2540 } else {
2541 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2542 }
2543 } elseif (in_array($object->element, array('salary'))) {
2544 $tmptxt = $object->getLibStatut(6, $object->alreadypaid);
2545 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2546 $tmptxt = $object->getLibStatut(5, $object->alreadypaid);
2547 }
2548 $morehtmlstatus .= $tmptxt;
2549 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier'))) { // TODO Move this to use ->alreadypaid
2550 $totalallpayments = $object->getSommePaiement(0);
2551 $totalallpayments += $object->getSumCreditNotesUsed(0);
2552 $totalallpayments += $object->getSumDepositsUsed(0);
2553 $tmptxt = $object->getLibStatut(6, $totalallpayments);
2554 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2555 $tmptxt = $object->getLibStatut(5, $totalallpayments);
2556 }
2557 $morehtmlstatus .= $tmptxt;
2558 } elseif (in_array($object->element, array('chargesociales', 'loan', 'tva'))) { // TODO Move this to use ->alreadypaid
2559 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2560 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2561 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2562 }
2563 $morehtmlstatus .= $tmptxt;
2564 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2565 if ($object->statut == 0) {
2566 $morehtmlstatus .= $object->getLibStatut(5);
2567 } else {
2568 $morehtmlstatus .= $object->getLibStatut(4);
2569 }
2570 } elseif ($object->element == 'facturerec') {
2571 if ($object->frequency == 0) {
2572 $morehtmlstatus .= $object->getLibStatut(2);
2573 } else {
2574 $morehtmlstatus .= $object->getLibStatut(5);
2575 }
2576 } elseif ($object->element == 'project_task') {
2577 $object->fk_statut = 1;
2578 if ($object->progress > 0) {
2579 $object->fk_statut = 2;
2580 }
2581 if ($object->progress >= 100) {
2582 $object->fk_statut = 3;
2583 }
2584 $tmptxt = $object->getLibStatut(5);
2585 $morehtmlstatus .= $tmptxt; // No status on task
2586 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2587 $tmptxt = $object->getLibStatut(6);
2588 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2589 $tmptxt = $object->getLibStatut(5);
2590 }
2591 $morehtmlstatus .= $tmptxt;
2592 }
2593
2594 // Add if object was dispatched "into accountancy"
2595 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2596 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2597 if (method_exists($object, 'getVentilExportCompta')) {
2598 $accounted = $object->getVentilExportCompta();
2599 $langs->load("accountancy");
2600 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2601 }
2602 }
2603
2604 // Add alias for thirdparty
2605 if (!empty($object->name_alias)) {
2606 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
2607 }
2608
2609 // Add label
2610 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
2611 if (!empty($object->label)) {
2612 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
2613 }
2614 }
2615
2616 // Show address and email
2617 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
2618 $moreaddress = $object->getBannerAddress('refaddress', $object); // address, email, url, social networks
2619 if ($moreaddress) {
2620 $morehtmlref .= '<div class="refidno refaddress">';
2621 $morehtmlref .= $moreaddress;
2622 $morehtmlref .= '</div>';
2623 }
2624 }
2625 if (getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && (getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') == '1' || preg_match('/'.preg_quote($object->element, '/').'/i', $conf->global->MAIN_SHOW_TECHNICAL_ID)) && !empty($object->id)) {
2626 $morehtmlref .= '<div style="clear: both;"></div>';
2627 $morehtmlref .= '<div class="refidno opacitymedium">';
2628 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
2629 $morehtmlref .= '</div>';
2630 }
2631
2632 $parameters=array('morehtmlref'=>$morehtmlref);
2633 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
2634 if ($reshook < 0) {
2635 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2636 } elseif (empty($reshook)) {
2637 $morehtmlref .= $hookmanager->resPrint;
2638 } elseif ($reshook > 0) {
2639 $morehtmlref = $hookmanager->resPrint;
2640 }
2641
2642 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
2643 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
2644 print '</div>';
2645 print '<div class="underrefbanner clearboth"></div>';
2646}
2647
2657function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
2658{
2659 global $langs;
2660 $ret = '';
2661 if ($fieldrequired) {
2662 $ret .= '<span class="fieldrequired">';
2663 }
2664 $ret .= '<label for="'.$fieldkey.'">';
2665 $ret .= $langs->trans($langkey);
2666 $ret .= '</label>';
2667 if ($fieldrequired) {
2668 $ret .= '</span>';
2669 }
2670 return $ret;
2671}
2672
2680function dol_bc($var, $moreclass = '')
2681{
2682 global $bc;
2683 $ret = ' '.$bc[$var];
2684 if ($moreclass) {
2685 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
2686 }
2687 return $ret;
2688}
2689
2703function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = '', $mode = 0, $extralangcode = '')
2704{
2705 global $conf, $langs, $hookmanager;
2706
2707 $ret = '';
2708 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
2709
2710 // See format of addresses on https://en.wikipedia.org/wiki/Address
2711 // Address
2712 if (empty($mode)) {
2713 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
2714 }
2715 // Zip/Town/State
2716 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || getDolGlobalString('MAIN_FORCE_STATE_INTO_ADDRESS')) {
2717 // US: title firstname name \n address lines \n town, state, zip \n country
2718 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2719 $ret .= (($ret && $town) ? $sep : '').$town;
2720
2721 if (!empty($object->state)) {
2722 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
2723 }
2724 if (!empty($object->zip)) {
2725 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
2726 }
2727 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
2728 // UK: title firstname name \n address lines \n town state \n zip \n country
2729 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2730 $ret .= ($ret ? $sep : '').$town;
2731 if (!empty($object->state)) {
2732 $ret .= ($ret ? ", " : '').$object->state;
2733 }
2734 if (!empty($object->zip)) {
2735 $ret .= ($ret ? $sep : '').$object->zip;
2736 }
2737 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
2738 // ES: title firstname name \n address lines \n zip town \n state \n country
2739 $ret .= ($ret ? $sep : '').$object->zip;
2740 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2741 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2742 if (!empty($object->state)) {
2743 $ret .= $sep.$object->state;
2744 }
2745 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
2746 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
2747 // See https://www.sljfaq.org/afaq/addresses.html
2748 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2749 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
2750 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
2751 // IT: title firstname name\n address lines \n zip town state_code \n country
2752 $ret .= ($ret ? $sep : '').$object->zip;
2753 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2754 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2755 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
2756 } else {
2757 // Other: title firstname name \n address lines \n zip town[, state] \n country
2758 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2759 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
2760 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
2761 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
2762 $ret .= ($ret ? ", " : '').$object->state;
2763 }
2764 }
2765
2766 if (!is_object($outputlangs)) {
2767 $outputlangs = $langs;
2768 }
2769 if ($withcountry) {
2770 $langs->load("dict");
2771 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
2772 }
2773 if ($hookmanager) {
2774 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
2775 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
2776 if ($reshook > 0) {
2777 $ret = '';
2778 }
2779 $ret .= $hookmanager->resPrint;
2780 }
2781
2782 return $ret;
2783}
2784
2785
2786
2795function dol_strftime($fmt, $ts = false, $is_gmt = false)
2796{
2797 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
2798 return ($is_gmt) ? @gmstrftime($fmt, $ts) : @strftime($fmt, $ts);
2799 } else {
2800 return 'Error date into a not supported range';
2801 }
2802}
2803
2825function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = '', $encodetooutput = false)
2826{
2827 global $conf, $langs;
2828
2829 // If date undefined or "", we return ""
2830 if (dol_strlen($time) == 0) {
2831 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
2832 }
2833
2834 if ($tzoutput === 'auto') {
2835 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
2836 }
2837
2838 // Clean parameters
2839 $to_gmt = false;
2840 $offsettz = $offsetdst = 0;
2841 if ($tzoutput) {
2842 $to_gmt = true; // For backward compatibility
2843 if (is_string($tzoutput)) {
2844 if ($tzoutput == 'tzserver') {
2845 $to_gmt = false;
2846 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
2847 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
2848 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
2849 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
2850 $to_gmt = true;
2851 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
2852
2853 if (class_exists('DateTimeZone')) {
2854 $user_date_tz = new DateTimeZone($offsettzstring);
2855 $user_dt = new DateTime();
2856 $user_dt->setTimezone($user_date_tz);
2857 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
2858 $offsettz = $user_dt->getOffset(); // should include dst ?
2859 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
2860 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
2861 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
2862 }
2863 }
2864 }
2865 }
2866 if (!is_object($outputlangs)) {
2867 $outputlangs = $langs;
2868 }
2869 if (!$format) {
2870 $format = 'daytextshort';
2871 }
2872
2873 // Do we have to reduce the length of date (year on 2 chars) to save space.
2874 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
2875 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour', 'dayhoursec'))) ? 1 : 0; // Test on original $format param.
2876 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
2877 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
2878 if ($formatwithoutreduce != $format) {
2879 $format = $formatwithoutreduce;
2880 $reduceformat = 1;
2881 } // so format 'dayreduceformat' is processed like day
2882
2883 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
2884 // TODO Add format daysmallyear and dayhoursmallyear
2885 if ($format == 'day') {
2886 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
2887 } elseif ($format == 'hour') {
2888 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
2889 } elseif ($format == 'hourduration') {
2890 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
2891 } elseif ($format == 'daytext') {
2892 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
2893 } elseif ($format == 'daytextshort') {
2894 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
2895 } elseif ($format == 'dayhour') {
2896 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
2897 } elseif ($format == 'dayhoursec') {
2898 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
2899 } elseif ($format == 'dayhourtext') {
2900 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
2901 } elseif ($format == 'dayhourtextshort') {
2902 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
2903 } elseif ($format == 'dayhourlog') {
2904 // Format not sensitive to language
2905 $format = '%Y%m%d%H%M%S';
2906 } elseif ($format == 'dayhourlogsmall') {
2907 // Format not sensitive to language
2908 $format = '%y%m%d%H%M';
2909 } elseif ($format == 'dayhourldap') {
2910 $format = '%Y%m%d%H%M%SZ';
2911 } elseif ($format == 'dayhourxcard') {
2912 $format = '%Y%m%dT%H%M%SZ';
2913 } elseif ($format == 'dayxcard') {
2914 $format = '%Y%m%d';
2915 } elseif ($format == 'dayrfc') {
2916 $format = '%Y-%m-%d'; // DATE_RFC3339
2917 } elseif ($format == 'dayhourrfc') {
2918 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
2919 } elseif ($format == 'standard') {
2920 $format = '%Y-%m-%d %H:%M:%S';
2921 }
2922
2923 if ($reduceformat) {
2924 $format = str_replace('%Y', '%y', $format);
2925 $format = str_replace('yyyy', 'yy', $format);
2926 }
2927
2928 // Clean format
2929 if (preg_match('/%b/i', $format)) { // There is some text to translate
2930 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2931 $format = str_replace('%b', '__b__', $format);
2932 $format = str_replace('%B', '__B__', $format);
2933 }
2934 if (preg_match('/%a/i', $format)) { // There is some text to translate
2935 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2936 $format = str_replace('%a', '__a__', $format);
2937 $format = str_replace('%A', '__A__', $format);
2938 }
2939
2940 // Analyze date
2941 $reg = array();
2942 if (preg_match('/^([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])$/i', $time, $reg)) { // Deprecated. Ex: 1970-01-01, 1970-01-01 01:00:00, 19700101010000
2943 dol_print_error('', "Functions.lib::dol_print_date function called with a bad value from page ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]));
2944 return '';
2945 } elseif (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?/i', $time, $reg)) { // Still available to solve problems in extrafields of type date
2946 // This part of code should not be used anymore.
2947 dol_syslog("Functions.lib::dol_print_date function called with a bad value from page ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]), LOG_WARNING);
2948 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
2949 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
2950 $syear = (!empty($reg[1]) ? $reg[1] : '');
2951 $smonth = (!empty($reg[2]) ? $reg[2] : '');
2952 $sday = (!empty($reg[3]) ? $reg[3] : '');
2953 $shour = (!empty($reg[4]) ? $reg[4] : '');
2954 $smin = (!empty($reg[5]) ? $reg[5] : '');
2955 $ssec = (!empty($reg[6]) ? $reg[6] : '');
2956
2957 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
2958
2959 if ($to_gmt) {
2960 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2961 } else {
2962 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2963 }
2964 $dtts = new DateTime();
2965 $dtts->setTimestamp($time);
2966 $dtts->setTimezone($tzo);
2967 $newformat = str_replace(
2968 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2969 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2970 $format
2971 );
2972 $ret = $dtts->format($newformat);
2973 $ret = str_replace(
2974 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2975 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2976 $ret
2977 );
2978 } else {
2979 // Date is a timestamps
2980 if ($time < 100000000000) { // Protection against bad date values
2981 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2982
2983 if ($to_gmt) {
2984 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2985 } else {
2986 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2987 }
2988 $dtts = new DateTime();
2989 $dtts->setTimestamp($timetouse);
2990 $dtts->setTimezone($tzo);
2991 $newformat = str_replace(
2992 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2993 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2994 $format
2995 );
2996 $ret = $dtts->format($newformat);
2997 $ret = str_replace(
2998 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2999 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
3000 $ret
3001 );
3002 //var_dump($ret);exit;
3003 } else {
3004 $ret = 'Bad value '.$time.' for date';
3005 }
3006 }
3007
3008 if (preg_match('/__b__/i', $format)) {
3009 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
3010
3011 if ($to_gmt) {
3012 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
3013 } else {
3014 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
3015 }
3016 $dtts = new DateTime();
3017 $dtts->setTimestamp($timetouse);
3018 $dtts->setTimezone($tzo);
3019 $month = $dtts->format("m");
3020 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
3021 if ($encodetooutput) {
3022 $monthtext = $outputlangs->transnoentities('Month'.$month);
3023 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
3024 } else {
3025 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
3026 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
3027 }
3028 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
3029 $ret = str_replace('__b__', $monthtextshort, $ret);
3030 $ret = str_replace('__B__', $monthtext, $ret);
3031 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
3032 //return $ret;
3033 }
3034 if (preg_match('/__a__/i', $format)) {
3035 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
3036 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
3037
3038 if ($to_gmt) {
3039 $tzo = new DateTimeZone('UTC');
3040 } else {
3041 $tzo = new DateTimeZone(date_default_timezone_get());
3042 }
3043 $dtts = new DateTime();
3044 $dtts->setTimestamp($timetouse);
3045 $dtts->setTimezone($tzo);
3046 $w = $dtts->format("w");
3047 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
3048
3049 $ret = str_replace('__A__', $dayweek, $ret);
3050 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
3051 }
3052
3053 return $ret;
3054}
3055
3056
3077function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
3078{
3079 if ($timestamp === '') {
3080 return array();
3081 }
3082
3083 $datetimeobj = new DateTime();
3084 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
3085 if ($forcetimezone) {
3086 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
3087 }
3088 $arrayinfo = array(
3089 'year'=>((int) date_format($datetimeobj, 'Y')),
3090 'mon'=>((int) date_format($datetimeobj, 'm')),
3091 'mday'=>((int) date_format($datetimeobj, 'd')),
3092 'wday'=>((int) date_format($datetimeobj, 'w')),
3093 'yday'=>((int) date_format($datetimeobj, 'z')),
3094 'hours'=>((int) date_format($datetimeobj, 'H')),
3095 'minutes'=>((int) date_format($datetimeobj, 'i')),
3096 'seconds'=>((int) date_format($datetimeobj, 's')),
3097 '0'=>$timestamp
3098 );
3099
3100 return $arrayinfo;
3101}
3102
3124function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3125{
3126 global $conf;
3127 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3128
3129 if ($gm === 'auto') {
3130 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3131 }
3132 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3133
3134 // Clean parameters
3135 if ($hour == -1 || empty($hour)) {
3136 $hour = 0;
3137 }
3138 if ($minute == -1 || empty($minute)) {
3139 $minute = 0;
3140 }
3141 if ($second == -1 || empty($second)) {
3142 $second = 0;
3143 }
3144
3145 // Check parameters
3146 if ($check) {
3147 if (!$month || !$day) {
3148 return '';
3149 }
3150 if ($day > 31) {
3151 return '';
3152 }
3153 if ($month > 12) {
3154 return '';
3155 }
3156 if ($hour < 0 || $hour > 24) {
3157 return '';
3158 }
3159 if ($minute < 0 || $minute > 60) {
3160 return '';
3161 }
3162 if ($second < 0 || $second > 60) {
3163 return '';
3164 }
3165 }
3166
3167 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3168 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3169 $localtz = new DateTimeZone($default_timezone);
3170 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3171 // We use dol_tz_string first because it is more reliable.
3172 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3173 try {
3174 $localtz = new DateTimeZone($default_timezone);
3175 } catch (Exception $e) {
3176 dol_syslog("Warning dol_tz_string contains an invalid value ".$_SESSION["dol_tz_string"], LOG_WARNING);
3177 $default_timezone = @date_default_timezone_get();
3178 }
3179 } elseif (strrpos($gm, "tz,") !== false) {
3180 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3181 try {
3182 $localtz = new DateTimeZone($timezone);
3183 } catch (Exception $e) {
3184 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3185 }
3186 }
3187
3188 if (empty($localtz)) {
3189 $localtz = new DateTimeZone('UTC');
3190 }
3191 //var_dump($localtz);
3192 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3193 $dt = new DateTime('now', $localtz);
3194 $dt->setDate((int) $year, (int) $month, (int) $day);
3195 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3196 $date = $dt->getTimestamp(); // should include daylight saving time
3197 //var_dump($date);
3198 return $date;
3199}
3200
3201
3212function dol_now($mode = 'auto')
3213{
3214 $ret = 0;
3215
3216 if ($mode === 'auto') {
3217 $mode = 'gmt';
3218 }
3219
3220 if ($mode == 'gmt') {
3221 $ret = time(); // Time for now at greenwich.
3222 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3223 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3224 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3225 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3226 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3227 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3228 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3229 // $ret=dol_now('gmt')+($tzsecond*3600);
3230 //}
3231 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3232 // Time for now with user timezone added
3233 //print 'time: '.time();
3234 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3235 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3236 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3237 }
3238
3239 return $ret;
3240}
3241
3242
3251function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3252{
3253 global $conf, $langs;
3254 $level = 1024;
3255
3256 if (!empty($conf->dol_optimize_smallscreen)) {
3257 $shortunit = 1;
3258 }
3259
3260 // Set value text
3261 if (empty($shortvalue) || $size < ($level * 10)) {
3262 $ret = $size;
3263 $textunitshort = $langs->trans("b");
3264 $textunitlong = $langs->trans("Bytes");
3265 } else {
3266 $ret = round($size / $level, 0);
3267 $textunitshort = $langs->trans("Kb");
3268 $textunitlong = $langs->trans("KiloBytes");
3269 }
3270 // Use long or short text unit
3271 if (empty($shortunit)) {
3272 $ret .= ' '.$textunitlong;
3273 } else {
3274 $ret .= ' '.$textunitshort;
3275 }
3276
3277 return $ret;
3278}
3279
3290function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = '')
3291{
3292 global $langs;
3293
3294 if (empty($url)) {
3295 return '';
3296 }
3297
3298 $linkstart = '<a href="';
3299 if (!preg_match('/^http/i', $url)) {
3300 $linkstart .= 'http://';
3301 }
3302 $linkstart .= $url;
3303 $linkstart .= '"';
3304 if ($target) {
3305 $linkstart .= ' target="'.$target.'"';
3306 }
3307 $linkstart .= ' title="'.$langs->trans("URL").': '.$url.'"';
3308 $linkstart .= '>';
3309
3310 $link = '';
3311 if (!preg_match('/^http/i', $url)) {
3312 $link .= 'http://';
3313 }
3314 $link .= dol_trunc($url, $max);
3315
3316 $linkend = '</a>';
3317
3318 if ($morecss == 'float') { // deprecated
3319 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto($langs->trans("Url"), 'globe', 'class="paddingrightonly"') : '').$link.'</div>';
3320 } else {
3321 return $linkstart.'<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto('', 'globe', 'class="paddingrightonly"') : '').$link.'</span>'.$linkend;
3322 }
3323}
3324
3337function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3338{
3339 global $user, $langs, $hookmanager;
3340
3341 //global $conf; $conf->global->AGENDA_ADDACTIONFOREMAIL = 1;
3342 //$showinvalid = 1; $email = 'rrrrr';
3343
3344 $newemail = dol_escape_htmltag($email);
3345
3346 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && $withpicto) {
3347 $withpicto = 0;
3348 }
3349
3350 if (empty($email)) {
3351 return '&nbsp;';
3352 }
3353
3354 if (!empty($addlink)) {
3355 $newemail = '<a class="paddingrightonly" style="text-overflow: ellipsis;" href="';
3356 if (!preg_match('/^mailto:/i', $email)) {
3357 $newemail .= 'mailto:';
3358 }
3359 $newemail .= $email;
3360 $newemail .= '">';
3361
3362 $newemail .= ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '');
3363
3364 $newemail .= dol_trunc($email, $max);
3365 $newemail .= '</a>';
3366 if ($showinvalid && !isValidEmail($email)) {
3367 $langs->load("errors");
3368 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email), '', 'paddingrightonly');
3369 }
3370
3371 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3372 $type = 'AC_EMAIL';
3373 $linktoaddaction = '';
3374 if (getDolGlobalString('AGENDA_ADDACTIONFOREMAIL')) {
3375 $linktoaddaction = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.urlencode($type).'&amp;contactid='.((int) $cid).'&amp;socid='.((int) $socid).'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3376 }
3377 if ($linktoaddaction) {
3378 $newemail = '<div>'.$newemail.' '.$linktoaddaction.'</div>';
3379 }
3380 }
3381 } else {
3382 $newemail = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3383
3384 if ($showinvalid && !isValidEmail($email)) {
3385 $langs->load("errors");
3386 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3387 }
3388 }
3389
3390 //$rep = '<div class="nospan" style="margin-right: 10px">';
3391 //$rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3392 //$rep .= '</div>';
3393 $rep = $newemail;
3394
3395 if ($hookmanager) {
3396 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3397
3398 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3399 if ($reshook > 0) {
3400 $rep = '';
3401 }
3402 $rep .= $hookmanager->resPrint;
3403 }
3404
3405 return $rep;
3406}
3407
3414{
3415 global $conf, $db;
3416
3417 $socialnetworks = array();
3418 // Enable caching of array
3419 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3420 $cachekey = 'socialnetworks_' . $conf->entity;
3421 $dataretrieved = dol_getcache($cachekey);
3422 if (!is_null($dataretrieved)) {
3423 $socialnetworks = $dataretrieved;
3424 } else {
3425 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3426 $sql .= " WHERE entity=".$conf->entity;
3427 $resql = $db->query($sql);
3428 if ($resql) {
3429 while ($obj = $db->fetch_object($resql)) {
3430 $socialnetworks[$obj->code] = array(
3431 'rowid' => $obj->rowid,
3432 'label' => $obj->label,
3433 'url' => $obj->url,
3434 'icon' => $obj->icon,
3435 'active' => $obj->active,
3436 );
3437 }
3438 }
3439 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3440 }
3441
3442 return $socialnetworks;
3443}
3444
3455function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3456{
3457 global $conf, $user, $langs;
3458
3459 $htmllink = $value;
3460
3461 if (empty($value)) {
3462 return '&nbsp;';
3463 }
3464
3465 if (!empty($type)) {
3466 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3467 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3468 $htmllink .= '<span class="fab pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3469 if ($type == 'skype') {
3470 $htmllink .= dol_escape_htmltag($value);
3471 $htmllink .= '&nbsp; <a href="skype:';
3472 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3473 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3474 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3475 $htmllink .= '</a><a href="skype:';
3476 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3477 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3478 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3479 $htmllink .= '</a>';
3480 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3481 $addlink = 'AC_SKYPE';
3482 $link = '';
3483 if (getDolGlobalString('AGENDA_ADDACTIONFORSKYPE')) {
3484 $link = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.$addlink.'&amp;contactid='.$cid.'&amp;socid='.$socid.'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3485 }
3486 $htmllink .= ($link ? ' '.$link : '');
3487 }
3488 } else {
3489 $networkconstname = 'MAIN_INFO_SOCIETE_'.strtoupper($type).'_URL';
3490 if (getDolGlobalString($networkconstname)) {
3491 $link = str_replace('{socialid}', $value, getDolGlobalString($networkconstname));
3492 if (preg_match('/^https?:\/\//i', $link)) {
3493 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3494 } else {
3495 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3496 }
3497 } elseif (!empty($dictsocialnetworks[$type]['url'])) {
3498 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3499 if ($tmpvirginurl) {
3500 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3501 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3502
3503 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3504 if ($tmpvirginurl3) {
3505 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3506 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3507 }
3508
3509 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3510 if ($tmpvirginurl2) {
3511 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3512 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3513 }
3514 }
3515 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3516 if (preg_match('/^https?:\/\//i', $link)) {
3517 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3518 } else {
3519 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3520 }
3521 } else {
3522 $htmllink .= dol_escape_htmltag($value);
3523 }
3524 }
3525 $htmllink .= '</div>';
3526 } else {
3527 $langs->load("errors");
3528 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3529 }
3530 return $htmllink;
3531}
3532
3542function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1)
3543{
3544 global $mysoc;
3545
3546 if (empty($profID) || empty($profIDtype)) {
3547 return '';
3548 }
3549 if (empty($countrycode)) {
3550 $countrycode = $mysoc->country_code;
3551 }
3552 $newProfID = $profID;
3553 $id = substr($profIDtype, -1);
3554 $ret = '';
3555 if (strtoupper($countrycode) == 'FR') {
3556 // France
3557 // (see https://www.economie.gouv.fr/entreprises/numeros-identification-entreprise)
3558
3559 if ($id == 1 && dol_strlen($newProfID) == 9) {
3560 // SIREN (ex: 123 123 123)
3561 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3);
3562 }
3563 if ($id == 2 && dol_strlen($newProfID) == 14) {
3564 // SIRET (ex: 123 123 123 12345)
3565 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3).' '.substr($newProfID, 9, 5);
3566 }
3567 if ($id == 3 && dol_strlen($newProfID) == 5) {
3568 // NAF/APE (ex: 69.20Z)
3569 $newProfID = substr($newProfID, 0, 2).'.'.substr($newProfID, 2, 3);
3570 }
3571 if ($profIDtype === 'VAT' && dol_strlen($newProfID) == 13) {
3572 // TVA intracommunautaire (ex: FR12 123 123 123)
3573 $newProfID = substr($newProfID, 0, 4).' '.substr($newProfID, 4, 3).' '.substr($newProfID, 7, 3).' '.substr($newProfID, 10, 3);
3574 }
3575 }
3576 if (!empty($addcpButton)) {
3577 $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3578 } else {
3579 $ret = $newProfID;
3580 }
3581 return $ret;
3582}
3583
3598function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0)
3599{
3600 global $conf, $user, $langs, $mysoc, $hookmanager;
3601
3602 // Clean phone parameter
3603 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
3604 if (empty($phone)) {
3605 return '';
3606 }
3607 if (getDolGlobalString('MAIN_PHONE_SEPAR')) {
3608 $separ = $conf->global->MAIN_PHONE_SEPAR;
3609 }
3610 if (empty($countrycode) && is_object($mysoc)) {
3611 $countrycode = $mysoc->country_code;
3612 }
3613
3614 // Short format for small screens
3615 if ($conf->dol_optimize_smallscreen) {
3616 $separ = '';
3617 }
3618
3619 $newphone = $phone;
3620 if (strtoupper($countrycode) == "FR") {
3621 // France
3622 if (dol_strlen($phone) == 10) {
3623 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 2).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3624 } elseif (dol_strlen($phone) == 7) {
3625 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
3626 } elseif (dol_strlen($phone) == 9) {
3627 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
3628 } elseif (dol_strlen($phone) == 11) {
3629 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3630 } elseif (dol_strlen($phone) == 12) {
3631 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3632 } elseif (dol_strlen($phone) == 13) {
3633 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 2);
3634 }
3635 } elseif (strtoupper($countrycode) == "CA") {
3636 if (dol_strlen($phone) == 10) {
3637 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
3638 }
3639 } elseif (strtoupper($countrycode) == "PT") {//Portugal
3640 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
3641 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3642 }
3643 } elseif (strtoupper($countrycode) == "SR") {//Suriname
3644 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
3645 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
3646 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
3647 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
3648 }
3649 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
3650 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
3651 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
3652 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
3653 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
3654 }
3655 } elseif (strtoupper($countrycode) == "ES") {//Espagne
3656 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
3657 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3658 }
3659 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
3660 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
3661 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3662 }
3663 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
3664 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
3665 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3666 }
3667 } elseif (strtoupper($countrycode) == "TR") {//Turquie
3668 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
3669 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3670 }
3671 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
3672 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
3673 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3674 }
3675 } elseif (strtoupper($countrycode) == "MX") {//Mexique
3676 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
3677 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3678 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
3679 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3680 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
3681 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3682 }
3683 } elseif (strtoupper($countrycode) == "ML") {//Mali
3684 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
3685 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3686 }
3687 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
3688 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
3689 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3690 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
3691 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 3);
3692 }
3693 } elseif (strtoupper($countrycode) == "MU") {
3694 //Maurice
3695 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
3696 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3697 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
3698 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3699 }
3700 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
3701 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
3702 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3703 }
3704 } elseif (strtoupper($countrycode) == "SY") {//Syrie
3705 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
3706 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3707 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
3708 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 3);
3709 }
3710 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
3711 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
3712 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3713 } elseif (dol_strlen($phone) == 13) {//ex: +971_ABC_DEF_GHI
3714 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3715 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
3716 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
3717 }
3718 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
3719 if (dol_strlen($phone) == 13) {//ex: +213_ABC_DEF_GHI
3720 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3721 }
3722 } elseif (strtoupper($countrycode) == "BE") {//Belgique
3723 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
3724 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3725 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
3726 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3727 }
3728 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
3729 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
3730 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3731 }
3732 } elseif (strtoupper($countrycode) == "CO") {//Colombie
3733 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
3734 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3735 }
3736 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
3737 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
3738 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 1).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3739 }
3740 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
3741 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
3742 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3743 }
3744 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
3745 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
3746 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 2);
3747 }
3748 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
3749 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
3750 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3751 }
3752 } elseif (strtoupper($countrycode) == "CH") {//Suisse
3753 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
3754 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3755 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
3756 $newphone = $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 4);
3757 }
3758 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
3759 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
3760 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3761 }
3762 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
3763 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
3764 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3765 }
3766 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
3767 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
3768 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3769 }
3770 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
3771 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
3772 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3773 }
3774 } elseif (strtoupper($countrycode) == "IT") {//Italie
3775 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
3776 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3777 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
3778 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3779 }
3780 } elseif (strtoupper($countrycode) == "AU") {
3781 //Australie
3782 if (dol_strlen($phone) == 12) {
3783 //ex: +61_A_BCDE_FGHI
3784 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
3785 }
3786 } elseif (strtoupper($countrycode) == "LU") {
3787 // Luxembourg
3788 if (dol_strlen($phone) == 10) {// fixe 6 chiffres +352_AA_BB_CC
3789 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3790 } elseif (dol_strlen($phone) == 11) {// fixe 7 chiffres +352_AA_BB_CC_D
3791 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 1);
3792 } elseif (dol_strlen($phone) == 12) {// fixe 8 chiffres +352_AA_BB_CC_DD
3793 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3794 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
3795 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3796 }
3797 }
3798
3799 $newphoneastart = $newphoneaend = '';
3800 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
3801 if ($addlink == 'tel' || $conf->browser->layout == 'phone' || (isModEnabled('clicktodial') && getDolGlobalString('CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS'))) { // If phone or option for, we use link of phone
3802 $newphoneastart = '<a href="tel:'.$phone.'">';
3803 $newphoneaend .= '</a>';
3804 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
3805 if (empty($user->clicktodial_loaded)) {
3806 $user->fetch_clicktodial();
3807 }
3808
3809 // Define urlmask
3810 $urlmask = getDolGlobalString('CLICKTODIAL_URL', 'ErrorClickToDialModuleNotConfigured');
3811 if (!empty($user->clicktodial_url)) {
3812 $urlmask = $user->clicktodial_url;
3813 }
3814
3815 $clicktodial_poste = (!empty($user->clicktodial_poste) ? urlencode($user->clicktodial_poste) : '');
3816 $clicktodial_login = (!empty($user->clicktodial_login) ? urlencode($user->clicktodial_login) : '');
3817 $clicktodial_password = (!empty($user->clicktodial_password) ? urlencode($user->clicktodial_password) : '');
3818 // This line is for backward compatibility
3819 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
3820 // Thoose lines are for substitution
3821 $substitarray = array('__PHONEFROM__'=>$clicktodial_poste,
3822 '__PHONETO__'=>urlencode($phone),
3823 '__LOGIN__'=>$clicktodial_login,
3824 '__PASS__'=>$clicktodial_password);
3825 $url = make_substitutions($url, $substitarray);
3826 if (!getDolGlobalString('CLICKTODIAL_DO_NOT_USE_AJAX_CALL')) {
3827 // Default and recommended: New method using ajax without submiting a page making a javascript history.go(-1) back
3828 $newphoneastart = '<a href="'.$url.'" class="cssforclicktodial">'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
3829 $newphoneaend = '</a>';
3830 } else {
3831 // Old method
3832 $newphoneastart = '<a href="'.$url.'"';
3833 if (getDolGlobalString('CLICKTODIAL_FORCENEWTARGET')) {
3834 $newphoneastart .= ' target="_blank" rel="noopener noreferrer"';
3835 }
3836 $newphoneastart .= '>';
3837 $newphoneaend .= '</a>';
3838 }
3839 }
3840
3841 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
3842 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3843 $type = 'AC_TEL';
3844 $addlinktoagenda = '';
3845 if ($addlink == 'AC_FAX') {
3846 $type = 'AC_FAX';
3847 }
3848 if (getDolGlobalString('AGENDA_ADDACTIONFORPHONE')) {
3849 $addlinktoagenda = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage='. urlencode($_SERVER['REQUEST_URI']) .'&amp;actioncode='.$type.($cid ? '&amp;contactid='.$cid : '').($socid ? '&amp;socid='.$socid : '').'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3850 }
3851 if ($addlinktoagenda) {
3852 $newphone = '<span>'.$newphone.' '.$addlinktoagenda.'</span>';
3853 }
3854 }
3855 }
3856
3857 if (empty($titlealt)) {
3858 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
3859 }
3860 $rep = '';
3861
3862 if ($hookmanager) {
3863 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
3864 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
3865 $rep .= $hookmanager->resPrint;
3866 }
3867 if (empty($reshook)) {
3868 $picto = '';
3869 if ($withpicto) {
3870 if ($withpicto == 'fax') {
3871 $picto = 'phoning_fax';
3872 } elseif ($withpicto == 'phone') {
3873 $picto = 'phoning';
3874 } elseif ($withpicto == 'mobile') {
3875 $picto = 'phoning_mobile';
3876 } else {
3877 $picto = '';
3878 }
3879 }
3880 if ($adddivfloat == 1) {
3881 $rep .= '<div class="nospan float" style="margin-right: 10px">';
3882 } elseif (empty($adddivfloat)) {
3883 $rep .= '<span style="margin-right: 10px;">';
3884 }
3885
3886 $rep .= $newphoneastart;
3887 $rep .= ($withpicto ? img_picto($titlealt, 'object_'.$picto.'.png') : '');
3888 if ($separ != 'hidenum') {
3889 $rep .= ($withpicto ? ' ' : '').$newphone;
3890 }
3891 $rep .= $newphoneaend;
3892
3893 if ($adddivfloat == 1) {
3894 $rep .= '</div>';
3895 } elseif (empty($adddivfloat)) {
3896 $rep .= '</span>';
3897 }
3898 }
3899
3900 return $rep;
3901}
3902
3910function dol_print_ip($ip, $mode = 0)
3911{
3912 global $langs;
3913
3914 $ret = '';
3915
3916 if (empty($mode)) {
3917 $ret .= $ip;
3918 }
3919
3920 if ($mode != 2) {
3921 $countrycode = dolGetCountryCodeFromIp($ip);
3922 if ($countrycode) { // If success, countrycode is us, fr, ...
3923 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
3924 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
3925 } else {
3926 $ret .= ' ('.$countrycode.')';
3927 }
3928 } else {
3929 // Nothing
3930 }
3931 }
3932
3933 return $ret;
3934}
3935
3945{
3946 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
3947 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
3948 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
3949 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
3950 } else {
3951 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
3952 }
3953 } else {
3954 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
3955 }
3956 } else {
3957 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
3958 }
3959 return $ip;
3960}
3961
3970function isHTTPS()
3971{
3972 $isSecure = false;
3973 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
3974 $isSecure = true;
3975 } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
3976 $isSecure = true;
3977 }
3978 return $isSecure;
3979}
3980
3988{
3989 global $conf;
3990
3991 $countrycode = '';
3992
3993 if (!empty($conf->geoipmaxmind->enabled)) {
3994 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3995 //$ip='24.24.24.24';
3996 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
3997 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3998 $geoip = new DolGeoIP('country', $datafile);
3999 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
4000 $countrycode = $geoip->getCountryCodeFromIP($ip);
4001 }
4002
4003 return $countrycode;
4004}
4005
4006
4014{
4015 global $conf, $langs, $user;
4016
4017 //$ret=$user->xxx;
4018 $ret = '';
4019 if (!empty($conf->geoipmaxmind->enabled)) {
4020 $ip = getUserRemoteIP();
4021 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
4022 //$ip='24.24.24.24';
4023 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
4024 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
4025 $geoip = new DolGeoIP('country', $datafile);
4026 $countrycode = $geoip->getCountryCodeFromIP($ip);
4027 $ret = $countrycode;
4028 }
4029 return $ret;
4030}
4031
4044function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
4045{
4046 global $conf, $user, $langs, $hookmanager;
4047
4048 $out = '';
4049
4050 if ($address) {
4051 if ($hookmanager) {
4052 $parameters = array('element' => $element, 'id' => $id);
4053 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
4054 $out .= $hookmanager->resPrint;
4055 }
4056 if (empty($reshook)) {
4057 if (empty($charfornl)) {
4058 $out .= nl2br($address);
4059 } else {
4060 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
4061 }
4062
4063 // TODO Remove this block, we can add this using the hook now
4064 $showgmap = $showomap = 0;
4065 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS')) {
4066 $showgmap = 1;
4067 }
4068 if ($element == 'contact' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_CONTACTS')) {
4069 $showgmap = 1;
4070 }
4071 if ($element == 'member' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_MEMBERS')) {
4072 $showgmap = 1;
4073 }
4074 if ($element == 'user' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_USERS')) {
4075 $showgmap = 1;
4076 }
4077 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS')) {
4078 $showomap = 1;
4079 }
4080 if ($element == 'contact' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_CONTACTS')) {
4081 $showomap = 1;
4082 }
4083 if ($element == 'member' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_MEMBERS')) {
4084 $showomap = 1;
4085 }
4086 if ($element == 'user' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_USERS')) {
4087 $showomap = 1;
4088 }
4089 if ($showgmap) {
4090 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
4091 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4092 }
4093 if ($showomap) {
4094 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
4095 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4096 }
4097 }
4098 }
4099 if ($noprint) {
4100 return $out;
4101 } else {
4102 print $out;
4103 }
4104}
4105
4106
4116function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
4117{
4118 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
4119 return true;
4120 }
4121 if ($acceptuserkey && $address == '__USER_EMAIL__') {
4122 return true;
4123 }
4124 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
4125 return true;
4126 }
4127
4128 return false;
4129}
4130
4139function isValidMXRecord($domain)
4140{
4141 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
4142 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
4143 return 0;
4144 }
4145 if (function_exists('getmxrr')) {
4146 $mxhosts = array();
4147 $weight = array();
4148 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
4149 if (count($mxhosts) > 1) {
4150 return 1;
4151 }
4152 if (count($mxhosts) == 1 && !empty($mxhosts[0])) {
4153 return 1;
4154 }
4155
4156 return 0;
4157 }
4158 }
4159
4160 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4161 return -1;
4162}
4163
4171function isValidPhone($phone)
4172{
4173 return true;
4174}
4175
4176
4186function dolGetFirstLetters($s, $nbofchar = 1)
4187{
4188 $ret = '';
4189 $tmparray = explode(' ', $s);
4190 foreach ($tmparray as $tmps) {
4191 $ret .= dol_substr($tmps, 0, $nbofchar);
4192 }
4193
4194 return $ret;
4195}
4196
4197
4205function dol_strlen($string, $stringencoding = 'UTF-8')
4206{
4207 if (is_null($string)) {
4208 return 0;
4209 }
4210
4211 if (function_exists('mb_strlen')) {
4212 return mb_strlen($string, $stringencoding);
4213 } else {
4214 return strlen($string);
4215 }
4216}
4217
4228function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4229{
4230 global $langs;
4231
4232 if (empty($stringencoding)) {
4233 $stringencoding = $langs->charset_output;
4234 }
4235
4236 $ret = '';
4237 if (empty($trunconbytes)) {
4238 if (function_exists('mb_substr')) {
4239 $ret = mb_substr($string, $start, $length, $stringencoding);
4240 } else {
4241 $ret = substr($string, $start, $length);
4242 }
4243 } else {
4244 if (function_exists('mb_strcut')) {
4245 $ret = mb_strcut($string, $start, $length, $stringencoding);
4246 } else {
4247 $ret = substr($string, $start, $length);
4248 }
4249 }
4250 return $ret;
4251}
4252
4253
4267function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4268{
4269 global $conf;
4270
4271 if (empty($size) || getDolGlobalString('MAIN_DISABLE_TRUNC')) {
4272 return $string;
4273 }
4274
4275 if (empty($stringencoding)) {
4276 $stringencoding = 'UTF-8';
4277 }
4278 // reduce for small screen
4279 if ($conf->dol_optimize_smallscreen == 1 && $display == 1) {
4280 $size = round($size / 3);
4281 }
4282
4283 // We go always here
4284 if ($trunc == 'right') {
4285 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4286 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4287 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4288 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4289 } else {
4290 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4291 return $string;
4292 }
4293 } elseif ($trunc == 'middle') {
4294 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4295 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4296 $size1 = round($size / 2);
4297 $size2 = round($size / 2);
4298 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4299 } else {
4300 return $string;
4301 }
4302 } elseif ($trunc == 'left') {
4303 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4304 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4305 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4306 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4307 } else {
4308 return $string;
4309 }
4310 } elseif ($trunc == 'wrap') {
4311 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4312 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4313 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4314 } else {
4315 return $string;
4316 }
4317 } else {
4318 return 'BadParam3CallingDolTrunc';
4319 }
4320}
4321
4328function getPictoForType($key)
4329{
4330 // Set array with type -> picto
4331 $type2picto = array(
4332 'varchar'=>'font',
4333 'text'=>'font',
4334 'html'=>'code',
4335 'int'=>'sort-numeric-down',
4336 'double'=>'sort-numeric-down',
4337 'price'=>'currency',
4338 'pricecy'=>'multicurrency',
4339 'password' => 'key',
4340 'boolean'=>'check-square',
4341 'date'=>'calendar',
4342 'datetime'=>'calendar',
4343 'phone'=> 'phone',
4344 'mail'=> 'email',
4345 'url'=> 'url',
4346 'ip'=> 'country',
4347 'select' => 'list',
4348 'sellist' => 'list',
4349 'radio' => 'check-circle',
4350 'checkbox' => 'check-square',
4351 'chkbxlst' => 'check-square',
4352 'link' => 'link',
4353 'separate'=> 'minus'
4354 );
4355
4356 if (!empty($type2picto[$key])) {
4357 return img_picto('', $type2picto[$key], 'class="pictofixedwidth"');
4358 }
4359
4360 return img_picto('', 'generic', 'class="pictofixedwidth"');
4361}
4362
4363
4385function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4386{
4387 global $conf, $langs;
4388
4389 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4390 $url = DOL_URL_ROOT;
4391 $theme = isset($conf->theme) ? $conf->theme : null;
4392 $path = 'theme/'.$theme;
4393 if (empty($picto)) {
4394 $picto = 'generic';
4395 }
4396
4397 // Define fullpathpicto to use into src
4398 if ($pictoisfullpath) {
4399 // Clean parameters
4400 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4401 $picto .= '.png';
4402 }
4403 $fullpathpicto = $picto;
4404 $reg = array();
4405 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4406 $morecss .= ($morecss ? ' ' : '').$reg[1];
4407 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4408 }
4409 } else {
4410 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', (is_null($picto) ? '' : $picto));
4411 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4412 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4413
4414 if (strpos($pictowithouttext, 'fontawesome_') === 0 || strpos($pictowithouttext, 'fa-') === 0) {
4415 // This is a font awesome image 'fontawesome_xxx' or 'fa-xxx'
4416 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4417 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4418
4419 // Compatibility with old fontawesome versions
4420 if ($pictowithouttext == 'file-o') {
4421 $pictowithouttext = 'file';
4422 }
4423
4424 $pictowithouttextarray = explode('_', $pictowithouttext);
4425 $marginleftonlyshort = 0;
4426
4427 if (!empty($pictowithouttextarray[1])) {
4428 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4429 $fakey = 'fa-'.$pictowithouttextarray[0];
4430 $faprefix = empty($pictowithouttextarray[1]) ? 'fas' : $pictowithouttextarray[1];
4431 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4432 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4433 } else {
4434 $fakey = 'fa-'.$pictowithouttext;
4435 $faprefix = 'fas';
4436 $facolor = '';
4437 $fasize = '';
4438 }
4439
4440 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4441 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4442 $morestyle = '';
4443 $reg = array();
4444 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4445 $morecss .= ($morecss ? ' ' : '').$reg[1];
4446 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4447 }
4448 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4449 $morestyle = $reg[1];
4450 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4451 }
4452 $moreatt = trim($moreatt);
4453
4454 $enabledisablehtml = '<span class="'.$faprefix.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4455 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4456 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4457 $enabledisablehtml .= $titlealt;
4458 }*/
4459 $enabledisablehtml .= '</span>';
4460
4461 return $enabledisablehtml;
4462 }
4463
4464 if (empty($srconly) && in_array($pictowithouttext, array(
4465 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4466 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'angle-double-down', 'angle-double-up', 'asset',
4467 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building',
4468 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4469 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'code', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4470 'check-circle', 'check-square', 'currency', 'multicurrency',
4471 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies',
4472 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4473 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4474 'filter', 'file', 'file-o', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus', 'font',
4475 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4476 'hands-helping', 'help', 'holiday',
4477 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4478 'key', 'knowledgemanagement',
4479 'label', 'language', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4480 'margin', 'map-marker-alt', 'member', 'meeting', 'minus', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4481 'off', 'on', 'order',
4482 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4483 'stock', 'resize', 'service', 'stats',
4484 'security', 'setup', 'share-alt', 'sign-out', 'split', 'stripe', 'stripe-s', 'switch_off', 'switch_on', 'switch_on_warning', 'switch_on_red', 'tools', 'unlink', 'uparrow', 'user', 'user-tie', 'vcard', 'wrench',
4485 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4486 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4487 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4488 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4489 'technic', 'ticket',
4490 'error', 'warning',
4491 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4492 'shapes', 'skill', 'square', 'sort-numeric-down', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4493 'tick', 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda',
4494 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4495 'conferenceorbooth', 'eventorganization',
4496 'stamp', 'signature'
4497 ))) {
4498 $fakey = $pictowithouttext;
4499 $facolor = '';
4500 $fasize = '';
4501 $fa = getDolGlobalString('MAIN_FONTAWESOME_ICON_STYLE', 'fas');
4502 if (in_array($pictowithouttext, array('card', 'bell', 'clock', 'establishment', 'file', 'file-o', 'generic', 'minus-square', 'object_generic', 'pdf', 'plus-square', 'timespent', 'note', 'off', 'on', 'object_bookmark', 'bookmark', 'vcard'))) {
4503 $fa = 'far';
4504 }
4505 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4506 $fa = 'fab';
4507 }
4508
4509 $arrayconvpictotofa = array(
4510 'account'=>'university', 'accounting_account'=>'clipboard-list', 'accountline'=>'receipt', 'accountancy'=>'search-dollar', 'action'=>'calendar-alt', 'add'=>'plus-circle', 'address'=> 'address-book', 'asset'=>'money-check-alt', 'autofill'=>'fill',
4511 'bank_account'=>'university',
4512 'bill'=>'file-invoice-dollar', 'billa'=>'file-excel', 'billr'=>'file-invoice-dollar', 'billd'=>'file-medical',
4513 'supplier_invoice'=>'file-invoice-dollar', 'supplier_invoicea'=>'file-excel', 'supplier_invoicer'=>'file-invoice-dollar', 'supplier_invoiced'=>'file-medical',
4514 'bom'=>'shapes',
4515 'card'=>'address-card', 'chart'=>'chart-line', 'company'=>'building', 'contact'=>'address-book', 'contract'=>'suitcase', 'collab'=>'people-arrows', 'conversation'=>'comments', 'country'=>'globe-americas', 'cron'=>'business-time', 'cross'=>'times',
4516 'donation'=>'file-alt', 'dynamicprice'=>'hand-holding-usd',
4517 'setup'=>'cog', 'companies'=>'building', 'products'=>'cube', 'commercial'=>'suitcase', 'invoicing'=>'coins',
4518 'accounting'=>'search-dollar', 'category'=>'tag', 'dollyrevert'=>'dolly',
4519 'file-o'=>'file', 'generate'=>'plus-square', 'hrm'=>'user-tie', 'incoterm'=>'truck-loading',
4520 'margin'=>'calculator', 'members'=>'user-friends', 'ticket'=>'ticket-alt', 'globe'=>'external-link-alt', 'lot'=>'barcode',
4521 'email'=>'at', 'establishment'=>'building', 'edit'=>'pencil-alt', 'entity'=>'globe',
4522 'graph'=>'chart-line', 'grip_title'=>'arrows-alt', 'grip'=>'arrows-alt', 'help'=>'question-circle',
4523 'generic'=>'file', 'holiday'=>'umbrella-beach',
4524 'info'=>'info-circle', 'inventory'=>'boxes', 'intracommreport'=>'globe-europe', 'jobprofile'=>'cogs',
4525 'knowledgemanagement'=>'ticket-alt', 'label'=>'layer-group', 'line'=>'bars', 'loan'=>'money-bill-alt',
4526 'member'=>'user-alt', 'meeting'=>'chalkboard-teacher', 'mrp'=>'cubes', 'next'=>'arrow-alt-circle-right',
4527 'trip'=>'wallet', 'expensereport'=>'wallet', 'group'=>'users', 'movement'=>'people-carry',
4528 'sign-out'=>'sign-out-alt',
4529 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_warning'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star',
4530 'bank'=>'university', 'close_title'=>'times', 'delete'=>'trash', 'filter'=>'filter',
4531 'list-alt'=>'list-alt', 'calendarlist'=>'bars', 'calendar'=>'calendar-alt', 'calendarmonth'=>'calendar-alt', 'calendarweek'=>'calendar-week', 'calendarday'=>'calendar-day', 'calendarperuser'=>'table',
4532 'intervention'=>'ambulance', 'invoice'=>'file-invoice-dollar', 'order'=>'file-invoice',
4533 'error'=>'exclamation-triangle', 'warning'=>'exclamation-triangle',
4534 'other'=>'square',
4535 'playdisabled'=>'play', 'pdf'=>'file-pdf', 'poll'=>'check-double', 'pos'=>'cash-register', 'preview'=>'binoculars', 'project'=>'project-diagram', 'projectpub'=>'project-diagram', 'projecttask'=>'tasks', 'propal'=>'file-signature', 'proposal'=>'file-signature',
4536 'partnership'=>'handshake', 'payment'=>'money-check-alt', 'payment_vat'=>'money-check-alt', 'pictoconfirm'=>'check-square', 'phoning'=>'phone', 'phoning_mobile'=>'mobile-alt', 'phoning_fax'=>'fax', 'previous'=>'arrow-alt-circle-left', 'printer'=>'print', 'product'=>'cube', 'puce'=>'angle-right',
4537 'recent' => 'check-square', 'reception'=>'dolly', 'recruitmentjobposition'=>'id-card-alt', 'recruitmentcandidature'=>'id-badge',
4538 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature',
4539 'refresh'=>'redo', 'region'=>'map-marked', 'replacement'=>'exchange-alt', 'resource'=>'laptop-house', 'recurring'=>'history',
4540 'service'=>'concierge-bell',
4541 'skill'=>'shapes', 'state'=>'map-marked-alt', 'security'=>'key', 'salary'=>'wallet', 'shipment'=>'dolly', 'stock'=>'box-open', 'stats' => 'chart-bar', 'split'=>'code-branch', 'stripe'=>'stripe-s',
4542 'supplier'=>'building', 'technic'=>'cogs',
4543 'timespent'=>'clock', 'tick' => 'check', 'title_setup'=>'tools', 'title_accountancy'=>'money-check-alt', 'title_bank'=>'university', 'title_hrm'=>'umbrella-beach',
4544 'title_agenda'=>'calendar-alt',
4545 'uncheck'=>'times', 'uparrow'=>'share', 'url'=>'external-link-alt', 'vat'=>'money-check-alt', 'vcard'=>'arrow-alt-circle-down',
4546 'jabber'=>'comment-o',
4547 'website'=>'globe-americas', 'workstation'=>'pallet', 'webhook'=>'bullseye', 'world'=>'globe', 'private'=>'user-lock',
4548 'conferenceorbooth'=>'chalkboard-teacher', 'eventorganization'=>'project-diagram'
4549 );
4550 if ($conf->currency == 'EUR') {
4551 $arrayconvpictotofa['currency'] = 'euro-sign';
4552 $arrayconvpictotofa['multicurrency'] = 'dollar-sign';
4553 } else {
4554 $arrayconvpictotofa['currency'] = 'dollar-sign';
4555 $arrayconvpictotofa['multicurrency'] = 'euro-sign';
4556 }
4557 if ($pictowithouttext == 'off') {
4558 $fakey = 'fa-square';
4559 $fasize = '1.3em';
4560 } elseif ($pictowithouttext == 'on') {
4561 $fakey = 'fa-check-square';
4562 $fasize = '1.3em';
4563 } elseif ($pictowithouttext == 'listlight') {
4564 $fakey = 'fa-download';
4565 $marginleftonlyshort = 1;
4566 } elseif ($pictowithouttext == 'printer') {
4567 $fakey = 'fa-print';
4568 $fasize = '1.2em';
4569 } elseif ($pictowithouttext == 'note') {
4570 $fakey = 'fa-sticky-note';
4571 $marginleftonlyshort = 1;
4572 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
4573 $convertarray = array('1uparrow'=>'caret-up', '1downarrow'=>'caret-down', '1leftarrow'=>'caret-left', '1rightarrow'=>'caret-right', '1uparrow_selected'=>'caret-up', '1downarrow_selected'=>'caret-down', '1leftarrow_selected'=>'caret-left', '1rightarrow_selected'=>'caret-right');
4574 $fakey = 'fa-'.$convertarray[$pictowithouttext];
4575 if (preg_match('/selected/', $pictowithouttext)) {
4576 $facolor = '#888';
4577 }
4578 $marginleftonlyshort = 1;
4579 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
4580 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
4581 } else {
4582 $fakey = 'fa-'.$pictowithouttext;
4583 }
4584
4585 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment'))) {
4586 $morecss .= ' em092';
4587 }
4588 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
4589 $morecss .= ' em088';
4590 }
4591 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
4592 $morecss .= ' em080';
4593 }
4594
4595 // Define $marginleftonlyshort
4596 $arrayconvpictotomarginleftonly = array(
4597 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
4598 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
4599 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
4600 );
4601 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
4602 $marginleftonlyshort = 0;
4603 }
4604
4605 // Add CSS
4606 $arrayconvpictotomorcess = array(
4607 'action'=>'infobox-action', 'account'=>'infobox-bank_account', 'accounting_account'=>'infobox-bank_account', 'accountline'=>'infobox-bank_account', 'accountancy'=>'infobox-bank_account', 'asset'=>'infobox-bank_account',
4608 'bank_account'=>'infobox-bank_account',
4609 'bill'=>'infobox-commande', 'billa'=>'infobox-commande', 'billr'=>'infobox-commande', 'billd'=>'infobox-commande',
4610 'margin'=>'infobox-bank_account', 'conferenceorbooth'=>'infobox-project',
4611 'cash-register'=>'infobox-bank_account', 'contract'=>'infobox-contrat', 'check'=>'font-status4', 'collab'=>'infobox-action', 'conversation'=>'infobox-contrat',
4612 'donation'=>'infobox-commande', 'dolly'=>'infobox-commande', 'dollyrevert'=>'flip infobox-order_supplier',
4613 'ecm'=>'infobox-action', 'eventorganization'=>'infobox-project',
4614 'hrm'=>'infobox-adherent', 'group'=>'infobox-adherent', 'intervention'=>'infobox-contrat',
4615 'incoterm'=>'infobox-supplier_proposal',
4616 'currency'=>'infobox-bank_account', 'multicurrency'=>'infobox-bank_account',
4617 'members'=>'infobox-adherent', 'member'=>'infobox-adherent', 'money-bill-alt'=>'infobox-bank_account',
4618 'order'=>'infobox-commande',
4619 'user'=>'infobox-adherent', 'users'=>'infobox-adherent',
4620 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_warning'=>'font-status4 warning', 'switch_on_red'=>'font-status8',
4621 'holiday'=>'infobox-holiday', 'info'=>'opacityhigh', 'invoice'=>'infobox-commande',
4622 'knowledgemanagement'=>'infobox-contrat rotate90', 'loan'=>'infobox-bank_account',
4623 'payment'=>'infobox-bank_account', 'payment_vat'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'pos'=>'infobox-bank_account', 'project'=>'infobox-project', 'projecttask'=>'infobox-project',
4624 'propal'=>'infobox-propal', 'proposal'=>'infobox-propal','private'=>'infobox-project',
4625 'reception'=>'flip', 'recruitmentjobposition'=>'infobox-adherent', 'recruitmentcandidature'=>'infobox-adherent',
4626 'resource'=>'infobox-action',
4627 'salary'=>'infobox-bank_account', 'shapes'=>'infobox-adherent', 'shipment'=>'infobox-commande', 'supplier_invoice'=>'infobox-order_supplier', 'supplier_invoicea'=>'infobox-order_supplier', 'supplier_invoiced'=>'infobox-order_supplier',
4628 'supplier'=>'infobox-order_supplier', 'supplier_order'=>'infobox-order_supplier', 'supplier_proposal'=>'infobox-supplier_proposal',
4629 'ticket'=>'infobox-contrat', 'title_accountancy'=>'infobox-bank_account', 'title_hrm'=>'infobox-holiday', 'expensereport'=>'infobox-expensereport', 'trip'=>'infobox-expensereport', 'title_agenda'=>'infobox-action',
4630 'vat'=>'infobox-bank_account',
4631 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
4632 'list-alt'=>'imgforviewmode', 'calendar'=>'imgforviewmode', 'calendarweek'=>'imgforviewmode', 'calendarmonth'=>'imgforviewmode', 'calendarday'=>'imgforviewmode', 'calendarperuser'=>'imgforviewmode'
4633 );
4634 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4635 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
4636 }
4637
4638 // Define $color
4639 $arrayconvpictotocolor = array(
4640 'address'=>'#6c6aa8', 'building'=>'#6c6aa8', 'bom'=>'#a69944',
4641 'clone'=>'#999', 'cog'=>'#999', 'companies'=>'#6c6aa8', 'company'=>'#6c6aa8', 'contact'=>'#6c6aa8', 'cron'=>'#555',
4642 'dynamicprice'=>'#a69944',
4643 'edit'=>'#444', 'note'=>'#999', 'error'=>'', 'help'=>'#bbb', 'listlight'=>'#999', 'language'=>'#555',
4644 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
4645 'lock'=>'#ddd', 'lot'=>'#a69944',
4646 'map-marker-alt'=>'#aaa', 'mrp'=>'#a69944', 'product'=>'#a69944', 'service'=>'#a69944', 'inventory'=>'#a69944', 'stock'=>'#a69944', 'movement'=>'#a69944',
4647 'other'=>'#ddd', 'world'=>'#986c6a',
4648 'partnership'=>'#6c6aa8', 'playdisabled'=>'#ccc', 'printer'=>'#444', 'projectpub'=>'#986c6a', 'reception'=>'#a69944', 'resize'=>'#444', 'rss'=>'#cba',
4649 //'shipment'=>'#a69944',
4650 'security'=>'#999', 'square'=>'#888', 'stop-circle'=>'#888', 'stats'=>'#444', 'switch_off'=>'#999',
4651 'technic' => '#999', 'tick' => '#282', 'timespent' => '#555',
4652 'uncheck'=>'#800', 'uparrow'=>'#555', 'user-cog'=>'#999', 'country'=>'#aaa', 'globe-americas'=>'#aaa', 'region'=>'#aaa', 'state'=>'#aaa',
4653 'website'=>'#304', 'workstation'=>'#a69944'
4654 );
4655 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4656 $facolor = $arrayconvpictotocolor[$pictowithouttext];
4657 }
4658
4659 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4660 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4661 $morestyle = '';
4662 $reg = array();
4663 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4664 $morecss .= ($morecss ? ' ' : '').$reg[1];
4665 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4666 }
4667 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4668 $morestyle = $reg[1];
4669 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4670 }
4671 $moreatt = trim($moreatt);
4672
4673 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4674 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4675 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4676 $enabledisablehtml .= $titlealt;
4677 }*/
4678 $enabledisablehtml .= '</span>';
4679
4680 return $enabledisablehtml;
4681 }
4682
4683 if (getDolGlobalString('MAIN_OVERWRITE_THEME_PATH')) {
4684 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_PATH') . '/theme/'.$theme; // If the theme does not have the same name as the module
4685 } elseif (getDolGlobalString('MAIN_OVERWRITE_THEME_RES')) {
4686 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_RES') . '/theme/' . getDolGlobalString('MAIN_OVERWRITE_THEME_RES'); // To allow an external module to overwrite image resources whatever is activated theme
4687 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
4688 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
4689 }
4690
4691 // If we ask an image into $url/$mymodule/img (instead of default path)
4692 $regs = array();
4693 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
4694 $picto = $regs[1];
4695 $path = $regs[2]; // $path is $mymodule
4696 }
4697
4698 // Clean parameters
4699 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4700 $picto .= '.png';
4701 }
4702 // If alt path are defined, define url where img file is, according to physical path
4703 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
4704 foreach ($conf->file->dol_document_root as $type => $dirroot) {
4705 if ($type == 'main') {
4706 continue;
4707 }
4708 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommanded
4709 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
4710 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
4711 break;
4712 }
4713 }
4714
4715 // $url is '' or '/custom', $path is current theme or
4716 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
4717 }
4718
4719 if ($srconly) {
4720 return $fullpathpicto;
4721 }
4722
4723 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
4724 return '<img src="'.$fullpathpicto.'"'.($notitle ? '' : ' alt="'.dol_escape_htmltag($alt).'"').(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt.($morecss ? ' class="'.$morecss.'"' : '') : ' class="inline-block'.($morecss ? ' '.$morecss : '').'"').'>'; // Alt is used for accessibility, title for popup
4725}
4726
4740function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0)
4741{
4742 if (strpos($picto, '^') === 0) {
4743 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
4744 } else {
4745 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
4746 }
4747}
4748
4760function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
4761{
4762 global $conf;
4763
4764 if (is_numeric($picto)) {
4765 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
4766 //$picto = $leveltopicto[$picto];
4767 return '<i class="fa fa-weather-level'.$picto.'"></i>';
4768 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4769 $picto .= '.png';
4770 }
4771
4772 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
4773
4774 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
4775}
4776
4788function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
4789{
4790 global $conf;
4791
4792 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4793 $picto .= '.png';
4794 }
4795
4796 if ($pictoisfullpath) {
4797 $path = $picto;
4798 } else {
4799 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
4800
4801 if (getDolGlobalInt('MAIN_MODULE_CAN_OVERWRITE_COMMONICONS')) {
4802 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
4803
4804 if (file_exists($themepath)) {
4805 $path = $themepath;
4806 }
4807 }
4808 }
4809
4810 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
4811}
4812
4826function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
4827{
4828 global $langs;
4829
4830 if (empty($titlealt) || $titlealt == 'default') {
4831 if ($numaction == '-1' || $numaction == 'ST_NO') {
4832 $numaction = -1;
4833 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
4834 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
4835 $numaction = 0;
4836 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
4837 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
4838 $numaction = 1;
4839 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
4840 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
4841 $numaction = 2;
4842 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
4843 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
4844 $numaction = 3;
4845 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
4846 } else {
4847 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
4848 $numaction = 0;
4849 }
4850 }
4851 if (!is_numeric($numaction)) {
4852 $numaction = 0;
4853 }
4854
4855 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
4856}
4857
4865function img_pdf($titlealt = 'default', $size = 3)
4866{
4867 global $langs;
4868
4869 if ($titlealt == 'default') {
4870 $titlealt = $langs->trans('Show');
4871 }
4872
4873 return img_picto($titlealt, 'pdf'.$size.'.png');
4874}
4875
4883function img_edit_add($titlealt = 'default', $other = '')
4884{
4885 global $langs;
4886
4887 if ($titlealt == 'default') {
4888 $titlealt = $langs->trans('Add');
4889 }
4890
4891 return img_picto($titlealt, 'edit_add.png', $other);
4892}
4900function img_edit_remove($titlealt = 'default', $other = '')
4901{
4902 global $langs;
4903
4904 if ($titlealt == 'default') {
4905 $titlealt = $langs->trans('Remove');
4906 }
4907
4908 return img_picto($titlealt, 'edit_remove.png', $other);
4909}
4910
4919function img_edit($titlealt = 'default', $float = 0, $other = '')
4920{
4921 global $langs;
4922
4923 if ($titlealt == 'default') {
4924 $titlealt = $langs->trans('Modify');
4925 }
4926
4927 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
4928}
4929
4938function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
4939{
4940 global $langs;
4941
4942 if ($titlealt == 'default') {
4943 $titlealt = $langs->trans('View');
4944 }
4945
4946 $moreatt = ($float ? 'style="float: right" ' : '').$other;
4947
4948 return img_picto($titlealt, 'eye', $moreatt);
4949}
4950
4959function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
4960{
4961 global $langs;
4962
4963 if ($titlealt == 'default') {
4964 $titlealt = $langs->trans('Delete');
4965 }
4966
4967 return img_picto($titlealt, 'delete.png', $other, false, 0, 0, '', $morecss);
4968}
4969
4977function img_printer($titlealt = "default", $other = '')
4978{
4979 global $langs;
4980 if ($titlealt == "default") {
4981 $titlealt = $langs->trans("Print");
4982 }
4983 return img_picto($titlealt, 'printer.png', $other);
4984}
4985
4993function img_split($titlealt = 'default', $other = 'class="pictosplit"')
4994{
4995 global $langs;
4996
4997 if ($titlealt == 'default') {
4998 $titlealt = $langs->trans('Split');
4999 }
5000
5001 return img_picto($titlealt, 'split.png', $other);
5002}
5003
5011function img_help($usehelpcursor = 1, $usealttitle = 1)
5012{
5013 global $langs;
5014
5015 if ($usealttitle) {
5016 if (is_string($usealttitle)) {
5017 $usealttitle = dol_escape_htmltag($usealttitle);
5018 } else {
5019 $usealttitle = $langs->trans('Info');
5020 }
5021 }
5022
5023 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
5024}
5025
5032function img_info($titlealt = 'default')
5033{
5034 global $langs;
5035
5036 if ($titlealt == 'default') {
5037 $titlealt = $langs->trans('Informations');
5038 }
5039
5040 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
5041}
5042
5051function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
5052{
5053 global $langs;
5054
5055 if ($titlealt == 'default') {
5056 $titlealt = $langs->trans('Warning');
5057 }
5058
5059 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
5060 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
5061}
5062
5069function img_error($titlealt = 'default')
5070{
5071 global $langs;
5072
5073 if ($titlealt == 'default') {
5074 $titlealt = $langs->trans('Error');
5075 }
5076
5077 return img_picto($titlealt, 'error.png');
5078}
5079
5087function img_next($titlealt = 'default', $moreatt = '')
5088{
5089 global $langs;
5090
5091 if ($titlealt == 'default') {
5092 $titlealt = $langs->trans('Next');
5093 }
5094
5095 //return img_picto($titlealt, 'next.png', $moreatt);
5096 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5097}
5098
5106function img_previous($titlealt = 'default', $moreatt = '')
5107{
5108 global $langs;
5109
5110 if ($titlealt == 'default') {
5111 $titlealt = $langs->trans('Previous');
5112 }
5113
5114 //return img_picto($titlealt, 'previous.png', $moreatt);
5115 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5116}
5117
5126function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
5127{
5128 global $langs;
5129
5130 if ($titlealt == 'default') {
5131 $titlealt = $langs->trans('Down');
5132 }
5133
5134 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
5135}
5136
5145function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
5146{
5147 global $langs;
5148
5149 if ($titlealt == 'default') {
5150 $titlealt = $langs->trans('Up');
5151 }
5152
5153 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
5154}
5155
5164function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
5165{
5166 global $langs;
5167
5168 if ($titlealt == 'default') {
5169 $titlealt = $langs->trans('Left');
5170 }
5171
5172 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
5173}
5174
5183function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
5184{
5185 global $langs;
5186
5187 if ($titlealt == 'default') {
5188 $titlealt = $langs->trans('Right');
5189 }
5190
5191 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
5192}
5193
5201function img_allow($allow, $titlealt = 'default')
5202{
5203 global $langs;
5204
5205 if ($titlealt == 'default') {
5206 $titlealt = $langs->trans('Active');
5207 }
5208
5209 if ($allow == 1) {
5210 return img_picto($titlealt, 'tick.png');
5211 }
5212
5213 return '-';
5214}
5215
5223function img_credit_card($brand, $morecss = null)
5224{
5225 if (is_null($morecss)) {
5226 $morecss = 'fa-2x';
5227 }
5228
5229 if ($brand == 'visa' || $brand == 'Visa') {
5230 $brand = 'cc-visa';
5231 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5232 $brand = 'cc-mastercard';
5233 } elseif ($brand == 'amex' || $brand == 'American Express') {
5234 $brand = 'cc-amex';
5235 } elseif ($brand == 'discover' || $brand == 'Discover') {
5236 $brand = 'cc-discover';
5237 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5238 $brand = 'cc-jcb';
5239 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5240 $brand = 'cc-diners-club';
5241 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5242 $brand = 'credit-card';
5243 }
5244
5245 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5246}
5247
5256function img_mime($file, $titlealt = '', $morecss = '')
5257{
5258 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5259
5260 $mimetype = dol_mimetype($file, '', 1);
5261 $mimeimg = dol_mimetype($file, '', 2);
5262 $mimefa = dol_mimetype($file, '', 4);
5263
5264 if (empty($titlealt)) {
5265 $titlealt = 'Mime type: '.$mimetype;
5266 }
5267
5268 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5269 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5270}
5271
5272
5280function img_search($titlealt = 'default', $other = '')
5281{
5282 global $conf, $langs;
5283
5284 if ($titlealt == 'default') {
5285 $titlealt = $langs->trans('Search');
5286 }
5287
5288 $img = img_picto($titlealt, 'search.png', $other, false, 1);
5289
5290 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5291 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5292
5293 return $input;
5294}
5295
5303function img_searchclear($titlealt = 'default', $other = '')
5304{
5305 global $conf, $langs;
5306
5307 if ($titlealt == 'default') {
5308 $titlealt = $langs->trans('Search');
5309 }
5310
5311 $img = img_picto($titlealt, 'searchclear.png', $other, false, 1);
5312
5313 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5314 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5315
5316 return $input;
5317}
5318
5330function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '')
5331{
5332 global $conf, $langs;
5333
5334 if ($infoonimgalt) {
5335 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5336 } else {
5337 if (empty($conf->use_javascript_ajax)) {
5338 $textfordropdown = '';
5339 }
5340
5341 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5342 $result = ($nodiv ? '' : '<div class="'.$class.($morecss ? ' '.$morecss : '').($textfordropdown ? ' hidden' : '').'">').'<span class="fa fa-info-circle" title="'.dol_escape_htmltag($admin ? $langs->trans('InfoAdmin') : $langs->trans('Note')).'"></span> '.$text.($nodiv ? '' : '</div>');
5343
5344 if ($textfordropdown) {
5345 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5346 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5347 jQuery(document).ready(function() {
5348 jQuery(".'.$class.'text").click(function() {
5349 console.log("toggle text");
5350 jQuery(".'.$class.'").toggle();
5351 });
5352 });
5353 </script>';
5354
5355 $result = $tmpresult.$result;
5356 }
5357 }
5358
5359 return $result;
5360}
5361
5362
5374function dol_print_error($db = '', $error = '', $errors = null)
5375{
5376 global $conf, $langs, $argv;
5377 global $dolibarr_main_prod;
5378
5379 $out = '';
5380 $syslog = '';
5381
5382 // If error occurs before the $lang object was loaded
5383 if (!$langs) {
5384 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5385 $langs = new Translate('', $conf);
5386 $langs->load("main");
5387 }
5388
5389 // Load translation files required by the error messages
5390 $langs->loadLangs(array('main', 'errors'));
5391
5392 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5393 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5394 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5395 $out .= "You use an experimental or develop level of features, so please do NOT report any bugs or vulnerability, except if problem is confirmed after moving option MAIN_FEATURES_LEVEL back to 0.<br>\n";
5396 }
5397 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5398
5399 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5400 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5401 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5402 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5403 }
5404 if (function_exists("phpversion")) {
5405 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5406 }
5407 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5408 if (function_exists("php_uname")) {
5409 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5410 }
5411 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5412 $out .= "<br>\n";
5413 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5414 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5415 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5416 $out .= "<br>\n";
5417 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5418 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5419 } else { // Mode CLI
5420 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5421 $syslog .= "pid=".dol_getmypid();
5422 }
5423
5424 if (!empty($conf->modules)) {
5425 $out .= "<b>".$langs->trans("Modules").":</b> ".join(', ', $conf->modules)."<br>\n";
5426 }
5427
5428 if (is_object($db)) {
5429 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5430 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5431 $lastqueryerror = $db->lastqueryerror();
5432 if (!utf8_check($lastqueryerror)) {
5433 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5434 }
5435 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5436 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5437 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5438 $out .= "<br>\n";
5439 } else { // Mode CLI
5440 // No dol_escape_htmltag for output, we are in CLI mode
5441 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5442 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5443 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5444 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5445 }
5446 $syslog .= ", sql=".$db->lastquery();
5447 $syslog .= ", db_error=".$db->lasterror();
5448 }
5449
5450 if ($error || $errors) {
5451 $langs->load("errors");
5452
5453 // Merge all into $errors array
5454 if (is_array($error) && is_array($errors)) {
5455 $errors = array_merge($error, $errors);
5456 } elseif (is_array($error)) {
5457 $errors = $error;
5458 } elseif (is_array($errors)) {
5459 $errors = array_merge(array($error), $errors);
5460 } else {
5461 $errors = array_merge(array($error), array($errors));
5462 }
5463
5464 foreach ($errors as $msg) {
5465 if (empty($msg)) {
5466 continue;
5467 }
5468 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5469 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5470 } else { // Mode CLI
5471 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5472 }
5473 $syslog .= ", msg=".$msg;
5474 }
5475 }
5476 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5477 xdebug_print_function_stack();
5478 $out .= '<b>XDebug informations:</b>'."<br>\n";
5479 $out .= 'File: '.xdebug_call_file()."<br>\n";
5480 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5481 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5482 $out .= "<br>\n";
5483 }
5484
5485 // Return a http header with error code if possible
5486 if (!headers_sent()) {
5487 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5488 top_httphead();
5489 }
5490 //http_response_code(500); // If we use 500, message is not ouput with some command line tools
5491 http_response_code(202); // If we use 202, this is not really an error message, but this allow to ouput message on command line tools
5492 }
5493
5494 if (empty($dolibarr_main_prod)) {
5495 print $out;
5496 } else {
5497 if (empty($langs->defaultlang)) {
5498 $langs->setDefaultLang();
5499 }
5500 $langs->loadLangs(array("main", "errors")); // Reload main because language may have been set only on previous line so we have to reload files we need.
5501 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5502 print 'This website or feature is currently temporarly not available or failed after a technical error.<br><br>This may be due to a maintenance operation. Current status of operation ('.dol_print_date(dol_now(), 'dayhourrfc').') are on next line...<br><br>'."\n";
5503 print $langs->trans("DolibarrHasDetectedError").'. ';
5504 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5505 if (!defined("MAIN_CORE_ERROR")) {
5506 define("MAIN_CORE_ERROR", 1);
5507 }
5508 }
5509
5510 dol_syslog("Error ".$syslog, LOG_ERR);
5511}
5512
5523function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5524{
5525 global $langs, $conf;
5526
5527 if (empty($email)) {
5528 $email = $conf->global->MAIN_INFO_SOCIETE_MAIL;
5529 }
5530
5531 $langs->load("errors");
5532 $now = dol_now();
5533
5534 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5535 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5536 if ($errormessage) {
5537 print '<br><br>'.$errormessage;
5538 }
5539 if (is_array($errormessages) && count($errormessages)) {
5540 foreach ($errormessages as $mesgtoshow) {
5541 print '<br><br>'.$mesgtoshow;
5542 }
5543 }
5544 print '</div></div>';
5545}
5546
5563function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
5564{
5565 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
5566}
5567
5586function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
5587{
5588 global $conf, $langs, $form;
5589 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
5590
5591 if ($moreattrib == 'class="right"') {
5592 $prefix .= 'right '; // For backward compatibility
5593 }
5594
5595 $sortorder = strtoupper($sortorder);
5596 $out = '';
5597 $sortimg = '';
5598
5599 $tag = 'th';
5600 if ($thead == 2) {
5601 $tag = 'div';
5602 }
5603
5604 $tmpsortfield = explode(',', $sortfield);
5605 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
5606 $tmpfield = explode(',', $field);
5607 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
5608
5609 if (!getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle)) {
5610 $prefix = 'wrapcolumntitle '.$prefix;
5611 }
5612
5613 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
5614 // If field is used as sort criteria we use a specific css class liste_titre_sel
5615 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
5616 $liste_titre = 'liste_titre';
5617 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
5618 $liste_titre = 'liste_titre_sel';
5619 }
5620
5621 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
5622 //$out .= (($field && empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && preg_match('/^[a-zA-Z_0-9\s\.\-:&;]*$/', $name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5623 $tagstart .= ($name && !getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
5624 $tagstart .= '>';
5625
5626 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5627 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5628 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5629 $options = preg_replace('/&+/i', '&', $options);
5630 if (!preg_match('/^&/', $options)) {
5631 $options = '&'.$options;
5632 }
5633
5634 $sortordertouseinlink = '';
5635 if ($field1 != $sortfield1) { // We are on another field than current sorted field
5636 if (preg_match('/^DESC/i', $sortorder)) {
5637 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5638 } else { // We reverse the var $sortordertouseinlink
5639 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5640 }
5641 } else { // We are on field that is the first current sorting criteria
5642 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
5643 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5644 } else {
5645 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5646 }
5647 }
5648 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
5649 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
5650 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5651 $out .= '>';
5652 }
5653 if ($tooltip) {
5654 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
5655 if (preg_match('/:\w+$/', $tooltip)) {
5656 $tmptooltip = explode(':', $tooltip);
5657 } else {
5658 $tmptooltip = array($tooltip);
5659 }
5660 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
5661 } else {
5662 $out .= $langs->trans($name);
5663 }
5664
5665 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5666 $out .= '</a>';
5667 }
5668
5669 if (empty($thead) && $field) { // If this is a sort field
5670 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5671 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5672 $options = preg_replace('/&+/i', '&', $options);
5673 if (!preg_match('/^&/', $options)) {
5674 $options = '&'.$options;
5675 }
5676
5677 if (!$sortorder || ($field1 != $sortfield1)) {
5678 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5679 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5680 } else {
5681 if (preg_match('/^DESC/', $sortorder)) {
5682 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5683 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
5684 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
5685 }
5686 if (preg_match('/^ASC/', $sortorder)) {
5687 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
5688 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5689 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
5690 }
5691 }
5692 }
5693
5694 $tagend = '</'.$tag.'>';
5695
5696 $out = $tagstart.$sortimg.$out.$tagend;
5697
5698 return $out;
5699}
5700
5709function print_titre($title)
5710{
5711 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
5712
5713 print '<div class="titre">'.$title.'</div>';
5714}
5715
5727function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
5728{
5729 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
5730}
5731
5745function load_fiche_titre($titre, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
5746{
5747 global $conf;
5748
5749 $return = '';
5750
5751 if ($picto == 'setup') {
5752 $picto = 'generic';
5753 }
5754
5755 $return .= "\n";
5756 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
5757 $return .= '<tr class="titre">';
5758 if ($picto) {
5759 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
5760 }
5761 $return .= '<td class="nobordernopadding valignmiddle col-title">';
5762 $return .= '<div class="titre inline-block">'.$titre.'</div>';
5763 $return .= '</td>';
5764 if (dol_strlen($morehtmlcenter)) {
5765 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5766 }
5767 if (dol_strlen($morehtmlright)) {
5768 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
5769 }
5770 $return .= '</tr></table>'."\n";
5771
5772 return $return;
5773}
5774
5798function print_barre_liste($titre, $page, $file, $options = '', $sortfield = '', $sortorder = '', $morehtmlcenter = '', $num = -1, $totalnboflines = '', $picto = 'generic', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limit = -1, $hideselectlimit = 0, $hidenavigation = 0, $pagenavastextinput = 0, $morehtmlrightbeforearrow = '')
5799{
5800 global $conf;
5801
5802 $savlimit = $limit;
5803 $savtotalnboflines = $totalnboflines;
5804 $totalnboflines = abs((int) $totalnboflines);
5805
5806 $page = (int) $page;
5807
5808 if ($picto == 'setup') {
5809 $picto = 'title_setup.png';
5810 }
5811 if (($conf->browser->name == 'ie') && $picto == 'generic') {
5812 $picto = 'title.gif';
5813 }
5814 if ($limit < 0) {
5815 $limit = $conf->liste_limit;
5816 }
5817
5818 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
5819 $nextpage = 1;
5820 } else {
5821 $nextpage = 0;
5822 }
5823 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
5824
5825 print "\n";
5826 print "<!-- Begin title -->\n";
5827 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
5828
5829 // Left
5830
5831 if ($picto && $titre) {
5832 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
5833 }
5834
5835 print '<td class="nobordernopadding valignmiddle col-title">';
5836 print '<div class="titre inline-block">'.$titre;
5837 if (!empty($titre) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
5838 print '<span class="opacitymedium colorblack paddingleft">('.$totalnboflines.')</span>';
5839 }
5840 print '</div></td>';
5841
5842 // Center
5843 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
5844 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5845 }
5846
5847 // Right
5848 print '<td class="nobordernopadding valignmiddle right col-right">';
5849 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
5850 if ($sortfield) {
5851 $options .= "&sortfield=".urlencode($sortfield);
5852 }
5853 if ($sortorder) {
5854 $options .= "&sortorder=".urlencode($sortorder);
5855 }
5856 // Show navigation bar
5857 $pagelist = '';
5858 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
5859 if ($totalnboflines) { // If we know total nb of lines
5860 // Define nb of extra page links before and after selected page + ... + first or last
5861 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
5862
5863 if ($limit > 0) {
5864 $nbpages = ceil($totalnboflines / $limit);
5865 } else {
5866 $nbpages = 1;
5867 }
5868 $cpt = ($page - $maxnbofpage);
5869 if ($cpt < 0) {
5870 $cpt = 0;
5871 }
5872
5873 if ($cpt >= 1) {
5874 if (empty($pagenavastextinput)) {
5875 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=0'.$options.'">1</a></li>';
5876 if ($cpt > 2) {
5877 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5878 } elseif ($cpt == 2) {
5879 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=1'.$options.'">2</a></li>';
5880 }
5881 }
5882 }
5883
5884 do {
5885 if ($pagenavastextinput) {
5886 if ($cpt == $page) {
5887 $pagelist .= '<li class="pagination"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
5888 $pagelist .= '/';
5889 }
5890 } else {
5891 if ($cpt == $page) {
5892 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
5893 } else {
5894 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
5895 }
5896 }
5897 $cpt++;
5898 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
5899
5900 if (empty($pagenavastextinput)) {
5901 if ($cpt < $nbpages) {
5902 if ($cpt < $nbpages - 2) {
5903 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5904 } elseif ($cpt == $nbpages - 2) {
5905 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
5906 }
5907 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5908 }
5909 } else {
5910 //var_dump($page.' '.$cpt.' '.$nbpages);
5911 $pagelist .= '<li class="pagination paginationlastpage"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5912 }
5913 } else {
5914 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
5915 }
5916 }
5917
5918 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
5919 print_fleche_navigation($page, $file, $options, $nextpage, $pagelist, $morehtmlright, $savlimit, $totalnboflines, $hideselectlimit, $morehtmlrightbeforearrow, $hidenavigation); // output the div and ul for previous/last completed with page numbers into $pagelist
5920 }
5921
5922 // js to autoselect page field on focus
5923 if ($pagenavastextinput) {
5924 print ajax_autoselect('.pageplusone');
5925 }
5926
5927 print '</td>';
5928 print '</tr>';
5929
5930 print '</table>'."\n";
5931
5932 // Center
5933 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
5934 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
5935 }
5936
5937 print "<!-- End title -->\n\n";
5938}
5939
5956function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
5957{
5958 global $conf, $langs;
5959
5960 print '<div class="pagination"><ul>';
5961 if ($beforearrows) {
5962 print '<li class="paginationbeforearrows">';
5963 print $beforearrows;
5964 print '</li>';
5965 }
5966
5967 if (empty($hidenavigation)) {
5968 if ((int) $limit > 0 && empty($hideselectlimit)) {
5969 $pagesizechoices = '10:10,15:15,20:20,30:30,40:40,50:50,100:100,250:250,500:500,1000:1000';
5970 $pagesizechoices .= ',5000:5000,10000:10000,20000:20000';
5971 //$pagesizechoices.=',0:'.$langs->trans("All"); // Not yet supported
5972 //$pagesizechoices.=',2:2';
5973 if (getDolGlobalString('MAIN_PAGESIZE_CHOICES')) {
5974 $pagesizechoices = $conf->global->MAIN_PAGESIZE_CHOICES;
5975 }
5976
5977 print '<li class="pagination">';
5978 print '<select class="flat selectlimit" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
5979 $tmpchoice = explode(',', $pagesizechoices);
5980 $tmpkey = $limit.':'.$limit;
5981 if (!in_array($tmpkey, $tmpchoice)) {
5982 $tmpchoice[] = $tmpkey;
5983 }
5984 $tmpkey = $conf->liste_limit.':'.$conf->liste_limit;
5985 if (!in_array($tmpkey, $tmpchoice)) {
5986 $tmpchoice[] = $tmpkey;
5987 }
5988 asort($tmpchoice, SORT_NUMERIC);
5989 foreach ($tmpchoice as $val) {
5990 $selected = '';
5991 $tmp = explode(':', $val);
5992 $key = $tmp[0];
5993 $val = $tmp[1];
5994 if ($key != '' && $val != '') {
5995 if ((int) $key == (int) $limit) {
5996 $selected = ' selected="selected"';
5997 }
5998 print '<option name="'.$key.'"'.$selected.'>'.dol_escape_htmltag($val).'</option>'."\n";
5999 }
6000 }
6001 print '</select>';
6002 if ($conf->use_javascript_ajax) {
6003 print '<!-- JS CODE TO ENABLE select limit to launch submit of page -->
6004 <script>
6005 jQuery(document).ready(function () {
6006 jQuery(".selectlimit").change(function() {
6007 console.log("Change limit. Send submit");
6008 $(this).parents(\'form:first\').submit();
6009 });
6010 });
6011 </script>
6012 ';
6013 }
6014 print '</li>';
6015 }
6016 if ($page > 0) {
6017 print '<li class="pagination paginationpage paginationpageleft"><a class="paginationprevious reposition" href="'.$file.'?page='.($page - 1).$options.'"><i class="fa fa-chevron-left" title="'.dol_escape_htmltag($langs->trans("Previous")).'"></i></a></li>';
6018 }
6019 if ($betweenarrows) {
6020 print '<!--<div class="betweenarrows nowraponall inline-block">-->';
6021 print $betweenarrows;
6022 print '<!--</div>-->';
6023 }
6024 if ($nextpage > 0) {
6025 print '<li class="pagination paginationpage paginationpageright"><a class="paginationnext reposition" href="'.$file.'?page='.($page + 1).$options.'"><i class="fa fa-chevron-right" title="'.dol_escape_htmltag($langs->trans("Next")).'"></i></a></li>';
6026 }
6027 if ($afterarrows) {
6028 print '<li class="paginationafterarrows">';
6029 print $afterarrows;
6030 print '</li>';
6031 }
6032 }
6033 print '</ul></div>'."\n";
6034}
6035
6036
6048function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, $html = 0)
6049{
6050 $morelabel = '';
6051
6052 if (preg_match('/%/', $rate)) {
6053 $rate = str_replace('%', '', $rate);
6054 $addpercent = true;
6055 }
6056 $reg = array();
6057 if (preg_match('/\‍((.*)\‍)/', $rate, $reg)) {
6058 $morelabel = ' ('.$reg[1].')';
6059 $rate = preg_replace('/\s*'.preg_quote($morelabel, '/').'/', '', $rate);
6060 $morelabel = ' '.($html ? '<span class="opacitymedium">' : '').'('.$reg[1].')'.($html ? '</span>' : '');
6061 }
6062 if (preg_match('/\*/', $rate)) {
6063 $rate = str_replace('*', '', $rate);
6064 $info_bits |= 1;
6065 }
6066
6067 // If rate is '9/9/9' we don't change it. If rate is '9.000' we apply price()
6068 if (!preg_match('/\//', $rate)) {
6069 $ret = price($rate, 0, '', 0, 0).($addpercent ? '%' : '');
6070 } else {
6071 // TODO Split on / and output with a price2num to have clean numbers without ton of 000.
6072 $ret = $rate.($addpercent ? '%' : '');
6073 }
6074 if (($info_bits & 1) && $usestarfornpr >= 0) {
6075 $ret .= ' *';
6076 }
6077 $ret .= $morelabel;
6078 return $ret;
6079}
6080
6081
6097function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1, $currency_code = '')
6098{
6099 global $langs, $conf;
6100
6101 // Clean parameters
6102 if (empty($amount)) {
6103 $amount = 0; // To have a numeric value if amount not defined or = ''
6104 }
6105 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number)
6106 if ($rounding == -1) {
6107 $rounding = min(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), getDolGlobalString('MAIN_MAX_DECIMALS_TOT'));
6108 }
6109 $nbdecimal = $rounding;
6110
6111 if ($outlangs === 'none') {
6112 // Use international separators
6113 $dec = '.';
6114 $thousand = '';
6115 } else {
6116 // Output separators by default (french)
6117 $dec = ',';
6118 $thousand = ' ';
6119
6120 // If $outlangs not forced, we use use language
6121 if (!is_object($outlangs)) {
6122 $outlangs = $langs;
6123 }
6124
6125 if ($outlangs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6126 $dec = $outlangs->transnoentitiesnoconv("SeparatorDecimal");
6127 }
6128 if ($outlangs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6129 $thousand = $outlangs->transnoentitiesnoconv("SeparatorThousand");
6130 }
6131 if ($thousand == 'None') {
6132 $thousand = '';
6133 } elseif ($thousand == 'Space') {
6134 $thousand = ' ';
6135 }
6136 }
6137 //print "outlangs=".$outlangs->defaultlang." amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6138
6139 //print "amount=".$amount."-";
6140 $amount = str_replace(',', '.', $amount); // should be useless
6141 //print $amount."-";
6142 $datas = explode('.', $amount);
6143 $decpart = isset($datas[1]) ? $datas[1] : '';
6144 $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
6145 //print "decpart=".$decpart."<br>";
6146 $end = '';
6147
6148 // We increase nbdecimal if there is more decimal than asked (to not loose information)
6149 if (dol_strlen($decpart) > $nbdecimal) {
6150 $nbdecimal = dol_strlen($decpart);
6151 }
6152
6153 // If nbdecimal is higher than max to show
6154 $nbdecimalmaxshown = (int) str_replace('...', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'));
6155 if ($trunc && $nbdecimal > $nbdecimalmaxshown) {
6156 $nbdecimal = $nbdecimalmaxshown;
6157 if (preg_match('/\.\.\./i', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'))) {
6158 // If output is truncated, we show ...
6159 $end = '...';
6160 }
6161 }
6162
6163 // If force rounding
6164 if ((string) $forcerounding != '-1') {
6165 if ($forcerounding === 'MU') {
6166 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_UNIT');
6167 } elseif ($forcerounding === 'MT') {
6168 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_TOT');
6169 } elseif ($forcerounding >= 0) {
6170 $nbdecimal = $forcerounding;
6171 }
6172 }
6173
6174 // Format number
6175 $output = number_format($amount, $nbdecimal, $dec, $thousand);
6176 if ($form) {
6177 $output = preg_replace('/\s/', '&nbsp;', $output);
6178 $output = preg_replace('/\'/', '&#039;', $output);
6179 }
6180 // Add symbol of currency if requested
6181 $cursymbolbefore = $cursymbolafter = '';
6182 if ($currency_code && is_object($outlangs)) {
6183 if ($currency_code == 'auto') {
6184 $currency_code = $conf->currency;
6185 }
6186
6187 $listofcurrenciesbefore = array('AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD', 'CRC', 'ZAR');
6188 $listoflanguagesbefore = array('nl_NL');
6189 if (in_array($currency_code, $listofcurrenciesbefore) || in_array($outlangs->defaultlang, $listoflanguagesbefore)) {
6190 $cursymbolbefore .= $outlangs->getCurrencySymbol($currency_code);
6191 } else {
6192 $tmpcur = $outlangs->getCurrencySymbol($currency_code);
6193 $cursymbolafter .= ($tmpcur == $currency_code ? ' '.$tmpcur : $tmpcur);
6194 }
6195 }
6196 $output = $cursymbolbefore.$output.$end.($cursymbolafter ? ' ' : '').$cursymbolafter;
6197
6198 return $output;
6199}
6200
6225function price2num($amount, $rounding = '', $option = 0)
6226{
6227 global $langs, $conf;
6228
6229 // Clean parameters
6230 if (is_null($amount)) {
6231 $amount = '';
6232 }
6233
6234 // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
6235 // Numbers must be '1234.56'
6236 // Decimal delimiter for PHP and database SQL requests must be '.'
6237 $dec = ',';
6238 $thousand = ' ';
6239 if (is_null($langs)) { // $langs is not defined, we use english values.
6240 $dec = '.';
6241 $thousand = ',';
6242 } else {
6243 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6244 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
6245 }
6246 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6247 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
6248 }
6249 }
6250 if ($thousand == 'None') {
6251 $thousand = '';
6252 } elseif ($thousand == 'Space') {
6253 $thousand = ' ';
6254 }
6255 //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6256
6257 // Convert value to universal number format (no thousand separator, '.' as decimal separator)
6258 if ($option != 1) { // If not a PHP number or unknown, we change or clean format
6259 //print "\n".'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'<br>';
6260 if (!is_numeric($amount)) {
6261 $amount = preg_replace('/[a-zA-Z\/\\\*\‍(\‍)<>\_]/', '', $amount);
6262 }
6263
6264 if ($option == 2 && $thousand == '.' && preg_match('/\.(\d\d\d)$/', (string) $amount)) { // It means the . is used as a thousand separator and string come from input data, so 1.123 is 1123
6265 $amount = str_replace($thousand, '', $amount);
6266 }
6267
6268 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6269 // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
6270 // So if number was already a good number, it is converted into local Dolibarr setup.
6271 if (is_numeric($amount)) {
6272 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6273 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6274 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6275 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6276 $amount = number_format($amount, $nbofdec, $dec, $thousand);
6277 }
6278 //print "QQ".$amount."<br>\n";
6279
6280 // Now make replace (the main goal of function)
6281 if ($thousand != ',' && $thousand != '.') {
6282 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6283 }
6284
6285 $amount = str_replace(' ', '', $amount); // To avoid spaces
6286 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6287 $amount = str_replace($dec, '.', $amount);
6288
6289 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6290 }
6291 //print ' XX'.$amount.' '.$rounding;
6292
6293 // Now, $amount is a real PHP float number. We make a rounding if required.
6294 if ($rounding) {
6295 $nbofdectoround = '';
6296 if ($rounding == 'MU') {
6297 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_UNIT;
6298 } elseif ($rounding == 'MT') {
6299 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_TOT;
6300 } elseif ($rounding == 'MS') {
6301 $nbofdectoround = isset($conf->global->MAIN_MAX_DECIMALS_STOCK) ? $conf->global->MAIN_MAX_DECIMALS_STOCK : 5;
6302 } elseif ($rounding == 'CU') {
6303 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), 8); // TODO Use param of currency
6304 } elseif ($rounding == 'CT') {
6305 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_TOT'), 8); // TODO Use param of currency
6306 } elseif (is_numeric($rounding)) {
6307 $nbofdectoround = (int) $rounding;
6308 }
6309
6310 //print " RR".$amount.' - '.$nbofdectoround.'<br>';
6311 if (dol_strlen($nbofdectoround)) {
6312 $amount = round(is_string($amount) ? (float) $amount : $amount, $nbofdectoround); // $nbofdectoround can be 0.
6313 } else {
6314 return 'ErrorBadParameterProvidedToFunction';
6315 }
6316 //print ' SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
6317
6318 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6319 // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
6320 if (is_numeric($amount)) {
6321 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6322 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6323 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6324 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6325 $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
6326 }
6327 //print "TT".$amount.'<br>';
6328
6329 // Always make replace because each math function (like round) replace
6330 // with local values and we want a number that has a SQL string format x.y
6331 if ($thousand != ',' && $thousand != '.') {
6332 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6333 }
6334
6335 $amount = str_replace(' ', '', $amount); // To avoid spaces
6336 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6337 $amount = str_replace($dec, '.', $amount);
6338
6339 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6340 }
6341
6342 return $amount;
6343}
6344
6357function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round = -1, $forceunitoutput = 'no', $use_short_label = 0)
6358{
6359 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
6360
6361 if (($forceunitoutput == 'no' && $dimension < 1 / 10000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -6)) {
6362 $dimension = $dimension * 1000000;
6363 $unit = $unit - 6;
6364 } elseif (($forceunitoutput == 'no' && $dimension < 1 / 10 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -3)) {
6365 $dimension = $dimension * 1000;
6366 $unit = $unit - 3;
6367 } elseif (($forceunitoutput == 'no' && $dimension > 100000000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 6)) {
6368 $dimension = $dimension / 1000000;
6369 $unit = $unit + 6;
6370 } elseif (($forceunitoutput == 'no' && $dimension > 100000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 3)) {
6371 $dimension = $dimension / 1000;
6372 $unit = $unit + 3;
6373 }
6374 // Special case when we want output unit into pound or ounce
6375 /* TODO
6376 if ($unit < 90 && $type == 'weight' && is_numeric($forceunitoutput) && (($forceunitoutput == 98) || ($forceunitoutput == 99))
6377 {
6378 $dimension = // convert dimension from standard unit into ounce or pound
6379 $unit = $forceunitoutput;
6380 }
6381 if ($unit > 90 && $type == 'weight' && is_numeric($forceunitoutput) && $forceunitoutput < 90)
6382 {
6383 $dimension = // convert dimension from standard unit into ounce or pound
6384 $unit = $forceunitoutput;
6385 }*/
6386
6387 $ret = price($dimension, 0, $outputlangs, 0, 0, $round);
6388 $ret .= ' '.measuringUnitString(0, $type, $unit, $use_short_label, $outputlangs);
6389
6390 return $ret;
6391}
6392
6393
6406function get_localtax($vatrate, $local, $thirdparty_buyer = "", $thirdparty_seller = "", $vatnpr = 0)
6407{
6408 global $db, $conf, $mysoc;
6409
6410 if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
6411 $thirdparty_seller = $mysoc;
6412 }
6413
6414 dol_syslog("get_localtax tva=".$vatrate." local=".$local." thirdparty_buyer id=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->id : '')."/country_code=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->country_code : '')." thirdparty_seller id=".$thirdparty_seller->id."/country_code=".$thirdparty_seller->country_code." thirdparty_seller localtax1_assuj=".$thirdparty_seller->localtax1_assuj." thirdparty_seller localtax2_assuj=".$thirdparty_seller->localtax2_assuj);
6415
6416 $vatratecleaned = $vatrate;
6417 $reg = array();
6418 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6419 $vatratecleaned = trim($reg[1]);
6420 $vatratecode = $reg[2];
6421 }
6422
6423 /*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
6424 {
6425 return 0;
6426 }*/
6427
6428 // Some test to guess with no need to make database access
6429 if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
6430 if ($local == 1) {
6431 if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
6432 return 0;
6433 }
6434 if ($thirdparty_seller->id == $mysoc->id) {
6435 if (!$thirdparty_buyer->localtax1_assuj) {
6436 return 0;
6437 }
6438 } else {
6439 if (!$thirdparty_seller->localtax1_assuj) {
6440 return 0;
6441 }
6442 }
6443 }
6444
6445 if ($local == 2) {
6446 //if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
6447 if (!$mysoc->localtax2_assuj) {
6448 return 0; // If main vat is 0, IRPF may be different than 0.
6449 }
6450 if ($thirdparty_seller->id == $mysoc->id) {
6451 if (!$thirdparty_buyer->localtax2_assuj) {
6452 return 0;
6453 }
6454 } else {
6455 if (!$thirdparty_seller->localtax2_assuj) {
6456 return 0;
6457 }
6458 }
6459 }
6460 } else {
6461 if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
6462 return 0;
6463 }
6464 if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
6465 return 0;
6466 }
6467 }
6468
6469 // For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
6470 if (in_array($mysoc->country_code, array('ES'))) {
6471 $conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
6472 }
6473
6474 // Search local taxes
6475 if (getDolGlobalString('MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY')) {
6476 if ($local == 1) {
6477 if ($thirdparty_seller != $mysoc) {
6478 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6479 return $thirdparty_seller->localtax1_value;
6480 }
6481 } else { // i am the seller
6482 if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
6483 return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
6484 }
6485 }
6486 }
6487 if ($local == 2) {
6488 if ($thirdparty_seller != $mysoc) {
6489 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6490 // TODO We should also return value defined on thirdparty only if defined
6491 return $thirdparty_seller->localtax2_value;
6492 }
6493 } else { // i am the seller
6494 if (in_array($mysoc->country_code, array('ES'))) {
6495 return $thirdparty_buyer->localtax2_value;
6496 } else {
6497 return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
6498 }
6499 }
6500 }
6501 }
6502
6503 // By default, search value of local tax on line of common tax
6504 $sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
6505 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6506 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
6507 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6508 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6509 if (!empty($vatratecode)) {
6510 $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
6511 } else {
6512 $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
6513 }
6514
6515 $resql = $db->query($sql);
6516
6517 if ($resql) {
6518 $obj = $db->fetch_object($resql);
6519 if ($obj) {
6520 if ($local == 1) {
6521 return $obj->localtax1;
6522 } elseif ($local == 2) {
6523 return $obj->localtax2;
6524 }
6525 }
6526 }
6527
6528 return 0;
6529}
6530
6531
6540function isOnlyOneLocalTax($local)
6541{
6542 $tax = get_localtax_by_third($local);
6543
6544 $valors = explode(":", $tax);
6545
6546 if (count($valors) > 1) {
6547 return false;
6548 } else {
6549 return true;
6550 }
6551}
6552
6560{
6561 global $db, $mysoc;
6562
6563 $sql = " SELECT t.localtax".$local." as localtax";
6564 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_pays";
6565 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.active = 1 AND t.entity IN (".getEntity('c_tva').") AND t.taux = (";
6566 $sql .= "SELECT MAX(tt.taux) FROM ".MAIN_DB_PREFIX."c_tva as tt INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = tt.fk_pays";
6567 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.entity IN (".getEntity('c_tva').") AND tt.active = 1)";
6568 $sql .= " AND t.localtax".$local."_type <> '0'";
6569 $sql .= " ORDER BY t.rowid DESC";
6570
6571 $resql = $db->query($sql);
6572 if ($resql) {
6573 $obj = $db->fetch_object($resql);
6574 if ($obj) {
6575 return $obj->localtax;
6576 } else {
6577 return '0';
6578 }
6579 }
6580
6581 return 'Error';
6582}
6583
6584
6596function getTaxesFromId($vatrate, $buyer = null, $seller = null, $firstparamisid = 1)
6597{
6598 global $db, $mysoc;
6599
6600 dol_syslog("getTaxesFromId vat id or rate = ".$vatrate);
6601
6602 // Search local taxes
6603 $sql = "SELECT t.rowid, t.code, t.taux as rate, t.recuperableonly as npr, t.accountancy_code_sell, t.accountancy_code_buy,";
6604 $sql .= " t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type";
6605 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6606 if ($firstparamisid) {
6607 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6608 } else {
6609 $vatratecleaned = $vatrate;
6610 $vatratecode = '';
6611 $reg = array();
6612 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6613 $vatratecleaned = $reg[1];
6614 $vatratecode = $reg[2];
6615 }
6616
6617 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6618 /*if ($mysoc->country_code == 'ES') $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($buyer->country_code)."'"; // vat in spain use the buyer country ??
6619 else $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";*/
6620 $sql .= " WHERE t.fk_pays = c.rowid";
6621 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) {
6622 $sql .= " AND c.code = '".$db->escape($buyer->country_code)."'";
6623 } else {
6624 $sql .= " AND c.code = '".$db->escape($seller->country_code)."'";
6625 }
6626 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6627 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6628 if ($vatratecode) {
6629 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6630 }
6631 }
6632
6633 $resql = $db->query($sql);
6634 if ($resql) {
6635 $obj = $db->fetch_object($resql);
6636 if ($obj) {
6637 return array(
6638 'rowid'=>$obj->rowid,
6639 'code'=>$obj->code,
6640 'rate'=>$obj->rate,
6641 'localtax1'=>$obj->localtax1,
6642 'localtax1_type'=>$obj->localtax1_type,
6643 'localtax2'=>$obj->localtax2,
6644 'localtax2_type'=>$obj->localtax2_type,
6645 'npr'=>$obj->npr,
6646 'accountancy_code_sell'=>$obj->accountancy_code_sell,
6647 'accountancy_code_buy'=>$obj->accountancy_code_buy
6648 );
6649 } else {
6650 return array();
6651 }
6652 } else {
6653 dol_print_error($db);
6654 }
6655
6656 return array();
6657}
6658
6675function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid = 0)
6676{
6677 global $db, $mysoc;
6678
6679 dol_syslog("getLocalTaxesFromRate vatrate=".$vatrate." local=".$local);
6680
6681 // Search local taxes
6682 $sql = "SELECT t.taux as rate, t.code, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.accountancy_code_sell, t.accountancy_code_buy";
6683 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6684 if ($firstparamisid) {
6685 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6686 } else {
6687 $vatratecleaned = $vatrate;
6688 $vatratecode = '';
6689 $reg = array();
6690 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "x.x (yy)"
6691 $vatratecleaned = $reg[1];
6692 $vatratecode = $reg[2];
6693 }
6694
6695 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6696 if (!empty($mysoc) && $mysoc->country_code == 'ES') {
6697 $countrycodetouse = ((empty($buyer) || empty($buyer->country_code)) ? $mysoc->country_code : $buyer->country_code);
6698 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'"; // local tax in spain use the buyer country ??
6699 } else {
6700 $countrycodetouse = ((empty($seller) || empty($seller->country_code)) ? $mysoc->country_code : $seller->country_code);
6701 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'";
6702 }
6703 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6704 if ($vatratecode) {
6705 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6706 }
6707 }
6708
6709 $resql = $db->query($sql);
6710 if ($resql) {
6711 $obj = $db->fetch_object($resql);
6712
6713 if ($obj) {
6714 $vateratestring = $obj->rate.($obj->code ? ' ('.$obj->code.')' : '');
6715
6716 if ($local == 1) {
6717 return array($obj->localtax1_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6718 } elseif ($local == 2) {
6719 return array($obj->localtax2_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6720 } else {
6721 return array($obj->localtax1_type, get_localtax($vateratestring, 1, $buyer, $seller), $obj->localtax2_type, get_localtax($vateratestring, 2, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6722 }
6723 }
6724 }
6725
6726 return array();
6727}
6728
6739function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice = 0)
6740{
6741 global $db, $conf, $mysoc;
6742
6743 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6744
6745 $ret = 0;
6746 $found = 0;
6747
6748 if ($idprod > 0) {
6749 // Load product
6750 $product = new Product($db);
6751 $product->fetch($idprod);
6752
6753 if ($mysoc->country_code == $thirdpartytouse->country_code) {
6754 // If country to consider is ours
6755 if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object
6756 $result = $product->get_buyprice($idprodfournprice, 0, 0, 0);
6757 if ($result > 0) {
6758 $ret = $product->vatrate_supplier;
6759 if ($product->default_vat_code_supplier) {
6760 $ret .= ' ('.$product->default_vat_code_supplier.')';
6761 }
6762 $found = 1;
6763 }
6764 }
6765 if (!$found) {
6766 $ret = $product->tva_tx; // Default sales vat of product
6767 if ($product->default_vat_code) {
6768 $ret .= ' ('.$product->default_vat_code.')';
6769 }
6770 $found = 1;
6771 }
6772 } else {
6773 // TODO Read default product vat according to product and an other countrycode.
6774 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6775 }
6776 }
6777
6778 if (!$found) {
6779 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
6780 // If vat of product for the country not found or not defined, we return the first rate found (sorting on use_default, then on higher vat of country).
6781 $sql = "SELECT t.taux as vat_rate, t.code as default_vat_code";
6782 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6783 $sql .= " WHERE t.active = 1 AND t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdpartytouse->country_code)."'";
6784 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6785 $sql .= " ORDER BY t.use_default DESC, t.taux DESC, t.code ASC, t.recuperableonly ASC";
6786 $sql .= $db->plimit(1);
6787
6788 $resql = $db->query($sql);
6789 if ($resql) {
6790 $obj = $db->fetch_object($resql);
6791 if ($obj) {
6792 $ret = $obj->vat_rate;
6793 if ($obj->default_vat_code) {
6794 $ret .= ' ('.$obj->default_vat_code.')';
6795 }
6796 }
6797 $db->free($resql);
6798 } else {
6799 dol_print_error($db);
6800 }
6801 } else {
6802 // Forced value if autodetect fails. MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS can be
6803 // '1.23'
6804 // or '1.23 (CODE)'
6805 $defaulttx = '';
6806 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
6807 $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6808 }
6809 /*if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6810 $defaultcode = $reg[1];
6811 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6812 }*/
6813
6814 $ret = $defaulttx;
6815 }
6816 }
6817
6818 dol_syslog("get_product_vat_for_country: ret=".$ret);
6819 return $ret;
6820}
6821
6831function get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
6832{
6833 global $db, $mysoc;
6834
6835 if (!class_exists('Product')) {
6836 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6837 }
6838
6839 $ret = 0;
6840 $found = 0;
6841
6842 if ($idprod > 0) {
6843 // Load product
6844 $product = new Product($db);
6845 $result = $product->fetch($idprod);
6846
6847 if ($mysoc->country_code == $thirdpartytouse->country_code) { // If selling country is ours
6848 /* Not defined yet, so we don't use this
6849 if ($local==1) $ret=$product->localtax1_tx;
6850 elseif ($local==2) $ret=$product->localtax2_tx;
6851 $found=1;
6852 */
6853 } else {
6854 // TODO Read default product vat according to product and another countrycode.
6855 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6856 }
6857 }
6858
6859 if (!$found) {
6860 // If vat of product for the country not found or not defined, we return higher vat of country.
6861 $sql = "SELECT taux as vat_rate, localtax1, localtax2";
6862 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6863 $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code='".$db->escape($thirdpartytouse->country_code)."'";
6864 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6865 $sql .= " ORDER BY t.taux DESC, t.recuperableonly ASC";
6866 $sql .= $db->plimit(1);
6867
6868 $resql = $db->query($sql);
6869 if ($resql) {
6870 $obj = $db->fetch_object($resql);
6871 if ($obj) {
6872 if ($local == 1) {
6873 $ret = $obj->localtax1;
6874 } elseif ($local == 2) {
6875 $ret = $obj->localtax2;
6876 }
6877 }
6878 } else {
6879 dol_print_error($db);
6880 }
6881 }
6882
6883 dol_syslog("get_product_localtax_for_country: ret=".$ret);
6884 return $ret;
6885}
6886
6903function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6904{
6905 global $conf;
6906
6907 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6908
6909 // Note: possible values for tva_assuj are 0/1 or franchise/reel
6910 $seller_use_vat = ((is_numeric($thirdparty_seller->tva_assuj) && !$thirdparty_seller->tva_assuj) || (!is_numeric($thirdparty_seller->tva_assuj) && $thirdparty_seller->tva_assuj == 'franchise')) ? 0 : 1;
6911
6912 $seller_country_code = $thirdparty_seller->country_code;
6913 $seller_in_cee = isInEEC($thirdparty_seller);
6914
6915 $buyer_country_code = $thirdparty_buyer->country_code;
6916 $buyer_in_cee = isInEEC($thirdparty_buyer);
6917
6918 dol_syslog("get_default_tva: seller use vat=".$seller_use_vat.", seller country=".$seller_country_code.", seller in cee=".$seller_in_cee.", buyer vat number=".$thirdparty_buyer->tva_intra." buyer country=".$buyer_country_code.", buyer in cee=".$buyer_in_cee.", idprod=".$idprod.", idprodfournprice=".$idprodfournprice.", SERVICE_ARE_ECOMMERCE_200238EC=".(getDolGlobalString('SERVICES_ARE_ECOMMERCE_200238EC') ? $conf->global->SERVICES_ARE_ECOMMERCE_200238EC : ''));
6919
6920 // If services are eServices according to EU Council Directive 2002/38/EC (http://ec.europa.eu/taxation_customs/taxation/vat/traders/e-commerce/article_1610_en.htm)
6921 // we use the buyer VAT.
6922 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) {
6923 if ($seller_in_cee && $buyer_in_cee) {
6924 $isacompany = $thirdparty_buyer->isACompany();
6925 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6926 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6927 if (!isValidVATID($thirdparty_buyer)) {
6928 $isacompany = 0;
6929 }
6930 }
6931
6932 if (!$isacompany) {
6933 //print 'VATRULE 0';
6934 return get_product_vat_for_country($idprod, $thirdparty_buyer, $idprodfournprice);
6935 }
6936 }
6937 }
6938
6939 // If seller does not use VAT, default VAT is 0. End of rule.
6940 if (!$seller_use_vat) {
6941 //print 'VATRULE 1';
6942 return 0;
6943 }
6944
6945 // If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule.
6946 if (($seller_country_code == $buyer_country_code)
6947 || (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC')))) { // Warning ->country_code not always defined
6948 //print 'VATRULE 2';
6949 $tmpvat = get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6950
6951 if ($seller_country_code == 'IN' && getDolGlobalString('MAIN_SALETAX_AUTOSWITCH_I_CS_FOR_INDIA')) {
6952 // Special case for india.
6953 //print 'VATRULE 2b';
6954 $reg = array();
6955 if (preg_match('/C+S-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id != $thirdparty_buyer->state_id) {
6956 // we must revert the C+S into I
6957 $tmpvat = str_replace("C+S", "I", $tmpvat);
6958 } elseif (preg_match('/I-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id == $thirdparty_buyer->state_id) {
6959 // we must revert the I into C+S
6960 $tmpvat = str_replace("I", "C+S", $tmpvat);
6961 }
6962 }
6963
6964 return $tmpvat;
6965 }
6966
6967 // If (seller and buyer in the European Community) and (property sold = new means of transport such as car, boat, plane) then VAT by default = 0 (VAT must be paid by the buyer to the tax center of his country and not to the seller). End of rule.
6968 // 'VATRULE 3' - Not supported
6969
6970 // If (seller and buyer in the European Community) and (buyer = individual) then VAT by default = VAT of the product sold. End of rule
6971 // If (seller and buyer in European Community) and (buyer = company) then VAT by default=0. End of rule
6972 if (($seller_in_cee && $buyer_in_cee)) {
6973 $isacompany = $thirdparty_buyer->isACompany();
6974 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6975 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6976 if (!isValidVATID($thirdparty_buyer)) {
6977 $isacompany = 0;
6978 }
6979 }
6980
6981 if (!$isacompany) {
6982 //print 'VATRULE 4';
6983 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6984 } else {
6985 //print 'VATRULE 5';
6986 return 0;
6987 }
6988 }
6989
6990 // If (seller in the European Community and buyer outside the European Community and private buyer) then VAT by default = VAT of the product sold. End of rule
6991 // I don't see any use case that need this rule.
6992 if (getDolGlobalString('MAIN_USE_VAT_OF_PRODUCT_FOR_INDIVIDUAL_CUSTOMER_OUT_OF_EEC') && empty($buyer_in_cee)) {
6993 $isacompany = $thirdparty_buyer->isACompany();
6994 if (!$isacompany) {
6995 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6996 //print 'VATRULE extra';
6997 }
6998 }
6999
7000 // Otherwise the VAT proposed by default=0. End of rule.
7001 // Rem: This means that at least one of the 2 is outside the European Community and the country differs
7002 //print 'VATRULE 6';
7003 return 0;
7004}
7005
7006
7017function get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
7018{
7019 global $db;
7020
7021 if ($idprodfournprice > 0) {
7022 if (!class_exists('ProductFournisseur')) {
7023 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
7024 }
7025 $prodprice = new ProductFournisseur($db);
7026 $prodprice->fetch_product_fournisseur_price($idprodfournprice);
7027 return $prodprice->fourn_tva_npr;
7028 } elseif ($idprod > 0) {
7029 if (!class_exists('Product')) {
7030 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
7031 }
7032 $prod = new Product($db);
7033 $prod->fetch($idprod);
7034 return $prod->tva_npr;
7035 }
7036
7037 return 0;
7038}
7039
7053function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod = 0)
7054{
7055 global $mysoc;
7056
7057 if (!is_object($thirdparty_seller)) {
7058 return -1;
7059 }
7060 if (!is_object($thirdparty_buyer)) {
7061 return -1;
7062 }
7063
7064 if ($local == 1) { // Localtax 1
7065 if ($mysoc->country_code == 'ES') {
7066 if (is_numeric($thirdparty_buyer->localtax1_assuj) && !$thirdparty_buyer->localtax1_assuj) {
7067 return 0;
7068 }
7069 } else {
7070 // Si vendeur non assujeti a Localtax1, localtax1 par default=0
7071 if (is_numeric($thirdparty_seller->localtax1_assuj) && !$thirdparty_seller->localtax1_assuj) {
7072 return 0;
7073 }
7074 if (!is_numeric($thirdparty_seller->localtax1_assuj) && $thirdparty_seller->localtax1_assuj == 'localtax1off') {
7075 return 0;
7076 }
7077 }
7078 } elseif ($local == 2) { //I Localtax 2
7079 // Si vendeur non assujeti a Localtax2, localtax2 par default=0
7080 if (is_numeric($thirdparty_seller->localtax2_assuj) && !$thirdparty_seller->localtax2_assuj) {
7081 return 0;
7082 }
7083 if (!is_numeric($thirdparty_seller->localtax2_assuj) && $thirdparty_seller->localtax2_assuj == 'localtax2off') {
7084 return 0;
7085 }
7086 }
7087
7088 if ($thirdparty_seller->country_code == $thirdparty_buyer->country_code) {
7089 return get_product_localtax_for_country($idprod, $local, $thirdparty_seller);
7090 }
7091
7092 return 0;
7093}
7094
7103function yn($yesno, $case = 1, $color = 0)
7104{
7105 global $langs;
7106
7107 $result = 'unknown';
7108 $classname = '';
7109 if ($yesno == 1 || (isset($yesno) && (strtolower($yesno) == 'yes' || strtolower($yesno) == 'true'))) { // A mettre avant test sur no a cause du == 0
7110 $result = $langs->trans('yes');
7111 if ($case == 1 || $case == 3) {
7112 $result = $langs->trans("Yes");
7113 }
7114 if ($case == 2) {
7115 $result = '<input type="checkbox" value="1" checked disabled>';
7116 }
7117 if ($case == 3) {
7118 $result = '<input type="checkbox" value="1" checked disabled> '.$result;
7119 }
7120
7121 $classname = 'ok';
7122 } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') {
7123 $result = $langs->trans("no");
7124 if ($case == 1 || $case == 3) {
7125 $result = $langs->trans("No");
7126 }
7127 if ($case == 2) {
7128 $result = '<input type="checkbox" value="0" disabled>';
7129 }
7130 if ($case == 3) {
7131 $result = '<input type="checkbox" value="0" disabled> '.$result;
7132 }
7133
7134 if ($color == 2) {
7135 $classname = 'ok';
7136 } else {
7137 $classname = 'error';
7138 }
7139 }
7140 if ($color) {
7141 return '<span class="'.$classname.'">'.$result.'</span>';
7142 }
7143 return $result;
7144}
7145
7161function get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart = '')
7162{
7163 global $conf;
7164
7165 if (empty($modulepart) && !empty($object->module)) {
7166 $modulepart = $object->module;
7167 }
7168
7169 $path = '';
7170
7171 $arrayforoldpath = array('cheque', 'category', 'holiday', 'supplier_invoice', 'invoice_supplier', 'mailing', 'supplier_payment');
7172 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
7173 $arrayforoldpath[] = 'product';
7174 }
7175 if (!empty($level) && in_array($modulepart, $arrayforoldpath)) {
7176 // This part should be removed once all code is using "get_exdir" to forge path, with parameter $object and $modulepart provided.
7177 if (empty($alpha)) {
7178 $num = preg_replace('/([^0-9])/i', '', $num);
7179 } else {
7180 $num = preg_replace('/^.*\-/i', '', $num);
7181 }
7182 $num = substr("000".$num, -$level);
7183 if ($level == 1) {
7184 $path = substr($num, 0, 1);
7185 }
7186 if ($level == 2) {
7187 $path = substr($num, 1, 1).'/'.substr($num, 0, 1);
7188 }
7189 if ($level == 3) {
7190 $path = substr($num, 2, 1).'/'.substr($num, 1, 1).'/'.substr($num, 0, 1);
7191 }
7192 } else {
7193 // We will enhance here a common way of forging path for document storage.
7194 // In a future, we may distribute directories on several levels depending on setup and object.
7195 // Here, $object->id, $object->ref and $modulepart are required.
7196 //var_dump($modulepart);
7197 $path = dol_sanitizeFileName(empty($object->ref) ? (string) $object->id : $object->ref);
7198 }
7199
7200 if (empty($withoutslash) && !empty($path)) {
7201 $path .= '/';
7202 }
7203
7204 return $path;
7205}
7206
7215function dol_mkdir($dir, $dataroot = '', $newmask = '')
7216{
7217 global $conf;
7218
7219 dol_syslog("functions.lib::dol_mkdir: dir=".$dir, LOG_INFO);
7220
7221 $dir_osencoded = dol_osencode($dir);
7222 if (@is_dir($dir_osencoded)) {
7223 return 0;
7224 }
7225
7226 $nberr = 0;
7227 $nbcreated = 0;
7228
7229 $ccdir = '';
7230 if (!empty($dataroot)) {
7231 // Remove data root from loop
7232 $dir = str_replace($dataroot.'/', '', $dir);
7233 $ccdir = $dataroot.'/';
7234 }
7235
7236 $cdir = explode("/", $dir);
7237 $num = count($cdir);
7238 for ($i = 0; $i < $num; $i++) {
7239 if ($i > 0) {
7240 $ccdir .= '/'.$cdir[$i];
7241 } else {
7242 $ccdir .= $cdir[$i];
7243 }
7244 $regs = array();
7245 if (preg_match("/^.:$/", $ccdir, $regs)) {
7246 continue; // Si chemin Windows incomplet, on poursuit par rep suivant
7247 }
7248
7249 // Attention, le is_dir() peut echouer bien que le rep existe.
7250 // (ex selon config de open_basedir)
7251 if ($ccdir) {
7252 $ccdir_osencoded = dol_osencode($ccdir);
7253 if (!@is_dir($ccdir_osencoded)) {
7254 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.", LOG_DEBUG);
7255
7256 umask(0);
7257 $dirmaskdec = octdec((string) $newmask);
7258 if (empty($newmask)) {
7259 $dirmaskdec = !getDolGlobalString('MAIN_UMASK') ? octdec('0755') : octdec($conf->global->MAIN_UMASK);
7260 }
7261 $dirmaskdec |= octdec('0111'); // Set x bit required for directories
7262 if (!@mkdir($ccdir_osencoded, $dirmaskdec)) {
7263 // Si le is_dir a renvoye une fausse info, alors on passe ici.
7264 dol_syslog("functions.lib::dol_mkdir: Fails to create directory '".$ccdir."' or directory already exists.", LOG_WARNING);
7265 $nberr++;
7266 } else {
7267 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' created", LOG_DEBUG);
7268 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignore
7269 $nbcreated++;
7270 }
7271 } else {
7272 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignores
7273 }
7274 }
7275 }
7276 return ($nberr ? -$nberr : $nbcreated);
7277}
7278
7279
7287function dolChmod($filepath, $newmask = '')
7288{
7289 global $conf;
7290
7291 if (!empty($newmask)) {
7292 @chmod($filepath, octdec($newmask));
7293 } elseif (getDolGlobalString('MAIN_UMASK')) {
7294 @chmod($filepath, octdec($conf->global->MAIN_UMASK));
7295 }
7296}
7297
7298
7305{
7306 return '<span class="fieldrequired">*</span>';
7307}
7308
7309
7326function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = 'UTF-8', $strip_tags = 0, $removedoublespaces = 1)
7327{
7328 if (is_null($stringtoclean)) {
7329 return '';
7330 }
7331
7332 if ($removelinefeed == 2) {
7333 $stringtoclean = preg_replace('/<br[^>]*>(\n|\r)+/ims', '<br>', $stringtoclean);
7334 }
7335 $temp = preg_replace('/<br[^>]*>/i', "\n", $stringtoclean);
7336
7337 // We remove entities BEFORE stripping (in case of an open separator char that is entity encoded and not the closing other, the strip will fails)
7338 $temp = dol_html_entity_decode($temp, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7339
7340 $temp = str_replace('< ', '__ltspace__', $temp);
7341
7342 if ($strip_tags) {
7343 $temp = strip_tags($temp);
7344 } else {
7345 // Remove '<' into remainging, so remove non closing html tags like '<abc' or '<<abc'. Note: '<123abc' is not a html tag (can be kept), but '<abc123' is (must be removed).
7346 $pattern = "/<[^<>]+>/";
7347 // Example of $temp: <a href="/myurl" title="<u>A title</u>">0000-021</a>
7348 // pass 1 - $temp after pass 1: <a href="/myurl" title="A title">0000-021
7349 // pass 2 - $temp after pass 2: 0000-021
7350 $tempbis = $temp;
7351 do {
7352 $temp = $tempbis;
7353 $tempbis = str_replace('<>', '', $temp); // No reason to have this into a text, except if value is to try bypass the next html cleaning
7354 $tempbis = preg_replace($pattern, '', $tempbis);
7355 //$idowhile++; print $temp.'-'.$tempbis."\n"; if ($idowhile > 100) break;
7356 } while ($tempbis != $temp);
7357
7358 $temp = $tempbis;
7359
7360 // Remove '<' into remaining, so remove non closing html tags like '<abc' or '<<abc'. Note: '<123abc' is not a html tag (can be kept), but '<abc123' is (must be removed).
7361 $temp = preg_replace('/<+([a-z]+)/i', '\1', $temp);
7362 }
7363
7364 $temp = dol_html_entity_decode($temp, ENT_COMPAT, $pagecodeto);
7365
7366 // Remove also carriage returns
7367 if ($removelinefeed == 1) {
7368 $temp = str_replace(array("\r\n", "\r", "\n"), " ", $temp);
7369 }
7370
7371 // And double quotes
7372 if ($removedoublespaces) {
7373 while (strpos($temp, " ")) {
7374 $temp = str_replace(" ", " ", $temp);
7375 }
7376 }
7377
7378 $temp = str_replace('__ltspace__', '< ', $temp);
7379
7380 return trim($temp);
7381}
7382
7398function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1, $cleanalsojavascript = 0, $allowiframe = 0, $allowed_tags = array(), $allowlink = 0)
7399{
7400 if (empty($allowed_tags)) {
7401 $allowed_tags = array(
7402 "html", "head", "meta", "body", "article", "a", "abbr", "b", "blockquote", "br", "cite", "div", "dl", "dd", "dt", "em", "font", "img", "ins", "hr", "i", "li",
7403 "ol", "p", "q", "s", "span", "strike", "strong", "title", "table", "tr", "th", "td", "u", "ul", "sup", "sub", "blockquote", "pre", "h1", "h2", "h3", "h4", "h5", "h6",
7404 "header", "footer", "nav", "section", "menu", "menuitem" // html5 tags
7405 );
7406 }
7407 $allowed_tags[] = "comment"; // this tags is added to manage comment <!--...--> that are replaced into <comment>...</comment>
7408 if ($allowiframe) {
7409 if (!in_array('iframe', $allowed_tags)) {
7410 $allowed_tags[] = "iframe";
7411 }
7412 }
7413 if ($allowlink) {
7414 if (!in_array('link', $allowed_tags)) {
7415 $allowed_tags[] = "link";
7416 }
7417 }
7418
7419 $allowed_tags_string = join("><", $allowed_tags);
7420 $allowed_tags_string = '<'.$allowed_tags_string.'>';
7421
7422 $stringtoclean = str_replace('<!DOCTYPE html>', '__!DOCTYPE_HTML__', $stringtoclean); // Replace DOCTYPE to avoid to have it removed by the strip_tags
7423
7424 $stringtoclean = dol_string_nounprintableascii($stringtoclean, 0);
7425
7426 //$stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
7427 $stringtoclean = preg_replace('/<!--([^>]*)-->/', '<comment>\1</comment>', $stringtoclean);
7428
7429 $stringtoclean = preg_replace('/&colon;/i', ':', $stringtoclean);
7430 $stringtoclean = preg_replace('/&#58;|&#0+58|&#x3A/i', '', $stringtoclean); // refused string ':' encoded (no reason to have a : encoded like this) to disable 'javascript:...'
7431
7432 $temp = strip_tags($stringtoclean, $allowed_tags_string); // Warning: This remove also undesired </>, so may changes string obfuscated with </> that pass the injection detection into a harmfull string
7433
7434 if ($cleanalsosomestyles) { // Clean for remaining html tags
7435 $temp = preg_replace('/position\s*:\s*(absolute|fixed)\s*!\s*important/i', '', $temp); // Note: If hacker try to introduce css comment into string to bypass this regex, the string must also be encoded by the dol_htmlentitiesbr during output so it become harmless
7436 }
7437 if ($removeclassattribute) { // Clean for remaining html tags
7438 $temp = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $temp);
7439 }
7440
7441 // Remove 'javascript:' that we should not find into a text with
7442 // Warning: This is not reliable to fight against obfuscated javascript, there is a lot of other solution to include js into a common html tag (only filtered by a GETPOST(.., powerfullfilter)).
7443 if ($cleanalsojavascript) {
7444 $temp = preg_replace('/j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*:/i', '', $temp);
7445 }
7446
7447 $temp = str_replace('__!DOCTYPE_HTML__', '<!DOCTYPE html>', $temp); // Restore the DOCTYPE
7448
7449 $temp = preg_replace('/<comment>([^>]*)<\/comment>/', '<!--\1-->', $temp); // Restore html comments
7450
7451
7452 return $temp;
7453}
7454
7455
7467function dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes = null)
7468{
7469 if (is_null($allowed_attributes)) {
7470 $allowed_attributes = array(
7471 "allow", "allowfullscreen", "alt", "class", "contenteditable", "data-html", "frameborder", "height", "href", "id", "name", "src", "style", "target", "title", "width",
7472 // HTML5
7473 "header", "footer", "nav", "section", "menu", "menuitem"
7474 );
7475 }
7476
7477 if (class_exists('DOMDocument') && !empty($stringtoclean)) {
7478 $stringtoclean = '<?xml encoding="UTF-8"><html><body>'.$stringtoclean.'</body></html>';
7479
7480 // Warning: loadHTML does not support HTML5 on old libxml versions.
7481 $dom = new DOMDocument(null, 'UTF-8');
7482 $dom->loadHTML($stringtoclean, LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7483
7484 if (is_object($dom)) {
7485 for ($els = $dom->getElementsByTagname('*'), $i = $els->length - 1; $i >= 0; $i--) {
7486 for ($attrs = $els->item($i)->attributes, $ii = $attrs->length - 1; $ii >= 0; $ii--) {
7487 //var_dump($attrs->item($ii));
7488 if (!empty($attrs->item($ii)->name)) {
7489 if (! in_array($attrs->item($ii)->name, $allowed_attributes)) {
7490 // Delete attribute if not into allowed_attributes
7491 $els->item($i)->removeAttribute($attrs->item($ii)->name);
7492 } elseif (in_array($attrs->item($ii)->name, array('style'))) {
7493 // If attribute is 'style'
7494 $valuetoclean = $attrs->item($ii)->value;
7495
7496 if (isset($valuetoclean)) {
7497 do {
7498 $oldvaluetoclean = $valuetoclean;
7499 $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments
7500 $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean);
7501 if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags.
7502 $valuetoclean = preg_replace('/display\s*:/mi', '', $valuetoclean);
7503 $valuetoclean = preg_replace('/z-index\s*:/mi', '', $valuetoclean);
7504 $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*:/mi', '', $valuetoclean);
7505 }
7506
7507 // We do not allow logout|passwordforgotten.php and action= into the content of a "style" tag
7508 $valuetoclean = preg_replace('/(logout|passwordforgotten)\.php/mi', '', $valuetoclean);
7509 $valuetoclean = preg_replace('/action=/mi', '', $valuetoclean);
7510 } while ($oldvaluetoclean != $valuetoclean);
7511 }
7512
7513 $attrs->item($ii)->value = $valuetoclean;
7514 }
7515 }
7516 }
7517 }
7518 }
7519
7520 $return = $dom->saveHTML(); // This may add a LF at end of lines, so we will trim later
7521 //$return = '<html><body>aaaa</p>bb<p>ssdd</p>'."\n<p>aaa</p>aa<p>bb</p>";
7522
7523 $return = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $return);
7524 $return = preg_replace('/^'.preg_quote('<html><body>', '/').'/', '', $return);
7525 $return = preg_replace('/'.preg_quote('</body></html>', '/').'$/', '', $return);
7526 return trim($return);
7527 } else {
7528 return $stringtoclean;
7529 }
7530}
7531
7543function dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags = array('textarea'), $cleanalsosomestyles = 0)
7544{
7545 $temp = $stringtoclean;
7546 foreach ($disallowed_tags as $tagtoremove) {
7547 $temp = preg_replace('/<\/?'.$tagtoremove.'>/', '', $temp);
7548 $temp = preg_replace('/<\/?'.$tagtoremove.'\s+[^>]*>/', '', $temp);
7549 }
7550
7551 if ($cleanalsosomestyles) {
7552 $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
7553 }
7554
7555 return $temp;
7556}
7557
7558
7568function dolGetFirstLineOfText($text, $nboflines = 1, $charset = 'UTF-8')
7569{
7570 if ($nboflines == 1) {
7571 if (dol_textishtml($text)) {
7572 $firstline = preg_replace('/<br[^>]*>.*$/s', '', $text); // The s pattern modifier means the . can match newline characters
7573 $firstline = preg_replace('/<div[^>]*>.*$/s', '', $firstline); // The s pattern modifier means the . can match newline characters
7574 } else {
7575 if (isset($text)) {
7576 $firstline = preg_replace('/[\n\r].*/', '', $text);
7577 } else {
7578 $firstline = '';
7579 }
7580 }
7581 return $firstline.(isset($firstline) && isset($text) && (strlen($firstline) != strlen($text)) ? '...' : '');
7582 } else {
7583 $ishtml = 0;
7584 if (dol_textishtml($text)) {
7585 $text = preg_replace('/\n/', '', $text);
7586 $ishtml = 1;
7587 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7588 } else {
7589 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7590 }
7591
7592 $text = strtr($text, $repTable);
7593 if ($charset == 'UTF-8') {
7594 $pattern = '/(<br[^>]*>)/Uu';
7595 } else {
7596 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7597 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7598 }
7599 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7600
7601 $firstline = '';
7602 $i = 0;
7603 $countline = 0;
7604 $lastaddediscontent = 1;
7605 while ($countline < $nboflines && isset($a[$i])) {
7606 if (preg_match('/<br[^>]*>/', $a[$i])) {
7607 if (array_key_exists($i+1, $a) && !empty($a[$i+1])) {
7608 $firstline .= ($ishtml ? "<br>\n" : "\n");
7609 // Is it a br for a new line of after a printed line ?
7610 if (!$lastaddediscontent) {
7611 $countline++;
7612 }
7613 $lastaddediscontent = 0;
7614 }
7615 } else {
7616 $firstline .= $a[$i];
7617 $lastaddediscontent = 1;
7618 $countline++;
7619 }
7620 $i++;
7621 }
7622
7623 $adddots = (isset($a[$i]) && (!preg_match('/<br[^>]*>/', $a[$i]) || (array_key_exists($i+1, $a) && !empty($a[$i+1]))));
7624 //unset($a);
7625 $ret = $firstline.($adddots ? '...' : '');
7626 //exit;
7627 return $ret;
7628 }
7629}
7630
7631
7643function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false)
7644{
7645 if (is_null($stringtoencode)) {
7646 return '';
7647 }
7648
7649 if (!$nl2brmode) {
7650 return nl2br($stringtoencode, $forxml);
7651 } else {
7652 $ret = preg_replace('/(\r\n|\r|\n)/i', ($forxml ? '<br />' : '<br>'), $stringtoencode);
7653 return $ret;
7654 }
7655}
7656
7666function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = 'restricthtml')
7667{
7668 if (empty($nouseofiframesandbox) && getDolGlobalString('MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS')) {
7669 // TODO using sandbox on inline html content is not possible yet with current browsers
7670 //$s = '<iframe class="iframewithsandbox" sandbox><html><body>';
7671 //$s .= $stringtoencode;
7672 //$s .= '</body></html></iframe>';
7673 return $stringtoencode;
7674 } else {
7675 $out = $stringtoencode;
7676
7677 do {
7678 $oldstringtoclean = $out;
7679
7680 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML') && $check != 'restricthtmlallowunvalid') {
7681 try {
7682 libxml_use_internal_errors(false); // Avoid to fill memory with xml errors
7683 if (LIBXML_VERSION < 20900) {
7684 // Avoid load of external entities (security problem).
7685 // Required only if LIBXML_VERSION < 20900
7686 libxml_disable_entity_loader(true);
7687 }
7688
7689 $dom = new DOMDocument();
7690 // Add a trick to solve pb with text without parent tag
7691 // like '<h1>Foo</h1><p>bar</p>' that wrongly ends up, without the trick, with '<h1>Foo<p>bar</p></h1>'
7692 // like 'abc' that wrongly ends up, without the trick, with '<p>abc</p>'
7693
7694 if (dol_textishtml($out)) {
7695 $out = '<?xml encoding="UTF-8"><div class="tricktoremove">'.$out.'</div>';
7696 } else {
7697 $out = '<?xml encoding="UTF-8"><div class="tricktoremove">'.dol_nl2br($out).'</div>';
7698 }
7699 $dom->loadHTML($out, LIBXML_HTML_NODEFDTD | LIBXML_ERR_NONE | LIBXML_HTML_NOIMPLIED | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_NOERROR | LIBXML_NOXMLDECL);
7700 $out = trim($dom->saveHTML());
7701
7702 // Remove the trick added to solve pb with text without parent tag
7703 $out = preg_replace('/^<\?xml encoding="UTF-8"><div class="tricktoremove">/', '', $out);
7704 $out = preg_replace('/<\/div>$/', '', $out);
7705 } catch (Exception $e) {
7706 // If error, invalid HTML string with no way to clean it
7707 //print $e->getMessage();
7708 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
7709 }
7710 }
7711
7712 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY') && $check != 'restricthtmlallowunvalid') {
7713 try {
7714 // Try cleaning using tidy
7715 if (extension_loaded('tidy') && class_exists("tidy")) {
7716 //print "aaa".$out."\n";
7717
7718 // See options at https://tidy.sourceforge.net/docs/quickref.html
7719 $config = array(
7720 'clean' => false,
7721 'quote-marks' => false, // do not replace " that are used for real text content (not a string symbol for html attribute) into &quot;
7722 'doctype' => 'strict',
7723 'show-body-only' => true,
7724 "indent-attributes" => false,
7725 "vertical-space" => false,
7726 'ident' => false,
7727 "wrap" => 0
7728 // HTML5 tags
7729 //'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',
7730 //'new-blocklevel-tags' => 'footer header section menu menuitem'
7731 //'new-empty-tags' => 'command embed keygen source track wbr',
7732 //'new-inline-tags' => 'audio command datalist embed keygen mark menuitem meter output progress source time video wbr',
7733 );
7734
7735 // Tidy
7736 $tidy = new tidy();
7737 $out = $tidy->repairString($out, $config, 'utf8');
7738
7739 //print "xxx".$out;exit;
7740 }
7741 } catch (Exception $e) {
7742 // If error, invalid HTML string with no way to clean it
7743 //print $e->getMessage();
7744 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
7745 }
7746 }
7747
7748 //Clear ZERO WIDTH NO-BREAK SPACE, ZERO WIDTH SPACE, ZERO WIDTH JOINER
7749 $out = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $out);
7750
7751 // Clean some html entities that are useless so text is cleaner
7752 $out = preg_replace('/&(tab|newline);/i', ' ', $out);
7753
7754 // Ckeditor use the numeric entitic for apostrophe so we force it to text entity (all other special chars are
7755 // encoded using text entities) so we can then exclude all numeric entities.
7756 $out = preg_replace('/&#39;/i', '&apos;', $out);
7757
7758 // 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).
7759 // 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
7760 // using a non coventionnel way to be encoded, to not have them sanitized just after)
7761 $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) {
7762 return realCharForNumericEntities($m);
7763 }, $out);
7764
7765
7766 // Now we remove all remaining HTML entities starting with a number. We don't want such entities.
7767 $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'.
7768
7769 // Keep only some html tags and remove also some 'javascript:' strings
7770 $out = dol_string_onlythesehtmltags($out, 0, ($check == 'restricthtmlallowclass' ? 0 : 1), 1);
7771
7772 // Keep only some html attributes and exclude non expected HTML attributes and clean content of some attributes (keep only alt=, title=...).
7773 if (getDolGlobalString('MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES')) {
7775 }
7776
7777 // Restore entity &apos; into &#39; (restricthtml is for html content so we can use html entity)
7778 $out = preg_replace('/&apos;/i', "&#39;", $out);
7779 } while ($oldstringtoclean != $out);
7780
7781 // Check the limit of external links that are automatically executed in a Rich text content. We count:
7782 // '<img' to avoid <img src="http...">, we can only accept "<img src="data:..."
7783 // 'url(' to avoid inline style like background: url(http...
7784 // '<link' to avoid <link href="http...">
7785 $reg = array();
7786 $tmpout = preg_replace('/<img src="data:/mi', '<__IMG_SRC_DATA__ src="data:', $out);
7787 preg_match_all('/(<img|url\‍(|<link)/i', $tmpout, $reg);
7788 $nblinks = count($reg[0]);
7789 if ($nblinks > getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) {
7790 $out = 'ErrorTooManyLinksIntoHTMLString';
7791 }
7792
7793 if (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 2 || $check == 'restricthtmlnolink') {
7794 if ($nblinks > 0) {
7795 $out = 'ErrorHTMLLinksNotAllowed';
7796 }
7797 } elseif (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 1) {
7798 $nblinks = 0;
7799 // Loop on each url in src= and url(
7800 $pattern = '/src=["\']?(http[^"\']+)|url\‍(["\']?(http[^\‍)]+)/';
7801
7802 $matches = array();
7803 if (preg_match_all($pattern, $out, $matches)) {
7804 // URLs are into $matches[1]
7805 $urls = $matches[1];
7806
7807 // Affiche les URLs
7808 foreach ($urls as $url) {
7809 $nblinks++;
7810 echo "Found url = ".$url . "\n";
7811 }
7812 if ($nblinks > 0) {
7813 $out = 'ErrorHTMLExternalLinksNotAllowed';
7814 }
7815 }
7816 }
7817
7818 return $out;
7819 }
7820}
7821
7843function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UTF-8', $removelasteolbr = 1)
7844{
7845 if (is_null($stringtoencode)) {
7846 return '';
7847 }
7848
7849 $newstring = $stringtoencode;
7850 if (dol_textishtml($stringtoencode)) { // Check if text is already HTML or not
7851 $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.
7852 if ($removelasteolbr) {
7853 $newstring = preg_replace('/<br>$/i', '', $newstring); // Remove last <br> (remove only last one)
7854 }
7855 $newstring = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $newstring);
7856 $newstring = strtr($newstring, array('&'=>'__and__', '<'=>'__lt__', '>'=>'__gt__', '"'=>'__dquot__'));
7857 $newstring = dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom); // Make entity encoding
7858 $newstring = strtr($newstring, array('__and__'=>'&', '__lt__'=>'<', '__gt__'=>'>', '__dquot__'=>'"'));
7859 } else {
7860 if ($removelasteolbr) {
7861 $newstring = preg_replace('/(\r\n|\r|\n)$/i', '', $newstring); // Remove last \n (may remove several)
7862 }
7863 $newstring = dol_nl2br(dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom), $nl2brmode);
7864 }
7865 // Other substitutions that htmlentities does not do
7866 //$newstring=str_replace(chr(128),'&euro;',$newstring); // 128 = 0x80. Not in html entity table. // Seems useles with TCPDF. Make bug with UTF8 languages
7867 return $newstring;
7868}
7869
7877function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8')
7878{
7879 $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7880 $ret = preg_replace('/'."\r\n".'<br(\s[\sa-zA-Z_="]*)?\/?>/i', "<br>", $ret);
7881 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\r\n".'/i', "\r\n", $ret);
7882 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\n".'/i', "\n", $ret);
7883 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', "\n", $ret);
7884 return $ret;
7885}
7886
7893function dol_htmlcleanlastbr($stringtodecode)
7894{
7895 $ret = preg_replace('/&nbsp;$/i', "", $stringtodecode); // Because wysiwyg editor may add a &nbsp; at end of last line
7896 $ret = preg_replace('/(<br>|<br(\s[\sa-zA-Z_="]*)?\/?>|'."\n".'|'."\r".')+$/i', "", $ret);
7897 return $ret;
7898}
7899
7909function dol_html_entity_decode($a, $b, $c = 'UTF-8', $keepsomeentities = 0)
7910{
7911 $newstring = $a;
7912 if ($keepsomeentities) {
7913 $newstring = strtr($newstring, array('&amp;'=>'__andamp__', '&lt;'=>'__andlt__', '&gt;'=>'__andgt__', '"'=>'__dquot__'));
7914 }
7915 $newstring = html_entity_decode((string) $newstring, (int) $b, (string) $c);
7916 if ($keepsomeentities) {
7917 $newstring = strtr($newstring, array('__andamp__'=>'&amp;', '__andlt__'=>'&lt;', '__andgt__'=>'&gt;', '__dquot__'=>'"'));
7918 }
7919 return $newstring;
7920}
7921
7933function dol_htmlentities($string, $flags = ENT_QUOTES|ENT_SUBSTITUTE, $encoding = 'UTF-8', $double_encode = false)
7934{
7935 return htmlentities($string, $flags, $encoding, $double_encode);
7936}
7937
7949function dol_string_is_good_iso($s, $clean = 0)
7950{
7951 $len = dol_strlen($s);
7952 $out = '';
7953 $ok = 1;
7954 for ($scursor = 0; $scursor < $len; $scursor++) {
7955 $ordchar = ord($s[$scursor]);
7956 //print $scursor.'-'.$ordchar.'<br>';
7957 if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) {
7958 $ok = 0;
7959 break;
7960 } elseif ($ordchar > 126 && $ordchar < 160) {
7961 $ok = 0;
7962 break;
7963 } elseif ($clean) {
7964 $out .= $s[$scursor];
7965 }
7966 }
7967 if ($clean) {
7968 return $out;
7969 }
7970 return $ok;
7971}
7972
7981function dol_nboflines($s, $maxchar = 0)
7982{
7983 if ($s == '') {
7984 return 0;
7985 }
7986 $arraystring = explode("\n", $s);
7987 $nb = count($arraystring);
7988
7989 return $nb;
7990}
7991
7992
8002function dol_nboflines_bis($text, $maxlinesize = 0, $charset = 'UTF-8')
8003{
8004 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
8005 if (dol_textishtml($text)) {
8006 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
8007 }
8008
8009 $text = strtr($text, $repTable);
8010 if ($charset == 'UTF-8') {
8011 $pattern = '/(<br[^>]*>)/Uu';
8012 } else {
8013 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
8014 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
8015 }
8016 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
8017
8018 $nblines = (int) floor((count($a) + 1) / 2);
8019 // count possible auto line breaks
8020 if ($maxlinesize) {
8021 foreach ($a as $line) {
8022 if (dol_strlen($line) > $maxlinesize) {
8023 //$line_dec = html_entity_decode(strip_tags($line));
8024 $line_dec = html_entity_decode($line);
8025 if (dol_strlen($line_dec) > $maxlinesize) {
8026 $line_dec = wordwrap($line_dec, $maxlinesize, '\n', true);
8027 $nblines += substr_count($line_dec, '\n');
8028 }
8029 }
8030 }
8031 }
8032
8033 unset($a);
8034 return $nblines;
8035}
8036
8045function dol_textishtml($msg, $option = 0)
8046{
8047 if (is_null($msg)) {
8048 return false;
8049 }
8050
8051 if ($option == 1) {
8052 if (preg_match('/<html/i', $msg)) {
8053 return true;
8054 } elseif (preg_match('/<body/i', $msg)) {
8055 return true;
8056 } elseif (preg_match('/<\/textarea/i', $msg)) {
8057 return true;
8058 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8059 return true;
8060 } elseif (preg_match('/<br/i', $msg)) {
8061 return true;
8062 }
8063 return false;
8064 } else {
8065 // Remove all urls because 'http://aa?param1=abc&amp;param2=def' must not be used inside detection
8066 $msg = preg_replace('/https?:\/\/[^"\'\s]+/i', '', $msg);
8067 if (preg_match('/<html/i', $msg)) {
8068 return true;
8069 } elseif (preg_match('/<body/i', $msg)) {
8070 return true;
8071 } elseif (preg_match('/<\/textarea/i', $msg)) {
8072 return true;
8073 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8074 return true;
8075 } elseif (preg_match('/<(br|hr)\/>/i', $msg)) {
8076 return true;
8077 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)>/i', $msg)) {
8078 return true;
8079 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)\s+[^<>\/]*\/?>/i', $msg)) {
8080 return true;
8081 } elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i', $msg)) {
8082 return true; // must accept <img src="http://example.com/aaa.png" />
8083 } elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i', $msg)) {
8084 return true; // must accept <a href="http://example.com/aaa.png" />
8085 } elseif (preg_match('/<h[0-9]>/i', $msg)) {
8086 return true;
8087 } elseif (preg_match('/&[A-Z0-9]{1,6};/i', $msg)) {
8088 // TODO If content is 'A link https://aaa?param=abc&amp;param2=def', it return true but must be false
8089 return true; // Html entities names (http://www.w3schools.com/tags/ref_entities.asp)
8090 } elseif (preg_match('/&#[0-9]{2,3};/i', $msg)) {
8091 return true; // Html entities numbers (http://www.w3schools.com/tags/ref_entities.asp)
8092 }
8093
8094 return false;
8095 }
8096}
8097
8112function dol_concatdesc($text1, $text2, $forxml = false, $invert = false)
8113{
8114 if (!empty($invert)) {
8115 $tmp = $text1;
8116 $text1 = $text2;
8117 $text2 = $tmp;
8118 }
8119
8120 $ret = '';
8121 $ret .= (!dol_textishtml($text1) && dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text1, 0, 1, '', 1), 0, $forxml) : $text1;
8122 $ret .= (!empty($text1) && !empty($text2)) ? ((dol_textishtml($text1) || dol_textishtml($text2)) ? ($forxml ? "<br >\n" : "<br>\n") : "\n") : "";
8123 $ret .= (dol_textishtml($text1) && !dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text2, 0, 1, '', 1), 0, $forxml) : $text2;
8124 return $ret;
8125}
8126
8127
8128
8140function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null)
8141{
8142 global $db, $conf, $mysoc, $user, $extrafields;
8143
8144 $substitutionarray = array();
8145
8146 if ((empty($exclude) || !in_array('user', $exclude)) && (empty($include) || in_array('user', $include))) {
8147 // Add SIGNATURE into substitutionarray first, so, when we will make the substitution,
8148 // this will include signature content first and then replace var found into content of signature
8149 //var_dump($onlykey);
8150 $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()
8151 $usersignature = $user->signature;
8152 $substitutionarray = array_merge($substitutionarray, array(
8153 '__SENDEREMAIL_SIGNATURE__' => (string) ((!getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc('SignatureFromTheSelectedSenderProfile', 30) : $emailsendersignature) : ''),
8154 '__USER_SIGNATURE__' => (string) (($usersignature && !getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc(dol_string_nohtmltag($usersignature), 30) : $usersignature) : '')
8155 ));
8156
8157 if (is_object($user)) {
8158 $substitutionarray = array_merge($substitutionarray, array(
8159 '__USER_ID__' => (string) $user->id,
8160 '__USER_LOGIN__' => (string) $user->login,
8161 '__USER_EMAIL__' => (string) $user->email,
8162 '__USER_PHONE__' => (string) dol_print_phone($user->office_phone, '', 0, 0, '', " ", '', '', -1),
8163 '__USER_PHONEPRO__' => (string) dol_print_phone($user->user_mobile, '', 0, 0, '', " ", '', '', -1),
8164 '__USER_PHONEMOBILE__' => (string) dol_print_phone($user->personal_mobile, '', 0, 0, '', " ", '', '', -1),
8165 '__USER_FAX__' => (string) $user->office_fax,
8166 '__USER_LASTNAME__' => (string) $user->lastname,
8167 '__USER_FIRSTNAME__' => (string) $user->firstname,
8168 '__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
8169 '__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
8170 '__USER_JOB__' => (string) $user->job,
8171 '__USER_REMOTE_IP__' => (string) getUserRemoteIP(),
8172 '__USER_VCARD_URL__' => (string) $user->getOnlineVirtualCardUrl('', 'external')
8173 ));
8174 }
8175 }
8176 if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc) && (empty($include) || in_array('mycompany', $include))) {
8177 $substitutionarray = array_merge($substitutionarray, array(
8178 '__MYCOMPANY_NAME__' => $mysoc->name,
8179 '__MYCOMPANY_EMAIL__' => $mysoc->email,
8180 '__MYCOMPANY_PHONE__' => dol_print_phone($mysoc->phone, '', 0, 0, '', " ", '', '', -1),
8181 '__MYCOMPANY_FAX__' => dol_print_phone($mysoc->fax, '', 0, 0, '', " ", '', '', -1),
8182 '__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
8183 '__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
8184 '__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
8185 '__MYCOMPANY_PROFID4__' => $mysoc->idprof4,
8186 '__MYCOMPANY_PROFID5__' => $mysoc->idprof5,
8187 '__MYCOMPANY_PROFID6__' => $mysoc->idprof6,
8188 '__MYCOMPANY_CAPITAL__' => $mysoc->capital,
8189 '__MYCOMPANY_FULLADDRESS__' => (method_exists($mysoc, 'getFullAddress') ? $mysoc->getFullAddress(1, ', ') : ''), // $mysoc may be stdClass
8190 '__MYCOMPANY_ADDRESS__' => $mysoc->address,
8191 '__MYCOMPANY_ZIP__' => $mysoc->zip,
8192 '__MYCOMPANY_TOWN__' => $mysoc->town,
8193 '__MYCOMPANY_COUNTRY__' => $mysoc->country,
8194 '__MYCOMPANY_COUNTRY_ID__' => $mysoc->country_id,
8195 '__MYCOMPANY_COUNTRY_CODE__' => $mysoc->country_code,
8196 '__MYCOMPANY_CURRENCY_CODE__' => $conf->currency
8197 ));
8198 }
8199
8200 if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude)) && (empty($include) || in_array('object', $include))) {
8201 if ($onlykey) {
8202 $substitutionarray['__ID__'] = '__ID__';
8203 $substitutionarray['__REF__'] = '__REF__';
8204 $substitutionarray['__NEWREF__'] = '__NEWREF__';
8205 $substitutionarray['__LABEL__'] = '__LABEL__';
8206 $substitutionarray['__REF_CLIENT__'] = '__REF_CLIENT__';
8207 $substitutionarray['__REF_SUPPLIER__'] = '__REF_SUPPLIER__';
8208 $substitutionarray['__NOTE_PUBLIC__'] = '__NOTE_PUBLIC__';
8209 $substitutionarray['__NOTE_PRIVATE__'] = '__NOTE_PRIVATE__';
8210 $substitutionarray['__EXTRAFIELD_XXX__'] = '__EXTRAFIELD_XXX__';
8211
8212 if (isModEnabled("societe")) { // Most objects are concerned
8213 $substitutionarray['__THIRDPARTY_ID__'] = '__THIRDPARTY_ID__';
8214 $substitutionarray['__THIRDPARTY_NAME__'] = '__THIRDPARTY_NAME__';
8215 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = '__THIRDPARTY_NAME_ALIAS__';
8216 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = '__THIRDPARTY_CODE_CLIENT__';
8217 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = '__THIRDPARTY_CODE_FOURNISSEUR__';
8218 $substitutionarray['__THIRDPARTY_EMAIL__'] = '__THIRDPARTY_EMAIL__';
8219 $substitutionarray['__THIRDPARTY_PHONE__'] = '__THIRDPARTY_PHONE__';
8220 $substitutionarray['__THIRDPARTY_FAX__'] = '__THIRDPARTY_FAX__';
8221 $substitutionarray['__THIRDPARTY_ADDRESS__'] = '__THIRDPARTY_ADDRESS__';
8222 $substitutionarray['__THIRDPARTY_ZIP__'] = '__THIRDPARTY_ZIP__';
8223 $substitutionarray['__THIRDPARTY_TOWN__'] = '__THIRDPARTY_TOWN__';
8224 $substitutionarray['__THIRDPARTY_IDPROF1__'] = '__THIRDPARTY_IDPROF1__';
8225 $substitutionarray['__THIRDPARTY_IDPROF2__'] = '__THIRDPARTY_IDPROF2__';
8226 $substitutionarray['__THIRDPARTY_IDPROF3__'] = '__THIRDPARTY_IDPROF3__';
8227 $substitutionarray['__THIRDPARTY_IDPROF4__'] = '__THIRDPARTY_IDPROF4__';
8228 $substitutionarray['__THIRDPARTY_IDPROF5__'] = '__THIRDPARTY_IDPROF5__';
8229 $substitutionarray['__THIRDPARTY_IDPROF6__'] = '__THIRDPARTY_IDPROF6__';
8230 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = '__THIRDPARTY_TVAINTRA__';
8231 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = '__THIRDPARTY_NOTE_PUBLIC__';
8232 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = '__THIRDPARTY_NOTE_PRIVATE__';
8233 }
8234 if (isModEnabled('adherent') && (!is_object($object) || $object->element == 'adherent') && (empty($exclude) || !in_array('member', $exclude)) && (empty($include) || in_array('member', $include))) {
8235 $substitutionarray['__MEMBER_ID__'] = '__MEMBER_ID__';
8236 $substitutionarray['__MEMBER_CIVILITY__'] = '__MEMBER_CIVILITY__';
8237 $substitutionarray['__MEMBER_FIRSTNAME__'] = '__MEMBER_FIRSTNAME__';
8238 $substitutionarray['__MEMBER_LASTNAME__'] = '__MEMBER_LASTNAME__';
8239 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = 'Login and pass of the external user account';
8240 /*$substitutionarray['__MEMBER_NOTE_PUBLIC__'] = '__MEMBER_NOTE_PUBLIC__';
8241 $substitutionarray['__MEMBER_NOTE_PRIVATE__'] = '__MEMBER_NOTE_PRIVATE__';*/
8242 }
8243 // add variables subtitutions ticket
8244 if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket') && (empty($exclude) || !in_array('ticket', $exclude)) && (empty($include) || in_array('ticket', $include))) {
8245 $substitutionarray['__TICKET_TRACKID__'] = '__TICKET_TRACKID__';
8246 $substitutionarray['__TICKET_SUBJECT__'] = '__TICKET_SUBJECT__';
8247 $substitutionarray['__TICKET_TYPE__'] = '__TICKET_TYPE__';
8248 $substitutionarray['__TICKET_SEVERITY__'] = '__TICKET_SEVERITY__';
8249 $substitutionarray['__TICKET_CATEGORY__'] = '__TICKET_CATEGORY__';
8250 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = '__TICKET_ANALYTIC_CODE__';
8251 $substitutionarray['__TICKET_MESSAGE__'] = '__TICKET_MESSAGE__';
8252 $substitutionarray['__TICKET_PROGRESSION__'] = '__TICKET_PROGRESSION__';
8253 $substitutionarray['__TICKET_USER_ASSIGN__'] = '__TICKET_USER_ASSIGN__';
8254 }
8255
8256 if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature') && (empty($exclude) || !in_array('recruitment', $exclude)) && (empty($include) || in_array('recruitment', $include))) {
8257 $substitutionarray['__CANDIDATE_FULLNAME__'] = '__CANDIDATE_FULLNAME__';
8258 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = '__CANDIDATE_FIRSTNAME__';
8259 $substitutionarray['__CANDIDATE_LASTNAME__'] = '__CANDIDATE_LASTNAME__';
8260 }
8261 if (isModEnabled('project') && (empty($exclude) || !in_array('project', $exclude)) && (empty($include) || in_array('project', $include))) { // Most objects
8262 $substitutionarray['__PROJECT_ID__'] = '__PROJECT_ID__';
8263 $substitutionarray['__PROJECT_REF__'] = '__PROJECT_REF__';
8264 $substitutionarray['__PROJECT_NAME__'] = '__PROJECT_NAME__';
8265 /*$substitutionarray['__PROJECT_NOTE_PUBLIC__'] = '__PROJECT_NOTE_PUBLIC__';
8266 $substitutionarray['__PROJECT_NOTE_PRIVATE__'] = '__PROJECT_NOTE_PRIVATE__';*/
8267 }
8268 if (isModEnabled('contrat') && (!is_object($object) || $object->element == 'contract') && (empty($exclude) || !in_array('contract', $exclude)) && (empty($include) || in_array('contract', $include))) {
8269 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = 'Highest date planned for a service start';
8270 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = 'Highest date and hour planned for service start';
8271 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = 'Lowest data for planned expiration of service';
8272 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = 'Lowest date and hour for planned expiration of service';
8273 }
8274 if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal') && (empty($exclude) || !in_array('propal', $exclude)) && (empty($include) || in_array('propal', $include))) {
8275 $substitutionarray['__ONLINE_SIGN_URL__'] = 'ToOfferALinkForOnlineSignature';
8276 }
8277 if (isModEnabled("ficheinter") && (!is_object($object) || $object->element == 'fichinter') && (empty($exclude) || !in_array('intervention', $exclude)) && (empty($include) || in_array('intervention', $include))) {
8278 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = 'ToOfferALinkForOnlineSignature';
8279 }
8280 $substitutionarray['__ONLINE_PAYMENT_URL__'] = 'UrlToPayOnlineIfApplicable';
8281 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = 'TextAndUrlToPayOnlineIfApplicable';
8282 $substitutionarray['__SECUREKEYPAYMENT__'] = 'Security key (if key is not unique per record)';
8283 $substitutionarray['__SECUREKEYPAYMENT_MEMBER__'] = 'Security key for payment on a member subscription (one key per member)';
8284 $substitutionarray['__SECUREKEYPAYMENT_ORDER__'] = 'Security key for payment on an order';
8285 $substitutionarray['__SECUREKEYPAYMENT_INVOICE__'] = 'Security key for payment on an invoice';
8286 $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'Security key for payment on a service of a contract';
8287
8288 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = 'Direct download url of a proposal';
8289 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = 'Direct download url of an order';
8290 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = 'Direct download url of an invoice';
8291 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = 'Direct download url of a contract';
8292 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = 'Direct download url of a supplier proposal';
8293
8294 if (isModEnabled("expedition") && (!is_object($object) || $object->element == 'shipping')) {
8295 $substitutionarray['__SHIPPINGTRACKNUM__'] = 'Shipping tracking number';
8296 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = 'Shipping tracking url';
8297 $substitutionarray['__SHIPPINGMETHOD__'] = 'Shipping method';
8298 }
8299 if (isModEnabled("reception") && (!is_object($object) || $object->element == 'reception')) {
8300 $substitutionarray['__RECEPTIONTRACKNUM__'] = 'Shippin tracking number of shipment';
8301 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = 'Shipping tracking url';
8302 }
8303 } else {
8304 $substitutionarray['__ID__'] = $object->id;
8305 $substitutionarray['__REF__'] = $object->ref;
8306 $substitutionarray['__NEWREF__'] = $object->newref;
8307 $substitutionarray['__LABEL__'] = (isset($object->label) ? $object->label : (isset($object->title) ? $object->title : null));
8308 $substitutionarray['__REF_CLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8309 $substitutionarray['__REF_SUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8310 $substitutionarray['__NOTE_PUBLIC__'] = (isset($object->note_public) ? $object->note_public : null);
8311 $substitutionarray['__NOTE_PRIVATE__'] = (isset($object->note_private) ? $object->note_private : null);
8312 // handle date_delivery: in customer order/supplier order, the property name is delivery_date, in shipment/reception it is date_delivery
8313 $date_delivery = null;
8314 if (property_exists($object, 'date_delivery')) {
8315 $date_delivery = $object->date_delivery;
8316 } elseif (property_exists($object, 'delivery_date')) {
8317 $date_delivery = $object->delivery_date;
8318 }
8319 $substitutionarray['__DATE_DELIVERY__'] = (isset($date_delivery) ? dol_print_date($date_delivery, 'day', 0, $outputlangs) : '');
8320 $substitutionarray['__DATE_DELIVERY_DAY__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%d") : '');
8321 $substitutionarray['__DATE_DELIVERY_DAY_TEXT__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%A") : '');
8322 $substitutionarray['__DATE_DELIVERY_MON__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%m") : '');
8323 $substitutionarray['__DATE_DELIVERY_MON_TEXT__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%b") : '');
8324 $substitutionarray['__DATE_DELIVERY_YEAR__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%Y") : '');
8325 $substitutionarray['__DATE_DELIVERY_HH__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%H") : '');
8326 $substitutionarray['__DATE_DELIVERY_MM__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%M") : '');
8327 $substitutionarray['__DATE_DELIVERY_SS__'] = (isset($date_delivery) ? dol_print_date($date_delivery, "%S") : '');
8328
8329 // For backward compatibility (deprecated)
8330 $substitutionarray['__REFCLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8331 $substitutionarray['__REFSUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8332 $substitutionarray['__SUPPLIER_ORDER_DATE_DELIVERY__'] = (isset($date_delivery) ? dol_print_date($date_delivery, 'day', 0, $outputlangs) : '');
8333 $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 : '')) : '');
8334 $substitutionarray['__EXPIRATION_DATE__'] = (isset($object->fin_validite) ? dol_print_date($object->fin_validite, 'daytext') : '');
8335
8336 if (is_object($object) && ($object->element == 'adherent' || $object->element == 'member') && $object->id > 0) {
8337 $birthday = (empty($object->birth) ? '' : dol_print_date($object->birth, 'day'));
8338
8339 $substitutionarray['__MEMBER_ID__'] = (isset($object->id) ? $object->id : '');
8340 if (method_exists($object, 'getCivilityLabel')) {
8341 $substitutionarray['__MEMBER_CIVILITY__'] = $object->getCivilityLabel();
8342 }
8343 $substitutionarray['__MEMBER_FIRSTNAME__'] = (isset($object->firstname) ? $object->firstname : '');
8344 $substitutionarray['__MEMBER_LASTNAME__'] = (isset($object->lastname) ? $object->lastname : '');
8345 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = '';
8346 if (method_exists($object, 'getFullName')) {
8347 $substitutionarray['__MEMBER_FULLNAME__'] = $object->getFullName($outputlangs);
8348 }
8349 $substitutionarray['__MEMBER_COMPANY__'] = (isset($object->societe) ? $object->societe : '');
8350 $substitutionarray['__MEMBER_ADDRESS__'] = (isset($object->address) ? $object->address : '');
8351 $substitutionarray['__MEMBER_ZIP__'] = (isset($object->zip) ? $object->zip : '');
8352 $substitutionarray['__MEMBER_TOWN__'] = (isset($object->town) ? $object->town : '');
8353 $substitutionarray['__MEMBER_COUNTRY__'] = (isset($object->country) ? $object->country : '');
8354 $substitutionarray['__MEMBER_EMAIL__'] = (isset($object->email) ? $object->email : '');
8355 $substitutionarray['__MEMBER_BIRTH__'] = (isset($birthday) ? $birthday : '');
8356 $substitutionarray['__MEMBER_PHOTO__'] = (isset($object->photo) ? $object->photo : '');
8357 $substitutionarray['__MEMBER_LOGIN__'] = (isset($object->login) ? $object->login : '');
8358 $substitutionarray['__MEMBER_PASSWORD__'] = (isset($object->pass) ? $object->pass : '');
8359 $substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? dol_print_phone($object->phone) : '');
8360 $substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? dol_print_phone($object->phone_perso) : '');
8361 $substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? dol_print_phone($object->phone_mobile) : '');
8362 $substitutionarray['__MEMBER_TYPE__'] = (isset($object->type) ? $object->type : '');
8363 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__'] = dol_print_date($object->first_subscription_date, 'day');
8364 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = (isset($object->first_subscription_date_start) ? dol_print_date($object->first_subscription_date_start, 'day') : '');
8365 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END__'] = (isset($object->first_subscription_date_end) ? dol_print_date($object->first_subscription_date_end, 'day') : '');
8366 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE__'] = dol_print_date($object->last_subscription_date, 'day');
8367 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->last_subscription_date_start, 'day');
8368 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END__'] = dol_print_date($object->last_subscription_date_end, 'day');
8369 }
8370
8371 if (is_object($object) && $object->element == 'societe') {
8372 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object) ? $object->id : '');
8373 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object) ? $object->name : '');
8374 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object) ? $object->name_alias : '');
8375 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object) ? $object->code_client : '');
8376 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object) ? $object->code_fournisseur : '');
8377 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object) ? $object->email : '');
8378 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? dol_print_phone($object->phone) : '');
8379 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? dol_print_phone($object->fax) : '');
8380 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object) ? $object->address : '');
8381 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object) ? $object->zip : '');
8382 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object) ? $object->town : '');
8383 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object) ? $object->country_id : '');
8384 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object) ? $object->country_code : '');
8385 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object) ? $object->idprof1 : '');
8386 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object) ? $object->idprof2 : '');
8387 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object) ? $object->idprof3 : '');
8388 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object) ? $object->idprof4 : '');
8389 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object) ? $object->idprof5 : '');
8390 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object) ? $object->idprof6 : '');
8391 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object) ? $object->tva_intra : '');
8392 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_public) : '');
8393 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_private) : '');
8394 } elseif (is_object($object->thirdparty)) {
8395 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->id : '');
8396 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object->thirdparty) ? $object->thirdparty->name : '');
8397 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object->thirdparty) ? $object->thirdparty->name_alias : '');
8398 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_client : '');
8399 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_fournisseur : '');
8400 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object->thirdparty) ? $object->thirdparty->email : '');
8401 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->phone) : '');
8402 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->fax) : '');
8403 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object->thirdparty) ? $object->thirdparty->address : '');
8404 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object->thirdparty) ? $object->thirdparty->zip : '');
8405 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object->thirdparty) ? $object->thirdparty->town : '');
8406 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_id : '');
8407 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_code : '');
8408 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof1 : '');
8409 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof2 : '');
8410 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof3 : '');
8411 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof4 : '');
8412 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof5 : '');
8413 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof6 : '');
8414 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object->thirdparty) ? $object->thirdparty->tva_intra : '');
8415 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_public) : '');
8416 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_private) : '');
8417 }
8418
8419 if (is_object($object) && $object->element == 'recruitmentcandidature') {
8420 $substitutionarray['__CANDIDATE_FULLNAME__'] = $object->getFullName($outputlangs);
8421 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8422 $substitutionarray['__CANDIDATE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8423 }
8424 if (is_object($object) && $object->element == 'conferenceorboothattendee') {
8425 $substitutionarray['__ATTENDEE_FULLNAME__'] = $object->getFullName($outputlangs);
8426 $substitutionarray['__ATTENDEE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8427 $substitutionarray['__ATTENDEE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8428 }
8429
8430 if (is_object($object) && $object->element == 'project') {
8431 $substitutionarray['__PROJECT_ID__'] = $object->id;
8432 $substitutionarray['__PROJECT_REF__'] = $object->ref;
8433 $substitutionarray['__PROJECT_NAME__'] = $object->title;
8434 } elseif (is_object($object)) {
8435 $project = null;
8436 if (!empty($object->project)) {
8437 $project = $object->project;
8438 } elseif (!empty($object->projet)) { // Deprecated, for backward compatibility
8439 $project = $object->projet;
8440 }
8441 if (!is_null($project) && is_object($project)) {
8442 $substitutionarray['__PROJECT_ID__'] = $project->id;
8443 $substitutionarray['__PROJECT_REF__'] = $project->ref;
8444 $substitutionarray['__PROJECT_NAME__'] = $project->title;
8445 } else {
8446 // can substitute variables for project : uses lazy load in "make_substitutions" method
8447 $project_id = 0;
8448 if (!empty($object->fk_project) && $object->fk_project > 0) {
8449 $project_id = $object->fk_project;
8450 } elseif (!empty($object->fk_projet) && $object->fk_projet > 0) {
8451 $project_id = $object->fk_project;
8452 }
8453 if ($project_id > 0) {
8454 // path:class:method:id
8455 $substitutionarray['__PROJECT_ID__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8456 $substitutionarray['__PROJECT_REF__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8457 $substitutionarray['__PROJECT_NAME__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8458 }
8459 }
8460 }
8461
8462 if (is_object($object) && $object->element == 'shipping') {
8463 $substitutionarray['__SHIPPINGTRACKNUM__'] = $object->tracking_number;
8464 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = $object->tracking_url;
8465 $substitutionarray['__SHIPPINGMETHOD__'] = $object->shipping_method;
8466 }
8467 if (is_object($object) && $object->element == 'reception') {
8468 $substitutionarray['__RECEPTIONTRACKNUM__'] = $object->tracking_number;
8469 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = $object->tracking_url;
8470 }
8471
8472 if (is_object($object) && $object->element == 'contrat' && $object->id > 0 && is_array($object->lines)) {
8473 $dateplannedstart = '';
8474 $datenextexpiration = '';
8475 foreach ($object->lines as $line) {
8476 if ($line->date_start > $dateplannedstart) {
8477 $dateplannedstart = $line->date_start;
8478 }
8479 if ($line->statut == 4 && $line->date_end && (!$datenextexpiration || $line->date_end < $datenextexpiration)) {
8480 $datenextexpiration = $line->date_end;
8481 }
8482 }
8483 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = dol_print_date($dateplannedstart, 'day');
8484 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = dol_print_date($dateplannedstart, 'standard');
8485 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = dol_print_date($datenextexpiration, 'day');
8486 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = dol_print_date($datenextexpiration, 'standard');
8487 }
8488 // add substition variable for ticket
8489 if (is_object($object) && $object->element == 'ticket') {
8490 $substitutionarray['__TICKET_TRACKID__'] = $object->track_id;
8491 $substitutionarray['__REF__'] = $object->ref;
8492 $substitutionarray['__TICKET_SUBJECT__'] = $object->subject;
8493 $substitutionarray['__TICKET_TYPE__'] = $object->type_code;
8494 $substitutionarray['__TICKET_SEVERITY__'] = $object->severity_code;
8495 $substitutionarray['__TICKET_CATEGORY__'] = $object->category_code; // For backward compatibility
8496 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = $object->category_code;
8497 $substitutionarray['__TICKET_MESSAGE__'] = $object->message;
8498 $substitutionarray['__TICKET_PROGRESSION__'] = $object->progress;
8499 $userstat = new User($db);
8500 if ($object->fk_user_assign > 0) {
8501 $userstat->fetch($object->fk_user_assign);
8502 $substitutionarray['__TICKET_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8503 }
8504
8505 if ($object->fk_user_create > 0) {
8506 $userstat->fetch($object->fk_user_create);
8507 $substitutionarray['__USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8508 }
8509 }
8510
8511 // Create dynamic tags for __EXTRAFIELD_FIELD__
8512 if ($object->table_element && $object->id > 0) {
8513 if (!is_object($extrafields)) {
8514 $extrafields = new ExtraFields($db);
8515 }
8516 $extrafields->fetch_name_optionals_label($object->table_element, true);
8517
8518 if ($object->fetch_optionals() > 0) {
8519 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) {
8520 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
8521 if ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
8522 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_date($object->array_options['options_'.$key], 'day');
8523 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = dol_print_date($object->array_options['options_'.$key], 'day', 'tzserver', $outputlangs);
8524 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = dol_print_date($object->array_options['options_'.$key], 'dayrfc');
8525 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'datetime') {
8526 $datetime = $object->array_options['options_'.$key];
8527 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour') : '');
8528 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : '');
8529 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_DAY_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'day', 'tzserver', $outputlangs) : '');
8530 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : '');
8531 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'phone') {
8532 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_phone($object->array_options['options_'.$key]);
8533 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
8534 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = $object->array_options['options_'.$key];
8535 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATED__'] = price($object->array_options['options_'.$key]);
8536 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] != 'separator') {
8537 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = !empty($object->array_options['options_'.$key]) ? $object->array_options['options_'.$key] : '';
8538 }
8539 }
8540 }
8541 }
8542 }
8543
8544 // Complete substitution array with the url to make online payment
8545 $paymenturl = '';
8546 if (empty($substitutionarray['__REF__'])) {
8547 $paymenturl = '';
8548 } else {
8549 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
8550 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
8551 $outputlangs->loadLangs(array('paypal', 'other'));
8552
8553 $amounttouse = 0;
8554 $typeforonlinepayment = 'free';
8555 if (is_object($object) && $object->element == 'commande') {
8556 $typeforonlinepayment = 'order';
8557 }
8558 if (is_object($object) && $object->element == 'facture') {
8559 $typeforonlinepayment = 'invoice';
8560 }
8561 if (is_object($object) && $object->element == 'member') {
8562 $typeforonlinepayment = 'member';
8563 if (!empty($object->last_subscription_amount)) {
8564 $amounttouse = $object->last_subscription_amount;
8565 }
8566 }
8567 if (is_object($object) && $object->element == 'contrat') {
8568 $typeforonlinepayment = 'contract';
8569 }
8570 if (is_object($object) && $object->element == 'fichinter') {
8571 $typeforonlinepayment = 'ficheinter';
8572 }
8573
8574 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__'], $amounttouse);
8575 $paymenturl = $url;
8576 }
8577
8578 if ($object->id > 0) {
8579 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ? str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : '');
8580 $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl;
8581
8582 if (getDolGlobalString('PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'propal') {
8583 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8584 } else {
8585 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = '';
8586 }
8587 if (getDolGlobalString('ORDER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'commande') {
8588 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = $object->getLastMainDocLink($object->element);
8589 } else {
8590 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = '';
8591 }
8592 if (getDolGlobalString('INVOICE_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'facture') {
8593 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = $object->getLastMainDocLink($object->element);
8594 } else {
8595 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = '';
8596 }
8597 if (getDolGlobalString('CONTRACT_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'contrat') {
8598 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = $object->getLastMainDocLink($object->element);
8599 } else {
8600 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = '';
8601 }
8602 if (getDolGlobalString('FICHINTER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'fichinter') {
8603 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = $object->getLastMainDocLink($object->element);
8604 } else {
8605 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = '';
8606 }
8607 if (getDolGlobalString('SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'supplier_proposal') {
8608 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8609 } else {
8610 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = '';
8611 }
8612
8613 if (is_object($object) && $object->element == 'propal') {
8614 $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id;
8615 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8616 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref);
8617 }
8618 if (is_object($object) && $object->element == 'commande') {
8619 $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id;
8620 }
8621 if (is_object($object) && $object->element == 'facture') {
8622 $substitutionarray['__URL_INVOICE__'] = DOL_MAIN_URL_ROOT."/compta/facture/card.php?id=".$object->id;
8623 }
8624 if (is_object($object) && $object->element == 'contrat') {
8625 $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id;
8626 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8627 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref);
8628 }
8629 if (is_object($object) && $object->element == 'fichinter') {
8630 $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id;
8631 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8632 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref);
8633 }
8634 if (is_object($object) && $object->element == 'supplier_proposal') {
8635 $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id;
8636 }
8637 if (is_object($object) && $object->element == 'shipping') {
8638 $substitutionarray['__URL_SHIPMENT__'] = DOL_MAIN_URL_ROOT."/expedition/card.php?id=".$object->id;
8639 }
8640 }
8641
8642 if (is_object($object) && $object->element == 'action') {
8643 $substitutionarray['__EVENT_LABEL__'] = $object->label;
8644 $substitutionarray['__EVENT_TYPE__'] = $outputlangs->trans("Action".$object->type_code);
8645 $substitutionarray['__EVENT_DATE__'] = dol_print_date($object->datep, 'day', 'auto', $outputlangs);
8646 $substitutionarray['__EVENT_TIME__'] = dol_print_date($object->datep, 'hour', 'auto', $outputlangs);
8647 }
8648 }
8649 }
8650 if ((empty($exclude) || !in_array('objectamount', $exclude)) && (empty($include) || in_array('objectamount', $include))) {
8651 include_once DOL_DOCUMENT_ROOT.'/core/lib/functionsnumtoword.lib.php';
8652
8653 $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : '';
8654 $substitutionarray['__DATE_DUE_YMD__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs) : null) : '';
8655
8656 $already_payed_all = 0;
8657 if (is_object($object) && ($object instanceof Facture)) {
8658 $already_payed_all = $object->sumpayed + $object->sumdeposit + $object->sumcreditnote;
8659 }
8660
8661 $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : '';
8662
8663 $substitutionarray['__AMOUNT__'] = is_object($object) ? $object->total_ttc : '';
8664 $substitutionarray['__AMOUNT_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, '', true) : '';
8665 $substitutionarray['__AMOUNT_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, $conf->currency, true) : '';
8666
8667 $substitutionarray['__AMOUNT_REMAIN__'] = is_object($object) ? price2num($object->total_ttc - $already_payed_all, 'MT') : '';
8668
8669 $substitutionarray['__AMOUNT_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8670 $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)) : '';
8671 $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)) : '';
8672
8673 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8674 $substitutionarray['__AMOUNT_TAX2__'] = is_object($object) ? $object->total_localtax1 : '';
8675 }
8676 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8677 $substitutionarray['__AMOUNT_TAX3__'] = is_object($object) ? $object->total_localtax2 : '';
8678 }
8679
8680 // Amount keys formated in a currency
8681 $substitutionarray['__AMOUNT_EXCL_TAX_FORMATED__'] = is_object($object) ? ($object->total_ht ? price($object->total_ht, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8682 $substitutionarray['__AMOUNT_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8683 $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) : '';
8684 $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)) : '';
8685 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8686 $substitutionarray['__AMOUNT_TAX2_FORMATED__'] = is_object($object) ? ($object->total_localtax1 ? price($object->total_localtax1, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8687 }
8688 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8689 $substitutionarray['__AMOUNT_TAX3_FORMATED__'] = is_object($object) ? ($object->total_localtax2 ? price($object->total_localtax2, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8690 }
8691
8692 $substitutionarray['__AMOUNT_MULTICURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? $object->multicurrency_total_ttc : '';
8693 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXT__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, '', true) : '';
8694 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXTCURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, $object->multicurrency_code, true) : '';
8695 // TODO Add other keys for foreign multicurrency
8696
8697 // For backward compatibility
8698 if ($onlykey != 2) {
8699 $substitutionarray['__TOTAL_TTC__'] = is_object($object) ? $object->total_ttc : '';
8700 $substitutionarray['__TOTAL_HT__'] = is_object($object) ? $object->total_ht : '';
8701 $substitutionarray['__TOTAL_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8702 }
8703 }
8704
8705 //var_dump($substitutionarray['__AMOUNT_FORMATED__']);
8706 if ((empty($exclude) || !in_array('date', $exclude)) && (empty($include) || in_array('date', $include))) {
8707 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
8708
8709 $now = dol_now();
8710
8711 $tmp = dol_getdate($now, true);
8712 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8713 $tmp3 = dol_get_prev_month($tmp['mon'], $tmp['year']);
8714 $tmp4 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8715 $tmp5 = dol_get_next_month($tmp['mon'], $tmp['year']);
8716
8717 $daytext = $outputlangs->trans('Day'.$tmp['wday']);
8718
8719 $substitutionarray = array_merge($substitutionarray, array(
8720 '__NOW_TMS__' => (string) $now, // Must be the string that represent the int
8721 '__NOW_TMS_YMD__' => dol_print_date($now, 'day', 'auto', $outputlangs),
8722 '__DAY__' => (string) $tmp['mday'],
8723 '__DAY_TEXT__' => $daytext, // Monday
8724 '__DAY_TEXT_SHORT__' => dol_trunc($daytext, 3, 'right', 'UTF-8', 1), // Mon
8725 '__DAY_TEXT_MIN__' => dol_trunc($daytext, 1, 'right', 'UTF-8', 1), // M
8726 '__MONTH__' => (string) $tmp['mon'],
8727 '__MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp['mon'])),
8728 '__MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp['mon'])),
8729 '__MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp['mon'])),
8730 '__YEAR__' => (string) $tmp['year'],
8731 '__PREVIOUS_DAY__' => (string) $tmp2['day'],
8732 '__PREVIOUS_MONTH__' => (string) $tmp3['month'],
8733 '__PREVIOUS_YEAR__' => (string) ($tmp['year'] - 1),
8734 '__NEXT_DAY__' => (string) $tmp4['day'],
8735 '__NEXT_MONTH__' => (string) $tmp5['month'],
8736 '__NEXT_MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp5['month'])),
8737 '__NEXT_MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp5['month'])),
8738 '__NEXT_MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp5['month'])),
8739 '__NEXT_YEAR__' => (string) ($tmp['year'] + 1),
8740 ));
8741 }
8742
8743 if (isModEnabled('multicompany')) {
8744 $substitutionarray = array_merge($substitutionarray, array('__ENTITY_ID__' => $conf->entity));
8745 }
8746 if ((empty($exclude) || !in_array('system', $exclude)) && (empty($include) || in_array('user', $include))) {
8747 $substitutionarray['__DOL_MAIN_URL_ROOT__'] = DOL_MAIN_URL_ROOT;
8748 $substitutionarray['__(AnyTranslationKey)__'] = $outputlangs->trans('TranslationOfKey');
8749 $substitutionarray['__(AnyTranslationKey|langfile)__'] = $outputlangs->trans('TranslationOfKey').' (load also language file before)';
8750 $substitutionarray['__[AnyConstantKey]__'] = $outputlangs->trans('ValueOfConstantKey');
8751 }
8752
8753 // Note: The lazyload variables are replaced only during the call by make_substitutions, and only if necessary
8754
8755 return $substitutionarray;
8756}
8757
8774function make_substitutions($text, $substitutionarray, $outputlangs = null, $converttextinhtmlifnecessary = 0)
8775{
8776 global $conf, $db, $langs;
8777
8778 if (!is_array($substitutionarray)) {
8779 return 'ErrorBadParameterSubstitutionArrayWhenCalling_make_substitutions';
8780 }
8781
8782 if (empty($outputlangs)) {
8783 $outputlangs = $langs;
8784 }
8785
8786 // Is initial text HTML or simple text ?
8787 $msgishtml = 0;
8788 if (dol_textishtml($text, 1)) {
8789 $msgishtml = 1;
8790 }
8791
8792 // Make substitution for language keys: __(AnyTranslationKey)__ or __(AnyTranslationKey|langfile)__
8793 if (is_object($outputlangs)) {
8794 $reg = array();
8795 while (preg_match('/__\‍(([^\‍)]+)\‍)__/', $text, $reg)) {
8796 // If key is __(TranslationKey|langfile)__, then force load of langfile.lang
8797 $tmp = explode('|', $reg[1]);
8798 if (!empty($tmp[1])) {
8799 $outputlangs->load($tmp[1]);
8800 }
8801
8802 $value = $outputlangs->transnoentitiesnoconv($reg[1]);
8803
8804 if (empty($converttextinhtmlifnecessary)) {
8805 // convert $newval into HTML is necessary
8806 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8807 } else {
8808 if (! $msgishtml) {
8809 $valueishtml = dol_textishtml($value, 1);
8810 //var_dump("valueishtml=".$valueishtml);
8811
8812 if ($valueishtml) {
8813 $text = dol_htmlentitiesbr($text);
8814 $msgishtml = 1;
8815 }
8816 } else {
8817 $value = dol_nl2br("$value");
8818 }
8819
8820 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $value, $text);
8821 }
8822 }
8823 }
8824
8825 // Make substitution for constant keys.
8826 // Must be after the substitution of translation, so if the text of translation contains a string __[xxx]__, it is also converted.
8827 $reg = array();
8828 while (preg_match('/__\[([^\]]+)\]__/', $text, $reg)) {
8829 $keyfound = $reg[1];
8830 if (isASecretKey($keyfound)) {
8831 $value = '*****forbidden*****';
8832 } else {
8833 $value = empty($conf->global->$keyfound) ? '' : $conf->global->$keyfound;
8834 }
8835
8836 if (empty($converttextinhtmlifnecessary)) {
8837 // convert $newval into HTML is necessary
8838 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8839 } else {
8840 if (! $msgishtml) {
8841 $valueishtml = dol_textishtml($value, 1);
8842
8843 if ($valueishtml) {
8844 $text = dol_htmlentitiesbr($text);
8845 $msgishtml = 1;
8846 }
8847 } else {
8848 $value = dol_nl2br("$value");
8849 }
8850
8851 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $value, $text);
8852 }
8853 }
8854
8855 // Make substitution for array $substitutionarray
8856 foreach ($substitutionarray as $key => $value) {
8857 if (!isset($value)) {
8858 continue; // If value is null, it same than not having substitution key at all into array, we do not replace.
8859 }
8860
8861 if (($key == '__USER_SIGNATURE__' || $key == '__SENDEREMAIL_SIGNATURE__') && (getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN'))) {
8862 $value = ''; // Protection
8863 }
8864
8865 if (empty($converttextinhtmlifnecessary)) {
8866 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8867 } else {
8868 if (! $msgishtml) {
8869 $valueishtml = dol_textishtml($value, 1);
8870
8871 if ($valueishtml) {
8872 $text = dol_htmlentitiesbr($text);
8873 $msgishtml = 1;
8874 }
8875 } else {
8876 $value = dol_nl2br("$value");
8877 }
8878 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8879 }
8880 }
8881
8882 // TODO Implement the lazyload substitution
8883 /*
8884 add a loop to scan $substitutionarray:
8885 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.
8886 If no, we don't need to make replacement, so we do nothing.
8887 If yes, we can make the substitution:
8888
8889 include_once $path;
8890 $tmpobj = new $class($db);
8891 $valuetouseforsubstitution = $tmpobj->$method($id, '__XXX__');
8892 And make the replacement of "__XXX__@lazyload" with $valuetouseforsubstitution
8893 */
8894 $memory_object_list = array();
8895 foreach ($substitutionarray as $key => $value) {
8896 $lazy_load_arr = array();
8897 if (preg_match('/(__[A-Z\_]+__)@lazyload$/', $key, $lazy_load_arr)) {
8898 if (isset($lazy_load_arr[1]) && !empty($lazy_load_arr[1])) {
8899 $key_to_substitute = $lazy_load_arr[1];
8900 if (preg_match('/' . preg_quote($key_to_substitute, '/') . '/', $text)) {
8901 $param_arr = explode(':', $value);
8902 // path:class:method:id
8903 if (count($param_arr) == 4) {
8904 $path = $param_arr[0];
8905 $class = $param_arr[1];
8906 $method = $param_arr[2];
8907 $id = (int) $param_arr[3];
8908
8909 // load class file and init object list in memory
8910 if (!isset($memory_object_list[$class])) {
8911 if (dol_is_file(DOL_DOCUMENT_ROOT . $path)) {
8912 require_once DOL_DOCUMENT_ROOT . $path;
8913 if (class_exists($class)) {
8914 $memory_object_list[$class] = array(
8915 'list' => array(),
8916 );
8917 }
8918 }
8919 }
8920
8921 // fetch object and set substitution
8922 if (isset($memory_object_list[$class]) && isset($memory_object_list[$class]['list'])) {
8923 if (method_exists($class, $method)) {
8924 if (!isset($memory_object_list[$class]['list'][$id])) {
8925 $tmpobj = new $class($db);
8926 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute);
8927 $memory_object_list[$class]['list'][$id] = $tmpobj;
8928 } else {
8929 $tmpobj = $memory_object_list[$class]['list'][$id];
8930 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute, true);
8931 }
8932
8933 $text = str_replace("$key_to_substitute", "$valuetouseforsubstitution", $text); // We must keep the " to work when value is 123.5 for example
8934 }
8935 }
8936 }
8937 }
8938 }
8939 }
8940 }
8941
8942 return $text;
8943}
8944
8957function complete_substitutions_array(&$substitutionarray, $outputlangs, $object = null, $parameters = null, $callfunc = "completesubstitutionarray")
8958{
8959 global $conf, $user;
8960
8961 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
8962
8963 // Note: substitution key for each extrafields, using key __EXTRA_XXX__ is already available into the getCommonSubstitutionArray used to build the substitution array.
8964
8965 // Check if there is external substitution to do, requested by plugins
8966 $dirsubstitutions = array_merge(array(), (array) $conf->modules_parts['substitutions']);
8967
8968 foreach ($dirsubstitutions as $reldir) {
8969 $dir = dol_buildpath($reldir, 0);
8970
8971 // Check if directory exists
8972 if (!dol_is_dir($dir)) {
8973 continue;
8974 }
8975
8976 $substitfiles = dol_dir_list($dir, 'files', 0, 'functions_');
8977 foreach ($substitfiles as $substitfile) {
8978 $reg = array();
8979 if (preg_match('/functions_(.*)\.lib\.php/i', $substitfile['name'], $reg)) {
8980 $module = $reg[1];
8981
8982 dol_syslog("Library ".$substitfile['name']." found into ".$dir);
8983 // Include the user's functions file
8984 require_once $dir.$substitfile['name'];
8985 // Call the user's function, and only if it is defined
8986 $function_name = $module."_".$callfunc;
8987 if (function_exists($function_name)) {
8988 $function_name($substitutionarray, $outputlangs, $object, $parameters);
8989 }
8990 }
8991 }
8992 }
8993 if (getDolGlobalString('ODT_ENABLE_ALL_TAGS_IN_SUBSTITUTIONS')) {
8994 // to list all tags in odt template
8995 $tags = '';
8996 foreach ($substitutionarray as $key => $value) {
8997 $tags .= '{'.$key.'} => '.$value."\n";
8998 }
8999 $substitutionarray = array_merge($substitutionarray, array('__ALL_TAGS__' => $tags));
9000 }
9001}
9002
9012function print_date_range($date_start, $date_end, $format = '', $outputlangs = '')
9013{
9014 print get_date_range($date_start, $date_end, $format, $outputlangs);
9015}
9016
9027function get_date_range($date_start, $date_end, $format = '', $outputlangs = '', $withparenthesis = 1)
9028{
9029 global $langs;
9030
9031 $out = '';
9032
9033 if (!is_object($outputlangs)) {
9034 $outputlangs = $langs;
9035 }
9036
9037 if ($date_start && $date_end) {
9038 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFromTo', dol_print_date($date_start, $format, false, $outputlangs), dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9039 }
9040 if ($date_start && !$date_end) {
9041 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($date_start, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9042 }
9043 if (!$date_start && $date_end) {
9044 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9045 }
9046
9047 return $out;
9048}
9049
9058function dolGetFirstLastname($firstname, $lastname, $nameorder = -1)
9059{
9060 global $conf;
9061
9062 $ret = '';
9063 // If order not defined, we use the setup
9064 if ($nameorder < 0) {
9065 $nameorder = (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION') ? 1 : 0);
9066 }
9067 if ($nameorder == 1) {
9068 $ret .= $firstname;
9069 if ($firstname && $lastname) {
9070 $ret .= ' ';
9071 }
9072 $ret .= $lastname;
9073 } elseif ($nameorder == 2 || $nameorder == 3) {
9074 $ret .= $firstname;
9075 if (empty($ret) && $nameorder == 3) {
9076 $ret .= $lastname;
9077 }
9078 } else { // 0, 4 or 5
9079 $ret .= $lastname;
9080 if (empty($ret) && $nameorder == 5) {
9081 $ret .= $firstname;
9082 }
9083 if ($nameorder == 0) {
9084 if ($firstname && $lastname) {
9085 $ret .= ' ';
9086 }
9087 $ret .= $firstname;
9088 }
9089 }
9090 return $ret;
9091}
9092
9093
9105function setEventMessage($mesgs, $style = 'mesgs', $noduplicate = 0)
9106{
9107 //dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING); This is not deprecated, it is used by setEventMessages function
9108 if (!is_array($mesgs)) {
9109 $mesgs = trim((string) $mesgs);
9110 // If mesgs is a not an empty string
9111 if ($mesgs) {
9112 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesgs, $_SESSION['dol_events'][$style])) {
9113 return;
9114 }
9115 $_SESSION['dol_events'][$style][] = $mesgs;
9116 }
9117 } else {
9118 // If mesgs is an array
9119 foreach ($mesgs as $mesg) {
9120 $mesg = trim((string) $mesg);
9121 if ($mesg) {
9122 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesg, $_SESSION['dol_events'][$style])) {
9123 return;
9124 }
9125 $_SESSION['dol_events'][$style][] = $mesg;
9126 }
9127 }
9128 }
9129}
9130
9143function setEventMessages($mesg, $mesgs, $style = 'mesgs', $messagekey = '', $noduplicate = 0)
9144{
9145 if (empty($mesg) && empty($mesgs)) {
9146 dol_syslog("Try to add a message in stack, but value to add is empty message", LOG_WARNING);
9147 } else {
9148 if ($messagekey) {
9149 // Complete message with a js link to set a cookie "DOLHIDEMESSAGE".$messagekey;
9150 // TODO
9151 $mesg .= '';
9152 }
9153 if (empty($messagekey) || empty($_COOKIE["DOLHIDEMESSAGE".$messagekey])) {
9154 if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
9155 dol_print_error('', 'Bad parameter style='.$style.' for setEventMessages');
9156 }
9157 if (empty($mesgs)) {
9158 setEventMessage($mesg, $style, $noduplicate);
9159 } else {
9160 if (!empty($mesg) && !in_array($mesg, $mesgs)) {
9161 setEventMessage($mesg, $style, $noduplicate); // Add message string if not already into array
9162 }
9163 setEventMessage($mesgs, $style, $noduplicate);
9164 }
9165 }
9166 }
9167}
9168
9178function dol_htmloutput_events($disabledoutputofmessages = 0)
9179{
9180 // Show mesgs
9181 if (isset($_SESSION['dol_events']['mesgs'])) {
9182 if (empty($disabledoutputofmessages)) {
9183 dol_htmloutput_mesg('', $_SESSION['dol_events']['mesgs']);
9184 }
9185 unset($_SESSION['dol_events']['mesgs']);
9186 }
9187 // Show errors
9188 if (isset($_SESSION['dol_events']['errors'])) {
9189 if (empty($disabledoutputofmessages)) {
9190 dol_htmloutput_mesg('', $_SESSION['dol_events']['errors'], 'error');
9191 }
9192 unset($_SESSION['dol_events']['errors']);
9193 }
9194
9195 // Show warnings
9196 if (isset($_SESSION['dol_events']['warnings'])) {
9197 if (empty($disabledoutputofmessages)) {
9198 dol_htmloutput_mesg('', $_SESSION['dol_events']['warnings'], 'warning');
9199 }
9200 unset($_SESSION['dol_events']['warnings']);
9201 }
9202}
9203
9218function get_htmloutput_mesg($mesgstring = '', $mesgarray = '', $style = 'ok', $keepembedded = 0)
9219{
9220 global $conf, $langs;
9221
9222 $ret = 0;
9223 $return = '';
9224 $out = '';
9225 $divstart = $divend = '';
9226
9227 // If inline message with no format, we add it.
9228 if ((empty($conf->use_javascript_ajax) || getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') || $keepembedded) && !preg_match('/<div class=".*">/i', $out)) {
9229 $divstart = '<div class="'.$style.' clearboth">';
9230 $divend = '</div>';
9231 }
9232
9233 if ((is_array($mesgarray) && count($mesgarray)) || $mesgstring) {
9234 $langs->load("errors");
9235 $out .= $divstart;
9236 if (is_array($mesgarray) && count($mesgarray)) {
9237 foreach ($mesgarray as $message) {
9238 $ret++;
9239 $out .= $langs->trans($message);
9240 if ($ret < count($mesgarray)) {
9241 $out .= "<br>\n";
9242 }
9243 }
9244 }
9245 if ($mesgstring) {
9246 $ret++;
9247 $out .= $langs->trans($mesgstring);
9248 }
9249 $out .= $divend;
9250 }
9251
9252 if ($out) {
9253 if (!empty($conf->use_javascript_ajax) && !getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') && empty($keepembedded)) {
9254 $return = '<script nonce="'.getNonce().'">
9255 $(document).ready(function() {
9256 var block = '.(getDolGlobalString('MAIN_USE_JQUERY_BLOCKUI') ? "true" : "false").'
9257 if (block) {
9258 $.dolEventValid("","'.dol_escape_js($out).'");
9259 } else {
9260 /* jnotify(message, preset of message type, keepmessage) */
9261 $.jnotify("'.dol_escape_js($out).'",
9262 "'.($style == "ok" ? 3000 : $style).'",
9263 '.($style == "ok" ? "false" : "true").',
9264 { remove: function (){} } );
9265 }
9266 });
9267 </script>';
9268 } else {
9269 $return = $out;
9270 }
9271 }
9272
9273 return $return;
9274}
9275
9287function get_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9288{
9289 return get_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9290}
9291
9305function dol_htmloutput_mesg($mesgstring = '', $mesgarray = array(), $style = 'ok', $keepembedded = 0)
9306{
9307 if (empty($mesgstring) && (!is_array($mesgarray) || count($mesgarray) == 0)) {
9308 return;
9309 }
9310
9311 $iserror = 0;
9312 $iswarning = 0;
9313 if (is_array($mesgarray)) {
9314 foreach ($mesgarray as $val) {
9315 if ($val && preg_match('/class="error"/i', $val)) {
9316 $iserror++;
9317 break;
9318 }
9319 if ($val && preg_match('/class="warning"/i', $val)) {
9320 $iswarning++;
9321 break;
9322 }
9323 }
9324 } elseif ($mesgstring && preg_match('/class="error"/i', $mesgstring)) {
9325 $iserror++;
9326 } elseif ($mesgstring && preg_match('/class="warning"/i', $mesgstring)) {
9327 $iswarning++;
9328 }
9329 if ($style == 'error') {
9330 $iserror++;
9331 }
9332 if ($style == 'warning') {
9333 $iswarning++;
9334 }
9335
9336 if ($iserror || $iswarning) {
9337 // Remove div from texts
9338 $mesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $mesgstring);
9339 $mesgstring = preg_replace('/<div class="(error|warning)">/', '', $mesgstring);
9340 $mesgstring = preg_replace('/<\/div>/', '', $mesgstring);
9341 // Remove div from texts array
9342 if (is_array($mesgarray)) {
9343 $newmesgarray = array();
9344 foreach ($mesgarray as $val) {
9345 if (is_string($val)) {
9346 $tmpmesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $val);
9347 $tmpmesgstring = preg_replace('/<div class="(error|warning)">/', '', $tmpmesgstring);
9348 $tmpmesgstring = preg_replace('/<\/div>/', '', $tmpmesgstring);
9349 $newmesgarray[] = $tmpmesgstring;
9350 } else {
9351 dol_syslog("Error call of dol_htmloutput_mesg with an array with a value that is not a string", LOG_WARNING);
9352 }
9353 }
9354 $mesgarray = $newmesgarray;
9355 }
9356 print get_htmloutput_mesg($mesgstring, $mesgarray, ($iserror ? 'error' : 'warning'), $keepembedded);
9357 } else {
9358 print get_htmloutput_mesg($mesgstring, $mesgarray, 'ok', $keepembedded);
9359 }
9360}
9361
9373function dol_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9374{
9375 dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9376}
9377
9392function dol_sort_array(&$array, $index, $order = 'asc', $natsort = 0, $case_sensitive = 0, $keepindex = 0)
9393{
9394 // Clean parameters
9395 $order = strtolower($order);
9396
9397 if (is_array($array)) {
9398 $sizearray = count($array);
9399 if ($sizearray > 0) {
9400 $temp = array();
9401 foreach (array_keys($array) as $key) {
9402 if (is_object($array[$key])) {
9403 $temp[$key] = empty($array[$key]->$index) ? 0 : $array[$key]->$index;
9404 } else {
9405 $temp[$key] = empty($array[$key][$index]) ? 0 : $array[$key][$index];
9406 }
9407 if ($natsort == -1) {
9408 $temp[$key] = '___'.$temp[$key]; // We add a string at begin of value to force an alpha order when using asort.
9409 }
9410 }
9411
9412 if (empty($natsort) || $natsort == -1) {
9413 if ($order == 'asc') {
9414 asort($temp);
9415 } else {
9416 arsort($temp);
9417 }
9418 } else {
9419 if ($case_sensitive) {
9420 natsort($temp);
9421 } else {
9422 natcasesort($temp); // natecasesort is not sensible to case
9423 }
9424 if ($order != 'asc') {
9425 $temp = array_reverse($temp, true);
9426 }
9427 }
9428
9429 $sorted = array();
9430
9431 foreach (array_keys($temp) as $key) {
9432 (is_numeric($key) && empty($keepindex)) ? $sorted[] = $array[$key] : $sorted[$key] = $array[$key];
9433 }
9434
9435 return $sorted;
9436 }
9437 }
9438 return $array;
9439}
9440
9441
9449function utf8_check($str)
9450{
9451 $str = (string) $str; // Sometimes string is an int.
9452
9453 // We must use here a binary strlen function (so not dol_strlen)
9454 $strLength = strlen($str);
9455 for ($i = 0; $i < $strLength; $i++) {
9456 if (ord($str[$i]) < 0x80) {
9457 continue; // 0bbbbbbb
9458 } elseif ((ord($str[$i]) & 0xE0) == 0xC0) {
9459 $n = 1; // 110bbbbb
9460 } elseif ((ord($str[$i]) & 0xF0) == 0xE0) {
9461 $n = 2; // 1110bbbb
9462 } elseif ((ord($str[$i]) & 0xF8) == 0xF0) {
9463 $n = 3; // 11110bbb
9464 } elseif ((ord($str[$i]) & 0xFC) == 0xF8) {
9465 $n = 4; // 111110bb
9466 } elseif ((ord($str[$i]) & 0xFE) == 0xFC) {
9467 $n = 5; // 1111110b
9468 } else {
9469 return false; // Does not match any model
9470 }
9471 for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
9472 if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80)) {
9473 return false;
9474 }
9475 }
9476 }
9477 return true;
9478}
9479
9487function utf8_valid($str)
9488{
9489 /* 2 other methods to test if string is utf8
9490 $validUTF8 = mb_check_encoding($messagetext, 'UTF-8');
9491 $validUTF8b = ! (false === mb_detect_encoding($messagetext, 'UTF-8', true));
9492 */
9493 return preg_match('//u', $str) ? true : false;
9494}
9495
9496
9503function ascii_check($str)
9504{
9505 if (function_exists('mb_check_encoding')) {
9506 //if (mb_detect_encoding($str, 'ASCII', true) return false;
9507 if (!mb_check_encoding($str, 'ASCII')) {
9508 return false;
9509 }
9510 } else {
9511 if (preg_match('/[^\x00-\x7f]/', $str)) {
9512 return false; // Contains a byte > 7f
9513 }
9514 }
9515
9516 return true;
9517}
9518
9519
9527function dol_osencode($str)
9528{
9529 global $conf;
9530
9531 $tmp = ini_get("unicode.filesystem_encoding"); // Disponible avec PHP 6.0
9532 if (empty($tmp) && !empty($_SERVER["WINDIR"])) {
9533 $tmp = 'iso-8859-1'; // By default for windows
9534 }
9535 if (empty($tmp)) {
9536 $tmp = 'utf-8'; // By default for other
9537 }
9538 if (getDolGlobalString('MAIN_FILESYSTEM_ENCODING')) {
9539 $tmp = $conf->global->MAIN_FILESYSTEM_ENCODING;
9540 }
9541
9542 if ($tmp == 'iso-8859-1') {
9543 return mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8');
9544 }
9545 return $str;
9546}
9547
9548
9564function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '', $useCache = true)
9565{
9566 global $cache_codes;
9567
9568 // If key empty
9569 if ($key == '') {
9570 return '';
9571 }
9572
9573 // Check in cache
9574 if ($useCache && isset($cache_codes[$tablename][$fieldkey][$fieldid][$entityfilter][$filters][$key])) { // Can be defined to 0 or ''
9575 return $cache_codes[$tablename][$fieldkey][$fieldid][$entityfilter][$filters][$key]; // Found in cache
9576 }
9577
9578 dol_syslog('dol_getIdFromCode (value for field '.$fieldid.' from key '.$key.' not found into cache)', LOG_DEBUG);
9579
9580 $sql = "SELECT ".$fieldid." as valuetoget";
9581 $sql .= " FROM ".MAIN_DB_PREFIX.$tablename;
9582 $sql .= " WHERE ".$fieldkey." = '".$db->escape($key)."'";
9583 if (!empty($entityfilter)) {
9584 $sql .= " AND entity IN (".getEntity($tablename).")";
9585 }
9586 if ($filters) {
9587 $sql .= $filters;
9588 }
9589
9590 $resql = $db->query($sql);
9591 if ($resql) {
9592 $obj = $db->fetch_object($resql);
9593 $valuetoget = '';
9594 if ($obj) {
9595 $valuetoget = $obj->valuetoget;
9596 }
9597 $db->free($resql);
9598 if ($useCache) {
9599 $cache_codes[$tablename][$fieldkey][$fieldid][$entityfilter][$filters][$key] = $valuetoget;
9600 }
9601 return $valuetoget;
9602 } else {
9603 return -1;
9604 }
9605}
9606
9616function isStringVarMatching($var, $regextext, $matchrule = 1)
9617{
9618 if ($matchrule == 1) {
9619 if ($var == 'mainmenu') {
9620 global $mainmenu;
9621 return (preg_match('/^'.$regextext.'/', $mainmenu));
9622 } elseif ($var == 'leftmenu') {
9623 global $leftmenu;
9624 return (preg_match('/^'.$regextext.'/', $leftmenu));
9625 } else {
9626 return 'This variable is not accessible with dol_eval';
9627 }
9628 } else {
9629 return 'This value for matchrule is not implemented';
9630 }
9631}
9632
9633
9640function verifCond($strToEvaluate)
9641{
9642 //print $strToEvaluate."<br>\n";
9643 $rights = true;
9644 if (isset($strToEvaluate) && $strToEvaluate !== '') {
9645 //var_dump($strToEvaluate);
9646 //$rep = dol_eval($strToEvaluate, 1, 0, '1'); // to show the error
9647 $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
9648 $rights = $rep && (!is_string($rep) || strpos($rep, 'Bad string syntax to evaluate') === false);
9649 //var_dump($rights);
9650 }
9651 return $rights;
9652}
9653
9667function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1')
9668{
9669 // Only this global variables can be read by eval function and returned to caller
9670 global $conf; // Read of const is done with getDolGlobalString() but we need $conf->currency for example
9671 global $db, $langs, $user, $website, $websitepage;
9672 global $action, $mainmenu, $leftmenu;
9673 global $mysoc;
9674 global $objectoffield; // To allow the use of $objectoffield in computed fields
9675
9676 // Old variables used
9677 global $object;
9678 global $obj; // To get $obj used into list when dol_eval() is used for computed fields and $obj is not yet $object
9679
9680 if (!in_array($onlysimplestring, array('0', '1', '2'))) {
9681 return "Bad call of dol_eval. Parameter onlysimplestring must be '0' (deprecated), '1' or '2'";
9682 }
9683
9684 try {
9685 // Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing
9686 if ($onlysimplestring == '1') {
9687 // We must accept: '1 && getDolGlobalInt("doesnotexist1") && getDolGlobalString("MAIN_FEATURES_LEVEL")'
9688 // We must accept: '$user->hasRight("cabinetmed", "read") && !$object->canvas=="patient@cabinetmed"'
9689 $specialcharsallowed = '^$_+-.*>&|=!?():"\',/@';
9690 if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
9691 $specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
9692 }
9693 if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
9694 if ($returnvalue) {
9695 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9696 } else {
9697 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9698 return '';
9699 }
9700 }
9701 $savescheck = '';
9702 $scheck = $s;
9703 while ($scheck && $savescheck != $scheck) {
9704 $savescheck = $scheck;
9705 $scheck = preg_replace('/->[a-zA-Z0-9_]+\‍(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
9706 $scheck = preg_replace('/^\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9707 $scheck = preg_replace('/\s\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9708 $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
9709 $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
9710 $scheck = preg_replace('/(\^|\')\‍(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
9711 }
9712 //print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
9713 if (strpos($scheck, '(') !== false) {
9714 if ($returnvalue) {
9715 return 'Bad string syntax to evaluate (mode 1, found call of a function or method without using the direct name of the function): '.$s;
9716 } else {
9717 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);
9718 return '';
9719 }
9720 }
9721 // TODO
9722 // We can exclude $ char that are not: $db, $langs, $leftmenu, $topmenu, $user, $langs, $objectoffield, $object...,
9723 } elseif ($onlysimplestring == '2') {
9724 // 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"
9725 $specialcharsallowed = '^$_+-.*>&|=!?():"\',/@[]';
9726 if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
9727 $specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
9728 }
9729 if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
9730 if ($returnvalue) {
9731 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9732 } else {
9733 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9734 return '';
9735 }
9736 }
9737 $savescheck = '';
9738 $scheck = $s;
9739 while ($scheck && $savescheck != $scheck) {
9740 $savescheck = $scheck;
9741 $scheck = preg_replace('/->[a-zA-Z0-9_]+\‍(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
9742 $scheck = preg_replace('/^\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9743 $scheck = preg_replace('/\s\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9744 $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
9745 $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
9746 $scheck = preg_replace('/(\^|\')\‍(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
9747 }
9748 //print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
9749 if (strpos($scheck, '(') !== false) {
9750 if ($returnvalue) {
9751 return 'Bad string syntax to evaluate (mode 2, found call of a function or method without using the direct name of the function): '.$s;
9752 } else {
9753 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);
9754 return '';
9755 }
9756 }
9757 // TODO
9758 // We can exclude $ char that are not: $db, $leftmenu, $topmenu, $user, $langs, $object...,
9759 }
9760 if (is_array($s) || $s === 'Array') {
9761 return 'Bad string syntax to evaluate (value is Array) '.var_export($s, true);
9762 }
9763 if (strpos($s, '::') !== false) {
9764 if ($returnvalue) {
9765 return 'Bad string syntax to evaluate (double : char is forbidden): '.$s;
9766 } else {
9767 dol_syslog('Bad string syntax to evaluate (double : char is forbidden): '.$s);
9768 return '';
9769 }
9770 }
9771 if (strpos($s, '`') !== false) {
9772 if ($returnvalue) {
9773 return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
9774 } else {
9775 dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s);
9776 return '';
9777 }
9778 }
9779 if (preg_match('/[^0-9]+\.[^0-9]+/', $s)) { // We refuse . if not between 2 numbers
9780 if ($returnvalue) {
9781 return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
9782 } else {
9783 dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s);
9784 return '';
9785 }
9786 }
9787
9788 // We block use of php exec or php file functions
9789 $forbiddenphpstrings = array('$$');
9790 $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
9791
9792 $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen");
9793 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
9794 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64_decode", "rawurldecode", "urldecode", "str_rot13", "hex2bin")); // decode string functions used to obfuscated function name
9795 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
9796 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
9797 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));
9798 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
9799 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
9800
9801 $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
9802
9803 $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
9804
9805 $forbiddenphpmethodsregex = '->('.implode('|', $forbiddenphpmethods).')';
9806
9807 do {
9808 $oldstringtoclean = $s;
9809 $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);
9810 $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);
9811 $s = preg_replace('/'.$forbiddenphpmethodsregex.'/i', '__forbiddenstring__', $s);
9812 //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\‍(/i', '', $s); // Remove $function( call and $mycall->mymethod(
9813 } while ($oldstringtoclean != $s);
9814
9815 if (strpos($s, '__forbiddenstring__') !== false) {
9816 dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
9817 if ($returnvalue) {
9818 return 'Bad string syntax to evaluate: '.$s;
9819 } else {
9820 dol_syslog('Bad string syntax to evaluate: '.$s);
9821 return '';
9822 }
9823 }
9824
9825 //print $s."<br>\n";
9826 if ($returnvalue) {
9827 if ($hideerrors) {
9828 return @eval('return '.$s.';');
9829 } else {
9830 return eval('return '.$s.';');
9831 }
9832 } else {
9833 if ($hideerrors) {
9834 @eval($s);
9835 } else {
9836 eval($s);
9837 }
9838 }
9839 } catch (Error $e) {
9840 $error = 'dol_eval try/catch error : ';
9841 $error .= $e->getMessage();
9842 dol_syslog($error, LOG_WARNING);
9843 }
9844}
9845
9853function dol_validElement($element)
9854{
9855 return (trim($element) != '');
9856}
9857
9866function picto_from_langcode($codelang, $moreatt = '', $notitlealt = 0)
9867{
9868 if (empty($codelang)) {
9869 return '';
9870 }
9871
9872 if ($codelang == 'auto') {
9873 return '<span class="fa fa-language"></span>';
9874 }
9875
9876 $langtocountryflag = array(
9877 'ar_AR' => '',
9878 'ca_ES' => 'catalonia',
9879 'da_DA' => 'dk',
9880 'fr_CA' => 'mq',
9881 'sv_SV' => 'se',
9882 'sw_SW' => 'unknown',
9883 'AQ' => 'unknown',
9884 'CW' => 'unknown',
9885 'IM' => 'unknown',
9886 'JE' => 'unknown',
9887 'MF' => 'unknown',
9888 'BL' => 'unknown',
9889 'SX' => 'unknown'
9890 );
9891
9892 if (isset($langtocountryflag[$codelang])) {
9893 $flagImage = $langtocountryflag[$codelang];
9894 } else {
9895 $tmparray = explode('_', $codelang);
9896 $flagImage = empty($tmparray[1]) ? $tmparray[0] : $tmparray[1];
9897 }
9898
9899 $morecss = '';
9900 $reg = array();
9901 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
9902 $morecss = $reg[1];
9903 $moreatt = "";
9904 }
9905
9906 // return img_picto_common($codelang, 'flags/'.strtolower($flagImage).'.png', $moreatt, 0, $notitlealt);
9907 return '<span class="flag-sprite '.strtolower($flagImage).($morecss ? ' '.$morecss : '').'"'.($moreatt ? ' '.$moreatt : '').(!$notitlealt ? ' title="'.$codelang.'"' : '').'></span>';
9908}
9909
9918{
9919 global $mysoc;
9920
9921 if (empty($countrycode)) {
9922 return null;
9923 }
9924
9925 if (strtoupper($countrycode) == 'MQ') {
9926 return 'fr_CA';
9927 }
9928 if (strtoupper($countrycode) == 'SE') {
9929 return 'sv_SE'; // se_SE is Sami/Sweden, and we want in priority sv_SE for SE country
9930 }
9931 if (strtoupper($countrycode) == 'CH') {
9932 if ($mysoc->country_code == 'FR') {
9933 return 'fr_CH';
9934 }
9935 if ($mysoc->country_code == 'DE') {
9936 return 'de_CH';
9937 }
9938 if ($mysoc->country_code == 'IT') {
9939 return 'it_CH';
9940 }
9941 }
9942
9943 // Locale list taken from:
9944 // http://stackoverflow.com/questions/3191664/
9945 // list-of-all-locales-and-their-short-codes
9946 $locales = array(
9947 'af-ZA',
9948 'am-ET',
9949 'ar-AE',
9950 'ar-BH',
9951 'ar-DZ',
9952 'ar-EG',
9953 'ar-IQ',
9954 'ar-JO',
9955 'ar-KW',
9956 'ar-LB',
9957 'ar-LY',
9958 'ar-MA',
9959 'ar-OM',
9960 'ar-QA',
9961 'ar-SA',
9962 'ar-SY',
9963 'ar-TN',
9964 'ar-YE',
9965 //'as-IN', // Moved after en-IN
9966 'ba-RU',
9967 'be-BY',
9968 'bg-BG',
9969 'bn-BD',
9970 //'bn-IN', // Moved after en-IN
9971 'bo-CN',
9972 'br-FR',
9973 'ca-ES',
9974 'co-FR',
9975 'cs-CZ',
9976 'cy-GB',
9977 'da-DK',
9978 'de-AT',
9979 'de-CH',
9980 'de-DE',
9981 'de-LI',
9982 'de-LU',
9983 'dv-MV',
9984 'el-GR',
9985 'en-AU',
9986 'en-BZ',
9987 'en-CA',
9988 'en-GB',
9989 'en-IE',
9990 'en-IN',
9991 'as-IN', // as-IN must be after en-IN (en in priority if country is IN)
9992 'bn-IN', // bn-IN must be after en-IN (en in priority if country is IN)
9993 'en-JM',
9994 'en-MY',
9995 'en-NZ',
9996 'en-PH',
9997 'en-SG',
9998 'en-TT',
9999 'en-US',
10000 'en-ZA',
10001 'en-ZW',
10002 'es-AR',
10003 'es-BO',
10004 'es-CL',
10005 'es-CO',
10006 'es-CR',
10007 'es-DO',
10008 'es-EC',
10009 'es-ES',
10010 'es-GT',
10011 'es-HN',
10012 'es-MX',
10013 'es-NI',
10014 'es-PA',
10015 'es-PE',
10016 'es-PR',
10017 'es-PY',
10018 'es-SV',
10019 'es-US',
10020 'es-UY',
10021 'es-VE',
10022 'et-EE',
10023 'eu-ES',
10024 'fa-IR',
10025 'fi-FI',
10026 'fo-FO',
10027 'fr-BE',
10028 'fr-CA',
10029 'fr-CH',
10030 'fr-FR',
10031 'fr-LU',
10032 'fr-MC',
10033 'fy-NL',
10034 'ga-IE',
10035 'gd-GB',
10036 'gl-ES',
10037 'gu-IN',
10038 'he-IL',
10039 'hi-IN',
10040 'hr-BA',
10041 'hr-HR',
10042 'hu-HU',
10043 'hy-AM',
10044 'id-ID',
10045 'ig-NG',
10046 'ii-CN',
10047 'is-IS',
10048 'it-CH',
10049 'it-IT',
10050 'ja-JP',
10051 'ka-GE',
10052 'kk-KZ',
10053 'kl-GL',
10054 'km-KH',
10055 'kn-IN',
10056 'ko-KR',
10057 'ky-KG',
10058 'lb-LU',
10059 'lo-LA',
10060 'lt-LT',
10061 'lv-LV',
10062 'mi-NZ',
10063 'mk-MK',
10064 'ml-IN',
10065 'mn-MN',
10066 'mr-IN',
10067 'ms-BN',
10068 'ms-MY',
10069 'mt-MT',
10070 'nb-NO',
10071 'ne-NP',
10072 'nl-BE',
10073 'nl-NL',
10074 'nn-NO',
10075 'oc-FR',
10076 'or-IN',
10077 'pa-IN',
10078 'pl-PL',
10079 'ps-AF',
10080 'pt-BR',
10081 'pt-PT',
10082 'rm-CH',
10083 'ro-MD',
10084 'ro-RO',
10085 'ru-RU',
10086 'rw-RW',
10087 'sa-IN',
10088 'se-FI',
10089 'se-NO',
10090 'se-SE',
10091 'si-LK',
10092 'sk-SK',
10093 'sl-SI',
10094 'sq-AL',
10095 'sv-FI',
10096 'sv-SE',
10097 'sw-KE',
10098 'ta-IN',
10099 'te-IN',
10100 'th-TH',
10101 'tk-TM',
10102 'tn-ZA',
10103 'tr-TR',
10104 'tt-RU',
10105 'ug-CN',
10106 'uk-UA',
10107 'ur-PK',
10108 'vi-VN',
10109 'wo-SN',
10110 'xh-ZA',
10111 'yo-NG',
10112 'zh-CN',
10113 'zh-HK',
10114 'zh-MO',
10115 'zh-SG',
10116 'zh-TW',
10117 'zu-ZA',
10118 );
10119
10120 $buildprimarykeytotest = strtolower($countrycode).'-'.strtoupper($countrycode);
10121 if (in_array($buildprimarykeytotest, $locales)) {
10122 return strtolower($countrycode).'_'.strtoupper($countrycode);
10123 }
10124
10125 if (function_exists('locale_get_primary_language') && function_exists('locale_get_region')) { // Need extension php-intl
10126 foreach ($locales as $locale) {
10127 $locale_language = locale_get_primary_language($locale);
10128 $locale_region = locale_get_region($locale);
10129 if (strtoupper($countrycode) == $locale_region) {
10130 //var_dump($locale.' - '.$locale_language.' - '.$locale_region);
10131 return strtolower($locale_language).'_'.strtoupper($locale_region);
10132 }
10133 }
10134 } else {
10135 dol_syslog("Warning Exention php-intl is not available", LOG_WARNING);
10136 }
10137
10138 return null;
10139}
10140
10171function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode = 'add', $filterorigmodule = '')
10172{
10173 global $hookmanager, $db;
10174
10175 if (isset($conf->modules_parts['tabs'][$type]) && is_array($conf->modules_parts['tabs'][$type])) {
10176 foreach ($conf->modules_parts['tabs'][$type] as $value) {
10177 $values = explode(':', $value);
10178
10179 $reg = array();
10180 if ($mode == 'add' && !preg_match('/^\-/', $values[1])) {
10181 $newtab = array();
10182 $postab = $h;
10183 // detect if position set in $values[1] ie : +(2)mytab@mymodule (first tab is 0, second is one, ...)
10184 $str = $values[1];
10185 $posstart = strpos($str, '(');
10186 if ($posstart > 0) {
10187 $posend = strpos($str, ')');
10188 if ($posstart > 0) {
10189 $res1 = substr($str, $posstart + 1, $posend - $posstart -1);
10190 if (is_numeric($res1)) {
10191 $postab = (int) $res1;
10192 $values[1] = '+' . substr($str, $posend + 1);
10193 }
10194 }
10195 }
10196 if (count($values) == 6) {
10197 // new declaration with permissions:
10198 // $value='objecttype:+tabname1:Title1:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10199 // $value='objecttype:+tabname1:Title1,class,pathfile,method:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10200 if ($values[0] != $type) {
10201 continue;
10202 }
10203
10204 if (verifCond($values[4])) {
10205 if ($values[3]) {
10206 if ($filterorigmodule) { // If a filter of module origin has been requested
10207 if (strpos($values[3], '@')) { // This is an external module
10208 if ($filterorigmodule != 'external') {
10209 continue;
10210 }
10211 } else { // This looks a core module
10212 if ($filterorigmodule != 'core') {
10213 continue;
10214 }
10215 }
10216 }
10217 $langs->load($values[3]);
10218 }
10219 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10220 // If label is "SUBSTITUION_..."
10221 $substitutionarray = array();
10222 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
10223 $label = make_substitutions($reg[1], $substitutionarray);
10224 } else {
10225 // If label is "Label,Class,File,Method", we call the method to show content inside the badge
10226 $labeltemp = explode(',', $values[2]);
10227 $label = $langs->trans($labeltemp[0]);
10228
10229 if (!empty($labeltemp[1]) && is_object($object) && !empty($object->id)) {
10230 dol_include_once($labeltemp[2]);
10231 $classtoload = $labeltemp[1];
10232 if (class_exists($classtoload)) {
10233 $obj = new $classtoload($db);
10234 $function = $labeltemp[3];
10235 if ($obj && $function && method_exists($obj, $function)) {
10236 $nbrec = $obj->$function($object->id, $obj);
10237 if (!empty($nbrec)) {
10238 $label .= '<span class="badge marginleftonlyshort">'.$nbrec.'</span>';
10239 }
10240 }
10241 }
10242 }
10243 }
10244
10245 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[5]), 1);
10246 $newtab[1] = $label;
10247 $newtab[2] = str_replace('+', '', $values[1]);
10248 $h++;
10249 } else {
10250 continue;
10251 }
10252 } elseif (count($values) == 5) { // case deprecated
10253 dol_syslog('Passing 5 values in tabs module_parts is deprecated. Please update to 6 with permissions.', LOG_WARNING);
10254
10255 if ($values[0] != $type) {
10256 continue;
10257 }
10258 if ($values[3]) {
10259 if ($filterorigmodule) { // If a filter of module origin has been requested
10260 if (strpos($values[3], '@')) { // This is an external module
10261 if ($filterorigmodule != 'external') {
10262 continue;
10263 }
10264 } else { // This looks a core module
10265 if ($filterorigmodule != 'core') {
10266 continue;
10267 }
10268 }
10269 }
10270 $langs->load($values[3]);
10271 }
10272 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10273 $substitutionarray = array();
10274 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
10275 $label = make_substitutions($reg[1], $substitutionarray);
10276 } else {
10277 $label = $langs->trans($values[2]);
10278 }
10279
10280 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[4]), 1);
10281 $newtab[1] = $label;
10282 $newtab[2] = str_replace('+', '', $values[1]);
10283 $h++;
10284 }
10285 // set tab at its position
10286 $head = array_merge(array_slice($head, 0, $postab), array($newtab), array_slice($head, $postab));
10287 } elseif ($mode == 'remove' && preg_match('/^\-/', $values[1])) {
10288 if ($values[0] != $type) {
10289 continue;
10290 }
10291 $tabname = str_replace('-', '', $values[1]);
10292 foreach ($head as $key => $val) {
10293 $condition = (!empty($values[3]) ? verifCond($values[3]) : 1);
10294 //var_dump($key.' - '.$tabname.' - '.$head[$key][2].' - '.$values[3].' - '.$condition);
10295 if ($head[$key][2] == $tabname && $condition) {
10296 unset($head[$key]);
10297 break;
10298 }
10299 }
10300 }
10301 }
10302 }
10303
10304 // No need to make a return $head. Var is modified as a reference
10305 if (!empty($hookmanager)) {
10306 $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule);
10307 $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters, $object);
10308 if ($reshook > 0) { // Hook ask to replace completely the array
10309 $head = $hookmanager->resArray;
10310 } else { // Hook
10311 $head = array_merge($head, $hookmanager->resArray);
10312 }
10313 $h = count($head);
10314 }
10315}
10316
10328function printCommonFooter($zone = 'private')
10329{
10330 global $conf, $hookmanager, $user, $debugbar;
10331 global $action;
10332 global $micro_start_time;
10333
10334 if ($zone == 'private') {
10335 print "\n".'<!-- Common footer for private page -->'."\n";
10336 } else {
10337 print "\n".'<!-- Common footer for public page -->'."\n";
10338 }
10339
10340 // A div to store page_y POST parameter so we can read it using javascript
10341 print "\n<!-- A div to store page_y POST parameter -->\n";
10342 print '<div id="page_y" style="display: none;">'.(GETPOST('page_y') ? GETPOST('page_y') : '').'</div>'."\n";
10343
10344 $parameters = array();
10345 $reshook = $hookmanager->executeHooks('printCommonFooter', $parameters); // Note that $action and $object may have been modified by some hooks
10346 if (empty($reshook)) {
10347 if (getDolGlobalString('MAIN_HTML_FOOTER')) {
10348 print getDolGlobalString('MAIN_HTML_FOOTER') . "\n";
10349 }
10350
10351 print "\n";
10352 if (!empty($conf->use_javascript_ajax)) {
10353 print "\n<!-- A script section to add menuhider handler on backoffice, manage focus and madatory fields, tuning info, ... -->\n";
10354 print '<script>'."\n";
10355 print 'jQuery(document).ready(function() {'."\n";
10356
10357 if ($zone == 'private' && empty($conf->dol_use_jmobile)) {
10358 print "\n";
10359 print '/* JS CODE TO ENABLE to manage handler to switch left menu page (menuhider) */'."\n";
10360 print 'jQuery("li.menuhider").click(function(event) {';
10361 print ' if (!$( "body" ).hasClass( "sidebar-collapse" )){ event.preventDefault(); }'."\n";
10362 print ' console.log("We click on .menuhider");'."\n";
10363 print ' $("body").toggleClass("sidebar-collapse")'."\n";
10364 print '});'."\n";
10365 }
10366
10367 // Management of focus and mandatory for fields
10368 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"])))) {
10369 print '/* JS CODE TO ENABLE to manage focus and mandatory form fields */'."\n";
10370 $relativepathstring = $_SERVER["PHP_SELF"];
10371 // Clean $relativepathstring
10372 if (constant('DOL_URL_ROOT')) {
10373 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
10374 }
10375 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
10376 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
10377 //$tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
10378 if (!empty($user->default_values[$relativepathstring]['focus'])) {
10379 foreach ($user->default_values[$relativepathstring]['focus'] as $defkey => $defval) {
10380 $qualified = 0;
10381 if ($defkey != '_noquery_') {
10382 $tmpqueryarraytohave = explode('&', $defkey);
10383 $foundintru = 0;
10384 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
10385 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
10386 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
10387 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
10388 $foundintru = 1;
10389 }
10390 }
10391 if (!$foundintru) {
10392 $qualified = 1;
10393 }
10394 //var_dump($defkey.'-'.$qualified);
10395 } else {
10396 $qualified = 1;
10397 }
10398
10399 if ($qualified) {
10400 foreach ($defval as $paramkey => $paramval) {
10401 // Set focus on field
10402 print 'jQuery("input[name=\''.$paramkey.'\']").focus();'."\n";
10403 print 'jQuery("textarea[name=\''.$paramkey.'\']").focus();'."\n";
10404 print 'jQuery("select[name=\''.$paramkey.'\']").focus();'."\n"; // Not really usefull, but we keep it in case of.
10405 }
10406 }
10407 }
10408 }
10409 if (!empty($user->default_values[$relativepathstring]['mandatory'])) {
10410 foreach ($user->default_values[$relativepathstring]['mandatory'] as $defkey => $defval) {
10411 $qualified = 0;
10412 if ($defkey != '_noquery_') {
10413 $tmpqueryarraytohave = explode('&', $defkey);
10414 $foundintru = 0;
10415 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
10416 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
10417 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
10418 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
10419 $foundintru = 1;
10420 }
10421 }
10422 if (!$foundintru) {
10423 $qualified = 1;
10424 }
10425 //var_dump($defkey.'-'.$qualified);
10426 } else {
10427 $qualified = 1;
10428 }
10429
10430 if ($qualified) {
10431 foreach ($defval as $paramkey => $paramval) {
10432 // Add property 'required' on input
10433 print 'jQuery("input[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10434 print 'jQuery("textarea[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10435 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";
10436 print 'jQuery("select[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10437 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'-1\']").prop(\'value\', \'\');'."\n";
10438 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'0\']").prop(\'value\', \'\');'."\n";
10439
10440 // Add 'field required' class on closest td for all input elements : input, textarea and select
10441 print 'jQuery(":input[name=\'' . $paramkey . '\']").closest("tr").find("td:first").addClass("fieldrequired");' . "\n";
10442 }
10443 // If we submit the cancel button we remove the required attributes
10444 print 'jQuery("input[name=\'cancel\']").click(function() {
10445 console.log("We click on cancel button so removed all required attribute");
10446 jQuery("input, textarea, select").each(function(){this.removeAttribute(\'required\');});
10447 });'."\n";
10448 }
10449 }
10450 }
10451 }
10452
10453 print '});'."\n";
10454
10455 // End of tuning
10456 if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO']) || getDolGlobalString('MAIN_SHOW_TUNING_INFO')) {
10457 print "\n";
10458 print "/* JS CODE TO ENABLE to add memory info */\n";
10459 print 'window.console && console.log("';
10460 if (getDolGlobalString('MEMCACHED_SERVER')) {
10461 print 'MEMCACHED_SERVER=' . getDolGlobalString('MEMCACHED_SERVER').' - ';
10462 }
10463 print 'MAIN_OPTIMIZE_SPEED='.(isset($conf->global->MAIN_OPTIMIZE_SPEED) ? $conf->global->MAIN_OPTIMIZE_SPEED : 'off');
10464 if (!empty($micro_start_time)) { // Works only if MAIN_SHOW_TUNING_INFO is defined at $_SERVER level. Not in global variable.
10465 $micro_end_time = microtime(true);
10466 print ' - Build time: '.ceil(1000 * ($micro_end_time - $micro_start_time)).' ms';
10467 }
10468
10469 if (function_exists("memory_get_usage")) {
10470 print ' - Mem: '.memory_get_usage(); // Do not use true here, it seems it takes the peak amount
10471 }
10472 if (function_exists("memory_get_peak_usage")) {
10473 print ' - Real mem peak: '.memory_get_peak_usage(true);
10474 }
10475 if (function_exists("zend_loader_file_encoded")) {
10476 print ' - Zend encoded file: '.(zend_loader_file_encoded() ? 'yes' : 'no');
10477 }
10478 print '");'."\n";
10479 }
10480
10481 print "\n".'</script>'."\n";
10482
10483 // Google Analytics
10484 // TODO Add a hook here
10485 if (isModEnabled('google') && getDolGlobalString('MAIN_GOOGLE_AN_ID')) {
10486 $tmptagarray = explode(',', getDolGlobalString('MAIN_GOOGLE_AN_ID'));
10487 foreach ($tmptagarray as $tmptag) {
10488 print "\n";
10489 print "<!-- JS CODE TO ENABLE for google analtics tag -->\n";
10490 print '
10491 <!-- Global site tag (gtag.js) - Google Analytics -->
10492 <script nonce="'.getNonce().'" async src="https://www.googletagmanager.com/gtag/js?id='.trim($tmptag).'"></script>
10493 <script>
10494 window.dataLayer = window.dataLayer || [];
10495 function gtag(){dataLayer.push(arguments);}
10496 gtag(\'js\', new Date());
10497
10498 gtag(\'config\', \''.trim($tmptag).'\');
10499 </script>';
10500 print "\n";
10501 }
10502 }
10503 }
10504
10505 // Add Xdebug coverage of code
10506 if (defined('XDEBUGCOVERAGE')) {
10507 print_r(xdebug_get_code_coverage());
10508 }
10509
10510 // Add DebugBar data
10511 if ($user->hasRight('debugbar', 'read') && is_object($debugbar)) {
10512 $debugbar['time']->stopMeasure('pageaftermaster');
10513 print '<!-- Output debugbar data -->'."\n";
10514 $renderer = $debugbar->getRenderer();
10515 print $debugbar->getRenderer()->render();
10516 } elseif (count($conf->logbuffer)) { // If there is some logs in buffer to show
10517 print "\n";
10518 print "<!-- Start of log output\n";
10519 //print '<div class="hidden">'."\n";
10520 foreach ($conf->logbuffer as $logline) {
10521 print $logline."<br>\n";
10522 }
10523 //print '</div>'."\n";
10524 print "End of log output -->\n";
10525 }
10526 }
10527}
10528
10538function dolExplodeIntoArray($string, $delimiter = ';', $kv = '=')
10539{
10540 if (is_null($string)) {
10541 return array();
10542 }
10543
10544 if (preg_match('/^\[.*\]$/sm', $delimiter) || preg_match('/^\‍(.*\‍)$/sm', $delimiter)) {
10545 // This is a regex string
10546 $newdelimiter = $delimiter;
10547 } else {
10548 // This is a simple string
10549 $newdelimiter = preg_quote($delimiter, '/');
10550 }
10551
10552 if ($a = preg_split('/'.$newdelimiter.'/', $string)) {
10553 $ka = array();
10554 foreach ($a as $s) { // each part
10555 if ($s) {
10556 if ($pos = strpos($s, $kv)) { // key/value delimiter
10557 $ka[trim(substr($s, 0, $pos))] = trim(substr($s, $pos + strlen($kv)));
10558 } else { // key delimiter not found
10559 $ka[] = trim($s);
10560 }
10561 }
10562 }
10563 return $ka;
10564 }
10565
10566 return array();
10567}
10568
10569
10576function dol_set_focus($selector)
10577{
10578 print "\n".'<!-- Set focus onto a specific field -->'."\n";
10579 print '<script nonce="'.getNonce().'">jQuery(document).ready(function() { jQuery("'.dol_escape_js($selector).'").focus(); });</script>'."\n";
10580}
10581
10582
10590function dol_getmypid()
10591{
10592 if (!function_exists('getmypid')) {
10593 return mt_rand(99900000, 99965535);
10594 } else {
10595 return getmypid(); // May be a number on 64 bits (depending on OS)
10596 }
10597}
10598
10599
10617function natural_search($fields, $value, $mode = 0, $nofirstand = 0)
10618{
10619 global $db, $langs;
10620
10621 $value = trim($value);
10622
10623 if ($mode == 0) {
10624 $value = preg_replace('/\*/', '%', $value); // Replace * with %
10625 }
10626 if ($mode == 1) {
10627 $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
10628 }
10629
10630 $value = preg_replace('/\s*\|\s*/', '|', $value);
10631
10632 $crits = explode(' ', $value);
10633 $res = '';
10634 if (!is_array($fields)) {
10635 $fields = array($fields);
10636 }
10637
10638 $i1 = 0; // count the nb of and criteria added (all fields / criterias)
10639 foreach ($crits as $crit) { // Loop on each AND criteria
10640 $crit = trim($crit);
10641 $i2 = 0; // count the nb of valid criteria added for this this first criteria
10642 $newres = '';
10643 foreach ($fields as $field) {
10644 if ($mode == 1) {
10645 $tmpcrits = explode('|', $crit);
10646 $i3 = 0; // count the nb of valid criteria added for this current field
10647 foreach ($tmpcrits as $tmpcrit) {
10648 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10649 continue;
10650 }
10651 $tmpcrit = trim($tmpcrit);
10652
10653 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10654
10655 $operator = '=';
10656 $newcrit = preg_replace('/([!<>=]+)/', '', $tmpcrit);
10657
10658 $reg = array();
10659 preg_match('/([!<>=]+)/', $tmpcrit, $reg);
10660 if (!empty($reg[1])) {
10661 $operator = $reg[1];
10662 }
10663 if ($newcrit != '') {
10664 $numnewcrit = price2num($newcrit);
10665 if (is_numeric($numnewcrit)) {
10666 $newres .= $field.' '.$operator.' '.((float) $numnewcrit); // should be a numeric
10667 } else {
10668 $newres .= '1 = 2'; // force false, we received a corrupted data
10669 }
10670 $i3++; // a criteria was added to string
10671 }
10672 }
10673 $i2++; // a criteria for 1 more field was added to string
10674 } elseif ($mode == 2 || $mode == -2) {
10675 $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer
10676 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -2 ? 'NOT ' : '');
10677 $newres .= $crit ? "IN (".$db->sanitize($db->escape($crit)).")" : "IN (0)";
10678 if ($mode == -2) {
10679 $newres .= ' OR '.$field.' IS NULL';
10680 }
10681 $i2++; // a criteria for 1 more field was added to string
10682 } elseif ($mode == 3 || $mode == -3) {
10683 $tmparray = explode(',', $crit);
10684 if (count($tmparray)) {
10685 $listofcodes = '';
10686 foreach ($tmparray as $val) {
10687 $val = trim($val);
10688 if ($val) {
10689 $listofcodes .= ($listofcodes ? ',' : '');
10690 $listofcodes .= "'".$db->escape($val)."'";
10691 }
10692 }
10693 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -3 ? 'NOT ' : '')."IN (".$db->sanitize($listofcodes, 1).")";
10694 $i2++; // a criteria for 1 more field was added to string
10695 }
10696 if ($mode == -3) {
10697 $newres .= ' OR '.$field.' IS NULL';
10698 }
10699 } elseif ($mode == 4) {
10700 $tmparray = explode(',', $crit);
10701 if (count($tmparray)) {
10702 $listofcodes = '';
10703 foreach ($tmparray as $val) {
10704 $val = trim($val);
10705 if ($val) {
10706 $newres .= ($i2 > 0 ? " OR (" : "(").$field." LIKE '".$db->escape($val).",%'";
10707 $newres .= ' OR '.$field." = '".$db->escape($val)."'";
10708 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val)."'";
10709 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val).",%'";
10710 $newres .= ')';
10711 $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)
10712 }
10713 }
10714 }
10715 } else { // $mode=0
10716 $tmpcrits = explode('|', $crit);
10717 $i3 = 0; // count the nb of valid criteria added for the current couple criteria/field
10718 foreach ($tmpcrits as $tmpcrit) { // loop on each OR criteria
10719 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10720 continue;
10721 }
10722 $tmpcrit = trim($tmpcrit);
10723
10724 if ($tmpcrit == '^$' || strpos($crit, '!') === 0) { // If we search empty, we must combined different OR fields with AND
10725 $newres .= (($i2 > 0 || $i3 > 0) ? ' AND ' : '');
10726 } else {
10727 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10728 }
10729
10730 if (preg_match('/\.(id|rowid)$/', $field)) { // Special case for rowid that is sometimes a ref so used as a search field
10731 $newres .= $field." = ".(is_numeric($tmpcrit) ? ((float) $tmpcrit) : '0');
10732 } else {
10733 $tmpcrit2 = $tmpcrit;
10734 $tmpbefore = '%';
10735 $tmpafter = '%';
10736 $tmps = '';
10737
10738 if (preg_match('/^!/', $tmpcrit)) {
10739 $tmps .= $field." NOT LIKE "; // ! as exclude character
10740 $tmpcrit2 = preg_replace('/^!/', '', $tmpcrit2);
10741 } else {
10742 $tmps .= $field." LIKE ";
10743 }
10744 $tmps .= "'";
10745
10746 if (preg_match('/^[\^\$]/', $tmpcrit)) {
10747 $tmpbefore = '';
10748 $tmpcrit2 = preg_replace('/^[\^\$]/', '', $tmpcrit2);
10749 }
10750 if (preg_match('/[\^\$]$/', $tmpcrit)) {
10751 $tmpafter = '';
10752 $tmpcrit2 = preg_replace('/[\^\$]$/', '', $tmpcrit2);
10753 }
10754
10755 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10756 $tmps = "(".$tmps;
10757 }
10758 $newres .= $tmps;
10759 $newres .= $tmpbefore;
10760 $newres .= $db->escape($tmpcrit2);
10761 $newres .= $tmpafter;
10762 $newres .= "'";
10763 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10764 $newres .= " OR ".$field." IS NULL)";
10765 }
10766 }
10767
10768 $i3++;
10769 }
10770
10771 $i2++; // a criteria for 1 more field was added to string
10772 }
10773 }
10774
10775 if ($newres) {
10776 $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : '');
10777 }
10778 $i1++;
10779 }
10780 $res = ($nofirstand ? "" : " AND ")."(".$res.")";
10781
10782 return $res;
10783}
10784
10791function showDirectDownloadLink($object)
10792{
10793 global $conf, $langs;
10794
10795 $out = '';
10796 $url = $object->getLastMainDocLink($object->element);
10797
10798 $out .= img_picto($langs->trans("PublicDownloadLinkDesc"), 'globe').' <span class="opacitymedium">'.$langs->trans("DirectDownloadLink").'</span><br>';
10799 if ($url) {
10800 $out .= '<div class="urllink"><input type="text" id="directdownloadlink" class="quatrevingtpercent" value="'.$url.'"></div>';
10801 $out .= ajax_autoselect("directdownloadlink", 0);
10802 } else {
10803 $out .= '<div class="urllink">'.$langs->trans("FileNotShared").'</div>';
10804 }
10805
10806 return $out;
10807}
10808
10817function getImageFileNameForSize($file, $extName, $extImgTarget = '')
10818{
10819 $dirName = dirname($file);
10820 if ($dirName == '.') {
10821 $dirName = '';
10822 }
10823
10824 $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.webp)$/i', '', $file); // We remove extension, whatever is its case
10825 $fileName = basename($fileName);
10826
10827 if (empty($extImgTarget)) {
10828 $extImgTarget = (preg_match('/\.jpg$/i', $file) ? '.jpg' : '');
10829 }
10830 if (empty($extImgTarget)) {
10831 $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '');
10832 }
10833 if (empty($extImgTarget)) {
10834 $extImgTarget = (preg_match('/\.gif$/i', $file) ? '.gif' : '');
10835 }
10836 if (empty($extImgTarget)) {
10837 $extImgTarget = (preg_match('/\.png$/i', $file) ? '.png' : '');
10838 }
10839 if (empty($extImgTarget)) {
10840 $extImgTarget = (preg_match('/\.bmp$/i', $file) ? '.bmp' : '');
10841 }
10842 if (empty($extImgTarget)) {
10843 $extImgTarget = (preg_match('/\.webp$/i', $file) ? '.webp' : '');
10844 }
10845
10846 if (!$extImgTarget) {
10847 return $file;
10848 }
10849
10850 $subdir = '';
10851 if ($extName) {
10852 $subdir = 'thumbs/';
10853 }
10854
10855 return ($dirName ? $dirName.'/' : '').$subdir.$fileName.$extName.$extImgTarget; // New filename for thumb
10856}
10857
10858
10868function getAdvancedPreviewUrl($modulepart, $relativepath, $alldata = 0, $param = '')
10869{
10870 global $conf, $langs;
10871
10872 if (empty($conf->use_javascript_ajax)) {
10873 return '';
10874 }
10875
10876 $isAllowedForPreview = dolIsAllowedForPreview($relativepath);
10877
10878 if ($alldata == 1) {
10879 if ($isAllowedForPreview) {
10880 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));
10881 } else {
10882 return array();
10883 }
10884 }
10885
10886 // old behavior, return a string
10887 if ($isAllowedForPreview) {
10888 $tmpurl = DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : '');
10889
10890 $title = $langs->trans("Preview");
10891 //$title = '%27-alert(document.domain)-%27';
10892 //$tmpurl = 'file='.urlencode("'-alert(document.domain)-'_small.jpg");
10893
10894 // 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.
10895 // and when we click on href with this javascript string, a urlcode is done by browser, converted the %27 of file param
10896 return 'javascript:document_preview(\''.urlencode(dol_escape_js($tmpurl)).'\', \''.urlencode(dol_mimetype($relativepath)).'\', \''.rawurlencode(dol_escape_js($title)).'\')';
10897 } else {
10898 return '';
10899 }
10900}
10901
10902
10911function ajax_autoselect($htmlname, $addlink = '', $textonlink = 'Link')
10912{
10913 global $langs;
10914 $out = '<script nonce="'.getNonce().'">
10915 jQuery(document).ready(function () {
10916 jQuery("'.((strpos($htmlname, '.') === 0 ? '' : '#').$htmlname).'").click(function() { jQuery(this).select(); } );
10917 });
10918 </script>';
10919 if ($addlink) {
10920 if ($textonlink === 'image') {
10921 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.img_picto('', 'globe').'</a>';
10922 } else {
10923 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.$langs->trans("Link").'</a>';
10924 }
10925 }
10926 return $out;
10927}
10928
10936function dolIsAllowedForPreview($file)
10937{
10938 global $conf;
10939
10940 // Check .noexe extension in filename
10941 if (preg_match('/\.noexe$/i', $file)) {
10942 return 0;
10943 }
10944
10945 // Check mime types
10946 $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'webp');
10947 if (getDolGlobalString('MAIN_ALLOW_SVG_FILES_AS_IMAGES')) {
10948 $mime_preview[] = 'svg+xml';
10949 }
10950 //$mime_preview[]='vnd.oasis.opendocument.presentation';
10951 //$mime_preview[]='archive';
10952 $num_mime = array_search(dol_mimetype($file, '', 1), $mime_preview);
10953 if ($num_mime !== false) {
10954 return 1;
10955 }
10956
10957 // By default, not allowed for preview
10958 return 0;
10959}
10960
10961
10971function dol_mimetype($file, $default = 'application/octet-stream', $mode = 0)
10972{
10973 $mime = $default;
10974 $imgmime = 'other.png';
10975 $famime = 'file-o';
10976 $srclang = '';
10977
10978 $tmpfile = preg_replace('/\.noexe$/', '', $file);
10979
10980 // Plain text files
10981 if (preg_match('/\.txt$/i', $tmpfile)) {
10982 $mime = 'text/plain';
10983 $imgmime = 'text.png';
10984 $famime = 'file-alt';
10985 } elseif (preg_match('/\.rtx$/i', $tmpfile)) {
10986 $mime = 'text/richtext';
10987 $imgmime = 'text.png';
10988 $famime = 'file-alt';
10989 } elseif (preg_match('/\.csv$/i', $tmpfile)) {
10990 $mime = 'text/csv';
10991 $imgmime = 'text.png';
10992 $famime = 'file-csv';
10993 } elseif (preg_match('/\.tsv$/i', $tmpfile)) {
10994 $mime = 'text/tab-separated-values';
10995 $imgmime = 'text.png';
10996 $famime = 'file-alt';
10997 } elseif (preg_match('/\.(cf|conf|log)$/i', $tmpfile)) {
10998 $mime = 'text/plain';
10999 $imgmime = 'text.png';
11000 $famime = 'file-alt';
11001 } elseif (preg_match('/\.ini$/i', $tmpfile)) {
11002 $mime = 'text/plain';
11003 $imgmime = 'text.png';
11004 $srclang = 'ini';
11005 $famime = 'file-alt';
11006 } elseif (preg_match('/\.md$/i', $tmpfile)) {
11007 $mime = 'text/plain';
11008 $imgmime = 'text.png';
11009 $srclang = 'md';
11010 $famime = 'file-alt';
11011 } elseif (preg_match('/\.css$/i', $tmpfile)) {
11012 $mime = 'text/css';
11013 $imgmime = 'css.png';
11014 $srclang = 'css';
11015 $famime = 'file-alt';
11016 } elseif (preg_match('/\.lang$/i', $tmpfile)) {
11017 $mime = 'text/plain';
11018 $imgmime = 'text.png';
11019 $srclang = 'lang';
11020 $famime = 'file-alt';
11021 } elseif (preg_match('/\.(crt|cer|key|pub)$/i', $tmpfile)) { // Certificate files
11022 $mime = 'text/plain';
11023 $imgmime = 'text.png';
11024 $famime = 'file-alt';
11025 } elseif (preg_match('/\.(html|htm|shtml)$/i', $tmpfile)) { // XML based (HTML/XML/XAML)
11026 $mime = 'text/html';
11027 $imgmime = 'html.png';
11028 $srclang = 'html';
11029 $famime = 'file-alt';
11030 } elseif (preg_match('/\.(xml|xhtml)$/i', $tmpfile)) {
11031 $mime = 'text/xml';
11032 $imgmime = 'other.png';
11033 $srclang = 'xml';
11034 $famime = 'file-alt';
11035 } elseif (preg_match('/\.xaml$/i', $tmpfile)) {
11036 $mime = 'text/xml';
11037 $imgmime = 'other.png';
11038 $srclang = 'xaml';
11039 $famime = 'file-alt';
11040 } elseif (preg_match('/\.bas$/i', $tmpfile)) { // Languages
11041 $mime = 'text/plain';
11042 $imgmime = 'text.png';
11043 $srclang = 'bas';
11044 $famime = 'file-code';
11045 } elseif (preg_match('/\.(c)$/i', $tmpfile)) {
11046 $mime = 'text/plain';
11047 $imgmime = 'text.png';
11048 $srclang = 'c';
11049 $famime = 'file-code';
11050 } elseif (preg_match('/\.(cpp)$/i', $tmpfile)) {
11051 $mime = 'text/plain';
11052 $imgmime = 'text.png';
11053 $srclang = 'cpp';
11054 $famime = 'file-code';
11055 } elseif (preg_match('/\.cs$/i', $tmpfile)) {
11056 $mime = 'text/plain';
11057 $imgmime = 'text.png';
11058 $srclang = 'cs';
11059 $famime = 'file-code';
11060 } elseif (preg_match('/\.(h)$/i', $tmpfile)) {
11061 $mime = 'text/plain';
11062 $imgmime = 'text.png';
11063 $srclang = 'h';
11064 $famime = 'file-code';
11065 } elseif (preg_match('/\.(java|jsp)$/i', $tmpfile)) {
11066 $mime = 'text/plain';
11067 $imgmime = 'text.png';
11068 $srclang = 'java';
11069 $famime = 'file-code';
11070 } elseif (preg_match('/\.php([0-9]{1})?$/i', $tmpfile)) {
11071 $mime = 'text/plain';
11072 $imgmime = 'php.png';
11073 $srclang = 'php';
11074 $famime = 'file-code';
11075 } elseif (preg_match('/\.phtml$/i', $tmpfile)) {
11076 $mime = 'text/plain';
11077 $imgmime = 'php.png';
11078 $srclang = 'php';
11079 $famime = 'file-code';
11080 } elseif (preg_match('/\.(pl|pm)$/i', $tmpfile)) {
11081 $mime = 'text/plain';
11082 $imgmime = 'pl.png';
11083 $srclang = 'perl';
11084 $famime = 'file-code';
11085 } elseif (preg_match('/\.sql$/i', $tmpfile)) {
11086 $mime = 'text/plain';
11087 $imgmime = 'text.png';
11088 $srclang = 'sql';
11089 $famime = 'file-code';
11090 } elseif (preg_match('/\.js$/i', $tmpfile)) {
11091 $mime = 'text/x-javascript';
11092 $imgmime = 'jscript.png';
11093 $srclang = 'js';
11094 $famime = 'file-code';
11095 } elseif (preg_match('/\.odp$/i', $tmpfile)) { // Open office
11096 $mime = 'application/vnd.oasis.opendocument.presentation';
11097 $imgmime = 'ooffice.png';
11098 $famime = 'file-powerpoint';
11099 } elseif (preg_match('/\.ods$/i', $tmpfile)) {
11100 $mime = 'application/vnd.oasis.opendocument.spreadsheet';
11101 $imgmime = 'ooffice.png';
11102 $famime = 'file-excel';
11103 } elseif (preg_match('/\.odt$/i', $tmpfile)) {
11104 $mime = 'application/vnd.oasis.opendocument.text';
11105 $imgmime = 'ooffice.png';
11106 $famime = 'file-word';
11107 } elseif (preg_match('/\.mdb$/i', $tmpfile)) { // MS Office
11108 $mime = 'application/msaccess';
11109 $imgmime = 'mdb.png';
11110 $famime = 'file';
11111 } elseif (preg_match('/\.doc[xm]?$/i', $tmpfile)) {
11112 $mime = 'application/msword';
11113 $imgmime = 'doc.png';
11114 $famime = 'file-word';
11115 } elseif (preg_match('/\.dot[xm]?$/i', $tmpfile)) {
11116 $mime = 'application/msword';
11117 $imgmime = 'doc.png';
11118 $famime = 'file-word';
11119 } elseif (preg_match('/\.xlt(x)?$/i', $tmpfile)) {
11120 $mime = 'application/vnd.ms-excel';
11121 $imgmime = 'xls.png';
11122 $famime = 'file-excel';
11123 } elseif (preg_match('/\.xla(m)?$/i', $tmpfile)) {
11124 $mime = 'application/vnd.ms-excel';
11125 $imgmime = 'xls.png';
11126 $famime = 'file-excel';
11127 } elseif (preg_match('/\.xls$/i', $tmpfile)) {
11128 $mime = 'application/vnd.ms-excel';
11129 $imgmime = 'xls.png';
11130 $famime = 'file-excel';
11131 } elseif (preg_match('/\.xls[bmx]$/i', $tmpfile)) {
11132 $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
11133 $imgmime = 'xls.png';
11134 $famime = 'file-excel';
11135 } elseif (preg_match('/\.pps[mx]?$/i', $tmpfile)) {
11136 $mime = 'application/vnd.ms-powerpoint';
11137 $imgmime = 'ppt.png';
11138 $famime = 'file-powerpoint';
11139 } elseif (preg_match('/\.ppt[mx]?$/i', $tmpfile)) {
11140 $mime = 'application/x-mspowerpoint';
11141 $imgmime = 'ppt.png';
11142 $famime = 'file-powerpoint';
11143 } elseif (preg_match('/\.pdf$/i', $tmpfile)) { // Other
11144 $mime = 'application/pdf';
11145 $imgmime = 'pdf.png';
11146 $famime = 'file-pdf';
11147 } elseif (preg_match('/\.bat$/i', $tmpfile)) { // Scripts
11148 $mime = 'text/x-bat';
11149 $imgmime = 'script.png';
11150 $srclang = 'dos';
11151 $famime = 'file-code';
11152 } elseif (preg_match('/\.sh$/i', $tmpfile)) {
11153 $mime = 'text/x-sh';
11154 $imgmime = 'script.png';
11155 $srclang = 'bash';
11156 $famime = 'file-code';
11157 } elseif (preg_match('/\.ksh$/i', $tmpfile)) {
11158 $mime = 'text/x-ksh';
11159 $imgmime = 'script.png';
11160 $srclang = 'bash';
11161 $famime = 'file-code';
11162 } elseif (preg_match('/\.bash$/i', $tmpfile)) {
11163 $mime = 'text/x-bash';
11164 $imgmime = 'script.png';
11165 $srclang = 'bash';
11166 $famime = 'file-code';
11167 } elseif (preg_match('/\.ico$/i', $tmpfile)) { // Images
11168 $mime = 'image/x-icon';
11169 $imgmime = 'image.png';
11170 $famime = 'file-image';
11171 } elseif (preg_match('/\.(jpg|jpeg)$/i', $tmpfile)) {
11172 $mime = 'image/jpeg';
11173 $imgmime = 'image.png';
11174 $famime = 'file-image';
11175 } elseif (preg_match('/\.png$/i', $tmpfile)) {
11176 $mime = 'image/png';
11177 $imgmime = 'image.png';
11178 $famime = 'file-image';
11179 } elseif (preg_match('/\.gif$/i', $tmpfile)) {
11180 $mime = 'image/gif';
11181 $imgmime = 'image.png';
11182 $famime = 'file-image';
11183 } elseif (preg_match('/\.bmp$/i', $tmpfile)) {
11184 $mime = 'image/bmp';
11185 $imgmime = 'image.png';
11186 $famime = 'file-image';
11187 } elseif (preg_match('/\.(tif|tiff)$/i', $tmpfile)) {
11188 $mime = 'image/tiff';
11189 $imgmime = 'image.png';
11190 $famime = 'file-image';
11191 } elseif (preg_match('/\.svg$/i', $tmpfile)) {
11192 $mime = 'image/svg+xml';
11193 $imgmime = 'image.png';
11194 $famime = 'file-image';
11195 } elseif (preg_match('/\.webp$/i', $tmpfile)) {
11196 $mime = 'image/webp';
11197 $imgmime = 'image.png';
11198 $famime = 'file-image';
11199 } elseif (preg_match('/\.vcs$/i', $tmpfile)) { // Calendar
11200 $mime = 'text/calendar';
11201 $imgmime = 'other.png';
11202 $famime = 'file-alt';
11203 } elseif (preg_match('/\.ics$/i', $tmpfile)) {
11204 $mime = 'text/calendar';
11205 $imgmime = 'other.png';
11206 $famime = 'file-alt';
11207 } elseif (preg_match('/\.torrent$/i', $tmpfile)) { // Other
11208 $mime = 'application/x-bittorrent';
11209 $imgmime = 'other.png';
11210 $famime = 'file-o';
11211 } elseif (preg_match('/\.(mp3|ogg|au|wav|wma|mid)$/i', $tmpfile)) { // Audio
11212 $mime = 'audio';
11213 $imgmime = 'audio.png';
11214 $famime = 'file-audio';
11215 } elseif (preg_match('/\.mp4$/i', $tmpfile)) { // Video
11216 $mime = 'video/mp4';
11217 $imgmime = 'video.png';
11218 $famime = 'file-video';
11219 } elseif (preg_match('/\.ogv$/i', $tmpfile)) {
11220 $mime = 'video/ogg';
11221 $imgmime = 'video.png';
11222 $famime = 'file-video';
11223 } elseif (preg_match('/\.webm$/i', $tmpfile)) {
11224 $mime = 'video/webm';
11225 $imgmime = 'video.png';
11226 $famime = 'file-video';
11227 } elseif (preg_match('/\.avi$/i', $tmpfile)) {
11228 $mime = 'video/x-msvideo';
11229 $imgmime = 'video.png';
11230 $famime = 'file-video';
11231 } elseif (preg_match('/\.divx$/i', $tmpfile)) {
11232 $mime = 'video/divx';
11233 $imgmime = 'video.png';
11234 $famime = 'file-video';
11235 } elseif (preg_match('/\.xvid$/i', $tmpfile)) {
11236 $mime = 'video/xvid';
11237 $imgmime = 'video.png';
11238 $famime = 'file-video';
11239 } elseif (preg_match('/\.(wmv|mpg|mpeg)$/i', $tmpfile)) {
11240 $mime = 'video';
11241 $imgmime = 'video.png';
11242 $famime = 'file-video';
11243 } elseif (preg_match('/\.(zip|rar|gz|tgz|z|cab|bz2|7z|tar|lzh|zst)$/i', $tmpfile)) { // Archive
11244 // application/xxx where zzz is zip, ...
11245 $mime = 'archive';
11246 $imgmime = 'archive.png';
11247 $famime = 'file-archive';
11248 } elseif (preg_match('/\.(exe|com)$/i', $tmpfile)) { // Exe
11249 $mime = 'application/octet-stream';
11250 $imgmime = 'other.png';
11251 $famime = 'file-o';
11252 } elseif (preg_match('/\.(dll|lib|o|so|a)$/i', $tmpfile)) { // Lib
11253 $mime = 'library';
11254 $imgmime = 'library.png';
11255 $famime = 'file-o';
11256 } elseif (preg_match('/\.err$/i', $tmpfile)) { // phpcs:ignore
11257 $mime = 'error';
11258 $imgmime = 'error.png';
11259 $famime = 'file-alt';
11260 }
11261
11262 // Return mimetype string
11263 switch ((int) $mode) {
11264 case 1:
11265 $tmp = explode('/', $mime);
11266 return (!empty($tmp[1]) ? $tmp[1] : $tmp[0]);
11267 case 2:
11268 return $imgmime;
11269 case 3:
11270 return $srclang;
11271 case 4:
11272 return $famime;
11273 }
11274 return $mime;
11275}
11276
11288function getDictionaryValue($tablename, $field, $id, $checkentity = false, $rowidfield = 'rowid')
11289{
11290 global $conf, $db;
11291
11292 $tablename = preg_replace('/^'.preg_quote(MAIN_DB_PREFIX, '/').'/', '', $tablename); // Clean name of table for backward compatibility.
11293
11294 $dictvalues = (isset($conf->cache['dictvalues_'.$tablename]) ? $conf->cache['dictvalues_'.$tablename] : null);
11295
11296 if (is_null($dictvalues)) {
11297 $dictvalues = array();
11298
11299 $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
11300 if ($checkentity) {
11301 $sql .= ' AND entity IN (0,'.getEntity($tablename).')';
11302 }
11303
11304 $resql = $db->query($sql);
11305 if ($resql) {
11306 while ($obj = $db->fetch_object($resql)) {
11307 $dictvalues[$obj->$rowidfield] = $obj; // $obj is stdClass
11308 }
11309 } else {
11310 dol_print_error($db);
11311 }
11312
11313 $conf->cache['dictvalues_'.$tablename] = $dictvalues;
11314 }
11315
11316 if (!empty($dictvalues[$id])) {
11317 // Found
11318 $tmp = $dictvalues[$id];
11319 return (property_exists($tmp, $field) ? $tmp->$field : '');
11320 } else {
11321 // Not found
11322 return '';
11323 }
11324}
11325
11332function colorIsLight($stringcolor)
11333{
11334 $stringcolor = str_replace('#', '', $stringcolor);
11335 $res = -1;
11336 if (!empty($stringcolor)) {
11337 $res = 0;
11338 $tmp = explode(',', $stringcolor);
11339 if (count($tmp) > 1) { // This is a comma RGB ('255','255','255')
11340 $r = $tmp[0];
11341 $g = $tmp[1];
11342 $b = $tmp[2];
11343 } else {
11344 $hexr = $stringcolor[0].$stringcolor[1];
11345 $hexg = $stringcolor[2].$stringcolor[3];
11346 $hexb = $stringcolor[4].$stringcolor[5];
11347 $r = hexdec($hexr);
11348 $g = hexdec($hexg);
11349 $b = hexdec($hexb);
11350 }
11351 $bright = (max($r, $g, $b) + min($r, $g, $b)) / 510.0; // HSL algorithm
11352 if ($bright > 0.6) {
11353 $res = 1;
11354 }
11355 }
11356 return $res;
11357}
11358
11367function isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
11368{
11369 global $conf;
11370
11371 //print 'type_user='.$type_user.' module='.$menuentry['module'].' enabled='.$menuentry['enabled'].' perms='.$menuentry['perms'];
11372 //print 'ok='.in_array($menuentry['module'], $listofmodulesforexternal);
11373 if (empty($menuentry['enabled'])) {
11374 return 0; // Entry disabled by condition
11375 }
11376 if ($type_user && $menuentry['module']) {
11377 $tmploops = explode('|', $menuentry['module']);
11378 $found = 0;
11379 foreach ($tmploops as $tmploop) {
11380 if (in_array($tmploop, $listofmodulesforexternal)) {
11381 $found++;
11382 break;
11383 }
11384 }
11385 if (!$found) {
11386 return 0; // Entry is for menus all excluded to external users
11387 }
11388 }
11389 if (!$menuentry['perms'] && $type_user) {
11390 return 0; // No permissions and user is external
11391 }
11392 if (!$menuentry['perms'] && getDolGlobalString('MAIN_MENU_HIDE_UNAUTHORIZED')) {
11393 return 0; // No permissions and option to hide when not allowed, even for internal user, is on
11394 }
11395 if (!$menuentry['perms']) {
11396 return 2; // No permissions and user is external
11397 }
11398 return 1;
11399}
11400
11408function roundUpToNextMultiple($n, $x = 5)
11409{
11410 return (ceil($n) % $x === 0) ? ceil($n) : round(($n + $x / 2) / $x) * $x;
11411}
11412
11424function dolGetBadge($label, $html = '', $type = 'primary', $mode = '', $url = '', $params = array())
11425{
11426 $attr = array(
11427 'class'=>'badge '.(!empty($mode) ? ' badge-'.$mode : '').(!empty($type) ? ' badge-'.$type : '').(empty($params['css']) ? '' : ' '.$params['css'])
11428 );
11429
11430 if (empty($html)) {
11431 $html = $label;
11432 }
11433
11434 if (!empty($url)) {
11435 $attr['href'] = $url;
11436 }
11437
11438 if ($mode === 'dot') {
11439 $attr['class'] .= ' classfortooltip';
11440 $attr['title'] = $html;
11441 $attr['aria-label'] = $label;
11442 $html = '';
11443 }
11444
11445 // Override attr
11446 if (!empty($params['attr']) && is_array($params['attr'])) {
11447 foreach ($params['attr'] as $key => $value) {
11448 if ($key == 'class') {
11449 $attr['class'] .= ' '.$value;
11450 } elseif ($key == 'classOverride') {
11451 $attr['class'] = $value;
11452 } else {
11453 $attr[$key] = $value;
11454 }
11455 }
11456 }
11457
11458 // TODO: add hook
11459
11460 // escape all attribute
11461 $attr = array_map('dol_escape_htmltag', $attr);
11462
11463 $TCompiledAttr = array();
11464 foreach ($attr as $key => $value) {
11465 $TCompiledAttr[] = $key.'="'.$value.'"';
11466 }
11467
11468 $compiledAttributes = !empty($TCompiledAttr) ? implode(' ', $TCompiledAttr) : '';
11469
11470 $tag = !empty($url) ? 'a' : 'span';
11471
11472 return '<'.$tag.' '.$compiledAttributes.'>'.$html.'</'.$tag.'>';
11473}
11474
11475
11488function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $statusType = 'status0', $displayMode = 0, $url = '', $params = array())
11489{
11490 global $conf;
11491
11492 $return = '';
11493 $dolGetBadgeParams = array();
11494
11495 if (!empty($params['badgeParams'])) {
11496 $dolGetBadgeParams = $params['badgeParams'];
11497 }
11498
11499 // TODO : add a hook
11500 if ($displayMode == 0) {
11501 $return = !empty($html) ? $html : (empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort));
11502 } elseif ($displayMode == 1) {
11503 $return = !empty($html) ? $html : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11504 } elseif (getDolGlobalString('MAIN_STATUS_USES_IMAGES')) {
11505 // Use status with images (for backward compatibility)
11506 $return = '';
11507 $htmlLabel = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : $statusLabel).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
11508 $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>' : '');
11509
11510 // For small screen, we always use the short label instead of long label.
11511 if (!empty($conf->dol_optimize_smallscreen)) {
11512 if ($displayMode == 0) {
11513 $displayMode = 1;
11514 } elseif ($displayMode == 4) {
11515 $displayMode = 2;
11516 } elseif ($displayMode == 6) {
11517 $displayMode = 5;
11518 }
11519 }
11520
11521 // For backward compatibility. Image's filename are still in French, so we use this array to convert
11522 $statusImg = array(
11523 'status0' => 'statut0',
11524 'status1' => 'statut1',
11525 'status2' => 'statut2',
11526 'status3' => 'statut3',
11527 'status4' => 'statut4',
11528 'status5' => 'statut5',
11529 'status6' => 'statut6',
11530 'status7' => 'statut7',
11531 'status8' => 'statut8',
11532 'status9' => 'statut9'
11533 );
11534
11535 if (!empty($statusImg[$statusType])) {
11536 $htmlImg = img_picto($statusLabel, $statusImg[$statusType]);
11537 } else {
11538 $htmlImg = img_picto($statusLabel, $statusType);
11539 }
11540
11541 if ($displayMode === 2) {
11542 $return = $htmlImg.' '.$htmlLabelShort;
11543 } elseif ($displayMode === 3) {
11544 $return = $htmlImg;
11545 } elseif ($displayMode === 4) {
11546 $return = $htmlImg.' '.$htmlLabel;
11547 } elseif ($displayMode === 5) {
11548 $return = $htmlLabelShort.' '.$htmlImg;
11549 } else { // $displayMode >= 6
11550 $return = $htmlLabel.' '.$htmlImg;
11551 }
11552 } elseif (!getDolGlobalString('MAIN_STATUS_USES_IMAGES') && !empty($displayMode)) {
11553 // Use new badge
11554 $statusLabelShort = (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11555
11556 $dolGetBadgeParams['attr']['class'] = 'badge-status';
11557 $dolGetBadgeParams['attr']['title'] = empty($params['tooltip']) ? $statusLabel : ($params['tooltip'] != 'no' ? $params['tooltip'] : '');
11558
11559 if ($displayMode == 3) {
11560 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), '', $statusType, 'dot', $url, $dolGetBadgeParams);
11561 } elseif ($displayMode === 5) {
11562 $return = dolGetBadge($statusLabelShort, $html, $statusType, '', $url, $dolGetBadgeParams);
11563 } else {
11564 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), $html, $statusType, '', $url, $dolGetBadgeParams);
11565 }
11566 }
11567
11568 return $return;
11569}
11570
11571
11606function dolGetButtonAction($label, $text = '', $actionType = 'default', $url = '', $id = '', $userRight = 1, $params = array())
11607{
11608 global $hookmanager, $action, $object, $langs;
11609
11610 // If $url is an array, we must build a dropdown button
11611 if (is_array($url)) {
11612 // Loop on $url array to remove entries of disabled modules
11613 foreach ($url as $key => $subbutton) {
11614 if (isset($subbutton['enabled']) && empty($subbutton['enabled'])) {
11615 unset($url[$key]);
11616 }
11617 }
11618
11619 $out = '';
11620
11621 if (count($url) > 1) {
11622 $out .= '<div class="dropdown inline-block dropdown-holder">';
11623 $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>';
11624 $out .= '<div class="dropdown-content">';
11625 foreach ($url as $subbutton) {
11626 if (!empty($subbutton['lang'])) {
11627 $langs->load($subbutton['lang']);
11628 }
11629 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
11630 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm'], array('isDropDown' => true));
11631 }
11632 $out .= "</div>";
11633 $out .= "</div>";
11634 } else {
11635 foreach ($url as $subbutton) { // Should loop on 1 record only
11636 if (!empty($subbutton['lang'])) {
11637 $langs->load($subbutton['lang']);
11638 }
11639 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
11640 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm']);
11641 }
11642 }
11643
11644 return $out;
11645 }
11646
11647 // Here, $url is a simple link
11648
11649 if (!empty($params['isDropdown'])) {
11650 $class = "dropdown-item";
11651 } else {
11652 $class = 'butAction';
11653 if ($actionType == 'danger' || $actionType == 'delete') {
11654 $class = 'butActionDelete';
11655 if (!empty($url) && strpos($url, 'token=') === false) {
11656 $url .= '&token='.newToken();
11657 }
11658 }
11659 }
11660 $attr = array(
11661 'class' => $class,
11662 'href' => empty($url) ? '' : $url,
11663 'title' => $label
11664 );
11665
11666 if (empty($text)) {
11667 $text = $label;
11668 $attr['title'] = ''; // if html not set, leave label on title is redundant
11669 } else {
11670 $attr['title'] = $label;
11671 $attr['aria-label'] = $label;
11672 }
11673
11674 if (empty($userRight)) {
11675 $attr['class'] = 'butActionRefused';
11676 $attr['href'] = '';
11677 $attr['title'] = (($label && $text && $label != $text) ? $label : $langs->trans('NotEnoughPermissions'));
11678 }
11679
11680 if (!empty($id)) {
11681 $attr['id'] = $id;
11682 }
11683
11684 // Override attr
11685 if (!empty($params['attr']) && is_array($params['attr'])) {
11686 foreach ($params['attr'] as $key => $value) {
11687 if ($key == 'class') {
11688 $attr['class'] .= ' '.$value;
11689 } elseif ($key == 'classOverride') {
11690 $attr['class'] = $value;
11691 } else {
11692 $attr[$key] = $value;
11693 }
11694 }
11695 }
11696
11697 // automatic add tooltip when title is detected
11698 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
11699 $attr['class'].= ' classfortooltip';
11700 }
11701
11702 // Js Confirm button
11703 if ($userRight && !empty($params['confirm'])) {
11704 if (!is_array($params['confirm'])) {
11705 $params['confirm'] = array();
11706 }
11707
11708 if (empty($params['confirm']['url'])) {
11709 $params['confirm']['url'] = $url . (strpos($url, '?') > 0 ? '&' : '?') . 'confirm=yes';
11710 }
11711
11712 // for js desabled compatibility set $url as call to confirm action and $params['confirm']['url'] to confirmed action
11713 $attr['data-confirm-url'] = $params['confirm']['url'];
11714 $attr['data-confirm-title'] = !empty($params['confirm']['title']) ? $params['confirm']['title'] : $langs->trans('ConfirmBtnCommonTitle', $label);
11715 $attr['data-confirm-content'] = !empty($params['confirm']['content']) ? $params['confirm']['content'] : $langs->trans('ConfirmBtnCommonContent', $label);
11716 $attr['data-confirm-content'] = preg_replace("/\r|\n/", "", $attr['data-confirm-content']);
11717 $attr['data-confirm-action-btn-label'] = !empty($params['confirm']['action-btn-label']) ? $params['confirm']['action-btn-label'] : $langs->trans('Confirm');
11718 $attr['data-confirm-cancel-btn-label'] = !empty($params['confirm']['cancel-btn-label']) ? $params['confirm']['cancel-btn-label'] : $langs->trans('CloseDialog');
11719 $attr['data-confirm-modal'] = !empty($params['confirm']['modal']) ? $params['confirm']['modal'] : true;
11720
11721 $attr['class'].= ' butActionConfirm';
11722 }
11723
11724 if (isset($attr['href']) && empty($attr['href'])) {
11725 unset($attr['href']);
11726 }
11727
11728 // escape all attribute
11729 $attr = array_map('dol_escape_htmltag', $attr);
11730
11731 $TCompiledAttr = array();
11732 foreach ($attr as $key => $value) {
11733 $TCompiledAttr[] = $key.'= "'.$value.'"';
11734 }
11735
11736 $compiledAttributes = empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr);
11737
11738 $tag = !empty($attr['href']) ? 'a' : 'span';
11739
11740
11741 $parameters = array(
11742 'TCompiledAttr' => $TCompiledAttr, // array
11743 'compiledAttributes' => $compiledAttributes, // string
11744 'attr' => $attr,
11745 'tag' => $tag,
11746 'label' => $label,
11747 'html' => $text,
11748 'actionType' => $actionType,
11749 'url' => $url,
11750 'id' => $id,
11751 'userRight' => $userRight,
11752 'params' => $params
11753 );
11754
11755 $reshook = $hookmanager->executeHooks('dolGetButtonAction', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
11756 if ($reshook < 0) {
11757 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
11758 }
11759
11760 if (empty($reshook)) {
11761 if (dol_textishtml($text)) { // If content already HTML encoded
11762 return '<' . $tag . ' ' . $compiledAttributes . '>' . $text . '</' . $tag . '>';
11763 } else {
11764 return '<' . $tag . ' ' . $compiledAttributes . '>' . dol_escape_htmltag($text) . '</' . $tag . '>';
11765 }
11766 } else {
11767 return $hookmanager->resPrint;
11768 }
11769}
11770
11777function dolGetButtonTitleSeparator($moreClass = "")
11778{
11779 return '<span class="button-title-separator '.$moreClass.'" ></span>';
11780}
11781
11788function getFieldErrorIcon($fieldValidationErrorMsg)
11789{
11790 $out = '';
11791 if (!empty($fieldValidationErrorMsg)) {
11792 $out.= '<span class="field-error-icon classfortooltip" title="'.dol_escape_htmltag($fieldValidationErrorMsg, 1).'" role="alert" >'; // role alert is used for accessibility
11793 $out.= '<span class="fa fa-exclamation-circle" aria-hidden="true" ></span>'; // For accessibility icon is separated and aria-hidden
11794 $out.= '</span>';
11795 }
11796
11797 return $out;
11798}
11799
11812function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $url = '', $id = '', $status = 1, $params = array())
11813{
11814 global $langs, $conf, $user;
11815
11816 // Actually this conf is used in css too for external module compatibility and smooth transition to this function
11817 if (getDolGlobalString('MAIN_BUTTON_HIDE_UNAUTHORIZED') && (!$user->admin) && $status <= 0) {
11818 return '';
11819 }
11820
11821 $class = 'btnTitle';
11822 if (in_array($iconClass, array('fa fa-plus-circle', 'fa fa-plus-circle size15x', 'fa fa-comment-dots', 'fa fa-paper-plane'))) {
11823 $class .= ' btnTitlePlus';
11824 }
11825 $useclassfortooltip = 1;
11826
11827 if (!empty($params['morecss'])) {
11828 $class .= ' '.$params['morecss'];
11829 }
11830
11831 $attr = array(
11832 'class' => $class,
11833 'href' => empty($url) ? '' : $url
11834 );
11835
11836 if (!empty($helpText)) {
11837 $attr['title'] = dol_escape_htmltag($helpText);
11838 } elseif (empty($attr['title']) && $label) {
11839 $attr['title'] = $label;
11840 $useclassfortooltip = 0;
11841 }
11842
11843 if ($status == 2) {
11844 $attr['class'] .= ' btnTitleSelected';
11845 } elseif ($status <= 0) {
11846 $attr['class'] .= ' refused';
11847
11848 $attr['href'] = '';
11849
11850 if ($status == -1) { // disable
11851 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("FeatureDisabled"));
11852 } elseif ($status == 0) { // Not enough permissions
11853 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions"));
11854 }
11855 }
11856
11857 if (!empty($attr['title']) && $useclassfortooltip) {
11858 $attr['class'] .= ' classfortooltip';
11859 }
11860
11861 if (!empty($id)) {
11862 $attr['id'] = $id;
11863 }
11864
11865 // Override attr
11866 if (!empty($params['attr']) && is_array($params['attr'])) {
11867 foreach ($params['attr'] as $key => $value) {
11868 if ($key == 'class') {
11869 $attr['class'] .= ' '.$value;
11870 } elseif ($key == 'classOverride') {
11871 $attr['class'] = $value;
11872 } else {
11873 $attr[$key] = $value;
11874 }
11875 }
11876 }
11877
11878 if (isset($attr['href']) && empty($attr['href'])) {
11879 unset($attr['href']);
11880 }
11881
11882 // TODO : add a hook
11883
11884 // escape all attribute
11885 $attr = array_map('dol_escape_htmltag', $attr);
11886
11887 $TCompiledAttr = array();
11888 foreach ($attr as $key => $value) {
11889 $TCompiledAttr[] = $key.'="'.$value.'"';
11890 }
11891
11892 $compiledAttributes = (empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr));
11893
11894 $tag = (empty($attr['href']) ? 'span' : 'a');
11895
11896 $button = '<'.$tag.' '.$compiledAttributes.'>';
11897 $button .= '<span class="'.$iconClass.' valignmiddle btnTitle-icon"></span>';
11898 if (!empty($params['forcenohideoftext'])) {
11899 $button .= '<span class="valignmiddle text-plus-circle btnTitle-label'.(empty($params['forcenohideoftext']) ? ' hideonsmartphone' : '').'">'.$label.'</span>';
11900 }
11901 $button .= '</'.$tag.'>';
11902
11903 return $button;
11904}
11905
11916function getElementProperties($element_type)
11917{
11918 global $conf, $db, $hookmanager;
11919
11920 $regs = array();
11921
11922 //$element_type='facture';
11923
11924 $classfile = $classname = $classpath = $subdir = $dir_output = '';
11925
11926 // Parse element/subelement
11927 $module = $element_type;
11928 $element = $element_type;
11929 $subelement = $element_type;
11930 $table_element = $element_type;
11931
11932 // If we ask a resource form external module (instead of default path)
11933 if (preg_match('/^([^@]+)@([^@]+)$/i', $element_type, $regs)) { // 'myobject@mymodule'
11934 $element = $subelement = $regs[1];
11935 $module = $regs[2];
11936 }
11937
11938 // If we ask a resource for a string with an element and a subelement
11939 // Example 'project_task'
11940 if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { // 'myobject_mysubobject' with myobject=mymodule
11941 $module = $element = $regs[1];
11942 $subelement = $regs[2];
11943 }
11944
11945 // For compatibility and to work with non standard path
11946 if ($element_type == "action" || $element_type == "actioncomm") {
11947 $classpath = 'comm/action/class';
11948 $subelement = 'Actioncomm';
11949 $module = 'agenda';
11950 $table_element = 'actioncomm';
11951 } elseif ($element_type == 'cronjob') {
11952 $classpath = 'cron/class';
11953 $module = 'cron';
11954 $table_element = 'cron';
11955 } elseif ($element_type == 'adherent_type') {
11956 $classpath = 'adherents/class';
11957 $classfile = 'adherent_type';
11958 $module = 'adherent';
11959 $subelement = 'adherent_type';
11960 $classname = 'AdherentType';
11961 $table_element = 'adherent_type';
11962 } elseif ($element_type == 'bank_account') {
11963 $classpath = 'compta/bank/class';
11964 $module = 'bank'; // We need $conf->bank->dir_output and not $conf->banque->dir_output
11965 $classfile = 'account';
11966 $classname = 'Account';
11967 } elseif ($element_type == 'category') {
11968 $classpath = 'categories/class';
11969 $module = 'categorie';
11970 $subelement = 'categorie';
11971 $table_element = 'categorie';
11972 } elseif ($element_type == 'contact') {
11973 $classpath = 'contact/class';
11974 $classfile = 'contact';
11975 $module = 'societe';
11976 $subelement = 'contact';
11977 $table_element = 'socpeople';
11978 } elseif ($element_type == 'inventory') {
11979 $module = 'product';
11980 $classpath = 'product/inventory/class';
11981 } elseif ($element_type == 'stock' || $element_type == 'entrepot') {
11982 $module = 'stock';
11983 $classpath = 'product/stock/class';
11984 $classfile = 'entrepot';
11985 $classname = 'Entrepot';
11986 $table_element = 'entrepot';
11987 } elseif ($element_type == 'project') {
11988 $classpath = 'projet/class';
11989 $module = 'projet';
11990 $table_element = 'projet';
11991 } elseif ($element_type == 'project_task') {
11992 $classpath = 'projet/class';
11993 $module = 'projet';
11994 $subelement = 'task';
11995 $table_element = 'projet_task';
11996 } elseif ($element_type == 'facture' || $element_type == 'invoice') {
11997 $classpath = 'compta/facture/class';
11998 $module = 'facture';
11999 $subelement = 'facture';
12000 $table_element = 'facture';
12001 } elseif ($element_type == 'commande' || $element_type == 'order') {
12002 $classpath = 'commande/class';
12003 $module = 'commande';
12004 $subelement = 'commande';
12005 $table_element = 'commande';
12006 } elseif ($element_type == 'propal') {
12007 $classpath = 'comm/propal/class';
12008 $table_element = 'propal';
12009 } elseif ($element_type == 'shipping') {
12010 $classpath = 'expedition/class';
12011 $classfile = 'expedition';
12012 $classname = 'Expedition';
12013 $module = 'expedition';
12014 $table_element = 'expedition';
12015 } elseif ($element_type == 'supplier_proposal') {
12016 $classpath = 'supplier_proposal/class';
12017 $module = 'supplier_proposal';
12018 $element = 'supplierproposal';
12019 $classfile = 'supplier_proposal';
12020 $subelement = 'supplierproposal';
12021 } elseif ($element_type == 'shipping') {
12022 $classpath = 'expedition/class';
12023 $subelement = 'expedition';
12024 $module = 'expedition_bon';
12025 } elseif ($element_type == 'delivery') {
12026 $classpath = 'delivery/class';
12027 $subelement = 'delivery';
12028 $module = 'expedition';
12029 } elseif ($element_type == 'contract') {
12030 $classpath = 'contrat/class';
12031 $module = 'contrat';
12032 $subelement = 'contrat';
12033 $table_element = 'contract';
12034 } elseif ($element_type == 'mailing') {
12035 $classpath = 'comm/mailing/class';
12036 $module = 'mailing';
12037 $classfile = 'mailing';
12038 $classname = 'Mailing';
12039 $subelement = '';
12040 } elseif ($element_type == 'member') {
12041 $classpath = 'adherents/class';
12042 $module = 'adherent';
12043 $subelement = 'adherent';
12044 $table_element = 'adherent';
12045 } elseif ($element_type == 'usergroup') {
12046 $classpath = 'user/class';
12047 $module = 'user';
12048 } elseif ($element_type == 'mo') {
12049 $classpath = 'mrp/class';
12050 $classfile = 'mo';
12051 $classname = 'Mo';
12052 $module = 'mrp';
12053 $subelement = '';
12054 $table_element = 'mrp_mo';
12055 } elseif ($element_type == 'cabinetmed_cons') {
12056 $classpath = 'cabinetmed/class';
12057 $module = 'cabinetmed';
12058 $subelement = 'cabinetmedcons';
12059 $table_element = 'cabinetmedcons';
12060 } elseif ($element_type == 'fichinter') {
12061 $classpath = 'fichinter/class';
12062 $module = 'ficheinter';
12063 $subelement = 'fichinter';
12064 $table_element = 'fichinter';
12065 } elseif ($element_type == 'dolresource' || $element_type == 'resource') {
12066 $classpath = 'resource/class';
12067 $module = 'resource';
12068 $subelement = 'dolresource';
12069 $table_element = 'resource';
12070 } elseif ($element_type == 'propaldet') {
12071 $classpath = 'comm/propal/class';
12072 $module = 'propal';
12073 $subelement = 'propaleligne';
12074 } elseif ($element_type == 'opensurvey_sondage') {
12075 $classpath = 'opensurvey/class';
12076 $module = 'opensurvey';
12077 $subelement = 'opensurveysondage';
12078 } elseif ($element_type == 'order_supplier') {
12079 $classpath = 'fourn/class';
12080 $module = 'fournisseur';
12081 $classfile = 'fournisseur.commande';
12082 $element = 'order_supplier';
12083 $subelement = '';
12084 $classname = 'CommandeFournisseur';
12085 $table_element = 'commande_fournisseur';
12086 } elseif ($element_type == 'commande_fournisseurdet') {
12087 $classpath = 'fourn/class';
12088 $module = 'fournisseur';
12089 $classfile = 'fournisseur.commande';
12090 $element = 'commande_fournisseurdet';
12091 $subelement = '';
12092 $classname = 'CommandeFournisseurLigne';
12093 $table_element = 'commande_fournisseurdet';
12094 } elseif ($element_type == 'invoice_supplier') {
12095 $classpath = 'fourn/class';
12096 $module = 'fournisseur';
12097 $classfile = 'fournisseur.facture';
12098 $element = 'invoice_supplier';
12099 $subelement = '';
12100 $classname = 'FactureFournisseur';
12101 $table_element = 'facture_fourn';
12102 } elseif ($element_type == "service") {
12103 $classpath = 'product/class';
12104 $subelement = 'product';
12105 $table_element = 'product';
12106 } elseif ($element_type == 'salary') {
12107 $classpath = 'salaries/class';
12108 $module = 'salaries';
12109 } elseif ($element_type == 'payment_salary') {
12110 $classpath = 'salaries/class';
12111 $classfile = 'paymentsalary';
12112 $classname = 'PaymentSalary';
12113 $module = 'salaries';
12114 } elseif ($element_type == 'productlot') {
12115 $module = 'productbatch';
12116 $classpath = 'product/stock/class';
12117 $classfile = 'productlot';
12118 $classname = 'Productlot';
12119 $element = 'productlot';
12120 $subelement = '';
12121 $table_element = 'product_lot';
12122 } elseif ($element_type == 'websitepage') {
12123 $classpath = 'website/class';
12124 $classfile = 'websitepage';
12125 $classname = 'Websitepage';
12126 $module = 'website';
12127 $subelement = 'websitepage';
12128 $table_element = 'website_page';
12129 } elseif ($element_type == 'fiscalyear') {
12130 $classpath = 'core/class';
12131 $module = 'accounting';
12132 $subelement = 'fiscalyear';
12133 } elseif ($element_type == 'chargesociales') {
12134 $classpath = 'compta/sociales/class';
12135 $module = 'tax';
12136 $table_element = 'chargesociales';
12137 } elseif ($element_type == 'tva') {
12138 $classpath = 'compta/tva/class';
12139 $module = 'tax';
12140 $subdir = '/vat';
12141 $table_element = 'tva';
12142 } elseif ($element_type == 'emailsenderprofile') {
12143 $module = '';
12144 $classpath = 'core/class';
12145 $classfile = 'emailsenderprofile';
12146 $classname = 'EmailSenderProfile';
12147 $table_element = 'c_email_senderprofile';
12148 $subelement = '';
12149 } elseif ($element_type == 'ccountry') {
12150 $module = '';
12151 $classpath = 'core/class';
12152 $classfile = 'ccountry';
12153 $classname = 'Ccountry';
12154 $table_element = 'c_country';
12155 $subelement = '';
12156 }
12157
12158 if (empty($classfile)) {
12159 $classfile = strtolower($subelement);
12160 }
12161 if (empty($classname)) {
12162 $classname = ucfirst($subelement);
12163 }
12164 if (empty($classpath)) {
12165 $classpath = $module.'/class';
12166 }
12167
12168 //print 'getElementProperties subdir='.$subdir;
12169
12170 // Set dir_output
12171 if ($module && isset($conf->$module)) { // The generic case
12172 if (!empty($conf->$module->multidir_output[$conf->entity])) {
12173 $dir_output = $conf->$module->multidir_output[$conf->entity];
12174 } elseif (!empty($conf->$module->output[$conf->entity])) {
12175 $dir_output = $conf->$module->output[$conf->entity];
12176 } elseif (!empty($conf->$module->dir_output)) {
12177 $dir_output = $conf->$module->dir_output;
12178 }
12179 }
12180
12181 // Overwrite value for special cases
12182 if ($element == 'order_supplier') {
12183 $dir_output = $conf->fournisseur->commande->dir_output;
12184 } elseif ($element == 'invoice_supplier') {
12185 $dir_output = $conf->fournisseur->facture->dir_output;
12186 }
12187 $dir_output .= $subdir;
12188
12189 $elementProperties = array(
12190 'module' => $module,
12191 'element' => $element,
12192 'table_element' => $table_element,
12193 'subelement' => $subelement,
12194 'classpath' => $classpath,
12195 'classfile' => $classfile,
12196 'classname' => $classname,
12197 'dir_output' => $dir_output
12198 );
12199
12200
12201 // Add hook
12202 if (!is_object($hookmanager)) {
12203 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
12204 $hookmanager = new HookManager($db);
12205 }
12206 $hookmanager->initHooks(array('elementproperties'));
12207
12208
12209 // Hook params
12210 $parameters = array(
12211 'elementType' => $element_type,
12212 'elementProperties' => $elementProperties
12213 );
12214
12215 $reshook = $hookmanager->executeHooks('getElementProperties', $parameters);
12216
12217 if ($reshook) {
12218 $elementProperties = $hookmanager->resArray;
12219 } elseif (!empty($hookmanager->resArray) && is_array($hookmanager->resArray)) { // resArray is always an array but for sécurity against misconfigured external modules
12220 $elementProperties = array_replace($elementProperties, $hookmanager->resArray);
12221 }
12222
12223 // context of elementproperties doesn't need to exist out of this function so delete it to avoid elementproperties context is equal to all
12224 if (($key = array_search('elementproperties', $hookmanager->contextarray)) !== false) {
12225 unset($hookmanager->contextarray[$key]);
12226 }
12227
12228 return $elementProperties;
12229}
12230
12241function fetchObjectByElement($element_id, $element_type, $element_ref = '')
12242{
12243 global $db;
12244
12245 $ret = 0;
12246
12247 $element_prop = getElementProperties($element_type);
12248
12249 if ($element_prop['module'] == 'product' || $element_prop['module'] == 'service') {
12250 // For example, for an extrafield 'product' (shared for both product and service) that is a link to an object,
12251 // this is called with $element_type = 'product' when we need element properties of a service, we must return a product. If we create the
12252 // extrafield for a service, it is not supported and not found when editing the product/service card. So we must keep 'product' for extrafields
12253 // of service and we will return properties of a product.
12254 $ismodenabled = (isModEnabled('product') || isModEnabled('service'));
12255 } else {
12256 $ismodenabled = isModEnabled($element_prop['module']);
12257 }
12258 //var_dump('element_type='.$element_type);
12259 //var_dump($element_prop);
12260 //var_dump($element_prop['module'].' '.$ismodenabled);
12261 if (is_array($element_prop) && (empty($element_prop['module']) || $ismodenabled)) {
12262 dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php');
12263
12264 if (class_exists($element_prop['classname'])) {
12265 $classname = $element_prop['classname'];
12266 $objecttmp = new $classname($db);
12267
12268 if ($element_id > 0 || !empty($element_ref)) {
12269 $ret = $objecttmp->fetch($element_id, $element_ref);
12270 if ($ret >= 0) {
12271 if (empty($objecttmp->module)) {
12272 $objecttmp->module = $element_prop['module'];
12273 }
12274 return $objecttmp;
12275 }
12276 } else {
12277 return $objecttmp; // returned an object without fetch
12278 }
12279 } else {
12280 return -1;
12281 }
12282 }
12283
12284 return $ret;
12285}
12286
12294{
12295 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)) {
12296 return true;
12297 }
12298
12299 return false;
12300}
12301
12309function newToken()
12310{
12311 return empty($_SESSION['newtoken']) ? '' : $_SESSION['newtoken'];
12312}
12313
12322{
12323 return isset($_SESSION['token']) ? $_SESSION['token'] : '';
12324}
12325
12331function getNonce()
12332{
12333 global $conf;
12334
12335 if (empty($conf->cache['nonce'])) {
12336 $conf->cache['nonce'] = dolGetRandomBytes(8);
12337 }
12338
12339 return $conf->cache['nonce'];
12340}
12341
12342
12355function startSimpleTable($header, $link = "", $arguments = "", $emptyRows = 0, $number = -1)
12356{
12357 global $langs;
12358
12359 print '<div class="div-table-responsive-no-min">';
12360 print '<table class="noborder centpercent">';
12361 print '<tr class="liste_titre">';
12362
12363 print $emptyRows < 1 ? '<th>' : '<th colspan="'.($emptyRows + 1).'">';
12364
12365 print $langs->trans($header);
12366
12367 // extra space between the first header and the number
12368 if ($number > -1) {
12369 print ' ';
12370 }
12371
12372 if (!empty($link)) {
12373 if (!empty($arguments)) {
12374 print '<a href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
12375 } else {
12376 print '<a href="'.DOL_URL_ROOT.'/'.$link.'">';
12377 }
12378 }
12379
12380 if ($number > -1) {
12381 print '<span class="badge">'.$number.'</span>';
12382 }
12383
12384 if (!empty($link)) {
12385 print '</a>';
12386 }
12387
12388 print '</th>';
12389
12390 if ($number < 0 && !empty($link)) {
12391 print '<th class="right">';
12392
12393 if (!empty($arguments)) {
12394 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
12395 } else {
12396 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'">';
12397 }
12398
12399 print $langs->trans("FullList");
12400 print '</a>';
12401 print '</th>';
12402 }
12403
12404 print '</tr>';
12405}
12406
12415function finishSimpleTable($addLineBreak = false)
12416{
12417 print '</table>';
12418 print '</div>';
12419
12420 if ($addLineBreak) {
12421 print '<br>';
12422 }
12423}
12424
12436function addSummaryTableLine($tableColumnCount, $num, $nbofloop = 0, $total = 0, $noneWord = "None", $extraRightColumn = false)
12437{
12438 global $langs;
12439
12440 if ($num === 0) {
12441 print '<tr class="oddeven">';
12442 print '<td colspan="'.$tableColumnCount.'"><span class="opacitymedium">'.$langs->trans($noneWord).'</span></td>';
12443 print '</tr>';
12444 return;
12445 }
12446
12447 if ($nbofloop === 0) {
12448 // don't show a summary line
12449 return;
12450 }
12451
12452 if ($num === 0) {
12453 $colspan = $tableColumnCount;
12454 } elseif ($num > $nbofloop) {
12455 $colspan = $tableColumnCount;
12456 } else {
12457 $colspan = $tableColumnCount - 1;
12458 }
12459
12460 if ($extraRightColumn) {
12461 $colspan--;
12462 }
12463
12464 print '<tr class="liste_total">';
12465
12466 if ($nbofloop > 0 && $num > $nbofloop) {
12467 print '<td colspan="'.$colspan.'" class="right">'.$langs->trans("XMoreLines", ($num - $nbofloop)).'</td>';
12468 } else {
12469 print '<td colspan="'.$colspan.'" class="right"> '.$langs->trans("Total").'</td>';
12470 print '<td class="right centpercent">'.price($total).'</td>';
12471 }
12472
12473 if ($extraRightColumn) {
12474 print '<td></td>';
12475 }
12476
12477 print '</tr>';
12478}
12479
12488function readfileLowMemory($fullpath_original_file_osencoded, $method = -1)
12489{
12490 if ($method == -1) {
12491 $method = 0;
12492 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_FREAD')) {
12493 $method = 1;
12494 }
12495 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_STREAM_COPY')) {
12496 $method = 2;
12497 }
12498 }
12499
12500 // Be sure we don't have output buffering enabled to have readfile working correctly
12501 while (ob_get_level()) {
12502 ob_end_flush();
12503 }
12504
12505 // Solution 0
12506 if ($method == 0) {
12507 readfile($fullpath_original_file_osencoded);
12508 } elseif ($method == 1) {
12509 // Solution 1
12510 $handle = fopen($fullpath_original_file_osencoded, "rb");
12511 while (!feof($handle)) {
12512 print fread($handle, 8192);
12513 }
12514 fclose($handle);
12515 } elseif ($method == 2) {
12516 // Solution 2
12517 $handle1 = fopen($fullpath_original_file_osencoded, "rb");
12518 $handle2 = fopen("php://output", "wb");
12519 stream_copy_to_stream($handle1, $handle2);
12520 fclose($handle1);
12521 fclose($handle2);
12522 }
12523}
12524
12534function showValueWithClipboardCPButton($valuetocopy, $showonlyonhover = 1, $texttoshow = '')
12535{
12536 /*
12537 global $conf;
12538
12539 if (!empty($conf->dol_no_mouse_hover)) {
12540 $showonlyonhover = 0;
12541 }*/
12542
12543 $tag = 'span'; // Using div (like any style of type 'block') does not work when using the js copy code.
12544 if ($texttoshow === 'none') {
12545 $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>';
12546 } elseif ($texttoshow) {
12547 $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>';
12548 } else {
12549 $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>';
12550 }
12551
12552 return $result;
12553}
12554
12555
12562function jsonOrUnserialize($stringtodecode)
12563{
12564 $result = json_decode($stringtodecode);
12565 if ($result === null) {
12566 $result = unserialize($stringtodecode);
12567 }
12568
12569 return $result;
12570}
12571
12572
12586function forgeSQLFromUniversalSearchCriteria($filter, &$errorstr = '', $noand = 0, $nopar = 0, $noerror = 0)
12587{
12588 if (empty($filter)) {
12589 return ''; // to avoid the return "AND (())"
12590 }
12591
12592 if (!preg_match('/^\‍(.*\‍)$/', $filter)) { // If $filter does not start and end with ()
12593 $filter = '(' . $filter . ')';
12594 }
12595
12596 $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'
12597
12598 if (!dolCheckFilters($filter, $errorstr)) {
12599 if ($noerror) {
12600 return '1 = 2';
12601 } else {
12602 return 'Filter syntax error - '.$errorstr; // Bad balance of parenthesis, we return an error message or force a SQL not found
12603 }
12604 }
12605
12606 // Test the filter syntax
12607 $t = preg_replace_callback('/'.$regexstring.'/i', 'dolForgeDummyCriteriaCallback', $filter);
12608 $t = str_replace(array('and','or','AND','OR',' '), '', $t); // Remove the only strings allowed between each () criteria
12609 // If the string result contains something else than '()', the syntax was wrong
12610 if (preg_match('/[^\‍(\‍)]/', $t)) {
12611 $errorstr = 'Bad syntax of the search string';
12612 if ($noerror) {
12613 return '1 = 2';
12614 } else {
12615 return 'Filter syntax error - '.$errorstr; // Bad syntax of the search string, we return an error message or force a SQL not found
12616 }
12617 }
12618
12619 return ($noand ? "" : " AND ").($nopar ? "" : '(').preg_replace_callback('/'.$regexstring.'/i', 'dolForgeCriteriaCallback', $filter).($nopar ? "" : ')');
12620}
12621
12629function dolCheckFilters($sqlfilters, &$error = '')
12630{
12631 //$regexstring='\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^:\‍(\‍)]+)\‍)';
12632 //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
12633 $tmp = $sqlfilters;
12634 $i = 0;
12635 $nb = strlen($tmp);
12636 $counter = 0;
12637 while ($i < $nb) {
12638 if ($tmp[$i] == '(') {
12639 $counter++;
12640 }
12641 if ($tmp[$i] == ')') {
12642 $counter--;
12643 }
12644 if ($counter < 0) {
12645 $error = "Wrond balance of parenthesis in sqlfilters=".$sqlfilters;
12646 dol_syslog($error, LOG_WARNING);
12647 return false;
12648 }
12649 $i++;
12650 }
12651 return true;
12652}
12653
12662{
12663 //dol_syslog("Convert matches ".$matches[1]);
12664 if (empty($matches[1])) {
12665 return '';
12666 }
12667 $tmp = explode(':', $matches[1]);
12668 if (count($tmp) < 3) {
12669 return '';
12670 }
12671
12672 return '()'; // An empty criteria
12673}
12674
12684{
12685 global $db;
12686
12687 //dol_syslog("Convert matches ".$matches[1]);
12688 if (empty($matches[1])) {
12689 return '';
12690 }
12691 $tmp = explode(':', $matches[1]);
12692 if (count($tmp) < 3) {
12693 return '';
12694 }
12695
12696 $operand = preg_replace('/[^a-z0-9\._]/i', '', trim($tmp[0]));
12697
12698 $operator = strtoupper(preg_replace('/[^a-z<>!=]/i', '', trim($tmp[1])));
12699
12700 $realOperator = [
12701 'NOTLIKE' => 'NOT LIKE',
12702 'ISNOT' => 'IS NOT',
12703 'NOTIN' => 'NOT IN',
12704 '!=' => '<>',
12705 ];
12706
12707 if (array_key_exists($operator, $realOperator)) {
12708 $operator = $realOperator[$operator];
12709 }
12710
12711
12712 $tmpescaped = $tmp[2];
12713 $regbis = array();
12714
12715 if ($operator == 'IN' || $operator == 'NOT IN') { // IN is allowed for list of ID or code only
12716 //if (!preg_match('/^\‍(.*\‍)$/', $tmpescaped)) {
12717 $tmpescaped2 = '(';
12718 // Explode and sanitize each element in list
12719 $tmpelemarray = explode(',', $tmpescaped);
12720 foreach ($tmpelemarray as $tmpkey => $tmpelem) {
12721 $reg = array();
12722 if (preg_match('/^\'(.*)\'$/', $tmpelem, $reg)) {
12723 $tmpelemarray[$tmpkey] = "'".$db->escape($db->sanitize($reg[1], 1, 1, 1))."'";
12724 } else {
12725 $tmpelemarray[$tmpkey] = $db->escape($db->sanitize($tmpelem, 1, 1, 1));
12726 }
12727 }
12728 $tmpescaped2 .= join(',', $tmpelemarray);
12729 $tmpescaped2 .= ')';
12730
12731 $tmpescaped = $tmpescaped2;
12732 } elseif ($operator == 'LIKE' || $operator == 'NOT LIKE') {
12733 if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12734 $tmpescaped = $regbis[1];
12735 }
12736 //$tmpescaped = "'".$db->escape($db->escapeforlike($regbis[1]))."'";
12737 $tmpescaped = "'".$db->escape($tmpescaped)."'"; // We do not escape the _ and % so the like will works
12738 } elseif (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12739 $tmpescaped = "'".$db->escape($regbis[1])."'";
12740 } else {
12741 if (strtoupper($tmpescaped) == 'NULL') {
12742 $tmpescaped = 'NULL';
12743 } elseif (is_int($tmpescaped)) {
12744 $tmpescaped = (int) $tmpescaped;
12745 } else {
12746 $tmpescaped = (float) $tmpescaped;
12747 }
12748 }
12749
12750 return '('.$db->escape($operand).' '.strtoupper($operator).' '.$tmpescaped.')';
12751}
12752
12753
12763function getTimelineIcon($actionstatic, &$histo, $key)
12764{
12765 global $conf, $langs;
12766
12767 $out = '<!-- timeline icon -->'."\n";
12768 $iconClass = 'fa fa-comments';
12769 $img_picto = '';
12770 $colorClass = '';
12771 $pictoTitle = '';
12772
12773 if ($histo[$key]['percent'] == -1) {
12774 $colorClass = 'timeline-icon-not-applicble';
12775 $pictoTitle = $langs->trans('StatusNotApplicable');
12776 } elseif ($histo[$key]['percent'] == 0) {
12777 $colorClass = 'timeline-icon-todo';
12778 $pictoTitle = $langs->trans('StatusActionToDo').' (0%)';
12779 } elseif ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100) {
12780 $colorClass = 'timeline-icon-in-progress';
12781 $pictoTitle = $langs->trans('StatusActionInProcess').' ('.$histo[$key]['percent'].'%)';
12782 } elseif ($histo[$key]['percent'] >= 100) {
12783 $colorClass = 'timeline-icon-done';
12784 $pictoTitle = $langs->trans('StatusActionDone').' (100%)';
12785 }
12786
12787 if ($actionstatic->code == 'AC_TICKET_CREATE') {
12788 $iconClass = 'fa fa-ticket';
12789 } elseif ($actionstatic->code == 'AC_TICKET_MODIFY') {
12790 $iconClass = 'fa fa-pencilxxx';
12791 } elseif (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12792 $iconClass = 'fa fa-comments';
12793 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12794 $iconClass = 'fa fa-mask';
12795 } elseif (getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
12796 if ($actionstatic->type_picto) {
12797 $img_picto = img_picto('', $actionstatic->type_picto);
12798 } else {
12799 if ($actionstatic->type_code == 'AC_RDV') {
12800 $iconClass = 'fa fa-handshake';
12801 } elseif ($actionstatic->type_code == 'AC_TEL') {
12802 $iconClass = 'fa fa-phone';
12803 } elseif ($actionstatic->type_code == 'AC_FAX') {
12804 $iconClass = 'fa fa-fax';
12805 } elseif ($actionstatic->type_code == 'AC_EMAIL') {
12806 $iconClass = 'fa fa-envelope';
12807 } elseif ($actionstatic->type_code == 'AC_INT') {
12808 $iconClass = 'fa fa-shipping-fast';
12809 } elseif ($actionstatic->type_code == 'AC_OTH_AUTO') {
12810 $iconClass = 'fa fa-robot';
12811 } elseif (!preg_match('/_AUTO/', $actionstatic->type_code)) {
12812 $iconClass = 'fa fa-robot';
12813 }
12814 }
12815 }
12816
12817 $out .= '<i class="'.$iconClass.' '.$colorClass.'" title="'.$pictoTitle.'">'.$img_picto.'</i>'."\n";
12818 return $out;
12819}
12820
12827function getActionCommEcmList($object)
12828{
12829 global $conf, $db;
12830
12831 $documents = array();
12832
12833 $sql = 'SELECT ecm.rowid as id, ecm.src_object_type, ecm.src_object_id, ecm.filepath, ecm.filename';
12834 $sql .= ' FROM '.MAIN_DB_PREFIX.'ecm_files ecm';
12835 $sql .= " WHERE ecm.filepath = 'agenda/".((int) $object->id)."'";
12836 //$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
12837 $sql .= ' ORDER BY ecm.position ASC';
12838
12839 $resql = $db->query($sql);
12840 if ($resql) {
12841 if ($db->num_rows($resql)) {
12842 while ($obj = $db->fetch_object($resql)) {
12843 $documents[$obj->id] = $obj;
12844 }
12845 }
12846 }
12847
12848 return $documents;
12849}
12850
12851
12852
12870function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
12871{
12872 global $user, $conf;
12873 global $form;
12874
12875 global $param, $massactionbutton;
12876
12877 dol_include_once('/comm/action/class/actioncomm.class.php');
12878
12879 // Check parameters
12880 if (!is_object($filterobj) && !is_object($objcon)) {
12881 dol_print_error('', 'BadParameter');
12882 }
12883
12884 $histo = array();
12885 $numaction = 0;
12886 $now = dol_now();
12887
12888 $sortfield_list = explode(',', $sortfield);
12889 $sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent');
12890 $sortfield_new_list = array();
12891 foreach ($sortfield_list as $sortfield_value) {
12892 $sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)];
12893 }
12894 $sortfield_new = implode(',', $sortfield_new_list);
12895
12896 if (isModEnabled('agenda')) {
12897 // Search histo on actioncomm
12898 if (is_object($objcon) && $objcon->id > 0) {
12899 $sql = "SELECT DISTINCT a.id, a.label as label,";
12900 } else {
12901 $sql = "SELECT a.id, a.label as label,";
12902 }
12903 $sql .= " a.datep as dp,";
12904 $sql .= " a.note as message,";
12905 $sql .= " a.datep2 as dp2,";
12906 $sql .= " a.percent as percent, 'action' as type,";
12907 $sql .= " a.fk_element, a.elementtype,";
12908 $sql .= " a.fk_contact,";
12909 $sql .= " a.email_from as msg_from,";
12910 $sql .= " c.code as acode, c.libelle as alabel, c.picto as apicto,";
12911 $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";
12912 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12913 $sql .= ", sp.lastname, sp.firstname";
12914 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12915 $sql .= ", m.lastname, m.firstname";
12916 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12917 $sql .= ", o.ref";
12918 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12919 $sql .= ", o.ref";
12920 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12921 $sql .= ", o.ref";
12922 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12923 $sql .= ", o.ref";
12924 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12925 $sql .= ", o.ref";
12926 }
12927 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
12928 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
12929 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
12930
12931 $force_filter_contact = false;
12932 if (is_object($objcon) && $objcon->id > 0) {
12933 $force_filter_contact = true;
12934 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
12935 $sql .= " AND r.element_type = '".$db->escape($objcon->table_element)."' AND r.fk_element = ".((int) $objcon->id);
12936 }
12937
12938 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12939 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
12940 } elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
12941 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er";
12942 $sql .= " ON er.resource_type = 'dolresource'";
12943 $sql .= " AND er.element_id = a.id";
12944 $sql .= " AND er.resource_id = ".((int) $filterobj->id);
12945 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12946 $sql .= ", ".MAIN_DB_PREFIX."adherent as m";
12947 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12948 $sql .= ", ".MAIN_DB_PREFIX."commande_fournisseur as o";
12949 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12950 $sql .= ", ".MAIN_DB_PREFIX."product as o";
12951 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12952 $sql .= ", ".MAIN_DB_PREFIX."ticket as o";
12953 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12954 $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o";
12955 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12956 $sql .= ", ".MAIN_DB_PREFIX."contrat as o";
12957 }
12958
12959 $sql .= " WHERE a.entity IN (".getEntity('agenda').")";
12960 if ($force_filter_contact === false) {
12961 if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) {
12962 $sql .= " AND a.fk_soc = ".((int) $filterobj->id);
12963 } elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) {
12964 $sql .= " AND a.fk_project = ".((int) $filterobj->id);
12965 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12966 $sql .= " AND a.fk_element = m.rowid AND a.elementtype = 'member'";
12967 if ($filterobj->id) {
12968 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12969 }
12970 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12971 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'order_supplier'";
12972 if ($filterobj->id) {
12973 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12974 }
12975 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12976 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
12977 if ($filterobj->id) {
12978 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12979 }
12980 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12981 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'ticket'";
12982 if ($filterobj->id) {
12983 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12984 }
12985 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12986 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'bom'";
12987 if ($filterobj->id) {
12988 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12989 }
12990 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12991 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'contract'";
12992 if ($filterobj->id) {
12993 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12994 }
12995 }
12996 }
12997
12998 // Condition on actioncode
12999 if (!empty($actioncode)) {
13000 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
13001 if ($actioncode == 'AC_NON_AUTO') {
13002 $sql .= " AND c.type != 'systemauto'";
13003 } elseif ($actioncode == 'AC_ALL_AUTO') {
13004 $sql .= " AND c.type = 'systemauto'";
13005 } else {
13006 if ($actioncode == 'AC_OTH') {
13007 $sql .= " AND c.type != 'systemauto'";
13008 } elseif ($actioncode == 'AC_OTH_AUTO') {
13009 $sql .= " AND c.type = 'systemauto'";
13010 }
13011 }
13012 } else {
13013 if ($actioncode == 'AC_NON_AUTO') {
13014 $sql .= " AND c.type != 'systemauto'";
13015 } elseif ($actioncode == 'AC_ALL_AUTO') {
13016 $sql .= " AND c.type = 'systemauto'";
13017 } else {
13018 $sql .= " AND c.code = '".$db->escape($actioncode)."'";
13019 }
13020 }
13021 }
13022 if ($donetodo == 'todo') {
13023 $sql .= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
13024 } elseif ($donetodo == 'done') {
13025 $sql .= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
13026 }
13027 if (is_array($filters) && $filters['search_agenda_label']) {
13028 $sql .= natural_search('a.label', $filters['search_agenda_label']);
13029 }
13030 }
13031
13032 // Add also event from emailings. TODO This should be replaced by an automatic event ? May be it's too much for very large emailing.
13033 if (isModEnabled('mailing') && !empty($objcon->email)
13034 && (empty($actioncode) || $actioncode == 'AC_OTH_AUTO' || $actioncode == 'AC_EMAILING')) {
13035 $langs->load("mails");
13036
13037 $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";
13038 $sql2 .= ", null as fk_element, '' as elementtype, null as contact_id";
13039 $sql2 .= ", 'AC_EMAILING' as acode, '' as alabel, '' as apicto";
13040 $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
13041 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
13042 $sql2 .= ", '' as lastname, '' as firstname";
13043 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
13044 $sql2 .= ", '' as lastname, '' as firstname";
13045 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
13046 $sql2 .= ", '' as ref";
13047 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
13048 $sql2 .= ", '' as ref";
13049 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
13050 $sql2 .= ", '' as ref";
13051 }
13052 $sql2 .= " FROM ".MAIN_DB_PREFIX."mailing as m, ".MAIN_DB_PREFIX."mailing_cibles as mc, ".MAIN_DB_PREFIX."user as u";
13053 $sql2 .= " WHERE mc.email = '".$db->escape($objcon->email)."'"; // Search is done on email.
13054 $sql2 .= " AND mc.statut = 1";
13055 $sql2 .= " AND u.rowid = m.fk_user_valid";
13056 $sql2 .= " AND mc.fk_mailing=m.rowid";
13057 }
13058
13059 if (!empty($sql) && !empty($sql2)) {
13060 $sql = $sql." UNION ".$sql2;
13061 } elseif (empty($sql) && !empty($sql2)) {
13062 $sql = $sql2;
13063 }
13064
13065 // TODO Add limit in nb of results
13066 if ($sql) { // May not be defined if module Agenda is not enabled and mailing module disabled too
13067 $sql .= $db->order($sortfield_new, $sortorder);
13068
13069 dol_syslog("function.lib::show_actions_messaging", LOG_DEBUG);
13070 $resql = $db->query($sql);
13071 if ($resql) {
13072 $i = 0;
13073 $num = $db->num_rows($resql);
13074
13075 while ($i < $num) {
13076 $obj = $db->fetch_object($resql);
13077
13078 if ($obj->type == 'action') {
13079 $contactaction = new ActionComm($db);
13080 $contactaction->id = $obj->id;
13081 $result = $contactaction->fetchResources();
13082 if ($result < 0) {
13083 dol_print_error($db);
13084 setEventMessage("actions.lib::show_actions_messaging Error fetch ressource", 'errors');
13085 }
13086
13087 //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
13088 //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
13089 $tododone = '';
13090 if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && $obj->dp > $now)) {
13091 $tododone = 'todo';
13092 }
13093
13094 $histo[$numaction] = array(
13095 'type'=>$obj->type,
13096 'tododone'=>$tododone,
13097 'id'=>$obj->id,
13098 'datestart'=>$db->jdate($obj->dp),
13099 'dateend'=>$db->jdate($obj->dp2),
13100 'note'=>$obj->label,
13101 'message'=>$obj->message,
13102 'percent'=>$obj->percent,
13103
13104 'userid'=>$obj->user_id,
13105 'login'=>$obj->user_login,
13106 'userfirstname'=>$obj->user_firstname,
13107 'userlastname'=>$obj->user_lastname,
13108 'userphoto'=>$obj->user_photo,
13109 'msg_from'=>$obj->msg_from,
13110
13111 'contact_id'=>$obj->fk_contact,
13112 'socpeopleassigned' => $contactaction->socpeopleassigned,
13113 'lastname' => (empty($obj->lastname) ? '' : $obj->lastname),
13114 'firstname' => (empty($obj->firstname) ? '' : $obj->firstname),
13115 'fk_element'=>$obj->fk_element,
13116 'elementtype'=>$obj->elementtype,
13117 // Type of event
13118 'acode'=>$obj->acode,
13119 'alabel'=>$obj->alabel,
13120 'libelle'=>$obj->alabel, // deprecated
13121 'apicto'=>$obj->apicto
13122 );
13123 } else {
13124 $histo[$numaction] = array(
13125 'type'=>$obj->type,
13126 'tododone'=>'done',
13127 'id'=>$obj->id,
13128 'datestart'=>$db->jdate($obj->dp),
13129 'dateend'=>$db->jdate($obj->dp2),
13130 'note'=>$obj->label,
13131 'message'=>$obj->message,
13132 'percent'=>$obj->percent,
13133 'acode'=>$obj->acode,
13134
13135 'userid'=>$obj->user_id,
13136 'login'=>$obj->user_login,
13137 'userfirstname'=>$obj->user_firstname,
13138 'userlastname'=>$obj->user_lastname,
13139 'userphoto'=>$obj->user_photo
13140 );
13141 }
13142
13143 $numaction++;
13144 $i++;
13145 }
13146 } else {
13147 dol_print_error($db);
13148 }
13149 }
13150
13151 // Set $out to show events
13152 $out = '';
13153
13154 if (!isModEnabled('agenda')) {
13155 $langs->loadLangs(array("admin", "errors"));
13156 $out = info_admin($langs->trans("WarningModuleXDisabledSoYouMayMissEventHere", $langs->transnoentitiesnoconv("Module2400Name")), 0, 0, 'warning');
13157 }
13158
13159 if (isModEnabled('agenda') || (isModEnabled('mailing') && !empty($objcon->email))) {
13160 $delay_warning = $conf->global->MAIN_DELAY_ACTIONS_TODO * 24 * 60 * 60;
13161
13162 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
13163 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
13164 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
13165 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
13166
13167 $formactions = new FormActions($db);
13168
13169 $actionstatic = new ActionComm($db);
13170 $userstatic = new User($db);
13171 $contactstatic = new Contact($db);
13172 $userGetNomUrlCache = array();
13173 $contactGetNomUrlCache = array();
13174
13175 $out .= '<div class="filters-container" >';
13176 $out .= '<form name="listactionsfilter" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
13177 $out .= '<input type="hidden" name="token" value="'.newToken().'">';
13178
13179 if ($objcon && get_class($objcon) == 'Contact' &&
13180 (is_null($filterobj) || get_class($filterobj) == 'Societe')) {
13181 $out .= '<input type="hidden" name="id" value="'.$objcon->id.'" />';
13182 } else {
13183 $out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
13184 }
13185 if ($filterobj && get_class($filterobj) == 'Societe') {
13186 $out .= '<input type="hidden" name="socid" value="'.$filterobj->id.'" />';
13187 }
13188
13189 $out .= "\n";
13190
13191 $out .= '<div class="div-table-responsive-no-min">';
13192 $out .= '<table class="noborder borderbottom centpercent">';
13193
13194 $out .= '<tr class="liste_titre">';
13195
13196 // Action column
13197 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
13198 $out .= '<th class="liste_titre width50 middle">';
13199 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
13200 $out .= $searchpicto;
13201 $out .= '</th>';
13202 }
13203
13204 $out .= getTitleFieldOfList('Date', 0, $_SERVER["PHP_SELF"], 'a.datep', '', $param, '', $sortfield, $sortorder, '')."\n";
13205
13206 $out .= '<th class="liste_titre"><strong class="hideonsmartphone">'.$langs->trans("Search").' : </strong></th>';
13207 if ($donetodo) {
13208 $out .= '<th class="liste_titre"></th>';
13209 }
13210 $out .= '<th class="liste_titre">';
13211 $out .= '<span class="fas fa-square inline-block fawidth30" style=" color: #ddd;" title="'.$langs->trans("ActionType").'"></span>';
13212 //$out .= img_picto($langs->trans("Type"), 'type');
13213 $out .= $formactions->select_type_actions($actioncode, "actioncode", '', !getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : -1, 0, 0, 1, 'minwidth200imp');
13214 $out .= '</th>';
13215 $out .= '<th class="liste_titre maxwidth100onsmartphone">';
13216 $out .= '<input type="text" class="maxwidth100onsmartphone" name="search_agenda_label" value="'.$filters['search_agenda_label'].'" placeholder="'.$langs->trans("Label").'">';
13217 $out .= '</th>';
13218
13219 // Action column
13220 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
13221 $out .= '<th class="liste_titre width50 middle">';
13222 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
13223 $out .= $searchpicto;
13224 $out .= '</th>';
13225 }
13226
13227 $out .= '</tr>';
13228
13229
13230 $out .= '</table>';
13231
13232 $out .= '</form>';
13233 $out .= '</div>';
13234
13235 $out .= "\n";
13236
13237 $out .= '<ul class="timeline">';
13238
13239 if ($donetodo) {
13240 $tmp = '';
13241 if (get_class($filterobj) == 'Societe') {
13242 $tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&socid='.$filterobj->id.'&status=done">';
13243 }
13244 $tmp .= ($donetodo != 'done' ? $langs->trans("ActionsToDoShort") : '');
13245 $tmp .= ($donetodo != 'done' && $donetodo != 'todo' ? ' / ' : '');
13246 $tmp .= ($donetodo != 'todo' ? $langs->trans("ActionsDoneShort") : '');
13247 //$out.=$langs->trans("ActionsToDoShort").' / '.$langs->trans("ActionsDoneShort");
13248 if (get_class($filterobj) == 'Societe') {
13249 $tmp .= '</a>';
13250 }
13251 $out .= getTitleFieldOfList($tmp);
13252 }
13253
13254 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
13255 $caction = new CActionComm($db);
13256 $arraylist = $caction->liste_array(1, 'code', '', (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : 0), '', 1);
13257
13258 $actualCycleDate = false;
13259
13260 // Loop on each event to show it
13261 foreach ($histo as $key => $value) {
13262 $actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo
13263
13264 $actionstatic->type_picto = $histo[$key]['apicto'];
13265 $actionstatic->type_code = $histo[$key]['acode'];
13266
13267 $labeltype = $actionstatic->type_code;
13268 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') && empty($arraylist[$labeltype])) {
13269 $labeltype = 'AC_OTH';
13270 }
13271 if (!empty($actionstatic->code) && preg_match('/^TICKET_MSG/', $actionstatic->code)) {
13272 $labeltype = $langs->trans("Message");
13273 } else {
13274 if (!empty($arraylist[$labeltype])) {
13275 $labeltype = $arraylist[$labeltype];
13276 }
13277 if ($actionstatic->type_code == 'AC_OTH_AUTO' && ($actionstatic->type_code != $actionstatic->code) && $labeltype && !empty($arraylist[$actionstatic->code])) {
13278 $labeltype .= ' - '.$arraylist[$actionstatic->code]; // Use code in priority on type_code
13279 }
13280 }
13281
13282 $url = DOL_URL_ROOT.'/comm/action/card.php?id='.$histo[$key]['id'];
13283
13284 $tmpa = dol_getdate($histo[$key]['datestart'], false);
13285
13286 if (isset($tmpa['year']) && isset($tmpa['yday']) && $actualCycleDate !== $tmpa['year'].'-'.$tmpa['yday']) {
13287 $actualCycleDate = $tmpa['year'].'-'.$tmpa['yday'];
13288 $out .= '<!-- timeline time label -->';
13289 $out .= '<li class="time-label">';
13290 $out .= '<span class="timeline-badge-date">';
13291 $out .= dol_print_date($histo[$key]['datestart'], 'daytext', 'tzuserrel', $langs);
13292 $out .= '</span>';
13293 $out .= '</li>';
13294 $out .= '<!-- /.timeline-label -->';
13295 }
13296
13297
13298 $out .= '<!-- timeline item -->'."\n";
13299 $out .= '<li class="timeline-code-'.strtolower($actionstatic->code).'">';
13300
13301 //$timelineicon = getTimelineIcon($actionstatic, $histo, $key);
13302 $typeicon = $actionstatic->getTypePicto('pictofixedwidth timeline-icon-not-applicble', $labeltype);
13303 //$out .= $timelineicon;
13304 //var_dump($timelineicon);
13305 $out .= $typeicon;
13306
13307 $out .= '<div class="timeline-item">'."\n";
13308
13309 $out .= '<span class="time timeline-header-action2">';
13310
13311 if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
13312 $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").' ';
13313 $out .= $histo[$key]['id'];
13314 $out .= '</a> ';
13315 } else {
13316 $out .= $actionstatic->getNomUrl(1, -1, 'valignmiddle').' ';
13317 }
13318
13319 if ($user->hasRight('agenda', 'allactions', 'create') ||
13320 (($actionstatic->authorid == $user->id || $actionstatic->userownerid == $user->id) && $user->hasRight('agenda', 'myactions', 'create'))) {
13321 $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).'">';
13322 //$out .= '<i class="fa fa-pencil" title="'.$langs->trans("Modify").'" ></i>';
13323 $out .= img_picto($langs->trans("Modify"), 'edit', 'class="edita"');
13324 $out .= '</a>';
13325 }
13326
13327 $out .= '</span>';
13328
13329 // Date
13330 $out .= '<span class="time"><i class="fa fa-clock-o valignmiddle"></i> <span class="valignmiddle">';
13331 $out .= dol_print_date($histo[$key]['datestart'], 'dayhour', 'tzuserrel');
13332 if ($histo[$key]['dateend'] && $histo[$key]['dateend'] != $histo[$key]['datestart']) {
13333 $tmpa = dol_getdate($histo[$key]['datestart'], true);
13334 $tmpb = dol_getdate($histo[$key]['dateend'], true);
13335 if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
13336 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'hour', 'tzuserrel');
13337 } else {
13338 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'dayhour', 'tzuserrel');
13339 }
13340 }
13341 $late = 0;
13342 if ($histo[$key]['percent'] == 0 && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13343 $late = 1;
13344 }
13345 if ($histo[$key]['percent'] == 0 && !$histo[$key]['datestart'] && $histo[$key]['dateend'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13346 $late = 1;
13347 }
13348 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && $histo[$key]['dateend'] && $histo[$key]['dateend'] < ($now - $delay_warning)) {
13349 $late = 1;
13350 }
13351 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && !$histo[$key]['dateend'] && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13352 $late = 1;
13353 }
13354 if ($late) {
13355 $out .= img_warning($langs->trans("Late")).' ';
13356 }
13357 $out .= "</span></span>\n";
13358
13359 // Ref
13360 $out .= '<h3 class="timeline-header">';
13361
13362 // Author of event
13363 $out .= '<div class="messaging-author inline-block tdoverflowmax150 valignmiddle marginrightonly">';
13364 if ($histo[$key]['userid'] > 0) {
13365 if (!isset($userGetNomUrlCache[$histo[$key]['userid']])) { // is in cache ?
13366 $userstatic->fetch($histo[$key]['userid']);
13367 $userGetNomUrlCache[$histo[$key]['userid']] = $userstatic->getNomUrl(-1, '', 0, 0, 16, 0, 'firstelselast', '');
13368 }
13369 $out .= $userGetNomUrlCache[$histo[$key]['userid']];
13370 } elseif (!empty($histo[$key]['msg_from']) && $actionstatic->code == 'TICKET_MSG') {
13371 if (!isset($contactGetNomUrlCache[$histo[$key]['msg_from']])) {
13372 if ($contactstatic->fetch(0, null, '', $histo[$key]['msg_from']) > 0) {
13373 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $contactstatic->getNomUrl(-1, '', 16);
13374 } else {
13375 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $histo[$key]['msg_from'];
13376 }
13377 }
13378 $out .= $contactGetNomUrlCache[$histo[$key]['msg_from']];
13379 }
13380 $out .= '</div>';
13381
13382 // Title
13383 $out .= ' <div class="messaging-title inline-block">';
13384 //$out .= $actionstatic->getTypePicto();
13385 if (empty($conf->dol_optimize_smallscreen) && $actionstatic->type_code != 'AC_OTH_AUTO') {
13386 $out .= $labeltype.' - ';
13387 }
13388
13389 $libelle = '';
13390 if (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
13391 $out .= $langs->trans('TicketNewMessage');
13392 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
13393 $out .= $langs->trans('TicketNewMessage').' <em>('.$langs->trans('Private').')</em>';
13394 } elseif (isset($histo[$key]['type'])) {
13395 if ($histo[$key]['type'] == 'action') {
13396 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
13397 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : $histo[$key]['alabel']);
13398 $libelle = $histo[$key]['note'];
13399 $actionstatic->id = $histo[$key]['id'];
13400 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13401 } elseif ($histo[$key]['type'] == 'mailing') {
13402 $out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
13403 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
13404 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : 'Send mass mailing');
13405 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13406 } else {
13407 $libelle .= $histo[$key]['note'];
13408 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13409 }
13410 }
13411
13412 if (isset($histo[$key]['elementtype']) && !empty($histo[$key]['fk_element'])) {
13413 if (isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']]) && isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']])) {
13414 $link = $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']];
13415 } else {
13416 if (!isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']])) {
13417 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']] = array();
13418 }
13419 $link = dolGetElementUrl($histo[$key]['fk_element'], $histo[$key]['elementtype'], 1);
13420 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']] = $link;
13421 }
13422 if ($link) {
13423 $out .= ' - '.$link;
13424 }
13425 }
13426
13427 $out .= '</div>';
13428
13429 $out .= '</h3>';
13430
13431 // Message
13432 if (!empty($histo[$key]['message'] && $histo[$key]['message'] != $libelle)
13433 && $actionstatic->code != 'AC_TICKET_CREATE'
13434 && $actionstatic->code != 'AC_TICKET_MODIFY'
13435 ) {
13436 $out .= '<div class="timeline-body wordbreak">';
13437 $truncateLines = getDolGlobalInt('MAIN_TRUNCATE_TIMELINE_MESSAGE', 3);
13438 $truncatedText = dolGetFirstLineOfText($histo[$key]['message'], $truncateLines);
13439 if ($truncateLines > 0 && strlen($histo[$key]['message']) > strlen($truncatedText)) {
13440 $out .= '<div class="readmore-block --closed" >';
13441 $out .= ' <div class="readmore-block__excerpt" >';
13442 $out .= $truncatedText ;
13443 $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>';
13444 $out .= ' </div>';
13445 $out .= ' <div class="readmore-block__full-text" >';
13446 $out .= $histo[$key]['message'];
13447 $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>';
13448 $out .= ' </div>';
13449 $out .= '</div>';
13450 } else {
13451 $out .= $histo[$key]['message'];
13452 }
13453
13454 $out .= '</div>';
13455 }
13456
13457 // Timeline footer
13458 $footer = '';
13459
13460 // Contact for this action
13461 if (isset($histo[$key]['socpeopleassigned']) && is_array($histo[$key]['socpeopleassigned']) && count($histo[$key]['socpeopleassigned']) > 0) {
13462 $contactList = '';
13463 foreach ($histo[$key]['socpeopleassigned'] as $cid => $Tab) {
13464 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
13465 $contact = new Contact($db);
13466 $contact->fetch($cid);
13467 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
13468 } else {
13469 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
13470 }
13471
13472 if ($contact) {
13473 $contactList .= !empty($contactList) ? ', ' : '';
13474 $contactList .= $contact->getNomUrl(1);
13475 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
13476 if (!empty($contact->phone_pro)) {
13477 $contactList .= '('.dol_print_phone($contact->phone_pro).')';
13478 }
13479 }
13480 }
13481 }
13482
13483 $footer .= $langs->trans('ActionOnContact').' : '.$contactList;
13484 } elseif (empty($objcon->id) && isset($histo[$key]['contact_id']) && $histo[$key]['contact_id'] > 0) {
13485 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
13486 $contact = new Contact($db);
13487 $result = $contact->fetch($histo[$key]['contact_id']);
13488 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
13489 } else {
13490 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
13491 }
13492
13493 if ($result > 0) {
13494 $footer .= $contact->getNomUrl(1);
13495 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
13496 if (!empty($contact->phone_pro)) {
13497 $footer .= '('.dol_print_phone($contact->phone_pro).')';
13498 }
13499 }
13500 }
13501 }
13502
13503 $documents = getActionCommEcmList($actionstatic);
13504 if (!empty($documents)) {
13505 $footer .= '<div class="timeline-documents-container">';
13506 foreach ($documents as $doc) {
13507 $footer .= '<span id="document_'.$doc->id.'" class="timeline-documents" ';
13508 $footer .= ' data-id="'.$doc->id.'" ';
13509 $footer .= ' data-path="'.$doc->filepath.'"';
13510 $footer .= ' data-filename="'.dol_escape_htmltag($doc->filename).'" ';
13511 $footer .= '>';
13512
13513 $filePath = DOL_DATA_ROOT.'/'.$doc->filepath.'/'.$doc->filename;
13514 $mime = dol_mimetype($filePath);
13515 $file = $actionstatic->id.'/'.$doc->filename;
13516 $thumb = $actionstatic->id.'/thumbs/'.substr($doc->filename, 0, strrpos($doc->filename, '.')).'_mini'.substr($doc->filename, strrpos($doc->filename, '.'));
13517 $doclink = dol_buildpath('document.php', 1).'?modulepart=actions&attachment=0&file='.urlencode($file).'&entity='.$conf->entity;
13518 $viewlink = dol_buildpath('viewimage.php', 1).'?modulepart=actions&file='.urlencode($thumb).'&entity='.$conf->entity;
13519
13520 $mimeAttr = ' mime="'.$mime.'" ';
13521 $class = '';
13522 if (in_array($mime, array('image/png', 'image/jpeg', 'application/pdf'))) {
13523 $class .= ' documentpreview';
13524 }
13525
13526 $footer .= '<a href="'.$doclink.'" class="btn-link '.$class.'" target="_blank" rel="noopener noreferrer" '.$mimeAttr.' >';
13527 $footer .= img_mime($filePath).' '.$doc->filename;
13528 $footer .= '</a>';
13529
13530 $footer .= '</span>';
13531 }
13532 $footer .= '</div>';
13533 }
13534
13535 if (!empty($footer)) {
13536 $out .= '<div class="timeline-footer">'.$footer.'</div>';
13537 }
13538
13539 $out .= '</div>'."\n"; // end timeline-item
13540
13541 $out .= '</li>';
13542 $out .= '<!-- END timeline item -->';
13543
13544 $i++;
13545 }
13546
13547 $out .= "</ul>\n";
13548
13549 $out .= '<script>
13550 jQuery(document).ready(function () {
13551 $(document).on("click", "[data-read-more-action]", function(e){
13552 let readMoreBloc = $(this).closest(".readmore-block");
13553 if(readMoreBloc.length > 0){
13554 e.preventDefault();
13555 if($(this).attr("data-read-more-action") == "close"){
13556 readMoreBloc.addClass("--closed").removeClass("--open");
13557 $("html, body").animate({
13558 scrollTop: readMoreBloc.offset().top - 200
13559 }, 100);
13560 }else{
13561 readMoreBloc.addClass("--open").removeClass("--closed");
13562 }
13563 }
13564 });
13565 });
13566 </script>';
13567
13568
13569 if (empty($histo)) {
13570 $out .= '<span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span>';
13571 }
13572 }
13573
13574 if ($noprint) {
13575 return $out;
13576 } else {
13577 print $out;
13578 }
13579}
13580
13591function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto')
13592{
13593 if ($hourTime === 'getpost') {
13594 $hour = GETPOSTINT($prefix . 'hour');
13595 $minute = GETPOSTINT($prefix . 'minute');
13596 $second = GETPOSTINT($prefix . 'second');
13597 } elseif (preg_match('/^(\d\d):(\d\d):(\d\d)$/', $hourTime, $m)) {
13598 $hour = intval($m[1]);
13599 $minute = intval($m[2]);
13600 $second = intval($m[3]);
13601 } else {
13602 $hour = $minute = $second = 0;
13603 }
13604 // normalize out of range values
13605 $hour = min($hour, 23);
13606 $minute = min($minute, 59);
13607 $second = min($second, 59);
13608 return dol_mktime($hour, $minute, $second, GETPOSTINT($prefix . 'month'), GETPOSTINT($prefix . 'day'), GETPOSTINT($prefix . 'year'), $gm);
13609}
13610
13622function buildParamDate($prefix, $timestamp = null, $hourTime = '', $gm = 'auto')
13623{
13624 if ($timestamp === null) {
13625 $timestamp = GETPOSTDATE($prefix, $hourTime, $gm);
13626 }
13627 $TParam = array(
13628 $prefix . 'day' => intval(dol_print_date($timestamp, '%d')),
13629 $prefix . 'month' => intval(dol_print_date($timestamp, '%m')),
13630 $prefix . 'year' => intval(dol_print_date($timestamp, '%Y')),
13631 );
13632 if ($hourTime === 'getpost' || ($timestamp !== null && dol_print_date($timestamp, '%H:%M:%S') !== '00:00:00')) {
13633 $TParam = array_merge($TParam, array(
13634 $prefix . 'hour' => intval(dol_print_date($timestamp, '%H')),
13635 $prefix . 'minute' => intval(dol_print_date($timestamp, '%M')),
13636 $prefix . 'second' => intval(dol_print_date($timestamp, '%S'))
13637 ));
13638 }
13639
13640 return '&' . http_build_query($TParam);
13641}
if(preg_match('/set_([a-z0-9_\-]+)/i', $action, $reg)) if(preg_match('/del_([a-z0-9_\-]+)/i', $action, $reg)) if($action=='set') elseif( $action=='specimen') elseif($action=='setmodel') elseif( $action=='del') elseif($action=='setdoc') $formactions
View.
ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input=array(), $morecss='', $htmlname='', $forcenojs=0)
On/off button to change a property status of an object This uses the ajax service objectonoff....
Definition ajax.lib.php:717
Class to manage agenda events (actions)
Class to manage different types of events.
Class to manage GeoIP conversion Usage: $geoip=new GeoIP('country',$datfile); $geoip->getCountryCodeF...
Class to manage standard extra fields.
Class to manage invoices.
Class to manage building of HTML components.
Class to manage hooks.
Class to manage predefined suppliers products.
Class to manage products or services.
Class to manage third parties objects (customers, suppliers, prospects...)
isACompany()
Return if third party is a company (Business) or an end user (Consumer)
Class to manage translations.
Class to manage Dolibarr users.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
dol_get_prev_month($month, $year)
Return previous month.
Definition date.lib.php:513
dol_get_next_day($day, $month, $year)
Return next day.
Definition date.lib.php:498
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:86
dol_get_prev_day($day, $month, $year)
Return previous day.
Definition date.lib.php:482
dol_get_next_month($month, $year)
Return next month.
Definition date.lib.php:532
dol_convert_file($fileinput, $ext='png', $fileoutput='', $page='')
Convert an image file or a PDF into another image format.
dragAndDropFileUpload($htmlname)
Function to manage the drag and drop of a file.
dol_is_file($pathoffile)
Return if path is a file.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:62
dol_is_dir($folder)
Test if filename is a directory.
dolGetElementUrl($objectid, $objecttype, $withpicto=0, $option='')
Return link url to an object.
isValidVATID($company)
Check if VAT numero is valid (check done on syntax only, no database or remote access)
dol_html_entity_decode($a, $b, $c='UTF-8', $keepsomeentities=0)
Replace html_entity_decode functions to manage errors.
dol_fiche_end($notab=0)
Show tab footer of a card.
dolCheckFilters($sqlfilters, &$error='')
Return if a $sqlfilters parameter has a valid balance of parenthesis.
dol_print_size($size, $shortvalue=0, $shortunit=0)
Return string with formated size.
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
isOnlyOneLocalTax($local)
Return true if LocalTax (1 or 2) is unique.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod=0)
Function that return localtax of a product line (according to seller, buyer and product vat rate) Si ...
img_weather($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $morecss='')
Show weather picto.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='', $useCache=true)
Return an id or code from a code or id.
finishSimpleTable($addLineBreak=false)
Add the correct HTML close tags for "startSimpleTable(...)" (use after the last table line)
startSimpleTable($header, $link="", $arguments="", $emptyRows=0, $number=-1)
Start a table with headers and a optinal clickable number (don't forget to use "finishSimpleTable()" ...
getLanguageCodeFromCountryCode($countrycode)
Return default language from country code.
setEntity($currentobject)
Set entity id to use when to create an object.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks=array())
Show social network link.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
dol_ucfirst($string, $encoding="UTF-8")
Convert first character of the first word of a string to upper.
img_right($titlealt='default', $selected=0, $moreatt='')
Show right arrow logo.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
dol_strtolower($string, $encoding="UTF-8")
Convert a string to lower.
showValueWithClipboardCPButton($valuetocopy, $showonlyonhover=1, $texttoshow='')
Create a button to copy $valuetocopy in the clipboard (for copy and paste feature).
dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto='UTF-8')
This function is called to decode a HTML string (it decodes entities and br tags)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_left($titlealt='default', $selected=0, $moreatt='')
Show left arrow logo.
dol_print_ip($ip, $mode=0)
Return an IP formated to be shown on screen.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
GETPOSTINT($paramname, $method=0)
Return value of a param into GET or POST supervariable.
isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
Function to test if an entry is enabled or not.
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
getDolUserInt($key, $default=0, $tmpuser=null)
Return Dolibarr user constant int value.
yn($yesno, $case=1, $color=0)
Return yes or no in current language.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dolPrintHTML($s, $allowiframe=0)
Return a string ready to be output on HTML page To use text inside an attribute, you can simply use d...
isASecretKey($keyname)
Return if string has a name dedicated to store a secret.
dolPrintHTMLForTextArea($s, $allowiframe=0)
Return a string ready to be output on input textarea To use text inside an attribute,...
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
print_fleche_navigation($page, $file, $options='', $nextpage=0, $betweenarrows='', $afterarrows='', $limit=-1, $totalnboflines=0, $hideselectlimit=0, $beforearrows='', $hidenavigation=0)
Function to show navigation arrows into lists.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
get_date_range($date_start, $date_end, $format='', $outputlangs='', $withparenthesis=1)
Format output for start and end date.
get_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Get formated error messages to output (Used to show messages on html output).
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
roundUpToNextMultiple($n, $x=5)
Round to next multiple.
dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled='', $morecss='classlink button bordertransp', $jsonopen='', $backtopagejsfields='', $accesskey='')
Return HTML code to output a button to open a dialog popup box.
dol_user_country()
Return country code for current user.
dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes=null)
Clean a string from some undesirable HTML tags.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_format_address($object, $withcountry=0, $sep="\n", $outputlangs='', $mode=0, $extralangcode='')
Return a formated address (part address/zip/town/state) according to country rules.
isHTTPS()
Return if we are using a HTTPS connexion Check HTTPS (no way to be modified by user but may be empty ...
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
picto_required()
Return picto saying a field is required.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
img_action($titlealt, $numaction, $picto='', $moreatt='')
Show logo action.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0)
Set event message in dol_events session object.
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
GETPOSTDATE($prefix, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
printCommonFooter($zone='private')
Print common footer : conf->global->MAIN_HTML_FOOTER js for switch of menu hider js for conf->global-...
checkVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
img_down($titlealt='default', $selected=0, $moreclass='')
Show down arrow logo.
getTaxesFromId($vatrate, $buyer=null, $seller=null, $firstparamisid=1)
Get tax (VAT) main information from Id.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
utf8_valid($str)
Check if a string is in UTF8.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
getDolUserString($key, $default='', $tmpuser=null)
Return Dolibarr user constant string value.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
img_allow($allow, $titlealt='default')
Show tick logo if allowed.
isValidMXRecord($domain)
Return if the domain name has a valid MX record.
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
get_htmloutput_mesg($mesgstring='', $mesgarray='', $style='ok', $keepembedded=0)
Get formated messages to output (Used to show messages on html output).
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0)
Format phone numbers according to country.
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
dol_fiche_head($links=array(), $active='0', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tab header of a card.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
get_localtax_by_third($local)
Get values of localtaxes (1 or 2) for company country for the common vat with the highest value.
dol_escape_php($stringtoescape, $stringforquotes=2)
Returns text escaped for inclusion into a php string, build with double quotes " or '.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0)
Clean a string to keep only desirable HTML tags.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
ajax_autoselect($htmlname, $addlink='', $textonlink='Link')
Make content of an input box selected when we click into input field.
img_view($titlealt='default', $float=0, $other='class="valignmiddle"')
Show logo view card.
dolPrintHTMLForAttribute($s)
Return a string ready to be output on an HTML attribute (alt, title, data-html, .....
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_eval($s, $returnvalue=0, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_strftime($fmt, $ts=false, $is_gmt=false)
Format a string.
img_picto_common($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $notitle=0)
Show picto (generic function)
img_search($titlealt='default', $other='')
Show search logo.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
isValidPhone($phone)
Return true if phone number syntax is ok TODO Decide what to do with this.
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
img_previous($titlealt='default', $moreatt='')
Show previous logo.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
fieldLabel($langkey, $fieldkey, $fieldrequired=0)
Show a string with the label tag dedicated to the HTML edit field.
getBrowserInfo($user_agent)
Return information about user browser.
dolGetFirstLetters($s, $nbofchar=1)
Return first letters of a strings.
dol_strtoupper($string, $encoding="UTF-8")
Convert a string to upper.
dol_sanitizeUrl($stringtoclean, $type=1)
Clean a string to use it as an URL (into a href or src attribute)
img_printer($titlealt="default", $other='')
Show printer logo.
dol_htmloutput_events($disabledoutputofmessages=0)
Print formated messages to output (Used to show messages on html output).
getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $disablesortlink=0, $tooltip='', $forcenowrapcolumntitle=0)
Get title line of an array.
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
ascii_check($str)
Check if a string is in ASCII.
getPictoForType($key)
Return the picto for a data type.
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
getArrayOfSocialNetworks()
Get array of social network dictionary.
dolGetButtonTitleSeparator($moreClass="")
Add space between dolGetButtonTitle.
num2Alpha($n)
Return a numeric value into an Excel like column number.
dol_size($size, $type='')
Optimize a size for some browsers (phone, smarphone, ...)
img_split($titlealt='default', $other='class="pictosplit"')
Show split logo.
img_pdf($titlealt='default', $size=3)
Show pdf logo.
dolGetCountryCodeFromIp($ip)
Return a country code from IP.
dol_textishtml($msg, $option=0)
Return if a text is a html content.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolPrintPassword($s)
Return a string ready to be output on an HTML attribute (alt, title, ...)
colorIsLight($stringcolor)
Return true if the color is light.
dol_escape_all($stringtoescape)
Returns text escaped for all protocols (so only alpha chars and numbers)
readfileLowMemory($fullpath_original_file_osencoded, $method=-1)
Return a file on output using a low memory.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
dol_shutdown()
Function called at end of web php process.
dol_print_address($address, $htmlid, $element, $id, $noprint=0, $charfornl='')
Format address string.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_print_error_email($prefixcode, $errormessage='', $errormessages=array(), $morecss='error', $email='')
Show a public email and error code to contact if technical error.
dol_print_profids($profID, $profIDtype, $countrycode='', $addcpButton=1)
Format professional IDs according to their country.
print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
dol_bc($var, $moreclass='')
Return string to add class property on html element with pair/impair.
print_titre($title)
Show a title.
getElementProperties($element_type)
Get an array with properties of an element.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_string_nounprintableascii($str, $removetabcrlf=1)
Clean a string from all non printable ASCII chars (0x00-0x1F and 0x7F).
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
img_error($titlealt='default')
Show error logo.
getTimelineIcon($actionstatic, &$histo, $key)
Get timeline icon.
dol_htmloutput_mesg($mesgstring='', $mesgarray=array(), $style='ok', $keepembedded=0)
Print formated messages to output (Used to show messages on html output).
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
buildParamDate($prefix, $timestamp=null, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
img_next($titlealt='default', $moreatt='')
Show next logo.
print_date_range($date_start, $date_end, $format='', $outputlangs='')
Format output for start and end date.
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_string_is_good_iso($s, $clean=0)
Check if a string is a correct iso string If not, it will not be considered as HTML encoded even if i...
getNonce()
Return a random string to be used as a nonce value for js.
isStringVarMatching($var, $regextext, $matchrule=1)
Check if a variable with name $var start with $text.
complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode='add', $filterorigmodule='')
Complete or removed entries into a head array (used to build tabs).
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
Return localtax vat rate of a product in a particular country or default country vat if product is un...
getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $object=null, $include=null)
Return array of possible common substitutions.
dol_nboflines($s, $maxchar=0)
Return nb of lines of a clear text.
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js, dangerous content and external link.
jsonOrUnserialize($stringtodecode)
Decode an encode string.
addSummaryTableLine($tableColumnCount, $num, $nbofloop=0, $total=0, $noneWord="None", $extraRightColumn=false)
Add a summary line to the current open table ("None", "XMoreLines" or "Total xxx")
isValidEmail($address, $acceptsupervisorkey=0, $acceptuserkey=0)
Return true if email syntax is ok.
dol_escape_xml($stringtoescape)
Returns text escaped for inclusion into a XML string.
getActionCommEcmList($object)
getActionCommEcmList
dol_ucwords($string, $encoding="UTF-8")
Convert first character of all the words of a string to upper.
img_edit_add($titlealt='default', $other='')
Show logo +.
verifCond($strToEvaluate)
Verify if condition in string is ok or not.
if(!function_exists( 'utf8_encode')) if(!function_exists('utf8_decode')) if(!function_exists( 'str_starts_with')) if(!function_exists('str_ends_with')) if(!function_exists( 'str_contains')) getMultidirOutput($object, $module='')
Return the full path of the directory where a module (or an object of a module) stores its files.
print_fiche_titre($title, $mesg='', $picto='generic', $pictoisfullpath=0, $id='')
Show a title with picto.
get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice=0)
Return vat rate of a product in a particular country, or default country vat if product is unknown.
dolForgeDummyCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
dol_escape_json($stringtoescape)
Returns text escaped for inclusion into javascript code.
dolForgeCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
getUserRemoteIP()
Return the IP of remote user.
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_validElement($element)
Return if var element is ok.
img_credit_card($brand, $morecss=null)
Return image of a credit card according to its brand name.
img_searchclear($titlealt='default', $other='')
Show search logo.
dolPrintLabel($s)
Return a string label (so on 1 line only and that should not contains any HTML) ready to be output on...
fetchObjectByElement($element_id, $element_type, $element_ref='')
Fetch an object from its id and element_type Inclusion of classes is automatic.
utf8_check($str)
Check if a string is in UTF8.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
show_actions_messaging($conf, $langs, $db, $filterobj, $objcon='', $noprint=0, $actioncode='', $donetodo='done', $filters=array(), $sortfield='a.datep, a.id', $sortorder='DESC')
Show html area with actions in messaging format.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
img_up($titlealt='default', $selected=0, $moreclass='')
Show top arrow logo.
dol_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Print formated error messages to output (Used to show messages on html output).
getFieldErrorIcon($fieldValidationErrorMsg)
get field error icon
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
img_edit_remove($titlealt='default', $other='')
Show logo -.
img_info($titlealt='default')
Show info logo.
getDoliDBInstance($type, $host, $user, $pass, $name, $port)
Return a DoliDB instance (database handler).
dol_sanitizeEmail($stringtoclean)
Clean a string to use it as an Email.
dol_nboflines_bis($text, $maxlinesize=0, $charset='UTF-8')
Return nb of lines of a formated text with and (WARNING: string must not have mixed and br sepa...
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
dol_convertToWord($num, $langs, $currency='', $centimes=false)
Function to return a number into a text.
conf($dolibarr_main_document_root)
Load conf file (file must exists)
Definition inc.php:403
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php: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