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 Joachim Kueter <git-jk@bloxera.com>
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 3 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program. If not, see <https://www.gnu.org/licenses/>.
37 * or see https://www.gnu.org/
38 */
39
46include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
47
48// Function for better PHP x compatibility
49if (!function_exists('utf8_encode')) {
56 function utf8_encode($elements)
57 {
58 return mb_convert_encoding($elements, 'UTF-8', 'ISO-8859-1');
59 }
60}
61
62if (!function_exists('utf8_decode')) {
69 function utf8_decode($elements)
70 {
71 return mb_convert_encoding($elements, 'ISO-8859-1', 'UTF-8');
72 }
73}
74if (!function_exists('str_starts_with')) {
82 function str_starts_with($haystack, $needle)
83 {
84 return (string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0;
85 }
86}
87if (!function_exists('str_ends_with')) {
95 function str_ends_with($haystack, $needle)
96 {
97 return $needle !== '' && substr($haystack, -strlen($needle)) === (string) $needle;
98 }
99}
100if (!function_exists('str_contains')) {
108 function str_contains($haystack, $needle)
109 {
110 return $needle !== '' && mb_strpos($haystack, $needle) !== false;
111 }
112}
113
114
123function getMultidirOutput($object, $module = '')
124{
125 global $conf;
126
127 if (!is_object($object) && empty($module)) {
128 return null;
129 }
130 if (empty($module) && !empty($object->element)) {
131 $module = $object->element;
132 }
133 // Special case for backward compatibility
134 if ($module == 'fichinter') {
135 $module = 'ficheinter';
136 }
137 if (isset($conf->$module) && property_exists($conf->$module, 'multidir_output')) {
138 return $conf->$module->multidir_output[(empty($object->entity) ? $conf->entity : $object->entity)];
139 } else {
140 return 'error-diroutput-not-defined-for-this-object='.$module;
141 }
142}
143
151function getDolGlobalString($key, $default = '')
152{
153 global $conf;
154 return (string) (isset($conf->global->$key) ? $conf->global->$key : $default);
155}
156
165function getDolGlobalInt($key, $default = 0)
166{
167 global $conf;
168 return (int) (isset($conf->global->$key) ? $conf->global->$key : $default);
169}
170
179function getDolUserString($key, $default = '', $tmpuser = null)
180{
181 if (empty($tmpuser)) {
182 global $user;
183 $tmpuser = $user;
184 }
185
186 return (string) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
187}
188
197function getDolUserInt($key, $default = 0, $tmpuser = null)
198{
199 if (empty($tmpuser)) {
200 global $user;
201 $tmpuser = $user;
202 }
203
204 return (int) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
205}
206
213function isModEnabled($module)
214{
215 global $conf;
216
217 // Fix special cases
218 $arrayconv = array(
219 'bank' => 'banque',
220 'category' => 'categorie',
221 'contract' => 'contrat',
222 'project' => 'projet',
223 'delivery_note' => 'expedition'
224 );
225 if (!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD')) {
226 $arrayconv['supplier_order'] = 'fournisseur';
227 $arrayconv['supplier_invoice'] = 'fournisseur';
228 }
229 if (!empty($arrayconv[$module])) {
230 $module = $arrayconv[$module];
231 }
232
233 return !empty($conf->modules[$module]);
234 //return !empty($conf->$module->enabled);
235}
236
248function getDoliDBInstance($type, $host, $user, $pass, $name, $port)
249{
250 require_once DOL_DOCUMENT_ROOT."/core/db/".$type.'.class.php';
251
252 $class = 'DoliDB'.ucfirst($type);
253 $dolidb = new $class($type, $host, $user, $pass, $name, $port);
254 return $dolidb;
255}
256
274function getEntity($element, $shared = 1, $currentobject = null)
275{
276 global $conf, $mc, $hookmanager, $object, $action, $db;
277
278 if (!is_object($hookmanager)) {
279 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
280 $hookmanager = new HookManager($db);
281 }
282
283 // fix different element names (France to English)
284 switch ($element) {
285 case 'projet':
286 $element = 'project';
287 break;
288 case 'contrat':
289 $element = 'contract';
290 break; // "/contrat/class/contrat.class.php"
291 case 'order_supplier':
292 $element = 'supplier_order';
293 break; // "/fourn/class/fournisseur.commande.class.php"
294 case 'invoice_supplier':
295 $element = 'supplier_invoice';
296 break; // "/fourn/class/fournisseur.facture.class.php"
297 }
298
299 if (is_object($mc)) {
300 $out = $mc->getEntity($element, $shared, $currentobject);
301 } else {
302 $out = '';
303 $addzero = array('user', 'usergroup', 'cronjob', 'c_email_templates', 'email_template', 'default_values', 'overwrite_trans');
304 if (in_array($element, $addzero)) {
305 $out .= '0,';
306 }
307 $out .= ((int) $conf->entity);
308 }
309
310 // Manipulate entities to query on the fly
311 $parameters = array(
312 'element' => $element,
313 'shared' => $shared,
314 'object' => $object,
315 'currentobject' => $currentobject,
316 'out' => $out
317 );
318 $reshook = $hookmanager->executeHooks('hookGetEntity', $parameters, $currentobject, $action); // Note that $action and $object may have been modified by some hooks
319
320 if (is_numeric($reshook)) {
321 if ($reshook == 0 && !empty($hookmanager->resPrint)) {
322 $out .= ','.$hookmanager->resPrint; // add
323 } elseif ($reshook == 1) {
324 $out = $hookmanager->resPrint; // replace
325 }
326 }
327
328 return $out;
329}
330
337function setEntity($currentobject)
338{
339 global $conf, $mc;
340
341 if (is_object($mc) && method_exists($mc, 'setEntity')) {
342 return $mc->setEntity($currentobject);
343 } else {
344 return ((is_object($currentobject) && $currentobject->id > 0 && $currentobject->entity > 0) ? $currentobject->entity : $conf->entity);
345 }
346}
347
354function isASecretKey($keyname)
355{
356 return preg_match('/(_pass|password|_pw|_key|securekey|serverkey|secret\d?|p12key|exportkey|_PW_[a-z]+|token)$/i', $keyname);
357}
358
359
366function num2Alpha($n)
367{
368 for ($r = ""; $n >= 0; $n = intval($n / 26) - 1) {
369 $r = chr($n % 26 + 0x41) . $r;
370 }
371 return $r;
372}
373
374
391function getBrowserInfo($user_agent)
392{
393 include_once DOL_DOCUMENT_ROOT.'/includes/mobiledetect/mobiledetectlib/Mobile_Detect.php';
394
395 $name = 'unknown';
396 $version = '';
397 $os = 'unknown';
398 $phone = '';
399
400 $user_agent = substr($user_agent, 0, 512); // Avoid to process too large user agent
401
402 $detectmobile = new Mobile_Detect(null, $user_agent);
403 $tablet = $detectmobile->isTablet();
404
405 if ($detectmobile->isMobile()) {
406 $phone = 'unknown';
407
408 // If phone/smartphone, we set phone os name.
409 if ($detectmobile->is('AndroidOS')) {
410 $os = $phone = 'android';
411 } elseif ($detectmobile->is('BlackBerryOS')) {
412 $os = $phone = 'blackberry';
413 } elseif ($detectmobile->is('iOS')) {
414 $os = 'ios';
415 $phone = 'iphone';
416 } elseif ($detectmobile->is('PalmOS')) {
417 $os = $phone = 'palm';
418 } elseif ($detectmobile->is('SymbianOS')) {
419 $os = 'symbian';
420 } elseif ($detectmobile->is('webOS')) {
421 $os = 'webos';
422 } elseif ($detectmobile->is('MaemoOS')) {
423 $os = 'maemo';
424 } elseif ($detectmobile->is('WindowsMobileOS') || $detectmobile->is('WindowsPhoneOS')) {
425 $os = 'windows';
426 }
427 }
428
429 // OS
430 if (preg_match('/linux/i', $user_agent)) {
431 $os = 'linux';
432 } elseif (preg_match('/macintosh/i', $user_agent)) {
433 $os = 'macintosh';
434 } elseif (preg_match('/windows/i', $user_agent)) {
435 $os = 'windows';
436 }
437
438 // Name
439 $reg = array();
440 if (preg_match('/firefox(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
441 $name = 'firefox';
442 $version = empty($reg[2]) ? '' : $reg[2];
443 } elseif (preg_match('/edge(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
444 $name = 'edge';
445 $version = empty($reg[2]) ? '' : $reg[2];
446 } elseif (preg_match('/chrome(\/|\s)([\d\.]+)/i', $user_agent, $reg)) {
447 $name = 'chrome';
448 $version = empty($reg[2]) ? '' : $reg[2];
449 } elseif (preg_match('/chrome/i', $user_agent, $reg)) {
450 // we can have 'chrome (Mozilla...) chrome x.y' in one string
451 $name = 'chrome';
452 } elseif (preg_match('/iceweasel/i', $user_agent)) {
453 $name = 'iceweasel';
454 } elseif (preg_match('/epiphany/i', $user_agent)) {
455 $name = 'epiphany';
456 } elseif (preg_match('/safari(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
457 $name = 'safari';
458 $version = empty($reg[2]) ? '' : $reg[2];
459 } elseif (preg_match('/opera(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
460 // Safari is often present in string for mobile but its not.
461 $name = 'opera';
462 $version = empty($reg[2]) ? '' : $reg[2];
463 } elseif (preg_match('/(MSIE\s([0-9]+\.[0-9]))|.*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
464 $name = 'ie';
465 $version = end($reg);
466 } elseif (preg_match('/(Windows NT\s([0-9]+\.[0-9])).*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
467 // MS products at end
468 $name = 'ie';
469 $version = end($reg);
470 } elseif (preg_match('/l[iy]n(x|ks)(\‍(|\/|\s)*([\d\.]+)/i', $user_agent, $reg)) {
471 // MS products at end
472 $name = 'lynxlinks';
473 $version = empty($reg[3]) ? '' : $reg[3];
474 }
475
476 if ($tablet) {
477 $layout = 'tablet';
478 } elseif ($phone) {
479 $layout = 'phone';
480 } else {
481 $layout = 'classic';
482 }
483
484 return array(
485 'browsername' => $name,
486 'browserversion' => $version,
487 'browseros' => $os,
488 'browserua' => $user_agent,
489 'layout' => $layout, // tablet, phone, classic
490 'phone' => $phone, // deprecated
491 'tablet' => $tablet // deprecated
492 );
493}
494
500function dol_shutdown()
501{
502 global $db;
503 $disconnectdone = false;
504 $depth = 0;
505 if (is_object($db) && !empty($db->connected)) {
506 $depth = $db->transaction_opened;
507 $disconnectdone = $db->close();
508 }
509 dol_syslog("--- End access to ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]).(($disconnectdone && $depth) ? ' (Warn: db disconnection forced, transaction depth was '.$depth.')' : ''), (($disconnectdone && $depth) ? LOG_WARNING : LOG_INFO));
510}
511
521function GETPOSTISSET($paramname)
522{
523 $isset = false;
524
525 $relativepathstring = $_SERVER["PHP_SELF"];
526 // Clean $relativepathstring
527 if (constant('DOL_URL_ROOT')) {
528 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
529 }
530 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
531 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
532 //var_dump($relativepathstring);
533 //var_dump($user->default_values);
534
535 // Code for search criteria persistence.
536 // Retrieve values if restore_lastsearch_values
537 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
538 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
539 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
540 if (is_array($tmp)) {
541 foreach ($tmp as $key => $val) {
542 if ($key == $paramname) { // We are on the requested parameter
543 $isset = true;
544 break;
545 }
546 }
547 }
548 }
549 // If there is saved contextpage, limit, page or mode
550 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
551 $isset = true;
552 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
553 $isset = true;
554 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
555 $isset = true;
556 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
557 $isset = true;
558 }
559 } else {
560 $isset = (isset($_POST[$paramname]) || isset($_GET[$paramname])); // We must keep $_POST and $_GET here
561 }
562
563 return $isset;
564}
565
574function GETPOSTISARRAY($paramname, $method = 0)
575{
576 // for $method test need return the same $val as GETPOST
577 if (empty($method)) {
578 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
579 } elseif ($method == 1) {
580 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
581 } elseif ($method == 2) {
582 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
583 } elseif ($method == 3) {
584 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
585 } else {
586 $val = 'BadFirstParameterForGETPOST';
587 }
588
589 return is_array($val);
590}
591
621function GETPOST($paramname, $check = 'alphanohtml', $method = 0, $filter = null, $options = null, $noreplace = 0)
622{
623 global $mysoc, $user, $conf;
624
625 if (empty($paramname)) {
626 return 'BadFirstParameterForGETPOST';
627 }
628 if (empty($check)) {
629 dol_syslog("Deprecated use of GETPOST, called with 1st param = ".$paramname." and a 2nd param that is '', when calling page ".$_SERVER["PHP_SELF"], LOG_WARNING);
630 // Enable this line to know who call the GETPOST with '' $check parameter.
631 //var_dump(debug_backtrace()[0]);
632 }
633
634 if (empty($method)) {
635 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
636 } elseif ($method == 1) {
637 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
638 } elseif ($method == 2) {
639 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
640 } elseif ($method == 3) {
641 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
642 } else {
643 return 'BadThirdParameterForGETPOST';
644 }
645
646 if (empty($method) || $method == 3 || $method == 4) {
647 $relativepathstring = (empty($_SERVER["PHP_SELF"]) ? '' : $_SERVER["PHP_SELF"]);
648 // Clean $relativepathstring
649 if (constant('DOL_URL_ROOT')) {
650 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
651 }
652 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
653 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
654 //var_dump($relativepathstring);
655 //var_dump($user->default_values);
656
657 // Code for search criteria persistence.
658 // Retrieve saved values if restore_lastsearch_values is set
659 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
660 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
661 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
662 if (is_array($tmp)) {
663 foreach ($tmp as $key => $val) {
664 if ($key == $paramname) { // We are on the requested parameter
665 $out = $val;
666 break;
667 }
668 }
669 }
670 }
671 // If there is saved contextpage, page or limit
672 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
673 $out = $_SESSION['lastsearch_contextpage_'.$relativepathstring];
674 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
675 $out = $_SESSION['lastsearch_limit_'.$relativepathstring];
676 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
677 $out = $_SESSION['lastsearch_page_'.$relativepathstring];
678 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
679 $out = $_SESSION['lastsearch_mode_'.$relativepathstring];
680 }
681 } elseif (!isset($_GET['sortfield'])) {
682 // Else, retrieve default values if we are not doing a sort
683 // If we did a click on a field to sort, we do no apply default values. Same if option MAIN_ENABLE_DEFAULT_VALUES is not set
684 if (!empty($_GET['action']) && $_GET['action'] == 'create' && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
685 // Search default value from $object->field
686 global $object;
687 if (is_object($object) && isset($object->fields[$paramname]['default'])) {
688 $out = $object->fields[$paramname]['default'];
689 }
690 }
691 if (getDolGlobalString('MAIN_ENABLE_DEFAULT_VALUES')) {
692 if (!empty($_GET['action']) && (preg_match('/^create/', $_GET['action']) || preg_match('/^presend/', $_GET['action'])) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
693 // Now search in setup to overwrite default values
694 if (!empty($user->default_values)) { // $user->default_values defined from menu 'Setup - Default values'
695 if (isset($user->default_values[$relativepathstring]['createform'])) {
696 foreach ($user->default_values[$relativepathstring]['createform'] as $defkey => $defval) {
697 $qualified = 0;
698 if ($defkey != '_noquery_') {
699 $tmpqueryarraytohave = explode('&', $defkey);
700 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
701 $foundintru = 0;
702 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
703 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
704 $foundintru = 1;
705 }
706 }
707 if (!$foundintru) {
708 $qualified = 1;
709 }
710 //var_dump($defkey.'-'.$qualified);
711 } else {
712 $qualified = 1;
713 }
714
715 if ($qualified) {
716 if (isset($user->default_values[$relativepathstring]['createform'][$defkey][$paramname])) {
717 $out = $user->default_values[$relativepathstring]['createform'][$defkey][$paramname];
718 break;
719 }
720 }
721 }
722 }
723 }
724 } elseif (!empty($paramname) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
725 // Management of default search_filters and sort order
726 if (!empty($user->default_values)) {
727 // $user->default_values defined from menu 'Setup - Default values'
728 //var_dump($user->default_values[$relativepathstring]);
729 if ($paramname == 'sortfield' || $paramname == 'sortorder') {
730 // Sorted on which fields ? ASC or DESC ?
731 if (isset($user->default_values[$relativepathstring]['sortorder'])) {
732 // Even if paramname is sortfield, data are stored into ['sortorder...']
733 foreach ($user->default_values[$relativepathstring]['sortorder'] as $defkey => $defval) {
734 $qualified = 0;
735 if ($defkey != '_noquery_') {
736 $tmpqueryarraytohave = explode('&', $defkey);
737 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
738 $foundintru = 0;
739 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
740 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
741 $foundintru = 1;
742 }
743 }
744 if (!$foundintru) {
745 $qualified = 1;
746 }
747 //var_dump($defkey.'-'.$qualified);
748 } else {
749 $qualified = 1;
750 }
751
752 if ($qualified) {
753 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
754 foreach ($user->default_values[$relativepathstring]['sortorder'][$defkey] as $key => $val) {
755 if ($out) {
756 $out .= ', ';
757 }
758 if ($paramname == 'sortfield') {
759 $out .= dol_string_nospecial($key, '', $forbidden_chars_to_replace);
760 }
761 if ($paramname == 'sortorder') {
762 $out .= dol_string_nospecial($val, '', $forbidden_chars_to_replace);
763 }
764 }
765 //break; // No break for sortfield and sortorder so we can cumulate fields (is it realy usefull ?)
766 }
767 }
768 }
769 } elseif (isset($user->default_values[$relativepathstring]['filters'])) {
770 foreach ($user->default_values[$relativepathstring]['filters'] as $defkey => $defval) { // $defkey is a querystring like 'a=b&c=d', $defval is key of user
771 if (!empty($_GET['disabledefaultvalues'])) { // If set of default values has been disabled by a request parameter
772 continue;
773 }
774 $qualified = 0;
775 if ($defkey != '_noquery_') {
776 $tmpqueryarraytohave = explode('&', $defkey);
777 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
778 $foundintru = 0;
779 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
780 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
781 $foundintru = 1;
782 }
783 }
784 if (!$foundintru) {
785 $qualified = 1;
786 }
787 //var_dump($defkey.'-'.$qualified);
788 } else {
789 $qualified = 1;
790 }
791
792 if ($qualified && isset($user->default_values[$relativepathstring]['filters'][$defkey][$paramname])) {
793 // We must keep $_POST and $_GET here
794 if (isset($_POST['sall']) || isset($_POST['search_all']) || isset($_GET['sall']) || isset($_GET['search_all'])) {
795 // We made a search from quick search menu, do we still use default filter ?
796 if (!getDolGlobalString('MAIN_DISABLE_DEFAULT_FILTER_FOR_QUICK_SEARCH')) {
797 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
798 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
799 }
800 } else {
801 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
802 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
803 }
804 break;
805 }
806 }
807 }
808 }
809 }
810 }
811 }
812 }
813
814 // Substitution variables for GETPOST (used to get final url with variable parameters or final default value, when using variable parameters __XXX__ in the GET URL)
815 // Example of variables: __DAY__, __MONTH__, __YEAR__, __MYCOMPANY_COUNTRY_ID__, __USER_ID__, ...
816 // We do this only if var is a GET. If it is a POST, may be we want to post the text with vars as the setup text.
817 if (!is_array($out) && empty($_POST[$paramname]) && empty($noreplace)) {
818 $reg = array();
819 $maxloop = 20;
820 $loopnb = 0; // Protection against infinite loop
821 while (preg_match('/__([A-Z0-9]+_?[A-Z0-9]+)__/i', $out, $reg) && ($loopnb < $maxloop)) { // Detect '__ABCDEF__' as key 'ABCDEF' and '__ABC_DEF__' as key 'ABC_DEF'. Detection is also correct when 2 vars are side by side.
822 $loopnb++;
823 $newout = '';
824
825 if ($reg[1] == 'DAY') {
826 $tmp = dol_getdate(dol_now(), true);
827 $newout = $tmp['mday'];
828 } elseif ($reg[1] == 'MONTH') {
829 $tmp = dol_getdate(dol_now(), true);
830 $newout = $tmp['mon'];
831 } elseif ($reg[1] == 'YEAR') {
832 $tmp = dol_getdate(dol_now(), true);
833 $newout = $tmp['year'];
834 } elseif ($reg[1] == 'PREVIOUS_DAY') {
835 $tmp = dol_getdate(dol_now(), true);
836 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
837 $newout = $tmp2['day'];
838 } elseif ($reg[1] == 'PREVIOUS_MONTH') {
839 $tmp = dol_getdate(dol_now(), true);
840 $tmp2 = dol_get_prev_month($tmp['mon'], $tmp['year']);
841 $newout = $tmp2['month'];
842 } elseif ($reg[1] == 'PREVIOUS_YEAR') {
843 $tmp = dol_getdate(dol_now(), true);
844 $newout = ($tmp['year'] - 1);
845 } elseif ($reg[1] == 'NEXT_DAY') {
846 $tmp = dol_getdate(dol_now(), true);
847 $tmp2 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
848 $newout = $tmp2['day'];
849 } elseif ($reg[1] == 'NEXT_MONTH') {
850 $tmp = dol_getdate(dol_now(), true);
851 $tmp2 = dol_get_next_month($tmp['mon'], $tmp['year']);
852 $newout = $tmp2['month'];
853 } elseif ($reg[1] == 'NEXT_YEAR') {
854 $tmp = dol_getdate(dol_now(), true);
855 $newout = ($tmp['year'] + 1);
856 } elseif ($reg[1] == 'MYCOMPANY_COUNTRY_ID' || $reg[1] == 'MYCOUNTRY_ID' || $reg[1] == 'MYCOUNTRYID') {
857 $newout = $mysoc->country_id;
858 } elseif ($reg[1] == 'USER_ID' || $reg[1] == 'USERID') {
859 $newout = $user->id;
860 } elseif ($reg[1] == 'USER_SUPERVISOR_ID' || $reg[1] == 'SUPERVISOR_ID' || $reg[1] == 'SUPERVISORID') {
861 $newout = $user->fk_user;
862 } elseif ($reg[1] == 'ENTITY_ID' || $reg[1] == 'ENTITYID') {
863 $newout = $conf->entity;
864 } else {
865 $newout = ''; // Key not found, we replace with empty string
866 }
867 //var_dump('__'.$reg[1].'__ -> '.$newout);
868 $out = preg_replace('/__'.preg_quote($reg[1], '/').'__/', $newout, $out);
869 }
870 }
871
872 // Check type of variable and make sanitization according to this
873 if (preg_match('/^array/', $check)) { // If 'array' or 'array:restricthtml' or 'array:aZ09' or 'array:intcomma'
874 if (!is_array($out) || empty($out)) {
875 $out = array();
876 } else {
877 $tmparray = explode(':', $check);
878 if (!empty($tmparray[1])) {
879 $tmpcheck = $tmparray[1];
880 } else {
881 $tmpcheck = 'alphanohtml';
882 }
883 foreach ($out as $outkey => $outval) {
884 $out[$outkey] = sanitizeVal($outval, $tmpcheck, $filter, $options);
885 }
886 }
887 } else {
888 // If field name is 'search_xxx' then we force the add of space after each < and > (when following char is numeric) because it means
889 // we use the < or > to make a search on a numeric value to do higher or lower so we can add a space to break html tags
890 if (strpos($paramname, 'search_') === 0) {
891 $out = preg_replace('/([<>])([-+]?\d)/', '\1 \2', $out);
892 }
893
894 $out = sanitizeVal($out, $check, $filter, $options);
895 }
896
897 // Sanitizing for special parameters.
898 // Note: There is no reason to allow the backtopage, backtolist or backtourl parameter to contains an external URL. Only relative URLs are allowed.
899 if ($paramname == 'backtopage' || $paramname == 'backtolist' || $paramname == 'backtourl') {
900 $out = str_replace('\\', '/', $out); // Can be before the loop because only 1 char is replaced. No risk to get it after other replacements.
901 $out = str_replace(array(':', ';', '@', "\t", ' '), '', $out); // Can be before the loop because only 1 char is replaced. No risk to retreive it after other replacements.
902 do {
903 $oldstringtoclean = $out;
904 $out = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $out);
905 $out = preg_replace(array('/^[^\?]*%/'), '', $out); // We remove any % chars before the ?. Example in url: '/product/stock/card.php?action=create&backtopage=%2Fdolibarr_dev%2Fhtdocs%2Fpro%25duct%2Fcard.php%3Fid%3Dabc'
906 $out = preg_replace(array('/^[a-z]*\/\s*\/+/i'), '', $out); // We remove schema*// to remove external URL
907 } while ($oldstringtoclean != $out);
908 }
909
910 // Code for search criteria persistence.
911 // Save data into session if key start with 'search_' or is 'smonth', 'syear', 'month', 'year'
912 if (empty($method) || $method == 3 || $method == 4) {
913 if (preg_match('/^search_/', $paramname) || in_array($paramname, array('sortorder', 'sortfield'))) {
914 //var_dump($paramname.' - '.$out.' '.$user->default_values[$relativepathstring]['filters'][$paramname]);
915
916 // We save search key only if $out not empty that means:
917 // - posted value not empty, or
918 // - if posted value is empty and a default value exists that is not empty (it means we did a filter to an empty value when default was not).
919
920 if ($out != '' && isset($user)) {// $out = '0' or 'abc', it is a search criteria to keep
921 $user->lastsearch_values_tmp[$relativepathstring][$paramname] = $out;
922 }
923 }
924 }
925
926 return $out;
927}
928
938function GETPOSTINT($paramname, $method = 0)
939{
940 return (int) GETPOST($paramname, 'int', $method, null, null, 0);
941}
942
943
954function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
955{
956 return sanitizeVal($out, $check, $filter, $options);
957}
958
968function sanitizeVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
969{
970 // TODO : use class "Validate" to perform tests (and add missing tests) if needed for factorize
971 // Check is done after replacement
972 switch ($check) {
973 case 'none':
974 break;
975 case 'int': // Check param is a numeric value (integer but also float or hexadecimal)
976 if (!is_numeric($out)) {
977 $out = '';
978 }
979 break;
980 case 'intcomma':
981 if (is_array($out)) {
982 $out = implode(',', $out);
983 }
984 if (preg_match('/[^0-9,-]+/i', $out)) {
985 $out = '';
986 }
987 break;
988 case 'san_alpha':
989 $out = filter_var($out, FILTER_SANITIZE_STRING);
990 break;
991 case 'email':
992 $out = filter_var($out, FILTER_SANITIZE_EMAIL);
993 break;
994 case 'aZ':
995 if (!is_array($out)) {
996 $out = trim($out);
997 if (preg_match('/[^a-z]+/i', $out)) {
998 $out = '';
999 }
1000 }
1001 break;
1002 case 'aZ09':
1003 if (!is_array($out)) {
1004 $out = trim($out);
1005 if (preg_match('/[^a-z0-9_\-\.]+/i', $out)) {
1006 $out = '';
1007 }
1008 }
1009 break;
1010 case 'aZ09arobase': // great to sanitize $objecttype parameter
1011 if (!is_array($out)) {
1012 $out = trim($out);
1013 if (preg_match('/[^a-z0-9_\-\.@]+/i', $out)) {
1014 $out = '';
1015 }
1016 }
1017 break;
1018 case 'aZ09comma': // great to sanitize $sortfield or $sortorder params that can be 't.abc,t.def_gh'
1019 if (!is_array($out)) {
1020 $out = trim($out);
1021 if (preg_match('/[^a-z0-9_\-\.,]+/i', $out)) {
1022 $out = '';
1023 }
1024 }
1025 break;
1026 case 'alpha': // No html and no ../ and "
1027 case 'alphanohtml': // Recommended for most scalar parameters and search parameters
1028 if (!is_array($out)) {
1029 $out = trim($out);
1030 do {
1031 $oldstringtoclean = $out;
1032 // Remove html tags
1033 $out = dol_string_nohtmltag($out, 0);
1034 // Remove also other dangerous string sequences
1035 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1036 // '../' or '..\' is dangerous because it allows dir transversals
1037 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1038 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1039 } while ($oldstringtoclean != $out);
1040 // keep lines feed
1041 }
1042 break;
1043 case 'alphawithlgt': // No " and no ../ but we keep balanced < > tags with no special chars inside. Can be used for email string like "Name <email>". Less secured than 'alphanohtml'
1044 if (!is_array($out)) {
1045 $out = trim($out);
1046 do {
1047 $oldstringtoclean = $out;
1048 // Remove html tags
1049 $out = dol_html_entity_decode($out, ENT_COMPAT | ENT_HTML5, 'UTF-8');
1050 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1051 // '../' or '..\' is dangerous because it allows dir transversals
1052 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1053 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1054 } while ($oldstringtoclean != $out);
1055 }
1056 break;
1057 case 'nohtml': // No html
1058 $out = dol_string_nohtmltag($out, 0);
1059 break;
1060 case 'restricthtmlnolink':
1061 case 'restricthtml': // Recommended for most html textarea
1062 case 'restricthtmlallowclass':
1063 case 'restricthtmlallowunvalid':
1064 $out = dol_htmlwithnojs($out, 1, $check);
1065 break;
1066 case 'custom':
1067 if (!empty($out)) {
1068 if (empty($filter)) {
1069 return 'BadParameterForGETPOST - Param 3 of sanitizeVal()';
1070 }
1071 /*if (empty($options)) {
1072 return 'BadParameterForGETPOST - Param 4 of sanitizeVal()';
1073 }*/
1074 $out = filter_var($out, $filter, $options);
1075 }
1076 break;
1077 default:
1078 dol_syslog("Error, you call sanitizeVal() with a bad value for the check type. Data can't be sanitized.", LOG_ERR);
1079 break;
1080 }
1081
1082 return $out;
1083}
1084
1085
1086if (!function_exists('dol_getprefix')) {
1096 function dol_getprefix($mode = '')
1097 {
1098 // If prefix is for email (we need to have $conf already loaded for this case)
1099 if ($mode == 'email') {
1100 global $conf;
1101
1102 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID')) { // If MAIL_PREFIX_FOR_EMAIL_ID is set
1103 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID') != 'SERVER_NAME') {
1104 return $conf->global->MAIL_PREFIX_FOR_EMAIL_ID;
1105 } elseif (isset($_SERVER["SERVER_NAME"])) { // If MAIL_PREFIX_FOR_EMAIL_ID is set to 'SERVER_NAME'
1106 return $_SERVER["SERVER_NAME"];
1107 }
1108 }
1109
1110 // The recommended value if MAIL_PREFIX_FOR_EMAIL_ID is not defined (may be not defined for old versions)
1111 if (!empty($conf->file->instance_unique_id)) {
1112 return sha1('dolibarr'.$conf->file->instance_unique_id);
1113 }
1114
1115 // For backward compatibility when instance_unique_id is not set
1116 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1117 }
1118
1119 // If prefix is for session (no need to have $conf loaded)
1120 global $dolibarr_main_instance_unique_id, $dolibarr_main_cookie_cryptkey; // This is loaded by filefunc.inc.php
1121 $tmp_instance_unique_id = empty($dolibarr_main_instance_unique_id) ? (empty($dolibarr_main_cookie_cryptkey) ? '' : $dolibarr_main_cookie_cryptkey) : $dolibarr_main_instance_unique_id; // Unique id of instance
1122
1123 // The recommended value (may be not defined for old versions)
1124 if (!empty($tmp_instance_unique_id)) {
1125 return sha1('dolibarr'.$tmp_instance_unique_id);
1126 }
1127
1128 // For backward compatibility when instance_unique_id is not set
1129 if (isset($_SERVER["SERVER_NAME"]) && isset($_SERVER["DOCUMENT_ROOT"])) {
1130 return sha1($_SERVER["SERVER_NAME"].$_SERVER["DOCUMENT_ROOT"].DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1131 } else {
1132 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1133 }
1134 }
1135}
1136
1147function dol_include_once($relpath, $classname = '')
1148{
1149 global $conf, $langs, $user, $mysoc; // Do not remove this. They must be defined for files we include. Other globals var must be retrieved with $GLOBALS['var']
1150
1151 $fullpath = dol_buildpath($relpath);
1152
1153 if (!file_exists($fullpath)) {
1154 dol_syslog('functions::dol_include_once Tried to load unexisting file: '.$relpath, LOG_WARNING);
1155 return false;
1156 }
1157
1158 if (!empty($classname) && !class_exists($classname)) {
1159 return include $fullpath;
1160 } else {
1161 return include_once $fullpath;
1162 }
1163}
1164
1165
1176function dol_buildpath($path, $type = 0, $returnemptyifnotfound = 0)
1177{
1178 global $conf;
1179
1180 $path = preg_replace('/^\//', '', $path);
1181
1182 if (empty($type)) { // For a filesystem path
1183 $res = DOL_DOCUMENT_ROOT.'/'.$path; // Standard default path
1184 if (is_array($conf->file->dol_document_root)) {
1185 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array("main"=>"/home/main/htdocs", "alt0"=>"/home/dirmod/htdocs", ...)
1186 if ($key == 'main') {
1187 continue;
1188 }
1189 // if (@file_exists($dirroot.'/'.$path)) {
1190 if (@file_exists($dirroot.'/'.$path)) { // avoid [php:warn]
1191 $res = $dirroot.'/'.$path;
1192 return $res;
1193 }
1194 }
1195 }
1196 if ($returnemptyifnotfound) {
1197 // Not found into alternate dir
1198 if ($returnemptyifnotfound == 1 || !file_exists($res)) {
1199 return '';
1200 }
1201 }
1202 } else {
1203 // For an url path
1204 // We try to get local path of file on filesystem from url
1205 // Note that trying to know if a file on disk exist by forging path on disk from url
1206 // works only for some web server and some setup. This is bugged when
1207 // using proxy, rewriting, virtual path, etc...
1208 $res = '';
1209 if ($type == 1) {
1210 $res = DOL_URL_ROOT.'/'.$path; // Standard value
1211 }
1212 if ($type == 2) {
1213 $res = DOL_MAIN_URL_ROOT.'/'.$path; // Standard value
1214 }
1215 if ($type == 3) {
1216 $res = DOL_URL_ROOT.'/'.$path;
1217 }
1218
1219 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array(["main"]=>"/home/main/htdocs", ["alt0"]=>"/home/dirmod/htdocs", ...)
1220 if ($key == 'main') {
1221 if ($type == 3) {
1222 /*global $dolibarr_main_url_root;*/
1223
1224 // Define $urlwithroot
1225 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1226 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1227 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1228
1229 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).'/'.$path; // Test on start with http is for old conf syntax
1230 }
1231 continue;
1232 }
1233 $regs = array();
1234 preg_match('/^([^\?]+(\.css\.php|\.css|\.js\.php|\.js|\.png|\.jpg|\.php)?)/i', $path, $regs); // Take part before '?'
1235 if (!empty($regs[1])) {
1236 //print $key.'-'.$dirroot.'/'.$path.'-'.$conf->file->dol_url_root[$type].'<br>'."\n";
1237 //if (file_exists($dirroot.'/'.$regs[1])) {
1238 if (@file_exists($dirroot.'/'.$regs[1])) { // avoid [php:warn]
1239 if ($type == 1) {
1240 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1241 }
1242 if ($type == 2) {
1243 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_MAIN_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1244 }
1245 if ($type == 3) {
1246 /*global $dolibarr_main_url_root;*/
1247
1248 // Define $urlwithroot
1249 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1250 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1251 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1252
1253 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).$conf->file->dol_url_root[$key].'/'.$path; // Test on start with http is for old conf syntax
1254 }
1255 break;
1256 }
1257 }
1258 }
1259 }
1260
1261 return $res;
1262}
1263
1275function dol_clone($object, $native = 0)
1276{
1277 if ($native == 0) {
1278 // deprecated method, use the method with native = 2 instead
1279 $tmpsavdb = null;
1280 if (isset($object->db) && isset($object->db->db) && is_object($object->db->db) && get_class($object->db->db) == 'PgSql\Connection') {
1281 $tmpsavdb = $object->db;
1282 unset($object->db); // Such property can not be serialized with pgsl (when object->db->db = 'PgSql\Connection')
1283 }
1284
1285 $myclone = unserialize(serialize($object)); // serialize then unserialize is a hack to be sure to have a new object for all fields
1286
1287 if (!empty($tmpsavdb)) {
1288 $object->db = $tmpsavdb;
1289 }
1290 } elseif ($native == 2) {
1291 // recommended method to have a full isolated cloned object
1292 $myclone = new stdClass();
1293 $tmparray = get_object_vars($object); // return only public properties
1294
1295 if (is_array($tmparray)) {
1296 foreach ($tmparray as $propertykey => $propertyval) {
1297 if (is_scalar($propertyval) || is_array($propertyval)) {
1298 $myclone->$propertykey = $propertyval;
1299 }
1300 }
1301 }
1302 } else {
1303 $myclone = clone $object; // PHP clone is a shallow copy only, not a real clone, so properties of references will keep the reference (refering to the same target/variable)
1304 }
1305
1306 return $myclone;
1307}
1308
1318function dol_size($size, $type = '')
1319{
1320 global $conf;
1321 if (empty($conf->dol_optimize_smallscreen)) {
1322 return $size;
1323 }
1324 if ($type == 'width' && $size > 250) {
1325 return 250;
1326 } else {
1327 return 10;
1328 }
1329}
1330
1331
1343function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1)
1344{
1345 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1346 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1347 // Char '/' and '\' are file delimiters.
1348 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1349 $filesystem_forbidden_chars = array('<', '>', '/', '\\', '?', '*', '|', '"', ':', '°', '$', ';', '`');
1350 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1351 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1352 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1353 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1354 $tmp = str_replace('..', '', $tmp);
1355 return $tmp;
1356}
1357
1369function dol_sanitizePathName($str, $newstr = '_', $unaccent = 1)
1370{
1371 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1372 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1373 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1374 $filesystem_forbidden_chars = array('<', '>', '?', '*', '|', '"', '°', '$', ';', '`');
1375 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1376 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1377 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1378 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1379 $tmp = str_replace('..', '', $tmp);
1380 return $tmp;
1381}
1382
1390function dol_sanitizeUrl($stringtoclean, $type = 1)
1391{
1392 // We clean string because some hacks try to obfuscate evil strings by inserting non printable chars. Example: 'java(ascci09)scr(ascii00)ipt' is processed like 'javascript' (whatever is place of evil ascii char)
1393 // We should use dol_string_nounprintableascii but function may not be yet loaded/available
1394 $stringtoclean = preg_replace('/[\x00-\x1F\x7F]/u', '', $stringtoclean); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1395 // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: on<!-- -->error=alert(1)
1396 $stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
1397
1398 $stringtoclean = str_replace('\\', '/', $stringtoclean);
1399 if ($type == 1) {
1400 // removing : should disable links to external url like http:aaa)
1401 // removing ';' should disable "named" html entities encode into an url (we should not have this into an url)
1402 $stringtoclean = str_replace(array(':', ';', '@'), '', $stringtoclean);
1403 }
1404
1405 do {
1406 $oldstringtoclean = $stringtoclean;
1407 // removing '&colon' should disable links to external url like http:aaa)
1408 // removing '&#' should disable "numeric" html entities encode into an url (we should not have this into an url)
1409 $stringtoclean = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $stringtoclean);
1410 } while ($oldstringtoclean != $stringtoclean);
1411
1412 if ($type == 1) {
1413 // removing '//' should disable links to external url like //aaa or http//)
1414 $stringtoclean = preg_replace(array('/^[a-z]*\/\/+/i'), '', $stringtoclean);
1415 }
1416
1417 return $stringtoclean;
1418}
1419
1426function dol_sanitizeEmail($stringtoclean)
1427{
1428 do {
1429 $oldstringtoclean = $stringtoclean;
1430 $stringtoclean = str_ireplace(array('"', ':', '[', ']',"\n", "\r", '\\', '\/'), '', $stringtoclean);
1431 } while ($oldstringtoclean != $stringtoclean);
1432
1433 return $stringtoclean;
1434}
1435
1445{
1446 global $conf;
1447
1448 if (is_null($str)) {
1449 return '';
1450 }
1451
1452 if (utf8_check($str)) {
1453 if (extension_loaded('intl') && getDolGlobalString('MAIN_UNACCENT_USE_TRANSLITERATOR')) {
1454 $transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: NFC;', Transliterator::FORWARD);
1455 return $transliterator->transliterate($str);
1456 }
1457 // See http://www.utf8-chartable.de/
1458 $string = rawurlencode($str);
1459 $replacements = array(
1460 '%C3%80' => 'A', '%C3%81' => 'A', '%C3%82' => 'A', '%C3%83' => 'A', '%C3%84' => 'A', '%C3%85' => 'A',
1461 '%C3%87' => 'C',
1462 '%C3%88' => 'E', '%C3%89' => 'E', '%C3%8A' => 'E', '%C3%8B' => 'E',
1463 '%C3%8C' => 'I', '%C3%8D' => 'I', '%C3%8E' => 'I', '%C3%8F' => 'I',
1464 '%C3%91' => 'N',
1465 '%C3%92' => 'O', '%C3%93' => 'O', '%C3%94' => 'O', '%C3%95' => 'O', '%C3%96' => 'O',
1466 '%C5%A0' => 'S',
1467 '%C3%99' => 'U', '%C3%9A' => 'U', '%C3%9B' => 'U', '%C3%9C' => 'U',
1468 '%C3%9D' => 'Y', '%C5%B8' => 'y',
1469 '%C3%A0' => 'a', '%C3%A1' => 'a', '%C3%A2' => 'a', '%C3%A3' => 'a', '%C3%A4' => 'a', '%C3%A5' => 'a',
1470 '%C3%A7' => 'c',
1471 '%C3%A8' => 'e', '%C3%A9' => 'e', '%C3%AA' => 'e', '%C3%AB' => 'e',
1472 '%C3%AC' => 'i', '%C3%AD' => 'i', '%C3%AE' => 'i', '%C3%AF' => 'i',
1473 '%C3%B1' => 'n',
1474 '%C3%B2' => 'o', '%C3%B3' => 'o', '%C3%B4' => 'o', '%C3%B5' => 'o', '%C3%B6' => 'o',
1475 '%C5%A1' => 's',
1476 '%C3%B9' => 'u', '%C3%BA' => 'u', '%C3%BB' => 'u', '%C3%BC' => 'u',
1477 '%C3%BD' => 'y', '%C3%BF' => 'y'
1478 );
1479 $string = strtr($string, $replacements);
1480 return rawurldecode($string);
1481 } else {
1482 // See http://www.ascii-code.com/
1483 $string = strtr(
1484 $str,
1485 "\xC0\xC1\xC2\xC3\xC4\xC5\xC7
1486 \xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1
1487 \xD2\xD3\xD4\xD5\xD8\xD9\xDA\xDB\xDD
1488 \xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB
1489 \xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF8
1490 \xF9\xFA\xFB\xFC\xFD\xFF",
1491 "AAAAAAC
1492 EEEEIIIIDN
1493 OOOOOUUUY
1494 aaaaaaceeee
1495 iiiidnooooo
1496 uuuuyy"
1497 );
1498 $string = strtr($string, array("\xC4"=>"Ae", "\xC6"=>"AE", "\xD6"=>"Oe", "\xDC"=>"Ue", "\xDE"=>"TH", "\xDF"=>"ss", "\xE4"=>"ae", "\xE6"=>"ae", "\xF6"=>"oe", "\xFC"=>"ue", "\xFE"=>"th"));
1499 return $string;
1500 }
1501}
1502
1516function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '', $badcharstoremove = '', $keepspaces = 0)
1517{
1518 $forbidden_chars_to_replace = array("'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=", '°', '$', ';'); // more complete than dol_sanitizeFileName
1519 if (empty($keepspaces)) {
1520 $forbidden_chars_to_replace[] = " ";
1521 }
1522 $forbidden_chars_to_remove = array();
1523 //$forbidden_chars_to_remove=array("(",")");
1524
1525 if (is_array($badcharstoreplace)) {
1526 $forbidden_chars_to_replace = $badcharstoreplace;
1527 }
1528 if (is_array($badcharstoremove)) {
1529 $forbidden_chars_to_remove = $badcharstoremove;
1530 }
1531
1532 return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str));
1533}
1534
1535
1549function dol_string_nounprintableascii($str, $removetabcrlf = 1)
1550{
1551 if ($removetabcrlf) {
1552 return preg_replace('/[\x00-\x1F\x7F]/u', '', $str); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1553 } else {
1554 return preg_replace('/[\x00-\x08\x11-\x12\x14-\x1F\x7F]/u', '', $str); // /u operator should make UTF8 valid characters being ignored so are not included into the replace
1555 }
1556}
1557
1566function dol_escape_js($stringtoescape, $mode = 0, $noescapebackslashn = 0)
1567{
1568 if (is_null($stringtoescape)) {
1569 return '';
1570 }
1571
1572 // escape quotes and backslashes, newlines, etc.
1573 $substitjs = array("&#039;"=>"\\'", "\r"=>'\\r');
1574 //$substitjs['</']='<\/'; // We removed this. Should be useless.
1575 if (empty($noescapebackslashn)) {
1576 $substitjs["\n"] = '\\n';
1577 $substitjs['\\'] = '\\\\';
1578 }
1579 if (empty($mode)) {
1580 $substitjs["'"] = "\\'";
1581 $substitjs['"'] = "\\'";
1582 } elseif ($mode == 1) {
1583 $substitjs["'"] = "\\'";
1584 } elseif ($mode == 2) {
1585 $substitjs['"'] = '\\"';
1586 } elseif ($mode == 3) {
1587 $substitjs["'"] = "\\'";
1588 $substitjs['"'] = "\\\"";
1589 }
1590 return strtr($stringtoescape, $substitjs);
1591}
1592
1599function dol_escape_json($stringtoescape)
1600{
1601 return str_replace('"', '\"', $stringtoescape);
1602}
1603
1611function dol_escape_php($stringtoescape, $stringforquotes = 2)
1612{
1613 if (is_null($stringtoescape)) {
1614 return '';
1615 }
1616
1617 if ($stringforquotes == 2) {
1618 return str_replace('"', "'", $stringtoescape);
1619 }
1620 if ($stringforquotes == 1) {
1621 return str_replace("'", "\'", str_replace('"', "'", $stringtoescape));
1622 }
1623
1624 return 'Bad parameter for stringforquotes in dol_escape_php';
1625}
1626
1633function dol_escape_all($stringtoescape)
1634{
1635 return preg_replace('/[^a-z0-9_]/i', '', $stringtoescape);
1636}
1637
1644function dol_escape_xml($stringtoescape)
1645{
1646 return $stringtoescape;
1647}
1648
1656function dolPrintLabel($s)
1657{
1659}
1660
1669function dolPrintHTML($s, $allowiframe = 0)
1670{
1671 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, 'common', 0, 1);
1672}
1673
1681{
1682 // The dol_htmlentitiesbr will convert simple text into html
1683 // The dol_escape_htmltag will escape html chars.
1684 return dol_escape_htmltag(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 0, 0, 0, array('br', 'b', 'font', 'span')), 1, -1, '', 0, 1);
1685}
1686
1695function dolPrintHTMLForTextArea($s, $allowiframe = 0)
1696{
1697 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, '', 0, 1);
1698}
1699
1707{
1708 return htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
1709}
1710
1711
1728function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapetags = '', $escapeonlyhtmltags = 0, $cleanalsojavascript = 0)
1729{
1730 if ($noescapetags == 'common') {
1731 $noescapetags = 'html,body,a,b,em,hr,i,u,ul,li,br,div,img,font,p,span,strong,table,tr,td,th,tbody,h1,h2,h3,h4,h5,h6,h7,h8,h9';
1732 // Add also html5 tags
1733 $noescapetags .= ',header,footer,nav,section,menu,menuitem';
1734 }
1735 if ($cleanalsojavascript) {
1736 $stringtoescape = dol_string_onlythesehtmltags($stringtoescape, 0, 0, $cleanalsojavascript, 0, array(), 0);
1737 }
1738
1739 // escape quotes and backslashes, newlines, etc.
1740 if ($escapeonlyhtmltags) {
1741 $tmp = htmlspecialchars_decode((string) $stringtoescape, ENT_COMPAT);
1742 } else {
1743 $tmp = html_entity_decode((string) $stringtoescape, ENT_COMPAT, 'UTF-8');
1744 }
1745 if (!$keepb) {
1746 $tmp = strtr($tmp, array("<b>"=>'', '</b>'=>'', '<strong>'=>'', '</strong>'=>''));
1747 }
1748 if (!$keepn) {
1749 $tmp = strtr($tmp, array("\r"=>'\\r', "\n"=>'\\n'));
1750 } elseif ($keepn == -1) {
1751 $tmp = strtr($tmp, array("\r"=>'', "\n"=>''));
1752 }
1753
1754 if ($escapeonlyhtmltags) {
1755 return htmlspecialchars($tmp, ENT_COMPAT, 'UTF-8');
1756 } else {
1757 // Escape tags to keep
1758 $tmparrayoftags = array();
1759 if ($noescapetags) {
1760 $tmparrayoftags = explode(',', $noescapetags);
1761 }
1762 if (count($tmparrayoftags)) {
1763 // TODO Does not works yet when there is attributes into tag
1764 foreach ($tmparrayoftags as $tagtoreplace) {
1765 $tmp = str_ireplace('<'.$tagtoreplace.'>', '__BEGINTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1766 $tmp = str_ireplace('</'.$tagtoreplace.'>', '__ENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1767 $tmp = str_ireplace('<'.$tagtoreplace.' />', '__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1768 }
1769 }
1770
1771 $result = htmlentities($tmp, ENT_COMPAT, 'UTF-8');
1772
1773 if (count($tmparrayoftags)) {
1774 foreach ($tmparrayoftags as $tagtoreplace) {
1775 $result = str_ireplace('__BEGINTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.'>', $result);
1776 $result = str_ireplace('__ENDTAGTOREPLACE'.$tagtoreplace.'__', '</'.$tagtoreplace.'>', $result);
1777 $result = str_ireplace('__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.' />', $result);
1778 }
1779 }
1780
1781 return $result;
1782 }
1783}
1784
1792function dol_strtolower($string, $encoding = "UTF-8")
1793{
1794 if (function_exists('mb_strtolower')) {
1795 return mb_strtolower($string, $encoding);
1796 } else {
1797 return strtolower($string);
1798 }
1799}
1800
1809function dol_strtoupper($string, $encoding = "UTF-8")
1810{
1811 if (function_exists('mb_strtoupper')) {
1812 return mb_strtoupper($string, $encoding);
1813 } else {
1814 return strtoupper($string);
1815 }
1816}
1817
1826function dol_ucfirst($string, $encoding = "UTF-8")
1827{
1828 if (function_exists('mb_substr')) {
1829 return mb_strtoupper(mb_substr($string, 0, 1, $encoding), $encoding).mb_substr($string, 1, null, $encoding);
1830 } else {
1831 return ucfirst($string);
1832 }
1833}
1834
1843function dol_ucwords($string, $encoding = "UTF-8")
1844{
1845 if (function_exists('mb_convert_case')) {
1846 return mb_convert_case($string, MB_CASE_TITLE, $encoding);
1847 } else {
1848 return ucwords($string);
1849 }
1850}
1851
1873function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = '', $restricttologhandler = '', $logcontext = null)
1874{
1875 global $conf, $user, $debugbar;
1876
1877 // If syslog module enabled
1878 if (!isModEnabled('syslog')) {
1879 return;
1880 }
1881
1882 // Check if we are into execution of code of a website
1883 if (defined('USEEXTERNALSERVER') && !defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) {
1884 global $website, $websitekey;
1885 if (is_object($website) && !empty($website->ref)) {
1886 $suffixinfilename .= '_website_'.$website->ref;
1887 } elseif (!empty($websitekey)) {
1888 $suffixinfilename .= '_website_'.$websitekey;
1889 }
1890 }
1891
1892 // Check if we have a forced suffix
1893 if (defined('USESUFFIXINLOG')) {
1894 $suffixinfilename .= constant('USESUFFIXINLOG');
1895 }
1896
1897 if ($ident < 0) {
1898 foreach ($conf->loghandlers as $loghandlerinstance) {
1899 $loghandlerinstance->setIdent($ident);
1900 }
1901 }
1902
1903 if (!empty($message)) {
1904 // Test log level
1905 $logLevels = array(LOG_EMERG=>'EMERG', LOG_ALERT=>'ALERT', LOG_CRIT=>'CRITICAL', LOG_ERR=>'ERR', LOG_WARNING=>'WARN', LOG_NOTICE=>'NOTICE', LOG_INFO=>'INFO', LOG_DEBUG=>'DEBUG');
1906 if (!array_key_exists($level, $logLevels)) {
1907 throw new Exception('Incorrect log level');
1908 }
1909 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
1910 return;
1911 }
1912
1913 if (!getDolGlobalString('MAIN_SHOW_PASSWORD_INTO_LOG')) {
1914 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
1915 }
1916
1917 // If adding log inside HTML page is required
1918 if ((!empty($_REQUEST['logtohtml']) && getDolGlobalString('MAIN_ENABLE_LOG_TO_HTML'))
1919 || (is_object($user) && $user->hasRight('debugbar', 'read') && is_object($debugbar))) {
1920 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".$logLevels[$level]." ".$message;
1921 }
1922
1923 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
1924 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
1925 if (getDolGlobalString('MAIN_ENABLE_LOG_INLINE_HTML') && !empty($_GET["log"])) {
1926 print "\n\n<!-- Log start\n";
1927 print dol_escape_htmltag($message)."\n";
1928 print "Log end -->\n";
1929 }
1930
1931 $data = array(
1932 'message' => $message,
1933 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
1934 'level' => $level,
1935 'user' => ((is_object($user) && $user->id) ? $user->login : false),
1936 'ip' => false
1937 );
1938
1939 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
1940 if (!empty($remoteip)) {
1941 $data['ip'] = $remoteip;
1942 // This is when server run behind a reverse proxy
1943 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
1944 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
1945 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
1946 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
1947 }
1948 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
1949 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
1950 $data['ip'] = $_SERVER['SERVER_ADDR'];
1951 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
1952 // This is when PHP session is ran outside a web server, like from Windows command line (Not always defined, but useful if OS defined it).
1953 $data['ip'] = $_SERVER['COMPUTERNAME'].(empty($_SERVER['USERNAME']) ? '' : '@'.$_SERVER['USERNAME']);
1954 } elseif (!empty($_SERVER['LOGNAME'])) {
1955 // This is when PHP session is ran outside a web server, like from Linux command line (Not always defined, but usefull if OS defined it).
1956 $data['ip'] = '???@'.$_SERVER['LOGNAME'];
1957 }
1958
1959 // Loop on each log handler and send output
1960 foreach ($conf->loghandlers as $loghandlerinstance) {
1961 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
1962 continue;
1963 }
1964 $loghandlerinstance->export($data, $suffixinfilename);
1965 }
1966 unset($data);
1967 }
1968
1969 if ($ident > 0) {
1970 foreach ($conf->loghandlers as $loghandlerinstance) {
1971 $loghandlerinstance->setIdent($ident);
1972 }
1973 }
1974}
1975
1992function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
1993{
1994 global $conf;
1995
1996 if (strpos($url, '?') > 0) {
1997 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1998 } else {
1999 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2000 }
2001
2002 $out = '';
2003
2004 $backtopagejsfieldsid = '';
2005 $backtopagejsfieldslabel = '';
2006 if ($backtopagejsfields) {
2007 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
2008 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
2009 $backtopagejsfields = $name.":".$backtopagejsfields;
2010 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
2011 } else {
2012 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
2013 }
2014 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
2015 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
2016 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
2017 }
2018
2019 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
2020 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
2021 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
2022 if (empty($conf->use_javascript_ajax)) {
2023 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
2024 } elseif ($jsonopen) {
2025 $out .= ' href="#" onclick="'.$jsonopen.'"';
2026 } else {
2027 $out .= ' href="#"';
2028 }
2029 $out .= '>'.$buttonstring.'</a>';
2030
2031 if (!empty($conf->use_javascript_ajax)) {
2032 // Add code to open url using the popup. Add also hidden field to retreive the returned variables
2033 $out .= '<!-- code to open popup and variables to retreive returned variables -->';
2034 $out .= '<div id="idfordialog'.$name.'" class="hidden">div for dialog</div>';
2035 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">div for returned id</div>';
2036 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">div for returned label</div>';
2037 $out .= '<!-- Add js code to open dialog popup on dialog -->';
2038 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
2039 jQuery(document).ready(function () {
2040 jQuery(".button_'.$name.'").click(function () {
2041 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
2042 var $tmpdialog = $(\'#idfordialog'.$name.'\');
2043 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
2044 $tmpdialog.dialog({
2045 autoOpen: false,
2046 modal: true,
2047 height: (window.innerHeight - 150),
2048 width: \'80%\',
2049 title: \''.dol_escape_js($label).'\',
2050 open: function (event, ui) {
2051 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
2052 },
2053 close: function (event, ui) {
2054 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
2055 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
2056 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
2057 if (returnedid != "" && returnedid != "div for returned id") {
2058 jQuery("#'.(empty($backtopagejsfieldsid) ? "none" : $backtopagejsfieldsid).'").val(returnedid);
2059 }
2060 if (returnedlabel != "" && returnedlabel != "div for returned label") {
2061 jQuery("#'.(empty($backtopagejsfieldslabel) ? "none" : $backtopagejsfieldslabel).'").val(returnedlabel);
2062 }
2063 }
2064 });
2065
2066 $tmpdialog.dialog(\'open\');
2067 return false;
2068 });
2069 });
2070 </script>';
2071 }
2072 return $out;
2073}
2074
2091function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2092{
2093 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2094}
2095
2112function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2113{
2114 global $conf, $langs, $hookmanager;
2115
2116 // Show title
2117 $showtitle = 1;
2118 if (!empty($conf->dol_optimize_smallscreen)) {
2119 $showtitle = 0;
2120 }
2121
2122 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2123
2124 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2125 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2126 }
2127
2128 // Show right part
2129 if ($morehtmlright) {
2130 $out .= '<div class="inline-block floatright tabsElem">'.$morehtmlright.'</div>'; // Output right area first so when space is missing, text is in front of tabs and not under.
2131 }
2132
2133 // Show title
2134 if (!empty($title) && $showtitle && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2135 $limittitle = 30;
2136 $out .= '<a class="tabTitle">';
2137 if ($picto) {
2138 $noprefix = $pictoisfullpath;
2139 if (strpos($picto, 'fontawesome_') !== false) {
2140 $noprefix = 1;
2141 }
2142 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2143 }
2144 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2145 $out .= '</a>';
2146 }
2147
2148 // Show tabs
2149
2150 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2151 $maxkey = -1;
2152 if (is_array($links) && !empty($links)) {
2153 $keys = array_keys($links);
2154 if (count($keys)) {
2155 $maxkey = max($keys);
2156 }
2157 }
2158
2159 // Show tabs
2160 // if =0 we don't use the feature
2161 if (empty($limittoshow)) {
2162 $limittoshow = (!getDolGlobalString('MAIN_MAXTABS_IN_CARD') ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2163 }
2164 if (!empty($conf->dol_optimize_smallscreen)) {
2165 $limittoshow = 2;
2166 }
2167
2168 $displaytab = 0;
2169 $nbintab = 0;
2170 $popuptab = 0;
2171 $outmore = '';
2172 for ($i = 0; $i <= $maxkey; $i++) {
2173 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2174 // If active tab is already present
2175 if ($i >= $limittoshow) {
2176 $limittoshow--;
2177 }
2178 }
2179 }
2180
2181 for ($i = 0; $i <= $maxkey; $i++) {
2182 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2183 $isactive = true;
2184 } else {
2185 $isactive = false;
2186 }
2187
2188 if ($i < $limittoshow || $isactive) {
2189 // Output entry with a visible tab
2190 $out .= '<div class="inline-block tabsElem'.($isactive ? ' tabsElemActive' : '').((!$isactive && getDolGlobalString('MAIN_HIDE_INACTIVETAB_ON_PRINT')) ? ' hideonprint' : '').'"><!-- id tab = '.(empty($links[$i][2]) ? '' : dol_escape_htmltag($links[$i][2])).' -->';
2191
2192 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2193 if (!empty($links[$i][0])) {
2194 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2195 } else {
2196 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2197 }
2198 } elseif (!empty($links[$i][1])) {
2199 //print "x $i $active ".$links[$i][2]." z";
2200 $out .= '<div class="tab tab'.($isactive ? 'active' : 'unactive').'" style="margin: 0 !important">';
2201 if (!empty($links[$i][0])) {
2202 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2203 $out .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="tab inline-block valignmiddle'.($morecss ? ' '.$morecss : '').(!empty($links[$i][5]) ? ' '.$links[$i][5] : '').'" href="'.$links[$i][0].'" title="'.dol_escape_htmltag($titletoshow).'">';
2204 }
2205 $out .= $links[$i][1];
2206 if (!empty($links[$i][0])) {
2207 $out .= '</a>'."\n";
2208 }
2209 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2210 $out .= '</div>';
2211 }
2212
2213 $out .= '</div>';
2214 } else {
2215 // Add entry into the combo popup with the other tabs
2216 if (!$popuptab) {
2217 $popuptab = 1;
2218 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2219 }
2220 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2221 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2222 if (!empty($links[$i][0])) {
2223 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2224 } else {
2225 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2226 }
2227 } elseif (!empty($links[$i][1])) {
2228 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2229 $outmore .= preg_replace('/([a-z])\|([a-z])/i', '\\1 | \\2', $links[$i][1]); // Replace x|y with x | y to allow wrap on long composed texts.
2230 $outmore .= '</a>'."\n";
2231 }
2232 $outmore .= '</div>';
2233
2234 $nbintab++;
2235 }
2236 $displaytab = $i;
2237 }
2238 if ($popuptab) {
2239 $outmore .= '</div>';
2240 }
2241
2242 if ($popuptab) { // If there is some tabs not shown
2243 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2244 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2245 $widthofpopup = 200;
2246
2247 $tabsname = $moretabssuffix;
2248 if (empty($tabsname)) {
2249 $tabsname = str_replace("@", "", $picto);
2250 }
2251 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2252 $out .= '<div class="tab valignmiddle"><a href="#" class="tab moretab inline-block tabunactive valignmiddle"><span class="hideonsmartphone">'.$langs->trans("More").'</span>... ('.$nbintab.')</a></div>'; // Do not use "reposition" class in the "More".
2253 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2254 $out .= $outmore;
2255 $out .= '</div>';
2256 $out .= '<div></div>';
2257 $out .= "</div>\n";
2258
2259 $out .= '<script nonce="'.getNonce().'">';
2260 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2261 var x = this.offsetLeft, y = this.offsetTop;
2262 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2263 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2264 $('#moretabsList".$tabsname."').css('".$right."','8px');
2265 }
2266 $('#moretabsList".$tabsname."').css('".$left."','auto');
2267 });
2268 ";
2269 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2270 $out .= "</script>";
2271 }
2272
2273 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2274 $out .= "</div>\n";
2275 }
2276
2277 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2278 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom'))).'">'."\n";
2279 }
2280 if (!empty($dragdropfile)) {
2281 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2282 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2283 }
2284 $parameters = array('tabname' => $active, 'out' => $out);
2285 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2286 if ($reshook > 0) {
2287 $out = $hookmanager->resPrint;
2288 }
2289
2290 return $out;
2291}
2292
2300function dol_fiche_end($notab = 0)
2301{
2302 print dol_get_fiche_end($notab);
2303}
2304
2311function dol_get_fiche_end($notab = 0)
2312{
2313 if (!$notab || $notab == -1) {
2314 return "\n</div>\n";
2315 } else {
2316 return '';
2317 }
2318}
2319
2339function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2340{
2341 global $conf, $form, $user, $langs, $hookmanager, $action;
2342
2343 $error = 0;
2344
2345 $maxvisiblephotos = 1;
2346 $showimage = 1;
2347 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2348 $showbarcode = empty($conf->barcode->enabled) ? 0 : (empty($object->barcode) ? 0 : 1);
2349 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2350 $showbarcode = 0;
2351 }
2352 $modulepart = 'unknown';
2353
2354 if ($object->element == 'societe' || $object->element == 'contact' || $object->element == 'product' || $object->element == 'ticket') {
2355 $modulepart = $object->element;
2356 } elseif ($object->element == 'member') {
2357 $modulepart = 'memberphoto';
2358 } elseif ($object->element == 'user') {
2359 $modulepart = 'userphoto';
2360 }
2361
2362 if (class_exists("Imagick")) {
2363 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2364 $modulepart = $object->element;
2365 } elseif ($object->element == 'fichinter') {
2366 $modulepart = 'ficheinter';
2367 } elseif ($object->element == 'contrat') {
2368 $modulepart = 'contract';
2369 } elseif ($object->element == 'order_supplier') {
2370 $modulepart = 'supplier_order';
2371 } elseif ($object->element == 'invoice_supplier') {
2372 $modulepart = 'supplier_invoice';
2373 }
2374 }
2375
2376 if ($object->element == 'product') {
2377 $width = 80;
2378 $cssclass = 'photowithmargin photoref';
2379 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2380 $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : 5);
2381 if ($conf->browser->layout == 'phone') {
2382 $maxvisiblephotos = 1;
2383 }
2384 if ($showimage) {
2385 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$object->show_photos('product', $conf->product->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, 0, $width, 0, '').'</div>';
2386 } else {
2387 if (getDolGlobalString('PRODUCT_NODISPLAYIFNOPHOTO')) {
2388 $nophoto = '';
2389 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2390 } else { // Show no photo link
2391 $nophoto = '/public/theme/common/nophoto.png';
2392 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" title="'.dol_escape_htmltag($langs->trans("UploadAnImageToSeeAPhotoHere", $langs->transnoentitiesnoconv("Documents"))).'" alt="No photo"'.($width ? ' style="width: '.$width.'px"' : '').' src="'.DOL_URL_ROOT.$nophoto.'"></div>';
2393 }
2394 }
2395 } elseif ($object->element == 'ticket') {
2396 $width = 80;
2397 $cssclass = 'photoref';
2398 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2399 $maxvisiblephotos = (isset($conf->global->TICKET_MAX_VISIBLE_PHOTO) ? $conf->global->TICKET_MAX_VISIBLE_PHOTO : 2);
2400 if ($conf->browser->layout == 'phone') {
2401 $maxvisiblephotos = 1;
2402 }
2403
2404 if ($showimage) {
2405 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2406 if ($object->nbphoto > 0) {
2407 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2408 } else {
2409 $showimage = 0;
2410 }
2411 }
2412 if (!$showimage) {
2413 if (getDolGlobalString('TICKET_NODISPLAYIFNOPHOTO')) {
2414 $nophoto = '';
2415 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2416 } else { // Show no photo link
2417 $nophoto = img_picto('No photo', 'object_ticket');
2418 $morehtmlleft .= '<!-- No photo to show -->';
2419 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2420 $morehtmlleft .= $nophoto;
2421 $morehtmlleft .= '</div></div>';
2422 }
2423 }
2424 } else {
2425 if ($showimage) {
2426 if ($modulepart != 'unknown') {
2427 $phototoshow = '';
2428 // Check if a preview file is available
2429 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2430 $objectref = dol_sanitizeFileName($object->ref);
2431 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2432 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2433 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2434 $subdir .= ((!empty($subdir) && !preg_match('/\/$/', $subdir)) ? '/' : '').$objectref; // the objectref dir is not included into get_exdir when used with level=2, so we add it at end
2435 } else {
2436 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2437 }
2438 if (empty($subdir)) {
2439 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2440 }
2441
2442 $filepath = $dir_output.$subdir."/";
2443
2444 $filepdf = $filepath.$objectref.".pdf";
2445 $relativepath = $subdir.'/'.$objectref.'.pdf';
2446
2447 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2448 $fileimage = $filepdf.'_preview.png';
2449 $relativepathimage = $relativepath.'_preview.png';
2450
2451 $pdfexists = file_exists($filepdf);
2452
2453 // If PDF file exists
2454 if ($pdfexists) {
2455 // Conversion du PDF en image png si fichier png non existant
2456 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2457 if (!getDolGlobalString('MAIN_DISABLE_PDF_THUMBS')) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2458 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2459 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2460 if ($ret < 0) {
2461 $error++;
2462 }
2463 }
2464 }
2465 }
2466
2467 if ($pdfexists && !$error) {
2468 $heightforphotref = 80;
2469 if (!empty($conf->dol_optimize_smallscreen)) {
2470 $heightforphotref = 60;
2471 }
2472 // If the preview file is found
2473 if (file_exists($fileimage)) {
2474 $phototoshow = '<div class="photoref">';
2475 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2476 $phototoshow .= '</div>';
2477 }
2478 }
2479 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo'
2480 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2481 }
2482
2483 if ($phototoshow) {
2484 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2485 $morehtmlleft .= $phototoshow;
2486 $morehtmlleft .= '</div>';
2487 }
2488 }
2489
2490 if (empty($phototoshow)) { // Show No photo link (picto of object)
2491 if ($object->element == 'action') {
2492 $width = 80;
2493 $cssclass = 'photorefcenter';
2494 $nophoto = img_picto('No photo', 'title_agenda');
2495 } else {
2496 $width = 14;
2497 $cssclass = 'photorefcenter';
2498 $picto = $object->picto;
2499 $prefix = 'object_';
2500 if ($object->element == 'project' && !$object->public) {
2501 $picto = 'project'; // instead of projectpub
2502 }
2503 if (strpos($picto, 'fontawesome_') !== false) {
2504 $prefix = '';
2505 }
2506 $nophoto = img_picto('No photo', $prefix.$picto);
2507 }
2508 $morehtmlleft .= '<!-- No photo to show -->';
2509 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2510 $morehtmlleft .= $nophoto;
2511 $morehtmlleft .= '</div></div>';
2512 }
2513 }
2514 }
2515
2516 // Show barcode
2517 if ($showbarcode) {
2518 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2519 }
2520
2521 if ($object->element == 'societe') {
2522 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2523 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2524 } else {
2525 $morehtmlstatus .= $object->getLibStatut(6);
2526 }
2527 } elseif ($object->element == 'product') {
2528 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2529 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2530 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2531 } else {
2532 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2533 }
2534 $morehtmlstatus .= ' &nbsp; ';
2535 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2536 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2537 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2538 } else {
2539 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2540 }
2541 } elseif (in_array($object->element, array('salary'))) {
2542 $tmptxt = $object->getLibStatut(6, $object->alreadypaid);
2543 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2544 $tmptxt = $object->getLibStatut(5, $object->alreadypaid);
2545 }
2546 $morehtmlstatus .= $tmptxt;
2547 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier'))) { // TODO Move this to use ->alreadypaid
2548 $totalallpayments = $object->getSommePaiement(0);
2549 $totalallpayments += $object->getSumCreditNotesUsed(0);
2550 $totalallpayments += $object->getSumDepositsUsed(0);
2551 $tmptxt = $object->getLibStatut(6, $totalallpayments);
2552 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2553 $tmptxt = $object->getLibStatut(5, $totalallpayments);
2554 }
2555 $morehtmlstatus .= $tmptxt;
2556 } elseif (in_array($object->element, array('chargesociales', 'loan', 'tva'))) { // TODO Move this to use ->alreadypaid
2557 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2558 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2559 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2560 }
2561 $morehtmlstatus .= $tmptxt;
2562 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2563 if ($object->statut == 0) {
2564 $morehtmlstatus .= $object->getLibStatut(5);
2565 } else {
2566 $morehtmlstatus .= $object->getLibStatut(4);
2567 }
2568 } elseif ($object->element == 'facturerec') {
2569 if ($object->frequency == 0) {
2570 $morehtmlstatus .= $object->getLibStatut(2);
2571 } else {
2572 $morehtmlstatus .= $object->getLibStatut(5);
2573 }
2574 } elseif ($object->element == 'project_task') {
2575 $object->fk_statut = 1;
2576 if ($object->progress > 0) {
2577 $object->fk_statut = 2;
2578 }
2579 if ($object->progress >= 100) {
2580 $object->fk_statut = 3;
2581 }
2582 $tmptxt = $object->getLibStatut(5);
2583 $morehtmlstatus .= $tmptxt; // No status on task
2584 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2585 $tmptxt = $object->getLibStatut(6);
2586 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2587 $tmptxt = $object->getLibStatut(5);
2588 }
2589 $morehtmlstatus .= $tmptxt;
2590 }
2591
2592 // Add if object was dispatched "into accountancy"
2593 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2594 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2595 if (method_exists($object, 'getVentilExportCompta')) {
2596 $accounted = $object->getVentilExportCompta();
2597 $langs->load("accountancy");
2598 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2599 }
2600 }
2601
2602 // Add alias for thirdparty
2603 if (!empty($object->name_alias)) {
2604 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
2605 }
2606
2607 // Add label
2608 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
2609 if (!empty($object->label)) {
2610 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
2611 }
2612 }
2613
2614 // Show address and email
2615 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
2616 $moreaddress = $object->getBannerAddress('refaddress', $object); // address, email, url, social networks
2617 if ($moreaddress) {
2618 $morehtmlref .= '<div class="refidno refaddress">';
2619 $morehtmlref .= $moreaddress;
2620 $morehtmlref .= '</div>';
2621 }
2622 }
2623 if (getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && (getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') == '1' || preg_match('/'.preg_quote($object->element, '/').'/i', $conf->global->MAIN_SHOW_TECHNICAL_ID)) && !empty($object->id)) {
2624 $morehtmlref .= '<div style="clear: both;"></div>';
2625 $morehtmlref .= '<div class="refidno opacitymedium">';
2626 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
2627 $morehtmlref .= '</div>';
2628 }
2629
2630 $parameters=array('morehtmlref'=>$morehtmlref);
2631 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
2632 if ($reshook < 0) {
2633 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2634 } elseif (empty($reshook)) {
2635 $morehtmlref .= $hookmanager->resPrint;
2636 } elseif ($reshook > 0) {
2637 $morehtmlref = $hookmanager->resPrint;
2638 }
2639
2640 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
2641 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
2642 print '</div>';
2643 print '<div class="underrefbanner clearboth"></div>';
2644}
2645
2655function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
2656{
2657 global $langs;
2658 $ret = '';
2659 if ($fieldrequired) {
2660 $ret .= '<span class="fieldrequired">';
2661 }
2662 $ret .= '<label for="'.$fieldkey.'">';
2663 $ret .= $langs->trans($langkey);
2664 $ret .= '</label>';
2665 if ($fieldrequired) {
2666 $ret .= '</span>';
2667 }
2668 return $ret;
2669}
2670
2678function dol_bc($var, $moreclass = '')
2679{
2680 global $bc;
2681 $ret = ' '.$bc[$var];
2682 if ($moreclass) {
2683 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
2684 }
2685 return $ret;
2686}
2687
2701function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = '', $mode = 0, $extralangcode = '')
2702{
2703 global $conf, $langs, $hookmanager;
2704
2705 $ret = '';
2706 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
2707
2708 // See format of addresses on https://en.wikipedia.org/wiki/Address
2709 // Address
2710 if (empty($mode)) {
2711 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
2712 }
2713 // Zip/Town/State
2714 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || getDolGlobalString('MAIN_FORCE_STATE_INTO_ADDRESS')) {
2715 // US: title firstname name \n address lines \n town, state, zip \n country
2716 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2717 $ret .= (($ret && $town) ? $sep : '').$town;
2718
2719 if (!empty($object->state)) {
2720 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
2721 }
2722 if (!empty($object->zip)) {
2723 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
2724 }
2725 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
2726 // UK: title firstname name \n address lines \n town state \n zip \n country
2727 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2728 $ret .= ($ret ? $sep : '').$town;
2729 if (!empty($object->state)) {
2730 $ret .= ($ret ? ", " : '').$object->state;
2731 }
2732 if (!empty($object->zip)) {
2733 $ret .= ($ret ? $sep : '').$object->zip;
2734 }
2735 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
2736 // ES: title firstname name \n address lines \n zip town \n state \n country
2737 $ret .= ($ret ? $sep : '').$object->zip;
2738 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2739 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2740 if (!empty($object->state)) {
2741 $ret .= $sep.$object->state;
2742 }
2743 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
2744 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
2745 // See https://www.sljfaq.org/afaq/addresses.html
2746 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2747 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
2748 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
2749 // IT: title firstname name\n address lines \n zip town state_code \n country
2750 $ret .= ($ret ? $sep : '').$object->zip;
2751 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2752 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2753 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
2754 } else {
2755 // Other: title firstname name \n address lines \n zip town[, state] \n country
2756 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2757 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
2758 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
2759 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
2760 $ret .= ($ret ? ", " : '').$object->state;
2761 }
2762 }
2763
2764 if (!is_object($outputlangs)) {
2765 $outputlangs = $langs;
2766 }
2767 if ($withcountry) {
2768 $langs->load("dict");
2769 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
2770 }
2771 if ($hookmanager) {
2772 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
2773 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
2774 if ($reshook > 0) {
2775 $ret = '';
2776 }
2777 $ret .= $hookmanager->resPrint;
2778 }
2779
2780 return $ret;
2781}
2782
2783
2784
2793function dol_strftime($fmt, $ts = false, $is_gmt = false)
2794{
2795 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
2796 return ($is_gmt) ? @gmstrftime($fmt, $ts) : @strftime($fmt, $ts);
2797 } else {
2798 return 'Error date into a not supported range';
2799 }
2800}
2801
2823function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = '', $encodetooutput = false)
2824{
2825 global $conf, $langs;
2826
2827 // If date undefined or "", we return ""
2828 if (dol_strlen($time) == 0) {
2829 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
2830 }
2831
2832 if ($tzoutput === 'auto') {
2833 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
2834 }
2835
2836 // Clean parameters
2837 $to_gmt = false;
2838 $offsettz = $offsetdst = 0;
2839 if ($tzoutput) {
2840 $to_gmt = true; // For backward compatibility
2841 if (is_string($tzoutput)) {
2842 if ($tzoutput == 'tzserver') {
2843 $to_gmt = false;
2844 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
2845 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
2846 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
2847 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
2848 $to_gmt = true;
2849 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
2850
2851 if (class_exists('DateTimeZone')) {
2852 $user_date_tz = new DateTimeZone($offsettzstring);
2853 $user_dt = new DateTime();
2854 $user_dt->setTimezone($user_date_tz);
2855 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
2856 $offsettz = $user_dt->getOffset(); // should include dst ?
2857 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
2858 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
2859 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
2860 }
2861 }
2862 }
2863 }
2864 if (!is_object($outputlangs)) {
2865 $outputlangs = $langs;
2866 }
2867 if (!$format) {
2868 $format = 'daytextshort';
2869 }
2870
2871 // Do we have to reduce the length of date (year on 2 chars) to save space.
2872 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
2873 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour', 'dayhoursec'))) ? 1 : 0; // Test on original $format param.
2874 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
2875 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
2876 if ($formatwithoutreduce != $format) {
2877 $format = $formatwithoutreduce;
2878 $reduceformat = 1;
2879 } // so format 'dayreduceformat' is processed like day
2880
2881 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
2882 // TODO Add format daysmallyear and dayhoursmallyear
2883 if ($format == 'day') {
2884 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
2885 } elseif ($format == 'hour') {
2886 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
2887 } elseif ($format == 'hourduration') {
2888 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
2889 } elseif ($format == 'daytext') {
2890 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
2891 } elseif ($format == 'daytextshort') {
2892 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
2893 } elseif ($format == 'dayhour') {
2894 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
2895 } elseif ($format == 'dayhoursec') {
2896 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
2897 } elseif ($format == 'dayhourtext') {
2898 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
2899 } elseif ($format == 'dayhourtextshort') {
2900 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
2901 } elseif ($format == 'dayhourlog') {
2902 // Format not sensitive to language
2903 $format = '%Y%m%d%H%M%S';
2904 } elseif ($format == 'dayhourlogsmall') {
2905 // Format not sensitive to language
2906 $format = '%y%m%d%H%M';
2907 } elseif ($format == 'dayhourldap') {
2908 $format = '%Y%m%d%H%M%SZ';
2909 } elseif ($format == 'dayhourxcard') {
2910 $format = '%Y%m%dT%H%M%SZ';
2911 } elseif ($format == 'dayxcard') {
2912 $format = '%Y%m%d';
2913 } elseif ($format == 'dayrfc') {
2914 $format = '%Y-%m-%d'; // DATE_RFC3339
2915 } elseif ($format == 'dayhourrfc') {
2916 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
2917 } elseif ($format == 'standard') {
2918 $format = '%Y-%m-%d %H:%M:%S';
2919 }
2920
2921 if ($reduceformat) {
2922 $format = str_replace('%Y', '%y', $format);
2923 $format = str_replace('yyyy', 'yy', $format);
2924 }
2925
2926 // Clean format
2927 if (preg_match('/%b/i', $format)) { // There is some text to translate
2928 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2929 $format = str_replace('%b', '__b__', $format);
2930 $format = str_replace('%B', '__B__', $format);
2931 }
2932 if (preg_match('/%a/i', $format)) { // There is some text to translate
2933 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2934 $format = str_replace('%a', '__a__', $format);
2935 $format = str_replace('%A', '__A__', $format);
2936 }
2937
2938 // Analyze date
2939 $reg = array();
2940 if (preg_match('/^([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])$/i', $time, $reg)) { // Deprecated. Ex: 1970-01-01, 1970-01-01 01:00:00, 19700101010000
2941 dol_print_error('', "Functions.lib::dol_print_date function called with a bad value from page ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]));
2942 return '';
2943 } elseif (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?/i', $time, $reg)) { // Still available to solve problems in extrafields of type date
2944 // This part of code should not be used anymore.
2945 dol_syslog("Functions.lib::dol_print_date function called with a bad value from page ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]), LOG_WARNING);
2946 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
2947 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
2948 $syear = (!empty($reg[1]) ? $reg[1] : '');
2949 $smonth = (!empty($reg[2]) ? $reg[2] : '');
2950 $sday = (!empty($reg[3]) ? $reg[3] : '');
2951 $shour = (!empty($reg[4]) ? $reg[4] : '');
2952 $smin = (!empty($reg[5]) ? $reg[5] : '');
2953 $ssec = (!empty($reg[6]) ? $reg[6] : '');
2954
2955 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
2956
2957 if ($to_gmt) {
2958 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2959 } else {
2960 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2961 }
2962 $dtts = new DateTime();
2963 $dtts->setTimestamp($time);
2964 $dtts->setTimezone($tzo);
2965 $newformat = str_replace(
2966 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2967 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2968 $format
2969 );
2970 $ret = $dtts->format($newformat);
2971 $ret = str_replace(
2972 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2973 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2974 $ret
2975 );
2976 } else {
2977 // Date is a timestamps
2978 if ($time < 100000000000) { // Protection against bad date values
2979 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2980
2981 if ($to_gmt) {
2982 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2983 } else {
2984 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2985 }
2986 $dtts = new DateTime();
2987 $dtts->setTimestamp($timetouse);
2988 $dtts->setTimezone($tzo);
2989 $newformat = str_replace(
2990 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2991 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2992 $format
2993 );
2994 $ret = $dtts->format($newformat);
2995 $ret = str_replace(
2996 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2997 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2998 $ret
2999 );
3000 //var_dump($ret);exit;
3001 } else {
3002 $ret = 'Bad value '.$time.' for date';
3003 }
3004 }
3005
3006 if (preg_match('/__b__/i', $format)) {
3007 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
3008
3009 if ($to_gmt) {
3010 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
3011 } else {
3012 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
3013 }
3014 $dtts = new DateTime();
3015 $dtts->setTimestamp($timetouse);
3016 $dtts->setTimezone($tzo);
3017 $month = $dtts->format("m");
3018 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
3019 if ($encodetooutput) {
3020 $monthtext = $outputlangs->transnoentities('Month'.$month);
3021 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
3022 } else {
3023 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
3024 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
3025 }
3026 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
3027 $ret = str_replace('__b__', $monthtextshort, $ret);
3028 $ret = str_replace('__B__', $monthtext, $ret);
3029 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
3030 //return $ret;
3031 }
3032 if (preg_match('/__a__/i', $format)) {
3033 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
3034 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
3035
3036 if ($to_gmt) {
3037 $tzo = new DateTimeZone('UTC');
3038 } else {
3039 $tzo = new DateTimeZone(date_default_timezone_get());
3040 }
3041 $dtts = new DateTime();
3042 $dtts->setTimestamp($timetouse);
3043 $dtts->setTimezone($tzo);
3044 $w = $dtts->format("w");
3045 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
3046
3047 $ret = str_replace('__A__', $dayweek, $ret);
3048 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
3049 }
3050
3051 return $ret;
3052}
3053
3054
3075function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
3076{
3077 if ($timestamp === '') {
3078 return array();
3079 }
3080
3081 $datetimeobj = new DateTime();
3082 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
3083 if ($forcetimezone) {
3084 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
3085 }
3086 $arrayinfo = array(
3087 'year'=>((int) date_format($datetimeobj, 'Y')),
3088 'mon'=>((int) date_format($datetimeobj, 'm')),
3089 'mday'=>((int) date_format($datetimeobj, 'd')),
3090 'wday'=>((int) date_format($datetimeobj, 'w')),
3091 'yday'=>((int) date_format($datetimeobj, 'z')),
3092 'hours'=>((int) date_format($datetimeobj, 'H')),
3093 'minutes'=>((int) date_format($datetimeobj, 'i')),
3094 'seconds'=>((int) date_format($datetimeobj, 's')),
3095 '0'=>$timestamp
3096 );
3097
3098 return $arrayinfo;
3099}
3100
3122function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3123{
3124 global $conf;
3125 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3126
3127 if ($gm === 'auto') {
3128 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3129 }
3130 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3131
3132 // Clean parameters
3133 if ($hour == -1 || empty($hour)) {
3134 $hour = 0;
3135 }
3136 if ($minute == -1 || empty($minute)) {
3137 $minute = 0;
3138 }
3139 if ($second == -1 || empty($second)) {
3140 $second = 0;
3141 }
3142
3143 // Check parameters
3144 if ($check) {
3145 if (!$month || !$day) {
3146 return '';
3147 }
3148 if ($day > 31) {
3149 return '';
3150 }
3151 if ($month > 12) {
3152 return '';
3153 }
3154 if ($hour < 0 || $hour > 24) {
3155 return '';
3156 }
3157 if ($minute < 0 || $minute > 60) {
3158 return '';
3159 }
3160 if ($second < 0 || $second > 60) {
3161 return '';
3162 }
3163 }
3164
3165 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3166 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3167 $localtz = new DateTimeZone($default_timezone);
3168 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3169 // We use dol_tz_string first because it is more reliable.
3170 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3171 try {
3172 $localtz = new DateTimeZone($default_timezone);
3173 } catch (Exception $e) {
3174 dol_syslog("Warning dol_tz_string contains an invalid value ".$_SESSION["dol_tz_string"], LOG_WARNING);
3175 $default_timezone = @date_default_timezone_get();
3176 }
3177 } elseif (strrpos($gm, "tz,") !== false) {
3178 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3179 try {
3180 $localtz = new DateTimeZone($timezone);
3181 } catch (Exception $e) {
3182 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3183 }
3184 }
3185
3186 if (empty($localtz)) {
3187 $localtz = new DateTimeZone('UTC');
3188 }
3189 //var_dump($localtz);
3190 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3191 $dt = new DateTime('now', $localtz);
3192 $dt->setDate((int) $year, (int) $month, (int) $day);
3193 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3194 $date = $dt->getTimestamp(); // should include daylight saving time
3195 //var_dump($date);
3196 return $date;
3197}
3198
3199
3210function dol_now($mode = 'auto')
3211{
3212 $ret = 0;
3213
3214 if ($mode === 'auto') {
3215 $mode = 'gmt';
3216 }
3217
3218 if ($mode == 'gmt') {
3219 $ret = time(); // Time for now at greenwich.
3220 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3221 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3222 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3223 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3224 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3225 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3226 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3227 // $ret=dol_now('gmt')+($tzsecond*3600);
3228 //}
3229 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3230 // Time for now with user timezone added
3231 //print 'time: '.time();
3232 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3233 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3234 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3235 }
3236
3237 return $ret;
3238}
3239
3240
3249function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3250{
3251 global $conf, $langs;
3252 $level = 1024;
3253
3254 if (!empty($conf->dol_optimize_smallscreen)) {
3255 $shortunit = 1;
3256 }
3257
3258 // Set value text
3259 if (empty($shortvalue) || $size < ($level * 10)) {
3260 $ret = $size;
3261 $textunitshort = $langs->trans("b");
3262 $textunitlong = $langs->trans("Bytes");
3263 } else {
3264 $ret = round($size / $level, 0);
3265 $textunitshort = $langs->trans("Kb");
3266 $textunitlong = $langs->trans("KiloBytes");
3267 }
3268 // Use long or short text unit
3269 if (empty($shortunit)) {
3270 $ret .= ' '.$textunitlong;
3271 } else {
3272 $ret .= ' '.$textunitshort;
3273 }
3274
3275 return $ret;
3276}
3277
3288function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = '')
3289{
3290 global $langs;
3291
3292 if (empty($url)) {
3293 return '';
3294 }
3295
3296 $linkstart = '<a href="';
3297 if (!preg_match('/^http/i', $url)) {
3298 $linkstart .= 'http://';
3299 }
3300 $linkstart .= $url;
3301 $linkstart .= '"';
3302 if ($target) {
3303 $linkstart .= ' target="'.$target.'"';
3304 }
3305 $linkstart .= ' title="'.$langs->trans("URL").': '.$url.'"';
3306 $linkstart .= '>';
3307
3308 $link = '';
3309 if (!preg_match('/^http/i', $url)) {
3310 $link .= 'http://';
3311 }
3312 $link .= dol_trunc($url, $max);
3313
3314 $linkend = '</a>';
3315
3316 if ($morecss == 'float') { // deprecated
3317 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto($langs->trans("Url"), 'globe', 'class="paddingrightonly"') : '').$link.'</div>';
3318 } else {
3319 return $linkstart.'<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto('', 'globe', 'class="paddingrightonly"') : '').$link.'</span>'.$linkend;
3320 }
3321}
3322
3335function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3336{
3337 global $user, $langs, $hookmanager;
3338
3339 //global $conf; $conf->global->AGENDA_ADDACTIONFOREMAIL = 1;
3340 //$showinvalid = 1; $email = 'rrrrr';
3341
3342 $newemail = dol_escape_htmltag($email);
3343
3344 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && $withpicto) {
3345 $withpicto = 0;
3346 }
3347
3348 if (empty($email)) {
3349 return '&nbsp;';
3350 }
3351
3352 if (!empty($addlink)) {
3353 $newemail = '<a class="paddingrightonly" style="text-overflow: ellipsis;" href="';
3354 if (!preg_match('/^mailto:/i', $email)) {
3355 $newemail .= 'mailto:';
3356 }
3357 $newemail .= $email;
3358 $newemail .= '">';
3359
3360 $newemail .= ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '');
3361
3362 $newemail .= dol_trunc($email, $max);
3363 $newemail .= '</a>';
3364 if ($showinvalid && !isValidEmail($email)) {
3365 $langs->load("errors");
3366 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email), '', 'paddingrightonly');
3367 }
3368
3369 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3370 $type = 'AC_EMAIL';
3371 $linktoaddaction = '';
3372 if (getDolGlobalString('AGENDA_ADDACTIONFOREMAIL')) {
3373 $linktoaddaction = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.urlencode($type).'&amp;contactid='.((int) $cid).'&amp;socid='.((int) $socid).'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3374 }
3375 if ($linktoaddaction) {
3376 $newemail = '<div>'.$newemail.' '.$linktoaddaction.'</div>';
3377 }
3378 }
3379 } else {
3380 $newemail = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3381
3382 if ($showinvalid && !isValidEmail($email)) {
3383 $langs->load("errors");
3384 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3385 }
3386 }
3387
3388 //$rep = '<div class="nospan" style="margin-right: 10px">';
3389 //$rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3390 //$rep .= '</div>';
3391 $rep = $newemail;
3392
3393 if ($hookmanager) {
3394 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3395
3396 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3397 if ($reshook > 0) {
3398 $rep = '';
3399 }
3400 $rep .= $hookmanager->resPrint;
3401 }
3402
3403 return $rep;
3404}
3405
3412{
3413 global $conf, $db;
3414
3415 $socialnetworks = array();
3416 // Enable caching of array
3417 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3418 $cachekey = 'socialnetworks_' . $conf->entity;
3419 $dataretrieved = dol_getcache($cachekey);
3420 if (!is_null($dataretrieved)) {
3421 $socialnetworks = $dataretrieved;
3422 } else {
3423 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3424 $sql .= " WHERE entity=".$conf->entity;
3425 $resql = $db->query($sql);
3426 if ($resql) {
3427 while ($obj = $db->fetch_object($resql)) {
3428 $socialnetworks[$obj->code] = array(
3429 'rowid' => $obj->rowid,
3430 'label' => $obj->label,
3431 'url' => $obj->url,
3432 'icon' => $obj->icon,
3433 'active' => $obj->active,
3434 );
3435 }
3436 }
3437 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3438 }
3439
3440 return $socialnetworks;
3441}
3442
3453function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3454{
3455 global $conf, $user, $langs;
3456
3457 $htmllink = $value;
3458
3459 if (empty($value)) {
3460 return '&nbsp;';
3461 }
3462
3463 if (!empty($type)) {
3464 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3465 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3466 $htmllink .= '<span class="fab pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3467 if ($type == 'skype') {
3468 $htmllink .= dol_escape_htmltag($value);
3469 $htmllink .= '&nbsp; <a href="skype:';
3470 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3471 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3472 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3473 $htmllink .= '</a><a href="skype:';
3474 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3475 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3476 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3477 $htmllink .= '</a>';
3478 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3479 $addlink = 'AC_SKYPE';
3480 $link = '';
3481 if (getDolGlobalString('AGENDA_ADDACTIONFORSKYPE')) {
3482 $link = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.$addlink.'&amp;contactid='.$cid.'&amp;socid='.$socid.'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3483 }
3484 $htmllink .= ($link ? ' '.$link : '');
3485 }
3486 } else {
3487 $networkconstname = 'MAIN_INFO_SOCIETE_'.strtoupper($type).'_URL';
3488 if (getDolGlobalString($networkconstname)) {
3489 $link = str_replace('{socialid}', $value, getDolGlobalString($networkconstname));
3490 if (preg_match('/^https?:\/\//i', $link)) {
3491 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3492 } else {
3493 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3494 }
3495 } elseif (!empty($dictsocialnetworks[$type]['url'])) {
3496 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3497 if ($tmpvirginurl) {
3498 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3499 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3500
3501 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3502 if ($tmpvirginurl3) {
3503 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3504 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3505 }
3506
3507 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3508 if ($tmpvirginurl2) {
3509 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3510 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3511 }
3512 }
3513 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3514 if (preg_match('/^https?:\/\//i', $link)) {
3515 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3516 } else {
3517 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3518 }
3519 } else {
3520 $htmllink .= dol_escape_htmltag($value);
3521 }
3522 }
3523 $htmllink .= '</div>';
3524 } else {
3525 $langs->load("errors");
3526 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3527 }
3528 return $htmllink;
3529}
3530
3540function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1)
3541{
3542 global $mysoc;
3543
3544 if (empty($profID) || empty($profIDtype)) {
3545 return '';
3546 }
3547 if (empty($countrycode)) {
3548 $countrycode = $mysoc->country_code;
3549 }
3550 $newProfID = $profID;
3551 $id = substr($profIDtype, -1);
3552 $ret = '';
3553 if (strtoupper($countrycode) == 'FR') {
3554 // France
3555 // (see https://www.economie.gouv.fr/entreprises/numeros-identification-entreprise)
3556
3557 if ($id == 1 && dol_strlen($newProfID) == 9) {
3558 // SIREN (ex: 123 123 123)
3559 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3);
3560 }
3561 if ($id == 2 && dol_strlen($newProfID) == 14) {
3562 // SIRET (ex: 123 123 123 12345)
3563 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3).' '.substr($newProfID, 9, 5);
3564 }
3565 if ($id == 3 && dol_strlen($newProfID) == 5) {
3566 // NAF/APE (ex: 69.20Z)
3567 $newProfID = substr($newProfID, 0, 2).'.'.substr($newProfID, 2, 3);
3568 }
3569 if ($profIDtype === 'VAT' && dol_strlen($newProfID) == 13) {
3570 // TVA intracommunautaire (ex: FR12 123 123 123)
3571 $newProfID = substr($newProfID, 0, 4).' '.substr($newProfID, 4, 3).' '.substr($newProfID, 7, 3).' '.substr($newProfID, 10, 3);
3572 }
3573 }
3574 if (!empty($addcpButton)) {
3575 $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3576 } else {
3577 $ret = $newProfID;
3578 }
3579 return $ret;
3580}
3581
3596function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0)
3597{
3598 global $conf, $user, $langs, $mysoc, $hookmanager;
3599
3600 // Clean phone parameter
3601 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
3602 if (empty($phone)) {
3603 return '';
3604 }
3605 if (getDolGlobalString('MAIN_PHONE_SEPAR')) {
3606 $separ = $conf->global->MAIN_PHONE_SEPAR;
3607 }
3608 if (empty($countrycode) && is_object($mysoc)) {
3609 $countrycode = $mysoc->country_code;
3610 }
3611
3612 // Short format for small screens
3613 if ($conf->dol_optimize_smallscreen) {
3614 $separ = '';
3615 }
3616
3617 $newphone = $phone;
3618 if (strtoupper($countrycode) == "FR") {
3619 // France
3620 if (dol_strlen($phone) == 10) {
3621 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 2).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3622 } elseif (dol_strlen($phone) == 7) {
3623 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
3624 } elseif (dol_strlen($phone) == 9) {
3625 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
3626 } elseif (dol_strlen($phone) == 11) {
3627 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3628 } elseif (dol_strlen($phone) == 12) {
3629 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3630 } elseif (dol_strlen($phone) == 13) {
3631 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 2);
3632 }
3633 } elseif (strtoupper($countrycode) == "CA") {
3634 if (dol_strlen($phone) == 10) {
3635 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
3636 }
3637 } elseif (strtoupper($countrycode) == "PT") {//Portugal
3638 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
3639 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3640 }
3641 } elseif (strtoupper($countrycode) == "SR") {//Suriname
3642 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
3643 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
3644 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
3645 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
3646 }
3647 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
3648 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
3649 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
3650 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
3651 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
3652 }
3653 } elseif (strtoupper($countrycode) == "ES") {//Espagne
3654 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
3655 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3656 }
3657 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
3658 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
3659 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3660 }
3661 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
3662 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
3663 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3664 }
3665 } elseif (strtoupper($countrycode) == "TR") {//Turquie
3666 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
3667 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3668 }
3669 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
3670 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
3671 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3672 }
3673 } elseif (strtoupper($countrycode) == "MX") {//Mexique
3674 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
3675 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3676 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
3677 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3678 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
3679 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3680 }
3681 } elseif (strtoupper($countrycode) == "ML") {//Mali
3682 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
3683 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3684 }
3685 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
3686 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
3687 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3688 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
3689 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 3);
3690 }
3691 } elseif (strtoupper($countrycode) == "MU") {
3692 //Maurice
3693 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
3694 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3695 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
3696 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3697 }
3698 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
3699 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
3700 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3701 }
3702 } elseif (strtoupper($countrycode) == "SY") {//Syrie
3703 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
3704 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3705 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
3706 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 3);
3707 }
3708 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
3709 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
3710 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3711 } elseif (dol_strlen($phone) == 13) {//ex: +971_ABC_DEF_GHI
3712 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3713 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
3714 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
3715 }
3716 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
3717 if (dol_strlen($phone) == 13) {//ex: +213_ABC_DEF_GHI
3718 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3719 }
3720 } elseif (strtoupper($countrycode) == "BE") {//Belgique
3721 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
3722 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3723 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
3724 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3725 }
3726 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
3727 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
3728 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3729 }
3730 } elseif (strtoupper($countrycode) == "CO") {//Colombie
3731 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
3732 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3733 }
3734 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
3735 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
3736 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 1).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3737 }
3738 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
3739 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
3740 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3741 }
3742 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
3743 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
3744 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 2);
3745 }
3746 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
3747 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
3748 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3749 }
3750 } elseif (strtoupper($countrycode) == "CH") {//Suisse
3751 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
3752 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3753 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
3754 $newphone = $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 4);
3755 }
3756 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
3757 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
3758 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3759 }
3760 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
3761 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
3762 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3763 }
3764 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
3765 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
3766 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3767 }
3768 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
3769 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
3770 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3771 }
3772 } elseif (strtoupper($countrycode) == "IT") {//Italie
3773 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
3774 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3775 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
3776 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3777 }
3778 } elseif (strtoupper($countrycode) == "AU") {
3779 //Australie
3780 if (dol_strlen($phone) == 12) {
3781 //ex: +61_A_BCDE_FGHI
3782 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
3783 }
3784 } elseif (strtoupper($countrycode) == "LU") {
3785 // Luxembourg
3786 if (dol_strlen($phone) == 10) {// fixe 6 chiffres +352_AA_BB_CC
3787 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3788 } elseif (dol_strlen($phone) == 11) {// fixe 7 chiffres +352_AA_BB_CC_D
3789 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 1);
3790 } elseif (dol_strlen($phone) == 12) {// fixe 8 chiffres +352_AA_BB_CC_DD
3791 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3792 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
3793 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3794 }
3795 }
3796
3797 $newphoneastart = $newphoneaend = '';
3798 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
3799 if ($addlink == 'tel' || $conf->browser->layout == 'phone' || (isModEnabled('clicktodial') && getDolGlobalString('CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS'))) { // If phone or option for, we use link of phone
3800 $newphoneastart = '<a href="tel:'.$phone.'">';
3801 $newphoneaend .= '</a>';
3802 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
3803 if (empty($user->clicktodial_loaded)) {
3804 $user->fetch_clicktodial();
3805 }
3806
3807 // Define urlmask
3808 $urlmask = getDolGlobalString('CLICKTODIAL_URL', 'ErrorClickToDialModuleNotConfigured');
3809 if (!empty($user->clicktodial_url)) {
3810 $urlmask = $user->clicktodial_url;
3811 }
3812
3813 $clicktodial_poste = (!empty($user->clicktodial_poste) ? urlencode($user->clicktodial_poste) : '');
3814 $clicktodial_login = (!empty($user->clicktodial_login) ? urlencode($user->clicktodial_login) : '');
3815 $clicktodial_password = (!empty($user->clicktodial_password) ? urlencode($user->clicktodial_password) : '');
3816 // This line is for backward compatibility
3817 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
3818 // Thoose lines are for substitution
3819 $substitarray = array('__PHONEFROM__'=>$clicktodial_poste,
3820 '__PHONETO__'=>urlencode($phone),
3821 '__LOGIN__'=>$clicktodial_login,
3822 '__PASS__'=>$clicktodial_password);
3823 $url = make_substitutions($url, $substitarray);
3824 if (!getDolGlobalString('CLICKTODIAL_DO_NOT_USE_AJAX_CALL')) {
3825 // Default and recommended: New method using ajax without submiting a page making a javascript history.go(-1) back
3826 $newphoneastart = '<a href="'.$url.'" class="cssforclicktodial">'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
3827 $newphoneaend = '</a>';
3828 } else {
3829 // Old method
3830 $newphoneastart = '<a href="'.$url.'"';
3831 if (getDolGlobalString('CLICKTODIAL_FORCENEWTARGET')) {
3832 $newphoneastart .= ' target="_blank" rel="noopener noreferrer"';
3833 }
3834 $newphoneastart .= '>';
3835 $newphoneaend .= '</a>';
3836 }
3837 }
3838
3839 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
3840 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3841 $type = 'AC_TEL';
3842 $addlinktoagenda = '';
3843 if ($addlink == 'AC_FAX') {
3844 $type = 'AC_FAX';
3845 }
3846 if (getDolGlobalString('AGENDA_ADDACTIONFORPHONE')) {
3847 $addlinktoagenda = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage='. urlencode($_SERVER['REQUEST_URI']) .'&amp;actioncode='.$type.($cid ? '&amp;contactid='.$cid : '').($socid ? '&amp;socid='.$socid : '').'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3848 }
3849 if ($addlinktoagenda) {
3850 $newphone = '<span>'.$newphone.' '.$addlinktoagenda.'</span>';
3851 }
3852 }
3853 }
3854
3855 if (empty($titlealt)) {
3856 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
3857 }
3858 $rep = '';
3859
3860 if ($hookmanager) {
3861 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
3862 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
3863 $rep .= $hookmanager->resPrint;
3864 }
3865 if (empty($reshook)) {
3866 $picto = '';
3867 if ($withpicto) {
3868 if ($withpicto == 'fax') {
3869 $picto = 'phoning_fax';
3870 } elseif ($withpicto == 'phone') {
3871 $picto = 'phoning';
3872 } elseif ($withpicto == 'mobile') {
3873 $picto = 'phoning_mobile';
3874 } else {
3875 $picto = '';
3876 }
3877 }
3878 if ($adddivfloat == 1) {
3879 $rep .= '<div class="nospan float" style="margin-right: 10px">';
3880 } elseif (empty($adddivfloat)) {
3881 $rep .= '<span style="margin-right: 10px;">';
3882 }
3883
3884 $rep .= $newphoneastart;
3885 $rep .= ($withpicto ? img_picto($titlealt, 'object_'.$picto.'.png') : '');
3886 if ($separ != 'hidenum') {
3887 $rep .= ($withpicto ? ' ' : '').$newphone;
3888 }
3889 $rep .= $newphoneaend;
3890
3891 if ($adddivfloat == 1) {
3892 $rep .= '</div>';
3893 } elseif (empty($adddivfloat)) {
3894 $rep .= '</span>';
3895 }
3896 }
3897
3898 return $rep;
3899}
3900
3908function dol_print_ip($ip, $mode = 0)
3909{
3910 global $langs;
3911
3912 $ret = '';
3913
3914 if (empty($mode)) {
3915 $ret .= $ip;
3916 }
3917
3918 if ($mode != 2) {
3919 $countrycode = dolGetCountryCodeFromIp($ip);
3920 if ($countrycode) { // If success, countrycode is us, fr, ...
3921 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
3922 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
3923 } else {
3924 $ret .= ' ('.$countrycode.')';
3925 }
3926 } else {
3927 // Nothing
3928 }
3929 }
3930
3931 return $ret;
3932}
3933
3943{
3944 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
3945 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
3946 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
3947 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
3948 } else {
3949 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
3950 }
3951 } else {
3952 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
3953 }
3954 } else {
3955 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
3956 }
3957 return $ip;
3958}
3959
3968function isHTTPS()
3969{
3970 $isSecure = false;
3971 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
3972 $isSecure = true;
3973 } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
3974 $isSecure = true;
3975 }
3976 return $isSecure;
3977}
3978
3986{
3987 global $conf;
3988
3989 $countrycode = '';
3990
3991 if (!empty($conf->geoipmaxmind->enabled)) {
3992 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3993 //$ip='24.24.24.24';
3994 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
3995 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3996 $geoip = new DolGeoIP('country', $datafile);
3997 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
3998 $countrycode = $geoip->getCountryCodeFromIP($ip);
3999 }
4000
4001 return $countrycode;
4002}
4003
4004
4012{
4013 global $conf, $langs, $user;
4014
4015 //$ret=$user->xxx;
4016 $ret = '';
4017 if (!empty($conf->geoipmaxmind->enabled)) {
4018 $ip = getUserRemoteIP();
4019 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
4020 //$ip='24.24.24.24';
4021 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
4022 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
4023 $geoip = new DolGeoIP('country', $datafile);
4024 $countrycode = $geoip->getCountryCodeFromIP($ip);
4025 $ret = $countrycode;
4026 }
4027 return $ret;
4028}
4029
4042function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
4043{
4044 global $conf, $user, $langs, $hookmanager;
4045
4046 $out = '';
4047
4048 if ($address) {
4049 if ($hookmanager) {
4050 $parameters = array('element' => $element, 'id' => $id);
4051 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
4052 $out .= $hookmanager->resPrint;
4053 }
4054 if (empty($reshook)) {
4055 if (empty($charfornl)) {
4056 $out .= nl2br($address);
4057 } else {
4058 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
4059 }
4060
4061 // TODO Remove this block, we can add this using the hook now
4062 $showgmap = $showomap = 0;
4063 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS')) {
4064 $showgmap = 1;
4065 }
4066 if ($element == 'contact' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_CONTACTS')) {
4067 $showgmap = 1;
4068 }
4069 if ($element == 'member' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_MEMBERS')) {
4070 $showgmap = 1;
4071 }
4072 if ($element == 'user' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_USERS')) {
4073 $showgmap = 1;
4074 }
4075 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS')) {
4076 $showomap = 1;
4077 }
4078 if ($element == 'contact' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_CONTACTS')) {
4079 $showomap = 1;
4080 }
4081 if ($element == 'member' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_MEMBERS')) {
4082 $showomap = 1;
4083 }
4084 if ($element == 'user' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_USERS')) {
4085 $showomap = 1;
4086 }
4087 if ($showgmap) {
4088 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
4089 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4090 }
4091 if ($showomap) {
4092 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
4093 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4094 }
4095 }
4096 }
4097 if ($noprint) {
4098 return $out;
4099 } else {
4100 print $out;
4101 }
4102}
4103
4104
4114function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
4115{
4116 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
4117 return true;
4118 }
4119 if ($acceptuserkey && $address == '__USER_EMAIL__') {
4120 return true;
4121 }
4122 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
4123 return true;
4124 }
4125
4126 return false;
4127}
4128
4137function isValidMXRecord($domain)
4138{
4139 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
4140 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
4141 return 0;
4142 }
4143 if (function_exists('getmxrr')) {
4144 $mxhosts = array();
4145 $weight = array();
4146 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
4147 if (count($mxhosts) > 1) {
4148 return 1;
4149 }
4150 if (count($mxhosts) == 1 && !empty($mxhosts[0])) {
4151 return 1;
4152 }
4153
4154 return 0;
4155 }
4156 }
4157
4158 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4159 return -1;
4160}
4161
4169function isValidPhone($phone)
4170{
4171 return true;
4172}
4173
4174
4184function dolGetFirstLetters($s, $nbofchar = 1)
4185{
4186 $ret = '';
4187 $tmparray = explode(' ', $s);
4188 foreach ($tmparray as $tmps) {
4189 $ret .= dol_substr($tmps, 0, $nbofchar);
4190 }
4191
4192 return $ret;
4193}
4194
4195
4203function dol_strlen($string, $stringencoding = 'UTF-8')
4204{
4205 if (is_null($string)) {
4206 return 0;
4207 }
4208
4209 if (function_exists('mb_strlen')) {
4210 return mb_strlen($string, $stringencoding);
4211 } else {
4212 return strlen($string);
4213 }
4214}
4215
4226function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4227{
4228 global $langs;
4229
4230 if (empty($stringencoding)) {
4231 $stringencoding = $langs->charset_output;
4232 }
4233
4234 $ret = '';
4235 if (empty($trunconbytes)) {
4236 if (function_exists('mb_substr')) {
4237 $ret = mb_substr($string, $start, $length, $stringencoding);
4238 } else {
4239 $ret = substr($string, $start, $length);
4240 }
4241 } else {
4242 if (function_exists('mb_strcut')) {
4243 $ret = mb_strcut($string, $start, $length, $stringencoding);
4244 } else {
4245 $ret = substr($string, $start, $length);
4246 }
4247 }
4248 return $ret;
4249}
4250
4251
4265function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4266{
4267 global $conf;
4268
4269 if (empty($size) || getDolGlobalString('MAIN_DISABLE_TRUNC')) {
4270 return $string;
4271 }
4272
4273 if (empty($stringencoding)) {
4274 $stringencoding = 'UTF-8';
4275 }
4276 // reduce for small screen
4277 if ($conf->dol_optimize_smallscreen == 1 && $display == 1) {
4278 $size = round($size / 3);
4279 }
4280
4281 // We go always here
4282 if ($trunc == 'right') {
4283 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4284 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4285 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4286 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4287 } else {
4288 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4289 return $string;
4290 }
4291 } elseif ($trunc == 'middle') {
4292 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4293 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4294 $size1 = round($size / 2);
4295 $size2 = round($size / 2);
4296 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4297 } else {
4298 return $string;
4299 }
4300 } elseif ($trunc == 'left') {
4301 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4302 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4303 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4304 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4305 } else {
4306 return $string;
4307 }
4308 } elseif ($trunc == 'wrap') {
4309 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4310 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4311 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4312 } else {
4313 return $string;
4314 }
4315 } else {
4316 return 'BadParam3CallingDolTrunc';
4317 }
4318}
4319
4326function getPictoForType($key)
4327{
4328 // Set array with type -> picto
4329 $type2picto = array(
4330 'varchar'=>'font',
4331 'text'=>'font',
4332 'html'=>'code',
4333 'int'=>'sort-numeric-down',
4334 'double'=>'sort-numeric-down',
4335 'price'=>'currency',
4336 'pricecy'=>'multicurrency',
4337 'password' => 'key',
4338 'boolean'=>'check-square',
4339 'date'=>'calendar',
4340 'datetime'=>'calendar',
4341 'phone'=> 'phone',
4342 'mail'=> 'email',
4343 'url'=> 'url',
4344 'ip'=> 'country',
4345 'select' => 'list',
4346 'sellist' => 'list',
4347 'radio' => 'check-circle',
4348 'checkbox' => 'check-square',
4349 'chkbxlst' => 'check-square',
4350 'link' => 'link',
4351 'separate'=> 'minus'
4352 );
4353
4354 if (!empty($type2picto[$key])) {
4355 return img_picto('', $type2picto[$key], 'class="pictofixedwidth"');
4356 }
4357
4358 return img_picto('', 'generic', 'class="pictofixedwidth"');
4359}
4360
4361
4383function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4384{
4385 global $conf, $langs;
4386
4387 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4388 $url = DOL_URL_ROOT;
4389 $theme = isset($conf->theme) ? $conf->theme : null;
4390 $path = 'theme/'.$theme;
4391 if (empty($picto)) {
4392 $picto = 'generic';
4393 }
4394
4395 // Define fullpathpicto to use into src
4396 if ($pictoisfullpath) {
4397 // Clean parameters
4398 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4399 $picto .= '.png';
4400 }
4401 $fullpathpicto = $picto;
4402 $reg = array();
4403 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4404 $morecss .= ($morecss ? ' ' : '').$reg[1];
4405 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4406 }
4407 } else {
4408 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', (is_null($picto) ? '' : $picto));
4409 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4410 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4411
4412 if (strpos($pictowithouttext, 'fontawesome_') === 0 || strpos($pictowithouttext, 'fa-') === 0) {
4413 // This is a font awesome image 'fontawesome_xxx' or 'fa-xxx'
4414 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4415 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4416
4417 // Compatibility with old fontawesome versions
4418 if ($pictowithouttext == 'file-o') {
4419 $pictowithouttext = 'file';
4420 }
4421
4422 $pictowithouttextarray = explode('_', $pictowithouttext);
4423 $marginleftonlyshort = 0;
4424
4425 if (!empty($pictowithouttextarray[1])) {
4426 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4427 $fakey = 'fa-'.$pictowithouttextarray[0];
4428 $faprefix = empty($pictowithouttextarray[1]) ? 'fas' : $pictowithouttextarray[1];
4429 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4430 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4431 } else {
4432 $fakey = 'fa-'.$pictowithouttext;
4433 $faprefix = 'fas';
4434 $facolor = '';
4435 $fasize = '';
4436 }
4437
4438 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4439 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4440 $morestyle = '';
4441 $reg = array();
4442 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4443 $morecss .= ($morecss ? ' ' : '').$reg[1];
4444 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4445 }
4446 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4447 $morestyle = $reg[1];
4448 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4449 }
4450 $moreatt = trim($moreatt);
4451
4452 $enabledisablehtml = '<span class="'.$faprefix.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4453 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4454 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4455 $enabledisablehtml .= $titlealt;
4456 }*/
4457 $enabledisablehtml .= '</span>';
4458
4459 return $enabledisablehtml;
4460 }
4461
4462 if (empty($srconly) && in_array($pictowithouttext, array(
4463 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4464 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'angle-double-down', 'angle-double-up', 'asset',
4465 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building',
4466 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4467 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'code', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4468 'check-circle', 'check-square', 'currency', 'multicurrency',
4469 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies',
4470 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4471 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4472 'filter', 'file', 'file-o', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus', 'font',
4473 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4474 'hands-helping', 'help', 'holiday',
4475 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4476 'key', 'knowledgemanagement',
4477 'label', 'language', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4478 'margin', 'map-marker-alt', 'member', 'meeting', 'minus', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4479 'off', 'on', 'order',
4480 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4481 'stock', 'resize', 'service', 'stats',
4482 'security', 'setup', 'share-alt', 'sign-out', 'split', 'stripe', 'stripe-s', 'switch_off', 'switch_on', 'switch_on_warning', 'switch_on_red', 'tools', 'unlink', 'uparrow', 'user', 'user-tie', 'vcard', 'wrench',
4483 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4484 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4485 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4486 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4487 'technic', 'ticket',
4488 'error', 'warning',
4489 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4490 'shapes', 'skill', 'square', 'sort-numeric-down', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4491 'tick', 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda',
4492 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4493 'conferenceorbooth', 'eventorganization',
4494 'stamp', 'signature'
4495 ))) {
4496 $fakey = $pictowithouttext;
4497 $facolor = '';
4498 $fasize = '';
4499 $fa = getDolGlobalString('MAIN_FONTAWESOME_ICON_STYLE', 'fas');
4500 if (in_array($pictowithouttext, array('card', 'bell', 'clock', 'establishment', 'file', 'file-o', 'generic', 'minus-square', 'object_generic', 'pdf', 'plus-square', 'timespent', 'note', 'off', 'on', 'object_bookmark', 'bookmark', 'vcard'))) {
4501 $fa = 'far';
4502 }
4503 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4504 $fa = 'fab';
4505 }
4506
4507 $arrayconvpictotofa = array(
4508 'account'=>'university', 'accounting_account'=>'clipboard-list', 'accountline'=>'receipt', 'accountancy'=>'search-dollar', 'action'=>'calendar-alt', 'add'=>'plus-circle', 'address'=> 'address-book', 'asset'=>'money-check-alt', 'autofill'=>'fill',
4509 'bank_account'=>'university',
4510 'bill'=>'file-invoice-dollar', 'billa'=>'file-excel', 'billr'=>'file-invoice-dollar', 'billd'=>'file-medical',
4511 'supplier_invoice'=>'file-invoice-dollar', 'supplier_invoicea'=>'file-excel', 'supplier_invoicer'=>'file-invoice-dollar', 'supplier_invoiced'=>'file-medical',
4512 'bom'=>'shapes',
4513 'card'=>'address-card', 'chart'=>'chart-line', 'company'=>'building', 'contact'=>'address-book', 'contract'=>'suitcase', 'collab'=>'people-arrows', 'conversation'=>'comments', 'country'=>'globe-americas', 'cron'=>'business-time', 'cross'=>'times',
4514 'donation'=>'file-alt', 'dynamicprice'=>'hand-holding-usd',
4515 'setup'=>'cog', 'companies'=>'building', 'products'=>'cube', 'commercial'=>'suitcase', 'invoicing'=>'coins',
4516 'accounting'=>'search-dollar', 'category'=>'tag', 'dollyrevert'=>'dolly',
4517 'file-o'=>'file', 'generate'=>'plus-square', 'hrm'=>'user-tie', 'incoterm'=>'truck-loading',
4518 'margin'=>'calculator', 'members'=>'user-friends', 'ticket'=>'ticket-alt', 'globe'=>'external-link-alt', 'lot'=>'barcode',
4519 'email'=>'at', 'establishment'=>'building', 'edit'=>'pencil-alt', 'entity'=>'globe',
4520 'graph'=>'chart-line', 'grip_title'=>'arrows-alt', 'grip'=>'arrows-alt', 'help'=>'question-circle',
4521 'generic'=>'file', 'holiday'=>'umbrella-beach',
4522 'info'=>'info-circle', 'inventory'=>'boxes', 'intracommreport'=>'globe-europe', 'jobprofile'=>'cogs',
4523 'knowledgemanagement'=>'ticket-alt', 'label'=>'layer-group', 'line'=>'bars', 'loan'=>'money-bill-alt',
4524 'member'=>'user-alt', 'meeting'=>'chalkboard-teacher', 'mrp'=>'cubes', 'next'=>'arrow-alt-circle-right',
4525 'trip'=>'wallet', 'expensereport'=>'wallet', 'group'=>'users', 'movement'=>'people-carry',
4526 'sign-out'=>'sign-out-alt',
4527 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_warning'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star',
4528 'bank'=>'university', 'close_title'=>'times', 'delete'=>'trash', 'filter'=>'filter',
4529 'list-alt'=>'list-alt', 'calendarlist'=>'bars', 'calendar'=>'calendar-alt', 'calendarmonth'=>'calendar-alt', 'calendarweek'=>'calendar-week', 'calendarday'=>'calendar-day', 'calendarperuser'=>'table',
4530 'intervention'=>'ambulance', 'invoice'=>'file-invoice-dollar', 'order'=>'file-invoice',
4531 'error'=>'exclamation-triangle', 'warning'=>'exclamation-triangle',
4532 'other'=>'square',
4533 'playdisabled'=>'play', 'pdf'=>'file-pdf', 'poll'=>'check-double', 'pos'=>'cash-register', 'preview'=>'binoculars', 'project'=>'project-diagram', 'projectpub'=>'project-diagram', 'projecttask'=>'tasks', 'propal'=>'file-signature', 'proposal'=>'file-signature',
4534 'partnership'=>'handshake', 'payment'=>'money-check-alt', 'payment_vat'=>'money-check-alt', 'pictoconfirm'=>'check-square', 'phoning'=>'phone', 'phoning_mobile'=>'mobile-alt', 'phoning_fax'=>'fax', 'previous'=>'arrow-alt-circle-left', 'printer'=>'print', 'product'=>'cube', 'puce'=>'angle-right',
4535 'recent' => 'check-square', 'reception'=>'dolly', 'recruitmentjobposition'=>'id-card-alt', 'recruitmentcandidature'=>'id-badge',
4536 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature',
4537 'refresh'=>'redo', 'region'=>'map-marked', 'replacement'=>'exchange-alt', 'resource'=>'laptop-house', 'recurring'=>'history',
4538 'service'=>'concierge-bell',
4539 'skill'=>'shapes', 'state'=>'map-marked-alt', 'security'=>'key', 'salary'=>'wallet', 'shipment'=>'dolly', 'stock'=>'box-open', 'stats' => 'chart-bar', 'split'=>'code-branch', 'stripe'=>'stripe-s',
4540 'supplier'=>'building', 'technic'=>'cogs',
4541 'timespent'=>'clock', 'tick' => 'check', 'title_setup'=>'tools', 'title_accountancy'=>'money-check-alt', 'title_bank'=>'university', 'title_hrm'=>'umbrella-beach',
4542 'title_agenda'=>'calendar-alt',
4543 'uncheck'=>'times', 'uparrow'=>'share', 'url'=>'external-link-alt', 'vat'=>'money-check-alt', 'vcard'=>'arrow-alt-circle-down',
4544 'jabber'=>'comment-o',
4545 'website'=>'globe-americas', 'workstation'=>'pallet', 'webhook'=>'bullseye', 'world'=>'globe', 'private'=>'user-lock',
4546 'conferenceorbooth'=>'chalkboard-teacher', 'eventorganization'=>'project-diagram'
4547 );
4548 if ($conf->currency == 'EUR') {
4549 $arrayconvpictotofa['currency'] = 'euro-sign';
4550 $arrayconvpictotofa['multicurrency'] = 'dollar-sign';
4551 } else {
4552 $arrayconvpictotofa['currency'] = 'dollar-sign';
4553 $arrayconvpictotofa['multicurrency'] = 'euro-sign';
4554 }
4555 if ($pictowithouttext == 'off') {
4556 $fakey = 'fa-square';
4557 $fasize = '1.3em';
4558 } elseif ($pictowithouttext == 'on') {
4559 $fakey = 'fa-check-square';
4560 $fasize = '1.3em';
4561 } elseif ($pictowithouttext == 'listlight') {
4562 $fakey = 'fa-download';
4563 $marginleftonlyshort = 1;
4564 } elseif ($pictowithouttext == 'printer') {
4565 $fakey = 'fa-print';
4566 $fasize = '1.2em';
4567 } elseif ($pictowithouttext == 'note') {
4568 $fakey = 'fa-sticky-note';
4569 $marginleftonlyshort = 1;
4570 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
4571 $convertarray = array('1uparrow'=>'caret-up', '1downarrow'=>'caret-down', '1leftarrow'=>'caret-left', '1rightarrow'=>'caret-right', '1uparrow_selected'=>'caret-up', '1downarrow_selected'=>'caret-down', '1leftarrow_selected'=>'caret-left', '1rightarrow_selected'=>'caret-right');
4572 $fakey = 'fa-'.$convertarray[$pictowithouttext];
4573 if (preg_match('/selected/', $pictowithouttext)) {
4574 $facolor = '#888';
4575 }
4576 $marginleftonlyshort = 1;
4577 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
4578 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
4579 } else {
4580 $fakey = 'fa-'.$pictowithouttext;
4581 }
4582
4583 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment'))) {
4584 $morecss .= ' em092';
4585 }
4586 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
4587 $morecss .= ' em088';
4588 }
4589 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
4590 $morecss .= ' em080';
4591 }
4592
4593 // Define $marginleftonlyshort
4594 $arrayconvpictotomarginleftonly = array(
4595 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
4596 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
4597 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
4598 );
4599 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
4600 $marginleftonlyshort = 0;
4601 }
4602
4603 // Add CSS
4604 $arrayconvpictotomorcess = array(
4605 'action'=>'infobox-action', 'account'=>'infobox-bank_account', 'accounting_account'=>'infobox-bank_account', 'accountline'=>'infobox-bank_account', 'accountancy'=>'infobox-bank_account', 'asset'=>'infobox-bank_account',
4606 'bank_account'=>'infobox-bank_account',
4607 'bill'=>'infobox-commande', 'billa'=>'infobox-commande', 'billr'=>'infobox-commande', 'billd'=>'infobox-commande',
4608 'margin'=>'infobox-bank_account', 'conferenceorbooth'=>'infobox-project',
4609 'cash-register'=>'infobox-bank_account', 'contract'=>'infobox-contrat', 'check'=>'font-status4', 'collab'=>'infobox-action', 'conversation'=>'infobox-contrat',
4610 'donation'=>'infobox-commande', 'dolly'=>'infobox-commande', 'dollyrevert'=>'flip infobox-order_supplier',
4611 'ecm'=>'infobox-action', 'eventorganization'=>'infobox-project',
4612 'hrm'=>'infobox-adherent', 'group'=>'infobox-adherent', 'intervention'=>'infobox-contrat',
4613 'incoterm'=>'infobox-supplier_proposal',
4614 'currency'=>'infobox-bank_account', 'multicurrency'=>'infobox-bank_account',
4615 'members'=>'infobox-adherent', 'member'=>'infobox-adherent', 'money-bill-alt'=>'infobox-bank_account',
4616 'order'=>'infobox-commande',
4617 'user'=>'infobox-adherent', 'users'=>'infobox-adherent',
4618 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_warning'=>'font-status4 warning', 'switch_on_red'=>'font-status8',
4619 'holiday'=>'infobox-holiday', 'info'=>'opacityhigh', 'invoice'=>'infobox-commande',
4620 'knowledgemanagement'=>'infobox-contrat rotate90', 'loan'=>'infobox-bank_account',
4621 'payment'=>'infobox-bank_account', 'payment_vat'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'pos'=>'infobox-bank_account', 'project'=>'infobox-project', 'projecttask'=>'infobox-project',
4622 'propal'=>'infobox-propal', 'proposal'=>'infobox-propal','private'=>'infobox-project',
4623 'reception'=>'flip', 'recruitmentjobposition'=>'infobox-adherent', 'recruitmentcandidature'=>'infobox-adherent',
4624 'resource'=>'infobox-action',
4625 'salary'=>'infobox-bank_account', 'shapes'=>'infobox-adherent', 'shipment'=>'infobox-commande', 'supplier_invoice'=>'infobox-order_supplier', 'supplier_invoicea'=>'infobox-order_supplier', 'supplier_invoiced'=>'infobox-order_supplier',
4626 'supplier'=>'infobox-order_supplier', 'supplier_order'=>'infobox-order_supplier', 'supplier_proposal'=>'infobox-supplier_proposal',
4627 'ticket'=>'infobox-contrat', 'title_accountancy'=>'infobox-bank_account', 'title_hrm'=>'infobox-holiday', 'expensereport'=>'infobox-expensereport', 'trip'=>'infobox-expensereport', 'title_agenda'=>'infobox-action',
4628 'vat'=>'infobox-bank_account',
4629 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
4630 'list-alt'=>'imgforviewmode', 'calendar'=>'imgforviewmode', 'calendarweek'=>'imgforviewmode', 'calendarmonth'=>'imgforviewmode', 'calendarday'=>'imgforviewmode', 'calendarperuser'=>'imgforviewmode'
4631 );
4632 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4633 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
4634 }
4635
4636 // Define $color
4637 $arrayconvpictotocolor = array(
4638 'address'=>'#6c6aa8', 'building'=>'#6c6aa8', 'bom'=>'#a69944',
4639 'clone'=>'#999', 'cog'=>'#999', 'companies'=>'#6c6aa8', 'company'=>'#6c6aa8', 'contact'=>'#6c6aa8', 'cron'=>'#555',
4640 'dynamicprice'=>'#a69944',
4641 'edit'=>'#444', 'note'=>'#999', 'error'=>'', 'help'=>'#bbb', 'listlight'=>'#999', 'language'=>'#555',
4642 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
4643 'lock'=>'#ddd', 'lot'=>'#a69944',
4644 'map-marker-alt'=>'#aaa', 'mrp'=>'#a69944', 'product'=>'#a69944', 'service'=>'#a69944', 'inventory'=>'#a69944', 'stock'=>'#a69944', 'movement'=>'#a69944',
4645 'other'=>'#ddd', 'world'=>'#986c6a',
4646 'partnership'=>'#6c6aa8', 'playdisabled'=>'#ccc', 'printer'=>'#444', 'projectpub'=>'#986c6a', 'reception'=>'#a69944', 'resize'=>'#444', 'rss'=>'#cba',
4647 //'shipment'=>'#a69944',
4648 'security'=>'#999', 'square'=>'#888', 'stop-circle'=>'#888', 'stats'=>'#444', 'switch_off'=>'#999',
4649 'technic' => '#999', 'tick' => '#282', 'timespent' => '#555',
4650 'uncheck'=>'#800', 'uparrow'=>'#555', 'user-cog'=>'#999', 'country'=>'#aaa', 'globe-americas'=>'#aaa', 'region'=>'#aaa', 'state'=>'#aaa',
4651 'website'=>'#304', 'workstation'=>'#a69944'
4652 );
4653 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4654 $facolor = $arrayconvpictotocolor[$pictowithouttext];
4655 }
4656
4657 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4658 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4659 $morestyle = '';
4660 $reg = array();
4661 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4662 $morecss .= ($morecss ? ' ' : '').$reg[1];
4663 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4664 }
4665 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4666 $morestyle = $reg[1];
4667 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4668 }
4669 $moreatt = trim($moreatt);
4670
4671 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4672 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4673 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4674 $enabledisablehtml .= $titlealt;
4675 }*/
4676 $enabledisablehtml .= '</span>';
4677
4678 return $enabledisablehtml;
4679 }
4680
4681 if (getDolGlobalString('MAIN_OVERWRITE_THEME_PATH')) {
4682 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_PATH') . '/theme/'.$theme; // If the theme does not have the same name as the module
4683 } elseif (getDolGlobalString('MAIN_OVERWRITE_THEME_RES')) {
4684 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_RES') . '/theme/' . getDolGlobalString('MAIN_OVERWRITE_THEME_RES'); // To allow an external module to overwrite image resources whatever is activated theme
4685 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
4686 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
4687 }
4688
4689 // If we ask an image into $url/$mymodule/img (instead of default path)
4690 $regs = array();
4691 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
4692 $picto = $regs[1];
4693 $path = $regs[2]; // $path is $mymodule
4694 }
4695
4696 // Clean parameters
4697 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4698 $picto .= '.png';
4699 }
4700 // If alt path are defined, define url where img file is, according to physical path
4701 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
4702 foreach ($conf->file->dol_document_root as $type => $dirroot) {
4703 if ($type == 'main') {
4704 continue;
4705 }
4706 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommanded
4707 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
4708 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
4709 break;
4710 }
4711 }
4712
4713 // $url is '' or '/custom', $path is current theme or
4714 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
4715 }
4716
4717 if ($srconly) {
4718 return $fullpathpicto;
4719 }
4720
4721 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
4722 return '<img src="'.$fullpathpicto.'"'.($notitle ? '' : ' alt="'.dol_escape_htmltag($alt).'"').(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt.($morecss ? ' class="'.$morecss.'"' : '') : ' class="inline-block'.($morecss ? ' '.$morecss : '').'"').'>'; // Alt is used for accessibility, title for popup
4723}
4724
4738function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0)
4739{
4740 if (strpos($picto, '^') === 0) {
4741 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
4742 } else {
4743 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
4744 }
4745}
4746
4758function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
4759{
4760 global $conf;
4761
4762 if (is_numeric($picto)) {
4763 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
4764 //$picto = $leveltopicto[$picto];
4765 return '<i class="fa fa-weather-level'.$picto.'"></i>';
4766 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4767 $picto .= '.png';
4768 }
4769
4770 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
4771
4772 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
4773}
4774
4786function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
4787{
4788 global $conf;
4789
4790 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4791 $picto .= '.png';
4792 }
4793
4794 if ($pictoisfullpath) {
4795 $path = $picto;
4796 } else {
4797 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
4798
4799 if (getDolGlobalInt('MAIN_MODULE_CAN_OVERWRITE_COMMONICONS')) {
4800 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
4801
4802 if (file_exists($themepath)) {
4803 $path = $themepath;
4804 }
4805 }
4806 }
4807
4808 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
4809}
4810
4824function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
4825{
4826 global $langs;
4827
4828 if (empty($titlealt) || $titlealt == 'default') {
4829 if ($numaction == '-1' || $numaction == 'ST_NO') {
4830 $numaction = -1;
4831 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
4832 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
4833 $numaction = 0;
4834 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
4835 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
4836 $numaction = 1;
4837 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
4838 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
4839 $numaction = 2;
4840 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
4841 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
4842 $numaction = 3;
4843 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
4844 } else {
4845 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
4846 $numaction = 0;
4847 }
4848 }
4849 if (!is_numeric($numaction)) {
4850 $numaction = 0;
4851 }
4852
4853 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
4854}
4855
4863function img_pdf($titlealt = 'default', $size = 3)
4864{
4865 global $langs;
4866
4867 if ($titlealt == 'default') {
4868 $titlealt = $langs->trans('Show');
4869 }
4870
4871 return img_picto($titlealt, 'pdf'.$size.'.png');
4872}
4873
4881function img_edit_add($titlealt = 'default', $other = '')
4882{
4883 global $langs;
4884
4885 if ($titlealt == 'default') {
4886 $titlealt = $langs->trans('Add');
4887 }
4888
4889 return img_picto($titlealt, 'edit_add.png', $other);
4890}
4898function img_edit_remove($titlealt = 'default', $other = '')
4899{
4900 global $langs;
4901
4902 if ($titlealt == 'default') {
4903 $titlealt = $langs->trans('Remove');
4904 }
4905
4906 return img_picto($titlealt, 'edit_remove.png', $other);
4907}
4908
4917function img_edit($titlealt = 'default', $float = 0, $other = '')
4918{
4919 global $langs;
4920
4921 if ($titlealt == 'default') {
4922 $titlealt = $langs->trans('Modify');
4923 }
4924
4925 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
4926}
4927
4936function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
4937{
4938 global $langs;
4939
4940 if ($titlealt == 'default') {
4941 $titlealt = $langs->trans('View');
4942 }
4943
4944 $moreatt = ($float ? 'style="float: right" ' : '').$other;
4945
4946 return img_picto($titlealt, 'eye', $moreatt);
4947}
4948
4957function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
4958{
4959 global $langs;
4960
4961 if ($titlealt == 'default') {
4962 $titlealt = $langs->trans('Delete');
4963 }
4964
4965 return img_picto($titlealt, 'delete.png', $other, false, 0, 0, '', $morecss);
4966}
4967
4975function img_printer($titlealt = "default", $other = '')
4976{
4977 global $langs;
4978 if ($titlealt == "default") {
4979 $titlealt = $langs->trans("Print");
4980 }
4981 return img_picto($titlealt, 'printer.png', $other);
4982}
4983
4991function img_split($titlealt = 'default', $other = 'class="pictosplit"')
4992{
4993 global $langs;
4994
4995 if ($titlealt == 'default') {
4996 $titlealt = $langs->trans('Split');
4997 }
4998
4999 return img_picto($titlealt, 'split.png', $other);
5000}
5001
5009function img_help($usehelpcursor = 1, $usealttitle = 1)
5010{
5011 global $langs;
5012
5013 if ($usealttitle) {
5014 if (is_string($usealttitle)) {
5015 $usealttitle = dol_escape_htmltag($usealttitle);
5016 } else {
5017 $usealttitle = $langs->trans('Info');
5018 }
5019 }
5020
5021 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
5022}
5023
5030function img_info($titlealt = 'default')
5031{
5032 global $langs;
5033
5034 if ($titlealt == 'default') {
5035 $titlealt = $langs->trans('Informations');
5036 }
5037
5038 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
5039}
5040
5049function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
5050{
5051 global $langs;
5052
5053 if ($titlealt == 'default') {
5054 $titlealt = $langs->trans('Warning');
5055 }
5056
5057 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
5058 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
5059}
5060
5067function img_error($titlealt = 'default')
5068{
5069 global $langs;
5070
5071 if ($titlealt == 'default') {
5072 $titlealt = $langs->trans('Error');
5073 }
5074
5075 return img_picto($titlealt, 'error.png');
5076}
5077
5085function img_next($titlealt = 'default', $moreatt = '')
5086{
5087 global $langs;
5088
5089 if ($titlealt == 'default') {
5090 $titlealt = $langs->trans('Next');
5091 }
5092
5093 //return img_picto($titlealt, 'next.png', $moreatt);
5094 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5095}
5096
5104function img_previous($titlealt = 'default', $moreatt = '')
5105{
5106 global $langs;
5107
5108 if ($titlealt == 'default') {
5109 $titlealt = $langs->trans('Previous');
5110 }
5111
5112 //return img_picto($titlealt, 'previous.png', $moreatt);
5113 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5114}
5115
5124function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
5125{
5126 global $langs;
5127
5128 if ($titlealt == 'default') {
5129 $titlealt = $langs->trans('Down');
5130 }
5131
5132 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
5133}
5134
5143function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
5144{
5145 global $langs;
5146
5147 if ($titlealt == 'default') {
5148 $titlealt = $langs->trans('Up');
5149 }
5150
5151 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
5152}
5153
5162function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
5163{
5164 global $langs;
5165
5166 if ($titlealt == 'default') {
5167 $titlealt = $langs->trans('Left');
5168 }
5169
5170 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
5171}
5172
5181function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
5182{
5183 global $langs;
5184
5185 if ($titlealt == 'default') {
5186 $titlealt = $langs->trans('Right');
5187 }
5188
5189 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
5190}
5191
5199function img_allow($allow, $titlealt = 'default')
5200{
5201 global $langs;
5202
5203 if ($titlealt == 'default') {
5204 $titlealt = $langs->trans('Active');
5205 }
5206
5207 if ($allow == 1) {
5208 return img_picto($titlealt, 'tick.png');
5209 }
5210
5211 return '-';
5212}
5213
5221function img_credit_card($brand, $morecss = null)
5222{
5223 if (is_null($morecss)) {
5224 $morecss = 'fa-2x';
5225 }
5226
5227 if ($brand == 'visa' || $brand == 'Visa') {
5228 $brand = 'cc-visa';
5229 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5230 $brand = 'cc-mastercard';
5231 } elseif ($brand == 'amex' || $brand == 'American Express') {
5232 $brand = 'cc-amex';
5233 } elseif ($brand == 'discover' || $brand == 'Discover') {
5234 $brand = 'cc-discover';
5235 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5236 $brand = 'cc-jcb';
5237 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5238 $brand = 'cc-diners-club';
5239 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5240 $brand = 'credit-card';
5241 }
5242
5243 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5244}
5245
5254function img_mime($file, $titlealt = '', $morecss = '')
5255{
5256 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5257
5258 $mimetype = dol_mimetype($file, '', 1);
5259 $mimeimg = dol_mimetype($file, '', 2);
5260 $mimefa = dol_mimetype($file, '', 4);
5261
5262 if (empty($titlealt)) {
5263 $titlealt = 'Mime type: '.$mimetype;
5264 }
5265
5266 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5267 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5268}
5269
5270
5278function img_search($titlealt = 'default', $other = '')
5279{
5280 global $conf, $langs;
5281
5282 if ($titlealt == 'default') {
5283 $titlealt = $langs->trans('Search');
5284 }
5285
5286 $img = img_picto($titlealt, 'search.png', $other, false, 1);
5287
5288 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5289 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5290
5291 return $input;
5292}
5293
5301function img_searchclear($titlealt = 'default', $other = '')
5302{
5303 global $conf, $langs;
5304
5305 if ($titlealt == 'default') {
5306 $titlealt = $langs->trans('Search');
5307 }
5308
5309 $img = img_picto($titlealt, 'searchclear.png', $other, false, 1);
5310
5311 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5312 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5313
5314 return $input;
5315}
5316
5328function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '')
5329{
5330 global $conf, $langs;
5331
5332 if ($infoonimgalt) {
5333 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5334 } else {
5335 if (empty($conf->use_javascript_ajax)) {
5336 $textfordropdown = '';
5337 }
5338
5339 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5340 $result = ($nodiv ? '' : '<div class="'.$class.($morecss ? ' '.$morecss : '').($textfordropdown ? ' hidden' : '').'">').'<span class="fa fa-info-circle" title="'.dol_escape_htmltag($admin ? $langs->trans('InfoAdmin') : $langs->trans('Note')).'"></span> '.$text.($nodiv ? '' : '</div>');
5341
5342 if ($textfordropdown) {
5343 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5344 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5345 jQuery(document).ready(function() {
5346 jQuery(".'.$class.'text").click(function() {
5347 console.log("toggle text");
5348 jQuery(".'.$class.'").toggle();
5349 });
5350 });
5351 </script>';
5352
5353 $result = $tmpresult.$result;
5354 }
5355 }
5356
5357 return $result;
5358}
5359
5360
5372function dol_print_error($db = '', $error = '', $errors = null)
5373{
5374 global $conf, $langs, $argv;
5375 global $dolibarr_main_prod;
5376
5377 $out = '';
5378 $syslog = '';
5379
5380 // If error occurs before the $lang object was loaded
5381 if (!$langs) {
5382 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5383 $langs = new Translate('', $conf);
5384 $langs->load("main");
5385 }
5386
5387 // Load translation files required by the error messages
5388 $langs->loadLangs(array('main', 'errors'));
5389
5390 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5391 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5392 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5393 $out .= "You use an experimental or develop level of features, so please do NOT report any bugs or vulnerability, except if problem is confirmed after moving option MAIN_FEATURES_LEVEL back to 0.<br>\n";
5394 }
5395 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5396
5397 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5398 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5399 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5400 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5401 }
5402 if (function_exists("phpversion")) {
5403 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5404 }
5405 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5406 if (function_exists("php_uname")) {
5407 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5408 }
5409 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5410 $out .= "<br>\n";
5411 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5412 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5413 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5414 $out .= "<br>\n";
5415 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5416 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5417 } else { // Mode CLI
5418 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5419 $syslog .= "pid=".dol_getmypid();
5420 }
5421
5422 if (!empty($conf->modules)) {
5423 $out .= "<b>".$langs->trans("Modules").":</b> ".join(', ', $conf->modules)."<br>\n";
5424 }
5425
5426 if (is_object($db)) {
5427 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5428 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5429 $lastqueryerror = $db->lastqueryerror();
5430 if (!utf8_check($lastqueryerror)) {
5431 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5432 }
5433 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5434 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5435 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5436 $out .= "<br>\n";
5437 } else { // Mode CLI
5438 // No dol_escape_htmltag for output, we are in CLI mode
5439 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5440 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5441 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5442 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5443 }
5444 $syslog .= ", sql=".$db->lastquery();
5445 $syslog .= ", db_error=".$db->lasterror();
5446 }
5447
5448 if ($error || $errors) {
5449 $langs->load("errors");
5450
5451 // Merge all into $errors array
5452 if (is_array($error) && is_array($errors)) {
5453 $errors = array_merge($error, $errors);
5454 } elseif (is_array($error)) {
5455 $errors = $error;
5456 } elseif (is_array($errors)) {
5457 $errors = array_merge(array($error), $errors);
5458 } else {
5459 $errors = array_merge(array($error), array($errors));
5460 }
5461
5462 foreach ($errors as $msg) {
5463 if (empty($msg)) {
5464 continue;
5465 }
5466 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5467 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5468 } else { // Mode CLI
5469 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5470 }
5471 $syslog .= ", msg=".$msg;
5472 }
5473 }
5474 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5475 xdebug_print_function_stack();
5476 $out .= '<b>XDebug informations:</b>'."<br>\n";
5477 $out .= 'File: '.xdebug_call_file()."<br>\n";
5478 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5479 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5480 $out .= "<br>\n";
5481 }
5482
5483 // Return a http header with error code if possible
5484 if (!headers_sent()) {
5485 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5486 top_httphead();
5487 }
5488 //http_response_code(500); // If we use 500, message is not ouput with some command line tools
5489 http_response_code(202); // If we use 202, this is not really an error message, but this allow to ouput message on command line tools
5490 }
5491
5492 if (empty($dolibarr_main_prod)) {
5493 print $out;
5494 } else {
5495 if (empty($langs->defaultlang)) {
5496 $langs->setDefaultLang();
5497 }
5498 $langs->loadLangs(array("main", "errors")); // Reload main because language may have been set only on previous line so we have to reload files we need.
5499 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5500 print 'This website or feature is currently temporarly not available or failed after a technical error.<br><br>This may be due to a maintenance operation. Current status of operation ('.dol_print_date(dol_now(), 'dayhourrfc').') are on next line...<br><br>'."\n";
5501 print $langs->trans("DolibarrHasDetectedError").'. ';
5502 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5503 if (!defined("MAIN_CORE_ERROR")) {
5504 define("MAIN_CORE_ERROR", 1);
5505 }
5506 }
5507
5508 dol_syslog("Error ".$syslog, LOG_ERR);
5509}
5510
5521function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5522{
5523 global $langs, $conf;
5524
5525 if (empty($email)) {
5526 $email = $conf->global->MAIN_INFO_SOCIETE_MAIL;
5527 }
5528
5529 $langs->load("errors");
5530 $now = dol_now();
5531
5532 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5533 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5534 if ($errormessage) {
5535 print '<br><br>'.$errormessage;
5536 }
5537 if (is_array($errormessages) && count($errormessages)) {
5538 foreach ($errormessages as $mesgtoshow) {
5539 print '<br><br>'.$mesgtoshow;
5540 }
5541 }
5542 print '</div></div>';
5543}
5544
5561function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
5562{
5563 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
5564}
5565
5584function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
5585{
5586 global $conf, $langs, $form;
5587 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
5588
5589 if ($moreattrib == 'class="right"') {
5590 $prefix .= 'right '; // For backward compatibility
5591 }
5592
5593 $sortorder = strtoupper($sortorder);
5594 $out = '';
5595 $sortimg = '';
5596
5597 $tag = 'th';
5598 if ($thead == 2) {
5599 $tag = 'div';
5600 }
5601
5602 $tmpsortfield = explode(',', $sortfield);
5603 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
5604 $tmpfield = explode(',', $field);
5605 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
5606
5607 if (!getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle)) {
5608 $prefix = 'wrapcolumntitle '.$prefix;
5609 }
5610
5611 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
5612 // If field is used as sort criteria we use a specific css class liste_titre_sel
5613 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
5614 $liste_titre = 'liste_titre';
5615 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
5616 $liste_titre = 'liste_titre_sel';
5617 }
5618
5619 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
5620 //$out .= (($field && empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && preg_match('/^[a-zA-Z_0-9\s\.\-:&;]*$/', $name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5621 $tagstart .= ($name && !getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
5622 $tagstart .= '>';
5623
5624 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5625 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5626 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5627 $options = preg_replace('/&+/i', '&', $options);
5628 if (!preg_match('/^&/', $options)) {
5629 $options = '&'.$options;
5630 }
5631
5632 $sortordertouseinlink = '';
5633 if ($field1 != $sortfield1) { // We are on another field than current sorted field
5634 if (preg_match('/^DESC/i', $sortorder)) {
5635 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5636 } else { // We reverse the var $sortordertouseinlink
5637 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5638 }
5639 } else { // We are on field that is the first current sorting criteria
5640 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
5641 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5642 } else {
5643 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5644 }
5645 }
5646 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
5647 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
5648 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5649 $out .= '>';
5650 }
5651 if ($tooltip) {
5652 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
5653 if (preg_match('/:\w+$/', $tooltip)) {
5654 $tmptooltip = explode(':', $tooltip);
5655 } else {
5656 $tmptooltip = array($tooltip);
5657 }
5658 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
5659 } else {
5660 $out .= $langs->trans($name);
5661 }
5662
5663 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5664 $out .= '</a>';
5665 }
5666
5667 if (empty($thead) && $field) { // If this is a sort field
5668 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5669 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5670 $options = preg_replace('/&+/i', '&', $options);
5671 if (!preg_match('/^&/', $options)) {
5672 $options = '&'.$options;
5673 }
5674
5675 if (!$sortorder || ($field1 != $sortfield1)) {
5676 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5677 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5678 } else {
5679 if (preg_match('/^DESC/', $sortorder)) {
5680 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5681 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
5682 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
5683 }
5684 if (preg_match('/^ASC/', $sortorder)) {
5685 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
5686 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5687 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
5688 }
5689 }
5690 }
5691
5692 $tagend = '</'.$tag.'>';
5693
5694 $out = $tagstart.$sortimg.$out.$tagend;
5695
5696 return $out;
5697}
5698
5707function print_titre($title)
5708{
5709 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
5710
5711 print '<div class="titre">'.$title.'</div>';
5712}
5713
5725function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
5726{
5727 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
5728}
5729
5743function load_fiche_titre($titre, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
5744{
5745 global $conf;
5746
5747 $return = '';
5748
5749 if ($picto == 'setup') {
5750 $picto = 'generic';
5751 }
5752
5753 $return .= "\n";
5754 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
5755 $return .= '<tr class="titre">';
5756 if ($picto) {
5757 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
5758 }
5759 $return .= '<td class="nobordernopadding valignmiddle col-title">';
5760 $return .= '<div class="titre inline-block">'.$titre.'</div>';
5761 $return .= '</td>';
5762 if (dol_strlen($morehtmlcenter)) {
5763 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5764 }
5765 if (dol_strlen($morehtmlright)) {
5766 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
5767 }
5768 $return .= '</tr></table>'."\n";
5769
5770 return $return;
5771}
5772
5796function print_barre_liste($titre, $page, $file, $options = '', $sortfield = '', $sortorder = '', $morehtmlcenter = '', $num = -1, $totalnboflines = '', $picto = 'generic', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limit = -1, $hideselectlimit = 0, $hidenavigation = 0, $pagenavastextinput = 0, $morehtmlrightbeforearrow = '')
5797{
5798 global $conf;
5799
5800 $savlimit = $limit;
5801 $savtotalnboflines = $totalnboflines;
5802 $totalnboflines = abs((int) $totalnboflines);
5803
5804 $page = (int) $page;
5805
5806 if ($picto == 'setup') {
5807 $picto = 'title_setup.png';
5808 }
5809 if (($conf->browser->name == 'ie') && $picto == 'generic') {
5810 $picto = 'title.gif';
5811 }
5812 if ($limit < 0) {
5813 $limit = $conf->liste_limit;
5814 }
5815
5816 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
5817 $nextpage = 1;
5818 } else {
5819 $nextpage = 0;
5820 }
5821 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
5822
5823 print "\n";
5824 print "<!-- Begin title -->\n";
5825 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
5826
5827 // Left
5828
5829 if ($picto && $titre) {
5830 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
5831 }
5832
5833 print '<td class="nobordernopadding valignmiddle col-title">';
5834 print '<div class="titre inline-block">'.$titre;
5835 if (!empty($titre) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
5836 print '<span class="opacitymedium colorblack paddingleft">('.$totalnboflines.')</span>';
5837 }
5838 print '</div></td>';
5839
5840 // Center
5841 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
5842 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5843 }
5844
5845 // Right
5846 print '<td class="nobordernopadding valignmiddle right col-right">';
5847 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
5848 if ($sortfield) {
5849 $options .= "&sortfield=".urlencode($sortfield);
5850 }
5851 if ($sortorder) {
5852 $options .= "&sortorder=".urlencode($sortorder);
5853 }
5854 // Show navigation bar
5855 $pagelist = '';
5856 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
5857 if ($totalnboflines) { // If we know total nb of lines
5858 // Define nb of extra page links before and after selected page + ... + first or last
5859 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
5860
5861 if ($limit > 0) {
5862 $nbpages = ceil($totalnboflines / $limit);
5863 } else {
5864 $nbpages = 1;
5865 }
5866 $cpt = ($page - $maxnbofpage);
5867 if ($cpt < 0) {
5868 $cpt = 0;
5869 }
5870
5871 if ($cpt >= 1) {
5872 if (empty($pagenavastextinput)) {
5873 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=0'.$options.'">1</a></li>';
5874 if ($cpt > 2) {
5875 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5876 } elseif ($cpt == 2) {
5877 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=1'.$options.'">2</a></li>';
5878 }
5879 }
5880 }
5881
5882 do {
5883 if ($pagenavastextinput) {
5884 if ($cpt == $page) {
5885 $pagelist .= '<li class="pagination"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
5886 $pagelist .= '/';
5887 }
5888 } else {
5889 if ($cpt == $page) {
5890 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
5891 } else {
5892 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
5893 }
5894 }
5895 $cpt++;
5896 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
5897
5898 if (empty($pagenavastextinput)) {
5899 if ($cpt < $nbpages) {
5900 if ($cpt < $nbpages - 2) {
5901 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5902 } elseif ($cpt == $nbpages - 2) {
5903 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
5904 }
5905 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5906 }
5907 } else {
5908 //var_dump($page.' '.$cpt.' '.$nbpages);
5909 $pagelist .= '<li class="pagination paginationlastpage"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5910 }
5911 } else {
5912 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
5913 }
5914 }
5915
5916 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
5917 print_fleche_navigation($page, $file, $options, $nextpage, $pagelist, $morehtmlright, $savlimit, $totalnboflines, $hideselectlimit, $morehtmlrightbeforearrow, $hidenavigation); // output the div and ul for previous/last completed with page numbers into $pagelist
5918 }
5919
5920 // js to autoselect page field on focus
5921 if ($pagenavastextinput) {
5922 print ajax_autoselect('.pageplusone');
5923 }
5924
5925 print '</td>';
5926 print '</tr>';
5927
5928 print '</table>'."\n";
5929
5930 // Center
5931 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
5932 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
5933 }
5934
5935 print "<!-- End title -->\n\n";
5936}
5937
5954function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
5955{
5956 global $conf, $langs;
5957
5958 print '<div class="pagination"><ul>';
5959 if ($beforearrows) {
5960 print '<li class="paginationbeforearrows">';
5961 print $beforearrows;
5962 print '</li>';
5963 }
5964
5965 if (empty($hidenavigation)) {
5966 if ((int) $limit > 0 && empty($hideselectlimit)) {
5967 $pagesizechoices = '10:10,15:15,20:20,30:30,40:40,50:50,100:100,250:250,500:500,1000:1000';
5968 $pagesizechoices .= ',5000:5000,10000:10000,20000:20000';
5969 //$pagesizechoices.=',0:'.$langs->trans("All"); // Not yet supported
5970 //$pagesizechoices.=',2:2';
5971 if (getDolGlobalString('MAIN_PAGESIZE_CHOICES')) {
5972 $pagesizechoices = $conf->global->MAIN_PAGESIZE_CHOICES;
5973 }
5974
5975 print '<li class="pagination">';
5976 print '<select class="flat selectlimit" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
5977 $tmpchoice = explode(',', $pagesizechoices);
5978 $tmpkey = $limit.':'.$limit;
5979 if (!in_array($tmpkey, $tmpchoice)) {
5980 $tmpchoice[] = $tmpkey;
5981 }
5982 $tmpkey = $conf->liste_limit.':'.$conf->liste_limit;
5983 if (!in_array($tmpkey, $tmpchoice)) {
5984 $tmpchoice[] = $tmpkey;
5985 }
5986 asort($tmpchoice, SORT_NUMERIC);
5987 foreach ($tmpchoice as $val) {
5988 $selected = '';
5989 $tmp = explode(':', $val);
5990 $key = $tmp[0];
5991 $val = $tmp[1];
5992 if ($key != '' && $val != '') {
5993 if ((int) $key == (int) $limit) {
5994 $selected = ' selected="selected"';
5995 }
5996 print '<option name="'.$key.'"'.$selected.'>'.dol_escape_htmltag($val).'</option>'."\n";
5997 }
5998 }
5999 print '</select>';
6000 if ($conf->use_javascript_ajax) {
6001 print '<!-- JS CODE TO ENABLE select limit to launch submit of page -->
6002 <script>
6003 jQuery(document).ready(function () {
6004 jQuery(".selectlimit").change(function() {
6005 console.log("Change limit. Send submit");
6006 $(this).parents(\'form:first\').submit();
6007 });
6008 });
6009 </script>
6010 ';
6011 }
6012 print '</li>';
6013 }
6014 if ($page > 0) {
6015 print '<li class="pagination paginationpage paginationpageleft"><a class="paginationprevious reposition" href="'.$file.'?page='.($page - 1).$options.'"><i class="fa fa-chevron-left" title="'.dol_escape_htmltag($langs->trans("Previous")).'"></i></a></li>';
6016 }
6017 if ($betweenarrows) {
6018 print '<!--<div class="betweenarrows nowraponall inline-block">-->';
6019 print $betweenarrows;
6020 print '<!--</div>-->';
6021 }
6022 if ($nextpage > 0) {
6023 print '<li class="pagination paginationpage paginationpageright"><a class="paginationnext reposition" href="'.$file.'?page='.($page + 1).$options.'"><i class="fa fa-chevron-right" title="'.dol_escape_htmltag($langs->trans("Next")).'"></i></a></li>';
6024 }
6025 if ($afterarrows) {
6026 print '<li class="paginationafterarrows">';
6027 print $afterarrows;
6028 print '</li>';
6029 }
6030 }
6031 print '</ul></div>'."\n";
6032}
6033
6034
6046function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, $html = 0)
6047{
6048 $morelabel = '';
6049
6050 if (preg_match('/%/', $rate)) {
6051 $rate = str_replace('%', '', $rate);
6052 $addpercent = true;
6053 }
6054 $reg = array();
6055 if (preg_match('/\‍((.*)\‍)/', $rate, $reg)) {
6056 $morelabel = ' ('.$reg[1].')';
6057 $rate = preg_replace('/\s*'.preg_quote($morelabel, '/').'/', '', $rate);
6058 $morelabel = ' '.($html ? '<span class="opacitymedium">' : '').'('.$reg[1].')'.($html ? '</span>' : '');
6059 }
6060 if (preg_match('/\*/', $rate)) {
6061 $rate = str_replace('*', '', $rate);
6062 $info_bits |= 1;
6063 }
6064
6065 // If rate is '9/9/9' we don't change it. If rate is '9.000' we apply price()
6066 if (!preg_match('/\//', $rate)) {
6067 $ret = price($rate, 0, '', 0, 0).($addpercent ? '%' : '');
6068 } else {
6069 // TODO Split on / and output with a price2num to have clean numbers without ton of 000.
6070 $ret = $rate.($addpercent ? '%' : '');
6071 }
6072 if (($info_bits & 1) && $usestarfornpr >= 0) {
6073 $ret .= ' *';
6074 }
6075 $ret .= $morelabel;
6076 return $ret;
6077}
6078
6079
6095function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1, $currency_code = '')
6096{
6097 global $langs, $conf;
6098
6099 // Clean parameters
6100 if (empty($amount)) {
6101 $amount = 0; // To have a numeric value if amount not defined or = ''
6102 }
6103 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number)
6104 if ($rounding == -1) {
6105 $rounding = min(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), getDolGlobalString('MAIN_MAX_DECIMALS_TOT'));
6106 }
6107 $nbdecimal = $rounding;
6108
6109 if ($outlangs === 'none') {
6110 // Use international separators
6111 $dec = '.';
6112 $thousand = '';
6113 } else {
6114 // Output separators by default (french)
6115 $dec = ',';
6116 $thousand = ' ';
6117
6118 // If $outlangs not forced, we use use language
6119 if (!is_object($outlangs)) {
6120 $outlangs = $langs;
6121 }
6122
6123 if ($outlangs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6124 $dec = $outlangs->transnoentitiesnoconv("SeparatorDecimal");
6125 }
6126 if ($outlangs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6127 $thousand = $outlangs->transnoentitiesnoconv("SeparatorThousand");
6128 }
6129 if ($thousand == 'None') {
6130 $thousand = '';
6131 } elseif ($thousand == 'Space') {
6132 $thousand = ' ';
6133 }
6134 }
6135 //print "outlangs=".$outlangs->defaultlang." amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6136
6137 //print "amount=".$amount."-";
6138 $amount = str_replace(',', '.', $amount); // should be useless
6139 //print $amount."-";
6140 $datas = explode('.', $amount);
6141 $decpart = isset($datas[1]) ? $datas[1] : '';
6142 $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
6143 //print "decpart=".$decpart."<br>";
6144 $end = '';
6145
6146 // We increase nbdecimal if there is more decimal than asked (to not loose information)
6147 if (dol_strlen($decpart) > $nbdecimal) {
6148 $nbdecimal = dol_strlen($decpart);
6149 }
6150
6151 // If nbdecimal is higher than max to show
6152 $nbdecimalmaxshown = (int) str_replace('...', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'));
6153 if ($trunc && $nbdecimal > $nbdecimalmaxshown) {
6154 $nbdecimal = $nbdecimalmaxshown;
6155 if (preg_match('/\.\.\./i', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'))) {
6156 // If output is truncated, we show ...
6157 $end = '...';
6158 }
6159 }
6160
6161 // If force rounding
6162 if ((string) $forcerounding != '-1') {
6163 if ($forcerounding === 'MU') {
6164 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_UNIT');
6165 } elseif ($forcerounding === 'MT') {
6166 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_TOT');
6167 } elseif ($forcerounding >= 0) {
6168 $nbdecimal = $forcerounding;
6169 }
6170 }
6171
6172 // Format number
6173 $output = number_format($amount, $nbdecimal, $dec, $thousand);
6174 if ($form) {
6175 $output = preg_replace('/\s/', '&nbsp;', $output);
6176 $output = preg_replace('/\'/', '&#039;', $output);
6177 }
6178 // Add symbol of currency if requested
6179 $cursymbolbefore = $cursymbolafter = '';
6180 if ($currency_code && is_object($outlangs)) {
6181 if ($currency_code == 'auto') {
6182 $currency_code = $conf->currency;
6183 }
6184
6185 $listofcurrenciesbefore = array('AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD', 'CRC', 'ZAR');
6186 $listoflanguagesbefore = array('nl_NL');
6187 if (in_array($currency_code, $listofcurrenciesbefore) || in_array($outlangs->defaultlang, $listoflanguagesbefore)) {
6188 $cursymbolbefore .= $outlangs->getCurrencySymbol($currency_code);
6189 } else {
6190 $tmpcur = $outlangs->getCurrencySymbol($currency_code);
6191 $cursymbolafter .= ($tmpcur == $currency_code ? ' '.$tmpcur : $tmpcur);
6192 }
6193 }
6194 $output = $cursymbolbefore.$output.$end.($cursymbolafter ? ' ' : '').$cursymbolafter;
6195
6196 return $output;
6197}
6198
6223function price2num($amount, $rounding = '', $option = 0)
6224{
6225 global $langs, $conf;
6226
6227 // Clean parameters
6228 if (is_null($amount)) {
6229 $amount = '';
6230 }
6231
6232 // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
6233 // Numbers must be '1234.56'
6234 // Decimal delimiter for PHP and database SQL requests must be '.'
6235 $dec = ',';
6236 $thousand = ' ';
6237 if (is_null($langs)) { // $langs is not defined, we use english values.
6238 $dec = '.';
6239 $thousand = ',';
6240 } else {
6241 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6242 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
6243 }
6244 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6245 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
6246 }
6247 }
6248 if ($thousand == 'None') {
6249 $thousand = '';
6250 } elseif ($thousand == 'Space') {
6251 $thousand = ' ';
6252 }
6253 //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6254
6255 // Convert value to universal number format (no thousand separator, '.' as decimal separator)
6256 if ($option != 1) { // If not a PHP number or unknown, we change or clean format
6257 //print "\n".'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'<br>';
6258 if (!is_numeric($amount)) {
6259 $amount = preg_replace('/[a-zA-Z\/\\\*\‍(\‍)<>\_]/', '', $amount);
6260 }
6261
6262 if ($option == 2 && $thousand == '.' && preg_match('/\.(\d\d\d)$/', (string) $amount)) { // It means the . is used as a thousand separator and string come from input data, so 1.123 is 1123
6263 $amount = str_replace($thousand, '', $amount);
6264 }
6265
6266 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6267 // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
6268 // So if number was already a good number, it is converted into local Dolibarr setup.
6269 if (is_numeric($amount)) {
6270 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6271 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6272 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6273 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6274 $amount = number_format($amount, $nbofdec, $dec, $thousand);
6275 }
6276 //print "QQ".$amount."<br>\n";
6277
6278 // Now make replace (the main goal of function)
6279 if ($thousand != ',' && $thousand != '.') {
6280 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6281 }
6282
6283 $amount = str_replace(' ', '', $amount); // To avoid spaces
6284 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6285 $amount = str_replace($dec, '.', $amount);
6286
6287 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6288 }
6289 //print ' XX'.$amount.' '.$rounding;
6290
6291 // Now, $amount is a real PHP float number. We make a rounding if required.
6292 if ($rounding) {
6293 $nbofdectoround = '';
6294 if ($rounding == 'MU') {
6295 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_UNIT;
6296 } elseif ($rounding == 'MT') {
6297 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_TOT;
6298 } elseif ($rounding == 'MS') {
6299 $nbofdectoround = isset($conf->global->MAIN_MAX_DECIMALS_STOCK) ? $conf->global->MAIN_MAX_DECIMALS_STOCK : 5;
6300 } elseif ($rounding == 'CU') {
6301 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), 8); // TODO Use param of currency
6302 } elseif ($rounding == 'CT') {
6303 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_TOT'), 8); // TODO Use param of currency
6304 } elseif (is_numeric($rounding)) {
6305 $nbofdectoround = (int) $rounding;
6306 }
6307
6308 //print " RR".$amount.' - '.$nbofdectoround.'<br>';
6309 if (dol_strlen($nbofdectoround)) {
6310 $amount = round(is_string($amount) ? (float) $amount : $amount, $nbofdectoround); // $nbofdectoround can be 0.
6311 } else {
6312 return 'ErrorBadParameterProvidedToFunction';
6313 }
6314 //print ' SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
6315
6316 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6317 // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
6318 if (is_numeric($amount)) {
6319 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6320 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6321 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6322 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6323 $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
6324 }
6325 //print "TT".$amount.'<br>';
6326
6327 // Always make replace because each math function (like round) replace
6328 // with local values and we want a number that has a SQL string format x.y
6329 if ($thousand != ',' && $thousand != '.') {
6330 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6331 }
6332
6333 $amount = str_replace(' ', '', $amount); // To avoid spaces
6334 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6335 $amount = str_replace($dec, '.', $amount);
6336
6337 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6338 }
6339
6340 return $amount;
6341}
6342
6355function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round = -1, $forceunitoutput = 'no', $use_short_label = 0)
6356{
6357 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
6358
6359 if (($forceunitoutput == 'no' && $dimension < 1 / 10000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -6)) {
6360 $dimension = $dimension * 1000000;
6361 $unit = $unit - 6;
6362 } elseif (($forceunitoutput == 'no' && $dimension < 1 / 10 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -3)) {
6363 $dimension = $dimension * 1000;
6364 $unit = $unit - 3;
6365 } elseif (($forceunitoutput == 'no' && $dimension > 100000000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 6)) {
6366 $dimension = $dimension / 1000000;
6367 $unit = $unit + 6;
6368 } elseif (($forceunitoutput == 'no' && $dimension > 100000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 3)) {
6369 $dimension = $dimension / 1000;
6370 $unit = $unit + 3;
6371 }
6372 // Special case when we want output unit into pound or ounce
6373 /* TODO
6374 if ($unit < 90 && $type == 'weight' && is_numeric($forceunitoutput) && (($forceunitoutput == 98) || ($forceunitoutput == 99))
6375 {
6376 $dimension = // convert dimension from standard unit into ounce or pound
6377 $unit = $forceunitoutput;
6378 }
6379 if ($unit > 90 && $type == 'weight' && is_numeric($forceunitoutput) && $forceunitoutput < 90)
6380 {
6381 $dimension = // convert dimension from standard unit into ounce or pound
6382 $unit = $forceunitoutput;
6383 }*/
6384
6385 $ret = price($dimension, 0, $outputlangs, 0, 0, $round);
6386 $ret .= ' '.measuringUnitString(0, $type, $unit, $use_short_label, $outputlangs);
6387
6388 return $ret;
6389}
6390
6391
6404function get_localtax($vatrate, $local, $thirdparty_buyer = "", $thirdparty_seller = "", $vatnpr = 0)
6405{
6406 global $db, $conf, $mysoc;
6407
6408 if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
6409 $thirdparty_seller = $mysoc;
6410 }
6411
6412 dol_syslog("get_localtax tva=".$vatrate." local=".$local." thirdparty_buyer id=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->id : '')."/country_code=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->country_code : '')." thirdparty_seller id=".$thirdparty_seller->id."/country_code=".$thirdparty_seller->country_code." thirdparty_seller localtax1_assuj=".$thirdparty_seller->localtax1_assuj." thirdparty_seller localtax2_assuj=".$thirdparty_seller->localtax2_assuj);
6413
6414 $vatratecleaned = $vatrate;
6415 $reg = array();
6416 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6417 $vatratecleaned = trim($reg[1]);
6418 $vatratecode = $reg[2];
6419 }
6420
6421 /*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
6422 {
6423 return 0;
6424 }*/
6425
6426 // Some test to guess with no need to make database access
6427 if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
6428 if ($local == 1) {
6429 if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
6430 return 0;
6431 }
6432 if ($thirdparty_seller->id == $mysoc->id) {
6433 if (!$thirdparty_buyer->localtax1_assuj) {
6434 return 0;
6435 }
6436 } else {
6437 if (!$thirdparty_seller->localtax1_assuj) {
6438 return 0;
6439 }
6440 }
6441 }
6442
6443 if ($local == 2) {
6444 //if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
6445 if (!$mysoc->localtax2_assuj) {
6446 return 0; // If main vat is 0, IRPF may be different than 0.
6447 }
6448 if ($thirdparty_seller->id == $mysoc->id) {
6449 if (!$thirdparty_buyer->localtax2_assuj) {
6450 return 0;
6451 }
6452 } else {
6453 if (!$thirdparty_seller->localtax2_assuj) {
6454 return 0;
6455 }
6456 }
6457 }
6458 } else {
6459 if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
6460 return 0;
6461 }
6462 if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
6463 return 0;
6464 }
6465 }
6466
6467 // For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
6468 if (in_array($mysoc->country_code, array('ES'))) {
6469 $conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
6470 }
6471
6472 // Search local taxes
6473 if (getDolGlobalString('MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY')) {
6474 if ($local == 1) {
6475 if ($thirdparty_seller != $mysoc) {
6476 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6477 return $thirdparty_seller->localtax1_value;
6478 }
6479 } else { // i am the seller
6480 if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
6481 return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
6482 }
6483 }
6484 }
6485 if ($local == 2) {
6486 if ($thirdparty_seller != $mysoc) {
6487 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6488 // TODO We should also return value defined on thirdparty only if defined
6489 return $thirdparty_seller->localtax2_value;
6490 }
6491 } else { // i am the seller
6492 if (in_array($mysoc->country_code, array('ES'))) {
6493 return $thirdparty_buyer->localtax2_value;
6494 } else {
6495 return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
6496 }
6497 }
6498 }
6499 }
6500
6501 // By default, search value of local tax on line of common tax
6502 $sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
6503 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6504 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
6505 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6506 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6507 if (!empty($vatratecode)) {
6508 $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
6509 } else {
6510 $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
6511 }
6512
6513 $resql = $db->query($sql);
6514
6515 if ($resql) {
6516 $obj = $db->fetch_object($resql);
6517 if ($obj) {
6518 if ($local == 1) {
6519 return $obj->localtax1;
6520 } elseif ($local == 2) {
6521 return $obj->localtax2;
6522 }
6523 }
6524 }
6525
6526 return 0;
6527}
6528
6529
6538function isOnlyOneLocalTax($local)
6539{
6540 $tax = get_localtax_by_third($local);
6541
6542 $valors = explode(":", $tax);
6543
6544 if (count($valors) > 1) {
6545 return false;
6546 } else {
6547 return true;
6548 }
6549}
6550
6558{
6559 global $db, $mysoc;
6560
6561 $sql = " SELECT t.localtax".$local." as localtax";
6562 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_pays";
6563 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.active = 1 AND t.entity IN (".getEntity('c_tva').") AND t.taux = (";
6564 $sql .= "SELECT MAX(tt.taux) FROM ".MAIN_DB_PREFIX."c_tva as tt INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = tt.fk_pays";
6565 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.entity IN (".getEntity('c_tva').") AND tt.active = 1)";
6566 $sql .= " AND t.localtax".$local."_type <> '0'";
6567 $sql .= " ORDER BY t.rowid DESC";
6568
6569 $resql = $db->query($sql);
6570 if ($resql) {
6571 $obj = $db->fetch_object($resql);
6572 if ($obj) {
6573 return $obj->localtax;
6574 } else {
6575 return '0';
6576 }
6577 }
6578
6579 return 'Error';
6580}
6581
6582
6594function getTaxesFromId($vatrate, $buyer = null, $seller = null, $firstparamisid = 1)
6595{
6596 global $db, $mysoc;
6597
6598 dol_syslog("getTaxesFromId vat id or rate = ".$vatrate);
6599
6600 // Search local taxes
6601 $sql = "SELECT t.rowid, t.code, t.taux as rate, t.recuperableonly as npr, t.accountancy_code_sell, t.accountancy_code_buy,";
6602 $sql .= " t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type";
6603 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6604 if ($firstparamisid) {
6605 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6606 } else {
6607 $vatratecleaned = $vatrate;
6608 $vatratecode = '';
6609 $reg = array();
6610 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6611 $vatratecleaned = $reg[1];
6612 $vatratecode = $reg[2];
6613 }
6614
6615 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6616 /*if ($mysoc->country_code == 'ES') $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($buyer->country_code)."'"; // vat in spain use the buyer country ??
6617 else $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";*/
6618 $sql .= " WHERE t.fk_pays = c.rowid";
6619 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) {
6620 $sql .= " AND c.code = '".$db->escape($buyer->country_code)."'";
6621 } else {
6622 $sql .= " AND c.code = '".$db->escape($seller->country_code)."'";
6623 }
6624 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6625 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6626 if ($vatratecode) {
6627 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6628 }
6629 }
6630
6631 $resql = $db->query($sql);
6632 if ($resql) {
6633 $obj = $db->fetch_object($resql);
6634 if ($obj) {
6635 return array(
6636 'rowid'=>$obj->rowid,
6637 'code'=>$obj->code,
6638 'rate'=>$obj->rate,
6639 'localtax1'=>$obj->localtax1,
6640 'localtax1_type'=>$obj->localtax1_type,
6641 'localtax2'=>$obj->localtax2,
6642 'localtax2_type'=>$obj->localtax2_type,
6643 'npr'=>$obj->npr,
6644 'accountancy_code_sell'=>$obj->accountancy_code_sell,
6645 'accountancy_code_buy'=>$obj->accountancy_code_buy
6646 );
6647 } else {
6648 return array();
6649 }
6650 } else {
6651 dol_print_error($db);
6652 }
6653
6654 return array();
6655}
6656
6673function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid = 0)
6674{
6675 global $db, $mysoc;
6676
6677 dol_syslog("getLocalTaxesFromRate vatrate=".$vatrate." local=".$local);
6678
6679 // Search local taxes
6680 $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";
6681 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6682 if ($firstparamisid) {
6683 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6684 } else {
6685 $vatratecleaned = $vatrate;
6686 $vatratecode = '';
6687 $reg = array();
6688 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "x.x (yy)"
6689 $vatratecleaned = $reg[1];
6690 $vatratecode = $reg[2];
6691 }
6692
6693 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6694 if (!empty($mysoc) && $mysoc->country_code == 'ES') {
6695 $countrycodetouse = ((empty($buyer) || empty($buyer->country_code)) ? $mysoc->country_code : $buyer->country_code);
6696 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'"; // local tax in spain use the buyer country ??
6697 } else {
6698 $countrycodetouse = ((empty($seller) || empty($seller->country_code)) ? $mysoc->country_code : $seller->country_code);
6699 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'";
6700 }
6701 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6702 if ($vatratecode) {
6703 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6704 }
6705 }
6706
6707 $resql = $db->query($sql);
6708 if ($resql) {
6709 $obj = $db->fetch_object($resql);
6710
6711 if ($obj) {
6712 $vateratestring = $obj->rate.($obj->code ? ' ('.$obj->code.')' : '');
6713
6714 if ($local == 1) {
6715 return array($obj->localtax1_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6716 } elseif ($local == 2) {
6717 return array($obj->localtax2_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6718 } else {
6719 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);
6720 }
6721 }
6722 }
6723
6724 return array();
6725}
6726
6737function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice = 0)
6738{
6739 global $db, $conf, $mysoc;
6740
6741 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6742
6743 $ret = 0;
6744 $found = 0;
6745
6746 if ($idprod > 0) {
6747 // Load product
6748 $product = new Product($db);
6749 $product->fetch($idprod);
6750
6751 if ($mysoc->country_code == $thirdpartytouse->country_code) {
6752 // If country to consider is ours
6753 if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object
6754 $result = $product->get_buyprice($idprodfournprice, 0, 0, 0);
6755 if ($result > 0) {
6756 $ret = $product->vatrate_supplier;
6757 if ($product->default_vat_code_supplier) {
6758 $ret .= ' ('.$product->default_vat_code_supplier.')';
6759 }
6760 $found = 1;
6761 }
6762 }
6763 if (!$found) {
6764 $ret = $product->tva_tx; // Default sales vat of product
6765 if ($product->default_vat_code) {
6766 $ret .= ' ('.$product->default_vat_code.')';
6767 }
6768 $found = 1;
6769 }
6770 } else {
6771 // TODO Read default product vat according to product and an other countrycode.
6772 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6773 }
6774 }
6775
6776 if (!$found) {
6777 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
6778 // 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).
6779 $sql = "SELECT t.taux as vat_rate, t.code as default_vat_code";
6780 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6781 $sql .= " WHERE t.active = 1 AND t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdpartytouse->country_code)."'";
6782 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6783 $sql .= " ORDER BY t.use_default DESC, t.taux DESC, t.code ASC, t.recuperableonly ASC";
6784 $sql .= $db->plimit(1);
6785
6786 $resql = $db->query($sql);
6787 if ($resql) {
6788 $obj = $db->fetch_object($resql);
6789 if ($obj) {
6790 $ret = $obj->vat_rate;
6791 if ($obj->default_vat_code) {
6792 $ret .= ' ('.$obj->default_vat_code.')';
6793 }
6794 }
6795 $db->free($resql);
6796 } else {
6797 dol_print_error($db);
6798 }
6799 } else {
6800 // Forced value if autodetect fails. MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS can be
6801 // '1.23'
6802 // or '1.23 (CODE)'
6803 $defaulttx = '';
6804 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
6805 $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6806 }
6807 /*if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6808 $defaultcode = $reg[1];
6809 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6810 }*/
6811
6812 $ret = $defaulttx;
6813 }
6814 }
6815
6816 dol_syslog("get_product_vat_for_country: ret=".$ret);
6817 return $ret;
6818}
6819
6829function get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
6830{
6831 global $db, $mysoc;
6832
6833 if (!class_exists('Product')) {
6834 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6835 }
6836
6837 $ret = 0;
6838 $found = 0;
6839
6840 if ($idprod > 0) {
6841 // Load product
6842 $product = new Product($db);
6843 $result = $product->fetch($idprod);
6844
6845 if ($mysoc->country_code == $thirdpartytouse->country_code) { // If selling country is ours
6846 /* Not defined yet, so we don't use this
6847 if ($local==1) $ret=$product->localtax1_tx;
6848 elseif ($local==2) $ret=$product->localtax2_tx;
6849 $found=1;
6850 */
6851 } else {
6852 // TODO Read default product vat according to product and another countrycode.
6853 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6854 }
6855 }
6856
6857 if (!$found) {
6858 // If vat of product for the country not found or not defined, we return higher vat of country.
6859 $sql = "SELECT taux as vat_rate, localtax1, localtax2";
6860 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6861 $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code='".$db->escape($thirdpartytouse->country_code)."'";
6862 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6863 $sql .= " ORDER BY t.taux DESC, t.recuperableonly ASC";
6864 $sql .= $db->plimit(1);
6865
6866 $resql = $db->query($sql);
6867 if ($resql) {
6868 $obj = $db->fetch_object($resql);
6869 if ($obj) {
6870 if ($local == 1) {
6871 $ret = $obj->localtax1;
6872 } elseif ($local == 2) {
6873 $ret = $obj->localtax2;
6874 }
6875 }
6876 } else {
6877 dol_print_error($db);
6878 }
6879 }
6880
6881 dol_syslog("get_product_localtax_for_country: ret=".$ret);
6882 return $ret;
6883}
6884
6901function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6902{
6903 global $conf;
6904
6905 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6906
6907 // Note: possible values for tva_assuj are 0/1 or franchise/reel
6908 $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;
6909
6910 $seller_country_code = $thirdparty_seller->country_code;
6911 $seller_in_cee = isInEEC($thirdparty_seller);
6912
6913 $buyer_country_code = $thirdparty_buyer->country_code;
6914 $buyer_in_cee = isInEEC($thirdparty_buyer);
6915
6916 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 : ''));
6917
6918 // 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)
6919 // we use the buyer VAT.
6920 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) {
6921 if ($seller_in_cee && $buyer_in_cee) {
6922 $isacompany = $thirdparty_buyer->isACompany();
6923 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6924 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6925 if (!isValidVATID($thirdparty_buyer)) {
6926 $isacompany = 0;
6927 }
6928 }
6929
6930 if (!$isacompany) {
6931 //print 'VATRULE 0';
6932 return get_product_vat_for_country($idprod, $thirdparty_buyer, $idprodfournprice);
6933 }
6934 }
6935 }
6936
6937 // If seller does not use VAT, default VAT is 0. End of rule.
6938 if (!$seller_use_vat) {
6939 //print 'VATRULE 1';
6940 return 0;
6941 }
6942
6943 // If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule.
6944 if (($seller_country_code == $buyer_country_code)
6945 || (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC')))) { // Warning ->country_code not always defined
6946 //print 'VATRULE 2';
6947 $tmpvat = get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6948
6949 if ($seller_country_code == 'IN' && getDolGlobalString('MAIN_SALETAX_AUTOSWITCH_I_CS_FOR_INDIA')) {
6950 // Special case for india.
6951 //print 'VATRULE 2b';
6952 $reg = array();
6953 if (preg_match('/C+S-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id != $thirdparty_buyer->state_id) {
6954 // we must revert the C+S into I
6955 $tmpvat = str_replace("C+S", "I", $tmpvat);
6956 } elseif (preg_match('/I-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id == $thirdparty_buyer->state_id) {
6957 // we must revert the I into C+S
6958 $tmpvat = str_replace("I", "C+S", $tmpvat);
6959 }
6960 }
6961
6962 return $tmpvat;
6963 }
6964
6965 // 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.
6966 // 'VATRULE 3' - Not supported
6967
6968 // If (seller and buyer in the European Community) and (buyer = individual) then VAT by default = VAT of the product sold. End of rule
6969 // If (seller and buyer in European Community) and (buyer = company) then VAT by default=0. End of rule
6970 if (($seller_in_cee && $buyer_in_cee)) {
6971 $isacompany = $thirdparty_buyer->isACompany();
6972 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6973 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6974 if (!isValidVATID($thirdparty_buyer)) {
6975 $isacompany = 0;
6976 }
6977 }
6978
6979 if (!$isacompany) {
6980 //print 'VATRULE 4';
6981 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6982 } else {
6983 //print 'VATRULE 5';
6984 return 0;
6985 }
6986 }
6987
6988 // 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
6989 // I don't see any use case that need this rule.
6990 if (getDolGlobalString('MAIN_USE_VAT_OF_PRODUCT_FOR_INDIVIDUAL_CUSTOMER_OUT_OF_EEC') && empty($buyer_in_cee)) {
6991 $isacompany = $thirdparty_buyer->isACompany();
6992 if (!$isacompany) {
6993 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6994 //print 'VATRULE extra';
6995 }
6996 }
6997
6998 // Otherwise the VAT proposed by default=0. End of rule.
6999 // Rem: This means that at least one of the 2 is outside the European Community and the country differs
7000 //print 'VATRULE 6';
7001 return 0;
7002}
7003
7004
7015function get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
7016{
7017 global $db;
7018
7019 if ($idprodfournprice > 0) {
7020 if (!class_exists('ProductFournisseur')) {
7021 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
7022 }
7023 $prodprice = new ProductFournisseur($db);
7024 $prodprice->fetch_product_fournisseur_price($idprodfournprice);
7025 return $prodprice->fourn_tva_npr;
7026 } elseif ($idprod > 0) {
7027 if (!class_exists('Product')) {
7028 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
7029 }
7030 $prod = new Product($db);
7031 $prod->fetch($idprod);
7032 return $prod->tva_npr;
7033 }
7034
7035 return 0;
7036}
7037
7051function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod = 0)
7052{
7053 global $mysoc;
7054
7055 if (!is_object($thirdparty_seller)) {
7056 return -1;
7057 }
7058 if (!is_object($thirdparty_buyer)) {
7059 return -1;
7060 }
7061
7062 if ($local == 1) { // Localtax 1
7063 if ($mysoc->country_code == 'ES') {
7064 if (is_numeric($thirdparty_buyer->localtax1_assuj) && !$thirdparty_buyer->localtax1_assuj) {
7065 return 0;
7066 }
7067 } else {
7068 // Si vendeur non assujeti a Localtax1, localtax1 par default=0
7069 if (is_numeric($thirdparty_seller->localtax1_assuj) && !$thirdparty_seller->localtax1_assuj) {
7070 return 0;
7071 }
7072 if (!is_numeric($thirdparty_seller->localtax1_assuj) && $thirdparty_seller->localtax1_assuj == 'localtax1off') {
7073 return 0;
7074 }
7075 }
7076 } elseif ($local == 2) { //I Localtax 2
7077 // Si vendeur non assujeti a Localtax2, localtax2 par default=0
7078 if (is_numeric($thirdparty_seller->localtax2_assuj) && !$thirdparty_seller->localtax2_assuj) {
7079 return 0;
7080 }
7081 if (!is_numeric($thirdparty_seller->localtax2_assuj) && $thirdparty_seller->localtax2_assuj == 'localtax2off') {
7082 return 0;
7083 }
7084 }
7085
7086 if ($thirdparty_seller->country_code == $thirdparty_buyer->country_code) {
7087 return get_product_localtax_for_country($idprod, $local, $thirdparty_seller);
7088 }
7089
7090 return 0;
7091}
7092
7101function yn($yesno, $case = 1, $color = 0)
7102{
7103 global $langs;
7104
7105 $result = 'unknown';
7106 $classname = '';
7107 if ($yesno == 1 || (isset($yesno) && (strtolower($yesno) == 'yes' || strtolower($yesno) == 'true'))) { // A mettre avant test sur no a cause du == 0
7108 $result = $langs->trans('yes');
7109 if ($case == 1 || $case == 3) {
7110 $result = $langs->trans("Yes");
7111 }
7112 if ($case == 2) {
7113 $result = '<input type="checkbox" value="1" checked disabled>';
7114 }
7115 if ($case == 3) {
7116 $result = '<input type="checkbox" value="1" checked disabled> '.$result;
7117 }
7118
7119 $classname = 'ok';
7120 } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') {
7121 $result = $langs->trans("no");
7122 if ($case == 1 || $case == 3) {
7123 $result = $langs->trans("No");
7124 }
7125 if ($case == 2) {
7126 $result = '<input type="checkbox" value="0" disabled>';
7127 }
7128 if ($case == 3) {
7129 $result = '<input type="checkbox" value="0" disabled> '.$result;
7130 }
7131
7132 if ($color == 2) {
7133 $classname = 'ok';
7134 } else {
7135 $classname = 'error';
7136 }
7137 }
7138 if ($color) {
7139 return '<span class="'.$classname.'">'.$result.'</span>';
7140 }
7141 return $result;
7142}
7143
7159function get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart = '')
7160{
7161 global $conf;
7162
7163 if (empty($modulepart) && !empty($object->module)) {
7164 $modulepart = $object->module;
7165 }
7166
7167 $path = '';
7168
7169 $arrayforoldpath = array('cheque', 'category', 'holiday', 'supplier_invoice', 'invoice_supplier', 'mailing', 'supplier_payment');
7170 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
7171 $arrayforoldpath[] = 'product';
7172 }
7173 if (!empty($level) && in_array($modulepart, $arrayforoldpath)) {
7174 // This part should be removed once all code is using "get_exdir" to forge path, with parameter $object and $modulepart provided.
7175 if (empty($alpha)) {
7176 $num = preg_replace('/([^0-9])/i', '', $num);
7177 } else {
7178 $num = preg_replace('/^.*\-/i', '', $num);
7179 }
7180 $num = substr("000".$num, -$level);
7181 if ($level == 1) {
7182 $path = substr($num, 0, 1);
7183 }
7184 if ($level == 2) {
7185 $path = substr($num, 1, 1).'/'.substr($num, 0, 1);
7186 }
7187 if ($level == 3) {
7188 $path = substr($num, 2, 1).'/'.substr($num, 1, 1).'/'.substr($num, 0, 1);
7189 }
7190 } else {
7191 // We will enhance here a common way of forging path for document storage.
7192 // In a future, we may distribute directories on several levels depending on setup and object.
7193 // Here, $object->id, $object->ref and $modulepart are required.
7194 //var_dump($modulepart);
7195 $path = dol_sanitizeFileName(empty($object->ref) ? (string) $object->id : $object->ref);
7196 }
7197
7198 if (empty($withoutslash) && !empty($path)) {
7199 $path .= '/';
7200 }
7201
7202 return $path;
7203}
7204
7213function dol_mkdir($dir, $dataroot = '', $newmask = '')
7214{
7215 global $conf;
7216
7217 dol_syslog("functions.lib::dol_mkdir: dir=".$dir, LOG_INFO);
7218
7219 $dir_osencoded = dol_osencode($dir);
7220 if (@is_dir($dir_osencoded)) {
7221 return 0;
7222 }
7223
7224 $nberr = 0;
7225 $nbcreated = 0;
7226
7227 $ccdir = '';
7228 if (!empty($dataroot)) {
7229 // Remove data root from loop
7230 $dir = str_replace($dataroot.'/', '', $dir);
7231 $ccdir = $dataroot.'/';
7232 }
7233
7234 $cdir = explode("/", $dir);
7235 $num = count($cdir);
7236 for ($i = 0; $i < $num; $i++) {
7237 if ($i > 0) {
7238 $ccdir .= '/'.$cdir[$i];
7239 } else {
7240 $ccdir .= $cdir[$i];
7241 }
7242 $regs = array();
7243 if (preg_match("/^.:$/", $ccdir, $regs)) {
7244 continue; // Si chemin Windows incomplet, on poursuit par rep suivant
7245 }
7246
7247 // Attention, le is_dir() peut echouer bien que le rep existe.
7248 // (ex selon config de open_basedir)
7249 if ($ccdir) {
7250 $ccdir_osencoded = dol_osencode($ccdir);
7251 if (!@is_dir($ccdir_osencoded)) {
7252 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.", LOG_DEBUG);
7253
7254 umask(0);
7255 $dirmaskdec = octdec((string) $newmask);
7256 if (empty($newmask)) {
7257 $dirmaskdec = !getDolGlobalString('MAIN_UMASK') ? octdec('0755') : octdec($conf->global->MAIN_UMASK);
7258 }
7259 $dirmaskdec |= octdec('0111'); // Set x bit required for directories
7260 if (!@mkdir($ccdir_osencoded, $dirmaskdec)) {
7261 // Si le is_dir a renvoye une fausse info, alors on passe ici.
7262 dol_syslog("functions.lib::dol_mkdir: Fails to create directory '".$ccdir."' or directory already exists.", LOG_WARNING);
7263 $nberr++;
7264 } else {
7265 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' created", LOG_DEBUG);
7266 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignore
7267 $nbcreated++;
7268 }
7269 } else {
7270 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignores
7271 }
7272 }
7273 }
7274 return ($nberr ? -$nberr : $nbcreated);
7275}
7276
7277
7285function dolChmod($filepath, $newmask = '')
7286{
7287 global $conf;
7288
7289 if (!empty($newmask)) {
7290 @chmod($filepath, octdec($newmask));
7291 } elseif (getDolGlobalString('MAIN_UMASK')) {
7292 @chmod($filepath, octdec($conf->global->MAIN_UMASK));
7293 }
7294}
7295
7296
7303{
7304 return '<span class="fieldrequired">*</span>';
7305}
7306
7307
7324function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = 'UTF-8', $strip_tags = 0, $removedoublespaces = 1)
7325{
7326 if (is_null($stringtoclean)) {
7327 return '';
7328 }
7329
7330 if ($removelinefeed == 2) {
7331 $stringtoclean = preg_replace('/<br[^>]*>(\n|\r)+/ims', '<br>', $stringtoclean);
7332 }
7333 $temp = preg_replace('/<br[^>]*>/i', "\n", $stringtoclean);
7334
7335 // 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)
7336 $temp = dol_html_entity_decode($temp, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7337
7338 $temp = str_replace('< ', '__ltspace__', $temp);
7339
7340 if ($strip_tags) {
7341 $temp = strip_tags($temp);
7342 } else {
7343 // 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).
7344 $pattern = "/<[^<>]+>/";
7345 // Example of $temp: <a href="/myurl" title="<u>A title</u>">0000-021</a>
7346 // pass 1 - $temp after pass 1: <a href="/myurl" title="A title">0000-021
7347 // pass 2 - $temp after pass 2: 0000-021
7348 $tempbis = $temp;
7349 do {
7350 $temp = $tempbis;
7351 $tempbis = str_replace('<>', '', $temp); // No reason to have this into a text, except if value is to try bypass the next html cleaning
7352 $tempbis = preg_replace($pattern, '', $tempbis);
7353 //$idowhile++; print $temp.'-'.$tempbis."\n"; if ($idowhile > 100) break;
7354 } while ($tempbis != $temp);
7355
7356 $temp = $tempbis;
7357
7358 // 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).
7359 $temp = preg_replace('/<+([a-z]+)/i', '\1', $temp);
7360 }
7361
7362 $temp = dol_html_entity_decode($temp, ENT_COMPAT, $pagecodeto);
7363
7364 // Remove also carriage returns
7365 if ($removelinefeed == 1) {
7366 $temp = str_replace(array("\r\n", "\r", "\n"), " ", $temp);
7367 }
7368
7369 // And double quotes
7370 if ($removedoublespaces) {
7371 while (strpos($temp, " ")) {
7372 $temp = str_replace(" ", " ", $temp);
7373 }
7374 }
7375
7376 $temp = str_replace('__ltspace__', '< ', $temp);
7377
7378 return trim($temp);
7379}
7380
7396function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1, $cleanalsojavascript = 0, $allowiframe = 0, $allowed_tags = array(), $allowlink = 0)
7397{
7398 if (empty($allowed_tags)) {
7399 $allowed_tags = array(
7400 "html", "head", "meta", "body", "article", "a", "abbr", "b", "blockquote", "br", "cite", "div", "dl", "dd", "dt", "em", "font", "img", "ins", "hr", "i", "li",
7401 "ol", "p", "q", "s", "span", "strike", "strong", "title", "table", "tr", "th", "td", "u", "ul", "sup", "sub", "blockquote", "pre", "h1", "h2", "h3", "h4", "h5", "h6",
7402 "header", "footer", "nav", "section", "menu", "menuitem" // html5 tags
7403 );
7404 }
7405 $allowed_tags[] = "comment"; // this tags is added to manage comment <!--...--> that are replaced into <comment>...</comment>
7406 if ($allowiframe) {
7407 if (!in_array('iframe', $allowed_tags)) {
7408 $allowed_tags[] = "iframe";
7409 }
7410 }
7411 if ($allowlink) {
7412 if (!in_array('link', $allowed_tags)) {
7413 $allowed_tags[] = "link";
7414 }
7415 }
7416
7417 $allowed_tags_string = join("><", $allowed_tags);
7418 $allowed_tags_string = '<'.$allowed_tags_string.'>';
7419
7420 $stringtoclean = str_replace('<!DOCTYPE html>', '__!DOCTYPE_HTML__', $stringtoclean); // Replace DOCTYPE to avoid to have it removed by the strip_tags
7421
7422 $stringtoclean = dol_string_nounprintableascii($stringtoclean, 0);
7423
7424 //$stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
7425 $stringtoclean = preg_replace('/<!--([^>]*)-->/', '<comment>\1</comment>', $stringtoclean);
7426
7427 $stringtoclean = preg_replace('/&colon;/i', ':', $stringtoclean);
7428 $stringtoclean = preg_replace('/&#58;|&#0+58|&#x3A/i', '', $stringtoclean); // refused string ':' encoded (no reason to have a : encoded like this) to disable 'javascript:...'
7429
7430 $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
7431
7432 if ($cleanalsosomestyles) { // Clean for remaining html tags
7433 $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
7434 }
7435 if ($removeclassattribute) { // Clean for remaining html tags
7436 $temp = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $temp);
7437 }
7438
7439 // Remove 'javascript:' that we should not find into a text with
7440 // 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)).
7441 if ($cleanalsojavascript) {
7442 $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);
7443 }
7444
7445 $temp = str_replace('__!DOCTYPE_HTML__', '<!DOCTYPE html>', $temp); // Restore the DOCTYPE
7446
7447 $temp = preg_replace('/<comment>([^>]*)<\/comment>/', '<!--\1-->', $temp); // Restore html comments
7448
7449
7450 return $temp;
7451}
7452
7453
7465function dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes = null)
7466{
7467 if (is_null($allowed_attributes)) {
7468 $allowed_attributes = array(
7469 "allow", "allowfullscreen", "alt", "class", "contenteditable", "data-html", "frameborder", "height", "href", "id", "name", "src", "style", "target", "title", "width",
7470 // HTML5
7471 "header", "footer", "nav", "section", "menu", "menuitem"
7472 );
7473 }
7474
7475 if (class_exists('DOMDocument') && !empty($stringtoclean)) {
7476 $stringtoclean = '<?xml encoding="UTF-8"><html><body>'.$stringtoclean.'</body></html>';
7477
7478 // Warning: loadHTML does not support HTML5 on old libxml versions.
7479 $dom = new DOMDocument(null, 'UTF-8');
7480 $dom->loadHTML($stringtoclean, LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7481
7482 if (is_object($dom)) {
7483 for ($els = $dom->getElementsByTagname('*'), $i = $els->length - 1; $i >= 0; $i--) {
7484 for ($attrs = $els->item($i)->attributes, $ii = $attrs->length - 1; $ii >= 0; $ii--) {
7485 //var_dump($attrs->item($ii));
7486 if (!empty($attrs->item($ii)->name)) {
7487 if (! in_array($attrs->item($ii)->name, $allowed_attributes)) {
7488 // Delete attribute if not into allowed_attributes
7489 $els->item($i)->removeAttribute($attrs->item($ii)->name);
7490 } elseif (in_array($attrs->item($ii)->name, array('style'))) {
7491 // If attribute is 'style'
7492 $valuetoclean = $attrs->item($ii)->value;
7493
7494 if (isset($valuetoclean)) {
7495 do {
7496 $oldvaluetoclean = $valuetoclean;
7497 $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments
7498 $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean);
7499 if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags.
7500 $valuetoclean = preg_replace('/display\s*:/mi', '', $valuetoclean);
7501 $valuetoclean = preg_replace('/z-index\s*:/mi', '', $valuetoclean);
7502 $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*:/mi', '', $valuetoclean);
7503 }
7504
7505 // We do not allow logout|passwordforgotten.php and action= into the content of a "style" tag
7506 $valuetoclean = preg_replace('/(logout|passwordforgotten)\.php/mi', '', $valuetoclean);
7507 $valuetoclean = preg_replace('/action=/mi', '', $valuetoclean);
7508 } while ($oldvaluetoclean != $valuetoclean);
7509 }
7510
7511 $attrs->item($ii)->value = $valuetoclean;
7512 }
7513 }
7514 }
7515 }
7516 }
7517
7518 $return = $dom->saveHTML(); // This may add a LF at end of lines, so we will trim later
7519 //$return = '<html><body>aaaa</p>bb<p>ssdd</p>'."\n<p>aaa</p>aa<p>bb</p>";
7520
7521 $return = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $return);
7522 $return = preg_replace('/^'.preg_quote('<html><body>', '/').'/', '', $return);
7523 $return = preg_replace('/'.preg_quote('</body></html>', '/').'$/', '', $return);
7524 return trim($return);
7525 } else {
7526 return $stringtoclean;
7527 }
7528}
7529
7541function dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags = array('textarea'), $cleanalsosomestyles = 0)
7542{
7543 $temp = $stringtoclean;
7544 foreach ($disallowed_tags as $tagtoremove) {
7545 $temp = preg_replace('/<\/?'.$tagtoremove.'>/', '', $temp);
7546 $temp = preg_replace('/<\/?'.$tagtoremove.'\s+[^>]*>/', '', $temp);
7547 }
7548
7549 if ($cleanalsosomestyles) {
7550 $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
7551 }
7552
7553 return $temp;
7554}
7555
7556
7566function dolGetFirstLineOfText($text, $nboflines = 1, $charset = 'UTF-8')
7567{
7568 if ($nboflines == 1) {
7569 if (dol_textishtml($text)) {
7570 $firstline = preg_replace('/<br[^>]*>.*$/s', '', $text); // The s pattern modifier means the . can match newline characters
7571 $firstline = preg_replace('/<div[^>]*>.*$/s', '', $firstline); // The s pattern modifier means the . can match newline characters
7572 } else {
7573 if (isset($text)) {
7574 $firstline = preg_replace('/[\n\r].*/', '', $text);
7575 } else {
7576 $firstline = '';
7577 }
7578 }
7579 return $firstline.(isset($firstline) && isset($text) && (strlen($firstline) != strlen($text)) ? '...' : '');
7580 } else {
7581 $ishtml = 0;
7582 if (dol_textishtml($text)) {
7583 $text = preg_replace('/\n/', '', $text);
7584 $ishtml = 1;
7585 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7586 } else {
7587 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7588 }
7589
7590 $text = strtr($text, $repTable);
7591 if ($charset == 'UTF-8') {
7592 $pattern = '/(<br[^>]*>)/Uu';
7593 } else {
7594 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7595 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7596 }
7597 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7598
7599 $firstline = '';
7600 $i = 0;
7601 $countline = 0;
7602 $lastaddediscontent = 1;
7603 while ($countline < $nboflines && isset($a[$i])) {
7604 if (preg_match('/<br[^>]*>/', $a[$i])) {
7605 if (array_key_exists($i+1, $a) && !empty($a[$i+1])) {
7606 $firstline .= ($ishtml ? "<br>\n" : "\n");
7607 // Is it a br for a new line of after a printed line ?
7608 if (!$lastaddediscontent) {
7609 $countline++;
7610 }
7611 $lastaddediscontent = 0;
7612 }
7613 } else {
7614 $firstline .= $a[$i];
7615 $lastaddediscontent = 1;
7616 $countline++;
7617 }
7618 $i++;
7619 }
7620
7621 $adddots = (isset($a[$i]) && (!preg_match('/<br[^>]*>/', $a[$i]) || (array_key_exists($i+1, $a) && !empty($a[$i+1]))));
7622 //unset($a);
7623 $ret = $firstline.($adddots ? '...' : '');
7624 //exit;
7625 return $ret;
7626 }
7627}
7628
7629
7641function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false)
7642{
7643 if (is_null($stringtoencode)) {
7644 return '';
7645 }
7646
7647 if (!$nl2brmode) {
7648 return nl2br($stringtoencode, $forxml);
7649 } else {
7650 $ret = preg_replace('/(\r\n|\r|\n)/i', ($forxml ? '<br />' : '<br>'), $stringtoencode);
7651 return $ret;
7652 }
7653}
7654
7664function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = 'restricthtml')
7665{
7666 if (empty($nouseofiframesandbox) && getDolGlobalString('MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS')) {
7667 // TODO using sandbox on inline html content is not possible yet with current browsers
7668 //$s = '<iframe class="iframewithsandbox" sandbox><html><body>';
7669 //$s .= $stringtoencode;
7670 //$s .= '</body></html></iframe>';
7671 return $stringtoencode;
7672 } else {
7673 $out = $stringtoencode;
7674
7675 do {
7676 $oldstringtoclean = $out;
7677
7678 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML') && $check != 'restricthtmlallowunvalid') {
7679 try {
7680 libxml_use_internal_errors(false); // Avoid to fill memory with xml errors
7681 if (LIBXML_VERSION < 20900) {
7682 // Avoid load of external entities (security problem).
7683 // Required only if LIBXML_VERSION < 20900
7684 libxml_disable_entity_loader(true);
7685 }
7686
7687 $dom = new DOMDocument();
7688 // Add a trick to solve pb with text without parent tag
7689 // like '<h1>Foo</h1><p>bar</p>' that wrongly ends up, without the trick, with '<h1>Foo<p>bar</p></h1>'
7690 // like 'abc' that wrongly ends up, without the trick, with '<p>abc</p>'
7691
7692 if (dol_textishtml($out)) {
7693 $out = '<?xml encoding="UTF-8"><div class="tricktoremove">'.$out.'</div>';
7694 } else {
7695 $out = '<?xml encoding="UTF-8"><div class="tricktoremove">'.dol_nl2br($out).'</div>';
7696 }
7697 $dom->loadHTML($out, LIBXML_HTML_NODEFDTD | LIBXML_ERR_NONE | LIBXML_HTML_NOIMPLIED | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_NOERROR | LIBXML_NOXMLDECL);
7698 $out = trim($dom->saveHTML());
7699
7700 // Remove the trick added to solve pb with text without parent tag
7701 $out = preg_replace('/^<\?xml encoding="UTF-8"><div class="tricktoremove">/', '', $out);
7702 $out = preg_replace('/<\/div>$/', '', $out);
7703 } catch (Exception $e) {
7704 // If error, invalid HTML string with no way to clean it
7705 //print $e->getMessage();
7706 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
7707 }
7708 }
7709
7710 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY') && $check != 'restricthtmlallowunvalid') {
7711 try {
7712 // Try cleaning using tidy
7713 if (extension_loaded('tidy') && class_exists("tidy")) {
7714 //print "aaa".$out."\n";
7715
7716 // See options at https://tidy.sourceforge.net/docs/quickref.html
7717 $config = array(
7718 'clean' => false,
7719 'quote-marks' => false, // do not replace " that are used for real text content (not a string symbol for html attribute) into &quot;
7720 'doctype' => 'strict',
7721 'show-body-only' => true,
7722 "indent-attributes" => false,
7723 "vertical-space" => false,
7724 'ident' => false,
7725 "wrap" => 0
7726 // HTML5 tags
7727 //'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',
7728 //'new-blocklevel-tags' => 'footer header section menu menuitem'
7729 //'new-empty-tags' => 'command embed keygen source track wbr',
7730 //'new-inline-tags' => 'audio command datalist embed keygen mark menuitem meter output progress source time video wbr',
7731 );
7732
7733 // Tidy
7734 $tidy = new tidy();
7735 $out = $tidy->repairString($out, $config, 'utf8');
7736
7737 //print "xxx".$out;exit;
7738 }
7739 } catch (Exception $e) {
7740 // If error, invalid HTML string with no way to clean it
7741 //print $e->getMessage();
7742 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
7743 }
7744 }
7745
7746 //Clear ZERO WIDTH NO-BREAK SPACE, ZERO WIDTH SPACE, ZERO WIDTH JOINER
7747 $out = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $out);
7748
7749 // Clean some html entities that are useless so text is cleaner
7750 $out = preg_replace('/&(tab|newline);/i', ' ', $out);
7751
7752 // Ckeditor use the numeric entitic for apostrophe so we force it to text entity (all other special chars are
7753 // encoded using text entities) so we can then exclude all numeric entities.
7754 $out = preg_replace('/&#39;/i', '&apos;', $out);
7755
7756 // 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).
7757 // 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
7758 // using a non coventionnel way to be encoded, to not have them sanitized just after)
7759 $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) {
7760 return realCharForNumericEntities($m);
7761 }, $out);
7762
7763
7764 // Now we remove all remaining HTML entities starting with a number. We don't want such entities.
7765 $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'.
7766
7767 // Keep only some html tags and remove also some 'javascript:' strings
7768 $out = dol_string_onlythesehtmltags($out, 0, ($check == 'restricthtmlallowclass' ? 0 : 1), 1);
7769
7770 // Keep only some html attributes and exclude non expected HTML attributes and clean content of some attributes (keep only alt=, title=...).
7771 if (getDolGlobalString('MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES')) {
7773 }
7774
7775 // Restore entity &apos; into &#39; (restricthtml is for html content so we can use html entity)
7776 $out = preg_replace('/&apos;/i', "&#39;", $out);
7777 } while ($oldstringtoclean != $out);
7778
7779 // Check the limit of external links that are automatically executed in a Rich text content. We count:
7780 // '<img' to avoid <img src="http...">, we can only accept "<img src="data:..."
7781 // 'url(' to avoid inline style like background: url(http...
7782 // '<link' to avoid <link href="http...">
7783 $reg = array();
7784 $tmpout = preg_replace('/<img src="data:/mi', '<__IMG_SRC_DATA__ src="data:', $out);
7785 preg_match_all('/(<img|url\‍(|<link)/i', $tmpout, $reg);
7786 $nblinks = count($reg[0]);
7787 if ($nblinks > getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) {
7788 $out = 'ErrorTooManyLinksIntoHTMLString';
7789 }
7790
7791 if (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 2 || $check == 'restricthtmlnolink') {
7792 if ($nblinks > 0) {
7793 $out = 'ErrorHTMLLinksNotAllowed';
7794 }
7795 } elseif (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 1) {
7796 $nblinks = 0;
7797 // Loop on each url in src= and url(
7798 $pattern = '/src=["\']?(http[^"\']+)|url\‍(["\']?(http[^\‍)]+)/';
7799
7800 $matches = array();
7801 if (preg_match_all($pattern, $out, $matches)) {
7802 // URLs are into $matches[1]
7803 $urls = $matches[1];
7804
7805 // Affiche les URLs
7806 foreach ($urls as $url) {
7807 $nblinks++;
7808 echo "Found url = ".$url . "\n";
7809 }
7810 if ($nblinks > 0) {
7811 $out = 'ErrorHTMLExternalLinksNotAllowed';
7812 }
7813 }
7814 }
7815
7816 return $out;
7817 }
7818}
7819
7841function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UTF-8', $removelasteolbr = 1)
7842{
7843 if (is_null($stringtoencode)) {
7844 return '';
7845 }
7846
7847 $newstring = $stringtoencode;
7848 if (dol_textishtml($stringtoencode)) { // Check if text is already HTML or not
7849 $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.
7850 if ($removelasteolbr) {
7851 $newstring = preg_replace('/<br>$/i', '', $newstring); // Remove last <br> (remove only last one)
7852 }
7853 $newstring = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $newstring);
7854 $newstring = strtr($newstring, array('&'=>'__and__', '<'=>'__lt__', '>'=>'__gt__', '"'=>'__dquot__'));
7855 $newstring = dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom); // Make entity encoding
7856 $newstring = strtr($newstring, array('__and__'=>'&', '__lt__'=>'<', '__gt__'=>'>', '__dquot__'=>'"'));
7857 } else {
7858 if ($removelasteolbr) {
7859 $newstring = preg_replace('/(\r\n|\r|\n)$/i', '', $newstring); // Remove last \n (may remove several)
7860 }
7861 $newstring = dol_nl2br(dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom), $nl2brmode);
7862 }
7863 // Other substitutions that htmlentities does not do
7864 //$newstring=str_replace(chr(128),'&euro;',$newstring); // 128 = 0x80. Not in html entity table. // Seems useles with TCPDF. Make bug with UTF8 languages
7865 return $newstring;
7866}
7867
7875function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8')
7876{
7877 $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7878 $ret = preg_replace('/'."\r\n".'<br(\s[\sa-zA-Z_="]*)?\/?>/i', "<br>", $ret);
7879 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\r\n".'/i', "\r\n", $ret);
7880 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\n".'/i', "\n", $ret);
7881 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', "\n", $ret);
7882 return $ret;
7883}
7884
7891function dol_htmlcleanlastbr($stringtodecode)
7892{
7893 $ret = preg_replace('/&nbsp;$/i', "", $stringtodecode); // Because wysiwyg editor may add a &nbsp; at end of last line
7894 $ret = preg_replace('/(<br>|<br(\s[\sa-zA-Z_="]*)?\/?>|'."\n".'|'."\r".')+$/i', "", $ret);
7895 return $ret;
7896}
7897
7907function dol_html_entity_decode($a, $b, $c = 'UTF-8', $keepsomeentities = 0)
7908{
7909 $newstring = $a;
7910 if ($keepsomeentities) {
7911 $newstring = strtr($newstring, array('&amp;'=>'__andamp__', '&lt;'=>'__andlt__', '&gt;'=>'__andgt__', '"'=>'__dquot__'));
7912 }
7913 $newstring = html_entity_decode((string) $newstring, (int) $b, (string) $c);
7914 if ($keepsomeentities) {
7915 $newstring = strtr($newstring, array('__andamp__'=>'&amp;', '__andlt__'=>'&lt;', '__andgt__'=>'&gt;', '__dquot__'=>'"'));
7916 }
7917 return $newstring;
7918}
7919
7931function dol_htmlentities($string, $flags = ENT_QUOTES|ENT_SUBSTITUTE, $encoding = 'UTF-8', $double_encode = false)
7932{
7933 return htmlentities($string, $flags, $encoding, $double_encode);
7934}
7935
7947function dol_string_is_good_iso($s, $clean = 0)
7948{
7949 $len = dol_strlen($s);
7950 $out = '';
7951 $ok = 1;
7952 for ($scursor = 0; $scursor < $len; $scursor++) {
7953 $ordchar = ord($s[$scursor]);
7954 //print $scursor.'-'.$ordchar.'<br>';
7955 if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) {
7956 $ok = 0;
7957 break;
7958 } elseif ($ordchar > 126 && $ordchar < 160) {
7959 $ok = 0;
7960 break;
7961 } elseif ($clean) {
7962 $out .= $s[$scursor];
7963 }
7964 }
7965 if ($clean) {
7966 return $out;
7967 }
7968 return $ok;
7969}
7970
7979function dol_nboflines($s, $maxchar = 0)
7980{
7981 if ($s == '') {
7982 return 0;
7983 }
7984 $arraystring = explode("\n", $s);
7985 $nb = count($arraystring);
7986
7987 return $nb;
7988}
7989
7990
8000function dol_nboflines_bis($text, $maxlinesize = 0, $charset = 'UTF-8')
8001{
8002 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
8003 if (dol_textishtml($text)) {
8004 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
8005 }
8006
8007 $text = strtr($text, $repTable);
8008 if ($charset == 'UTF-8') {
8009 $pattern = '/(<br[^>]*>)/Uu';
8010 } else {
8011 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
8012 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
8013 }
8014 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
8015
8016 $nblines = (int) floor((count($a) + 1) / 2);
8017 // count possible auto line breaks
8018 if ($maxlinesize) {
8019 foreach ($a as $line) {
8020 if (dol_strlen($line) > $maxlinesize) {
8021 //$line_dec = html_entity_decode(strip_tags($line));
8022 $line_dec = html_entity_decode($line);
8023 if (dol_strlen($line_dec) > $maxlinesize) {
8024 $line_dec = wordwrap($line_dec, $maxlinesize, '\n', true);
8025 $nblines += substr_count($line_dec, '\n');
8026 }
8027 }
8028 }
8029 }
8030
8031 unset($a);
8032 return $nblines;
8033}
8034
8043function dol_textishtml($msg, $option = 0)
8044{
8045 if (is_null($msg)) {
8046 return false;
8047 }
8048
8049 if ($option == 1) {
8050 if (preg_match('/<html/i', $msg)) {
8051 return true;
8052 } elseif (preg_match('/<body/i', $msg)) {
8053 return true;
8054 } elseif (preg_match('/<\/textarea/i', $msg)) {
8055 return true;
8056 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8057 return true;
8058 } elseif (preg_match('/<br/i', $msg)) {
8059 return true;
8060 }
8061 return false;
8062 } else {
8063 // Remove all urls because 'http://aa?param1=abc&amp;param2=def' must not be used inside detection
8064 $msg = preg_replace('/https?:\/\/[^"\'\s]+/i', '', $msg);
8065 if (preg_match('/<html/i', $msg)) {
8066 return true;
8067 } elseif (preg_match('/<body/i', $msg)) {
8068 return true;
8069 } elseif (preg_match('/<\/textarea/i', $msg)) {
8070 return true;
8071 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8072 return true;
8073 } elseif (preg_match('/<(br|hr)\/>/i', $msg)) {
8074 return true;
8075 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)>/i', $msg)) {
8076 return true;
8077 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)\s+[^<>\/]*\/?>/i', $msg)) {
8078 return true;
8079 } elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i', $msg)) {
8080 return true; // must accept <img src="http://example.com/aaa.png" />
8081 } elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i', $msg)) {
8082 return true; // must accept <a href="http://example.com/aaa.png" />
8083 } elseif (preg_match('/<h[0-9]>/i', $msg)) {
8084 return true;
8085 } elseif (preg_match('/&[A-Z0-9]{1,6};/i', $msg)) {
8086 // TODO If content is 'A link https://aaa?param=abc&amp;param2=def', it return true but must be false
8087 return true; // Html entities names (http://www.w3schools.com/tags/ref_entities.asp)
8088 } elseif (preg_match('/&#[0-9]{2,3};/i', $msg)) {
8089 return true; // Html entities numbers (http://www.w3schools.com/tags/ref_entities.asp)
8090 }
8091
8092 return false;
8093 }
8094}
8095
8110function dol_concatdesc($text1, $text2, $forxml = false, $invert = false)
8111{
8112 if (!empty($invert)) {
8113 $tmp = $text1;
8114 $text1 = $text2;
8115 $text2 = $tmp;
8116 }
8117
8118 $ret = '';
8119 $ret .= (!dol_textishtml($text1) && dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text1, 0, 1, '', 1), 0, $forxml) : $text1;
8120 $ret .= (!empty($text1) && !empty($text2)) ? ((dol_textishtml($text1) || dol_textishtml($text2)) ? ($forxml ? "<br >\n" : "<br>\n") : "\n") : "";
8121 $ret .= (dol_textishtml($text1) && !dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text2, 0, 1, '', 1), 0, $forxml) : $text2;
8122 return $ret;
8123}
8124
8125
8126
8138function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null)
8139{
8140 global $db, $conf, $mysoc, $user, $extrafields;
8141
8142 $substitutionarray = array();
8143
8144 if ((empty($exclude) || !in_array('user', $exclude)) && (empty($include) || in_array('user', $include))) {
8145 // Add SIGNATURE into substitutionarray first, so, when we will make the substitution,
8146 // this will include signature content first and then replace var found into content of signature
8147 //var_dump($onlykey);
8148 $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()
8149 $usersignature = $user->signature;
8150 $substitutionarray = array_merge($substitutionarray, array(
8151 '__SENDEREMAIL_SIGNATURE__' => (string) ((!getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc('SignatureFromTheSelectedSenderProfile', 30) : $emailsendersignature) : ''),
8152 '__USER_SIGNATURE__' => (string) (($usersignature && !getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc(dol_string_nohtmltag($usersignature), 30) : $usersignature) : '')
8153 ));
8154
8155 if (is_object($user)) {
8156 $substitutionarray = array_merge($substitutionarray, array(
8157 '__USER_ID__' => (string) $user->id,
8158 '__USER_LOGIN__' => (string) $user->login,
8159 '__USER_EMAIL__' => (string) $user->email,
8160 '__USER_PHONE__' => (string) dol_print_phone($user->office_phone, '', 0, 0, '', " ", '', '', -1),
8161 '__USER_PHONEPRO__' => (string) dol_print_phone($user->user_mobile, '', 0, 0, '', " ", '', '', -1),
8162 '__USER_PHONEMOBILE__' => (string) dol_print_phone($user->personal_mobile, '', 0, 0, '', " ", '', '', -1),
8163 '__USER_FAX__' => (string) $user->office_fax,
8164 '__USER_LASTNAME__' => (string) $user->lastname,
8165 '__USER_FIRSTNAME__' => (string) $user->firstname,
8166 '__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
8167 '__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
8168 '__USER_JOB__' => (string) $user->job,
8169 '__USER_REMOTE_IP__' => (string) getUserRemoteIP(),
8170 '__USER_VCARD_URL__' => (string) $user->getOnlineVirtualCardUrl('', 'external')
8171 ));
8172 }
8173 }
8174 if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc) && (empty($include) || in_array('mycompany', $include))) {
8175 $substitutionarray = array_merge($substitutionarray, array(
8176 '__MYCOMPANY_NAME__' => $mysoc->name,
8177 '__MYCOMPANY_EMAIL__' => $mysoc->email,
8178 '__MYCOMPANY_PHONE__' => dol_print_phone($mysoc->phone, '', 0, 0, '', " ", '', '', -1),
8179 '__MYCOMPANY_FAX__' => dol_print_phone($mysoc->fax, '', 0, 0, '', " ", '', '', -1),
8180 '__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
8181 '__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
8182 '__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
8183 '__MYCOMPANY_PROFID4__' => $mysoc->idprof4,
8184 '__MYCOMPANY_PROFID5__' => $mysoc->idprof5,
8185 '__MYCOMPANY_PROFID6__' => $mysoc->idprof6,
8186 '__MYCOMPANY_CAPITAL__' => $mysoc->capital,
8187 '__MYCOMPANY_FULLADDRESS__' => (method_exists($mysoc, 'getFullAddress') ? $mysoc->getFullAddress(1, ', ') : ''), // $mysoc may be stdClass
8188 '__MYCOMPANY_ADDRESS__' => $mysoc->address,
8189 '__MYCOMPANY_ZIP__' => $mysoc->zip,
8190 '__MYCOMPANY_TOWN__' => $mysoc->town,
8191 '__MYCOMPANY_COUNTRY__' => $mysoc->country,
8192 '__MYCOMPANY_COUNTRY_ID__' => $mysoc->country_id,
8193 '__MYCOMPANY_COUNTRY_CODE__' => $mysoc->country_code,
8194 '__MYCOMPANY_CURRENCY_CODE__' => $conf->currency
8195 ));
8196 }
8197
8198 if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude)) && (empty($include) || in_array('object', $include))) {
8199 if ($onlykey) {
8200 $substitutionarray['__ID__'] = '__ID__';
8201 $substitutionarray['__REF__'] = '__REF__';
8202 $substitutionarray['__NEWREF__'] = '__NEWREF__';
8203 $substitutionarray['__LABEL__'] = '__LABEL__';
8204 $substitutionarray['__REF_CLIENT__'] = '__REF_CLIENT__';
8205 $substitutionarray['__REF_SUPPLIER__'] = '__REF_SUPPLIER__';
8206 $substitutionarray['__NOTE_PUBLIC__'] = '__NOTE_PUBLIC__';
8207 $substitutionarray['__NOTE_PRIVATE__'] = '__NOTE_PRIVATE__';
8208 $substitutionarray['__EXTRAFIELD_XXX__'] = '__EXTRAFIELD_XXX__';
8209
8210 if (isModEnabled("societe")) { // Most objects are concerned
8211 $substitutionarray['__THIRDPARTY_ID__'] = '__THIRDPARTY_ID__';
8212 $substitutionarray['__THIRDPARTY_NAME__'] = '__THIRDPARTY_NAME__';
8213 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = '__THIRDPARTY_NAME_ALIAS__';
8214 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = '__THIRDPARTY_CODE_CLIENT__';
8215 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = '__THIRDPARTY_CODE_FOURNISSEUR__';
8216 $substitutionarray['__THIRDPARTY_EMAIL__'] = '__THIRDPARTY_EMAIL__';
8217 $substitutionarray['__THIRDPARTY_PHONE__'] = '__THIRDPARTY_PHONE__';
8218 $substitutionarray['__THIRDPARTY_FAX__'] = '__THIRDPARTY_FAX__';
8219 $substitutionarray['__THIRDPARTY_ADDRESS__'] = '__THIRDPARTY_ADDRESS__';
8220 $substitutionarray['__THIRDPARTY_ZIP__'] = '__THIRDPARTY_ZIP__';
8221 $substitutionarray['__THIRDPARTY_TOWN__'] = '__THIRDPARTY_TOWN__';
8222 $substitutionarray['__THIRDPARTY_IDPROF1__'] = '__THIRDPARTY_IDPROF1__';
8223 $substitutionarray['__THIRDPARTY_IDPROF2__'] = '__THIRDPARTY_IDPROF2__';
8224 $substitutionarray['__THIRDPARTY_IDPROF3__'] = '__THIRDPARTY_IDPROF3__';
8225 $substitutionarray['__THIRDPARTY_IDPROF4__'] = '__THIRDPARTY_IDPROF4__';
8226 $substitutionarray['__THIRDPARTY_IDPROF5__'] = '__THIRDPARTY_IDPROF5__';
8227 $substitutionarray['__THIRDPARTY_IDPROF6__'] = '__THIRDPARTY_IDPROF6__';
8228 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = '__THIRDPARTY_TVAINTRA__';
8229 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = '__THIRDPARTY_NOTE_PUBLIC__';
8230 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = '__THIRDPARTY_NOTE_PRIVATE__';
8231 }
8232 if (isModEnabled('adherent') && (!is_object($object) || $object->element == 'adherent') && (empty($exclude) || !in_array('member', $exclude)) && (empty($include) || in_array('member', $include))) {
8233 $substitutionarray['__MEMBER_ID__'] = '__MEMBER_ID__';
8234 $substitutionarray['__MEMBER_CIVILITY__'] = '__MEMBER_CIVILITY__';
8235 $substitutionarray['__MEMBER_FIRSTNAME__'] = '__MEMBER_FIRSTNAME__';
8236 $substitutionarray['__MEMBER_LASTNAME__'] = '__MEMBER_LASTNAME__';
8237 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = 'Login and pass of the external user account';
8238 /*$substitutionarray['__MEMBER_NOTE_PUBLIC__'] = '__MEMBER_NOTE_PUBLIC__';
8239 $substitutionarray['__MEMBER_NOTE_PRIVATE__'] = '__MEMBER_NOTE_PRIVATE__';*/
8240 }
8241 // add variables subtitutions ticket
8242 if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket') && (empty($exclude) || !in_array('ticket', $exclude)) && (empty($include) || in_array('ticket', $include))) {
8243 $substitutionarray['__TICKET_TRACKID__'] = '__TICKET_TRACKID__';
8244 $substitutionarray['__TICKET_SUBJECT__'] = '__TICKET_SUBJECT__';
8245 $substitutionarray['__TICKET_TYPE__'] = '__TICKET_TYPE__';
8246 $substitutionarray['__TICKET_SEVERITY__'] = '__TICKET_SEVERITY__';
8247 $substitutionarray['__TICKET_CATEGORY__'] = '__TICKET_CATEGORY__';
8248 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = '__TICKET_ANALYTIC_CODE__';
8249 $substitutionarray['__TICKET_MESSAGE__'] = '__TICKET_MESSAGE__';
8250 $substitutionarray['__TICKET_PROGRESSION__'] = '__TICKET_PROGRESSION__';
8251 $substitutionarray['__TICKET_USER_ASSIGN__'] = '__TICKET_USER_ASSIGN__';
8252 }
8253
8254 if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature') && (empty($exclude) || !in_array('recruitment', $exclude)) && (empty($include) || in_array('recruitment', $include))) {
8255 $substitutionarray['__CANDIDATE_FULLNAME__'] = '__CANDIDATE_FULLNAME__';
8256 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = '__CANDIDATE_FIRSTNAME__';
8257 $substitutionarray['__CANDIDATE_LASTNAME__'] = '__CANDIDATE_LASTNAME__';
8258 }
8259 if (isModEnabled('project') && (empty($exclude) || !in_array('project', $exclude)) && (empty($include) || in_array('project', $include))) { // Most objects
8260 $substitutionarray['__PROJECT_ID__'] = '__PROJECT_ID__';
8261 $substitutionarray['__PROJECT_REF__'] = '__PROJECT_REF__';
8262 $substitutionarray['__PROJECT_NAME__'] = '__PROJECT_NAME__';
8263 /*$substitutionarray['__PROJECT_NOTE_PUBLIC__'] = '__PROJECT_NOTE_PUBLIC__';
8264 $substitutionarray['__PROJECT_NOTE_PRIVATE__'] = '__PROJECT_NOTE_PRIVATE__';*/
8265 }
8266 if (isModEnabled('contrat') && (!is_object($object) || $object->element == 'contract') && (empty($exclude) || !in_array('contract', $exclude)) && (empty($include) || in_array('contract', $include))) {
8267 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = 'Highest date planned for a service start';
8268 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = 'Highest date and hour planned for service start';
8269 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = 'Lowest data for planned expiration of service';
8270 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = 'Lowest date and hour for planned expiration of service';
8271 }
8272 if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal') && (empty($exclude) || !in_array('propal', $exclude)) && (empty($include) || in_array('propal', $include))) {
8273 $substitutionarray['__ONLINE_SIGN_URL__'] = 'ToOfferALinkForOnlineSignature';
8274 }
8275 if (isModEnabled("ficheinter") && (!is_object($object) || $object->element == 'fichinter') && (empty($exclude) || !in_array('intervention', $exclude)) && (empty($include) || in_array('intervention', $include))) {
8276 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = 'ToOfferALinkForOnlineSignature';
8277 }
8278 $substitutionarray['__ONLINE_PAYMENT_URL__'] = 'UrlToPayOnlineIfApplicable';
8279 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = 'TextAndUrlToPayOnlineIfApplicable';
8280 $substitutionarray['__SECUREKEYPAYMENT__'] = 'Security key (if key is not unique per record)';
8281 $substitutionarray['__SECUREKEYPAYMENT_MEMBER__'] = 'Security key for payment on a member subscription (one key per member)';
8282 $substitutionarray['__SECUREKEYPAYMENT_ORDER__'] = 'Security key for payment on an order';
8283 $substitutionarray['__SECUREKEYPAYMENT_INVOICE__'] = 'Security key for payment on an invoice';
8284 $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'Security key for payment on a service of a contract';
8285
8286 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = 'Direct download url of a proposal';
8287 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = 'Direct download url of an order';
8288 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = 'Direct download url of an invoice';
8289 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = 'Direct download url of a contract';
8290 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = 'Direct download url of a supplier proposal';
8291
8292 if (isModEnabled("expedition") && (!is_object($object) || $object->element == 'shipping')) {
8293 $substitutionarray['__SHIPPINGTRACKNUM__'] = 'Shipping tracking number';
8294 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = 'Shipping tracking url';
8295 $substitutionarray['__SHIPPINGMETHOD__'] = 'Shipping method';
8296 }
8297 if (isModEnabled("reception") && (!is_object($object) || $object->element == 'reception')) {
8298 $substitutionarray['__RECEPTIONTRACKNUM__'] = 'Shippin tracking number of shipment';
8299 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = 'Shipping tracking url';
8300 }
8301 } else {
8302 $substitutionarray['__ID__'] = $object->id;
8303 $substitutionarray['__REF__'] = $object->ref;
8304 $substitutionarray['__NEWREF__'] = $object->newref;
8305 $substitutionarray['__LABEL__'] = (isset($object->label) ? $object->label : (isset($object->title) ? $object->title : null));
8306 $substitutionarray['__REF_CLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8307 $substitutionarray['__REF_SUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8308 $substitutionarray['__NOTE_PUBLIC__'] = (isset($object->note_public) ? $object->note_public : null);
8309 $substitutionarray['__NOTE_PRIVATE__'] = (isset($object->note_private) ? $object->note_private : null);
8310 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, 'day', 0, $outputlangs) : '');
8311 $substitutionarray['__DATE_DELIVERY_DAY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%d") : '');
8312 $substitutionarray['__DATE_DELIVERY_DAY_TEXT__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%A") : '');
8313 $substitutionarray['__DATE_DELIVERY_MON__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%m") : '');
8314 $substitutionarray['__DATE_DELIVERY_MON_TEXT__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%b") : '');
8315 $substitutionarray['__DATE_DELIVERY_YEAR__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%Y") : '');
8316 $substitutionarray['__DATE_DELIVERY_HH__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%H") : '');
8317 $substitutionarray['__DATE_DELIVERY_MM__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%M") : '');
8318 $substitutionarray['__DATE_DELIVERY_SS__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%S") : '');
8319
8320 // For backward compatibility (deprecated)
8321 $substitutionarray['__REFCLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8322 $substitutionarray['__REFSUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8323 $substitutionarray['__SUPPLIER_ORDER_DATE_DELIVERY__'] = (isset($object->delivery_date) ? dol_print_date($object->delivery_date, 'day', 0, $outputlangs) : '');
8324 $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 : '')) : '');
8325 $substitutionarray['__EXPIRATION_DATE__'] = (isset($object->fin_validite) ? dol_print_date($object->fin_validite, 'daytext') : '');
8326
8327 if (is_object($object) && ($object->element == 'adherent' || $object->element == 'member') && $object->id > 0) {
8328 $birthday = (empty($object->birth) ? '' : dol_print_date($object->birth, 'day'));
8329
8330 $substitutionarray['__MEMBER_ID__'] = (isset($object->id) ? $object->id : '');
8331 if (method_exists($object, 'getCivilityLabel')) {
8332 $substitutionarray['__MEMBER_CIVILITY__'] = $object->getCivilityLabel();
8333 }
8334 $substitutionarray['__MEMBER_FIRSTNAME__'] = (isset($object->firstname) ? $object->firstname : '');
8335 $substitutionarray['__MEMBER_LASTNAME__'] = (isset($object->lastname) ? $object->lastname : '');
8336 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = '';
8337 if (method_exists($object, 'getFullName')) {
8338 $substitutionarray['__MEMBER_FULLNAME__'] = $object->getFullName($outputlangs);
8339 }
8340 $substitutionarray['__MEMBER_COMPANY__'] = (isset($object->societe) ? $object->societe : '');
8341 $substitutionarray['__MEMBER_ADDRESS__'] = (isset($object->address) ? $object->address : '');
8342 $substitutionarray['__MEMBER_ZIP__'] = (isset($object->zip) ? $object->zip : '');
8343 $substitutionarray['__MEMBER_TOWN__'] = (isset($object->town) ? $object->town : '');
8344 $substitutionarray['__MEMBER_COUNTRY__'] = (isset($object->country) ? $object->country : '');
8345 $substitutionarray['__MEMBER_EMAIL__'] = (isset($object->email) ? $object->email : '');
8346 $substitutionarray['__MEMBER_BIRTH__'] = (isset($birthday) ? $birthday : '');
8347 $substitutionarray['__MEMBER_PHOTO__'] = (isset($object->photo) ? $object->photo : '');
8348 $substitutionarray['__MEMBER_LOGIN__'] = (isset($object->login) ? $object->login : '');
8349 $substitutionarray['__MEMBER_PASSWORD__'] = (isset($object->pass) ? $object->pass : '');
8350 $substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? dol_print_phone($object->phone) : '');
8351 $substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? dol_print_phone($object->phone_perso) : '');
8352 $substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? dol_print_phone($object->phone_mobile) : '');
8353 $substitutionarray['__MEMBER_TYPE__'] = (isset($object->type) ? $object->type : '');
8354 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__'] = dol_print_date($object->first_subscription_date, 'day');
8355 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = (isset($object->first_subscription_date_start) ? dol_print_date($object->first_subscription_date_start, 'day') : '');
8356 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END__'] = (isset($object->first_subscription_date_end) ? dol_print_date($object->first_subscription_date_end, 'day') : '');
8357 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE__'] = dol_print_date($object->last_subscription_date, 'day');
8358 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->last_subscription_date_start, 'day');
8359 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END__'] = dol_print_date($object->last_subscription_date_end, 'day');
8360 }
8361
8362 if (is_object($object) && $object->element == 'societe') {
8363 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object) ? $object->id : '');
8364 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object) ? $object->name : '');
8365 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object) ? $object->name_alias : '');
8366 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object) ? $object->code_client : '');
8367 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object) ? $object->code_fournisseur : '');
8368 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object) ? $object->email : '');
8369 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? dol_print_phone($object->phone) : '');
8370 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? dol_print_phone($object->fax) : '');
8371 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object) ? $object->address : '');
8372 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object) ? $object->zip : '');
8373 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object) ? $object->town : '');
8374 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object) ? $object->country_id : '');
8375 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object) ? $object->country_code : '');
8376 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object) ? $object->idprof1 : '');
8377 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object) ? $object->idprof2 : '');
8378 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object) ? $object->idprof3 : '');
8379 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object) ? $object->idprof4 : '');
8380 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object) ? $object->idprof5 : '');
8381 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object) ? $object->idprof6 : '');
8382 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object) ? $object->tva_intra : '');
8383 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_public) : '');
8384 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_private) : '');
8385 } elseif (is_object($object->thirdparty)) {
8386 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->id : '');
8387 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object->thirdparty) ? $object->thirdparty->name : '');
8388 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object->thirdparty) ? $object->thirdparty->name_alias : '');
8389 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_client : '');
8390 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_fournisseur : '');
8391 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object->thirdparty) ? $object->thirdparty->email : '');
8392 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->phone) : '');
8393 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->fax) : '');
8394 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object->thirdparty) ? $object->thirdparty->address : '');
8395 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object->thirdparty) ? $object->thirdparty->zip : '');
8396 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object->thirdparty) ? $object->thirdparty->town : '');
8397 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_id : '');
8398 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_code : '');
8399 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof1 : '');
8400 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof2 : '');
8401 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof3 : '');
8402 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof4 : '');
8403 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof5 : '');
8404 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof6 : '');
8405 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object->thirdparty) ? $object->thirdparty->tva_intra : '');
8406 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_public) : '');
8407 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_private) : '');
8408 }
8409
8410 if (is_object($object) && $object->element == 'recruitmentcandidature') {
8411 $substitutionarray['__CANDIDATE_FULLNAME__'] = $object->getFullName($outputlangs);
8412 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8413 $substitutionarray['__CANDIDATE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8414 }
8415 if (is_object($object) && $object->element == 'conferenceorboothattendee') {
8416 $substitutionarray['__ATTENDEE_FULLNAME__'] = $object->getFullName($outputlangs);
8417 $substitutionarray['__ATTENDEE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8418 $substitutionarray['__ATTENDEE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8419 }
8420
8421 if (is_object($object) && $object->element == 'project') {
8422 $substitutionarray['__PROJECT_ID__'] = $object->id;
8423 $substitutionarray['__PROJECT_REF__'] = $object->ref;
8424 $substitutionarray['__PROJECT_NAME__'] = $object->title;
8425 } elseif (is_object($object)) {
8426 $project = null;
8427 if (!empty($object->project)) {
8428 $project = $object->project;
8429 } elseif (!empty($object->projet)) { // Deprecated, for backward compatibility
8430 $project = $object->projet;
8431 }
8432 if (!is_null($project) && is_object($project)) {
8433 $substitutionarray['__PROJECT_ID__'] = $project->id;
8434 $substitutionarray['__PROJECT_REF__'] = $project->ref;
8435 $substitutionarray['__PROJECT_NAME__'] = $project->title;
8436 } else {
8437 // can substitute variables for project : uses lazy load in "make_substitutions" method
8438 $project_id = 0;
8439 if (!empty($object->fk_project) && $object->fk_project > 0) {
8440 $project_id = $object->fk_project;
8441 } elseif (!empty($object->fk_projet) && $object->fk_projet > 0) {
8442 $project_id = $object->fk_project;
8443 }
8444 if ($project_id > 0) {
8445 // path:class:method:id
8446 $substitutionarray['__PROJECT_ID__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8447 $substitutionarray['__PROJECT_REF__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8448 $substitutionarray['__PROJECT_NAME__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8449 }
8450 }
8451 }
8452
8453 if (is_object($object) && $object->element == 'shipping') {
8454 $substitutionarray['__SHIPPINGTRACKNUM__'] = $object->tracking_number;
8455 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = $object->tracking_url;
8456 $substitutionarray['__SHIPPINGMETHOD__'] = $object->shipping_method;
8457 }
8458 if (is_object($object) && $object->element == 'reception') {
8459 $substitutionarray['__RECEPTIONTRACKNUM__'] = $object->tracking_number;
8460 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = $object->tracking_url;
8461 }
8462
8463 if (is_object($object) && $object->element == 'contrat' && $object->id > 0 && is_array($object->lines)) {
8464 $dateplannedstart = '';
8465 $datenextexpiration = '';
8466 foreach ($object->lines as $line) {
8467 if ($line->date_start > $dateplannedstart) {
8468 $dateplannedstart = $line->date_start;
8469 }
8470 if ($line->statut == 4 && $line->date_end && (!$datenextexpiration || $line->date_end < $datenextexpiration)) {
8471 $datenextexpiration = $line->date_end;
8472 }
8473 }
8474 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = dol_print_date($dateplannedstart, 'day');
8475 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = dol_print_date($dateplannedstart, 'standard');
8476 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = dol_print_date($datenextexpiration, 'day');
8477 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = dol_print_date($datenextexpiration, 'standard');
8478 }
8479 // add substition variable for ticket
8480 if (is_object($object) && $object->element == 'ticket') {
8481 $substitutionarray['__TICKET_TRACKID__'] = $object->track_id;
8482 $substitutionarray['__REF__'] = $object->ref;
8483 $substitutionarray['__TICKET_SUBJECT__'] = $object->subject;
8484 $substitutionarray['__TICKET_TYPE__'] = $object->type_code;
8485 $substitutionarray['__TICKET_SEVERITY__'] = $object->severity_code;
8486 $substitutionarray['__TICKET_CATEGORY__'] = $object->category_code; // For backward compatibility
8487 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = $object->category_code;
8488 $substitutionarray['__TICKET_MESSAGE__'] = $object->message;
8489 $substitutionarray['__TICKET_PROGRESSION__'] = $object->progress;
8490 $userstat = new User($db);
8491 if ($object->fk_user_assign > 0) {
8492 $userstat->fetch($object->fk_user_assign);
8493 $substitutionarray['__TICKET_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8494 }
8495
8496 if ($object->fk_user_create > 0) {
8497 $userstat->fetch($object->fk_user_create);
8498 $substitutionarray['__USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8499 }
8500 }
8501
8502 // Create dynamic tags for __EXTRAFIELD_FIELD__
8503 if ($object->table_element && $object->id > 0) {
8504 if (!is_object($extrafields)) {
8505 $extrafields = new ExtraFields($db);
8506 }
8507 $extrafields->fetch_name_optionals_label($object->table_element, true);
8508
8509 if ($object->fetch_optionals() > 0) {
8510 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) {
8511 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
8512 if ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
8513 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_date($object->array_options['options_'.$key], 'day');
8514 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = dol_print_date($object->array_options['options_'.$key], 'day', 'tzserver', $outputlangs);
8515 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = dol_print_date($object->array_options['options_'.$key], 'dayrfc');
8516 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'datetime') {
8517 $datetime = $object->array_options['options_'.$key];
8518 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour') : '');
8519 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : '');
8520 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_DAY_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'day', 'tzserver', $outputlangs) : '');
8521 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : '');
8522 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'phone') {
8523 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_phone($object->array_options['options_'.$key]);
8524 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
8525 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = $object->array_options['options_'.$key];
8526 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATED__'] = price($object->array_options['options_'.$key]);
8527 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] != 'separator') {
8528 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = !empty($object->array_options['options_'.$key]) ? $object->array_options['options_'.$key] : '';
8529 }
8530 }
8531 }
8532 }
8533 }
8534
8535 // Complete substitution array with the url to make online payment
8536 $paymenturl = '';
8537 if (empty($substitutionarray['__REF__'])) {
8538 $paymenturl = '';
8539 } else {
8540 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
8541 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
8542 $outputlangs->loadLangs(array('paypal', 'other'));
8543
8544 $amounttouse = 0;
8545 $typeforonlinepayment = 'free';
8546 if (is_object($object) && $object->element == 'commande') {
8547 $typeforonlinepayment = 'order';
8548 }
8549 if (is_object($object) && $object->element == 'facture') {
8550 $typeforonlinepayment = 'invoice';
8551 }
8552 if (is_object($object) && $object->element == 'member') {
8553 $typeforonlinepayment = 'member';
8554 if (!empty($object->last_subscription_amount)) {
8555 $amounttouse = $object->last_subscription_amount;
8556 }
8557 }
8558 if (is_object($object) && $object->element == 'contrat') {
8559 $typeforonlinepayment = 'contract';
8560 }
8561 if (is_object($object) && $object->element == 'fichinter') {
8562 $typeforonlinepayment = 'ficheinter';
8563 }
8564
8565 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__'], $amounttouse);
8566 $paymenturl = $url;
8567 }
8568
8569 if ($object->id > 0) {
8570 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ? str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : '');
8571 $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl;
8572
8573 if (getDolGlobalString('PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'propal') {
8574 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8575 } else {
8576 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = '';
8577 }
8578 if (getDolGlobalString('ORDER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'commande') {
8579 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = $object->getLastMainDocLink($object->element);
8580 } else {
8581 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = '';
8582 }
8583 if (getDolGlobalString('INVOICE_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'facture') {
8584 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = $object->getLastMainDocLink($object->element);
8585 } else {
8586 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = '';
8587 }
8588 if (getDolGlobalString('CONTRACT_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'contrat') {
8589 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = $object->getLastMainDocLink($object->element);
8590 } else {
8591 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = '';
8592 }
8593 if (getDolGlobalString('FICHINTER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'fichinter') {
8594 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = $object->getLastMainDocLink($object->element);
8595 } else {
8596 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = '';
8597 }
8598 if (getDolGlobalString('SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'supplier_proposal') {
8599 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8600 } else {
8601 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = '';
8602 }
8603
8604 if (is_object($object) && $object->element == 'propal') {
8605 $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id;
8606 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8607 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref);
8608 }
8609 if (is_object($object) && $object->element == 'commande') {
8610 $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id;
8611 }
8612 if (is_object($object) && $object->element == 'facture') {
8613 $substitutionarray['__URL_INVOICE__'] = DOL_MAIN_URL_ROOT."/compta/facture/card.php?id=".$object->id;
8614 }
8615 if (is_object($object) && $object->element == 'contrat') {
8616 $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id;
8617 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8618 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref);
8619 }
8620 if (is_object($object) && $object->element == 'fichinter') {
8621 $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id;
8622 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8623 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref);
8624 }
8625 if (is_object($object) && $object->element == 'supplier_proposal') {
8626 $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id;
8627 }
8628 if (is_object($object) && $object->element == 'shipping') {
8629 $substitutionarray['__URL_SHIPMENT__'] = DOL_MAIN_URL_ROOT."/expedition/card.php?id=".$object->id;
8630 }
8631 }
8632
8633 if (is_object($object) && $object->element == 'action') {
8634 $substitutionarray['__EVENT_LABEL__'] = $object->label;
8635 $substitutionarray['__EVENT_TYPE__'] = $outputlangs->trans("Action".$object->type_code);
8636 $substitutionarray['__EVENT_DATE__'] = dol_print_date($object->datep, 'day', 'auto', $outputlangs);
8637 $substitutionarray['__EVENT_TIME__'] = dol_print_date($object->datep, 'hour', 'auto', $outputlangs);
8638 }
8639 }
8640 }
8641 if ((empty($exclude) || !in_array('objectamount', $exclude)) && (empty($include) || in_array('objectamount', $include))) {
8642 include_once DOL_DOCUMENT_ROOT.'/core/lib/functionsnumtoword.lib.php';
8643
8644 $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : '';
8645 $substitutionarray['__DATE_DUE_YMD__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs) : null) : '';
8646
8647 $already_payed_all = 0;
8648 if (is_object($object) && ($object instanceof Facture)) {
8649 $already_payed_all = $object->sumpayed + $object->sumdeposit + $object->sumcreditnote;
8650 }
8651
8652 $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : '';
8653
8654 $substitutionarray['__AMOUNT__'] = is_object($object) ? $object->total_ttc : '';
8655 $substitutionarray['__AMOUNT_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, '', true) : '';
8656 $substitutionarray['__AMOUNT_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, $conf->currency, true) : '';
8657
8658 $substitutionarray['__AMOUNT_REMAIN__'] = is_object($object) ? price2num($object->total_ttc - $already_payed_all, 'MT') : '';
8659
8660 $substitutionarray['__AMOUNT_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8661 $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)) : '';
8662 $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)) : '';
8663
8664 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8665 $substitutionarray['__AMOUNT_TAX2__'] = is_object($object) ? $object->total_localtax1 : '';
8666 }
8667 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8668 $substitutionarray['__AMOUNT_TAX3__'] = is_object($object) ? $object->total_localtax2 : '';
8669 }
8670
8671 // Amount keys formated in a currency
8672 $substitutionarray['__AMOUNT_EXCL_TAX_FORMATED__'] = is_object($object) ? ($object->total_ht ? price($object->total_ht, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8673 $substitutionarray['__AMOUNT_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8674 $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) : '';
8675 $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)) : '';
8676 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8677 $substitutionarray['__AMOUNT_TAX2_FORMATED__'] = is_object($object) ? ($object->total_localtax1 ? price($object->total_localtax1, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8678 }
8679 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8680 $substitutionarray['__AMOUNT_TAX3_FORMATED__'] = is_object($object) ? ($object->total_localtax2 ? price($object->total_localtax2, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8681 }
8682
8683 $substitutionarray['__AMOUNT_MULTICURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? $object->multicurrency_total_ttc : '';
8684 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXT__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, '', true) : '';
8685 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXTCURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, $object->multicurrency_code, true) : '';
8686 // TODO Add other keys for foreign multicurrency
8687
8688 // For backward compatibility
8689 if ($onlykey != 2) {
8690 $substitutionarray['__TOTAL_TTC__'] = is_object($object) ? $object->total_ttc : '';
8691 $substitutionarray['__TOTAL_HT__'] = is_object($object) ? $object->total_ht : '';
8692 $substitutionarray['__TOTAL_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8693 }
8694 }
8695
8696 //var_dump($substitutionarray['__AMOUNT_FORMATED__']);
8697 if ((empty($exclude) || !in_array('date', $exclude)) && (empty($include) || in_array('date', $include))) {
8698 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
8699
8700 $now = dol_now();
8701
8702 $tmp = dol_getdate($now, true);
8703 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8704 $tmp3 = dol_get_prev_month($tmp['mon'], $tmp['year']);
8705 $tmp4 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8706 $tmp5 = dol_get_next_month($tmp['mon'], $tmp['year']);
8707
8708 $daytext = $outputlangs->trans('Day'.$tmp['wday']);
8709
8710 $substitutionarray = array_merge($substitutionarray, array(
8711 '__NOW_TMS__' => (string) $now, // Must be the string that represent the int
8712 '__NOW_TMS_YMD__' => dol_print_date($now, 'day', 'auto', $outputlangs),
8713 '__DAY__' => (string) $tmp['mday'],
8714 '__DAY_TEXT__' => $daytext, // Monday
8715 '__DAY_TEXT_SHORT__' => dol_trunc($daytext, 3, 'right', 'UTF-8', 1), // Mon
8716 '__DAY_TEXT_MIN__' => dol_trunc($daytext, 1, 'right', 'UTF-8', 1), // M
8717 '__MONTH__' => (string) $tmp['mon'],
8718 '__MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp['mon'])),
8719 '__MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp['mon'])),
8720 '__MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp['mon'])),
8721 '__YEAR__' => (string) $tmp['year'],
8722 '__PREVIOUS_DAY__' => (string) $tmp2['day'],
8723 '__PREVIOUS_MONTH__' => (string) $tmp3['month'],
8724 '__PREVIOUS_YEAR__' => (string) ($tmp['year'] - 1),
8725 '__NEXT_DAY__' => (string) $tmp4['day'],
8726 '__NEXT_MONTH__' => (string) $tmp5['month'],
8727 '__NEXT_MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp5['month'])),
8728 '__NEXT_MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp5['month'])),
8729 '__NEXT_MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp5['month'])),
8730 '__NEXT_YEAR__' => (string) ($tmp['year'] + 1),
8731 ));
8732 }
8733
8734 if (isModEnabled('multicompany')) {
8735 $substitutionarray = array_merge($substitutionarray, array('__ENTITY_ID__' => $conf->entity));
8736 }
8737 if ((empty($exclude) || !in_array('system', $exclude)) && (empty($include) || in_array('user', $include))) {
8738 $substitutionarray['__DOL_MAIN_URL_ROOT__'] = DOL_MAIN_URL_ROOT;
8739 $substitutionarray['__(AnyTranslationKey)__'] = $outputlangs->trans('TranslationOfKey');
8740 $substitutionarray['__(AnyTranslationKey|langfile)__'] = $outputlangs->trans('TranslationOfKey').' (load also language file before)';
8741 $substitutionarray['__[AnyConstantKey]__'] = $outputlangs->trans('ValueOfConstantKey');
8742 }
8743
8744 // Note: The lazyload variables are replaced only during the call by make_substitutions, and only if necessary
8745
8746 return $substitutionarray;
8747}
8748
8765function make_substitutions($text, $substitutionarray, $outputlangs = null, $converttextinhtmlifnecessary = 0)
8766{
8767 global $conf, $db, $langs;
8768
8769 if (!is_array($substitutionarray)) {
8770 return 'ErrorBadParameterSubstitutionArrayWhenCalling_make_substitutions';
8771 }
8772
8773 if (empty($outputlangs)) {
8774 $outputlangs = $langs;
8775 }
8776
8777 // Is initial text HTML or simple text ?
8778 $msgishtml = 0;
8779 if (dol_textishtml($text, 1)) {
8780 $msgishtml = 1;
8781 }
8782
8783 // Make substitution for language keys: __(AnyTranslationKey)__ or __(AnyTranslationKey|langfile)__
8784 if (is_object($outputlangs)) {
8785 $reg = array();
8786 while (preg_match('/__\‍(([^\‍)]+)\‍)__/', $text, $reg)) {
8787 // If key is __(TranslationKey|langfile)__, then force load of langfile.lang
8788 $tmp = explode('|', $reg[1]);
8789 if (!empty($tmp[1])) {
8790 $outputlangs->load($tmp[1]);
8791 }
8792
8793 $value = $outputlangs->transnoentitiesnoconv($reg[1]);
8794
8795 if (empty($converttextinhtmlifnecessary)) {
8796 // convert $newval into HTML is necessary
8797 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8798 } else {
8799 if (! $msgishtml) {
8800 $valueishtml = dol_textishtml($value, 1);
8801 //var_dump("valueishtml=".$valueishtml);
8802
8803 if ($valueishtml) {
8804 $text = dol_htmlentitiesbr($text);
8805 $msgishtml = 1;
8806 }
8807 } else {
8808 $value = dol_nl2br("$value");
8809 }
8810
8811 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $value, $text);
8812 }
8813 }
8814 }
8815
8816 // Make substitution for constant keys.
8817 // Must be after the substitution of translation, so if the text of translation contains a string __[xxx]__, it is also converted.
8818 $reg = array();
8819 while (preg_match('/__\[([^\]]+)\]__/', $text, $reg)) {
8820 $keyfound = $reg[1];
8821 if (isASecretKey($keyfound)) {
8822 $value = '*****forbidden*****';
8823 } else {
8824 $value = empty($conf->global->$keyfound) ? '' : $conf->global->$keyfound;
8825 }
8826
8827 if (empty($converttextinhtmlifnecessary)) {
8828 // convert $newval into HTML is necessary
8829 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8830 } else {
8831 if (! $msgishtml) {
8832 $valueishtml = dol_textishtml($value, 1);
8833
8834 if ($valueishtml) {
8835 $text = dol_htmlentitiesbr($text);
8836 $msgishtml = 1;
8837 }
8838 } else {
8839 $value = dol_nl2br("$value");
8840 }
8841
8842 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $value, $text);
8843 }
8844 }
8845
8846 // Make substitution for array $substitutionarray
8847 foreach ($substitutionarray as $key => $value) {
8848 if (!isset($value)) {
8849 continue; // If value is null, it same than not having substitution key at all into array, we do not replace.
8850 }
8851
8852 if (($key == '__USER_SIGNATURE__' || $key == '__SENDEREMAIL_SIGNATURE__') && (getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN'))) {
8853 $value = ''; // Protection
8854 }
8855
8856 if (empty($converttextinhtmlifnecessary)) {
8857 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8858 } else {
8859 if (! $msgishtml) {
8860 $valueishtml = dol_textishtml($value, 1);
8861
8862 if ($valueishtml) {
8863 $text = dol_htmlentitiesbr($text);
8864 $msgishtml = 1;
8865 }
8866 } else {
8867 $value = dol_nl2br("$value");
8868 }
8869 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8870 }
8871 }
8872
8873 // TODO Implement the lazyload substitution
8874 /*
8875 add a loop to scan $substitutionarray:
8876 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.
8877 If no, we don't need to make replacement, so we do nothing.
8878 If yes, we can make the substitution:
8879
8880 include_once $path;
8881 $tmpobj = new $class($db);
8882 $valuetouseforsubstitution = $tmpobj->$method($id, '__XXX__');
8883 And make the replacement of "__XXX__@lazyload" with $valuetouseforsubstitution
8884 */
8885 $memory_object_list = array();
8886 foreach ($substitutionarray as $key => $value) {
8887 $lazy_load_arr = array();
8888 if (preg_match('/(__[A-Z\_]+__)@lazyload$/', $key, $lazy_load_arr)) {
8889 if (isset($lazy_load_arr[1]) && !empty($lazy_load_arr[1])) {
8890 $key_to_substitute = $lazy_load_arr[1];
8891 if (preg_match('/' . preg_quote($key_to_substitute, '/') . '/', $text)) {
8892 $param_arr = explode(':', $value);
8893 // path:class:method:id
8894 if (count($param_arr) == 4) {
8895 $path = $param_arr[0];
8896 $class = $param_arr[1];
8897 $method = $param_arr[2];
8898 $id = (int) $param_arr[3];
8899
8900 // load class file and init object list in memory
8901 if (!isset($memory_object_list[$class])) {
8902 if (dol_is_file(DOL_DOCUMENT_ROOT . $path)) {
8903 require_once DOL_DOCUMENT_ROOT . $path;
8904 if (class_exists($class)) {
8905 $memory_object_list[$class] = array(
8906 'list' => array(),
8907 );
8908 }
8909 }
8910 }
8911
8912 // fetch object and set substitution
8913 if (isset($memory_object_list[$class]) && isset($memory_object_list[$class]['list'])) {
8914 if (method_exists($class, $method)) {
8915 if (!isset($memory_object_list[$class]['list'][$id])) {
8916 $tmpobj = new $class($db);
8917 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute);
8918 $memory_object_list[$class]['list'][$id] = $tmpobj;
8919 } else {
8920 $tmpobj = $memory_object_list[$class]['list'][$id];
8921 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute, true);
8922 }
8923
8924 $text = str_replace("$key_to_substitute", "$valuetouseforsubstitution", $text); // We must keep the " to work when value is 123.5 for example
8925 }
8926 }
8927 }
8928 }
8929 }
8930 }
8931 }
8932
8933 return $text;
8934}
8935
8948function complete_substitutions_array(&$substitutionarray, $outputlangs, $object = null, $parameters = null, $callfunc = "completesubstitutionarray")
8949{
8950 global $conf, $user;
8951
8952 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
8953
8954 // Note: substitution key for each extrafields, using key __EXTRA_XXX__ is already available into the getCommonSubstitutionArray used to build the substitution array.
8955
8956 // Check if there is external substitution to do, requested by plugins
8957 $dirsubstitutions = array_merge(array(), (array) $conf->modules_parts['substitutions']);
8958
8959 foreach ($dirsubstitutions as $reldir) {
8960 $dir = dol_buildpath($reldir, 0);
8961
8962 // Check if directory exists
8963 if (!dol_is_dir($dir)) {
8964 continue;
8965 }
8966
8967 $substitfiles = dol_dir_list($dir, 'files', 0, 'functions_');
8968 foreach ($substitfiles as $substitfile) {
8969 $reg = array();
8970 if (preg_match('/functions_(.*)\.lib\.php/i', $substitfile['name'], $reg)) {
8971 $module = $reg[1];
8972
8973 dol_syslog("Library ".$substitfile['name']." found into ".$dir);
8974 // Include the user's functions file
8975 require_once $dir.$substitfile['name'];
8976 // Call the user's function, and only if it is defined
8977 $function_name = $module."_".$callfunc;
8978 if (function_exists($function_name)) {
8979 $function_name($substitutionarray, $outputlangs, $object, $parameters);
8980 }
8981 }
8982 }
8983 }
8984 if (getDolGlobalString('ODT_ENABLE_ALL_TAGS_IN_SUBSTITUTIONS')) {
8985 // to list all tags in odt template
8986 $tags = '';
8987 foreach ($substitutionarray as $key => $value) {
8988 $tags .= '{'.$key.'} => '.$value."\n";
8989 }
8990 $substitutionarray = array_merge($substitutionarray, array('__ALL_TAGS__' => $tags));
8991 }
8992}
8993
9003function print_date_range($date_start, $date_end, $format = '', $outputlangs = '')
9004{
9005 print get_date_range($date_start, $date_end, $format, $outputlangs);
9006}
9007
9018function get_date_range($date_start, $date_end, $format = '', $outputlangs = '', $withparenthesis = 1)
9019{
9020 global $langs;
9021
9022 $out = '';
9023
9024 if (!is_object($outputlangs)) {
9025 $outputlangs = $langs;
9026 }
9027
9028 if ($date_start && $date_end) {
9029 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFromTo', dol_print_date($date_start, $format, false, $outputlangs), dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9030 }
9031 if ($date_start && !$date_end) {
9032 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($date_start, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9033 }
9034 if (!$date_start && $date_end) {
9035 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9036 }
9037
9038 return $out;
9039}
9040
9049function dolGetFirstLastname($firstname, $lastname, $nameorder = -1)
9050{
9051 global $conf;
9052
9053 $ret = '';
9054 // If order not defined, we use the setup
9055 if ($nameorder < 0) {
9056 $nameorder = (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION') ? 1 : 0);
9057 }
9058 if ($nameorder == 1) {
9059 $ret .= $firstname;
9060 if ($firstname && $lastname) {
9061 $ret .= ' ';
9062 }
9063 $ret .= $lastname;
9064 } elseif ($nameorder == 2 || $nameorder == 3) {
9065 $ret .= $firstname;
9066 if (empty($ret) && $nameorder == 3) {
9067 $ret .= $lastname;
9068 }
9069 } else { // 0, 4 or 5
9070 $ret .= $lastname;
9071 if (empty($ret) && $nameorder == 5) {
9072 $ret .= $firstname;
9073 }
9074 if ($nameorder == 0) {
9075 if ($firstname && $lastname) {
9076 $ret .= ' ';
9077 }
9078 $ret .= $firstname;
9079 }
9080 }
9081 return $ret;
9082}
9083
9084
9096function setEventMessage($mesgs, $style = 'mesgs', $noduplicate = 0)
9097{
9098 //dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING); This is not deprecated, it is used by setEventMessages function
9099 if (!is_array($mesgs)) {
9100 $mesgs = trim((string) $mesgs);
9101 // If mesgs is a not an empty string
9102 if ($mesgs) {
9103 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesgs, $_SESSION['dol_events'][$style])) {
9104 return;
9105 }
9106 $_SESSION['dol_events'][$style][] = $mesgs;
9107 }
9108 } else {
9109 // If mesgs is an array
9110 foreach ($mesgs as $mesg) {
9111 $mesg = trim((string) $mesg);
9112 if ($mesg) {
9113 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesg, $_SESSION['dol_events'][$style])) {
9114 return;
9115 }
9116 $_SESSION['dol_events'][$style][] = $mesg;
9117 }
9118 }
9119 }
9120}
9121
9134function setEventMessages($mesg, $mesgs, $style = 'mesgs', $messagekey = '', $noduplicate = 0)
9135{
9136 if (empty($mesg) && empty($mesgs)) {
9137 dol_syslog("Try to add a message in stack, but value to add is empty message", LOG_WARNING);
9138 } else {
9139 if ($messagekey) {
9140 // Complete message with a js link to set a cookie "DOLHIDEMESSAGE".$messagekey;
9141 // TODO
9142 $mesg .= '';
9143 }
9144 if (empty($messagekey) || empty($_COOKIE["DOLHIDEMESSAGE".$messagekey])) {
9145 if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
9146 dol_print_error('', 'Bad parameter style='.$style.' for setEventMessages');
9147 }
9148 if (empty($mesgs)) {
9149 setEventMessage($mesg, $style, $noduplicate);
9150 } else {
9151 if (!empty($mesg) && !in_array($mesg, $mesgs)) {
9152 setEventMessage($mesg, $style, $noduplicate); // Add message string if not already into array
9153 }
9154 setEventMessage($mesgs, $style, $noduplicate);
9155 }
9156 }
9157 }
9158}
9159
9169function dol_htmloutput_events($disabledoutputofmessages = 0)
9170{
9171 // Show mesgs
9172 if (isset($_SESSION['dol_events']['mesgs'])) {
9173 if (empty($disabledoutputofmessages)) {
9174 dol_htmloutput_mesg('', $_SESSION['dol_events']['mesgs']);
9175 }
9176 unset($_SESSION['dol_events']['mesgs']);
9177 }
9178 // Show errors
9179 if (isset($_SESSION['dol_events']['errors'])) {
9180 if (empty($disabledoutputofmessages)) {
9181 dol_htmloutput_mesg('', $_SESSION['dol_events']['errors'], 'error');
9182 }
9183 unset($_SESSION['dol_events']['errors']);
9184 }
9185
9186 // Show warnings
9187 if (isset($_SESSION['dol_events']['warnings'])) {
9188 if (empty($disabledoutputofmessages)) {
9189 dol_htmloutput_mesg('', $_SESSION['dol_events']['warnings'], 'warning');
9190 }
9191 unset($_SESSION['dol_events']['warnings']);
9192 }
9193}
9194
9209function get_htmloutput_mesg($mesgstring = '', $mesgarray = '', $style = 'ok', $keepembedded = 0)
9210{
9211 global $conf, $langs;
9212
9213 $ret = 0;
9214 $return = '';
9215 $out = '';
9216 $divstart = $divend = '';
9217
9218 // If inline message with no format, we add it.
9219 if ((empty($conf->use_javascript_ajax) || getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') || $keepembedded) && !preg_match('/<div class=".*">/i', $out)) {
9220 $divstart = '<div class="'.$style.' clearboth">';
9221 $divend = '</div>';
9222 }
9223
9224 if ((is_array($mesgarray) && count($mesgarray)) || $mesgstring) {
9225 $langs->load("errors");
9226 $out .= $divstart;
9227 if (is_array($mesgarray) && count($mesgarray)) {
9228 foreach ($mesgarray as $message) {
9229 $ret++;
9230 $out .= $langs->trans($message);
9231 if ($ret < count($mesgarray)) {
9232 $out .= "<br>\n";
9233 }
9234 }
9235 }
9236 if ($mesgstring) {
9237 $ret++;
9238 $out .= $langs->trans($mesgstring);
9239 }
9240 $out .= $divend;
9241 }
9242
9243 if ($out) {
9244 if (!empty($conf->use_javascript_ajax) && !getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') && empty($keepembedded)) {
9245 $return = '<script nonce="'.getNonce().'">
9246 $(document).ready(function() {
9247 var block = '.(getDolGlobalString('MAIN_USE_JQUERY_BLOCKUI') ? "true" : "false").'
9248 if (block) {
9249 $.dolEventValid("","'.dol_escape_js($out).'");
9250 } else {
9251 /* jnotify(message, preset of message type, keepmessage) */
9252 $.jnotify("'.dol_escape_js($out).'",
9253 "'.($style == "ok" ? 3000 : $style).'",
9254 '.($style == "ok" ? "false" : "true").',
9255 { remove: function (){} } );
9256 }
9257 });
9258 </script>';
9259 } else {
9260 $return = $out;
9261 }
9262 }
9263
9264 return $return;
9265}
9266
9278function get_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9279{
9280 return get_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9281}
9282
9296function dol_htmloutput_mesg($mesgstring = '', $mesgarray = array(), $style = 'ok', $keepembedded = 0)
9297{
9298 if (empty($mesgstring) && (!is_array($mesgarray) || count($mesgarray) == 0)) {
9299 return;
9300 }
9301
9302 $iserror = 0;
9303 $iswarning = 0;
9304 if (is_array($mesgarray)) {
9305 foreach ($mesgarray as $val) {
9306 if ($val && preg_match('/class="error"/i', $val)) {
9307 $iserror++;
9308 break;
9309 }
9310 if ($val && preg_match('/class="warning"/i', $val)) {
9311 $iswarning++;
9312 break;
9313 }
9314 }
9315 } elseif ($mesgstring && preg_match('/class="error"/i', $mesgstring)) {
9316 $iserror++;
9317 } elseif ($mesgstring && preg_match('/class="warning"/i', $mesgstring)) {
9318 $iswarning++;
9319 }
9320 if ($style == 'error') {
9321 $iserror++;
9322 }
9323 if ($style == 'warning') {
9324 $iswarning++;
9325 }
9326
9327 if ($iserror || $iswarning) {
9328 // Remove div from texts
9329 $mesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $mesgstring);
9330 $mesgstring = preg_replace('/<div class="(error|warning)">/', '', $mesgstring);
9331 $mesgstring = preg_replace('/<\/div>/', '', $mesgstring);
9332 // Remove div from texts array
9333 if (is_array($mesgarray)) {
9334 $newmesgarray = array();
9335 foreach ($mesgarray as $val) {
9336 if (is_string($val)) {
9337 $tmpmesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $val);
9338 $tmpmesgstring = preg_replace('/<div class="(error|warning)">/', '', $tmpmesgstring);
9339 $tmpmesgstring = preg_replace('/<\/div>/', '', $tmpmesgstring);
9340 $newmesgarray[] = $tmpmesgstring;
9341 } else {
9342 dol_syslog("Error call of dol_htmloutput_mesg with an array with a value that is not a string", LOG_WARNING);
9343 }
9344 }
9345 $mesgarray = $newmesgarray;
9346 }
9347 print get_htmloutput_mesg($mesgstring, $mesgarray, ($iserror ? 'error' : 'warning'), $keepembedded);
9348 } else {
9349 print get_htmloutput_mesg($mesgstring, $mesgarray, 'ok', $keepembedded);
9350 }
9351}
9352
9364function dol_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9365{
9366 dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9367}
9368
9383function dol_sort_array(&$array, $index, $order = 'asc', $natsort = 0, $case_sensitive = 0, $keepindex = 0)
9384{
9385 // Clean parameters
9386 $order = strtolower($order);
9387
9388 if (is_array($array)) {
9389 $sizearray = count($array);
9390 if ($sizearray > 0) {
9391 $temp = array();
9392 foreach (array_keys($array) as $key) {
9393 if (is_object($array[$key])) {
9394 $temp[$key] = empty($array[$key]->$index) ? 0 : $array[$key]->$index;
9395 } else {
9396 $temp[$key] = empty($array[$key][$index]) ? 0 : $array[$key][$index];
9397 }
9398 if ($natsort == -1) {
9399 $temp[$key] = '___'.$temp[$key]; // We add a string at begin of value to force an alpha order when using asort.
9400 }
9401 }
9402
9403 if (empty($natsort) || $natsort == -1) {
9404 if ($order == 'asc') {
9405 asort($temp);
9406 } else {
9407 arsort($temp);
9408 }
9409 } else {
9410 if ($case_sensitive) {
9411 natsort($temp);
9412 } else {
9413 natcasesort($temp); // natecasesort is not sensible to case
9414 }
9415 if ($order != 'asc') {
9416 $temp = array_reverse($temp, true);
9417 }
9418 }
9419
9420 $sorted = array();
9421
9422 foreach (array_keys($temp) as $key) {
9423 (is_numeric($key) && empty($keepindex)) ? $sorted[] = $array[$key] : $sorted[$key] = $array[$key];
9424 }
9425
9426 return $sorted;
9427 }
9428 }
9429 return $array;
9430}
9431
9432
9440function utf8_check($str)
9441{
9442 $str = (string) $str; // Sometimes string is an int.
9443
9444 // We must use here a binary strlen function (so not dol_strlen)
9445 $strLength = strlen($str);
9446 for ($i = 0; $i < $strLength; $i++) {
9447 if (ord($str[$i]) < 0x80) {
9448 continue; // 0bbbbbbb
9449 } elseif ((ord($str[$i]) & 0xE0) == 0xC0) {
9450 $n = 1; // 110bbbbb
9451 } elseif ((ord($str[$i]) & 0xF0) == 0xE0) {
9452 $n = 2; // 1110bbbb
9453 } elseif ((ord($str[$i]) & 0xF8) == 0xF0) {
9454 $n = 3; // 11110bbb
9455 } elseif ((ord($str[$i]) & 0xFC) == 0xF8) {
9456 $n = 4; // 111110bb
9457 } elseif ((ord($str[$i]) & 0xFE) == 0xFC) {
9458 $n = 5; // 1111110b
9459 } else {
9460 return false; // Does not match any model
9461 }
9462 for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
9463 if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80)) {
9464 return false;
9465 }
9466 }
9467 }
9468 return true;
9469}
9470
9478function utf8_valid($str)
9479{
9480 /* 2 other methods to test if string is utf8
9481 $validUTF8 = mb_check_encoding($messagetext, 'UTF-8');
9482 $validUTF8b = ! (false === mb_detect_encoding($messagetext, 'UTF-8', true));
9483 */
9484 return preg_match('//u', $str) ? true : false;
9485}
9486
9487
9494function ascii_check($str)
9495{
9496 if (function_exists('mb_check_encoding')) {
9497 //if (mb_detect_encoding($str, 'ASCII', true) return false;
9498 if (!mb_check_encoding($str, 'ASCII')) {
9499 return false;
9500 }
9501 } else {
9502 if (preg_match('/[^\x00-\x7f]/', $str)) {
9503 return false; // Contains a byte > 7f
9504 }
9505 }
9506
9507 return true;
9508}
9509
9510
9518function dol_osencode($str)
9519{
9520 global $conf;
9521
9522 $tmp = ini_get("unicode.filesystem_encoding"); // Disponible avec PHP 6.0
9523 if (empty($tmp) && !empty($_SERVER["WINDIR"])) {
9524 $tmp = 'iso-8859-1'; // By default for windows
9525 }
9526 if (empty($tmp)) {
9527 $tmp = 'utf-8'; // By default for other
9528 }
9529 if (getDolGlobalString('MAIN_FILESYSTEM_ENCODING')) {
9530 $tmp = $conf->global->MAIN_FILESYSTEM_ENCODING;
9531 }
9532
9533 if ($tmp == 'iso-8859-1') {
9534 return mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8');
9535 }
9536 return $str;
9537}
9538
9539
9554function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '')
9555{
9556 global $cache_codes;
9557
9558 // If key empty
9559 if ($key == '') {
9560 return '';
9561 }
9562
9563 // Check in cache
9564 if (isset($cache_codes[$tablename][$key][$fieldid])) { // Can be defined to 0 or ''
9565 return $cache_codes[$tablename][$key][$fieldid]; // Found in cache
9566 }
9567
9568 dol_syslog('dol_getIdFromCode (value for field '.$fieldid.' from key '.$key.' not found into cache)', LOG_DEBUG);
9569
9570 $sql = "SELECT ".$fieldid." as valuetoget";
9571 $sql .= " FROM ".MAIN_DB_PREFIX.$tablename;
9572 $sql .= " WHERE ".$fieldkey." = '".$db->escape($key)."'";
9573 if (!empty($entityfilter)) {
9574 $sql .= " AND entity IN (".getEntity($tablename).")";
9575 }
9576 if ($filters) {
9577 $sql .= $filters;
9578 }
9579
9580 $resql = $db->query($sql);
9581 if ($resql) {
9582 $obj = $db->fetch_object($resql);
9583 if ($obj) {
9584 $cache_codes[$tablename][$key][$fieldid] = $obj->valuetoget;
9585 } else {
9586 $cache_codes[$tablename][$key][$fieldid] = '';
9587 }
9588 $db->free($resql);
9589 return $cache_codes[$tablename][$key][$fieldid];
9590 } else {
9591 return -1;
9592 }
9593}
9594
9604function isStringVarMatching($var, $regextext, $matchrule = 1)
9605{
9606 if ($matchrule == 1) {
9607 if ($var == 'mainmenu') {
9608 global $mainmenu;
9609 return (preg_match('/^'.$regextext.'/', $mainmenu));
9610 } elseif ($var == 'leftmenu') {
9611 global $leftmenu;
9612 return (preg_match('/^'.$regextext.'/', $leftmenu));
9613 } else {
9614 return 'This variable is not accessible with dol_eval';
9615 }
9616 } else {
9617 return 'This value for matchrule is not implemented';
9618 }
9619}
9620
9621
9628function verifCond($strToEvaluate)
9629{
9630 //print $strToEvaluate."<br>\n";
9631 $rights = true;
9632 if (isset($strToEvaluate) && $strToEvaluate !== '') {
9633 //var_dump($strToEvaluate);
9634 //$rep = dol_eval($strToEvaluate, 1, 0, '1'); // to show the error
9635 $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
9636 $rights = $rep && (!is_string($rep) || strpos($rep, 'Bad string syntax to evaluate') === false);
9637 //var_dump($rights);
9638 }
9639 return $rights;
9640}
9641
9655function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1')
9656{
9657 // Only this global variables can be read by eval function and returned to caller
9658 global $conf; // Read of const is done with getDolGlobalString() but we need $conf->currency for example
9659 global $db, $langs, $user, $website, $websitepage;
9660 global $action, $mainmenu, $leftmenu;
9661 global $mysoc;
9662 global $objectoffield; // To allow the use of $objectoffield in computed fields
9663
9664 // Old variables used
9665 global $object;
9666 global $obj; // To get $obj used into list when dol_eval() is used for computed fields and $obj is not yet $object
9667
9668 if (!in_array($onlysimplestring, array('0', '1', '2'))) {
9669 return "Bad call of dol_eval. Parameter onlysimplestring must be '0' (deprecated), '1' or '2'";
9670 }
9671
9672 try {
9673 // Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing
9674 if ($onlysimplestring == '1') {
9675 // We must accept: '1 && getDolGlobalInt("doesnotexist1") && getDolGlobalString("MAIN_FEATURES_LEVEL")'
9676 // We must accept: '$user->hasRight("cabinetmed", "read") && !$object->canvas=="patient@cabinetmed"'
9677 $specialcharsallowed = '^$_+-.*>&|=!?():"\',/@';
9678 if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
9679 $specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
9680 }
9681 if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
9682 if ($returnvalue) {
9683 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9684 } else {
9685 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9686 return '';
9687 }
9688 }
9689 $savescheck = '';
9690 $scheck = $s;
9691 while ($scheck && $savescheck != $scheck) {
9692 $savescheck = $scheck;
9693 $scheck = preg_replace('/->[a-zA-Z0-9_]+\‍(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
9694 $scheck = preg_replace('/^\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9695 $scheck = preg_replace('/\s\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9696 $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
9697 $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
9698 $scheck = preg_replace('/(\^|\')\‍(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
9699 }
9700 //print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
9701 if (strpos($scheck, '(') !== false) {
9702 if ($returnvalue) {
9703 return 'Bad string syntax to evaluate (mode 1, found call of a function or method without using the direct name of the function): '.$s;
9704 } else {
9705 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);
9706 return '';
9707 }
9708 }
9709 // TODO
9710 // We can exclude $ char that are not: $db, $langs, $leftmenu, $topmenu, $user, $langs, $objectoffield, $object...,
9711 } elseif ($onlysimplestring == '2') {
9712 // 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"
9713 $specialcharsallowed = '^$_+-.*>&|=!?():"\',/@[]';
9714 if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
9715 $specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
9716 }
9717 if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
9718 if ($returnvalue) {
9719 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9720 } else {
9721 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9722 return '';
9723 }
9724 }
9725 $savescheck = '';
9726 $scheck = $s;
9727 while ($scheck && $savescheck != $scheck) {
9728 $savescheck = $scheck;
9729 $scheck = preg_replace('/->[a-zA-Z0-9_]+\‍(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
9730 $scheck = preg_replace('/^\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9731 $scheck = preg_replace('/\s\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... ('. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
9732 $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
9733 $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
9734 $scheck = preg_replace('/(\^|\')\‍(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
9735 }
9736 //print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
9737 if (strpos($scheck, '(') !== false) {
9738 if ($returnvalue) {
9739 return 'Bad string syntax to evaluate (mode 2, found call of a function or method without using the direct name of the function): '.$s;
9740 } else {
9741 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);
9742 return '';
9743 }
9744 }
9745 // TODO
9746 // We can exclude $ char that are not: $db, $leftmenu, $topmenu, $user, $langs, $object...,
9747 }
9748 if (is_array($s) || $s === 'Array') {
9749 return 'Bad string syntax to evaluate (value is Array) '.var_export($s, true);
9750 }
9751 if (strpos($s, '::') !== false) {
9752 if ($returnvalue) {
9753 return 'Bad string syntax to evaluate (double : char is forbidden): '.$s;
9754 } else {
9755 dol_syslog('Bad string syntax to evaluate (double : char is forbidden): '.$s);
9756 return '';
9757 }
9758 }
9759 if (strpos($s, '`') !== false) {
9760 if ($returnvalue) {
9761 return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
9762 } else {
9763 dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s);
9764 return '';
9765 }
9766 }
9767 if (preg_match('/[^0-9]+\.[^0-9]+/', $s)) { // We refuse . if not between 2 numbers
9768 if ($returnvalue) {
9769 return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
9770 } else {
9771 dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s);
9772 return '';
9773 }
9774 }
9775
9776 // We block use of php exec or php file functions
9777 $forbiddenphpstrings = array('$$');
9778 $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
9779
9780 $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen");
9781 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
9782 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64_decode", "rawurldecode", "urldecode", "str_rot13", "hex2bin")); // decode string functions used to obfuscated function name
9783 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
9784 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
9785 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));
9786 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
9787 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
9788
9789 $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
9790
9791 $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
9792
9793 $forbiddenphpmethodsregex = '->('.implode('|', $forbiddenphpmethods).')';
9794
9795 do {
9796 $oldstringtoclean = $s;
9797 $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);
9798 $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);
9799 $s = preg_replace('/'.$forbiddenphpmethodsregex.'/i', '__forbiddenstring__', $s);
9800 //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\‍(/i', '', $s); // Remove $function( call and $mycall->mymethod(
9801 } while ($oldstringtoclean != $s);
9802
9803 if (strpos($s, '__forbiddenstring__') !== false) {
9804 dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
9805 if ($returnvalue) {
9806 return 'Bad string syntax to evaluate: '.$s;
9807 } else {
9808 dol_syslog('Bad string syntax to evaluate: '.$s);
9809 return '';
9810 }
9811 }
9812
9813 //print $s."<br>\n";
9814 if ($returnvalue) {
9815 if ($hideerrors) {
9816 return @eval('return '.$s.';');
9817 } else {
9818 return eval('return '.$s.';');
9819 }
9820 } else {
9821 if ($hideerrors) {
9822 @eval($s);
9823 } else {
9824 eval($s);
9825 }
9826 }
9827 } catch (Error $e) {
9828 $error = 'dol_eval try/catch error : ';
9829 $error .= $e->getMessage();
9830 dol_syslog($error, LOG_WARNING);
9831 }
9832}
9833
9841function dol_validElement($element)
9842{
9843 return (trim($element) != '');
9844}
9845
9854function picto_from_langcode($codelang, $moreatt = '', $notitlealt = 0)
9855{
9856 if (empty($codelang)) {
9857 return '';
9858 }
9859
9860 if ($codelang == 'auto') {
9861 return '<span class="fa fa-language"></span>';
9862 }
9863
9864 $langtocountryflag = array(
9865 'ar_AR' => '',
9866 'ca_ES' => 'catalonia',
9867 'da_DA' => 'dk',
9868 'fr_CA' => 'mq',
9869 'sv_SV' => 'se',
9870 'sw_SW' => 'unknown',
9871 'AQ' => 'unknown',
9872 'CW' => 'unknown',
9873 'IM' => 'unknown',
9874 'JE' => 'unknown',
9875 'MF' => 'unknown',
9876 'BL' => 'unknown',
9877 'SX' => 'unknown'
9878 );
9879
9880 if (isset($langtocountryflag[$codelang])) {
9881 $flagImage = $langtocountryflag[$codelang];
9882 } else {
9883 $tmparray = explode('_', $codelang);
9884 $flagImage = empty($tmparray[1]) ? $tmparray[0] : $tmparray[1];
9885 }
9886
9887 $morecss = '';
9888 $reg = array();
9889 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
9890 $morecss = $reg[1];
9891 $moreatt = "";
9892 }
9893
9894 // return img_picto_common($codelang, 'flags/'.strtolower($flagImage).'.png', $moreatt, 0, $notitlealt);
9895 return '<span class="flag-sprite '.strtolower($flagImage).($morecss ? ' '.$morecss : '').'"'.($moreatt ? ' '.$moreatt : '').(!$notitlealt ? ' title="'.$codelang.'"' : '').'></span>';
9896}
9897
9906{
9907 global $mysoc;
9908
9909 if (empty($countrycode)) {
9910 return null;
9911 }
9912
9913 if (strtoupper($countrycode) == 'MQ') {
9914 return 'fr_CA';
9915 }
9916 if (strtoupper($countrycode) == 'SE') {
9917 return 'sv_SE'; // se_SE is Sami/Sweden, and we want in priority sv_SE for SE country
9918 }
9919 if (strtoupper($countrycode) == 'CH') {
9920 if ($mysoc->country_code == 'FR') {
9921 return 'fr_CH';
9922 }
9923 if ($mysoc->country_code == 'DE') {
9924 return 'de_CH';
9925 }
9926 if ($mysoc->country_code == 'IT') {
9927 return 'it_CH';
9928 }
9929 }
9930
9931 // Locale list taken from:
9932 // http://stackoverflow.com/questions/3191664/
9933 // list-of-all-locales-and-their-short-codes
9934 $locales = array(
9935 'af-ZA',
9936 'am-ET',
9937 'ar-AE',
9938 'ar-BH',
9939 'ar-DZ',
9940 'ar-EG',
9941 'ar-IQ',
9942 'ar-JO',
9943 'ar-KW',
9944 'ar-LB',
9945 'ar-LY',
9946 'ar-MA',
9947 'ar-OM',
9948 'ar-QA',
9949 'ar-SA',
9950 'ar-SY',
9951 'ar-TN',
9952 'ar-YE',
9953 //'as-IN', // Moved after en-IN
9954 'ba-RU',
9955 'be-BY',
9956 'bg-BG',
9957 'bn-BD',
9958 //'bn-IN', // Moved after en-IN
9959 'bo-CN',
9960 'br-FR',
9961 'ca-ES',
9962 'co-FR',
9963 'cs-CZ',
9964 'cy-GB',
9965 'da-DK',
9966 'de-AT',
9967 'de-CH',
9968 'de-DE',
9969 'de-LI',
9970 'de-LU',
9971 'dv-MV',
9972 'el-GR',
9973 'en-AU',
9974 'en-BZ',
9975 'en-CA',
9976 'en-GB',
9977 'en-IE',
9978 'en-IN',
9979 'as-IN', // as-IN must be after en-IN (en in priority if country is IN)
9980 'bn-IN', // bn-IN must be after en-IN (en in priority if country is IN)
9981 'en-JM',
9982 'en-MY',
9983 'en-NZ',
9984 'en-PH',
9985 'en-SG',
9986 'en-TT',
9987 'en-US',
9988 'en-ZA',
9989 'en-ZW',
9990 'es-AR',
9991 'es-BO',
9992 'es-CL',
9993 'es-CO',
9994 'es-CR',
9995 'es-DO',
9996 'es-EC',
9997 'es-ES',
9998 'es-GT',
9999 'es-HN',
10000 'es-MX',
10001 'es-NI',
10002 'es-PA',
10003 'es-PE',
10004 'es-PR',
10005 'es-PY',
10006 'es-SV',
10007 'es-US',
10008 'es-UY',
10009 'es-VE',
10010 'et-EE',
10011 'eu-ES',
10012 'fa-IR',
10013 'fi-FI',
10014 'fo-FO',
10015 'fr-BE',
10016 'fr-CA',
10017 'fr-CH',
10018 'fr-FR',
10019 'fr-LU',
10020 'fr-MC',
10021 'fy-NL',
10022 'ga-IE',
10023 'gd-GB',
10024 'gl-ES',
10025 'gu-IN',
10026 'he-IL',
10027 'hi-IN',
10028 'hr-BA',
10029 'hr-HR',
10030 'hu-HU',
10031 'hy-AM',
10032 'id-ID',
10033 'ig-NG',
10034 'ii-CN',
10035 'is-IS',
10036 'it-CH',
10037 'it-IT',
10038 'ja-JP',
10039 'ka-GE',
10040 'kk-KZ',
10041 'kl-GL',
10042 'km-KH',
10043 'kn-IN',
10044 'ko-KR',
10045 'ky-KG',
10046 'lb-LU',
10047 'lo-LA',
10048 'lt-LT',
10049 'lv-LV',
10050 'mi-NZ',
10051 'mk-MK',
10052 'ml-IN',
10053 'mn-MN',
10054 'mr-IN',
10055 'ms-BN',
10056 'ms-MY',
10057 'mt-MT',
10058 'nb-NO',
10059 'ne-NP',
10060 'nl-BE',
10061 'nl-NL',
10062 'nn-NO',
10063 'oc-FR',
10064 'or-IN',
10065 'pa-IN',
10066 'pl-PL',
10067 'ps-AF',
10068 'pt-BR',
10069 'pt-PT',
10070 'rm-CH',
10071 'ro-MD',
10072 'ro-RO',
10073 'ru-RU',
10074 'rw-RW',
10075 'sa-IN',
10076 'se-FI',
10077 'se-NO',
10078 'se-SE',
10079 'si-LK',
10080 'sk-SK',
10081 'sl-SI',
10082 'sq-AL',
10083 'sv-FI',
10084 'sv-SE',
10085 'sw-KE',
10086 'ta-IN',
10087 'te-IN',
10088 'th-TH',
10089 'tk-TM',
10090 'tn-ZA',
10091 'tr-TR',
10092 'tt-RU',
10093 'ug-CN',
10094 'uk-UA',
10095 'ur-PK',
10096 'vi-VN',
10097 'wo-SN',
10098 'xh-ZA',
10099 'yo-NG',
10100 'zh-CN',
10101 'zh-HK',
10102 'zh-MO',
10103 'zh-SG',
10104 'zh-TW',
10105 'zu-ZA',
10106 );
10107
10108 $buildprimarykeytotest = strtolower($countrycode).'-'.strtoupper($countrycode);
10109 if (in_array($buildprimarykeytotest, $locales)) {
10110 return strtolower($countrycode).'_'.strtoupper($countrycode);
10111 }
10112
10113 if (function_exists('locale_get_primary_language') && function_exists('locale_get_region')) { // Need extension php-intl
10114 foreach ($locales as $locale) {
10115 $locale_language = locale_get_primary_language($locale);
10116 $locale_region = locale_get_region($locale);
10117 if (strtoupper($countrycode) == $locale_region) {
10118 //var_dump($locale.' - '.$locale_language.' - '.$locale_region);
10119 return strtolower($locale_language).'_'.strtoupper($locale_region);
10120 }
10121 }
10122 } else {
10123 dol_syslog("Warning Exention php-intl is not available", LOG_WARNING);
10124 }
10125
10126 return null;
10127}
10128
10159function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode = 'add', $filterorigmodule = '')
10160{
10161 global $hookmanager, $db;
10162
10163 if (isset($conf->modules_parts['tabs'][$type]) && is_array($conf->modules_parts['tabs'][$type])) {
10164 foreach ($conf->modules_parts['tabs'][$type] as $value) {
10165 $values = explode(':', $value);
10166
10167 $reg = array();
10168 if ($mode == 'add' && !preg_match('/^\-/', $values[1])) {
10169 $newtab = array();
10170 $postab = $h;
10171 // detect if position set in $values[1] ie : +(2)mytab@mymodule (first tab is 0, second is one, ...)
10172 $str = $values[1];
10173 $posstart = strpos($str, '(');
10174 if ($posstart > 0) {
10175 $posend = strpos($str, ')');
10176 if ($posstart > 0) {
10177 $res1 = substr($str, $posstart + 1, $posend - $posstart -1);
10178 if (is_numeric($res1)) {
10179 $postab = (int) $res1;
10180 $values[1] = '+' . substr($str, $posend + 1);
10181 }
10182 }
10183 }
10184 if (count($values) == 6) {
10185 // new declaration with permissions:
10186 // $value='objecttype:+tabname1:Title1:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10187 // $value='objecttype:+tabname1:Title1,class,pathfile,method:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10188 if ($values[0] != $type) {
10189 continue;
10190 }
10191
10192 if (verifCond($values[4])) {
10193 if ($values[3]) {
10194 if ($filterorigmodule) { // If a filter of module origin has been requested
10195 if (strpos($values[3], '@')) { // This is an external module
10196 if ($filterorigmodule != 'external') {
10197 continue;
10198 }
10199 } else { // This looks a core module
10200 if ($filterorigmodule != 'core') {
10201 continue;
10202 }
10203 }
10204 }
10205 $langs->load($values[3]);
10206 }
10207 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10208 // If label is "SUBSTITUION_..."
10209 $substitutionarray = array();
10210 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
10211 $label = make_substitutions($reg[1], $substitutionarray);
10212 } else {
10213 // If label is "Label,Class,File,Method", we call the method to show content inside the badge
10214 $labeltemp = explode(',', $values[2]);
10215 $label = $langs->trans($labeltemp[0]);
10216
10217 if (!empty($labeltemp[1]) && is_object($object) && !empty($object->id)) {
10218 dol_include_once($labeltemp[2]);
10219 $classtoload = $labeltemp[1];
10220 if (class_exists($classtoload)) {
10221 $obj = new $classtoload($db);
10222 $function = $labeltemp[3];
10223 if ($obj && $function && method_exists($obj, $function)) {
10224 $nbrec = $obj->$function($object->id, $obj);
10225 if (!empty($nbrec)) {
10226 $label .= '<span class="badge marginleftonlyshort">'.$nbrec.'</span>';
10227 }
10228 }
10229 }
10230 }
10231 }
10232
10233 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[5]), 1);
10234 $newtab[1] = $label;
10235 $newtab[2] = str_replace('+', '', $values[1]);
10236 $h++;
10237 } else {
10238 continue;
10239 }
10240 } elseif (count($values) == 5) { // case deprecated
10241 dol_syslog('Passing 5 values in tabs module_parts is deprecated. Please update to 6 with permissions.', LOG_WARNING);
10242
10243 if ($values[0] != $type) {
10244 continue;
10245 }
10246 if ($values[3]) {
10247 if ($filterorigmodule) { // If a filter of module origin has been requested
10248 if (strpos($values[3], '@')) { // This is an external module
10249 if ($filterorigmodule != 'external') {
10250 continue;
10251 }
10252 } else { // This looks a core module
10253 if ($filterorigmodule != 'core') {
10254 continue;
10255 }
10256 }
10257 }
10258 $langs->load($values[3]);
10259 }
10260 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10261 $substitutionarray = array();
10262 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
10263 $label = make_substitutions($reg[1], $substitutionarray);
10264 } else {
10265 $label = $langs->trans($values[2]);
10266 }
10267
10268 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[4]), 1);
10269 $newtab[1] = $label;
10270 $newtab[2] = str_replace('+', '', $values[1]);
10271 $h++;
10272 }
10273 // set tab at its position
10274 $head = array_merge(array_slice($head, 0, $postab), array($newtab), array_slice($head, $postab));
10275 } elseif ($mode == 'remove' && preg_match('/^\-/', $values[1])) {
10276 if ($values[0] != $type) {
10277 continue;
10278 }
10279 $tabname = str_replace('-', '', $values[1]);
10280 foreach ($head as $key => $val) {
10281 $condition = (!empty($values[3]) ? verifCond($values[3]) : 1);
10282 //var_dump($key.' - '.$tabname.' - '.$head[$key][2].' - '.$values[3].' - '.$condition);
10283 if ($head[$key][2] == $tabname && $condition) {
10284 unset($head[$key]);
10285 break;
10286 }
10287 }
10288 }
10289 }
10290 }
10291
10292 // No need to make a return $head. Var is modified as a reference
10293 if (!empty($hookmanager)) {
10294 $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule);
10295 $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters, $object);
10296 if ($reshook > 0) { // Hook ask to replace completely the array
10297 $head = $hookmanager->resArray;
10298 } else { // Hook
10299 $head = array_merge($head, $hookmanager->resArray);
10300 }
10301 $h = count($head);
10302 }
10303}
10304
10316function printCommonFooter($zone = 'private')
10317{
10318 global $conf, $hookmanager, $user, $debugbar;
10319 global $action;
10320 global $micro_start_time;
10321
10322 if ($zone == 'private') {
10323 print "\n".'<!-- Common footer for private page -->'."\n";
10324 } else {
10325 print "\n".'<!-- Common footer for public page -->'."\n";
10326 }
10327
10328 // A div to store page_y POST parameter so we can read it using javascript
10329 print "\n<!-- A div to store page_y POST parameter -->\n";
10330 print '<div id="page_y" style="display: none;">'.(GETPOST('page_y') ? GETPOST('page_y') : '').'</div>'."\n";
10331
10332 $parameters = array();
10333 $reshook = $hookmanager->executeHooks('printCommonFooter', $parameters); // Note that $action and $object may have been modified by some hooks
10334 if (empty($reshook)) {
10335 if (getDolGlobalString('MAIN_HTML_FOOTER')) {
10336 print getDolGlobalString('MAIN_HTML_FOOTER') . "\n";
10337 }
10338
10339 print "\n";
10340 if (!empty($conf->use_javascript_ajax)) {
10341 print "\n<!-- A script section to add menuhider handler on backoffice, manage focus and madatory fields, tuning info, ... -->\n";
10342 print '<script>'."\n";
10343 print 'jQuery(document).ready(function() {'."\n";
10344
10345 if ($zone == 'private' && empty($conf->dol_use_jmobile)) {
10346 print "\n";
10347 print '/* JS CODE TO ENABLE to manage handler to switch left menu page (menuhider) */'."\n";
10348 print 'jQuery("li.menuhider").click(function(event) {';
10349 print ' if (!$( "body" ).hasClass( "sidebar-collapse" )){ event.preventDefault(); }'."\n";
10350 print ' console.log("We click on .menuhider");'."\n";
10351 print ' $("body").toggleClass("sidebar-collapse")'."\n";
10352 print '});'."\n";
10353 }
10354
10355 // Management of focus and mandatory for fields
10356 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"])))) {
10357 print '/* JS CODE TO ENABLE to manage focus and mandatory form fields */'."\n";
10358 $relativepathstring = $_SERVER["PHP_SELF"];
10359 // Clean $relativepathstring
10360 if (constant('DOL_URL_ROOT')) {
10361 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
10362 }
10363 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
10364 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
10365 //$tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
10366 if (!empty($user->default_values[$relativepathstring]['focus'])) {
10367 foreach ($user->default_values[$relativepathstring]['focus'] as $defkey => $defval) {
10368 $qualified = 0;
10369 if ($defkey != '_noquery_') {
10370 $tmpqueryarraytohave = explode('&', $defkey);
10371 $foundintru = 0;
10372 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
10373 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
10374 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
10375 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
10376 $foundintru = 1;
10377 }
10378 }
10379 if (!$foundintru) {
10380 $qualified = 1;
10381 }
10382 //var_dump($defkey.'-'.$qualified);
10383 } else {
10384 $qualified = 1;
10385 }
10386
10387 if ($qualified) {
10388 foreach ($defval as $paramkey => $paramval) {
10389 // Set focus on field
10390 print 'jQuery("input[name=\''.$paramkey.'\']").focus();'."\n";
10391 print 'jQuery("textarea[name=\''.$paramkey.'\']").focus();'."\n";
10392 print 'jQuery("select[name=\''.$paramkey.'\']").focus();'."\n"; // Not really usefull, but we keep it in case of.
10393 }
10394 }
10395 }
10396 }
10397 if (!empty($user->default_values[$relativepathstring]['mandatory'])) {
10398 foreach ($user->default_values[$relativepathstring]['mandatory'] as $defkey => $defval) {
10399 $qualified = 0;
10400 if ($defkey != '_noquery_') {
10401 $tmpqueryarraytohave = explode('&', $defkey);
10402 $foundintru = 0;
10403 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
10404 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
10405 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
10406 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
10407 $foundintru = 1;
10408 }
10409 }
10410 if (!$foundintru) {
10411 $qualified = 1;
10412 }
10413 //var_dump($defkey.'-'.$qualified);
10414 } else {
10415 $qualified = 1;
10416 }
10417
10418 if ($qualified) {
10419 foreach ($defval as $paramkey => $paramval) {
10420 // Add property 'required' on input
10421 print 'jQuery("input[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10422 print 'jQuery("textarea[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10423 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";
10424 print 'jQuery("select[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
10425 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'-1\']").prop(\'value\', \'\');'."\n";
10426 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'0\']").prop(\'value\', \'\');'."\n";
10427
10428 // Add 'field required' class on closest td for all input elements : input, textarea and select
10429 print 'jQuery(":input[name=\'' . $paramkey . '\']").closest("tr").find("td:first").addClass("fieldrequired");' . "\n";
10430 }
10431 // If we submit the cancel button we remove the required attributes
10432 print 'jQuery("input[name=\'cancel\']").click(function() {
10433 console.log("We click on cancel button so removed all required attribute");
10434 jQuery("input, textarea, select").each(function(){this.removeAttribute(\'required\');});
10435 });'."\n";
10436 }
10437 }
10438 }
10439 }
10440
10441 print '});'."\n";
10442
10443 // End of tuning
10444 if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO']) || getDolGlobalString('MAIN_SHOW_TUNING_INFO')) {
10445 print "\n";
10446 print "/* JS CODE TO ENABLE to add memory info */\n";
10447 print 'window.console && console.log("';
10448 if (getDolGlobalString('MEMCACHED_SERVER')) {
10449 print 'MEMCACHED_SERVER=' . getDolGlobalString('MEMCACHED_SERVER').' - ';
10450 }
10451 print 'MAIN_OPTIMIZE_SPEED='.(isset($conf->global->MAIN_OPTIMIZE_SPEED) ? $conf->global->MAIN_OPTIMIZE_SPEED : 'off');
10452 if (!empty($micro_start_time)) { // Works only if MAIN_SHOW_TUNING_INFO is defined at $_SERVER level. Not in global variable.
10453 $micro_end_time = microtime(true);
10454 print ' - Build time: '.ceil(1000 * ($micro_end_time - $micro_start_time)).' ms';
10455 }
10456
10457 if (function_exists("memory_get_usage")) {
10458 print ' - Mem: '.memory_get_usage(); // Do not use true here, it seems it takes the peak amount
10459 }
10460 if (function_exists("memory_get_peak_usage")) {
10461 print ' - Real mem peak: '.memory_get_peak_usage(true);
10462 }
10463 if (function_exists("zend_loader_file_encoded")) {
10464 print ' - Zend encoded file: '.(zend_loader_file_encoded() ? 'yes' : 'no');
10465 }
10466 print '");'."\n";
10467 }
10468
10469 print "\n".'</script>'."\n";
10470
10471 // Google Analytics
10472 // TODO Add a hook here
10473 if (isModEnabled('google') && getDolGlobalString('MAIN_GOOGLE_AN_ID')) {
10474 $tmptagarray = explode(',', getDolGlobalString('MAIN_GOOGLE_AN_ID'));
10475 foreach ($tmptagarray as $tmptag) {
10476 print "\n";
10477 print "<!-- JS CODE TO ENABLE for google analtics tag -->\n";
10478 print '
10479 <!-- Global site tag (gtag.js) - Google Analytics -->
10480 <script nonce="'.getNonce().'" async src="https://www.googletagmanager.com/gtag/js?id='.trim($tmptag).'"></script>
10481 <script>
10482 window.dataLayer = window.dataLayer || [];
10483 function gtag(){dataLayer.push(arguments);}
10484 gtag(\'js\', new Date());
10485
10486 gtag(\'config\', \''.trim($tmptag).'\');
10487 </script>';
10488 print "\n";
10489 }
10490 }
10491 }
10492
10493 // Add Xdebug coverage of code
10494 if (defined('XDEBUGCOVERAGE')) {
10495 print_r(xdebug_get_code_coverage());
10496 }
10497
10498 // Add DebugBar data
10499 if ($user->hasRight('debugbar', 'read') && is_object($debugbar)) {
10500 $debugbar['time']->stopMeasure('pageaftermaster');
10501 print '<!-- Output debugbar data -->'."\n";
10502 $renderer = $debugbar->getRenderer();
10503 print $debugbar->getRenderer()->render();
10504 } elseif (count($conf->logbuffer)) { // If there is some logs in buffer to show
10505 print "\n";
10506 print "<!-- Start of log output\n";
10507 //print '<div class="hidden">'."\n";
10508 foreach ($conf->logbuffer as $logline) {
10509 print $logline."<br>\n";
10510 }
10511 //print '</div>'."\n";
10512 print "End of log output -->\n";
10513 }
10514 }
10515}
10516
10526function dolExplodeIntoArray($string, $delimiter = ';', $kv = '=')
10527{
10528 if (is_null($string)) {
10529 return array();
10530 }
10531
10532 if (preg_match('/^\[.*\]$/sm', $delimiter) || preg_match('/^\‍(.*\‍)$/sm', $delimiter)) {
10533 // This is a regex string
10534 $newdelimiter = $delimiter;
10535 } else {
10536 // This is a simple string
10537 $newdelimiter = preg_quote($delimiter, '/');
10538 }
10539
10540 if ($a = preg_split('/'.$newdelimiter.'/', $string)) {
10541 $ka = array();
10542 foreach ($a as $s) { // each part
10543 if ($s) {
10544 if ($pos = strpos($s, $kv)) { // key/value delimiter
10545 $ka[trim(substr($s, 0, $pos))] = trim(substr($s, $pos + strlen($kv)));
10546 } else { // key delimiter not found
10547 $ka[] = trim($s);
10548 }
10549 }
10550 }
10551 return $ka;
10552 }
10553
10554 return array();
10555}
10556
10557
10564function dol_set_focus($selector)
10565{
10566 print "\n".'<!-- Set focus onto a specific field -->'."\n";
10567 print '<script nonce="'.getNonce().'">jQuery(document).ready(function() { jQuery("'.dol_escape_js($selector).'").focus(); });</script>'."\n";
10568}
10569
10570
10578function dol_getmypid()
10579{
10580 if (!function_exists('getmypid')) {
10581 return mt_rand(99900000, 99965535);
10582 } else {
10583 return getmypid(); // May be a number on 64 bits (depending on OS)
10584 }
10585}
10586
10587
10605function natural_search($fields, $value, $mode = 0, $nofirstand = 0)
10606{
10607 global $db, $langs;
10608
10609 $value = trim($value);
10610
10611 if ($mode == 0) {
10612 $value = preg_replace('/\*/', '%', $value); // Replace * with %
10613 }
10614 if ($mode == 1) {
10615 $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
10616 }
10617
10618 $value = preg_replace('/\s*\|\s*/', '|', $value);
10619
10620 $crits = explode(' ', $value);
10621 $res = '';
10622 if (!is_array($fields)) {
10623 $fields = array($fields);
10624 }
10625
10626 $i1 = 0; // count the nb of and criteria added (all fields / criterias)
10627 foreach ($crits as $crit) { // Loop on each AND criteria
10628 $crit = trim($crit);
10629 $i2 = 0; // count the nb of valid criteria added for this this first criteria
10630 $newres = '';
10631 foreach ($fields as $field) {
10632 if ($mode == 1) {
10633 $tmpcrits = explode('|', $crit);
10634 $i3 = 0; // count the nb of valid criteria added for this current field
10635 foreach ($tmpcrits as $tmpcrit) {
10636 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10637 continue;
10638 }
10639 $tmpcrit = trim($tmpcrit);
10640
10641 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10642
10643 $operator = '=';
10644 $newcrit = preg_replace('/([!<>=]+)/', '', $tmpcrit);
10645
10646 $reg = array();
10647 preg_match('/([!<>=]+)/', $tmpcrit, $reg);
10648 if (!empty($reg[1])) {
10649 $operator = $reg[1];
10650 }
10651 if ($newcrit != '') {
10652 $numnewcrit = price2num($newcrit);
10653 if (is_numeric($numnewcrit)) {
10654 $newres .= $field.' '.$operator.' '.((float) $numnewcrit); // should be a numeric
10655 } else {
10656 $newres .= '1 = 2'; // force false, we received a corrupted data
10657 }
10658 $i3++; // a criteria was added to string
10659 }
10660 }
10661 $i2++; // a criteria for 1 more field was added to string
10662 } elseif ($mode == 2 || $mode == -2) {
10663 $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer
10664 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -2 ? 'NOT ' : '');
10665 $newres .= $crit ? "IN (".$db->sanitize($db->escape($crit)).")" : "IN (0)";
10666 if ($mode == -2) {
10667 $newres .= ' OR '.$field.' IS NULL';
10668 }
10669 $i2++; // a criteria for 1 more field was added to string
10670 } elseif ($mode == 3 || $mode == -3) {
10671 $tmparray = explode(',', $crit);
10672 if (count($tmparray)) {
10673 $listofcodes = '';
10674 foreach ($tmparray as $val) {
10675 $val = trim($val);
10676 if ($val) {
10677 $listofcodes .= ($listofcodes ? ',' : '');
10678 $listofcodes .= "'".$db->escape($val)."'";
10679 }
10680 }
10681 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -3 ? 'NOT ' : '')."IN (".$db->sanitize($listofcodes, 1).")";
10682 $i2++; // a criteria for 1 more field was added to string
10683 }
10684 if ($mode == -3) {
10685 $newres .= ' OR '.$field.' IS NULL';
10686 }
10687 } elseif ($mode == 4) {
10688 $tmparray = explode(',', $crit);
10689 if (count($tmparray)) {
10690 $listofcodes = '';
10691 foreach ($tmparray as $val) {
10692 $val = trim($val);
10693 if ($val) {
10694 $newres .= ($i2 > 0 ? " OR (" : "(").$field." LIKE '".$db->escape($val).",%'";
10695 $newres .= ' OR '.$field." = '".$db->escape($val)."'";
10696 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val)."'";
10697 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val).",%'";
10698 $newres .= ')';
10699 $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)
10700 }
10701 }
10702 }
10703 } else { // $mode=0
10704 $tmpcrits = explode('|', $crit);
10705 $i3 = 0; // count the nb of valid criteria added for the current couple criteria/field
10706 foreach ($tmpcrits as $tmpcrit) { // loop on each OR criteria
10707 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10708 continue;
10709 }
10710 $tmpcrit = trim($tmpcrit);
10711
10712 if ($tmpcrit == '^$' || strpos($crit, '!') === 0) { // If we search empty, we must combined different OR fields with AND
10713 $newres .= (($i2 > 0 || $i3 > 0) ? ' AND ' : '');
10714 } else {
10715 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10716 }
10717
10718 if (preg_match('/\.(id|rowid)$/', $field)) { // Special case for rowid that is sometimes a ref so used as a search field
10719 $newres .= $field." = ".(is_numeric($tmpcrit) ? ((float) $tmpcrit) : '0');
10720 } else {
10721 $tmpcrit2 = $tmpcrit;
10722 $tmpbefore = '%';
10723 $tmpafter = '%';
10724 $tmps = '';
10725
10726 if (preg_match('/^!/', $tmpcrit)) {
10727 $tmps .= $field." NOT LIKE "; // ! as exclude character
10728 $tmpcrit2 = preg_replace('/^!/', '', $tmpcrit2);
10729 } else {
10730 $tmps .= $field." LIKE ";
10731 }
10732 $tmps .= "'";
10733
10734 if (preg_match('/^[\^\$]/', $tmpcrit)) {
10735 $tmpbefore = '';
10736 $tmpcrit2 = preg_replace('/^[\^\$]/', '', $tmpcrit2);
10737 }
10738 if (preg_match('/[\^\$]$/', $tmpcrit)) {
10739 $tmpafter = '';
10740 $tmpcrit2 = preg_replace('/[\^\$]$/', '', $tmpcrit2);
10741 }
10742
10743 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10744 $tmps = "(".$tmps;
10745 }
10746 $newres .= $tmps;
10747 $newres .= $tmpbefore;
10748 $newres .= $db->escape($tmpcrit2);
10749 $newres .= $tmpafter;
10750 $newres .= "'";
10751 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10752 $newres .= " OR ".$field." IS NULL)";
10753 }
10754 }
10755
10756 $i3++;
10757 }
10758
10759 $i2++; // a criteria for 1 more field was added to string
10760 }
10761 }
10762
10763 if ($newres) {
10764 $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : '');
10765 }
10766 $i1++;
10767 }
10768 $res = ($nofirstand ? "" : " AND ")."(".$res.")";
10769
10770 return $res;
10771}
10772
10779function showDirectDownloadLink($object)
10780{
10781 global $conf, $langs;
10782
10783 $out = '';
10784 $url = $object->getLastMainDocLink($object->element);
10785
10786 $out .= img_picto($langs->trans("PublicDownloadLinkDesc"), 'globe').' <span class="opacitymedium">'.$langs->trans("DirectDownloadLink").'</span><br>';
10787 if ($url) {
10788 $out .= '<div class="urllink"><input type="text" id="directdownloadlink" class="quatrevingtpercent" value="'.$url.'"></div>';
10789 $out .= ajax_autoselect("directdownloadlink", 0);
10790 } else {
10791 $out .= '<div class="urllink">'.$langs->trans("FileNotShared").'</div>';
10792 }
10793
10794 return $out;
10795}
10796
10805function getImageFileNameForSize($file, $extName, $extImgTarget = '')
10806{
10807 $dirName = dirname($file);
10808 if ($dirName == '.') {
10809 $dirName = '';
10810 }
10811
10812 $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.webp)$/i', '', $file); // We remove extension, whatever is its case
10813 $fileName = basename($fileName);
10814
10815 if (empty($extImgTarget)) {
10816 $extImgTarget = (preg_match('/\.jpg$/i', $file) ? '.jpg' : '');
10817 }
10818 if (empty($extImgTarget)) {
10819 $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '');
10820 }
10821 if (empty($extImgTarget)) {
10822 $extImgTarget = (preg_match('/\.gif$/i', $file) ? '.gif' : '');
10823 }
10824 if (empty($extImgTarget)) {
10825 $extImgTarget = (preg_match('/\.png$/i', $file) ? '.png' : '');
10826 }
10827 if (empty($extImgTarget)) {
10828 $extImgTarget = (preg_match('/\.bmp$/i', $file) ? '.bmp' : '');
10829 }
10830 if (empty($extImgTarget)) {
10831 $extImgTarget = (preg_match('/\.webp$/i', $file) ? '.webp' : '');
10832 }
10833
10834 if (!$extImgTarget) {
10835 return $file;
10836 }
10837
10838 $subdir = '';
10839 if ($extName) {
10840 $subdir = 'thumbs/';
10841 }
10842
10843 return ($dirName ? $dirName.'/' : '').$subdir.$fileName.$extName.$extImgTarget; // New filename for thumb
10844}
10845
10846
10856function getAdvancedPreviewUrl($modulepart, $relativepath, $alldata = 0, $param = '')
10857{
10858 global $conf, $langs;
10859
10860 if (empty($conf->use_javascript_ajax)) {
10861 return '';
10862 }
10863
10864 $isAllowedForPreview = dolIsAllowedForPreview($relativepath);
10865
10866 if ($alldata == 1) {
10867 if ($isAllowedForPreview) {
10868 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));
10869 } else {
10870 return array();
10871 }
10872 }
10873
10874 // old behavior, return a string
10875 if ($isAllowedForPreview) {
10876 $tmpurl = DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : '');
10877 $title = $langs->trans("Preview");
10878 //$title = '%27-alert(document.domain)-%27';
10879 //$tmpurl = 'file='.urlencode("'-alert(document.domain)-'_small.jpg");
10880
10881 // 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.
10882 // and when we click on href with this javascript string, a urlcode is done by browser, converted the %27 of file param
10883 return 'javascript:document_preview(\''.urlencode(dol_escape_js($tmpurl)).'\', \''.urlencode(dol_mimetype($relativepath)).'\', \''.urlencode(dol_escape_js($title)).'\')';
10884 } else {
10885 return '';
10886 }
10887}
10888
10889
10898function ajax_autoselect($htmlname, $addlink = '', $textonlink = 'Link')
10899{
10900 global $langs;
10901 $out = '<script nonce="'.getNonce().'">
10902 jQuery(document).ready(function () {
10903 jQuery("'.((strpos($htmlname, '.') === 0 ? '' : '#').$htmlname).'").click(function() { jQuery(this).select(); } );
10904 });
10905 </script>';
10906 if ($addlink) {
10907 if ($textonlink === 'image') {
10908 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.img_picto('', 'globe').'</a>';
10909 } else {
10910 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.$langs->trans("Link").'</a>';
10911 }
10912 }
10913 return $out;
10914}
10915
10923function dolIsAllowedForPreview($file)
10924{
10925 global $conf;
10926
10927 // Check .noexe extension in filename
10928 if (preg_match('/\.noexe$/i', $file)) {
10929 return 0;
10930 }
10931
10932 // Check mime types
10933 $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'webp');
10934 if (getDolGlobalString('MAIN_ALLOW_SVG_FILES_AS_IMAGES')) {
10935 $mime_preview[] = 'svg+xml';
10936 }
10937 //$mime_preview[]='vnd.oasis.opendocument.presentation';
10938 //$mime_preview[]='archive';
10939 $num_mime = array_search(dol_mimetype($file, '', 1), $mime_preview);
10940 if ($num_mime !== false) {
10941 return 1;
10942 }
10943
10944 // By default, not allowed for preview
10945 return 0;
10946}
10947
10948
10958function dol_mimetype($file, $default = 'application/octet-stream', $mode = 0)
10959{
10960 $mime = $default;
10961 $imgmime = 'other.png';
10962 $famime = 'file-o';
10963 $srclang = '';
10964
10965 $tmpfile = preg_replace('/\.noexe$/', '', $file);
10966
10967 // Plain text files
10968 if (preg_match('/\.txt$/i', $tmpfile)) {
10969 $mime = 'text/plain';
10970 $imgmime = 'text.png';
10971 $famime = 'file-alt';
10972 } elseif (preg_match('/\.rtx$/i', $tmpfile)) {
10973 $mime = 'text/richtext';
10974 $imgmime = 'text.png';
10975 $famime = 'file-alt';
10976 } elseif (preg_match('/\.csv$/i', $tmpfile)) {
10977 $mime = 'text/csv';
10978 $imgmime = 'text.png';
10979 $famime = 'file-csv';
10980 } elseif (preg_match('/\.tsv$/i', $tmpfile)) {
10981 $mime = 'text/tab-separated-values';
10982 $imgmime = 'text.png';
10983 $famime = 'file-alt';
10984 } elseif (preg_match('/\.(cf|conf|log)$/i', $tmpfile)) {
10985 $mime = 'text/plain';
10986 $imgmime = 'text.png';
10987 $famime = 'file-alt';
10988 } elseif (preg_match('/\.ini$/i', $tmpfile)) {
10989 $mime = 'text/plain';
10990 $imgmime = 'text.png';
10991 $srclang = 'ini';
10992 $famime = 'file-alt';
10993 } elseif (preg_match('/\.md$/i', $tmpfile)) {
10994 $mime = 'text/plain';
10995 $imgmime = 'text.png';
10996 $srclang = 'md';
10997 $famime = 'file-alt';
10998 } elseif (preg_match('/\.css$/i', $tmpfile)) {
10999 $mime = 'text/css';
11000 $imgmime = 'css.png';
11001 $srclang = 'css';
11002 $famime = 'file-alt';
11003 } elseif (preg_match('/\.lang$/i', $tmpfile)) {
11004 $mime = 'text/plain';
11005 $imgmime = 'text.png';
11006 $srclang = 'lang';
11007 $famime = 'file-alt';
11008 } elseif (preg_match('/\.(crt|cer|key|pub)$/i', $tmpfile)) { // Certificate files
11009 $mime = 'text/plain';
11010 $imgmime = 'text.png';
11011 $famime = 'file-alt';
11012 } elseif (preg_match('/\.(html|htm|shtml)$/i', $tmpfile)) { // XML based (HTML/XML/XAML)
11013 $mime = 'text/html';
11014 $imgmime = 'html.png';
11015 $srclang = 'html';
11016 $famime = 'file-alt';
11017 } elseif (preg_match('/\.(xml|xhtml)$/i', $tmpfile)) {
11018 $mime = 'text/xml';
11019 $imgmime = 'other.png';
11020 $srclang = 'xml';
11021 $famime = 'file-alt';
11022 } elseif (preg_match('/\.xaml$/i', $tmpfile)) {
11023 $mime = 'text/xml';
11024 $imgmime = 'other.png';
11025 $srclang = 'xaml';
11026 $famime = 'file-alt';
11027 } elseif (preg_match('/\.bas$/i', $tmpfile)) { // Languages
11028 $mime = 'text/plain';
11029 $imgmime = 'text.png';
11030 $srclang = 'bas';
11031 $famime = 'file-code';
11032 } elseif (preg_match('/\.(c)$/i', $tmpfile)) {
11033 $mime = 'text/plain';
11034 $imgmime = 'text.png';
11035 $srclang = 'c';
11036 $famime = 'file-code';
11037 } elseif (preg_match('/\.(cpp)$/i', $tmpfile)) {
11038 $mime = 'text/plain';
11039 $imgmime = 'text.png';
11040 $srclang = 'cpp';
11041 $famime = 'file-code';
11042 } elseif (preg_match('/\.cs$/i', $tmpfile)) {
11043 $mime = 'text/plain';
11044 $imgmime = 'text.png';
11045 $srclang = 'cs';
11046 $famime = 'file-code';
11047 } elseif (preg_match('/\.(h)$/i', $tmpfile)) {
11048 $mime = 'text/plain';
11049 $imgmime = 'text.png';
11050 $srclang = 'h';
11051 $famime = 'file-code';
11052 } elseif (preg_match('/\.(java|jsp)$/i', $tmpfile)) {
11053 $mime = 'text/plain';
11054 $imgmime = 'text.png';
11055 $srclang = 'java';
11056 $famime = 'file-code';
11057 } elseif (preg_match('/\.php([0-9]{1})?$/i', $tmpfile)) {
11058 $mime = 'text/plain';
11059 $imgmime = 'php.png';
11060 $srclang = 'php';
11061 $famime = 'file-code';
11062 } elseif (preg_match('/\.phtml$/i', $tmpfile)) {
11063 $mime = 'text/plain';
11064 $imgmime = 'php.png';
11065 $srclang = 'php';
11066 $famime = 'file-code';
11067 } elseif (preg_match('/\.(pl|pm)$/i', $tmpfile)) {
11068 $mime = 'text/plain';
11069 $imgmime = 'pl.png';
11070 $srclang = 'perl';
11071 $famime = 'file-code';
11072 } elseif (preg_match('/\.sql$/i', $tmpfile)) {
11073 $mime = 'text/plain';
11074 $imgmime = 'text.png';
11075 $srclang = 'sql';
11076 $famime = 'file-code';
11077 } elseif (preg_match('/\.js$/i', $tmpfile)) {
11078 $mime = 'text/x-javascript';
11079 $imgmime = 'jscript.png';
11080 $srclang = 'js';
11081 $famime = 'file-code';
11082 } elseif (preg_match('/\.odp$/i', $tmpfile)) { // Open office
11083 $mime = 'application/vnd.oasis.opendocument.presentation';
11084 $imgmime = 'ooffice.png';
11085 $famime = 'file-powerpoint';
11086 } elseif (preg_match('/\.ods$/i', $tmpfile)) {
11087 $mime = 'application/vnd.oasis.opendocument.spreadsheet';
11088 $imgmime = 'ooffice.png';
11089 $famime = 'file-excel';
11090 } elseif (preg_match('/\.odt$/i', $tmpfile)) {
11091 $mime = 'application/vnd.oasis.opendocument.text';
11092 $imgmime = 'ooffice.png';
11093 $famime = 'file-word';
11094 } elseif (preg_match('/\.mdb$/i', $tmpfile)) { // MS Office
11095 $mime = 'application/msaccess';
11096 $imgmime = 'mdb.png';
11097 $famime = 'file';
11098 } elseif (preg_match('/\.doc[xm]?$/i', $tmpfile)) {
11099 $mime = 'application/msword';
11100 $imgmime = 'doc.png';
11101 $famime = 'file-word';
11102 } elseif (preg_match('/\.dot[xm]?$/i', $tmpfile)) {
11103 $mime = 'application/msword';
11104 $imgmime = 'doc.png';
11105 $famime = 'file-word';
11106 } elseif (preg_match('/\.xlt(x)?$/i', $tmpfile)) {
11107 $mime = 'application/vnd.ms-excel';
11108 $imgmime = 'xls.png';
11109 $famime = 'file-excel';
11110 } elseif (preg_match('/\.xla(m)?$/i', $tmpfile)) {
11111 $mime = 'application/vnd.ms-excel';
11112 $imgmime = 'xls.png';
11113 $famime = 'file-excel';
11114 } elseif (preg_match('/\.xls$/i', $tmpfile)) {
11115 $mime = 'application/vnd.ms-excel';
11116 $imgmime = 'xls.png';
11117 $famime = 'file-excel';
11118 } elseif (preg_match('/\.xls[bmx]$/i', $tmpfile)) {
11119 $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
11120 $imgmime = 'xls.png';
11121 $famime = 'file-excel';
11122 } elseif (preg_match('/\.pps[mx]?$/i', $tmpfile)) {
11123 $mime = 'application/vnd.ms-powerpoint';
11124 $imgmime = 'ppt.png';
11125 $famime = 'file-powerpoint';
11126 } elseif (preg_match('/\.ppt[mx]?$/i', $tmpfile)) {
11127 $mime = 'application/x-mspowerpoint';
11128 $imgmime = 'ppt.png';
11129 $famime = 'file-powerpoint';
11130 } elseif (preg_match('/\.pdf$/i', $tmpfile)) { // Other
11131 $mime = 'application/pdf';
11132 $imgmime = 'pdf.png';
11133 $famime = 'file-pdf';
11134 } elseif (preg_match('/\.bat$/i', $tmpfile)) { // Scripts
11135 $mime = 'text/x-bat';
11136 $imgmime = 'script.png';
11137 $srclang = 'dos';
11138 $famime = 'file-code';
11139 } elseif (preg_match('/\.sh$/i', $tmpfile)) {
11140 $mime = 'text/x-sh';
11141 $imgmime = 'script.png';
11142 $srclang = 'bash';
11143 $famime = 'file-code';
11144 } elseif (preg_match('/\.ksh$/i', $tmpfile)) {
11145 $mime = 'text/x-ksh';
11146 $imgmime = 'script.png';
11147 $srclang = 'bash';
11148 $famime = 'file-code';
11149 } elseif (preg_match('/\.bash$/i', $tmpfile)) {
11150 $mime = 'text/x-bash';
11151 $imgmime = 'script.png';
11152 $srclang = 'bash';
11153 $famime = 'file-code';
11154 } elseif (preg_match('/\.ico$/i', $tmpfile)) { // Images
11155 $mime = 'image/x-icon';
11156 $imgmime = 'image.png';
11157 $famime = 'file-image';
11158 } elseif (preg_match('/\.(jpg|jpeg)$/i', $tmpfile)) {
11159 $mime = 'image/jpeg';
11160 $imgmime = 'image.png';
11161 $famime = 'file-image';
11162 } elseif (preg_match('/\.png$/i', $tmpfile)) {
11163 $mime = 'image/png';
11164 $imgmime = 'image.png';
11165 $famime = 'file-image';
11166 } elseif (preg_match('/\.gif$/i', $tmpfile)) {
11167 $mime = 'image/gif';
11168 $imgmime = 'image.png';
11169 $famime = 'file-image';
11170 } elseif (preg_match('/\.bmp$/i', $tmpfile)) {
11171 $mime = 'image/bmp';
11172 $imgmime = 'image.png';
11173 $famime = 'file-image';
11174 } elseif (preg_match('/\.(tif|tiff)$/i', $tmpfile)) {
11175 $mime = 'image/tiff';
11176 $imgmime = 'image.png';
11177 $famime = 'file-image';
11178 } elseif (preg_match('/\.svg$/i', $tmpfile)) {
11179 $mime = 'image/svg+xml';
11180 $imgmime = 'image.png';
11181 $famime = 'file-image';
11182 } elseif (preg_match('/\.webp$/i', $tmpfile)) {
11183 $mime = 'image/webp';
11184 $imgmime = 'image.png';
11185 $famime = 'file-image';
11186 } elseif (preg_match('/\.vcs$/i', $tmpfile)) { // Calendar
11187 $mime = 'text/calendar';
11188 $imgmime = 'other.png';
11189 $famime = 'file-alt';
11190 } elseif (preg_match('/\.ics$/i', $tmpfile)) {
11191 $mime = 'text/calendar';
11192 $imgmime = 'other.png';
11193 $famime = 'file-alt';
11194 } elseif (preg_match('/\.torrent$/i', $tmpfile)) { // Other
11195 $mime = 'application/x-bittorrent';
11196 $imgmime = 'other.png';
11197 $famime = 'file-o';
11198 } elseif (preg_match('/\.(mp3|ogg|au|wav|wma|mid)$/i', $tmpfile)) { // Audio
11199 $mime = 'audio';
11200 $imgmime = 'audio.png';
11201 $famime = 'file-audio';
11202 } elseif (preg_match('/\.mp4$/i', $tmpfile)) { // Video
11203 $mime = 'video/mp4';
11204 $imgmime = 'video.png';
11205 $famime = 'file-video';
11206 } elseif (preg_match('/\.ogv$/i', $tmpfile)) {
11207 $mime = 'video/ogg';
11208 $imgmime = 'video.png';
11209 $famime = 'file-video';
11210 } elseif (preg_match('/\.webm$/i', $tmpfile)) {
11211 $mime = 'video/webm';
11212 $imgmime = 'video.png';
11213 $famime = 'file-video';
11214 } elseif (preg_match('/\.avi$/i', $tmpfile)) {
11215 $mime = 'video/x-msvideo';
11216 $imgmime = 'video.png';
11217 $famime = 'file-video';
11218 } elseif (preg_match('/\.divx$/i', $tmpfile)) {
11219 $mime = 'video/divx';
11220 $imgmime = 'video.png';
11221 $famime = 'file-video';
11222 } elseif (preg_match('/\.xvid$/i', $tmpfile)) {
11223 $mime = 'video/xvid';
11224 $imgmime = 'video.png';
11225 $famime = 'file-video';
11226 } elseif (preg_match('/\.(wmv|mpg|mpeg)$/i', $tmpfile)) {
11227 $mime = 'video';
11228 $imgmime = 'video.png';
11229 $famime = 'file-video';
11230 } elseif (preg_match('/\.(zip|rar|gz|tgz|z|cab|bz2|7z|tar|lzh|zst)$/i', $tmpfile)) { // Archive
11231 // application/xxx where zzz is zip, ...
11232 $mime = 'archive';
11233 $imgmime = 'archive.png';
11234 $famime = 'file-archive';
11235 } elseif (preg_match('/\.(exe|com)$/i', $tmpfile)) { // Exe
11236 $mime = 'application/octet-stream';
11237 $imgmime = 'other.png';
11238 $famime = 'file-o';
11239 } elseif (preg_match('/\.(dll|lib|o|so|a)$/i', $tmpfile)) { // Lib
11240 $mime = 'library';
11241 $imgmime = 'library.png';
11242 $famime = 'file-o';
11243 } elseif (preg_match('/\.err$/i', $tmpfile)) { // phpcs:ignore
11244 $mime = 'error';
11245 $imgmime = 'error.png';
11246 $famime = 'file-alt';
11247 }
11248
11249 // Return mimetype string
11250 switch ((int) $mode) {
11251 case 1:
11252 $tmp = explode('/', $mime);
11253 return (!empty($tmp[1]) ? $tmp[1] : $tmp[0]);
11254 case 2:
11255 return $imgmime;
11256 case 3:
11257 return $srclang;
11258 case 4:
11259 return $famime;
11260 }
11261 return $mime;
11262}
11263
11275function getDictionaryValue($tablename, $field, $id, $checkentity = false, $rowidfield = 'rowid')
11276{
11277 global $conf, $db;
11278
11279 $tablename = preg_replace('/^'.preg_quote(MAIN_DB_PREFIX, '/').'/', '', $tablename); // Clean name of table for backward compatibility.
11280
11281 $dictvalues = (isset($conf->cache['dictvalues_'.$tablename]) ? $conf->cache['dictvalues_'.$tablename] : null);
11282
11283 if (is_null($dictvalues)) {
11284 $dictvalues = array();
11285
11286 $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
11287 if ($checkentity) {
11288 $sql .= ' AND entity IN (0,'.getEntity($tablename).')';
11289 }
11290
11291 $resql = $db->query($sql);
11292 if ($resql) {
11293 while ($obj = $db->fetch_object($resql)) {
11294 $dictvalues[$obj->$rowidfield] = $obj; // $obj is stdClass
11295 }
11296 } else {
11297 dol_print_error($db);
11298 }
11299
11300 $conf->cache['dictvalues_'.$tablename] = $dictvalues;
11301 }
11302
11303 if (!empty($dictvalues[$id])) {
11304 // Found
11305 $tmp = $dictvalues[$id];
11306 return (property_exists($tmp, $field) ? $tmp->$field : '');
11307 } else {
11308 // Not found
11309 return '';
11310 }
11311}
11312
11319function colorIsLight($stringcolor)
11320{
11321 $stringcolor = str_replace('#', '', $stringcolor);
11322 $res = -1;
11323 if (!empty($stringcolor)) {
11324 $res = 0;
11325 $tmp = explode(',', $stringcolor);
11326 if (count($tmp) > 1) { // This is a comma RGB ('255','255','255')
11327 $r = $tmp[0];
11328 $g = $tmp[1];
11329 $b = $tmp[2];
11330 } else {
11331 $hexr = $stringcolor[0].$stringcolor[1];
11332 $hexg = $stringcolor[2].$stringcolor[3];
11333 $hexb = $stringcolor[4].$stringcolor[5];
11334 $r = hexdec($hexr);
11335 $g = hexdec($hexg);
11336 $b = hexdec($hexb);
11337 }
11338 $bright = (max($r, $g, $b) + min($r, $g, $b)) / 510.0; // HSL algorithm
11339 if ($bright > 0.6) {
11340 $res = 1;
11341 }
11342 }
11343 return $res;
11344}
11345
11354function isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
11355{
11356 global $conf;
11357
11358 //print 'type_user='.$type_user.' module='.$menuentry['module'].' enabled='.$menuentry['enabled'].' perms='.$menuentry['perms'];
11359 //print 'ok='.in_array($menuentry['module'], $listofmodulesforexternal);
11360 if (empty($menuentry['enabled'])) {
11361 return 0; // Entry disabled by condition
11362 }
11363 if ($type_user && $menuentry['module']) {
11364 $tmploops = explode('|', $menuentry['module']);
11365 $found = 0;
11366 foreach ($tmploops as $tmploop) {
11367 if (in_array($tmploop, $listofmodulesforexternal)) {
11368 $found++;
11369 break;
11370 }
11371 }
11372 if (!$found) {
11373 return 0; // Entry is for menus all excluded to external users
11374 }
11375 }
11376 if (!$menuentry['perms'] && $type_user) {
11377 return 0; // No permissions and user is external
11378 }
11379 if (!$menuentry['perms'] && getDolGlobalString('MAIN_MENU_HIDE_UNAUTHORIZED')) {
11380 return 0; // No permissions and option to hide when not allowed, even for internal user, is on
11381 }
11382 if (!$menuentry['perms']) {
11383 return 2; // No permissions and user is external
11384 }
11385 return 1;
11386}
11387
11395function roundUpToNextMultiple($n, $x = 5)
11396{
11397 return (ceil($n) % $x === 0) ? ceil($n) : round(($n + $x / 2) / $x) * $x;
11398}
11399
11411function dolGetBadge($label, $html = '', $type = 'primary', $mode = '', $url = '', $params = array())
11412{
11413 $attr = array(
11414 'class'=>'badge '.(!empty($mode) ? ' badge-'.$mode : '').(!empty($type) ? ' badge-'.$type : '').(empty($params['css']) ? '' : ' '.$params['css'])
11415 );
11416
11417 if (empty($html)) {
11418 $html = $label;
11419 }
11420
11421 if (!empty($url)) {
11422 $attr['href'] = $url;
11423 }
11424
11425 if ($mode === 'dot') {
11426 $attr['class'] .= ' classfortooltip';
11427 $attr['title'] = $html;
11428 $attr['aria-label'] = $label;
11429 $html = '';
11430 }
11431
11432 // Override attr
11433 if (!empty($params['attr']) && is_array($params['attr'])) {
11434 foreach ($params['attr'] as $key => $value) {
11435 if ($key == 'class') {
11436 $attr['class'] .= ' '.$value;
11437 } elseif ($key == 'classOverride') {
11438 $attr['class'] = $value;
11439 } else {
11440 $attr[$key] = $value;
11441 }
11442 }
11443 }
11444
11445 // TODO: add hook
11446
11447 // escape all attribute
11448 $attr = array_map('dol_escape_htmltag', $attr);
11449
11450 $TCompiledAttr = array();
11451 foreach ($attr as $key => $value) {
11452 $TCompiledAttr[] = $key.'="'.$value.'"';
11453 }
11454
11455 $compiledAttributes = !empty($TCompiledAttr) ? implode(' ', $TCompiledAttr) : '';
11456
11457 $tag = !empty($url) ? 'a' : 'span';
11458
11459 return '<'.$tag.' '.$compiledAttributes.'>'.$html.'</'.$tag.'>';
11460}
11461
11462
11475function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $statusType = 'status0', $displayMode = 0, $url = '', $params = array())
11476{
11477 global $conf;
11478
11479 $return = '';
11480 $dolGetBadgeParams = array();
11481
11482 if (!empty($params['badgeParams'])) {
11483 $dolGetBadgeParams = $params['badgeParams'];
11484 }
11485
11486 // TODO : add a hook
11487 if ($displayMode == 0) {
11488 $return = !empty($html) ? $html : (empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort));
11489 } elseif ($displayMode == 1) {
11490 $return = !empty($html) ? $html : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11491 } elseif (getDolGlobalString('MAIN_STATUS_USES_IMAGES')) {
11492 // Use status with images (for backward compatibility)
11493 $return = '';
11494 $htmlLabel = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : $statusLabel).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
11495 $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>' : '');
11496
11497 // For small screen, we always use the short label instead of long label.
11498 if (!empty($conf->dol_optimize_smallscreen)) {
11499 if ($displayMode == 0) {
11500 $displayMode = 1;
11501 } elseif ($displayMode == 4) {
11502 $displayMode = 2;
11503 } elseif ($displayMode == 6) {
11504 $displayMode = 5;
11505 }
11506 }
11507
11508 // For backward compatibility. Image's filename are still in French, so we use this array to convert
11509 $statusImg = array(
11510 'status0' => 'statut0',
11511 'status1' => 'statut1',
11512 'status2' => 'statut2',
11513 'status3' => 'statut3',
11514 'status4' => 'statut4',
11515 'status5' => 'statut5',
11516 'status6' => 'statut6',
11517 'status7' => 'statut7',
11518 'status8' => 'statut8',
11519 'status9' => 'statut9'
11520 );
11521
11522 if (!empty($statusImg[$statusType])) {
11523 $htmlImg = img_picto($statusLabel, $statusImg[$statusType]);
11524 } else {
11525 $htmlImg = img_picto($statusLabel, $statusType);
11526 }
11527
11528 if ($displayMode === 2) {
11529 $return = $htmlImg.' '.$htmlLabelShort;
11530 } elseif ($displayMode === 3) {
11531 $return = $htmlImg;
11532 } elseif ($displayMode === 4) {
11533 $return = $htmlImg.' '.$htmlLabel;
11534 } elseif ($displayMode === 5) {
11535 $return = $htmlLabelShort.' '.$htmlImg;
11536 } else { // $displayMode >= 6
11537 $return = $htmlLabel.' '.$htmlImg;
11538 }
11539 } elseif (!getDolGlobalString('MAIN_STATUS_USES_IMAGES') && !empty($displayMode)) {
11540 // Use new badge
11541 $statusLabelShort = (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11542
11543 $dolGetBadgeParams['attr']['class'] = 'badge-status';
11544 $dolGetBadgeParams['attr']['title'] = empty($params['tooltip']) ? $statusLabel : ($params['tooltip'] != 'no' ? $params['tooltip'] : '');
11545
11546 if ($displayMode == 3) {
11547 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), '', $statusType, 'dot', $url, $dolGetBadgeParams);
11548 } elseif ($displayMode === 5) {
11549 $return = dolGetBadge($statusLabelShort, $html, $statusType, '', $url, $dolGetBadgeParams);
11550 } else {
11551 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), $html, $statusType, '', $url, $dolGetBadgeParams);
11552 }
11553 }
11554
11555 return $return;
11556}
11557
11558
11593function dolGetButtonAction($label, $text = '', $actionType = 'default', $url = '', $id = '', $userRight = 1, $params = array())
11594{
11595 global $hookmanager, $action, $object, $langs;
11596
11597 // If $url is an array, we must build a dropdown button
11598 if (is_array($url)) {
11599 // Loop on $url array to remove entries of disabled modules
11600 foreach ($url as $key => $subbutton) {
11601 if (isset($subbutton['enabled']) && empty($subbutton['enabled'])) {
11602 unset($url[$key]);
11603 }
11604 }
11605
11606 $out = '';
11607
11608 if (count($url) > 1) {
11609 $out .= '<div class="dropdown inline-block dropdown-holder">';
11610 $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>';
11611 $out .= '<div class="dropdown-content">';
11612 foreach ($url as $subbutton) {
11613 if (!empty($subbutton['lang'])) {
11614 $langs->load($subbutton['lang']);
11615 }
11616 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
11617 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm'], array('isDropDown' => true));
11618 }
11619 $out .= "</div>";
11620 $out .= "</div>";
11621 } else {
11622 foreach ($url as $subbutton) { // Should loop on 1 record only
11623 if (!empty($subbutton['lang'])) {
11624 $langs->load($subbutton['lang']);
11625 }
11626 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
11627 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm']);
11628 }
11629 }
11630
11631 return $out;
11632 }
11633
11634 // Here, $url is a simple link
11635
11636 if (!empty($params['isDropdown'])) {
11637 $class = "dropdown-item";
11638 } else {
11639 $class = 'butAction';
11640 if ($actionType == 'danger' || $actionType == 'delete') {
11641 $class = 'butActionDelete';
11642 if (!empty($url) && strpos($url, 'token=') === false) {
11643 $url .= '&token='.newToken();
11644 }
11645 }
11646 }
11647 $attr = array(
11648 'class' => $class,
11649 'href' => empty($url) ? '' : $url,
11650 'title' => $label
11651 );
11652
11653 if (empty($text)) {
11654 $text = $label;
11655 $attr['title'] = ''; // if html not set, leave label on title is redundant
11656 } else {
11657 $attr['title'] = $label;
11658 $attr['aria-label'] = $label;
11659 }
11660
11661 if (empty($userRight)) {
11662 $attr['class'] = 'butActionRefused';
11663 $attr['href'] = '';
11664 $attr['title'] = (($label && $text && $label != $text) ? $label : $langs->trans('NotEnoughPermissions'));
11665 }
11666
11667 if (!empty($id)) {
11668 $attr['id'] = $id;
11669 }
11670
11671 // Override attr
11672 if (!empty($params['attr']) && is_array($params['attr'])) {
11673 foreach ($params['attr'] as $key => $value) {
11674 if ($key == 'class') {
11675 $attr['class'] .= ' '.$value;
11676 } elseif ($key == 'classOverride') {
11677 $attr['class'] = $value;
11678 } else {
11679 $attr[$key] = $value;
11680 }
11681 }
11682 }
11683
11684 // automatic add tooltip when title is detected
11685 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
11686 $attr['class'].= ' classfortooltip';
11687 }
11688
11689 // Js Confirm button
11690 if ($userRight && !empty($params['confirm'])) {
11691 if (!is_array($params['confirm'])) {
11692 $params['confirm'] = array();
11693 }
11694
11695 if (empty($params['confirm']['url'])) {
11696 $params['confirm']['url'] = $url . (strpos($url, '?') > 0 ? '&' : '?') . 'confirm=yes';
11697 }
11698
11699 // for js desabled compatibility set $url as call to confirm action and $params['confirm']['url'] to confirmed action
11700 $attr['data-confirm-url'] = $params['confirm']['url'];
11701 $attr['data-confirm-title'] = !empty($params['confirm']['title']) ? $params['confirm']['title'] : $langs->trans('ConfirmBtnCommonTitle', $label);
11702 $attr['data-confirm-content'] = !empty($params['confirm']['content']) ? $params['confirm']['content'] : $langs->trans('ConfirmBtnCommonContent', $label);
11703 $attr['data-confirm-content'] = preg_replace("/\r|\n/", "", $attr['data-confirm-content']);
11704 $attr['data-confirm-action-btn-label'] = !empty($params['confirm']['action-btn-label']) ? $params['confirm']['action-btn-label'] : $langs->trans('Confirm');
11705 $attr['data-confirm-cancel-btn-label'] = !empty($params['confirm']['cancel-btn-label']) ? $params['confirm']['cancel-btn-label'] : $langs->trans('CloseDialog');
11706 $attr['data-confirm-modal'] = !empty($params['confirm']['modal']) ? $params['confirm']['modal'] : true;
11707
11708 $attr['class'].= ' butActionConfirm';
11709 }
11710
11711 if (isset($attr['href']) && empty($attr['href'])) {
11712 unset($attr['href']);
11713 }
11714
11715 // escape all attribute
11716 $attr = array_map('dol_escape_htmltag', $attr);
11717
11718 $TCompiledAttr = array();
11719 foreach ($attr as $key => $value) {
11720 $TCompiledAttr[] = $key.'= "'.$value.'"';
11721 }
11722
11723 $compiledAttributes = empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr);
11724
11725 $tag = !empty($attr['href']) ? 'a' : 'span';
11726
11727
11728 $parameters = array(
11729 'TCompiledAttr' => $TCompiledAttr, // array
11730 'compiledAttributes' => $compiledAttributes, // string
11731 'attr' => $attr,
11732 'tag' => $tag,
11733 'label' => $label,
11734 'html' => $text,
11735 'actionType' => $actionType,
11736 'url' => $url,
11737 'id' => $id,
11738 'userRight' => $userRight,
11739 'params' => $params
11740 );
11741
11742 $reshook = $hookmanager->executeHooks('dolGetButtonAction', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
11743 if ($reshook < 0) {
11744 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
11745 }
11746
11747 if (empty($reshook)) {
11748 if (dol_textishtml($text)) { // If content already HTML encoded
11749 return '<' . $tag . ' ' . $compiledAttributes . '>' . $text . '</' . $tag . '>';
11750 } else {
11751 return '<' . $tag . ' ' . $compiledAttributes . '>' . dol_escape_htmltag($text) . '</' . $tag . '>';
11752 }
11753 } else {
11754 return $hookmanager->resPrint;
11755 }
11756}
11757
11764function dolGetButtonTitleSeparator($moreClass = "")
11765{
11766 return '<span class="button-title-separator '.$moreClass.'" ></span>';
11767}
11768
11775function getFieldErrorIcon($fieldValidationErrorMsg)
11776{
11777 $out = '';
11778 if (!empty($fieldValidationErrorMsg)) {
11779 $out.= '<span class="field-error-icon classfortooltip" title="'.dol_escape_htmltag($fieldValidationErrorMsg, 1).'" role="alert" >'; // role alert is used for accessibility
11780 $out.= '<span class="fa fa-exclamation-circle" aria-hidden="true" ></span>'; // For accessibility icon is separated and aria-hidden
11781 $out.= '</span>';
11782 }
11783
11784 return $out;
11785}
11786
11799function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $url = '', $id = '', $status = 1, $params = array())
11800{
11801 global $langs, $conf, $user;
11802
11803 // Actually this conf is used in css too for external module compatibility and smooth transition to this function
11804 if (getDolGlobalString('MAIN_BUTTON_HIDE_UNAUTHORIZED') && (!$user->admin) && $status <= 0) {
11805 return '';
11806 }
11807
11808 $class = 'btnTitle';
11809 if (in_array($iconClass, array('fa fa-plus-circle', 'fa fa-plus-circle size15x', 'fa fa-comment-dots', 'fa fa-paper-plane'))) {
11810 $class .= ' btnTitlePlus';
11811 }
11812 $useclassfortooltip = 1;
11813
11814 if (!empty($params['morecss'])) {
11815 $class .= ' '.$params['morecss'];
11816 }
11817
11818 $attr = array(
11819 'class' => $class,
11820 'href' => empty($url) ? '' : $url
11821 );
11822
11823 if (!empty($helpText)) {
11824 $attr['title'] = dol_escape_htmltag($helpText);
11825 } elseif (empty($attr['title']) && $label) {
11826 $attr['title'] = $label;
11827 $useclassfortooltip = 0;
11828 }
11829
11830 if ($status == 2) {
11831 $attr['class'] .= ' btnTitleSelected';
11832 } elseif ($status <= 0) {
11833 $attr['class'] .= ' refused';
11834
11835 $attr['href'] = '';
11836
11837 if ($status == -1) { // disable
11838 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("FeatureDisabled"));
11839 } elseif ($status == 0) { // Not enough permissions
11840 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions"));
11841 }
11842 }
11843
11844 if (!empty($attr['title']) && $useclassfortooltip) {
11845 $attr['class'] .= ' classfortooltip';
11846 }
11847
11848 if (!empty($id)) {
11849 $attr['id'] = $id;
11850 }
11851
11852 // Override attr
11853 if (!empty($params['attr']) && is_array($params['attr'])) {
11854 foreach ($params['attr'] as $key => $value) {
11855 if ($key == 'class') {
11856 $attr['class'] .= ' '.$value;
11857 } elseif ($key == 'classOverride') {
11858 $attr['class'] = $value;
11859 } else {
11860 $attr[$key] = $value;
11861 }
11862 }
11863 }
11864
11865 if (isset($attr['href']) && empty($attr['href'])) {
11866 unset($attr['href']);
11867 }
11868
11869 // TODO : add a hook
11870
11871 // escape all attribute
11872 $attr = array_map('dol_escape_htmltag', $attr);
11873
11874 $TCompiledAttr = array();
11875 foreach ($attr as $key => $value) {
11876 $TCompiledAttr[] = $key.'="'.$value.'"';
11877 }
11878
11879 $compiledAttributes = (empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr));
11880
11881 $tag = (empty($attr['href']) ? 'span' : 'a');
11882
11883 $button = '<'.$tag.' '.$compiledAttributes.'>';
11884 $button .= '<span class="'.$iconClass.' valignmiddle btnTitle-icon"></span>';
11885 if (!empty($params['forcenohideoftext'])) {
11886 $button .= '<span class="valignmiddle text-plus-circle btnTitle-label'.(empty($params['forcenohideoftext']) ? ' hideonsmartphone' : '').'">'.$label.'</span>';
11887 }
11888 $button .= '</'.$tag.'>';
11889
11890 return $button;
11891}
11892
11903function getElementProperties($element_type)
11904{
11905 global $conf, $db, $hookmanager;
11906
11907 $regs = array();
11908
11909 //$element_type='facture';
11910
11911 $classfile = $classname = $classpath = $subdir = $dir_output = '';
11912
11913 // Parse element/subelement
11914 $module = $element_type;
11915 $element = $element_type;
11916 $subelement = $element_type;
11917 $table_element = $element_type;
11918
11919 // If we ask a resource form external module (instead of default path)
11920 if (preg_match('/^([^@]+)@([^@]+)$/i', $element_type, $regs)) { // 'myobject@mymodule'
11921 $element = $subelement = $regs[1];
11922 $module = $regs[2];
11923 }
11924
11925 // If we ask a resource for a string with an element and a subelement
11926 // Example 'project_task'
11927 if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { // 'myobject_mysubobject' with myobject=mymodule
11928 $module = $element = $regs[1];
11929 $subelement = $regs[2];
11930 }
11931
11932 // For compatibility and to work with non standard path
11933 if ($element_type == "action" || $element_type == "actioncomm") {
11934 $classpath = 'comm/action/class';
11935 $subelement = 'Actioncomm';
11936 $module = 'agenda';
11937 $table_element = 'actioncomm';
11938 } elseif ($element_type == 'cronjob') {
11939 $classpath = 'cron/class';
11940 $module = 'cron';
11941 $table_element = 'cron';
11942 } elseif ($element_type == 'adherent_type') {
11943 $classpath = 'adherents/class';
11944 $classfile = 'adherent_type';
11945 $module = 'adherent';
11946 $subelement = 'adherent_type';
11947 $classname = 'AdherentType';
11948 $table_element = 'adherent_type';
11949 } elseif ($element_type == 'bank_account') {
11950 $classpath = 'compta/bank/class';
11951 $module = 'bank'; // We need $conf->bank->dir_output and not $conf->banque->dir_output
11952 $classfile = 'account';
11953 $classname = 'Account';
11954 } elseif ($element_type == 'category') {
11955 $classpath = 'categories/class';
11956 $module = 'categorie';
11957 $subelement = 'categorie';
11958 $table_element = 'categorie';
11959 } elseif ($element_type == 'contact') {
11960 $classpath = 'contact/class';
11961 $classfile = 'contact';
11962 $module = 'societe';
11963 $subelement = 'contact';
11964 $table_element = 'socpeople';
11965 } elseif ($element_type == 'inventory') {
11966 $module = 'product';
11967 $classpath = 'product/inventory/class';
11968 } elseif ($element_type == 'stock' || $element_type == 'entrepot') {
11969 $module = 'stock';
11970 $classpath = 'product/stock/class';
11971 $classfile = 'entrepot';
11972 $classname = 'Entrepot';
11973 $table_element = 'entrepot';
11974 } elseif ($element_type == 'project') {
11975 $classpath = 'projet/class';
11976 $module = 'projet';
11977 $table_element = 'projet';
11978 } elseif ($element_type == 'project_task') {
11979 $classpath = 'projet/class';
11980 $module = 'projet';
11981 $subelement = 'task';
11982 $table_element = 'projet_task';
11983 } elseif ($element_type == 'facture' || $element_type == 'invoice') {
11984 $classpath = 'compta/facture/class';
11985 $module = 'facture';
11986 $subelement = 'facture';
11987 $table_element = 'facture';
11988 } elseif ($element_type == 'commande' || $element_type == 'order') {
11989 $classpath = 'commande/class';
11990 $module = 'commande';
11991 $subelement = 'commande';
11992 $table_element = 'commande';
11993 } elseif ($element_type == 'propal') {
11994 $classpath = 'comm/propal/class';
11995 $table_element = 'propal';
11996 } elseif ($element_type == 'shipping') {
11997 $classpath = 'expedition/class';
11998 $classfile = 'expedition';
11999 $classname = 'Expedition';
12000 $module = 'expedition';
12001 $table_element = 'expedition';
12002 } elseif ($element_type == 'supplier_proposal') {
12003 $classpath = 'supplier_proposal/class';
12004 $module = 'supplier_proposal';
12005 $element = 'supplierproposal';
12006 $classfile = 'supplier_proposal';
12007 $subelement = 'supplierproposal';
12008 } elseif ($element_type == 'shipping') {
12009 $classpath = 'expedition/class';
12010 $subelement = 'expedition';
12011 $module = 'expedition_bon';
12012 } elseif ($element_type == 'delivery') {
12013 $classpath = 'delivery/class';
12014 $subelement = 'delivery';
12015 $module = 'expedition';
12016 } elseif ($element_type == 'contract') {
12017 $classpath = 'contrat/class';
12018 $module = 'contrat';
12019 $subelement = 'contrat';
12020 $table_element = 'contract';
12021 } elseif ($element_type == 'mailing') {
12022 $classpath = 'comm/mailing/class';
12023 $module = 'mailing';
12024 $classfile = 'mailing';
12025 $classname = 'Mailing';
12026 $subelement = '';
12027 } elseif ($element_type == 'member') {
12028 $classpath = 'adherents/class';
12029 $module = 'adherent';
12030 $subelement = 'adherent';
12031 $table_element = 'adherent';
12032 } elseif ($element_type == 'usergroup') {
12033 $classpath = 'user/class';
12034 $module = 'user';
12035 } elseif ($element_type == 'mo') {
12036 $classpath = 'mrp/class';
12037 $classfile = 'mo';
12038 $classname = 'Mo';
12039 $module = 'mrp';
12040 $subelement = '';
12041 $table_element = 'mrp_mo';
12042 } elseif ($element_type == 'cabinetmed_cons') {
12043 $classpath = 'cabinetmed/class';
12044 $module = 'cabinetmed';
12045 $subelement = 'cabinetmedcons';
12046 $table_element = 'cabinetmedcons';
12047 } elseif ($element_type == 'fichinter') {
12048 $classpath = 'fichinter/class';
12049 $module = 'ficheinter';
12050 $subelement = 'fichinter';
12051 $table_element = 'fichinter';
12052 } elseif ($element_type == 'dolresource' || $element_type == 'resource') {
12053 $classpath = 'resource/class';
12054 $module = 'resource';
12055 $subelement = 'dolresource';
12056 $table_element = 'resource';
12057 } elseif ($element_type == 'propaldet') {
12058 $classpath = 'comm/propal/class';
12059 $module = 'propal';
12060 $subelement = 'propaleligne';
12061 } elseif ($element_type == 'opensurvey_sondage') {
12062 $classpath = 'opensurvey/class';
12063 $module = 'opensurvey';
12064 $subelement = 'opensurveysondage';
12065 } elseif ($element_type == 'order_supplier') {
12066 $classpath = 'fourn/class';
12067 $module = 'fournisseur';
12068 $classfile = 'fournisseur.commande';
12069 $element = 'order_supplier';
12070 $subelement = '';
12071 $classname = 'CommandeFournisseur';
12072 $table_element = 'commande_fournisseur';
12073 } elseif ($element_type == 'commande_fournisseurdet') {
12074 $classpath = 'fourn/class';
12075 $module = 'fournisseur';
12076 $classfile = 'fournisseur.commande';
12077 $element = 'commande_fournisseurdet';
12078 $subelement = '';
12079 $classname = 'CommandeFournisseurLigne';
12080 $table_element = 'commande_fournisseurdet';
12081 } elseif ($element_type == 'invoice_supplier') {
12082 $classpath = 'fourn/class';
12083 $module = 'fournisseur';
12084 $classfile = 'fournisseur.facture';
12085 $element = 'invoice_supplier';
12086 $subelement = '';
12087 $classname = 'FactureFournisseur';
12088 $table_element = 'facture_fourn';
12089 } elseif ($element_type == "service") {
12090 $classpath = 'product/class';
12091 $subelement = 'product';
12092 $table_element = 'product';
12093 } elseif ($element_type == 'salary') {
12094 $classpath = 'salaries/class';
12095 $module = 'salaries';
12096 } elseif ($element_type == 'payment_salary') {
12097 $classpath = 'salaries/class';
12098 $classfile = 'paymentsalary';
12099 $classname = 'PaymentSalary';
12100 $module = 'salaries';
12101 } elseif ($element_type == 'productlot') {
12102 $module = 'productbatch';
12103 $classpath = 'product/stock/class';
12104 $classfile = 'productlot';
12105 $classname = 'Productlot';
12106 $element = 'productlot';
12107 $subelement = '';
12108 $table_element = 'product_lot';
12109 } elseif ($element_type == 'websitepage') {
12110 $classpath = 'website/class';
12111 $classfile = 'websitepage';
12112 $classname = 'Websitepage';
12113 $module = 'website';
12114 $subelement = 'websitepage';
12115 $table_element = 'website_page';
12116 } elseif ($element_type == 'fiscalyear') {
12117 $classpath = 'core/class';
12118 $module = 'accounting';
12119 $subelement = 'fiscalyear';
12120 } elseif ($element_type == 'chargesociales') {
12121 $classpath = 'compta/sociales/class';
12122 $module = 'tax';
12123 $table_element = 'chargesociales';
12124 } elseif ($element_type == 'tva') {
12125 $classpath = 'compta/tva/class';
12126 $module = 'tax';
12127 $subdir = '/vat';
12128 $table_element = 'tva';
12129 } elseif ($element_type == 'emailsenderprofile') {
12130 $module = '';
12131 $classpath = 'core/class';
12132 $classfile = 'emailsenderprofile';
12133 $classname = 'EmailSenderProfile';
12134 $table_element = 'c_email_senderprofile';
12135 $subelement = '';
12136 } elseif ($element_type == 'ccountry') {
12137 $module = '';
12138 $classpath = 'core/class';
12139 $classfile = 'ccountry';
12140 $classname = 'Ccountry';
12141 $table_element = 'c_country';
12142 $subelement = '';
12143 }
12144
12145 if (empty($classfile)) {
12146 $classfile = strtolower($subelement);
12147 }
12148 if (empty($classname)) {
12149 $classname = ucfirst($subelement);
12150 }
12151 if (empty($classpath)) {
12152 $classpath = $module.'/class';
12153 }
12154
12155 //print 'getElementProperties subdir='.$subdir;
12156
12157 // Set dir_output
12158 if ($module && isset($conf->$module)) { // The generic case
12159 if (!empty($conf->$module->multidir_output[$conf->entity])) {
12160 $dir_output = $conf->$module->multidir_output[$conf->entity];
12161 } elseif (!empty($conf->$module->output[$conf->entity])) {
12162 $dir_output = $conf->$module->output[$conf->entity];
12163 } elseif (!empty($conf->$module->dir_output)) {
12164 $dir_output = $conf->$module->dir_output;
12165 }
12166 }
12167
12168 // Overwrite value for special cases
12169 if ($element == 'order_supplier') {
12170 $dir_output = $conf->fournisseur->commande->dir_output;
12171 } elseif ($element == 'invoice_supplier') {
12172 $dir_output = $conf->fournisseur->facture->dir_output;
12173 }
12174 $dir_output .= $subdir;
12175
12176 $elementProperties = array(
12177 'module' => $module,
12178 'element' => $element,
12179 'table_element' => $table_element,
12180 'subelement' => $subelement,
12181 'classpath' => $classpath,
12182 'classfile' => $classfile,
12183 'classname' => $classname,
12184 'dir_output' => $dir_output
12185 );
12186
12187
12188 // Add hook
12189 if (!is_object($hookmanager)) {
12190 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
12191 $hookmanager = new HookManager($db);
12192 }
12193 $hookmanager->initHooks(array('elementproperties'));
12194
12195
12196 // Hook params
12197 $parameters = array(
12198 'elementType' => $element_type,
12199 'elementProperties' => $elementProperties
12200 );
12201
12202 $reshook = $hookmanager->executeHooks('getElementProperties', $parameters);
12203
12204 if ($reshook) {
12205 $elementProperties = $hookmanager->resArray;
12206 } elseif (!empty($hookmanager->resArray) && is_array($hookmanager->resArray)) { // resArray is always an array but for sécurity against misconfigured external modules
12207 $elementProperties = array_replace($elementProperties, $hookmanager->resArray);
12208 }
12209
12210 // context of elementproperties doesn't need to exist out of this function so delete it to avoid elementproperties context is equal to all
12211 if (($key = array_search('elementproperties', $hookmanager->contextarray)) !== false) {
12212 unset($hookmanager->contextarray[$key]);
12213 }
12214
12215 return $elementProperties;
12216}
12217
12228function fetchObjectByElement($element_id, $element_type, $element_ref = '')
12229{
12230 global $db;
12231
12232 $ret = 0;
12233
12234 $element_prop = getElementProperties($element_type);
12235
12236 if ($element_prop['module'] == 'product' || $element_prop['module'] == 'service') {
12237 // For example, for an extrafield 'product' (shared for both product and service) that is a link to an object,
12238 // this is called with $element_type = 'product' when we need element properties of a service, we must return a product. If we create the
12239 // extrafield for a service, it is not supported and not found when editing the product/service card. So we must keep 'product' for extrafields
12240 // of service and we will return properties of a product.
12241 $ismodenabled = (isModEnabled('product') || isModEnabled('service'));
12242 } else {
12243 $ismodenabled = isModEnabled($element_prop['module']);
12244 }
12245 //var_dump('element_type='.$element_type);
12246 //var_dump($element_prop);
12247 //var_dump($element_prop['module'].' '.$ismodenabled);
12248 if (is_array($element_prop) && (empty($element_prop['module']) || $ismodenabled)) {
12249 dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php');
12250
12251 if (class_exists($element_prop['classname'])) {
12252 $classname = $element_prop['classname'];
12253 $objecttmp = new $classname($db);
12254
12255 if ($element_id > 0 || !empty($element_ref)) {
12256 $ret = $objecttmp->fetch($element_id, $element_ref);
12257 if ($ret >= 0) {
12258 if (empty($objecttmp->module)) {
12259 $objecttmp->module = $element_prop['module'];
12260 }
12261 return $objecttmp;
12262 }
12263 } else {
12264 return $objecttmp; // returned an object without fetch
12265 }
12266 } else {
12267 return -1;
12268 }
12269 }
12270
12271 return $ret;
12272}
12273
12281{
12282 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)) {
12283 return true;
12284 }
12285
12286 return false;
12287}
12288
12296function newToken()
12297{
12298 return empty($_SESSION['newtoken']) ? '' : $_SESSION['newtoken'];
12299}
12300
12309{
12310 return isset($_SESSION['token']) ? $_SESSION['token'] : '';
12311}
12312
12318function getNonce()
12319{
12320 global $conf;
12321
12322 if (empty($conf->cache['nonce'])) {
12323 $conf->cache['nonce'] = dolGetRandomBytes(8);
12324 }
12325
12326 return $conf->cache['nonce'];
12327}
12328
12329
12342function startSimpleTable($header, $link = "", $arguments = "", $emptyRows = 0, $number = -1)
12343{
12344 global $langs;
12345
12346 print '<div class="div-table-responsive-no-min">';
12347 print '<table class="noborder centpercent">';
12348 print '<tr class="liste_titre">';
12349
12350 print $emptyRows < 1 ? '<th>' : '<th colspan="'.($emptyRows + 1).'">';
12351
12352 print $langs->trans($header);
12353
12354 // extra space between the first header and the number
12355 if ($number > -1) {
12356 print ' ';
12357 }
12358
12359 if (!empty($link)) {
12360 if (!empty($arguments)) {
12361 print '<a href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
12362 } else {
12363 print '<a href="'.DOL_URL_ROOT.'/'.$link.'">';
12364 }
12365 }
12366
12367 if ($number > -1) {
12368 print '<span class="badge">'.$number.'</span>';
12369 }
12370
12371 if (!empty($link)) {
12372 print '</a>';
12373 }
12374
12375 print '</th>';
12376
12377 if ($number < 0 && !empty($link)) {
12378 print '<th class="right">';
12379
12380 if (!empty($arguments)) {
12381 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
12382 } else {
12383 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'">';
12384 }
12385
12386 print $langs->trans("FullList");
12387 print '</a>';
12388 print '</th>';
12389 }
12390
12391 print '</tr>';
12392}
12393
12402function finishSimpleTable($addLineBreak = false)
12403{
12404 print '</table>';
12405 print '</div>';
12406
12407 if ($addLineBreak) {
12408 print '<br>';
12409 }
12410}
12411
12423function addSummaryTableLine($tableColumnCount, $num, $nbofloop = 0, $total = 0, $noneWord = "None", $extraRightColumn = false)
12424{
12425 global $langs;
12426
12427 if ($num === 0) {
12428 print '<tr class="oddeven">';
12429 print '<td colspan="'.$tableColumnCount.'"><span class="opacitymedium">'.$langs->trans($noneWord).'</span></td>';
12430 print '</tr>';
12431 return;
12432 }
12433
12434 if ($nbofloop === 0) {
12435 // don't show a summary line
12436 return;
12437 }
12438
12439 if ($num === 0) {
12440 $colspan = $tableColumnCount;
12441 } elseif ($num > $nbofloop) {
12442 $colspan = $tableColumnCount;
12443 } else {
12444 $colspan = $tableColumnCount - 1;
12445 }
12446
12447 if ($extraRightColumn) {
12448 $colspan--;
12449 }
12450
12451 print '<tr class="liste_total">';
12452
12453 if ($nbofloop > 0 && $num > $nbofloop) {
12454 print '<td colspan="'.$colspan.'" class="right">'.$langs->trans("XMoreLines", ($num - $nbofloop)).'</td>';
12455 } else {
12456 print '<td colspan="'.$colspan.'" class="right"> '.$langs->trans("Total").'</td>';
12457 print '<td class="right centpercent">'.price($total).'</td>';
12458 }
12459
12460 if ($extraRightColumn) {
12461 print '<td></td>';
12462 }
12463
12464 print '</tr>';
12465}
12466
12475function readfileLowMemory($fullpath_original_file_osencoded, $method = -1)
12476{
12477 if ($method == -1) {
12478 $method = 0;
12479 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_FREAD')) {
12480 $method = 1;
12481 }
12482 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_STREAM_COPY')) {
12483 $method = 2;
12484 }
12485 }
12486
12487 // Be sure we don't have output buffering enabled to have readfile working correctly
12488 while (ob_get_level()) {
12489 ob_end_flush();
12490 }
12491
12492 // Solution 0
12493 if ($method == 0) {
12494 readfile($fullpath_original_file_osencoded);
12495 } elseif ($method == 1) {
12496 // Solution 1
12497 $handle = fopen($fullpath_original_file_osencoded, "rb");
12498 while (!feof($handle)) {
12499 print fread($handle, 8192);
12500 }
12501 fclose($handle);
12502 } elseif ($method == 2) {
12503 // Solution 2
12504 $handle1 = fopen($fullpath_original_file_osencoded, "rb");
12505 $handle2 = fopen("php://output", "wb");
12506 stream_copy_to_stream($handle1, $handle2);
12507 fclose($handle1);
12508 fclose($handle2);
12509 }
12510}
12511
12521function showValueWithClipboardCPButton($valuetocopy, $showonlyonhover = 1, $texttoshow = '')
12522{
12523 /*
12524 global $conf;
12525
12526 if (!empty($conf->dol_no_mouse_hover)) {
12527 $showonlyonhover = 0;
12528 }*/
12529
12530 $tag = 'span'; // Using div (like any style of type 'block') does not work when using the js copy code.
12531 if ($texttoshow === 'none') {
12532 $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>';
12533 } elseif ($texttoshow) {
12534 $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>';
12535 } else {
12536 $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>';
12537 }
12538
12539 return $result;
12540}
12541
12542
12549function jsonOrUnserialize($stringtodecode)
12550{
12551 $result = json_decode($stringtodecode);
12552 if ($result === null) {
12553 $result = unserialize($stringtodecode);
12554 }
12555
12556 return $result;
12557}
12558
12559
12573function forgeSQLFromUniversalSearchCriteria($filter, &$errorstr = '', $noand = 0, $nopar = 0, $noerror = 0)
12574{
12575 if (empty($filter)) {
12576 return ''; // to avoid the return "AND (())"
12577 }
12578
12579 if (!preg_match('/^\‍(.*\‍)$/', $filter)) { // If $filter does not start and end with ()
12580 $filter = '(' . $filter . ')';
12581 }
12582
12583 $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'
12584
12585 if (!dolCheckFilters($filter, $errorstr)) {
12586 if ($noerror) {
12587 return '1 = 2';
12588 } else {
12589 return 'Filter syntax error - '.$errorstr; // Bad balance of parenthesis, we return an error message or force a SQL not found
12590 }
12591 }
12592
12593 // Test the filter syntax
12594 $t = preg_replace_callback('/'.$regexstring.'/i', 'dolForgeDummyCriteriaCallback', $filter);
12595 $t = str_replace(array('and','or','AND','OR',' '), '', $t); // Remove the only strings allowed between each () criteria
12596 // If the string result contains something else than '()', the syntax was wrong
12597 if (preg_match('/[^\‍(\‍)]/', $t)) {
12598 $errorstr = 'Bad syntax of the search string';
12599 if ($noerror) {
12600 return '1 = 2';
12601 } else {
12602 return 'Filter syntax error - '.$errorstr; // Bad syntax of the search string, we return an error message or force a SQL not found
12603 }
12604 }
12605
12606 return ($noand ? "" : " AND ").($nopar ? "" : '(').preg_replace_callback('/'.$regexstring.'/i', 'dolForgeCriteriaCallback', $filter).($nopar ? "" : ')');
12607}
12608
12616function dolCheckFilters($sqlfilters, &$error = '')
12617{
12618 //$regexstring='\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^:\‍(\‍)]+)\‍)';
12619 //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
12620 $tmp = $sqlfilters;
12621 $i = 0;
12622 $nb = strlen($tmp);
12623 $counter = 0;
12624 while ($i < $nb) {
12625 if ($tmp[$i] == '(') {
12626 $counter++;
12627 }
12628 if ($tmp[$i] == ')') {
12629 $counter--;
12630 }
12631 if ($counter < 0) {
12632 $error = "Wrond balance of parenthesis in sqlfilters=".$sqlfilters;
12633 dol_syslog($error, LOG_WARNING);
12634 return false;
12635 }
12636 $i++;
12637 }
12638 return true;
12639}
12640
12649{
12650 //dol_syslog("Convert matches ".$matches[1]);
12651 if (empty($matches[1])) {
12652 return '';
12653 }
12654 $tmp = explode(':', $matches[1]);
12655 if (count($tmp) < 3) {
12656 return '';
12657 }
12658
12659 return '()'; // An empty criteria
12660}
12661
12671{
12672 global $db;
12673
12674 //dol_syslog("Convert matches ".$matches[1]);
12675 if (empty($matches[1])) {
12676 return '';
12677 }
12678 $tmp = explode(':', $matches[1]);
12679 if (count($tmp) < 3) {
12680 return '';
12681 }
12682
12683 $operand = preg_replace('/[^a-z0-9\._]/i', '', trim($tmp[0]));
12684
12685 $operator = strtoupper(preg_replace('/[^a-z<>!=]/i', '', trim($tmp[1])));
12686
12687 $realOperator = [
12688 'NOTLIKE' => 'NOT LIKE',
12689 'ISNOT' => 'IS NOT',
12690 'NOTIN' => 'NOT IN',
12691 '!=' => '<>',
12692 ];
12693
12694 if (array_key_exists($operator, $realOperator)) {
12695 $operator = $realOperator[$operator];
12696 }
12697
12698
12699 $tmpescaped = $tmp[2];
12700 $regbis = array();
12701
12702 if ($operator == 'IN' || $operator == 'NOT IN') { // IN is allowed for list of ID or code only
12703 //if (!preg_match('/^\‍(.*\‍)$/', $tmpescaped)) {
12704 $tmpescaped2 = '(';
12705 // Explode and sanitize each element in list
12706 $tmpelemarray = explode(',', $tmpescaped);
12707 foreach ($tmpelemarray as $tmpkey => $tmpelem) {
12708 $reg = array();
12709 if (preg_match('/^\'(.*)\'$/', $tmpelem, $reg)) {
12710 $tmpelemarray[$tmpkey] = "'".$db->escape($db->sanitize($reg[1], 1, 1, 1))."'";
12711 } else {
12712 $tmpelemarray[$tmpkey] = $db->escape($db->sanitize($tmpelem, 1, 1, 1));
12713 }
12714 }
12715 $tmpescaped2 .= join(',', $tmpelemarray);
12716 $tmpescaped2 .= ')';
12717
12718 $tmpescaped = $tmpescaped2;
12719 } elseif ($operator == 'LIKE' || $operator == 'NOT LIKE') {
12720 if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12721 $tmpescaped = $regbis[1];
12722 }
12723 //$tmpescaped = "'".$db->escape($db->escapeforlike($regbis[1]))."'";
12724 $tmpescaped = "'".$db->escape($tmpescaped)."'"; // We do not escape the _ and % so the like will works
12725 } elseif (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12726 $tmpescaped = "'".$db->escape($regbis[1])."'";
12727 } else {
12728 if (strtoupper($tmpescaped) == 'NULL') {
12729 $tmpescaped = 'NULL';
12730 } elseif (is_int($tmpescaped)) {
12731 $tmpescaped = (int) $tmpescaped;
12732 } else {
12733 $tmpescaped = (float) $tmpescaped;
12734 }
12735 }
12736
12737 return '('.$db->escape($operand).' '.strtoupper($operator).' '.$tmpescaped.')';
12738}
12739
12740
12750function getTimelineIcon($actionstatic, &$histo, $key)
12751{
12752 global $conf, $langs;
12753
12754 $out = '<!-- timeline icon -->'."\n";
12755 $iconClass = 'fa fa-comments';
12756 $img_picto = '';
12757 $colorClass = '';
12758 $pictoTitle = '';
12759
12760 if ($histo[$key]['percent'] == -1) {
12761 $colorClass = 'timeline-icon-not-applicble';
12762 $pictoTitle = $langs->trans('StatusNotApplicable');
12763 } elseif ($histo[$key]['percent'] == 0) {
12764 $colorClass = 'timeline-icon-todo';
12765 $pictoTitle = $langs->trans('StatusActionToDo').' (0%)';
12766 } elseif ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100) {
12767 $colorClass = 'timeline-icon-in-progress';
12768 $pictoTitle = $langs->trans('StatusActionInProcess').' ('.$histo[$key]['percent'].'%)';
12769 } elseif ($histo[$key]['percent'] >= 100) {
12770 $colorClass = 'timeline-icon-done';
12771 $pictoTitle = $langs->trans('StatusActionDone').' (100%)';
12772 }
12773
12774 if ($actionstatic->code == 'AC_TICKET_CREATE') {
12775 $iconClass = 'fa fa-ticket';
12776 } elseif ($actionstatic->code == 'AC_TICKET_MODIFY') {
12777 $iconClass = 'fa fa-pencilxxx';
12778 } elseif (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12779 $iconClass = 'fa fa-comments';
12780 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12781 $iconClass = 'fa fa-mask';
12782 } elseif (getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
12783 if ($actionstatic->type_picto) {
12784 $img_picto = img_picto('', $actionstatic->type_picto);
12785 } else {
12786 if ($actionstatic->type_code == 'AC_RDV') {
12787 $iconClass = 'fa fa-handshake';
12788 } elseif ($actionstatic->type_code == 'AC_TEL') {
12789 $iconClass = 'fa fa-phone';
12790 } elseif ($actionstatic->type_code == 'AC_FAX') {
12791 $iconClass = 'fa fa-fax';
12792 } elseif ($actionstatic->type_code == 'AC_EMAIL') {
12793 $iconClass = 'fa fa-envelope';
12794 } elseif ($actionstatic->type_code == 'AC_INT') {
12795 $iconClass = 'fa fa-shipping-fast';
12796 } elseif ($actionstatic->type_code == 'AC_OTH_AUTO') {
12797 $iconClass = 'fa fa-robot';
12798 } elseif (!preg_match('/_AUTO/', $actionstatic->type_code)) {
12799 $iconClass = 'fa fa-robot';
12800 }
12801 }
12802 }
12803
12804 $out .= '<i class="'.$iconClass.' '.$colorClass.'" title="'.$pictoTitle.'">'.$img_picto.'</i>'."\n";
12805 return $out;
12806}
12807
12814function getActionCommEcmList($object)
12815{
12816 global $conf, $db;
12817
12818 $documents = array();
12819
12820 $sql = 'SELECT ecm.rowid as id, ecm.src_object_type, ecm.src_object_id, ecm.filepath, ecm.filename';
12821 $sql .= ' FROM '.MAIN_DB_PREFIX.'ecm_files ecm';
12822 $sql .= " WHERE ecm.filepath = 'agenda/".((int) $object->id)."'";
12823 //$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
12824 $sql .= ' ORDER BY ecm.position ASC';
12825
12826 $resql = $db->query($sql);
12827 if ($resql) {
12828 if ($db->num_rows($resql)) {
12829 while ($obj = $db->fetch_object($resql)) {
12830 $documents[$obj->id] = $obj;
12831 }
12832 }
12833 }
12834
12835 return $documents;
12836}
12837
12838
12839
12857function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
12858{
12859 global $user, $conf;
12860 global $form;
12861
12862 global $param, $massactionbutton;
12863
12864 dol_include_once('/comm/action/class/actioncomm.class.php');
12865
12866 // Check parameters
12867 if (!is_object($filterobj) && !is_object($objcon)) {
12868 dol_print_error('', 'BadParameter');
12869 }
12870
12871 $histo = array();
12872 $numaction = 0;
12873 $now = dol_now();
12874
12875 $sortfield_list = explode(',', $sortfield);
12876 $sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent');
12877 $sortfield_new_list = array();
12878 foreach ($sortfield_list as $sortfield_value) {
12879 $sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)];
12880 }
12881 $sortfield_new = implode(',', $sortfield_new_list);
12882
12883 if (isModEnabled('agenda')) {
12884 // Search histo on actioncomm
12885 if (is_object($objcon) && $objcon->id > 0) {
12886 $sql = "SELECT DISTINCT a.id, a.label as label,";
12887 } else {
12888 $sql = "SELECT a.id, a.label as label,";
12889 }
12890 $sql .= " a.datep as dp,";
12891 $sql .= " a.note as message,";
12892 $sql .= " a.datep2 as dp2,";
12893 $sql .= " a.percent as percent, 'action' as type,";
12894 $sql .= " a.fk_element, a.elementtype,";
12895 $sql .= " a.fk_contact,";
12896 $sql .= " a.email_from as msg_from,";
12897 $sql .= " c.code as acode, c.libelle as alabel, c.picto as apicto,";
12898 $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";
12899 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12900 $sql .= ", sp.lastname, sp.firstname";
12901 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12902 $sql .= ", m.lastname, m.firstname";
12903 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12904 $sql .= ", o.ref";
12905 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12906 $sql .= ", o.ref";
12907 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12908 $sql .= ", o.ref";
12909 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12910 $sql .= ", o.ref";
12911 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12912 $sql .= ", o.ref";
12913 }
12914 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
12915 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
12916 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
12917
12918 $force_filter_contact = false;
12919 if (is_object($objcon) && $objcon->id > 0) {
12920 $force_filter_contact = true;
12921 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
12922 $sql .= " AND r.element_type = '".$db->escape($objcon->table_element)."' AND r.fk_element = ".((int) $objcon->id);
12923 }
12924
12925 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12926 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
12927 } elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
12928 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er";
12929 $sql .= " ON er.resource_type = 'dolresource'";
12930 $sql .= " AND er.element_id = a.id";
12931 $sql .= " AND er.resource_id = ".((int) $filterobj->id);
12932 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12933 $sql .= ", ".MAIN_DB_PREFIX."adherent as m";
12934 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12935 $sql .= ", ".MAIN_DB_PREFIX."commande_fournisseur as o";
12936 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12937 $sql .= ", ".MAIN_DB_PREFIX."product as o";
12938 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12939 $sql .= ", ".MAIN_DB_PREFIX."ticket as o";
12940 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12941 $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o";
12942 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12943 $sql .= ", ".MAIN_DB_PREFIX."contrat as o";
12944 }
12945
12946 $sql .= " WHERE a.entity IN (".getEntity('agenda').")";
12947 if ($force_filter_contact === false) {
12948 if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) {
12949 $sql .= " AND a.fk_soc = ".((int) $filterobj->id);
12950 } elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) {
12951 $sql .= " AND a.fk_project = ".((int) $filterobj->id);
12952 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12953 $sql .= " AND a.fk_element = m.rowid AND a.elementtype = 'member'";
12954 if ($filterobj->id) {
12955 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12956 }
12957 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12958 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'order_supplier'";
12959 if ($filterobj->id) {
12960 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12961 }
12962 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12963 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
12964 if ($filterobj->id) {
12965 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12966 }
12967 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12968 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'ticket'";
12969 if ($filterobj->id) {
12970 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12971 }
12972 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12973 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'bom'";
12974 if ($filterobj->id) {
12975 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12976 }
12977 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12978 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'contract'";
12979 if ($filterobj->id) {
12980 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12981 }
12982 }
12983 }
12984
12985 // Condition on actioncode
12986 if (!empty($actioncode)) {
12987 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
12988 if ($actioncode == 'AC_NON_AUTO') {
12989 $sql .= " AND c.type != 'systemauto'";
12990 } elseif ($actioncode == 'AC_ALL_AUTO') {
12991 $sql .= " AND c.type = 'systemauto'";
12992 } else {
12993 if ($actioncode == 'AC_OTH') {
12994 $sql .= " AND c.type != 'systemauto'";
12995 } elseif ($actioncode == 'AC_OTH_AUTO') {
12996 $sql .= " AND c.type = 'systemauto'";
12997 }
12998 }
12999 } else {
13000 if ($actioncode == 'AC_NON_AUTO') {
13001 $sql .= " AND c.type != 'systemauto'";
13002 } elseif ($actioncode == 'AC_ALL_AUTO') {
13003 $sql .= " AND c.type = 'systemauto'";
13004 } else {
13005 $sql .= " AND c.code = '".$db->escape($actioncode)."'";
13006 }
13007 }
13008 }
13009 if ($donetodo == 'todo') {
13010 $sql .= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
13011 } elseif ($donetodo == 'done') {
13012 $sql .= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
13013 }
13014 if (is_array($filters) && $filters['search_agenda_label']) {
13015 $sql .= natural_search('a.label', $filters['search_agenda_label']);
13016 }
13017 }
13018
13019 // Add also event from emailings. TODO This should be replaced by an automatic event ? May be it's too much for very large emailing.
13020 if (isModEnabled('mailing') && !empty($objcon->email)
13021 && (empty($actioncode) || $actioncode == 'AC_OTH_AUTO' || $actioncode == 'AC_EMAILING')) {
13022 $langs->load("mails");
13023
13024 $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";
13025 $sql2 .= ", null as fk_element, '' as elementtype, null as contact_id";
13026 $sql2 .= ", 'AC_EMAILING' as acode, '' as alabel, '' as apicto";
13027 $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
13028 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
13029 $sql2 .= ", '' as lastname, '' as firstname";
13030 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
13031 $sql2 .= ", '' as lastname, '' as firstname";
13032 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
13033 $sql2 .= ", '' as ref";
13034 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
13035 $sql2 .= ", '' as ref";
13036 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
13037 $sql2 .= ", '' as ref";
13038 }
13039 $sql2 .= " FROM ".MAIN_DB_PREFIX."mailing as m, ".MAIN_DB_PREFIX."mailing_cibles as mc, ".MAIN_DB_PREFIX."user as u";
13040 $sql2 .= " WHERE mc.email = '".$db->escape($objcon->email)."'"; // Search is done on email.
13041 $sql2 .= " AND mc.statut = 1";
13042 $sql2 .= " AND u.rowid = m.fk_user_valid";
13043 $sql2 .= " AND mc.fk_mailing=m.rowid";
13044 }
13045
13046 if (!empty($sql) && !empty($sql2)) {
13047 $sql = $sql." UNION ".$sql2;
13048 } elseif (empty($sql) && !empty($sql2)) {
13049 $sql = $sql2;
13050 }
13051
13052 // TODO Add limit in nb of results
13053 if ($sql) { // May not be defined if module Agenda is not enabled and mailing module disabled too
13054 $sql .= $db->order($sortfield_new, $sortorder);
13055
13056 dol_syslog("function.lib::show_actions_messaging", LOG_DEBUG);
13057 $resql = $db->query($sql);
13058 if ($resql) {
13059 $i = 0;
13060 $num = $db->num_rows($resql);
13061
13062 while ($i < $num) {
13063 $obj = $db->fetch_object($resql);
13064
13065 if ($obj->type == 'action') {
13066 $contactaction = new ActionComm($db);
13067 $contactaction->id = $obj->id;
13068 $result = $contactaction->fetchResources();
13069 if ($result < 0) {
13070 dol_print_error($db);
13071 setEventMessage("actions.lib::show_actions_messaging Error fetch ressource", 'errors');
13072 }
13073
13074 //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
13075 //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
13076 $tododone = '';
13077 if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && $obj->dp > $now)) {
13078 $tododone = 'todo';
13079 }
13080
13081 $histo[$numaction] = array(
13082 'type'=>$obj->type,
13083 'tododone'=>$tododone,
13084 'id'=>$obj->id,
13085 'datestart'=>$db->jdate($obj->dp),
13086 'dateend'=>$db->jdate($obj->dp2),
13087 'note'=>$obj->label,
13088 'message'=>$obj->message,
13089 'percent'=>$obj->percent,
13090
13091 'userid'=>$obj->user_id,
13092 'login'=>$obj->user_login,
13093 'userfirstname'=>$obj->user_firstname,
13094 'userlastname'=>$obj->user_lastname,
13095 'userphoto'=>$obj->user_photo,
13096 'msg_from'=>$obj->msg_from,
13097
13098 'contact_id'=>$obj->fk_contact,
13099 'socpeopleassigned' => $contactaction->socpeopleassigned,
13100 'lastname' => (empty($obj->lastname) ? '' : $obj->lastname),
13101 'firstname' => (empty($obj->firstname) ? '' : $obj->firstname),
13102 'fk_element'=>$obj->fk_element,
13103 'elementtype'=>$obj->elementtype,
13104 // Type of event
13105 'acode'=>$obj->acode,
13106 'alabel'=>$obj->alabel,
13107 'libelle'=>$obj->alabel, // deprecated
13108 'apicto'=>$obj->apicto
13109 );
13110 } else {
13111 $histo[$numaction] = array(
13112 'type'=>$obj->type,
13113 'tododone'=>'done',
13114 'id'=>$obj->id,
13115 'datestart'=>$db->jdate($obj->dp),
13116 'dateend'=>$db->jdate($obj->dp2),
13117 'note'=>$obj->label,
13118 'message'=>$obj->message,
13119 'percent'=>$obj->percent,
13120 'acode'=>$obj->acode,
13121
13122 'userid'=>$obj->user_id,
13123 'login'=>$obj->user_login,
13124 'userfirstname'=>$obj->user_firstname,
13125 'userlastname'=>$obj->user_lastname,
13126 'userphoto'=>$obj->user_photo
13127 );
13128 }
13129
13130 $numaction++;
13131 $i++;
13132 }
13133 } else {
13134 dol_print_error($db);
13135 }
13136 }
13137
13138 // Set $out to show events
13139 $out = '';
13140
13141 if (!isModEnabled('agenda')) {
13142 $langs->loadLangs(array("admin", "errors"));
13143 $out = info_admin($langs->trans("WarningModuleXDisabledSoYouMayMissEventHere", $langs->transnoentitiesnoconv("Module2400Name")), 0, 0, 'warning');
13144 }
13145
13146 if (isModEnabled('agenda') || (isModEnabled('mailing') && !empty($objcon->email))) {
13147 $delay_warning = $conf->global->MAIN_DELAY_ACTIONS_TODO * 24 * 60 * 60;
13148
13149 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
13150 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
13151 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
13152 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
13153
13154 $formactions = new FormActions($db);
13155
13156 $actionstatic = new ActionComm($db);
13157 $userstatic = new User($db);
13158 $contactstatic = new Contact($db);
13159 $userGetNomUrlCache = array();
13160 $contactGetNomUrlCache = array();
13161
13162 $out .= '<div class="filters-container" >';
13163 $out .= '<form name="listactionsfilter" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
13164 $out .= '<input type="hidden" name="token" value="'.newToken().'">';
13165
13166 if ($objcon && get_class($objcon) == 'Contact' &&
13167 (is_null($filterobj) || get_class($filterobj) == 'Societe')) {
13168 $out .= '<input type="hidden" name="id" value="'.$objcon->id.'" />';
13169 } else {
13170 $out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
13171 }
13172 if ($filterobj && get_class($filterobj) == 'Societe') {
13173 $out .= '<input type="hidden" name="socid" value="'.$filterobj->id.'" />';
13174 }
13175
13176 $out .= "\n";
13177
13178 $out .= '<div class="div-table-responsive-no-min">';
13179 $out .= '<table class="noborder borderbottom centpercent">';
13180
13181 $out .= '<tr class="liste_titre">';
13182
13183 // Action column
13184 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
13185 $out .= '<th class="liste_titre width50 middle">';
13186 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
13187 $out .= $searchpicto;
13188 $out .= '</th>';
13189 }
13190
13191 $out .= getTitleFieldOfList('Date', 0, $_SERVER["PHP_SELF"], 'a.datep', '', $param, '', $sortfield, $sortorder, '')."\n";
13192
13193 $out .= '<th class="liste_titre"><strong class="hideonsmartphone">'.$langs->trans("Search").' : </strong></th>';
13194 if ($donetodo) {
13195 $out .= '<th class="liste_titre"></th>';
13196 }
13197 $out .= '<th class="liste_titre">';
13198 $out .= '<span class="fas fa-square inline-block fawidth30" style=" color: #ddd;" title="'.$langs->trans("ActionType").'"></span>';
13199 //$out .= img_picto($langs->trans("Type"), 'type');
13200 $out .= $formactions->select_type_actions($actioncode, "actioncode", '', !getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : -1, 0, 0, 1, 'minwidth200imp');
13201 $out .= '</th>';
13202 $out .= '<th class="liste_titre maxwidth100onsmartphone">';
13203 $out .= '<input type="text" class="maxwidth100onsmartphone" name="search_agenda_label" value="'.$filters['search_agenda_label'].'" placeholder="'.$langs->trans("Label").'">';
13204 $out .= '</th>';
13205
13206 // Action column
13207 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
13208 $out .= '<th class="liste_titre width50 middle">';
13209 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
13210 $out .= $searchpicto;
13211 $out .= '</th>';
13212 }
13213
13214 $out .= '</tr>';
13215
13216
13217 $out .= '</table>';
13218
13219 $out .= '</form>';
13220 $out .= '</div>';
13221
13222 $out .= "\n";
13223
13224 $out .= '<ul class="timeline">';
13225
13226 if ($donetodo) {
13227 $tmp = '';
13228 if (get_class($filterobj) == 'Societe') {
13229 $tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&socid='.$filterobj->id.'&status=done">';
13230 }
13231 $tmp .= ($donetodo != 'done' ? $langs->trans("ActionsToDoShort") : '');
13232 $tmp .= ($donetodo != 'done' && $donetodo != 'todo' ? ' / ' : '');
13233 $tmp .= ($donetodo != 'todo' ? $langs->trans("ActionsDoneShort") : '');
13234 //$out.=$langs->trans("ActionsToDoShort").' / '.$langs->trans("ActionsDoneShort");
13235 if (get_class($filterobj) == 'Societe') {
13236 $tmp .= '</a>';
13237 }
13238 $out .= getTitleFieldOfList($tmp);
13239 }
13240
13241 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
13242 $caction = new CActionComm($db);
13243 $arraylist = $caction->liste_array(1, 'code', '', (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : 0), '', 1);
13244
13245 $actualCycleDate = false;
13246
13247 // Loop on each event to show it
13248 foreach ($histo as $key => $value) {
13249 $actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo
13250
13251 $actionstatic->type_picto = $histo[$key]['apicto'];
13252 $actionstatic->type_code = $histo[$key]['acode'];
13253
13254 $labeltype = $actionstatic->type_code;
13255 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') && empty($arraylist[$labeltype])) {
13256 $labeltype = 'AC_OTH';
13257 }
13258 if (!empty($actionstatic->code) && preg_match('/^TICKET_MSG/', $actionstatic->code)) {
13259 $labeltype = $langs->trans("Message");
13260 } else {
13261 if (!empty($arraylist[$labeltype])) {
13262 $labeltype = $arraylist[$labeltype];
13263 }
13264 if ($actionstatic->type_code == 'AC_OTH_AUTO' && ($actionstatic->type_code != $actionstatic->code) && $labeltype && !empty($arraylist[$actionstatic->code])) {
13265 $labeltype .= ' - '.$arraylist[$actionstatic->code]; // Use code in priority on type_code
13266 }
13267 }
13268
13269 $url = DOL_URL_ROOT.'/comm/action/card.php?id='.$histo[$key]['id'];
13270
13271 $tmpa = dol_getdate($histo[$key]['datestart'], false);
13272
13273 if (isset($tmpa['year']) && isset($tmpa['yday']) && $actualCycleDate !== $tmpa['year'].'-'.$tmpa['yday']) {
13274 $actualCycleDate = $tmpa['year'].'-'.$tmpa['yday'];
13275 $out .= '<!-- timeline time label -->';
13276 $out .= '<li class="time-label">';
13277 $out .= '<span class="timeline-badge-date">';
13278 $out .= dol_print_date($histo[$key]['datestart'], 'daytext', 'tzuserrel', $langs);
13279 $out .= '</span>';
13280 $out .= '</li>';
13281 $out .= '<!-- /.timeline-label -->';
13282 }
13283
13284
13285 $out .= '<!-- timeline item -->'."\n";
13286 $out .= '<li class="timeline-code-'.strtolower($actionstatic->code).'">';
13287
13288 //$timelineicon = getTimelineIcon($actionstatic, $histo, $key);
13289 $typeicon = $actionstatic->getTypePicto('pictofixedwidth timeline-icon-not-applicble', $labeltype);
13290 //$out .= $timelineicon;
13291 //var_dump($timelineicon);
13292 $out .= $typeicon;
13293
13294 $out .= '<div class="timeline-item">'."\n";
13295
13296 $out .= '<span class="time timeline-header-action2">';
13297
13298 if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
13299 $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").' ';
13300 $out .= $histo[$key]['id'];
13301 $out .= '</a> ';
13302 } else {
13303 $out .= $actionstatic->getNomUrl(1, -1, 'valignmiddle').' ';
13304 }
13305
13306 if ($user->hasRight('agenda', 'allactions', 'create') ||
13307 (($actionstatic->authorid == $user->id || $actionstatic->userownerid == $user->id) && $user->hasRight('agenda', 'myactions', 'create'))) {
13308 $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).'">';
13309 //$out .= '<i class="fa fa-pencil" title="'.$langs->trans("Modify").'" ></i>';
13310 $out .= img_picto($langs->trans("Modify"), 'edit', 'class="edita"');
13311 $out .= '</a>';
13312 }
13313
13314 $out .= '</span>';
13315
13316 // Date
13317 $out .= '<span class="time"><i class="fa fa-clock-o valignmiddle"></i> <span class="valignmiddle">';
13318 $out .= dol_print_date($histo[$key]['datestart'], 'dayhour', 'tzuserrel');
13319 if ($histo[$key]['dateend'] && $histo[$key]['dateend'] != $histo[$key]['datestart']) {
13320 $tmpa = dol_getdate($histo[$key]['datestart'], true);
13321 $tmpb = dol_getdate($histo[$key]['dateend'], true);
13322 if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
13323 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'hour', 'tzuserrel');
13324 } else {
13325 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'dayhour', 'tzuserrel');
13326 }
13327 }
13328 $late = 0;
13329 if ($histo[$key]['percent'] == 0 && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13330 $late = 1;
13331 }
13332 if ($histo[$key]['percent'] == 0 && !$histo[$key]['datestart'] && $histo[$key]['dateend'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13333 $late = 1;
13334 }
13335 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && $histo[$key]['dateend'] && $histo[$key]['dateend'] < ($now - $delay_warning)) {
13336 $late = 1;
13337 }
13338 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && !$histo[$key]['dateend'] && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
13339 $late = 1;
13340 }
13341 if ($late) {
13342 $out .= img_warning($langs->trans("Late")).' ';
13343 }
13344 $out .= "</span></span>\n";
13345
13346 // Ref
13347 $out .= '<h3 class="timeline-header">';
13348
13349 // Author of event
13350 $out .= '<div class="messaging-author inline-block tdoverflowmax150 valignmiddle marginrightonly">';
13351 if ($histo[$key]['userid'] > 0) {
13352 if (!isset($userGetNomUrlCache[$histo[$key]['userid']])) { // is in cache ?
13353 $userstatic->fetch($histo[$key]['userid']);
13354 $userGetNomUrlCache[$histo[$key]['userid']] = $userstatic->getNomUrl(-1, '', 0, 0, 16, 0, 'firstelselast', '');
13355 }
13356 $out .= $userGetNomUrlCache[$histo[$key]['userid']];
13357 } elseif (!empty($histo[$key]['msg_from']) && $actionstatic->code == 'TICKET_MSG') {
13358 if (!isset($contactGetNomUrlCache[$histo[$key]['msg_from']])) {
13359 if ($contactstatic->fetch(0, null, '', $histo[$key]['msg_from']) > 0) {
13360 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $contactstatic->getNomUrl(-1, '', 16);
13361 } else {
13362 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $histo[$key]['msg_from'];
13363 }
13364 }
13365 $out .= $contactGetNomUrlCache[$histo[$key]['msg_from']];
13366 }
13367 $out .= '</div>';
13368
13369 // Title
13370 $out .= ' <div class="messaging-title inline-block">';
13371 //$out .= $actionstatic->getTypePicto();
13372 if (empty($conf->dol_optimize_smallscreen) && $actionstatic->type_code != 'AC_OTH_AUTO') {
13373 $out .= $labeltype.' - ';
13374 }
13375
13376 $libelle = '';
13377 if (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
13378 $out .= $langs->trans('TicketNewMessage');
13379 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
13380 $out .= $langs->trans('TicketNewMessage').' <em>('.$langs->trans('Private').')</em>';
13381 } elseif (isset($histo[$key]['type'])) {
13382 if ($histo[$key]['type'] == 'action') {
13383 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
13384 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : $histo[$key]['alabel']);
13385 $libelle = $histo[$key]['note'];
13386 $actionstatic->id = $histo[$key]['id'];
13387 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13388 } elseif ($histo[$key]['type'] == 'mailing') {
13389 $out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
13390 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
13391 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : 'Send mass mailing');
13392 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13393 } else {
13394 $libelle .= $histo[$key]['note'];
13395 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
13396 }
13397 }
13398
13399 if (isset($histo[$key]['elementtype']) && !empty($histo[$key]['fk_element'])) {
13400 if (isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']]) && isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']])) {
13401 $link = $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']];
13402 } else {
13403 if (!isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']])) {
13404 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']] = array();
13405 }
13406 $link = dolGetElementUrl($histo[$key]['fk_element'], $histo[$key]['elementtype'], 1);
13407 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']] = $link;
13408 }
13409 if ($link) {
13410 $out .= ' - '.$link;
13411 }
13412 }
13413
13414 $out .= '</div>';
13415
13416 $out .= '</h3>';
13417
13418 // Message
13419 if (!empty($histo[$key]['message'] && $histo[$key]['message'] != $libelle)
13420 && $actionstatic->code != 'AC_TICKET_CREATE'
13421 && $actionstatic->code != 'AC_TICKET_MODIFY'
13422 ) {
13423 $out .= '<div class="timeline-body wordbreak">';
13424 $truncateLines = getDolGlobalInt('MAIN_TRUNCATE_TIMELINE_MESSAGE', 3);
13425 $truncatedText = dolGetFirstLineOfText($histo[$key]['message'], $truncateLines);
13426 if ($truncateLines > 0 && strlen($histo[$key]['message']) > strlen($truncatedText)) {
13427 $out .= '<div class="readmore-block --closed" >';
13428 $out .= ' <div class="readmore-block__excerpt" >';
13429 $out .= $truncatedText ;
13430 $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>';
13431 $out .= ' </div>';
13432 $out .= ' <div class="readmore-block__full-text" >';
13433 $out .= $histo[$key]['message'];
13434 $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>';
13435 $out .= ' </div>';
13436 $out .= '</div>';
13437 } else {
13438 $out .= $histo[$key]['message'];
13439 }
13440
13441 $out .= '</div>';
13442 }
13443
13444 // Timeline footer
13445 $footer = '';
13446
13447 // Contact for this action
13448 if (isset($histo[$key]['socpeopleassigned']) && is_array($histo[$key]['socpeopleassigned']) && count($histo[$key]['socpeopleassigned']) > 0) {
13449 $contactList = '';
13450 foreach ($histo[$key]['socpeopleassigned'] as $cid => $Tab) {
13451 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
13452 $contact = new Contact($db);
13453 $contact->fetch($cid);
13454 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
13455 } else {
13456 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
13457 }
13458
13459 if ($contact) {
13460 $contactList .= !empty($contactList) ? ', ' : '';
13461 $contactList .= $contact->getNomUrl(1);
13462 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
13463 if (!empty($contact->phone_pro)) {
13464 $contactList .= '('.dol_print_phone($contact->phone_pro).')';
13465 }
13466 }
13467 }
13468 }
13469
13470 $footer .= $langs->trans('ActionOnContact').' : '.$contactList;
13471 } elseif (empty($objcon->id) && isset($histo[$key]['contact_id']) && $histo[$key]['contact_id'] > 0) {
13472 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
13473 $contact = new Contact($db);
13474 $result = $contact->fetch($histo[$key]['contact_id']);
13475 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
13476 } else {
13477 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
13478 }
13479
13480 if ($result > 0) {
13481 $footer .= $contact->getNomUrl(1);
13482 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
13483 if (!empty($contact->phone_pro)) {
13484 $footer .= '('.dol_print_phone($contact->phone_pro).')';
13485 }
13486 }
13487 }
13488 }
13489
13490 $documents = getActionCommEcmList($actionstatic);
13491 if (!empty($documents)) {
13492 $footer .= '<div class="timeline-documents-container">';
13493 foreach ($documents as $doc) {
13494 $footer .= '<span id="document_'.$doc->id.'" class="timeline-documents" ';
13495 $footer .= ' data-id="'.$doc->id.'" ';
13496 $footer .= ' data-path="'.$doc->filepath.'"';
13497 $footer .= ' data-filename="'.dol_escape_htmltag($doc->filename).'" ';
13498 $footer .= '>';
13499
13500 $filePath = DOL_DATA_ROOT.'/'.$doc->filepath.'/'.$doc->filename;
13501 $mime = dol_mimetype($filePath);
13502 $file = $actionstatic->id.'/'.$doc->filename;
13503 $thumb = $actionstatic->id.'/thumbs/'.substr($doc->filename, 0, strrpos($doc->filename, '.')).'_mini'.substr($doc->filename, strrpos($doc->filename, '.'));
13504 $doclink = dol_buildpath('document.php', 1).'?modulepart=actions&attachment=0&file='.urlencode($file).'&entity='.$conf->entity;
13505 $viewlink = dol_buildpath('viewimage.php', 1).'?modulepart=actions&file='.urlencode($thumb).'&entity='.$conf->entity;
13506
13507 $mimeAttr = ' mime="'.$mime.'" ';
13508 $class = '';
13509 if (in_array($mime, array('image/png', 'image/jpeg', 'application/pdf'))) {
13510 $class .= ' documentpreview';
13511 }
13512
13513 $footer .= '<a href="'.$doclink.'" class="btn-link '.$class.'" target="_blank" rel="noopener noreferrer" '.$mimeAttr.' >';
13514 $footer .= img_mime($filePath).' '.$doc->filename;
13515 $footer .= '</a>';
13516
13517 $footer .= '</span>';
13518 }
13519 $footer .= '</div>';
13520 }
13521
13522 if (!empty($footer)) {
13523 $out .= '<div class="timeline-footer">'.$footer.'</div>';
13524 }
13525
13526 $out .= '</div>'."\n"; // end timeline-item
13527
13528 $out .= '</li>';
13529 $out .= '<!-- END timeline item -->';
13530
13531 $i++;
13532 }
13533
13534 $out .= "</ul>\n";
13535
13536 $out .= '<script>
13537 jQuery(document).ready(function () {
13538 $(document).on("click", "[data-read-more-action]", function(e){
13539 let readMoreBloc = $(this).closest(".readmore-block");
13540 if(readMoreBloc.length > 0){
13541 e.preventDefault();
13542 if($(this).attr("data-read-more-action") == "close"){
13543 readMoreBloc.addClass("--closed").removeClass("--open");
13544 $("html, body").animate({
13545 scrollTop: readMoreBloc.offset().top - 200
13546 }, 100);
13547 }else{
13548 readMoreBloc.addClass("--open").removeClass("--closed");
13549 }
13550 }
13551 });
13552 });
13553 </script>';
13554
13555
13556 if (empty($histo)) {
13557 $out .= '<span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span>';
13558 }
13559 }
13560
13561 if ($noprint) {
13562 return $out;
13563 } else {
13564 print $out;
13565 }
13566}
13567
13578function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto')
13579{
13580 if ($hourTime === 'getpost') {
13581 $hour = GETPOSTINT($prefix . 'hour');
13582 $minute = GETPOSTINT($prefix . 'minute');
13583 $second = GETPOSTINT($prefix . 'second');
13584 } elseif (preg_match('/^(\d\d):(\d\d):(\d\d)$/', $hourTime, $m)) {
13585 $hour = intval($m[1]);
13586 $minute = intval($m[2]);
13587 $second = intval($m[3]);
13588 } else {
13589 $hour = $minute = $second = 0;
13590 }
13591 // normalize out of range values
13592 $hour = min($hour, 23);
13593 $minute = min($minute, 59);
13594 $second = min($second, 59);
13595 return dol_mktime($hour, $minute, $second, GETPOSTINT($prefix . 'month'), GETPOSTINT($prefix . 'day'), GETPOSTINT($prefix . 'year'), $gm);
13596}
13597
13609function buildParamDate($prefix, $timestamp = null, $hourTime = '', $gm = 'auto')
13610{
13611 if ($timestamp === null) {
13612 $timestamp = GETPOSTDATE($prefix, $hourTime, $gm);
13613 }
13614 $TParam = array(
13615 $prefix . 'day' => intval(dol_print_date($timestamp, '%d')),
13616 $prefix . 'month' => intval(dol_print_date($timestamp, '%m')),
13617 $prefix . 'year' => intval(dol_print_date($timestamp, '%Y')),
13618 );
13619 if ($hourTime === 'getpost' || ($timestamp !== null && dol_print_date($timestamp, '%H:%M:%S') !== '00:00:00')) {
13620 $TParam = array_merge($TParam, array(
13621 $prefix . 'hour' => intval(dol_print_date($timestamp, '%H')),
13622 $prefix . 'minute' => intval(dol_print_date($timestamp, '%M')),
13623 $prefix . 'second' => intval(dol_print_date($timestamp, '%S'))
13624 ));
13625 }
13626
13627 return '&' . http_build_query($TParam);
13628}
if(preg_match('/set_([a-z0-9_\-]+)/i', $action, $reg)) if(preg_match('/del_([a-z0-9_\-]+)/i', $action, $reg)) if($action=='set') elseif( $action=='specimen') elseif($action=='setmodel') elseif( $action=='del') elseif($action=='setdoc') $formactions
View.
ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input=array(), $morecss='', $htmlname='', $forcenojs=0)
On/off button to change a property status of an object This uses the ajax service objectonoff....
Definition ajax.lib.php:717
Class to manage agenda events (actions)
Class to manage different types of events.
Class to manage GeoIP conversion Usage: $geoip=new GeoIP('country',$datfile); $geoip->getCountryCodeF...
Class to manage standard extra fields.
Class to manage invoices.
Class to manage building of HTML components.
Class to manage hooks.
Class to manage predefined suppliers products.
Class to manage products or services.
Class to manage third parties objects (customers, suppliers, prospects...)
isACompany()
Return if third party is a company (Business) or an end user (Consumer)
Class to manage translations.
Class to manage Dolibarr users.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
dol_get_prev_month($month, $year)
Return previous month.
Definition date.lib.php:513
dol_get_next_day($day, $month, $year)
Return next day.
Definition date.lib.php:498
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:86
dol_get_prev_day($day, $month, $year)
Return previous day.
Definition date.lib.php:482
dol_get_next_month($month, $year)
Return next month.
Definition date.lib.php:532
dol_convert_file($fileinput, $ext='png', $fileoutput='', $page='')
Convert an image file or a PDF into another image format.
dragAndDropFileUpload($htmlname)
Function to manage the drag and drop of a file.
dol_is_file($pathoffile)
Return if path is a file.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:62
dol_is_dir($folder)
Test if filename is a directory.
dolGetElementUrl($objectid, $objecttype, $withpicto=0, $option='')
Return link url to an object.
isValidVATID($company)
Check if VAT numero is valid (check done on syntax only, no database or remote access)
dol_html_entity_decode($a, $b, $c='UTF-8', $keepsomeentities=0)
Replace html_entity_decode functions to manage errors.
dol_fiche_end($notab=0)
Show tab footer of a card.
dolCheckFilters($sqlfilters, &$error='')
Return if a $sqlfilters parameter has a valid balance of parenthesis.
dol_print_size($size, $shortvalue=0, $shortunit=0)
Return string with formated size.
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
isOnlyOneLocalTax($local)
Return true if LocalTax (1 or 2) is unique.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod=0)
Function that return localtax of a product line (according to seller, buyer and product vat rate) Si ...
img_weather($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $morecss='')
Show weather picto.
finishSimpleTable($addLineBreak=false)
Add the correct HTML close tags for "startSimpleTable(...)" (use after the last table line)
startSimpleTable($header, $link="", $arguments="", $emptyRows=0, $number=-1)
Start a table with headers and a optinal clickable number (don't forget to use "finishSimpleTable()" ...
getLanguageCodeFromCountryCode($countrycode)
Return default language from country code.
setEntity($currentobject)
Set entity id to use when to create an object.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks=array())
Show social network link.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
dol_ucfirst($string, $encoding="UTF-8")
Convert first character of the first word of a string to upper.
img_right($titlealt='default', $selected=0, $moreatt='')
Show right arrow logo.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
dol_strtolower($string, $encoding="UTF-8")
Convert a string to lower.
showValueWithClipboardCPButton($valuetocopy, $showonlyonhover=1, $texttoshow='')
Create a button to copy $valuetocopy in the clipboard (for copy and paste feature).
dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto='UTF-8')
This function is called to decode a HTML string (it decodes entities and br tags)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_left($titlealt='default', $selected=0, $moreatt='')
Show left arrow logo.
dol_print_ip($ip, $mode=0)
Return an IP formated to be shown on screen.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
GETPOSTINT($paramname, $method=0)
Return value of a param into GET or POST supervariable.
isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
Function to test if an entry is enabled or not.
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
getDolUserInt($key, $default=0, $tmpuser=null)
Return Dolibarr user constant int value.
yn($yesno, $case=1, $color=0)
Return yes or no in current language.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
dolPrintHTML($s, $allowiframe=0)
Return a string ready to be output on HTML page To use text inside an attribute, you can simply use d...
isASecretKey($keyname)
Return if string has a name dedicated to store a secret.
dolPrintHTMLForTextArea($s, $allowiframe=0)
Return a string ready to be output on input textarea To use text inside an attribute,...
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
print_fleche_navigation($page, $file, $options='', $nextpage=0, $betweenarrows='', $afterarrows='', $limit=-1, $totalnboflines=0, $hideselectlimit=0, $beforearrows='', $hidenavigation=0)
Function to show navigation arrows into lists.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
get_date_range($date_start, $date_end, $format='', $outputlangs='', $withparenthesis=1)
Format output for start and end date.
get_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Get formated error messages to output (Used to show messages on html output).
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
roundUpToNextMultiple($n, $x=5)
Round to next multiple.
dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled='', $morecss='classlink button bordertransp', $jsonopen='', $backtopagejsfields='', $accesskey='')
Return HTML code to output a button to open a dialog popup box.
dol_user_country()
Return country code for current user.
dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes=null)
Clean a string from some undesirable HTML tags.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_format_address($object, $withcountry=0, $sep="\n", $outputlangs='', $mode=0, $extralangcode='')
Return a formated address (part address/zip/town/state) according to country rules.
isHTTPS()
Return if we are using a HTTPS connexion Check HTTPS (no way to be modified by user but may be empty ...
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
picto_required()
Return picto saying a field is required.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
img_action($titlealt, $numaction, $picto='', $moreatt='')
Show logo action.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0)
Set event message in dol_events session object.
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
GETPOSTDATE($prefix, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
printCommonFooter($zone='private')
Print common footer : conf->global->MAIN_HTML_FOOTER js for switch of menu hider js for conf->global-...
checkVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
img_down($titlealt='default', $selected=0, $moreclass='')
Show down arrow logo.
getTaxesFromId($vatrate, $buyer=null, $seller=null, $firstparamisid=1)
Get tax (VAT) main information from Id.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
utf8_valid($str)
Check if a string is in UTF8.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
getDolUserString($key, $default='', $tmpuser=null)
Return Dolibarr user constant string value.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
img_allow($allow, $titlealt='default')
Show tick logo if allowed.
isValidMXRecord($domain)
Return if the domain name has a valid MX record.
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
get_htmloutput_mesg($mesgstring='', $mesgarray='', $style='ok', $keepembedded=0)
Get formated messages to output (Used to show messages on html output).
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0)
Format phone numbers according to country.
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
dol_fiche_head($links=array(), $active='0', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tab header of a card.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
get_localtax_by_third($local)
Get values of localtaxes (1 or 2) for company country for the common vat with the highest value.
dol_escape_php($stringtoescape, $stringforquotes=2)
Returns text escaped for inclusion into a php string, build with double quotes " or '.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0)
Clean a string to keep only desirable HTML tags.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
ajax_autoselect($htmlname, $addlink='', $textonlink='Link')
Make content of an input box selected when we click into input field.
img_view($titlealt='default', $float=0, $other='class="valignmiddle"')
Show logo view card.
dolPrintHTMLForAttribute($s)
Return a string ready to be output on an HTML attribute (alt, title, data-html, .....
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_eval($s, $returnvalue=0, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_strftime($fmt, $ts=false, $is_gmt=false)
Format a string.
img_picto_common($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $notitle=0)
Show picto (generic function)
img_search($titlealt='default', $other='')
Show search logo.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
isValidPhone($phone)
Return true if phone number syntax is ok TODO Decide what to do with this.
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
img_previous($titlealt='default', $moreatt='')
Show previous logo.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
fieldLabel($langkey, $fieldkey, $fieldrequired=0)
Show a string with the label tag dedicated to the HTML edit field.
getBrowserInfo($user_agent)
Return information about user browser.
dolGetFirstLetters($s, $nbofchar=1)
Return first letters of a strings.
dol_strtoupper($string, $encoding="UTF-8")
Convert a string to upper.
dol_sanitizeUrl($stringtoclean, $type=1)
Clean a string to use it as an URL (into a href or src attribute)
img_printer($titlealt="default", $other='')
Show printer logo.
dol_htmloutput_events($disabledoutputofmessages=0)
Print formated messages to output (Used to show messages on html output).
getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $disablesortlink=0, $tooltip='', $forcenowrapcolumntitle=0)
Get title line of an array.
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
ascii_check($str)
Check if a string is in ASCII.
getPictoForType($key)
Return the picto for a data type.
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
getArrayOfSocialNetworks()
Get array of social network dictionary.
dolGetButtonTitleSeparator($moreClass="")
Add space between dolGetButtonTitle.
num2Alpha($n)
Return a numeric value into an Excel like column number.
dol_size($size, $type='')
Optimize a size for some browsers (phone, smarphone, ...)
img_split($titlealt='default', $other='class="pictosplit"')
Show split logo.
img_pdf($titlealt='default', $size=3)
Show pdf logo.
dolGetCountryCodeFromIp($ip)
Return a country code from IP.
dol_textishtml($msg, $option=0)
Return if a text is a html content.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dolPrintPassword($s)
Return a string ready to be output on an HTML attribute (alt, title, ...)
colorIsLight($stringcolor)
Return true if the color is light.
dol_escape_all($stringtoescape)
Returns text escaped for all protocols (so only alpha chars and numbers)
readfileLowMemory($fullpath_original_file_osencoded, $method=-1)
Return a file on output using a low memory.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
dol_shutdown()
Function called at end of web php process.
dol_print_address($address, $htmlid, $element, $id, $noprint=0, $charfornl='')
Format address string.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_print_error_email($prefixcode, $errormessage='', $errormessages=array(), $morecss='error', $email='')
Show a public email and error code to contact if technical error.
dol_print_profids($profID, $profIDtype, $countrycode='', $addcpButton=1)
Format professional IDs according to their country.
print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
dol_bc($var, $moreclass='')
Return string to add class property on html element with pair/impair.
print_titre($title)
Show a title.
getElementProperties($element_type)
Get an array with properties of an element.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_string_nounprintableascii($str, $removetabcrlf=1)
Clean a string from all non printable ASCII chars (0x00-0x1F and 0x7F).
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
img_error($titlealt='default')
Show error logo.
getTimelineIcon($actionstatic, &$histo, $key)
Get timeline icon.
dol_htmloutput_mesg($mesgstring='', $mesgarray=array(), $style='ok', $keepembedded=0)
Print formated messages to output (Used to show messages on html output).
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
buildParamDate($prefix, $timestamp=null, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
img_next($titlealt='default', $moreatt='')
Show next logo.
print_date_range($date_start, $date_end, $format='', $outputlangs='')
Format output for start and end date.
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_string_is_good_iso($s, $clean=0)
Check if a string is a correct iso string If not, it will not be considered as HTML encoded even if i...
getNonce()
Return a random string to be used as a nonce value for js.
isStringVarMatching($var, $regextext, $matchrule=1)
Check if a variable with name $var start with $text.
complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode='add', $filterorigmodule='')
Complete or removed entries into a head array (used to build tabs).
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
Return localtax vat rate of a product in a particular country or default country vat if product is un...
getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $object=null, $include=null)
Return array of possible common substitutions.
dol_nboflines($s, $maxchar=0)
Return nb of lines of a clear text.
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js, dangerous content and external link.
jsonOrUnserialize($stringtodecode)
Decode an encode string.
addSummaryTableLine($tableColumnCount, $num, $nbofloop=0, $total=0, $noneWord="None", $extraRightColumn=false)
Add a summary line to the current open table ("None", "XMoreLines" or "Total xxx")
isValidEmail($address, $acceptsupervisorkey=0, $acceptuserkey=0)
Return true if email syntax is ok.
dol_escape_xml($stringtoescape)
Returns text escaped for inclusion into a XML string.
getActionCommEcmList($object)
getActionCommEcmList
dol_ucwords($string, $encoding="UTF-8")
Convert first character of all the words of a string to upper.
img_edit_add($titlealt='default', $other='')
Show logo +.
verifCond($strToEvaluate)
Verify if condition in string is ok or not.
if(!function_exists( 'utf8_encode')) if(!function_exists('utf8_decode')) if(!function_exists( 'str_starts_with')) if(!function_exists('str_ends_with')) if(!function_exists( 'str_contains')) getMultidirOutput($object, $module='')
Return the full path of the directory where a module (or an object of a module) stores its files.
print_fiche_titre($title, $mesg='', $picto='generic', $pictoisfullpath=0, $id='')
Show a title with picto.
get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice=0)
Return vat rate of a product in a particular country, or default country vat if product is unknown.
dolForgeDummyCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
dol_escape_json($stringtoescape)
Returns text escaped for inclusion into javascript code.
dolForgeCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
getUserRemoteIP()
Return the IP of remote user.
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_validElement($element)
Return if var element is ok.
img_credit_card($brand, $morecss=null)
Return image of a credit card according to its brand name.
img_searchclear($titlealt='default', $other='')
Show search logo.
dolPrintLabel($s)
Return a string label (so on 1 line only and that should not contains any HTML) ready to be output on...
fetchObjectByElement($element_id, $element_type, $element_ref='')
Fetch an object from its id and element_type Inclusion of classes is automatic.
utf8_check($str)
Check if a string is in UTF8.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
show_actions_messaging($conf, $langs, $db, $filterobj, $objcon='', $noprint=0, $actioncode='', $donetodo='done', $filters=array(), $sortfield='a.datep, a.id', $sortorder='DESC')
Show html area with actions in messaging format.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
img_up($titlealt='default', $selected=0, $moreclass='')
Show top arrow logo.
dol_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Print formated error messages to output (Used to show messages on html output).
getFieldErrorIcon($fieldValidationErrorMsg)
get field error icon
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
img_edit_remove($titlealt='default', $other='')
Show logo -.
img_info($titlealt='default')
Show info logo.
getDoliDBInstance($type, $host, $user, $pass, $name, $port)
Return a DoliDB instance (database handler).
dol_sanitizeEmail($stringtoclean)
Clean a string to use it as an Email.
dol_nboflines_bis($text, $maxlinesize=0, $charset='UTF-8')
Return nb of lines of a formated text with and (WARNING: string must not have mixed and br sepa...
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
dol_convertToWord($num, $langs, $currency='', $centimes=false)
Function to return a number into a text.
conf($dolibarr_main_document_root)
Load conf file (file must exists)
Definition inc.php:403
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1926
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
if(!empty( $_SERVER[ 'MAIN_SHOW_TUNING_INFO'])) realCharForNumericEntities($matches)
Return the real char for a numeric entities.
Definition main.inc.php:63
dol_setcache($memoryid, $data, $expire=0)
Save data into a memory area shared by all users, all sessions on server.
dol_getcache($memoryid)
Read a memory area shared by all users, all sessions on server.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:121
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:124
dolGetRandomBytes($length)
Return a string of random bytes (hexa string) with length = $length fro cryptographic purposes.
Contact()
Old copy.
Definition index.php:572