dolibarr 20.0.0
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-2024 Frédéric France <frederic.france@free.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 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
25 * Copyright (C) 2024 Lenin Rivas <lenin.rivas777@gmail.com>
26 *
27 * This program is free software; you can redistribute it and/or modify
28 * it under the terms of the GNU General Public License as published by
29 * the Free Software Foundation; either version 3 of the License, or
30 * (at your option) any later version.
31 *
32 * This program is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
36 *
37 * You should have received a copy of the GNU General Public License
38 * along with this program. If not, see <https://www.gnu.org/licenses/>.
39 * or see https://www.gnu.org/
40 */
41
48include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
49
50// Function for better PHP x compatibility
51if (!function_exists('utf8_encode')) {
59 function utf8_encode($elements)
60 {
61 return mb_convert_encoding($elements, 'UTF-8', 'ISO-8859-1');
62 }
63}
64
65if (!function_exists('utf8_decode')) {
73 function utf8_decode($elements)
74 {
75 return mb_convert_encoding($elements, 'ISO-8859-1', 'UTF-8');
76 }
77}
78if (!function_exists('str_starts_with')) {
87 function str_starts_with($haystack, $needle)
88 {
89 return (string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0;
90 }
91}
92if (!function_exists('str_ends_with')) {
101 function str_ends_with($haystack, $needle)
102 {
103 return $needle !== '' && substr($haystack, -strlen($needle)) === (string) $needle;
104 }
105}
106if (!function_exists('str_contains')) {
115 function str_contains($haystack, $needle)
116 {
117 return $needle !== '' && mb_strpos($haystack, $needle) !== false;
118 }
119}
120
121
133function getMultidirOutput($object, $module = '', $forobject = 0, $mode = 'output')
134{
135 global $conf;
136
137 if (!is_object($object) && empty($module)) {
138 return null;
139 }
140 if (empty($module) && !empty($object->element)) {
141 $module = $object->element;
142 }
143
144 // Special case for backward compatibility
145 if ($module == 'fichinter') {
146 $module = 'ficheinter';
147 } elseif ($module == 'invoice_supplier') {
148 $module = 'supplier_invoice';
149 } elseif ($module == 'order_supplier') {
150 $module = 'supplier_order';
151 }
152
153 // Get the relative path of directory
154 if ($mode == 'output' || $mode == 'outputrel' || $mode == 'version') {
155 if (isset($conf->$module) && property_exists($conf->$module, 'multidir_output')) {
156 $s = '';
157 if ($mode != 'outputrel') {
158 $s = $conf->$module->multidir_output[(empty($object->entity) ? $conf->entity : $object->entity)];
159 }
160 if ($forobject && $object->id > 0) {
161 $s .= ($mode != 'outputrel' ? '/' : '').get_exdir(0, 0, 0, 0, $object);
162 }
163 return $s;
164 } else {
165 return 'error-diroutput-not-defined-for-this-object='.$module;
166 }
167 } elseif ($mode == 'temp') {
168 if (isset($conf->$module) && property_exists($conf->$module, 'multidir_temp')) {
169 return $conf->$module->multidir_temp[(empty($object->entity) ? $conf->entity : $object->entity)];
170 } else {
171 return 'error-dirtemp-not-defined-for-this-object='.$module;
172 }
173 } else {
174 return 'error-bad-value-for-mode';
175 }
176}
177
187function getMultidirTemp($object, $module = '', $forobject = 0)
188{
189 return getMultidirOutput($object, $module, $forobject, 'temp');
190}
191
201function getMultidirVersion($object, $module = '', $forobject = 0)
202{
203 return getMultidirOutput($object, $module, $forobject, 'version');
204}
205
206
215function getDolGlobalString($key, $default = '')
216{
217 global $conf;
218 return (string) (isset($conf->global->$key) ? $conf->global->$key : $default);
219}
220
230function getDolGlobalInt($key, $default = 0)
231{
232 global $conf;
233 return (int) (isset($conf->global->$key) ? $conf->global->$key : $default);
234}
235
245function getDolUserString($key, $default = '', $tmpuser = null)
246{
247 if (empty($tmpuser)) {
248 global $user;
249 $tmpuser = $user;
250 }
251
252 return (string) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
253}
254
263function getDolUserInt($key, $default = 0, $tmpuser = null)
264{
265 if (empty($tmpuser)) {
266 global $user;
267 $tmpuser = $user;
268 }
269
270 return (int) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
271}
272
273
283define(
284 'MODULE_MAPPING',
285 array(
286 // Map deprecated names to new names
287 'adherent' => 'member', // Has new directory
288 'member_type' => 'adherent_type', // No directory, but file called adherent_type
289 'banque' => 'bank', // Has new directory
290 'contrat' => 'contract', // Has new directory
291 'entrepot' => 'stock', // Has new directory
292 'projet' => 'project', // Has new directory
293 'categorie' => 'category', // Has old directory
294 'commande' => 'order', // Has old directory
295 'expedition' => 'shipping', // Has old directory
296 'facture' => 'invoice', // Has old directory
297 'fichinter' => 'intervention', // Has old directory
298 'ficheinter' => 'intervention', // Backup for 'fichinter'
299 'propale' => 'propal', // Has old directory
300 'socpeople' => 'contact', // Has old directory
301 'fournisseur' => 'supplier', // Has old directory
302
303 'actioncomm' => 'agenda', // NO module directory (public dir agenda)
304 'product_price' => 'productprice', // NO directory
305 'product_fournisseur_price' => 'productsupplierprice', // NO directory
306 )
307);
308
315function isModEnabled($module)
316{
317 global $conf;
318
319 // Fix old names (map to new names)
320 $arrayconv = MODULE_MAPPING;
321 $arrayconvbis = array_flip(MODULE_MAPPING);
322
323 if (!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD')) {
324 // Special cases: both use the same module.
325 $arrayconv['supplier_order'] = 'fournisseur';
326 $arrayconv['supplier_invoice'] = 'fournisseur';
327 }
328 // Special case.
329 // @TODO Replace isModEnabled('delivery_note') with
330 // isModEnabled('shipping') && getDolGlobalString('MAIN_SUBMODULE_EXPEDITION')
331 if ($module == 'delivery_note') {
332 if (!getDolGlobalString('MAIN_SUBMODULE_EXPEDITION')) {
333 return false;
334 } else {
335 $module = 'shipping';
336 }
337 }
338
339 $module_alt = $module;
340 if (!empty($arrayconv[$module])) {
341 $module_alt = $arrayconv[$module];
342 }
343 $module_bis = $module;
344 if (!empty($arrayconvbis[$module])) {
345 $module_bis = $arrayconvbis[$module];
346 }
347
348 return !empty($conf->modules[$module]) || !empty($conf->modules[$module_alt]) || !empty($conf->modules[$module_bis]);
349 //return !empty($conf->$module->enabled);
350}
351
358function isDolTms($timestamp)
359{
360 if ($timestamp === '') {
361 dol_syslog('Using empty string for a timestamp is deprecated, prefer use of null when calling page '.$_SERVER["PHP_SELF"], LOG_NOTICE);
362 return false;
363 }
364 if (is_null($timestamp) || !is_numeric($timestamp)) {
365 return false;
366 }
367
368 return true;
369}
370
382function getDoliDBInstance($type, $host, $user, $pass, $name, $port)
383{
384 require_once DOL_DOCUMENT_ROOT."/core/db/".$type.'.class.php';
385
386 $class = 'DoliDB'.ucfirst($type);
387 $db = new $class($type, $host, $user, $pass, $name, $port);
388 return $db;
389}
390
408function getEntity($element, $shared = 1, $currentobject = null)
409{
410 global $conf, $mc, $hookmanager, $object, $action, $db;
411
412 if (!is_object($hookmanager)) {
413 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
414 $hookmanager = new HookManager($db);
415 }
416
417 // fix different element names (France to English)
418 switch ($element) {
419 case 'projet':
420 $element = 'project';
421 break;
422 case 'contrat':
423 $element = 'contract';
424 break; // "/contrat/class/contrat.class.php"
425 case 'order_supplier':
426 $element = 'supplier_order';
427 break; // "/fourn/class/fournisseur.commande.class.php"
428 case 'invoice_supplier':
429 $element = 'supplier_invoice';
430 break; // "/fourn/class/fournisseur.facture.class.php"
431 }
432
433 if (is_object($mc)) {
434 $out = $mc->getEntity($element, $shared, $currentobject);
435 } else {
436 $out = '';
437 $addzero = array('user', 'usergroup', 'cronjob', 'c_email_templates', 'email_template', 'default_values', 'overwrite_trans');
438 if (in_array($element, $addzero)) {
439 $out .= '0,';
440 }
441 $out .= ((int) $conf->entity);
442 }
443
444 // Manipulate entities to query on the fly
445 $parameters = array(
446 'element' => $element,
447 'shared' => $shared,
448 'object' => $object,
449 'currentobject' => $currentobject,
450 'out' => $out
451 );
452 $reshook = $hookmanager->executeHooks('hookGetEntity', $parameters, $currentobject, $action); // Note that $action and $object may have been modified by some hooks
453
454 if (is_numeric($reshook)) {
455 if ($reshook == 0 && !empty($hookmanager->resPrint)) {
456 $out .= ','.$hookmanager->resPrint; // add
457 } elseif ($reshook == 1) {
458 $out = $hookmanager->resPrint; // replace
459 }
460 }
461
462 return $out;
463}
464
471function setEntity($currentobject)
472{
473 global $conf, $mc;
474
475 if (is_object($mc) && method_exists($mc, 'setEntity')) {
476 return $mc->setEntity($currentobject);
477 } else {
478 return ((is_object($currentobject) && $currentobject->id > 0 && $currentobject->entity > 0) ? $currentobject->entity : $conf->entity);
479 }
480}
481
488function isASecretKey($keyname)
489{
490 return preg_match('/(_pass|password|_pw|_key|securekey|serverkey|secret\d?|p12key|exportkey|_PW_[a-z]+|token)$/i', $keyname);
491}
492
493
500function num2Alpha($n)
501{
502 for ($r = ""; $n >= 0; $n = intval($n / 26) - 1) {
503 $r = chr($n % 26 + 0x41) . $r;
504 }
505 return $r;
506}
507
508
525function getBrowserInfo($user_agent)
526{
527 include_once DOL_DOCUMENT_ROOT.'/includes/mobiledetect/mobiledetectlib/Mobile_Detect.php';
528
529 $name = 'unknown';
530 $version = '';
531 $os = 'unknown';
532 $phone = '';
533
534 $user_agent = substr($user_agent, 0, 512); // Avoid to process too large user agent
535
536 $detectmobile = new Mobile_Detect(null, $user_agent);
537 $tablet = $detectmobile->isTablet();
538
539 if ($detectmobile->isMobile()) {
540 $phone = 'unknown';
541
542 // If phone/smartphone, we set phone os name.
543 if ($detectmobile->is('AndroidOS')) {
544 $os = $phone = 'android';
545 } elseif ($detectmobile->is('BlackBerryOS')) {
546 $os = $phone = 'blackberry';
547 } elseif ($detectmobile->is('iOS')) {
548 $os = 'ios';
549 $phone = 'iphone';
550 } elseif ($detectmobile->is('PalmOS')) {
551 $os = $phone = 'palm';
552 } elseif ($detectmobile->is('SymbianOS')) {
553 $os = 'symbian';
554 } elseif ($detectmobile->is('webOS')) {
555 $os = 'webos';
556 } elseif ($detectmobile->is('MaemoOS')) {
557 $os = 'maemo';
558 } elseif ($detectmobile->is('WindowsMobileOS') || $detectmobile->is('WindowsPhoneOS')) {
559 $os = 'windows';
560 }
561 }
562
563 // OS
564 if (preg_match('/linux/i', $user_agent)) {
565 $os = 'linux';
566 } elseif (preg_match('/macintosh/i', $user_agent)) {
567 $os = 'macintosh';
568 } elseif (preg_match('/windows/i', $user_agent)) {
569 $os = 'windows';
570 }
571
572 // Name
573 $reg = array();
574 if (preg_match('/firefox(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
575 $name = 'firefox';
576 $version = empty($reg[2]) ? '' : $reg[2];
577 } elseif (preg_match('/edge(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
578 $name = 'edge';
579 $version = empty($reg[2]) ? '' : $reg[2];
580 } elseif (preg_match('/chrome(\/|\s)([\d\.]+)/i', $user_agent, $reg)) {
581 $name = 'chrome';
582 $version = empty($reg[2]) ? '' : $reg[2];
583 } elseif (preg_match('/chrome/i', $user_agent, $reg)) {
584 // we can have 'chrome (Mozilla...) chrome x.y' in one string
585 $name = 'chrome';
586 } elseif (preg_match('/iceweasel/i', $user_agent)) {
587 $name = 'iceweasel';
588 } elseif (preg_match('/epiphany/i', $user_agent)) {
589 $name = 'epiphany';
590 } elseif (preg_match('/safari(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
591 $name = 'safari';
592 $version = empty($reg[2]) ? '' : $reg[2];
593 } elseif (preg_match('/opera(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
594 // Safari is often present in string for mobile but its not.
595 $name = 'opera';
596 $version = empty($reg[2]) ? '' : $reg[2];
597 } elseif (preg_match('/(MSIE\s([0-9]+\.[0-9]))|.*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
598 $name = 'ie';
599 $version = end($reg);
600 } elseif (preg_match('/(Windows NT\s([0-9]+\.[0-9])).*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
601 // MS products at end
602 $name = 'ie';
603 $version = end($reg);
604 } elseif (preg_match('/l[iy]n(x|ks)(\‍(|\/|\s)*([\d\.]+)/i', $user_agent, $reg)) {
605 // MS products at end
606 $name = 'lynxlinks';
607 $version = empty($reg[3]) ? '' : $reg[3];
608 }
609
610 if ($tablet) {
611 $layout = 'tablet';
612 } elseif ($phone) {
613 $layout = 'phone';
614 } else {
615 $layout = 'classic';
616 }
617
618 return array(
619 'browsername' => $name,
620 'browserversion' => $version,
621 'browseros' => $os,
622 'browserua' => $user_agent,
623 'layout' => $layout, // tablet, phone, classic
624 'phone' => $phone, // deprecated
625 'tablet' => $tablet // deprecated
626 );
627}
628
634function dol_shutdown()
635{
636 global $db;
637 $disconnectdone = false;
638 $depth = 0;
639 if (is_object($db) && !empty($db->connected)) {
640 $depth = $db->transaction_opened;
641 $disconnectdone = $db->close();
642 }
643 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));
644}
645
655function GETPOSTISSET($paramname)
656{
657 $isset = false;
658
659 $relativepathstring = $_SERVER["PHP_SELF"];
660 // Clean $relativepathstring
661 if (constant('DOL_URL_ROOT')) {
662 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
663 }
664 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
665 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
666 //var_dump($relativepathstring);
667 //var_dump($user->default_values);
668
669 // Code for search criteria persistence.
670 // Retrieve values if restore_lastsearch_values
671 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
672 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
673 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
674 if (is_array($tmp)) {
675 foreach ($tmp as $key => $val) {
676 if ($key == $paramname) { // We are on the requested parameter
677 $isset = true;
678 break;
679 }
680 }
681 }
682 }
683 // If there is saved contextpage, limit, page or mode
684 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
685 $isset = true;
686 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
687 $isset = true;
688 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
689 $isset = true;
690 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
691 $isset = true;
692 }
693 } else {
694 $isset = (isset($_POST[$paramname]) || isset($_GET[$paramname])); // We must keep $_POST and $_GET here
695 }
696
697 return $isset;
698}
699
708function GETPOSTISARRAY($paramname, $method = 0)
709{
710 // for $method test need return the same $val as GETPOST
711 if (empty($method)) {
712 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
713 } elseif ($method == 1) {
714 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
715 } elseif ($method == 2) {
716 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
717 } elseif ($method == 3) {
718 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
719 } else {
720 $val = 'BadFirstParameterForGETPOST';
721 }
722
723 return is_array($val);
724}
725
755function GETPOST($paramname, $check = 'alphanohtml', $method = 0, $filter = null, $options = null, $noreplace = 0)
756{
757 global $mysoc, $user, $conf;
758
759 if (empty($paramname)) { // Explicit test for null for phan.
760 return 'BadFirstParameterForGETPOST';
761 }
762 if (empty($check)) {
763 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);
764 // Enable this line to know who call the GETPOST with '' $check parameter.
765 //var_dump(debug_backtrace()[0]);
766 }
767
768 if (empty($method)) {
769 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
770 } elseif ($method == 1) {
771 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
772 } elseif ($method == 2) {
773 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
774 } elseif ($method == 3) {
775 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
776 } else {
777 return 'BadThirdParameterForGETPOST';
778 }
779
780 $relativepathstring = ''; // For static analysis - looks possibly undefined if not set.
781
782 if (empty($method) || $method == 3 || $method == 4) {
783 $relativepathstring = (empty($_SERVER["PHP_SELF"]) ? '' : $_SERVER["PHP_SELF"]);
784 // Clean $relativepathstring
785 if (constant('DOL_URL_ROOT')) {
786 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
787 }
788 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
789 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
790 //var_dump($relativepathstring);
791 //var_dump($user->default_values);
792
793 // Code for search criteria persistence.
794 // Retrieve saved values if restore_lastsearch_values is set
795 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
796 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
797 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
798 if (is_array($tmp)) {
799 foreach ($tmp as $key => $val) {
800 if ($key == $paramname) { // We are on the requested parameter
801 $out = $val;
802 break;
803 }
804 }
805 }
806 }
807 // If there is saved contextpage, page or limit
808 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
809 $out = $_SESSION['lastsearch_contextpage_'.$relativepathstring];
810 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
811 $out = $_SESSION['lastsearch_limit_'.$relativepathstring];
812 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
813 $out = $_SESSION['lastsearch_page_'.$relativepathstring];
814 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
815 $out = $_SESSION['lastsearch_mode_'.$relativepathstring];
816 }
817 } elseif (!isset($_GET['sortfield'])) {
818 // Else, retrieve default values if we are not doing a sort
819 // 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
820 if (!empty($_GET['action']) && $_GET['action'] == 'create' && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
821 // Search default value from $object->field
822 global $object;
823 '@phan-var-force CommonObject $object'; // Suppose it's a CommonObject for analysis, but other objects have the $fields field as well
824 if (is_object($object) && isset($object->fields[$paramname]['default'])) {
825 // @phan-suppress-next-line PhanTypePossiblyInvalidDimOffset
826 $out = $object->fields[$paramname]['default'];
827 }
828 }
829 if (getDolGlobalString('MAIN_ENABLE_DEFAULT_VALUES')) {
830 if (!empty($_GET['action']) && (preg_match('/^create/', $_GET['action']) || preg_match('/^presend/', $_GET['action'])) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
831 // Now search in setup to overwrite default values
832 if (!empty($user->default_values)) { // $user->default_values defined from menu 'Setup - Default values'
833 if (isset($user->default_values[$relativepathstring]['createform'])) {
834 foreach ($user->default_values[$relativepathstring]['createform'] as $defkey => $defval) {
835 $qualified = 0;
836 if ($defkey != '_noquery_') {
837 $tmpqueryarraytohave = explode('&', $defkey);
838 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
839 $foundintru = 0;
840 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
841 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
842 $foundintru = 1;
843 }
844 }
845 if (!$foundintru) {
846 $qualified = 1;
847 }
848 //var_dump($defkey.'-'.$qualified);
849 } else {
850 $qualified = 1;
851 }
852
853 if ($qualified) {
854 if (isset($user->default_values[$relativepathstring]['createform'][$defkey][$paramname])) {
855 $out = $user->default_values[$relativepathstring]['createform'][$defkey][$paramname];
856 break;
857 }
858 }
859 }
860 }
861 }
862 } elseif (!empty($paramname) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
863 // Management of default search_filters and sort order
864 if (!empty($user->default_values)) {
865 // $user->default_values defined from menu 'Setup - Default values'
866 //var_dump($user->default_values[$relativepathstring]);
867 if ($paramname == 'sortfield' || $paramname == 'sortorder') {
868 // Sorted on which fields ? ASC or DESC ?
869 if (isset($user->default_values[$relativepathstring]['sortorder'])) {
870 // Even if paramname is sortfield, data are stored into ['sortorder...']
871 foreach ($user->default_values[$relativepathstring]['sortorder'] as $defkey => $defval) {
872 $qualified = 0;
873 if ($defkey != '_noquery_') {
874 $tmpqueryarraytohave = explode('&', $defkey);
875 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
876 $foundintru = 0;
877 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
878 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
879 $foundintru = 1;
880 }
881 }
882 if (!$foundintru) {
883 $qualified = 1;
884 }
885 //var_dump($defkey.'-'.$qualified);
886 } else {
887 $qualified = 1;
888 }
889
890 if ($qualified) {
891 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
892 foreach ($user->default_values[$relativepathstring]['sortorder'][$defkey] as $key => $val) {
893 if ($out) {
894 $out .= ', ';
895 }
896 if ($paramname == 'sortfield') {
897 $out .= dol_string_nospecial($key, '', $forbidden_chars_to_replace);
898 }
899 if ($paramname == 'sortorder') {
900 $out .= dol_string_nospecial($val, '', $forbidden_chars_to_replace);
901 }
902 }
903 //break; // No break for sortfield and sortorder so we can cumulate fields (is it really useful ?)
904 }
905 }
906 }
907 } elseif (isset($user->default_values[$relativepathstring]['filters'])) {
908 foreach ($user->default_values[$relativepathstring]['filters'] as $defkey => $defval) { // $defkey is a querystring like 'a=b&c=d', $defval is key of user
909 if (!empty($_GET['disabledefaultvalues'])) { // If set of default values has been disabled by a request parameter
910 continue;
911 }
912 $qualified = 0;
913 if ($defkey != '_noquery_') {
914 $tmpqueryarraytohave = explode('&', $defkey);
915 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
916 $foundintru = 0;
917 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
918 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
919 $foundintru = 1;
920 }
921 }
922 if (!$foundintru) {
923 $qualified = 1;
924 }
925 //var_dump($defkey.'-'.$qualified);
926 } else {
927 $qualified = 1;
928 }
929
930 if ($qualified && isset($user->default_values[$relativepathstring]['filters'][$defkey][$paramname])) {
931 // We must keep $_POST and $_GET here
932 if (isset($_POST['sall']) || isset($_POST['search_all']) || isset($_GET['sall']) || isset($_GET['search_all'])) {
933 // We made a search from quick search menu, do we still use default filter ?
934 if (!getDolGlobalString('MAIN_DISABLE_DEFAULT_FILTER_FOR_QUICK_SEARCH')) {
935 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
936 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
937 }
938 } else {
939 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
940 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
941 }
942 break;
943 }
944 }
945 }
946 }
947 }
948 }
949 }
950 }
951
952 // 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)
953 // Example of variables: __DAY__, __MONTH__, __YEAR__, __MYCOMPANY_COUNTRY_ID__, __USER_ID__, ...
954 // 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.
955 '@phan-var-force string $paramname';
956 if (!is_array($out) && empty($_POST[$paramname]) && empty($noreplace)) {
957 $reg = array();
958 $maxloop = 20;
959 $loopnb = 0; // Protection against infinite loop
960 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.
961 $loopnb++;
962 $newout = '';
963
964 if ($reg[1] == 'DAY') {
965 $tmp = dol_getdate(dol_now(), true);
966 $newout = $tmp['mday'];
967 } elseif ($reg[1] == 'MONTH') {
968 $tmp = dol_getdate(dol_now(), true);
969 $newout = $tmp['mon'];
970 } elseif ($reg[1] == 'YEAR') {
971 $tmp = dol_getdate(dol_now(), true);
972 $newout = $tmp['year'];
973 } elseif ($reg[1] == 'PREVIOUS_DAY') {
974 $tmp = dol_getdate(dol_now(), true);
975 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
976 $newout = $tmp2['day'];
977 } elseif ($reg[1] == 'PREVIOUS_MONTH') {
978 $tmp = dol_getdate(dol_now(), true);
979 $tmp2 = dol_get_prev_month($tmp['mon'], $tmp['year']);
980 $newout = $tmp2['month'];
981 } elseif ($reg[1] == 'PREVIOUS_YEAR') {
982 $tmp = dol_getdate(dol_now(), true);
983 $newout = ($tmp['year'] - 1);
984 } elseif ($reg[1] == 'NEXT_DAY') {
985 $tmp = dol_getdate(dol_now(), true);
986 $tmp2 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
987 $newout = $tmp2['day'];
988 } elseif ($reg[1] == 'NEXT_MONTH') {
989 $tmp = dol_getdate(dol_now(), true);
990 $tmp2 = dol_get_next_month($tmp['mon'], $tmp['year']);
991 $newout = $tmp2['month'];
992 } elseif ($reg[1] == 'NEXT_YEAR') {
993 $tmp = dol_getdate(dol_now(), true);
994 $newout = ($tmp['year'] + 1);
995 } elseif ($reg[1] == 'MYCOMPANY_COUNTRY_ID' || $reg[1] == 'MYCOUNTRY_ID' || $reg[1] == 'MYCOUNTRYID') {
996 $newout = $mysoc->country_id;
997 } elseif ($reg[1] == 'USER_ID' || $reg[1] == 'USERID') {
998 $newout = $user->id;
999 } elseif ($reg[1] == 'USER_SUPERVISOR_ID' || $reg[1] == 'SUPERVISOR_ID' || $reg[1] == 'SUPERVISORID') {
1000 $newout = $user->fk_user;
1001 } elseif ($reg[1] == 'ENTITY_ID' || $reg[1] == 'ENTITYID') {
1002 $newout = $conf->entity;
1003 } elseif ($reg[1] == 'ID') {
1004 $newout = '__ID__'; // We keep __ID__ we find into backtopage url
1005 } else {
1006 $newout = ''; // Key not found, we replace with empty string
1007 }
1008 //var_dump('__'.$reg[1].'__ -> '.$newout);
1009 $out = preg_replace('/__'.preg_quote($reg[1], '/').'__/', $newout, $out);
1010 }
1011 }
1012
1013 // Check type of variable and make sanitization according to this
1014 if (preg_match('/^array/', $check)) { // If 'array' or 'array:restricthtml' or 'array:aZ09' or 'array:intcomma'
1015 if (!is_array($out) || empty($out)) {
1016 $out = array();
1017 } else {
1018 $tmparray = explode(':', $check);
1019 if (!empty($tmparray[1])) {
1020 $tmpcheck = $tmparray[1];
1021 } else {
1022 $tmpcheck = 'alphanohtml';
1023 }
1024 foreach ($out as $outkey => $outval) {
1025 $out[$outkey] = sanitizeVal($outval, $tmpcheck, $filter, $options);
1026 }
1027 }
1028 } else {
1029 // If field name is 'search_xxx' then we force the add of space after each < and > (when following char is numeric) because it means
1030 // 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
1031 if (strpos($paramname, 'search_') === 0) {
1032 $out = preg_replace('/([<>])([-+]?\d)/', '\1 \2', $out);
1033 }
1034
1035 // @phan-suppress-next-line UnknownSanitizeType
1036 $out = sanitizeVal($out, $check, $filter, $options);
1037 }
1038
1039 // Sanitizing for special parameters.
1040 // Note: There is no reason to allow the backtopage, backtolist or backtourl parameter to contains an external URL. Only relative URLs are allowed.
1041 if ($paramname == 'backtopage' || $paramname == 'backtolist' || $paramname == 'backtourl') {
1042 $out = str_replace('\\', '/', $out); // Can be before the loop because only 1 char is replaced. No risk to get it after other replacements.
1043 $out = str_replace(array(':', ';', '@', "\t", ' '), '', $out); // Can be before the loop because only 1 char is replaced. No risk to retrieve it after other replacements.
1044 do {
1045 $oldstringtoclean = $out;
1046 $out = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $out);
1047 $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'
1048 $out = preg_replace(array('/^[a-z]*\/\s*\/+/i'), '', $out); // We remove schema*// to remove external URL
1049 } while ($oldstringtoclean != $out);
1050 }
1051
1052 // Code for search criteria persistence.
1053 // Save data into session if key start with 'search_'
1054 if (empty($method) || $method == 3 || $method == 4) {
1055 if (preg_match('/^search_/', $paramname) || in_array($paramname, array('sortorder', 'sortfield'))) {
1056 //var_dump($paramname.' - '.$out.' '.$user->default_values[$relativepathstring]['filters'][$paramname]);
1057
1058 // We save search key only if $out not empty that means:
1059 // - posted value not empty, or
1060 // - 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).
1061
1062 if ($out != '' && isset($user)) {// $out = '0' or 'abc', it is a search criteria to keep
1063 $user->lastsearch_values_tmp[$relativepathstring][$paramname] = $out;
1064 }
1065 }
1066 }
1067
1068 return $out;
1069}
1070
1080function GETPOSTINT($paramname, $method = 0)
1081{
1082 return (int) GETPOST($paramname, 'int', $method, null, null, 0);
1083}
1084
1085
1094function GETPOSTFLOAT($paramname, $rounding = '')
1095{
1096 // price2num() is used to sanitize any valid user input (such as "1 234.5", "1 234,5", "1'234,5", "1·234,5", "1,234.5", etc.)
1097 return (float) price2num(GETPOST($paramname), $rounding, 2);
1098}
1099
1100
1111function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
1112{
1113 return sanitizeVal($out, $check, $filter, $options);
1114}
1115
1125function sanitizeVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
1126{
1127 // TODO : use class "Validate" to perform tests (and add missing tests) if needed for factorize
1128 // Check is done after replacement
1129 switch ($check) {
1130 case 'none':
1131 break;
1132 case 'int': // Check param is a numeric value (integer but also float or hexadecimal)
1133 if (!is_numeric($out)) {
1134 $out = '';
1135 }
1136 break;
1137 case 'intcomma':
1138 if (is_array($out)) {
1139 $out = implode(',', $out);
1140 }
1141 if (preg_match('/[^0-9,-]+/i', $out)) {
1142 $out = '';
1143 }
1144 break;
1145 case 'san_alpha':
1146 $out = filter_var($out, FILTER_SANITIZE_STRING);
1147 break;
1148 case 'email':
1149 $out = filter_var($out, FILTER_SANITIZE_EMAIL);
1150 break;
1151 case 'aZ':
1152 if (!is_array($out)) {
1153 $out = trim($out);
1154 if (preg_match('/[^a-z]+/i', $out)) {
1155 $out = '';
1156 }
1157 }
1158 break;
1159 case 'aZ09':
1160 if (!is_array($out)) {
1161 $out = trim($out);
1162 if (preg_match('/[^a-z0-9_\-\.]+/i', $out)) {
1163 $out = '';
1164 }
1165 }
1166 break;
1167 case 'aZ09arobase': // great to sanitize $objecttype parameter
1168 if (!is_array($out)) {
1169 $out = trim($out);
1170 if (preg_match('/[^a-z0-9_\-\.@]+/i', $out)) {
1171 $out = '';
1172 }
1173 }
1174 break;
1175 case 'aZ09comma': // great to sanitize $sortfield or $sortorder params that can be 't.abc,t.def_gh'
1176 if (!is_array($out)) {
1177 $out = trim($out);
1178 if (preg_match('/[^a-z0-9_\-\.,]+/i', $out)) {
1179 $out = '';
1180 }
1181 }
1182 break;
1183 case 'alpha': // No html and no ../ and "
1184 case 'alphanohtml': // Recommended for most scalar parameters and search parameters
1185 if (!is_array($out)) {
1186 $out = trim($out);
1187 do {
1188 $oldstringtoclean = $out;
1189 // Remove html tags
1190 $out = dol_string_nohtmltag($out, 0);
1191 // Refuse octal syntax \999, hexa syntax \x999 and unicode syntax \u{999} by replacing the \ into / (so if it is a \ for a windows path, it is still ok).
1192 $out = preg_replace('/\\\‍([0-9xu])/', '/\1', $out);
1193 // Remove also other dangerous string sequences
1194 // '../' or '..\' is dangerous because it allows dir transversals
1195 // '&#38', '&#0000038', '&#x26'... is a the char '&' alone but there is no reason to accept such way to encode input char
1196 // '"' = '&#34' = '&#0000034' = '&#x22' is dangerous because param in url can close the href= or src= and add javascript functions.
1197 // '&#47', '&#0000047', '&#x2F' is the char '/' but there is no reason to accept such way to encode this input char
1198 // '&#92' = '&#0000092' = '&#x5C' is the char '\' but there is no reason to accept such way to encode this input char
1199 $out = str_ireplace(array('../', '..\\', '&#38', '&#0000038', '&#x26', '&quot', '"', '&#34', '&#0000034', '&#x22', '&#47', '&#0000047', '&#x2F', '&#92', '&#0000092', '&#x5C'), '', $out);
1200 } while ($oldstringtoclean != $out);
1201 // keep lines feed
1202 }
1203 break;
1204 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'
1205 if (!is_array($out)) {
1206 $out = trim($out);
1207 do {
1208 $oldstringtoclean = $out;
1209 // Decode html entities
1210 $out = dol_html_entity_decode($out, ENT_COMPAT | ENT_HTML5, 'UTF-8');
1211 // Refuse octal syntax \999, hexa syntax \x999 and unicode syntax \u{999} by replacing the \ into / (so if it is a \ for a windows path, it is still ok).
1212 $out = preg_replace('/\\\‍([0-9xu])/', '/\1', $out);
1213 // Remove also other dangerous string sequences
1214 // '../' or '..\' is dangerous because it allows dir transversals
1215 // '&#38', '&#0000038', '&#x26'... is a the char '&' alone but there is no reason to accept such way to encode input char
1216 // '"' = '&#34' = '&#0000034' = '&#x22' is dangerous because param in url can close the href= or src= and add javascript functions.
1217 // '&#47', '&#0000047', '&#x2F' is the char '/' but there is no reason to accept such way to encode this input char
1218 // '&#92' = '&#0000092' = '&#x5C' is the char '\' but there is no reason to accept such way to encode this input char
1219 $out = str_ireplace(array('../', '..\\', '&#38', '&#0000038', '&#x26', '&quot', '"', '&#34', '&#0000034', '&#x22', '&#47', '&#0000047', '&#x2F', '&#92', '&#0000092', '&#x5C'), '', $out);
1220 } while ($oldstringtoclean != $out);
1221 }
1222 break;
1223 case 'nohtml': // No html
1224 $out = dol_string_nohtmltag($out, 0);
1225 break;
1226 case 'restricthtmlnolink':
1227 case 'restricthtml': // Recommended for most html textarea
1228 case 'restricthtmlallowclass':
1229 case 'restricthtmlallowunvalid':
1230 $out = dol_htmlwithnojs($out, 1, $check);
1231 break;
1232 case 'custom':
1233 if (!empty($out)) {
1234 if (empty($filter)) {
1235 return 'BadParameterForGETPOST - Param 3 of sanitizeVal()';
1236 }
1237 if (is_null($options)) {
1238 $options = 0;
1239 }
1240 $out = filter_var($out, $filter, $options);
1241 }
1242 break;
1243 default:
1244 dol_syslog("Error, you call sanitizeVal() with a bad value for the check type. Data will be sanitized with alphanohtml.", LOG_ERR);
1245 $out = GETPOST($out, 'alphanohtml');
1246 break;
1247 }
1248
1249 return $out;
1250}
1251
1252
1253if (!function_exists('dol_getprefix')) {
1264 function dol_getprefix($mode = '')
1265 {
1266 // If prefix is for email (we need to have $conf already loaded for this case)
1267 if ($mode == 'email') {
1268 global $conf;
1269
1270 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID')) { // If MAIL_PREFIX_FOR_EMAIL_ID is set
1271 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID') != 'SERVER_NAME') {
1272 return $conf->global->MAIL_PREFIX_FOR_EMAIL_ID;
1273 } elseif (isset($_SERVER["SERVER_NAME"])) { // If MAIL_PREFIX_FOR_EMAIL_ID is set to 'SERVER_NAME'
1274 return $_SERVER["SERVER_NAME"];
1275 }
1276 }
1277
1278 // The recommended value if MAIL_PREFIX_FOR_EMAIL_ID is not defined (may be not defined for old versions)
1279 if (!empty($conf->file->instance_unique_id)) {
1280 return sha1('dolibarr'.$conf->file->instance_unique_id);
1281 }
1282
1283 // For backward compatibility when instance_unique_id is not set
1284 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1285 }
1286
1287 // If prefix is for session (no need to have $conf loaded)
1288 global $dolibarr_main_instance_unique_id, $dolibarr_main_cookie_cryptkey; // This is loaded by filefunc.inc.php
1289 $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
1290
1291 // The recommended value (may be not defined for old versions)
1292 if (!empty($tmp_instance_unique_id)) {
1293 return sha1('dolibarr'.$tmp_instance_unique_id);
1294 }
1295
1296 // For backward compatibility when instance_unique_id is not set
1297 if (isset($_SERVER["SERVER_NAME"]) && isset($_SERVER["DOCUMENT_ROOT"])) {
1298 return sha1($_SERVER["SERVER_NAME"].$_SERVER["DOCUMENT_ROOT"].DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1299 } else {
1300 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1301 }
1302 }
1303}
1304
1315function dol_include_once($relpath, $classname = '')
1316{
1317 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']
1318
1319 $fullpath = dol_buildpath($relpath);
1320
1321 if (!file_exists($fullpath)) {
1322 dol_syslog('functions::dol_include_once Tried to load unexisting file: '.$relpath, LOG_WARNING);
1323 return false;
1324 }
1325
1326 if (!empty($classname) && !class_exists($classname)) {
1327 return include $fullpath;
1328 } else {
1329 return include_once $fullpath;
1330 }
1331}
1332
1333
1344function dol_buildpath($path, $type = 0, $returnemptyifnotfound = 0)
1345{
1346 global $conf;
1347
1348 $path = preg_replace('/^\//', '', $path);
1349
1350 if (empty($type)) { // For a filesystem path
1351 $res = DOL_DOCUMENT_ROOT.'/'.$path; // Standard default path
1352 if (is_array($conf->file->dol_document_root)) {
1353 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array("main"=>"/home/main/htdocs", "alt0"=>"/home/dirmod/htdocs", ...)
1354 if ($key == 'main') {
1355 continue;
1356 }
1357 // if (@file_exists($dirroot.'/'.$path)) {
1358 if (@file_exists($dirroot.'/'.$path)) { // avoid [php:warn]
1359 $res = $dirroot.'/'.$path;
1360 return $res;
1361 }
1362 }
1363 }
1364 if ($returnemptyifnotfound) {
1365 // Not found into alternate dir
1366 if ($returnemptyifnotfound == 1 || !file_exists($res)) {
1367 return '';
1368 }
1369 }
1370 } else {
1371 // For an url path
1372 // We try to get local path of file on filesystem from url
1373 // Note that trying to know if a file on disk exist by forging path on disk from url
1374 // works only for some web server and some setup. This is bugged when
1375 // using proxy, rewriting, virtual path, etc...
1376 $res = '';
1377 if ($type == 1) {
1378 $res = DOL_URL_ROOT.'/'.$path; // Standard value
1379 }
1380 if ($type == 2) {
1381 $res = DOL_MAIN_URL_ROOT.'/'.$path; // Standard value
1382 }
1383 if ($type == 3) {
1384 $res = DOL_URL_ROOT.'/'.$path;
1385 }
1386
1387 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array(["main"]=>"/home/main/htdocs", ["alt0"]=>"/home/dirmod/htdocs", ...)
1388 if ($key == 'main') {
1389 if ($type == 3) {
1390 /*global $dolibarr_main_url_root;*/
1391
1392 // Define $urlwithroot
1393 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1394 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1395 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1396
1397 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).'/'.$path; // Test on start with http is for old conf syntax
1398 }
1399 continue;
1400 }
1401 $regs = array();
1402 preg_match('/^([^\?]+(\.css\.php|\.css|\.js\.php|\.js|\.png|\.jpg|\.php)?)/i', $path, $regs); // Take part before '?'
1403 if (!empty($regs[1])) {
1404 //print $key.'-'.$dirroot.'/'.$path.'-'.$conf->file->dol_url_root[$type].'<br>'."\n";
1405 //if (file_exists($dirroot.'/'.$regs[1])) {
1406 if (@file_exists($dirroot.'/'.$regs[1])) { // avoid [php:warn]
1407 if ($type == 1) {
1408 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1409 }
1410 if ($type == 2) {
1411 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_MAIN_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1412 }
1413 if ($type == 3) {
1414 /*global $dolibarr_main_url_root;*/
1415
1416 // Define $urlwithroot
1417 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1418 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1419 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1420
1421 $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
1422 }
1423 break;
1424 }
1425 }
1426 }
1427 }
1428
1429 return $res;
1430}
1431
1442function dol_get_object_properties($obj, $properties = [])
1443{
1444 // Get real properties using get_object_vars() if $properties is empty
1445 if (empty($properties)) {
1446 return get_object_vars($obj);
1447 }
1448
1449 $existingProperties = [];
1450 $realProperties = get_object_vars($obj);
1451
1452 // Get the real or magic property values
1453 foreach ($properties as $property) {
1454 if (array_key_exists($property, $realProperties)) {
1455 // Real property, add the value
1456 $existingProperties[$property] = $obj->{$property};
1457 } elseif (property_exists($obj, $property)) {
1458 // Magic property
1459 $existingProperties[$property] = $obj->{$property};
1460 }
1461 }
1462
1463 return $existingProperties;
1464}
1465
1466
1481function dol_clone($object, $native = 0)
1482{
1483 if ($native == 0) {
1484 // deprecated method, use the method with native = 2 instead
1485 $tmpsavdb = null;
1486 if (isset($object->db) && isset($object->db->db) && is_object($object->db->db) && get_class($object->db->db) == 'PgSql\Connection') {
1487 $tmpsavdb = $object->db;
1488 unset($object->db); // Such property can not be serialized with pgsl (when object->db->db = 'PgSql\Connection')
1489 }
1490
1491 $myclone = unserialize(serialize($object)); // serialize then unserialize is a hack to be sure to have a new object for all fields
1492
1493 if (!empty($tmpsavdb)) {
1494 $object->db = $tmpsavdb;
1495 }
1496 } elseif ($native == 2) {
1497 // recommended method to have a full isolated cloned object
1498 $myclone = new stdClass();
1499 $tmparray = get_object_vars($object); // return only public properties
1500
1501 if (is_array($tmparray)) {
1502 foreach ($tmparray as $propertykey => $propertyval) {
1503 if (is_scalar($propertyval) || is_array($propertyval)) {
1504 $myclone->$propertykey = $propertyval;
1505 }
1506 }
1507 }
1508 } else {
1509 $myclone = clone $object; // PHP clone is a shallow copy only, not a real clone, so properties of references will keep the reference (referring to the same target/variable)
1510 }
1511
1512 return $myclone;
1513}
1514
1524function dol_size($size, $type = '')
1525{
1526 global $conf;
1527 if (empty($conf->dol_optimize_smallscreen)) {
1528 return $size;
1529 }
1530 if ($type == 'width' && $size > 250) {
1531 return 250;
1532 } else {
1533 return 10;
1534 }
1535}
1536
1537
1549function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1)
1550{
1551 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1552 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1553 // Char '/' and '\' are file delimiters.
1554 // Chars '--' can be used into filename to inject special parameters like --use-compress-program to make command with file as parameter making remote execution of command
1555 $filesystem_forbidden_chars = array('<', '>', '/', '\\', '?', '*', '|', '"', ':', '°', '$', ';', '`');
1556 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1557 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1558 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1559 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1560 $tmp = str_replace('..', '', $tmp);
1561 return $tmp;
1562}
1563
1564
1576function dol_sanitizePathName($str, $newstr = '_', $unaccent = 1)
1577{
1578 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1579 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1580 // Chars '--' can be used into filename to inject special parameters like --use-compress-program to make command with file as parameter making remote execution of command
1581 $filesystem_forbidden_chars = array('<', '>', '?', '*', '|', '"', '°', '$', ';', '`');
1582 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1583 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1584 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1585 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1586 $tmp = str_replace('..', '', $tmp);
1587 return $tmp;
1588}
1589
1597function dol_sanitizeUrl($stringtoclean, $type = 1)
1598{
1599 // 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)
1600 // We should use dol_string_nounprintableascii but function may not be yet loaded/available
1601 $stringtoclean = preg_replace('/[\x00-\x1F\x7F]/u', '', $stringtoclean); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1602 // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: on<!-- -->error=alert(1)
1603 $stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
1604
1605 $stringtoclean = str_replace('\\', '/', $stringtoclean);
1606 if ($type == 1) {
1607 // removing : should disable links to external url like http:aaa)
1608 // removing ';' should disable "named" html entities encode into an url (we should not have this into an url)
1609 $stringtoclean = str_replace(array(':', ';', '@'), '', $stringtoclean);
1610 }
1611
1612 do {
1613 $oldstringtoclean = $stringtoclean;
1614 // removing '&colon' should disable links to external url like http:aaa)
1615 // removing '&#' should disable "numeric" html entities encode into an url (we should not have this into an url)
1616 $stringtoclean = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $stringtoclean);
1617 } while ($oldstringtoclean != $stringtoclean);
1618
1619 if ($type == 1) {
1620 // removing '//' should disable links to external url like //aaa or http//)
1621 $stringtoclean = preg_replace(array('/^[a-z]*\/\/+/i'), '', $stringtoclean);
1622 }
1623
1624 return $stringtoclean;
1625}
1626
1633function dol_sanitizeEmail($stringtoclean)
1634{
1635 do {
1636 $oldstringtoclean = $stringtoclean;
1637 $stringtoclean = str_ireplace(array('"', ':', '[', ']',"\n", "\r", '\\', '\/'), '', $stringtoclean);
1638 } while ($oldstringtoclean != $stringtoclean);
1639
1640 return $stringtoclean;
1641}
1642
1651function dol_string_unaccent($str)
1652{
1653 global $conf;
1654
1655 if (is_null($str)) {
1656 return '';
1657 }
1658
1659 if (utf8_check($str)) {
1660 if (extension_loaded('intl') && getDolGlobalString('MAIN_UNACCENT_USE_TRANSLITERATOR')) {
1661 $transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: NFC;', Transliterator::FORWARD);
1662 return $transliterator->transliterate($str);
1663 }
1664 // See http://www.utf8-chartable.de/
1665 $string = rawurlencode($str);
1666 $replacements = array(
1667 '%C3%80' => 'A', '%C3%81' => 'A', '%C3%82' => 'A', '%C3%83' => 'A', '%C3%84' => 'A', '%C3%85' => 'A',
1668 '%C3%87' => 'C',
1669 '%C3%88' => 'E', '%C3%89' => 'E', '%C3%8A' => 'E', '%C3%8B' => 'E',
1670 '%C3%8C' => 'I', '%C3%8D' => 'I', '%C3%8E' => 'I', '%C3%8F' => 'I',
1671 '%C3%91' => 'N',
1672 '%C3%92' => 'O', '%C3%93' => 'O', '%C3%94' => 'O', '%C3%95' => 'O', '%C3%96' => 'O',
1673 '%C5%A0' => 'S',
1674 '%C3%99' => 'U', '%C3%9A' => 'U', '%C3%9B' => 'U', '%C3%9C' => 'U',
1675 '%C3%9D' => 'Y', '%C5%B8' => 'y',
1676 '%C3%A0' => 'a', '%C3%A1' => 'a', '%C3%A2' => 'a', '%C3%A3' => 'a', '%C3%A4' => 'a', '%C3%A5' => 'a',
1677 '%C3%A7' => 'c',
1678 '%C3%A8' => 'e', '%C3%A9' => 'e', '%C3%AA' => 'e', '%C3%AB' => 'e',
1679 '%C3%AC' => 'i', '%C3%AD' => 'i', '%C3%AE' => 'i', '%C3%AF' => 'i',
1680 '%C3%B1' => 'n',
1681 '%C3%B2' => 'o', '%C3%B3' => 'o', '%C3%B4' => 'o', '%C3%B5' => 'o', '%C3%B6' => 'o',
1682 '%C5%A1' => 's',
1683 '%C3%B9' => 'u', '%C3%BA' => 'u', '%C3%BB' => 'u', '%C3%BC' => 'u',
1684 '%C3%BD' => 'y', '%C3%BF' => 'y'
1685 );
1686 $string = strtr($string, $replacements);
1687 return rawurldecode($string);
1688 } else {
1689 // See http://www.ascii-code.com/
1690 $string = strtr(
1691 $str,
1692 "\xC0\xC1\xC2\xC3\xC4\xC5\xC7
1693 \xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1
1694 \xD2\xD3\xD4\xD5\xD8\xD9\xDA\xDB\xDD
1695 \xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB
1696 \xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF8
1697 \xF9\xFA\xFB\xFC\xFD\xFF",
1698 "AAAAAAC
1699 EEEEIIIIDN
1700 OOOOOUUUY
1701 aaaaaaceeee
1702 iiiidnooooo
1703 uuuuyy"
1704 );
1705 $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"));
1706 return $string;
1707 }
1708}
1709
1723function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '', $badcharstoremove = '', $keepspaces = 0)
1724{
1725 $forbidden_chars_to_replace = array("'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=", '°', '$', ';'); // more complete than dol_sanitizeFileName
1726 if (empty($keepspaces)) {
1727 $forbidden_chars_to_replace[] = " ";
1728 }
1729 $forbidden_chars_to_remove = array();
1730 //$forbidden_chars_to_remove=array("(",")");
1731
1732 if (is_array($badcharstoreplace)) {
1733 $forbidden_chars_to_replace = $badcharstoreplace;
1734 }
1735 if (is_array($badcharstoremove)) {
1736 $forbidden_chars_to_remove = $badcharstoremove;
1737 }
1738
1739 // @phan-suppress-next-line PhanPluginSuspiciousParamOrderInternal
1740 return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str));
1741}
1742
1743
1757function dol_string_nounprintableascii($str, $removetabcrlf = 1)
1758{
1759 if ($removetabcrlf) {
1760 return preg_replace('/[\x00-\x1F\x7F]/u', '', $str); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1761 } else {
1762 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
1763 }
1764}
1765
1774function dol_escape_js($stringtoescape, $mode = 0, $noescapebackslashn = 0)
1775{
1776 if (is_null($stringtoescape)) {
1777 return '';
1778 }
1779
1780 // escape quotes and backslashes, newlines, etc.
1781 $substitjs = array("&#039;" => "\\'", "\r" => '\\r');
1782 //$substitjs['</']='<\/'; // We removed this. Should be useless.
1783 if (empty($noescapebackslashn)) {
1784 $substitjs["\n"] = '\\n';
1785 $substitjs['\\'] = '\\\\';
1786 }
1787 if (empty($mode)) {
1788 $substitjs["'"] = "\\'";
1789 $substitjs['"'] = "\\'";
1790 } elseif ($mode == 1) {
1791 $substitjs["'"] = "\\'";
1792 } elseif ($mode == 2) {
1793 $substitjs['"'] = '\\"';
1794 } elseif ($mode == 3) {
1795 $substitjs["'"] = "\\'";
1796 $substitjs['"'] = "\\\"";
1797 }
1798 return strtr($stringtoescape, $substitjs);
1799}
1800
1807function dol_escape_json($stringtoescape)
1808{
1809 return str_replace('"', '\"', $stringtoescape);
1810}
1811
1819function dol_escape_php($stringtoescape, $stringforquotes = 2)
1820{
1821 if (is_null($stringtoescape)) {
1822 return '';
1823 }
1824
1825 if ($stringforquotes == 2) {
1826 return str_replace('"', "'", $stringtoescape);
1827 } elseif ($stringforquotes == 1) {
1828 // We remove the \ char.
1829 // If we allow the \ char, we can have $stringtoescape =
1830 // abc\';phpcodedanger; so the escapement will become
1831 // abc\\';phpcodedanger; and injecting this into
1832 // $a='...' will give $ac='abc\\';phpcodedanger;
1833 $stringtoescape = str_replace('\\', '', $stringtoescape);
1834 return str_replace("'", "\'", str_replace('"', "'", $stringtoescape));
1835 }
1836
1837 return 'Bad parameter for stringforquotes in dol_escape_php';
1838}
1839
1846function dol_escape_xml($stringtoescape)
1847{
1848 return $stringtoescape;
1849}
1850
1858function dolPrintLabel($s)
1859{
1860 return dol_escape_htmltag(dol_string_nohtmltag($s, 1, 'UTF-8', 0, 0), 0, 0, '', 0, 1);
1861}
1862
1872function dolPrintHTML($s, $allowiframe = 0)
1873{
1874 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, 'common', 0, 1);
1875}
1876
1884function dolPrintHTMLForAttribute($s)
1885{
1886 // The dol_htmlentitiesbr will convert simple text into html
1887 // The dol_escape_htmltag will escape html chars.
1888 return dol_escape_htmltag(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 0, 0, 0, array('br', 'b', 'font', 'span')), 1, -1, '', 0, 1);
1889}
1890
1899function dolPrintHTMLForTextArea($s, $allowiframe = 0)
1900{
1901 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, '', 0, 1);
1902}
1903
1910function dolPrintPassword($s)
1911{
1912 return htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
1913}
1914
1915
1932function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapetags = '', $escapeonlyhtmltags = 0, $cleanalsojavascript = 0)
1933{
1934 if ($noescapetags == 'common') {
1935 $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';
1936 // Add also html5 tags
1937 $noescapetags .= ',header,footer,nav,section,menu,menuitem';
1938 }
1939 if ($cleanalsojavascript) {
1940 $stringtoescape = dol_string_onlythesehtmltags($stringtoescape, 0, 0, $cleanalsojavascript, 0, array(), 0);
1941 }
1942
1943 // escape quotes and backslashes, newlines, etc.
1944 if ($escapeonlyhtmltags) {
1945 $tmp = htmlspecialchars_decode((string) $stringtoescape, ENT_COMPAT);
1946 } else {
1947 $tmp = html_entity_decode((string) $stringtoescape, ENT_COMPAT, 'UTF-8'); // This decode &egrave; into è so string is UTF8 (but &#39; is not decoded).
1948 $tmp = str_ireplace('&#39;', '__SIMPLEQUOTE', $tmp);
1949 }
1950 if (!$keepb) {
1951 $tmp = strtr($tmp, array("<b>" => '', '</b>' => '', '<strong>' => '', '</strong>' => ''));
1952 }
1953 if (!$keepn) {
1954 $tmp = strtr($tmp, array("\r" => '\\r', "\n" => '\\n'));
1955 } elseif ($keepn == -1) {
1956 $tmp = strtr($tmp, array("\r" => '', "\n" => ''));
1957 }
1958
1959 if ($escapeonlyhtmltags) {
1960 return htmlspecialchars($tmp, ENT_COMPAT, 'UTF-8');
1961 } else {
1962 // Escape tags to keep
1963 $tmparrayoftags = array();
1964 if ($noescapetags) {
1965 $tmparrayoftags = explode(',', $noescapetags);
1966 }
1967 if (count($tmparrayoftags)) {
1968 $reg = array();
1969 $tmp = str_ireplace('__DOUBLEQUOTE', '', $tmp); // The keyword DOUBLEQUOTE is forbidden. Reserved, so we removed it if we find it.
1970
1971 foreach ($tmparrayoftags as $tagtoreplace) {
1972 $tmp = preg_replace('/<'.preg_quote($tagtoreplace, '/').'>/', '__BEGINTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1973 $tmp = str_ireplace('</'.$tagtoreplace.'>', '__ENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1974 $tmp = preg_replace('/<'.preg_quote($tagtoreplace, '/').' \/>/', '__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1975
1976 // For case of tag with attribute
1977 do {
1978 $tmpold = $tmp;
1979
1980 if (preg_match('/<'.preg_quote($tagtoreplace, '/').'\s+([^>]+)>/', $tmp, $reg)) {
1981 $tmpattributes = str_ireplace(array('[', ']'), '_', $reg[1]); // We must never have [ ] inside the attribute string
1982 $tmpattributes = str_ireplace('href="http:', '__HREFHTTPA', $tmpattributes);
1983 $tmpattributes = str_ireplace('href="https:', '__HREFHTTPSA', $tmpattributes);
1984 $tmpattributes = str_ireplace('src="http:', '__SRCHTTPIMG', $tmpattributes);
1985 $tmpattributes = str_ireplace('src="https:', '__SRCHTTPSIMG', $tmpattributes);
1986 $tmpattributes = str_ireplace('"', '__DOUBLEQUOTE', $tmpattributes);
1987 $tmpattributes = preg_replace('/[^a-z0-9_\/\?\;\s=&\.\-@:\.#\+]/i', '', $tmpattributes);
1988 //$tmpattributes = preg_replace("/float:\s*(left|right)/", "", $tmpattributes); // Disabled: we must not remove content
1989 $tmp = preg_replace('/<'.preg_quote($tagtoreplace, '/').'\s+'.preg_quote($reg[1], '/').'>/', '__BEGINTAGTOREPLACE'.$tagtoreplace.'['.$tmpattributes.']__', $tmp);
1990 }
1991 if (preg_match('/<'.preg_quote($tagtoreplace, '/').'\s+([^>]+)\s+\/>/', $tmp, $reg)) {
1992 $tmpattributes = str_ireplace(array('[', ']'), '_', $reg[1]); // We must not have [ ] inside the attribute string
1993 $tmpattributes = str_ireplace('"', '__DOUBLEQUOTE', $tmpattributes);
1994 $tmpattributes = preg_replace('/[^a-z0-9_\/\?\;\s=&\.\-@:\.#\+]/i', '', $tmpattributes);
1995 //$tmpattributes = preg_replace("/float:\s*(left|right)/", "", $tmpattributes); // Disabled: we must not remove content.
1996 $tmp = preg_replace('/<'.preg_quote($tagtoreplace, '/').'\s+'.preg_quote($reg[1], '/').'\s+\/>/', '__BEGINENDTAGTOREPLACE'.$tagtoreplace.'['.$tmpattributes.']__', $tmp);
1997 }
1998
1999 $diff = strcmp($tmpold, $tmp);
2000 } while ($diff);
2001 }
2002 }
2003
2004 $result = htmlentities($tmp, ENT_COMPAT, 'UTF-8'); // Convert & into &amp; and more...
2005
2006 //print $result;
2007
2008 if (count($tmparrayoftags)) {
2009 foreach ($tmparrayoftags as $tagtoreplace) {
2010 $result = str_ireplace('__BEGINTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.'>', $result);
2011 $result = preg_replace('/__BEGINTAGTOREPLACE'.$tagtoreplace.'\[([^\]]*)\]__/', '<'.$tagtoreplace.' \1>', $result);
2012 $result = str_ireplace('__ENDTAGTOREPLACE'.$tagtoreplace.'__', '</'.$tagtoreplace.'>', $result);
2013 $result = str_ireplace('__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.' />', $result);
2014 $result = preg_replace('/__BEGINENDTAGTOREPLACE'.$tagtoreplace.'\[([^\]]*)\]__/', '<'.$tagtoreplace.' \1 />', $result);
2015 }
2016
2017 $result = str_ireplace('__HREFHTTPA', 'href="http:', $result);
2018 $result = str_ireplace('__HREFHTTPSA', 'href="https:', $result);
2019 $result = str_ireplace('__SRCHTTPIMG', 'src="http:', $result);
2020 $result = str_ireplace('__SRCHTTPSIMG', 'src="https:', $result);
2021 $result = str_ireplace('__DOUBLEQUOTE', '"', $result);
2022 }
2023
2024 $result = str_ireplace('__SIMPLEQUOTE', '&#39;', $result);
2025
2026 //$result="\n\n\n".var_export($tmp, true)."\n\n\n".var_export($result, true);
2027
2028 return $result;
2029 }
2030}
2031
2039function dol_strtolower($string, $encoding = "UTF-8")
2040{
2041 if (function_exists('mb_strtolower')) {
2042 return mb_strtolower($string, $encoding);
2043 } else {
2044 return strtolower($string);
2045 }
2046}
2047
2056function dol_strtoupper($string, $encoding = "UTF-8")
2057{
2058 if (function_exists('mb_strtoupper')) {
2059 return mb_strtoupper($string, $encoding);
2060 } else {
2061 return strtoupper($string);
2062 }
2063}
2064
2073function dol_ucfirst($string, $encoding = "UTF-8")
2074{
2075 if (function_exists('mb_substr')) {
2076 return mb_strtoupper(mb_substr($string, 0, 1, $encoding), $encoding).mb_substr($string, 1, null, $encoding);
2077 } else {
2078 return ucfirst($string);
2079 }
2080}
2081
2090function dol_ucwords($string, $encoding = "UTF-8")
2091{
2092 if (function_exists('mb_convert_case')) {
2093 return mb_convert_case($string, MB_CASE_TITLE, $encoding);
2094 } else {
2095 return ucwords($string);
2096 }
2097}
2098
2121function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = '', $restricttologhandler = '', $logcontext = null)
2122{
2123 global $conf, $user, $debugbar;
2124
2125 // If syslog module enabled
2126 if (!isModEnabled('syslog')) {
2127 return;
2128 }
2129
2130 // Check if we are into execution of code of a website
2131 if (defined('USEEXTERNALSERVER') && !defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) {
2132 global $website, $websitekey;
2133 if (is_object($website) && !empty($website->ref)) {
2134 $suffixinfilename .= '_website_'.$website->ref;
2135 } elseif (!empty($websitekey)) {
2136 $suffixinfilename .= '_website_'.$websitekey;
2137 }
2138 }
2139
2140 // Check if we have a forced suffix
2141 if (defined('USESUFFIXINLOG')) {
2142 $suffixinfilename .= constant('USESUFFIXINLOG');
2143 }
2144
2145 if ($ident < 0) {
2146 foreach ($conf->loghandlers as $loghandlerinstance) {
2147 $loghandlerinstance->setIdent($ident);
2148 }
2149 }
2150
2151 if (!empty($message)) {
2152 // Test log level
2153 // @phan-suppress-next-line PhanPluginDuplicateArrayKey
2154 $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');
2155 if (!array_key_exists($level, $logLevels)) {
2156 throw new Exception('Incorrect log level');
2157 }
2158 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
2159 return;
2160 }
2161
2162 if (!getDolGlobalString('MAIN_SHOW_PASSWORD_INTO_LOG')) {
2163 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
2164 }
2165
2166 // If adding log inside HTML page is required
2167 if ((!empty($_REQUEST['logtohtml']) && getDolGlobalString('MAIN_ENABLE_LOG_TO_HTML'))
2168 || (is_object($user) && $user->hasRight('debugbar', 'read') && is_object($debugbar))) {
2169 $ospid = sprintf("%7s", dol_trunc(getmypid(), 7, 'right', 'UTF-8', 1));
2170 $osuser = " ".sprintf("%6s", dol_trunc(function_exists('posix_getuid') ? posix_getuid() : '', 6, 'right', 'UTF-8', 1));
2171
2172 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".sprintf("%-7s", $logLevels[$level])." ".$ospid." ".$osuser." ".$message;
2173 }
2174
2175 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
2176 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
2177 if (getDolGlobalString('MAIN_ENABLE_LOG_INLINE_HTML') && GETPOSTINT("log")) {
2178 print "\n\n<!-- Log start\n";
2179 print dol_escape_htmltag($message)."\n";
2180 print "Log end -->\n";
2181 }
2182
2183 $data = array(
2184 'message' => $message,
2185 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
2186 'level' => $level,
2187 'user' => ((is_object($user) && $user->id) ? $user->login : false),
2188 'ip' => false,
2189 'osuser' => function_exists('posix_getuid') ? posix_getuid() : false,
2190 'ospid' => getmypid() // on linux, max value is defined into cat /proc/sys/kernel/pid_max
2191 );
2192
2193 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
2194 if (!empty($remoteip)) {
2195 $data['ip'] = $remoteip;
2196 // This is when server run behind a reverse proxy
2197 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
2198 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
2199 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
2200 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
2201 }
2202 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
2203 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
2204 $data['ip'] = $_SERVER['SERVER_ADDR'];
2205 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
2206 // This is when PHP session is ran outside a web server, like from Windows command line (Not always defined, but useful if OS defines it).
2207 $data['ip'] = $_SERVER['COMPUTERNAME'];
2208 } else {
2209 $data['ip'] = '???';
2210 }
2211
2212 if (!empty($_SERVER['USERNAME'])) {
2213 // This is when PHP session is ran outside a web server, like from Linux command line (Not always defined, but useful if OS defines it).
2214 $data['osuser'] = $_SERVER['USERNAME'];
2215 } elseif (!empty($_SERVER['LOGNAME'])) {
2216 // This is when PHP session is ran outside a web server, like from Linux command line (Not always defined, but useful if OS defines it).
2217 $data['osuser'] = $_SERVER['LOGNAME'];
2218 }
2219
2220 // Loop on each log handler and send output
2221 foreach ($conf->loghandlers as $loghandlerinstance) {
2222 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
2223 continue;
2224 }
2225 $loghandlerinstance->export($data, $suffixinfilename);
2226 }
2227 unset($data);
2228 }
2229
2230 if ($ident > 0) {
2231 foreach ($conf->loghandlers as $loghandlerinstance) {
2232 $loghandlerinstance->setIdent($ident);
2233 }
2234 }
2235}
2236
2248function dolButtonToOpenExportDialog($name, $label, $buttonstring, $exportSiteName, $overwriteGitUrl, $website)
2249{
2250 global $langs, $db;
2251
2252 $form = new Form($db);
2253
2254 $templatenameforexport = $website->name_template; // Example 'website_template-corporate'
2255 if (empty($templatenameforexport)) {
2256 $templatenameforexport = 'website_'.$website->ref;
2257 }
2258
2259 $out = '';
2260 $out .= '<input type="button" class="cursorpointer button bordertransp" id="open-dialog-' . $name . '" value="'.dol_escape_htmltag($buttonstring).'"/>';
2261
2262 // for generate popup
2263 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">';
2264 $out .= 'jQuery(document).ready(function () {';
2265 $out .= ' jQuery("#open-dialog-' . $name . '").click(function () {';
2266 $out .= ' var dialogHtml = \'';
2267
2268 $dialogcontent = ' <div id="custom-dialog-' . $name . '">';
2269 $dialogcontent .= ' <div style="margin-top: 20px;">';
2270 $dialogcontent .= ' <label for="export-site-' . $name . '"><strong>'.$langs->trans("ExportSiteLabel").'...</label><br>';
2271 $dialogcontent .= ' <button class="button smallpaddingimp" id="export-site-' . $name . '">' . dol_escape_htmltag($langs->trans("DownloadZip")) . '</button>';
2272 $dialogcontent .= ' </div>';
2273 $dialogcontent .= ' <br>';
2274 $dialogcontent .= ' <div style="margin-top: 20px;">';
2275 $dialogcontent .= ' <strong>'.$langs->trans("ExportSiteGitLabel").' '.$form->textwithpicto('', $langs->trans("SourceFiles"), 1, 'help', '', 0, 3, '').'</strong><br>';
2276 $dialogcontent .= ' <form action="'.dol_escape_htmltag($overwriteGitUrl).'" method="POST">';
2277 $dialogcontent .= ' <input type="hidden" name="action" value="overwritesite">';
2278 $dialogcontent .= ' <input type="hidden" name="token" value="'.newToken().'">';
2279 $dialogcontent .= ' <input type="text" autofocus name="export_path" id="export-path-'.$name.'" placeholder="'.$langs->trans('ExportPath').'" style="width:400px " value="'.dol_escape_htmltag($templatenameforexport).'"/><br>';
2280 $dialogcontent .= ' <button type="submit" class="button smallpaddingimp" id="overwrite-git-' . $name . '">' . dol_escape_htmltag($langs->trans("ExportIntoGIT")) . '</button>';
2281 $dialogcontent .= ' </form>';
2282 $dialogcontent .= ' </div>';
2283 $dialogcontent .= ' </div>';
2284
2285 $out .= dol_escape_js($dialogcontent);
2286
2287 $out .= '\';';
2288
2289
2290 // Add the content of the dialog to the body of the page
2291 $out .= ' var $dialog = jQuery("#custom-dialog-' . $name . '");';
2292 $out .= ' if ($dialog.length > 0) {
2293 $dialog.remove();
2294 }
2295 jQuery("body").append(dialogHtml);';
2296
2297 // Configuration of popup
2298 $out .= ' jQuery("#custom-dialog-' . $name . '").dialog({';
2299 $out .= ' autoOpen: false,';
2300 $out .= ' modal: true,';
2301 $out .= ' height: 290,';
2302 $out .= ' width: "40%",';
2303 $out .= ' title: "' . dol_escape_js($label) . '",';
2304 $out .= ' });';
2305
2306 // Simulate a click on the original "submit" input to export the site.
2307 $out .= ' jQuery("#export-site-' . $name . '").click(function () {';
2308 $out .= ' console.log("Clic on exportsite.");';
2309 $out .= ' var target = jQuery("input[name=\'' . dol_escape_js($exportSiteName) . '\']");';
2310 $out .= ' console.log("element founded:", target.length > 0);';
2311 $out .= ' if (target.length > 0) { target.click(); }';
2312 $out .= ' jQuery("#custom-dialog-' . $name . '").dialog("close");';
2313 $out .= ' });';
2314
2315 // open popup
2316 $out .= ' jQuery("#custom-dialog-' . $name . '").dialog("open");';
2317 $out .= ' return false;';
2318 $out .= ' });';
2319 $out .= '});';
2320 $out .= '</script>';
2321
2322 return $out;
2323}
2324
2325
2342function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
2343{
2344 global $conf;
2345
2346 if (strpos($url, '?') > 0) {
2347 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2348 } else {
2349 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2350 }
2351
2352 $out = '';
2353
2354 $backtopagejsfieldsid = '';
2355 $backtopagejsfieldslabel = '';
2356 if ($backtopagejsfields) {
2357 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
2358 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
2359 $backtopagejsfields = $name.":".$backtopagejsfields;
2360 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
2361 } else {
2362 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
2363 }
2364 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
2365 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
2366 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
2367 }
2368
2369 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
2370 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
2371 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
2372 if (empty($conf->use_javascript_ajax)) {
2373 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
2374 } elseif ($jsonopen) {
2375 $out .= ' href="#" onclick="'.$jsonopen.'"';
2376 } else {
2377 $out .= ' href="#"';
2378 }
2379 $out .= '>'.$buttonstring.'</a>';
2380
2381 if (!empty($conf->use_javascript_ajax)) {
2382 // Add code to open url using the popup. Add also hidden field to retrieve the returned variables
2383 $out .= '<!-- code to open popup and variables to retrieve returned variables -->';
2384 $out .= '<div id="idfordialog'.$name.'" class="hidden">'.(getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2 ? 'div for dialog' : '').'</div>';
2385 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">'.(getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2 ? 'div for returned id' : '').'</div>';
2386 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">'.(getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2 ? 'div for returned label' : '').'</div>';
2387
2388 $out .= '<!-- Add js code to open dialog popup on dialog -->';
2389 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
2390 jQuery(document).ready(function () {
2391 jQuery(".button_'.$name.'").click(function () {
2392 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
2393 var $tmpdialog = $(\'#idfordialog'.$name.'\');
2394 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
2395 $tmpdialog.dialog({
2396 autoOpen: false,
2397 modal: true,
2398 height: (window.innerHeight - 150),
2399 width: \'80%\',
2400 title: \''.dol_escape_js($label).'\',
2401 open: function (event, ui) {
2402 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
2403 },
2404 close: function (event, ui) {
2405 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
2406 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
2407 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
2408 if (returnedid != "" && returnedid != "div for returned id") {
2409 jQuery("#'.(empty($backtopagejsfieldsid) ? "none" : $backtopagejsfieldsid).'").val(returnedid);
2410 }
2411 if (returnedlabel != "" && returnedlabel != "div for returned label") {
2412 jQuery("#'.(empty($backtopagejsfieldslabel) ? "none" : $backtopagejsfieldslabel).'").val(returnedlabel);
2413 }
2414 }
2415 });
2416
2417 $tmpdialog.dialog(\'open\');
2418 return false;
2419 });
2420 });
2421 </script>';
2422 }
2423 return $out;
2424}
2425
2442function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2443{
2444 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2445}
2446
2463function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2464{
2465 global $conf, $langs, $hookmanager;
2466
2467 // Show title
2468 $showtitle = 1;
2469 if (!empty($conf->dol_optimize_smallscreen)) {
2470 $showtitle = 0;
2471 }
2472
2473 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2474
2475 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2476 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2477 }
2478
2479 // Show right part
2480 if ($morehtmlright) {
2481 $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.
2482 }
2483
2484 // Show title
2485 if (!empty($title) && $showtitle && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2486 $limittitle = 30;
2487 $out .= '<a class="tabTitle">';
2488 if ($picto) {
2489 $noprefix = $pictoisfullpath;
2490 if (strpos($picto, 'fontawesome_') !== false) {
2491 $noprefix = 1;
2492 }
2493 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2494 }
2495 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2496 $out .= '</a>';
2497 }
2498
2499 // Show tabs
2500
2501 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2502 $maxkey = -1;
2503 if (is_array($links) && !empty($links)) {
2504 $keys = array_keys($links);
2505 if (count($keys)) {
2506 $maxkey = max($keys);
2507 }
2508 }
2509
2510 // Show tabs
2511 // if =0 we don't use the feature
2512 if (empty($limittoshow)) {
2513 $limittoshow = (!getDolGlobalString('MAIN_MAXTABS_IN_CARD') ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2514 }
2515 if (!empty($conf->dol_optimize_smallscreen)) {
2516 $limittoshow = 2;
2517 }
2518
2519 $displaytab = 0;
2520 $nbintab = 0;
2521 $popuptab = 0;
2522 $outmore = '';
2523 for ($i = 0; $i <= $maxkey; $i++) {
2524 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2525 // If active tab is already present
2526 if ($i >= $limittoshow) {
2527 $limittoshow--;
2528 }
2529 }
2530 }
2531
2532 for ($i = 0; $i <= $maxkey; $i++) {
2533 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2534 $isactive = true;
2535 } else {
2536 $isactive = false;
2537 }
2538
2539 if ($i < $limittoshow || $isactive) {
2540 // Output entry with a visible tab
2541 $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])).' -->';
2542
2543 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2544 if (!empty($links[$i][0])) {
2545 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2546 } else {
2547 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2548 }
2549 } elseif (!empty($links[$i][1])) {
2550 //print "x $i $active ".$links[$i][2]." z";
2551 $out .= '<div class="tab tab'.($isactive ? 'active' : 'unactive').'" style="margin: 0 !important">';
2552 if (!empty($links[$i][0])) {
2553 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2554 $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).'">';
2555 }
2556 $out .= $links[$i][1];
2557 if (!empty($links[$i][0])) {
2558 $out .= '</a>'."\n";
2559 }
2560 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2561 $out .= '</div>';
2562 }
2563
2564 $out .= '</div>';
2565 } else {
2566 // Add entry into the combo popup with the other tabs
2567 if (!$popuptab) {
2568 $popuptab = 1;
2569 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2570 }
2571 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2572 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2573 if (!empty($links[$i][0])) {
2574 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2575 } else {
2576 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2577 }
2578 } elseif (!empty($links[$i][1])) {
2579 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2580 $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.
2581 $outmore .= '</a>'."\n";
2582 }
2583 $outmore .= '</div>';
2584
2585 $nbintab++;
2586 }
2587 $displaytab = $i;
2588 }
2589 if ($popuptab) {
2590 $outmore .= '</div>';
2591 }
2592
2593 if ($popuptab) { // If there is some tabs not shown
2594 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2595 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2596 $widthofpopup = 200;
2597
2598 $tabsname = $moretabssuffix;
2599 if (empty($tabsname)) {
2600 $tabsname = str_replace("@", "", $picto);
2601 }
2602 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2603 if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
2604 $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".
2605 }
2606 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2607 $out .= $outmore;
2608 $out .= '</div>';
2609 $out .= '<div></div>';
2610 $out .= "</div>\n";
2611
2612 $out .= '<script nonce="'.getNonce().'">';
2613 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2614 var x = this.offsetLeft, y = this.offsetTop;
2615 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2616 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2617 $('#moretabsList".$tabsname."').css('".$right."','8px');
2618 }
2619 $('#moretabsList".$tabsname."').css('".$left."','auto');
2620 });
2621 ";
2622 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2623 $out .= "</script>";
2624 }
2625
2626 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2627 $out .= "</div>\n";
2628 }
2629
2630 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2631 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom')));
2632 $out .= '">'."\n";
2633 }
2634 if (!empty($dragdropfile)) {
2635 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2636 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2637 }
2638 $parameters = array('tabname' => $active, 'out' => $out);
2639 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2640 if ($reshook > 0) {
2641 $out = $hookmanager->resPrint;
2642 }
2643
2644 return $out;
2645}
2646
2654function dol_fiche_end($notab = 0)
2655{
2656 print dol_get_fiche_end($notab);
2657}
2658
2665function dol_get_fiche_end($notab = 0)
2666{
2667 if (!$notab || $notab == -1) {
2668 return "\n</div>\n";
2669 } else {
2670 return '';
2671 }
2672}
2673
2693function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2694{
2695 global $conf, $form, $user, $langs, $hookmanager, $action;
2696
2697 $error = 0;
2698
2699 $maxvisiblephotos = 1;
2700 $showimage = 1;
2701 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2702 // @phan-suppress-next-line PhanUndeclaredMethod
2703 $showbarcode = !isModEnabled('barcode') ? 0 : (empty($object->barcode) ? 0 : 1);
2704 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2705 $showbarcode = 0;
2706 }
2707 $modulepart = 'unknown';
2708
2709 if (in_array($object->element, ['societe', 'contact', 'product', 'ticket', 'bom'])) {
2710 $modulepart = $object->element;
2711 } elseif ($object->element == 'member') {
2712 $modulepart = 'memberphoto';
2713 } elseif ($object->element == 'user') {
2714 $modulepart = 'userphoto';
2715 }
2716
2717 if (class_exists("Imagick")) {
2718 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2719 $modulepart = $object->element;
2720 } elseif ($object->element == 'fichinter' || $object->element == 'intervention') {
2721 $modulepart = 'ficheinter';
2722 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2723 $modulepart = 'contract';
2724 } elseif ($object->element == 'order_supplier') {
2725 $modulepart = 'supplier_order';
2726 } elseif ($object->element == 'invoice_supplier') {
2727 $modulepart = 'supplier_invoice';
2728 }
2729 }
2730
2731 if ($object->element == 'product') {
2733 '@phan-var-force Product $object';
2734 $width = 80;
2735 $cssclass = 'photowithmargin photoref';
2736 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2737 $maxvisiblephotos = getDolGlobalInt('PRODUCT_MAX_VISIBLE_PHOTO', 5);
2738 if ($conf->browser->layout == 'phone') {
2739 $maxvisiblephotos = 1;
2740 }
2741 if ($showimage) {
2742 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$object->show_photos('product', $conf->product->multidir_output[$entity], 1, $maxvisiblephotos, 0, 0, 0, 0, $width, 0, '').'</div>';
2743 } else {
2744 if (getDolGlobalString('PRODUCT_NODISPLAYIFNOPHOTO')) {
2745 $nophoto = '';
2746 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2747 } else { // Show no photo link
2748 $nophoto = '/public/theme/common/nophoto.png';
2749 $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>';
2750 }
2751 }
2752 } elseif ($object->element == 'category') {
2754 '@phan-var-force Categorie $object';
2755 $width = 80;
2756 $cssclass = 'photowithmargin photoref';
2757 $showimage = $object->isAnyPhotoAvailable($conf->categorie->multidir_output[$entity]);
2758 $maxvisiblephotos = getDolGlobalInt('CATEGORY_MAX_VISIBLE_PHOTO', 5);
2759 if ($conf->browser->layout == 'phone') {
2760 $maxvisiblephotos = 1;
2761 }
2762 if ($showimage) {
2763 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$object->show_photos('category', $conf->categorie->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, 0, $width, 0, '').'</div>';
2764 } else {
2765 if (getDolGlobalString('CATEGORY_NODISPLAYIFNOPHOTO')) {
2766 $nophoto = '';
2767 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2768 } else { // Show no photo link
2769 $nophoto = '/public/theme/common/nophoto.png';
2770 $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>';
2771 }
2772 }
2773 } elseif ($object->element == 'bom') {
2775 '@phan-var-force Bom $object';
2776 $width = 80;
2777 $cssclass = 'photowithmargin photoref';
2778 $showimage = $object->is_photo_available($conf->bom->multidir_output[$entity]);
2779 $maxvisiblephotos = getDolGlobalInt('BOM_MAX_VISIBLE_PHOTO', 5);
2780 if ($conf->browser->layout == 'phone') {
2781 $maxvisiblephotos = 1;
2782 }
2783 if ($showimage) {
2784 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$object->show_photos('bom', $conf->bom->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, 0, $width, 0, '').'</div>';
2785 } else {
2786 if (getDolGlobalString('BOM_NODISPLAYIFNOPHOTO')) {
2787 $nophoto = '';
2788 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2789 } else { // Show no photo link
2790 $nophoto = '/public/theme/common/nophoto.png';
2791 $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>';
2792 }
2793 }
2794 } elseif ($object->element == 'ticket') {
2795 $width = 80;
2796 $cssclass = 'photoref';
2798 '@phan-var-force Ticket $object';
2799 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2800 $maxvisiblephotos = getDolGlobalInt('TICKET_MAX_VISIBLE_PHOTO', 2);
2801 if ($conf->browser->layout == 'phone') {
2802 $maxvisiblephotos = 1;
2803 }
2804
2805 if ($showimage) {
2806 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2807 if ($object->nbphoto > 0) {
2808 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2809 } else {
2810 $showimage = 0;
2811 }
2812 }
2813 if (!$showimage) {
2814 if (getDolGlobalString('TICKET_NODISPLAYIFNOPHOTO')) {
2815 $nophoto = '';
2816 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2817 } else { // Show no photo link
2818 $nophoto = img_picto('No photo', 'object_ticket');
2819 $morehtmlleft .= '<!-- No photo to show -->';
2820 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2821 $morehtmlleft .= $nophoto;
2822 $morehtmlleft .= '</div></div>';
2823 }
2824 }
2825 } else {
2826 if ($showimage) {
2827 if ($modulepart != 'unknown' || method_exists($object, 'getDataToShowPhoto')) {
2828 $phototoshow = '';
2829 // Check if a preview file is available
2830 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2831 $objectref = dol_sanitizeFileName($object->ref);
2832 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2833 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2834 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2835 $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
2836 } else {
2837 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2838 }
2839 if (empty($subdir)) {
2840 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2841 }
2842
2843 $filepath = $dir_output.$subdir."/";
2844
2845 $filepdf = $filepath.$objectref.".pdf";
2846 $relativepath = $subdir.'/'.$objectref.'.pdf';
2847
2848 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2849 $fileimage = $filepdf.'_preview.png';
2850 $relativepathimage = $relativepath.'_preview.png';
2851
2852 $pdfexists = file_exists($filepdf);
2853
2854 // If PDF file exists
2855 if ($pdfexists) {
2856 // Conversion du PDF en image png si fichier png non existent
2857 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2858 if (!getDolGlobalString('MAIN_DISABLE_PDF_THUMBS')) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2859 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2860 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2861 if ($ret < 0) {
2862 $error++;
2863 }
2864 }
2865 }
2866 }
2867
2868 if ($pdfexists && !$error) {
2869 $heightforphotref = 80;
2870 if (!empty($conf->dol_optimize_smallscreen)) {
2871 $heightforphotref = 60;
2872 }
2873 // If the preview file is found
2874 if (file_exists($fileimage)) {
2875 $phototoshow = '<div class="photoref">';
2876 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2877 $phototoshow .= '</div>';
2878 }
2879 }
2880 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo' or 'memberphoto'
2881 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2882 }
2883
2884 if ($phototoshow) {
2885 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2886 $morehtmlleft .= $phototoshow;
2887 $morehtmlleft .= '</div>';
2888 }
2889 }
2890
2891 if (empty($phototoshow)) { // Show No photo link (picto of object)
2892 if ($object->element == 'action') {
2893 $width = 80;
2894 $cssclass = 'photorefcenter';
2895 $nophoto = img_picto('No photo', 'title_agenda');
2896 } else {
2897 $width = 14;
2898 $cssclass = 'photorefcenter';
2899 $picto = $object->picto; // @phan-suppress-current-line PhanUndeclaredProperty
2900 $prefix = 'object_';
2901 if ($object->element == 'project' && !$object->public) { // @phan-suppress-current-line PhanUndeclaredProperty
2902 $picto = 'project'; // instead of projectpub
2903 }
2904 if (strpos($picto, 'fontawesome_') !== false) {
2905 $prefix = '';
2906 }
2907 $nophoto = img_picto('No photo', $prefix.$picto);
2908 }
2909 $morehtmlleft .= '<!-- No photo to show -->';
2910 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2911 $morehtmlleft .= $nophoto;
2912 $morehtmlleft .= '</div></div>';
2913 }
2914 }
2915 }
2916
2917 // Show barcode
2918 if ($showbarcode) {
2919 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2920 }
2921
2922 if ($object->element == 'societe') {
2923 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2924 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2925 } else {
2926 $morehtmlstatus .= $object->getLibStatut(6);
2927 }
2928 } elseif ($object->element == 'product') {
2929 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2930 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2931 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2932 } else {
2933 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2934 }
2935 $morehtmlstatus .= ' &nbsp; ';
2936 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2937 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2938 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2939 } else {
2940 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2941 }
2942 } elseif (in_array($object->element, array('salary'))) {
2943 $tmptxt = $object->getLibStatut(6, $object->alreadypaid);
2944 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2945 $tmptxt = $object->getLibStatut(5, $object->alreadypaid);
2946 }
2947 $morehtmlstatus .= $tmptxt;
2948 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier', 'chargesociales', 'loan', 'tva'))) { // TODO Move this to use ->alreadypaid
2949 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2950 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2951 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2952 }
2953 $morehtmlstatus .= $tmptxt;
2954 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2955 if ($object->statut == 0) {
2956 $morehtmlstatus .= $object->getLibStatut(5);
2957 } else {
2958 $morehtmlstatus .= $object->getLibStatut(4);
2959 }
2960 } elseif ($object->element == 'facturerec') {
2961 '@phan-var-force FactureRec $object';
2962 if ($object->frequency == 0) {
2963 $morehtmlstatus .= $object->getLibStatut(2);
2964 } else {
2965 $morehtmlstatus .= $object->getLibStatut(5);
2966 }
2967 } elseif ($object->element == 'project_task') {
2968 $object->fk_statut = 1;
2969 if ($object->progress > 0) {
2970 $object->fk_statut = 2;
2971 }
2972 if ($object->progress >= 100) {
2973 $object->fk_statut = 3;
2974 }
2975 $tmptxt = $object->getLibStatut(5);
2976 $morehtmlstatus .= $tmptxt; // No status on task
2977 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2978 $tmptxt = $object->getLibStatut(6);
2979 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2980 $tmptxt = $object->getLibStatut(5);
2981 }
2982 $morehtmlstatus .= $tmptxt;
2983 }
2984
2985 // Add if object was dispatched "into accountancy"
2986 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2987 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2988 if (method_exists($object, 'getVentilExportCompta')) {
2989 $accounted = $object->getVentilExportCompta();
2990 $langs->load("accountancy");
2991 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2992 }
2993 }
2994
2995 // Add alias for thirdparty
2996 if (!empty($object->name_alias)) {
2997 '@phan-var-force Societe $object';
2998 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
2999 }
3000
3001 // Add label
3002 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
3003 if (!empty($object->label)) {
3004 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
3005 }
3006 }
3007 // Show address and email
3008 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
3009 $moreaddress = $object->getBannerAddress('refaddress', $object); // address, email, url, social networks
3010 if ($moreaddress) {
3011 $morehtmlref .= '<div class="refidno refaddress">';
3012 $morehtmlref .= $moreaddress;
3013 $morehtmlref .= '</div>';
3014 }
3015 }
3016 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)) {
3017 $morehtmlref .= '<div style="clear: both;"></div>';
3018 $morehtmlref .= '<div class="refidno opacitymedium">';
3019 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
3020 $morehtmlref .= '</div>';
3021 }
3022
3023 $parameters = array('morehtmlref' => &$morehtmlref, 'moreparam' => &$moreparam, 'morehtmlleft' => &$morehtmlleft, 'morehtmlstatus' => &$morehtmlstatus, 'morehtmlright' => &$morehtmlright);
3024 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
3025 if ($reshook < 0) {
3026 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
3027 } elseif (empty($reshook)) {
3028 $morehtmlref .= $hookmanager->resPrint;
3029 } elseif ($reshook > 0) {
3030 $morehtmlref = $hookmanager->resPrint;
3031 }
3032
3033 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
3034 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
3035 print '</div>';
3036 print '<div class="underrefbanner clearboth"></div>';
3037}
3038
3048function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
3049{
3050 global $langs;
3051 $ret = '';
3052 if ($fieldrequired) {
3053 $ret .= '<span class="fieldrequired">';
3054 }
3055 $ret .= '<label for="'.$fieldkey.'">';
3056 $ret .= $langs->trans($langkey);
3057 $ret .= '</label>';
3058 if ($fieldrequired) {
3059 $ret .= '</span>';
3060 }
3061 return $ret;
3062}
3063
3071function dol_bc($var, $moreclass = '')
3072{
3073 global $bc;
3074 $ret = ' '.$bc[$var];
3075 if ($moreclass) {
3076 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
3077 }
3078 return $ret;
3079}
3080
3094function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = null, $mode = 0, $extralangcode = '')
3095{
3096 global $langs, $hookmanager;
3097
3098 $ret = '';
3099 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
3100
3101 // See format of addresses on https://en.wikipedia.org/wiki/Address
3102 // Address
3103 if (empty($mode)) {
3104 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
3105 }
3106 // Zip/Town/State
3107 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || getDolGlobalString('MAIN_FORCE_STATE_INTO_ADDRESS')) {
3108 // US: title firstname name \n address lines \n town, state, zip \n country
3109 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3110 $ret .= (($ret && $town) ? $sep : '').$town;
3111
3112 if (!empty($object->state)) {
3113 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
3114 }
3115 if (!empty($object->zip)) {
3116 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
3117 }
3118 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
3119 // UK: title firstname name \n address lines \n town state \n zip \n country
3120 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3121 $ret .= ($ret ? $sep : '').$town;
3122 if (!empty($object->state)) {
3123 $ret .= ($ret ? ", " : '').$object->state;
3124 }
3125 if (!empty($object->zip)) {
3126 $ret .= ($ret ? $sep : '').$object->zip;
3127 }
3128 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
3129 // ES: title firstname name \n address lines \n zip town \n state \n country
3130 $ret .= ($ret ? $sep : '').$object->zip;
3131 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3132 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
3133 if (!empty($object->state)) {
3134 $ret .= $sep.$object->state;
3135 }
3136 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
3137 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
3138 // See https://www.sljfaq.org/afaq/addresses.html
3139 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3140 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
3141 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
3142 // IT: title firstname name\n address lines \n zip town state_code \n country
3143 $ret .= ($ret ? $sep : '').$object->zip;
3144 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3145 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
3146 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
3147 } else {
3148 // Other: title firstname name \n address lines \n zip town[, state] \n country
3149 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3150 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
3151 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
3152 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
3153 $ret .= ($ret ? ", " : '').$object->state;
3154 }
3155 }
3156
3157 if (!is_object($outputlangs)) {
3158 $outputlangs = $langs;
3159 }
3160 if ($withcountry) {
3161 $langs->load("dict");
3162 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
3163 }
3164 if ($hookmanager) {
3165 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
3166 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
3167 if ($reshook > 0) {
3168 $ret = '';
3169 }
3170 $ret .= $hookmanager->resPrint;
3171 }
3172
3173 return $ret;
3174}
3175
3176
3177
3187function dol_strftime($fmt, $ts = false, $is_gmt = false)
3188{
3189 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
3190 return dol_print_date($ts, $fmt, $is_gmt);
3191 } else {
3192 return 'Error date outside supported range';
3193 }
3194}
3195
3217function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = null, $encodetooutput = false)
3218{
3219 global $conf, $langs;
3220
3221 // If date undefined or "", we return ""
3222 if (dol_strlen($time) == 0) {
3223 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
3224 }
3225
3226 if ($tzoutput === 'auto') {
3227 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
3228 }
3229
3230 // Clean parameters
3231 $to_gmt = false;
3232 $offsettz = $offsetdst = 0;
3233 if ($tzoutput) {
3234 $to_gmt = true; // For backward compatibility
3235 if (is_string($tzoutput)) {
3236 if ($tzoutput == 'tzserver') {
3237 $to_gmt = false;
3238 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
3239 // @phan-suppress-next-line PhanPluginRedundantAssignment
3240 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
3241 // @phan-suppress-next-line PhanPluginRedundantAssignment
3242 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
3243 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
3244 $to_gmt = true;
3245 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
3246
3247 if (class_exists('DateTimeZone')) {
3248 $user_date_tz = new DateTimeZone($offsettzstring);
3249 $user_dt = new DateTime();
3250 $user_dt->setTimezone($user_date_tz);
3251 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
3252 $offsettz = $user_dt->getOffset(); // should include dst ?
3253 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
3254 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
3255 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
3256 }
3257 }
3258 }
3259 }
3260 if (!is_object($outputlangs)) {
3261 $outputlangs = $langs;
3262 }
3263 if (!$format) {
3264 $format = 'daytextshort';
3265 }
3266
3267 // Do we have to reduce the length of date (year on 2 chars) to save space.
3268 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
3269 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour', 'dayhoursec'))) ? 1 : 0; // Test on original $format param.
3270 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
3271 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
3272 if ($formatwithoutreduce != $format) {
3273 $format = $formatwithoutreduce;
3274 $reduceformat = 1;
3275 } // so format 'dayreduceformat' is processed like day
3276
3277 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
3278 // TODO Add format daysmallyear and dayhoursmallyear
3279 if ($format == 'day') {
3280 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
3281 } elseif ($format == 'hour') {
3282 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
3283 } elseif ($format == 'hourduration') {
3284 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
3285 } elseif ($format == 'daytext') {
3286 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
3287 } elseif ($format == 'daytextshort') {
3288 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
3289 } elseif ($format == 'dayhour') {
3290 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
3291 } elseif ($format == 'dayhoursec') {
3292 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
3293 } elseif ($format == 'dayhourtext') {
3294 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
3295 } elseif ($format == 'dayhourtextshort') {
3296 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
3297 } elseif ($format == 'dayhourlog') {
3298 // Format not sensitive to language
3299 $format = '%Y%m%d%H%M%S';
3300 } elseif ($format == 'dayhourlogsmall') {
3301 // Format not sensitive to language
3302 $format = '%y%m%d%H%M';
3303 } elseif ($format == 'dayhourldap') {
3304 $format = '%Y%m%d%H%M%SZ';
3305 } elseif ($format == 'dayhourxcard') {
3306 $format = '%Y%m%dT%H%M%SZ';
3307 } elseif ($format == 'dayxcard') {
3308 $format = '%Y%m%d';
3309 } elseif ($format == 'dayrfc') {
3310 $format = '%Y-%m-%d'; // DATE_RFC3339
3311 } elseif ($format == 'dayhourrfc') {
3312 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
3313 } elseif ($format == 'standard') {
3314 $format = '%Y-%m-%d %H:%M:%S';
3315 }
3316
3317 if ($reduceformat) {
3318 $format = str_replace('%Y', '%y', $format);
3319 $format = str_replace('yyyy', 'yy', $format);
3320 }
3321
3322 // Clean format
3323 if (preg_match('/%b/i', $format)) { // There is some text to translate
3324 // We inhibit translation to text made by strftime functions. We will use trans instead later.
3325 $format = str_replace('%b', '__b__', $format);
3326 $format = str_replace('%B', '__B__', $format);
3327 }
3328 if (preg_match('/%a/i', $format)) { // There is some text to translate
3329 // We inhibit translation to text made by strftime functions. We will use trans instead later.
3330 $format = str_replace('%a', '__a__', $format);
3331 $format = str_replace('%A', '__A__', $format);
3332 }
3333
3334 // Analyze date
3335 $reg = array();
3336 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', (string) $time, $reg)) { // Deprecated. Ex: 1970-01-01, 1970-01-01 01:00:00, 19700101010000
3337 dol_print_error(null, "Functions.lib::dol_print_date function called with a bad value from page ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]));
3338 return '';
3339 } elseif (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?/i', (string) $time, $reg)) { // Still available to solve problems in extrafields of type date
3340 // This part of code should not be used anymore.
3341 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);
3342 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
3343 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
3344 $syear = (!empty($reg[1]) ? $reg[1] : '');
3345 $smonth = (!empty($reg[2]) ? $reg[2] : '');
3346 $sday = (!empty($reg[3]) ? $reg[3] : '');
3347 $shour = (!empty($reg[4]) ? $reg[4] : '');
3348 $smin = (!empty($reg[5]) ? $reg[5] : '');
3349 $ssec = (!empty($reg[6]) ? $reg[6] : '');
3350
3351 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
3352
3353 if ($to_gmt) {
3354 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
3355 } else {
3356 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
3357 }
3358 $dtts = new DateTime();
3359 $dtts->setTimestamp($time);
3360 $dtts->setTimezone($tzo);
3361 $newformat = str_replace(
3362 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
3363 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
3364 $format
3365 );
3366 $ret = $dtts->format($newformat);
3367 $ret = str_replace(
3368 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
3369 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
3370 $ret
3371 );
3372 } else {
3373 // Date is a timestamps
3374 if ($time < 100000000000) { // Protection against bad date values
3375 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
3376
3377 if ($to_gmt) {
3378 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
3379 } else {
3380 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
3381 }
3382 $dtts = new DateTime();
3383 $dtts->setTimestamp($timetouse);
3384 $dtts->setTimezone($tzo);
3385 $newformat = str_replace(
3386 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
3387 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
3388 $format
3389 );
3390 $ret = $dtts->format($newformat);
3391 $ret = str_replace(
3392 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
3393 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
3394 $ret
3395 );
3396 //var_dump($ret);exit;
3397 } else {
3398 $ret = 'Bad value '.$time.' for date';
3399 }
3400 }
3401
3402 if (preg_match('/__b__/i', $format)) {
3403 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
3404
3405 if ($to_gmt) {
3406 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
3407 } else {
3408 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
3409 }
3410 $dtts = new DateTime();
3411 $dtts->setTimestamp($timetouse);
3412 $dtts->setTimezone($tzo);
3413 $month = (int) $dtts->format("m");
3414 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
3415 if ($encodetooutput) {
3416 $monthtext = $outputlangs->transnoentities('Month'.$month);
3417 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
3418 } else {
3419 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
3420 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
3421 }
3422 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
3423 $ret = str_replace('__b__', $monthtextshort, $ret);
3424 $ret = str_replace('__B__', $monthtext, $ret);
3425 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
3426 //return $ret;
3427 }
3428 if (preg_match('/__a__/i', $format)) {
3429 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
3430 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
3431
3432 if ($to_gmt) {
3433 $tzo = new DateTimeZone('UTC');
3434 } else {
3435 $tzo = new DateTimeZone(date_default_timezone_get());
3436 }
3437 $dtts = new DateTime();
3438 $dtts->setTimestamp($timetouse);
3439 $dtts->setTimezone($tzo);
3440 $w = $dtts->format("w");
3441 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
3442
3443 $ret = str_replace('__A__', $dayweek, $ret);
3444 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
3445 }
3446
3447 return $ret;
3448}
3449
3450
3471function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
3472{
3473 if ($timestamp === '') {
3474 return array();
3475 }
3476
3477 $datetimeobj = new DateTime();
3478 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
3479 if ($forcetimezone) {
3480 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
3481 }
3482 $arrayinfo = array(
3483 'year' => ((int) date_format($datetimeobj, 'Y')),
3484 'mon' => ((int) date_format($datetimeobj, 'm')),
3485 'mday' => ((int) date_format($datetimeobj, 'd')),
3486 'wday' => ((int) date_format($datetimeobj, 'w')),
3487 'yday' => ((int) date_format($datetimeobj, 'z')),
3488 'hours' => ((int) date_format($datetimeobj, 'H')),
3489 'minutes' => ((int) date_format($datetimeobj, 'i')),
3490 'seconds' => ((int) date_format($datetimeobj, 's')),
3491 '0' => $timestamp
3492 );
3493
3494 return $arrayinfo;
3495}
3496
3518function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3519{
3520 global $conf;
3521 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3522
3523 if ($gm === 'auto') {
3524 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3525 }
3526 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3527
3528 // Clean parameters
3529 if ($hour == -1 || empty($hour)) {
3530 $hour = 0;
3531 }
3532 if ($minute == -1 || empty($minute)) {
3533 $minute = 0;
3534 }
3535 if ($second == -1 || empty($second)) {
3536 $second = 0;
3537 }
3538
3539 // Check parameters
3540 if ($check) {
3541 if (!$month || !$day) {
3542 return '';
3543 }
3544 if ($day > 31) {
3545 return '';
3546 }
3547 if ($month > 12) {
3548 return '';
3549 }
3550 if ($hour < 0 || $hour > 24) {
3551 return '';
3552 }
3553 if ($minute < 0 || $minute > 60) {
3554 return '';
3555 }
3556 if ($second < 0 || $second > 60) {
3557 return '';
3558 }
3559 }
3560
3561 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3562 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3563 $localtz = new DateTimeZone($default_timezone);
3564 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3565 // We use dol_tz_string first because it is more reliable.
3566 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3567 try {
3568 $localtz = new DateTimeZone($default_timezone);
3569 } catch (Exception $e) {
3570 dol_syslog("Warning dol_tz_string contains an invalid value ".json_encode($_SESSION["dol_tz_string"] ?? null), LOG_WARNING);
3571 $default_timezone = @date_default_timezone_get();
3572 }
3573 } elseif (strrpos($gm, "tz,") !== false) {
3574 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3575 try {
3576 $localtz = new DateTimeZone($timezone);
3577 } catch (Exception $e) {
3578 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3579 }
3580 }
3581
3582 if (empty($localtz)) {
3583 $localtz = new DateTimeZone('UTC');
3584 }
3585 //var_dump($localtz);
3586 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3587 $dt = new DateTime('now', $localtz);
3588 $dt->setDate((int) $year, (int) $month, (int) $day);
3589 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3590 $date = $dt->getTimestamp(); // should include daylight saving time
3591 //var_dump($date);
3592 return $date;
3593}
3594
3595
3606function dol_now($mode = 'auto')
3607{
3608 $ret = 0;
3609
3610 if ($mode === 'auto') {
3611 $mode = 'gmt';
3612 }
3613
3614 if ($mode == 'gmt') {
3615 $ret = time(); // Time for now at greenwich.
3616 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3617 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3618 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3619 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3620 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3621 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3622 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3623 // $ret=dol_now('gmt')+($tzsecond*3600);
3624 //}
3625 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3626 // Time for now with user timezone added
3627 //print 'time: '.time();
3628 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3629 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3630 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3631 }
3632
3633 return $ret;
3634}
3635
3636
3645function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3646{
3647 global $conf, $langs;
3648 $level = 1024;
3649
3650 if (!empty($conf->dol_optimize_smallscreen)) {
3651 $shortunit = 1;
3652 }
3653
3654 // Set value text
3655 if (empty($shortvalue) || $size < ($level * 10)) {
3656 $ret = $size;
3657 $textunitshort = $langs->trans("b");
3658 $textunitlong = $langs->trans("Bytes");
3659 } else {
3660 $ret = round($size / $level, 0);
3661 $textunitshort = $langs->trans("Kb");
3662 $textunitlong = $langs->trans("KiloBytes");
3663 }
3664 // Use long or short text unit
3665 if (empty($shortunit)) {
3666 $ret .= ' '.$textunitlong;
3667 } else {
3668 $ret .= ' '.$textunitshort;
3669 }
3670
3671 return $ret;
3672}
3673
3684function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = '')
3685{
3686 global $langs;
3687
3688 if (empty($url)) {
3689 return '';
3690 }
3691
3692 $linkstart = '<a href="';
3693 if (!preg_match('/^http/i', $url)) {
3694 $linkstart .= 'http://';
3695 }
3696 $linkstart .= $url;
3697 $linkstart .= '"';
3698 if ($target) {
3699 $linkstart .= ' target="'.$target.'"';
3700 }
3701 $linkstart .= ' title="'.$langs->trans("URL").': '.$url.'"';
3702 $linkstart .= '>';
3703
3704 $link = '';
3705 if (!preg_match('/^http/i', $url)) {
3706 $link .= 'http://';
3707 }
3708 $link .= dol_trunc($url, $max);
3709
3710 $linkend = '</a>';
3711
3712 if ($morecss == 'float') { // deprecated
3713 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto($langs->trans("Url"), 'globe', 'class="paddingrightonly"') : '').$link.'</div>';
3714 } else {
3715 return $linkstart.'<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto('', 'globe', 'class="paddingrightonly"') : '').$link.'</span>'.$linkend;
3716 }
3717}
3718
3731function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3732{
3733 global $user, $langs, $hookmanager;
3734
3735 //global $conf; $conf->global->AGENDA_ADDACTIONFOREMAIL = 1;
3736 //$showinvalid = 1; $email = 'rrrrr';
3737
3738 $newemail = dol_escape_htmltag($email);
3739
3740 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && $withpicto) {
3741 $withpicto = 0;
3742 }
3743
3744 if (empty($email)) {
3745 return '&nbsp;';
3746 }
3747
3748 if (!empty($addlink)) {
3749 $newemail = '<a class="paddingrightonly" style="text-overflow: ellipsis;" href="';
3750 if (!preg_match('/^mailto:/i', $email)) {
3751 $newemail .= 'mailto:';
3752 }
3753 $newemail .= $email;
3754 $newemail .= '">';
3755
3756 $newemail .= ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '');
3757
3758 $newemail .= dol_trunc($email, $max);
3759 $newemail .= '</a>';
3760 if ($showinvalid && !isValidEmail($email)) {
3761 $langs->load("errors");
3762 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email), '', 'paddingrightonly');
3763 }
3764
3765 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3766 $type = 'AC_EMAIL';
3767 $linktoaddaction = '';
3768 if (getDolGlobalString('AGENDA_ADDACTIONFOREMAIL')) {
3769 $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>';
3770 }
3771 if ($linktoaddaction) {
3772 $newemail = '<div>'.$newemail.' '.$linktoaddaction.'</div>';
3773 }
3774 }
3775 } else {
3776 $newemail = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3777
3778 if ($showinvalid && !isValidEmail($email)) {
3779 $langs->load("errors");
3780 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3781 }
3782 }
3783
3784 //$rep = '<div class="nospan" style="margin-right: 10px">';
3785 //$rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3786 //$rep .= '</div>';
3787 $rep = $newemail;
3788
3789 if ($hookmanager) {
3790 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3791
3792 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3793 if ($reshook > 0) {
3794 $rep = '';
3795 }
3796 $rep .= $hookmanager->resPrint;
3797 }
3798
3799 return $rep;
3800}
3801
3807function getArrayOfSocialNetworks()
3808{
3809 global $conf, $db;
3810
3811 $socialnetworks = array();
3812 // Enable caching of array
3813 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3814 $cachekey = 'socialnetworks_' . $conf->entity;
3815 $dataretrieved = dol_getcache($cachekey);
3816 if (!is_null($dataretrieved)) {
3817 $socialnetworks = $dataretrieved;
3818 } else {
3819 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3820 $sql .= " WHERE entity=".$conf->entity;
3821 $resql = $db->query($sql);
3822 if ($resql) {
3823 while ($obj = $db->fetch_object($resql)) {
3824 $socialnetworks[$obj->code] = array(
3825 'rowid' => $obj->rowid,
3826 'label' => $obj->label,
3827 'url' => $obj->url,
3828 'icon' => $obj->icon,
3829 'active' => $obj->active,
3830 );
3831 }
3832 }
3833 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3834 }
3835 return $socialnetworks;
3836}
3837
3848function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3849{
3850 global $user, $langs;
3851
3852 $htmllink = $value;
3853
3854 if (empty($value)) {
3855 return '&nbsp;';
3856 }
3857
3858 if (!empty($type)) {
3859 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3860 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3861 $htmllink .= '<span class="fab pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3862 if ($type == 'skype') {
3863 $htmllink .= dol_escape_htmltag($value);
3864 $htmllink .= '&nbsp; <a href="skype:';
3865 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3866 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3867 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3868 $htmllink .= '</a><a href="skype:';
3869 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3870 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3871 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3872 $htmllink .= '</a>';
3873 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3874 $addlink = 'AC_SKYPE';
3875 $link = '';
3876 if (getDolGlobalString('AGENDA_ADDACTIONFORSKYPE')) {
3877 $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>';
3878 }
3879 $htmllink .= ($link ? ' '.$link : '');
3880 }
3881 } else {
3882 $networkconstname = 'MAIN_INFO_SOCIETE_'.strtoupper($type).'_URL';
3883 if (getDolGlobalString($networkconstname)) {
3884 $link = str_replace('{socialid}', $value, getDolGlobalString($networkconstname));
3885 if (preg_match('/^https?:\/\//i', $link)) {
3886 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3887 } else {
3888 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3889 }
3890 } elseif (!empty($dictsocialnetworks[$type]['url'])) {
3891 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3892 if ($tmpvirginurl) {
3893 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3894 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3895
3896 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3897 if ($tmpvirginurl3) {
3898 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3899 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3900 }
3901
3902 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3903 if ($tmpvirginurl2) {
3904 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3905 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3906 }
3907 }
3908 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3909 if (preg_match('/^https?:\/\//i', $link)) {
3910 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3911 } else {
3912 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3913 }
3914 } else {
3915 $htmllink .= dol_escape_htmltag($value);
3916 }
3917 }
3918 $htmllink .= '</div>';
3919 } else {
3920 $langs->load("errors");
3921 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3922 }
3923 return $htmllink;
3924}
3925
3935function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1)
3936{
3937 global $mysoc;
3938
3939 if (empty($profID) || empty($profIDtype)) {
3940 return '';
3941 }
3942 if (empty($countrycode)) {
3943 $countrycode = $mysoc->country_code;
3944 }
3945 $newProfID = $profID;
3946 $id = substr($profIDtype, -1);
3947 $ret = '';
3948 if (strtoupper($countrycode) == 'FR') {
3949 // France
3950 // (see https://www.economie.gouv.fr/entreprises/numeros-identification-entreprise)
3951
3952 if ($id == 1 && dol_strlen($newProfID) == 9) {
3953 // SIREN (ex: 123 123 123)
3954 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3);
3955 }
3956 if ($id == 2 && dol_strlen($newProfID) == 14) {
3957 // SIRET (ex: 123 123 123 12345)
3958 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3).' '.substr($newProfID, 9, 5);
3959 }
3960 if ($id == 3 && dol_strlen($newProfID) == 5) {
3961 // NAF/APE (ex: 69.20Z)
3962 $newProfID = substr($newProfID, 0, 2).'.'.substr($newProfID, 2, 3);
3963 }
3964 if ($profIDtype === 'VAT' && dol_strlen($newProfID) == 13) {
3965 // TVA intracommunautaire (ex: FR12 123 123 123)
3966 $newProfID = substr($newProfID, 0, 4).' '.substr($newProfID, 4, 3).' '.substr($newProfID, 7, 3).' '.substr($newProfID, 10, 3);
3967 }
3968 }
3969 if (!empty($addcpButton)) {
3970 $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3971 } else {
3972 $ret = $newProfID;
3973 }
3974 return $ret;
3975}
3976
3992function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0, $morecss = '')
3993{
3994 global $conf, $user, $langs, $mysoc, $hookmanager;
3995
3996 // Clean phone parameter
3997 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
3998 if (empty($phone)) {
3999 return '';
4000 }
4001 if (getDolGlobalString('MAIN_PHONE_SEPAR')) {
4002 $separ = getDolGlobalString('MAIN_PHONE_SEPAR');
4003 }
4004 if (empty($countrycode) && is_object($mysoc)) {
4005 $countrycode = $mysoc->country_code;
4006 }
4007
4008 // Short format for small screens
4009 if (!empty($conf->dol_optimize_smallscreen) && $separ != 'hidenum') {
4010 $separ = '';
4011 }
4012
4013 $newphone = $phone;
4014 $newphonewa = $phone;
4015 if (strtoupper($countrycode) == "FR") {
4016 // France
4017 if (dol_strlen($phone) == 10) {
4018 $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);
4019 } elseif (dol_strlen($phone) == 7) {
4020 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
4021 } elseif (dol_strlen($phone) == 9) {
4022 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
4023 } elseif (dol_strlen($phone) == 11) {
4024 $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);
4025 } elseif (dol_strlen($phone) == 12) {
4026 $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);
4027 } elseif (dol_strlen($phone) == 13) {
4028 $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);
4029 }
4030 } elseif (strtoupper($countrycode) == "CA") {
4031 if (dol_strlen($phone) == 10) {
4032 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
4033 }
4034 } elseif (strtoupper($countrycode) == "PT") {//Portugal
4035 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
4036 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
4037 }
4038 } elseif (strtoupper($countrycode) == "SR") {//Suriname
4039 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
4040 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
4041 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
4042 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
4043 }
4044 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
4045 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
4046 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
4047 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
4048 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
4049 }
4050 } elseif (strtoupper($countrycode) == "ES") {//Espagne
4051 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
4052 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
4053 }
4054 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
4055 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
4056 $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);
4057 }
4058 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
4059 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
4060 $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);
4061 }
4062 } elseif (strtoupper($countrycode) == "TR") {//Turquie
4063 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
4064 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
4065 }
4066 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
4067 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
4068 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
4069 }
4070 } elseif (strtoupper($countrycode) == "MX") {//Mexique
4071 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
4072 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
4073 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
4074 $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);
4075 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
4076 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
4077 }
4078 } elseif (strtoupper($countrycode) == "ML") {//Mali
4079 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
4080 $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);
4081 }
4082 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
4083 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
4084 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
4085 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
4086 $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);
4087 }
4088 } elseif (strtoupper($countrycode) == "MU") {
4089 //Maurice
4090 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
4091 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
4092 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
4093 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
4094 }
4095 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
4096 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
4097 $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);
4098 }
4099 } elseif (strtoupper($countrycode) == "SY") {//Syrie
4100 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
4101 $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);
4102 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
4103 $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);
4104 }
4105 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
4106 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
4107 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
4108 } elseif (dol_strlen($phone) == 13) {//ex: +971_ABC_DEF_GHI
4109 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
4110 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
4111 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
4112 }
4113 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
4114 if (dol_strlen($phone) == 13) {//ex: +213_ABC_DEF_GHI
4115 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
4116 }
4117 } elseif (strtoupper($countrycode) == "BE") {//Belgique
4118 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
4119 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
4120 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
4121 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
4122 }
4123 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
4124 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
4125 $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);
4126 }
4127 } elseif (strtoupper($countrycode) == "CO") {//Colombie
4128 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
4129 $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);
4130 }
4131 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
4132 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
4133 $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);
4134 }
4135 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
4136 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
4137 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
4138 }
4139 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
4140 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
4141 $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);
4142 }
4143 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
4144 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
4145 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
4146 }
4147 } elseif (strtoupper($countrycode) == "CH") {//Suisse
4148 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
4149 $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);
4150 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
4151 $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);
4152 }
4153 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
4154 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
4155 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
4156 }
4157 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
4158 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
4159 $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);
4160 }
4161 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
4162 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
4163 $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);
4164 }
4165 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
4166 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
4167 $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);
4168 }
4169 } elseif (strtoupper($countrycode) == "IT") {//Italie
4170 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
4171 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
4172 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
4173 $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);
4174 }
4175 } elseif (strtoupper($countrycode) == "AU") {
4176 //Australie
4177 if (dol_strlen($phone) == 12) {
4178 //ex: +61_A_BCDE_FGHI
4179 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
4180 }
4181 } elseif (strtoupper($countrycode) == "LU") {
4182 // Luxembourg
4183 if (dol_strlen($phone) == 10) {// fix 6 digits +352_AA_BB_CC
4184 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
4185 } elseif (dol_strlen($phone) == 11) {// fix 7 digits +352_AA_BB_CC_D
4186 $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);
4187 } elseif (dol_strlen($phone) == 12) {// fix 8 digits +352_AA_BB_CC_DD
4188 $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);
4189 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
4190 $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);
4191 }
4192 } elseif (strtoupper($countrycode) == "PE") {
4193 // Peru
4194 if (dol_strlen($phone) == 7) {// fix 7 chiffres without code AAA_BBBB
4195 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4);
4196 } elseif (dol_strlen($phone) == 9) {// mobile add code and fix 9 chiffres +51_AAA_BBB_CCC
4197 $newphonewa = '+51'.$newphone;
4198 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 10, 3);
4199 } elseif (dol_strlen($phone) == 11) {// fix 11 chiffres +511_AAA_BBBB
4200 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 8, 4);
4201 } elseif (dol_strlen($phone) == 12) {// mobile +51_AAA_BBB_CCC
4202 $newphonewa = $newphone;
4203 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 10, 3).$separ.substr($newphone, 14, 3);
4204 }
4205 }
4206
4207 $newphoneastart = $newphoneaend = '';
4208 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
4209 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
4210 $newphoneastart = '<a href="tel:'.urlencode($phone).'">';
4211 $newphoneaend .= '</a>';
4212 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
4213 if (empty($user->clicktodial_loaded)) {
4214 $user->fetch_clicktodial();
4215 }
4216
4217 // Define urlmask
4218 $urlmask = getDolGlobalString('CLICKTODIAL_URL', 'ErrorClickToDialModuleNotConfigured');
4219 if (!empty($user->clicktodial_url)) {
4220 $urlmask = $user->clicktodial_url;
4221 }
4222
4223 $clicktodial_poste = (!empty($user->clicktodial_poste) ? urlencode($user->clicktodial_poste) : '');
4224 $clicktodial_login = (!empty($user->clicktodial_login) ? urlencode($user->clicktodial_login) : '');
4225 $clicktodial_password = (!empty($user->clicktodial_password) ? urlencode($user->clicktodial_password) : '');
4226 // This line is for backward compatibility @phan-suppress-next-line PhanPluginPrintfVariableFormatString
4227 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
4228 // Those lines are for substitution
4229 $substitarray = array('__PHONEFROM__' => $clicktodial_poste,
4230 '__PHONETO__' => urlencode($phone),
4231 '__LOGIN__' => $clicktodial_login,
4232 '__PASS__' => $clicktodial_password);
4233 $url = make_substitutions($url, $substitarray);
4234 if (!getDolGlobalString('CLICKTODIAL_DO_NOT_USE_AJAX_CALL')) {
4235 // Default and recommended: New method using ajax without submitting a page making a javascript history.go(-1) back
4236 $newphoneastart = '<a href="'.$url.'" class="cssforclicktodial">'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
4237 $newphoneaend = '</a>';
4238 } else {
4239 // Old method
4240 $newphoneastart = '<a href="'.$url.'"';
4241 if (getDolGlobalString('CLICKTODIAL_FORCENEWTARGET')) {
4242 $newphoneastart .= ' target="_blank" rel="noopener noreferrer"';
4243 }
4244 $newphoneastart .= '>';
4245 $newphoneaend .= '</a>';
4246 }
4247 }
4248
4249 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
4250 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
4251 $type = 'AC_TEL';
4252 $addlinktoagenda = '';
4253 if ($addlink == 'AC_FAX') {
4254 $type = 'AC_FAX';
4255 }
4256 if (getDolGlobalString('AGENDA_ADDACTIONFORPHONE')) {
4257 $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>';
4258 }
4259 if ($addlinktoagenda) {
4260 $newphone = '<span>'.$newphone.' '.$addlinktoagenda.'</span>';
4261 }
4262 }
4263 }
4264
4265 if (getDolGlobalString('CONTACT_PHONEMOBILE_SHOW_LINK_TO_WHATSAPP') && $withpicto == 'mobile') {
4266 // Link to Whatsapp
4267 $newphone .= ' <a href="https://wa.me/'.$newphonewa.'" target="_blank"';// Use api to whatasapp contacts
4268 $newphone .= '><span class="paddingright fab fa-whatsapp" style="color:#25D366;" title="WhatsApp"></span></a>';
4269 }
4270
4271 if (empty($titlealt)) {
4272 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
4273 }
4274 $rep = '';
4275
4276 if ($hookmanager) {
4277 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
4278 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
4279 $rep .= $hookmanager->resPrint;
4280 }
4281 if (empty($reshook)) {
4282 $picto = '';
4283 if ($withpicto) {
4284 if ($withpicto == 'fax') {
4285 $picto = 'phoning_fax';
4286 } elseif ($withpicto == 'phone') {
4287 $picto = 'phoning';
4288 } elseif ($withpicto == 'mobile') {
4289 $picto = 'phoning_mobile';
4290 } else {
4291 $picto = '';
4292 }
4293 }
4294 if ($adddivfloat == 1) {
4295 $rep .= '<div class="nospan float'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">';
4296 } elseif (empty($adddivfloat)) {
4297 $rep .= '<span'.($morecss ? ' class="'.$morecss.'"' : '').' style="margin-right: 10px;">';
4298 }
4299
4300 $rep .= $newphoneastart;
4301 $rep .= ($withpicto ? img_picto($titlealt, 'object_'.$picto.'.png') : '');
4302 if ($separ != 'hidenum') {
4303 $rep .= ($withpicto ? ' ' : '').$newphone;
4304 }
4305 $rep .= $newphoneaend;
4306
4307 if ($adddivfloat == 1) {
4308 $rep .= '</div>';
4309 } elseif (empty($adddivfloat)) {
4310 $rep .= '</span>';
4311 }
4312 }
4313
4314 return $rep;
4315}
4316
4324function dol_print_ip($ip, $mode = 0)
4325{
4326 global $langs;
4327
4328 $ret = '';
4329
4330 if (empty($mode)) {
4331 $ret .= $ip;
4332 }
4333
4334 if ($mode != 2) {
4335 $countrycode = dolGetCountryCodeFromIp($ip);
4336 if ($countrycode) { // If success, countrycode is us, fr, ...
4337 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
4338 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
4339 } else {
4340 $ret .= ' ('.$countrycode.')';
4341 }
4342 } else {
4343 // Nothing
4344 }
4345 }
4346
4347 return $ret;
4348}
4349
4358function getUserRemoteIP()
4359{
4360 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
4361 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
4362 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
4363 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
4364 } else {
4365 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
4366 }
4367 } else {
4368 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
4369 }
4370 } else {
4371 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
4372 }
4373 return $ip;
4374}
4375
4384function isHTTPS()
4385{
4386 $isSecure = false;
4387 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
4388 $isSecure = true;
4389 } 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') {
4390 $isSecure = true;
4391 }
4392 return $isSecure;
4393}
4394
4401function dolGetCountryCodeFromIp($ip)
4402{
4403 global $conf;
4404
4405 $countrycode = '';
4406
4407 if (!empty($conf->geoipmaxmind->enabled)) {
4408 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
4409 //$ip='24.24.24.24';
4410 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
4411 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
4412 $geoip = new DolGeoIP('country', $datafile);
4413 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
4414 $countrycode = $geoip->getCountryCodeFromIP($ip);
4415 }
4416
4417 return $countrycode;
4418}
4419
4420
4427function dol_user_country()
4428{
4429 global $conf, $langs, $user;
4430
4431 //$ret=$user->xxx;
4432 $ret = '';
4433 if (!empty($conf->geoipmaxmind->enabled)) {
4434 $ip = getUserRemoteIP();
4435 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
4436 //$ip='24.24.24.24';
4437 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
4438 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
4439 $geoip = new DolGeoIP('country', $datafile);
4440 $countrycode = $geoip->getCountryCodeFromIP($ip);
4441 $ret = $countrycode;
4442 }
4443 return $ret;
4444}
4445
4458function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
4459{
4460 global $conf, $user, $langs, $hookmanager;
4461
4462 $out = '';
4463
4464 if ($address) {
4465 if ($hookmanager) {
4466 $parameters = array('element' => $element, 'id' => $id);
4467 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
4468 $out .= $hookmanager->resPrint;
4469 }
4470 if (empty($reshook)) {
4471 if (empty($charfornl)) {
4472 $out .= nl2br($address);
4473 } else {
4474 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
4475 }
4476
4477 // TODO Remove this block, we can add this using the hook now
4478 $showgmap = $showomap = 0;
4479 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS')) {
4480 $showgmap = 1;
4481 }
4482 if ($element == 'contact' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_CONTACTS')) {
4483 $showgmap = 1;
4484 }
4485 if ($element == 'member' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_MEMBERS')) {
4486 $showgmap = 1;
4487 }
4488 if ($element == 'user' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_USERS')) {
4489 $showgmap = 1;
4490 }
4491 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS')) {
4492 $showomap = 1;
4493 }
4494 if ($element == 'contact' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_CONTACTS')) {
4495 $showomap = 1;
4496 }
4497 if ($element == 'member' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_MEMBERS')) {
4498 $showomap = 1;
4499 }
4500 if ($element == 'user' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_USERS')) {
4501 $showomap = 1;
4502 }
4503 if ($showgmap) {
4504 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
4505 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4506 }
4507 if ($showomap) {
4508 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
4509 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4510 }
4511 }
4512 }
4513 if ($noprint) {
4514 return $out;
4515 } else {
4516 print $out;
4517 }
4518}
4519
4520
4530function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
4531{
4532 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
4533 return true;
4534 }
4535 if ($acceptuserkey && $address == '__USER_EMAIL__') {
4536 return true;
4537 }
4538 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
4539 return true;
4540 }
4541
4542 return false;
4543}
4544
4554function isValidMXRecord($domain)
4555{
4556 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
4557 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
4558 return 0;
4559 }
4560 if (function_exists('getmxrr')) {
4561 $mxhosts = array();
4562 $weight = array();
4563 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
4564 if (count($mxhosts) > 1) {
4565 return 1;
4566 }
4567 if (count($mxhosts) == 1 && !in_array((string) $mxhosts[0], array('', '.'))) {
4568 return 1;
4569 }
4570
4571 return 0;
4572 }
4573 }
4574
4575 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4576 return -1;
4577}
4578
4586function isValidPhone($phone)
4587{
4588 return true;
4589}
4590
4591
4601function dolGetFirstLetters($s, $nbofchar = 1)
4602{
4603 $ret = '';
4604 $tmparray = explode(' ', $s);
4605 foreach ($tmparray as $tmps) {
4606 $ret .= dol_substr($tmps, 0, $nbofchar);
4607 }
4608
4609 return $ret;
4610}
4611
4612
4620function dol_strlen($string, $stringencoding = 'UTF-8')
4621{
4622 if (is_null($string)) {
4623 return 0;
4624 }
4625
4626 if (function_exists('mb_strlen')) {
4627 return mb_strlen($string, $stringencoding);
4628 } else {
4629 return strlen($string);
4630 }
4631}
4632
4643function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4644{
4645 global $langs;
4646
4647 if (empty($stringencoding)) {
4648 $stringencoding = (empty($langs) ? 'UTF-8' : $langs->charset_output);
4649 }
4650
4651 $ret = '';
4652 if (empty($trunconbytes)) {
4653 if (function_exists('mb_substr')) {
4654 $ret = mb_substr($string, $start, $length, $stringencoding);
4655 } else {
4656 $ret = substr($string, $start, $length);
4657 }
4658 } else {
4659 if (function_exists('mb_strcut')) {
4660 $ret = mb_strcut($string, $start, $length, $stringencoding);
4661 } else {
4662 $ret = substr($string, $start, $length);
4663 }
4664 }
4665 return $ret;
4666}
4667
4668
4682function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4683{
4684 global $conf;
4685
4686 if (empty($size) || getDolGlobalString('MAIN_DISABLE_TRUNC')) {
4687 return $string;
4688 }
4689
4690 if (empty($stringencoding)) {
4691 $stringencoding = 'UTF-8';
4692 }
4693 // reduce for small screen
4694 if (!empty($conf->dol_optimize_smallscreen) && $conf->dol_optimize_smallscreen == 1 && $display == 1) {
4695 $size = round($size / 3);
4696 }
4697
4698 // We go always here
4699 if ($trunc == 'right') {
4700 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4701 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4702 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4703 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4704 } else {
4705 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4706 return $string;
4707 }
4708 } elseif ($trunc == 'middle') {
4709 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4710 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4711 $size1 = round($size / 2);
4712 $size2 = round($size / 2);
4713 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4714 } else {
4715 return $string;
4716 }
4717 } elseif ($trunc == 'left') {
4718 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4719 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4720 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4721 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4722 } else {
4723 return $string;
4724 }
4725 } elseif ($trunc == 'wrap') {
4726 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4727 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4728 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4729 } else {
4730 return $string;
4731 }
4732 } else {
4733 return 'BadParam3CallingDolTrunc';
4734 }
4735}
4736
4744function getPictoForType($key, $morecss = '')
4745{
4746 // Set array with type -> picto
4747 $type2picto = array(
4748 'varchar' => 'font',
4749 'text' => 'font',
4750 'html' => 'code',
4751 'int' => 'sort-numeric-down',
4752 'double' => 'sort-numeric-down',
4753 'price' => 'currency',
4754 'pricecy' => 'multicurrency',
4755 'password' => 'key',
4756 'boolean' => 'check-square',
4757 'date' => 'calendar',
4758 'datetime' => 'calendar',
4759 'phone' => 'phone',
4760 'mail' => 'email',
4761 'url' => 'url',
4762 'ip' => 'country',
4763 'select' => 'list',
4764 'sellist' => 'list',
4765 'radio' => 'check-circle',
4766 'checkbox' => 'list',
4767 'chkbxlst' => 'list',
4768 'link' => 'link',
4769 'icon' => "question",
4770 'point' => "country",
4771 'multipts' => 'country',
4772 'linestrg' => "country",
4773 'polygon' => "country",
4774 'separate' => 'minus'
4775 );
4776
4777 if (!empty($type2picto[$key])) {
4778 return img_picto('', $type2picto[$key], 'class="pictofixedwidth'.($morecss ? ' '.$morecss : '').'"');
4779 }
4780
4781 return img_picto('', 'generic', 'class="pictofixedwidth'.($morecss ? ' '.$morecss : '').'"');
4782}
4783
4784
4806function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4807{
4808 global $conf;
4809
4810 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4811 $url = DOL_URL_ROOT;
4812 $theme = isset($conf->theme) ? $conf->theme : null;
4813 $path = 'theme/'.$theme;
4814 if (empty($picto)) {
4815 $picto = 'generic';
4816 }
4817
4818 // Define fullpathpicto to use into src
4819 if ($pictoisfullpath) {
4820 // Clean parameters
4821 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4822 $picto .= '.png';
4823 }
4824 $fullpathpicto = $picto;
4825 $reg = array();
4826 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4827 $morecss .= ($morecss ? ' ' : '').$reg[1];
4828 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4829 }
4830 } else {
4831 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', (is_null($picto) ? '' : $picto));
4832 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4833 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4834
4835 if (strpos($pictowithouttext, 'fontawesome_') === 0 || strpos($pictowithouttext, 'fa-') === 0) {
4836 // This is a font awesome image 'fontawesome_xxx' or 'fa-xxx'
4837 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4838 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4839
4840 // Compatibility with old fontawesome versions
4841 if ($pictowithouttext == 'file-o') {
4842 $pictowithouttext = 'file';
4843 }
4844
4845 $pictowithouttextarray = explode('_', $pictowithouttext);
4846 $marginleftonlyshort = 0;
4847
4848 if (!empty($pictowithouttextarray[1])) {
4849 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4850 $fakey = 'fa-'.$pictowithouttextarray[0];
4851 $faprefix = empty($pictowithouttextarray[1]) ? 'fas' : $pictowithouttextarray[1];
4852 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4853 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4854 } else {
4855 $fakey = 'fa-'.$pictowithouttext;
4856 $faprefix = 'fas';
4857 $facolor = '';
4858 $fasize = '';
4859 }
4860
4861 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4862 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4863 $morestyle = '';
4864 $reg = array();
4865 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4866 $morecss .= ($morecss ? ' ' : '').$reg[1];
4867 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4868 }
4869 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4870 $morestyle = $reg[1];
4871 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4872 }
4873 $moreatt = trim($moreatt);
4874
4875 $enabledisablehtml = '<span class="'.$faprefix.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4876 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4877 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4878 $enabledisablehtml .= $titlealt;
4879 }*/
4880 $enabledisablehtml .= '</span>';
4881
4882 return $enabledisablehtml;
4883 }
4884
4885 if (empty($srconly) && in_array($pictowithouttext, array(
4886 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4887 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'ai', 'angle-double-down', 'angle-double-up', 'asset',
4888 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bom', 'bookcal', 'bookmark', 'briefcase-medical', 'bug', 'building',
4889 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4890 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'code', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4891 'check-circle', 'check-square', 'circle', 'stop-circle', 'currency', 'multicurrency',
4892 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top',
4893 'chevron-double-left', 'chevron-double-right', 'chevron-double-down', 'chevron-double-top',
4894 'commercial', 'companies',
4895 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4896 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4897 'filter', 'file', 'file-o', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus', 'font',
4898 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4899 'hands-helping', 'help', 'holiday',
4900 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4901 'key', 'knowledgemanagement',
4902 'label', 'language', 'layout', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4903 'margin', 'map-marker-alt', 'member', 'meeting', 'minus', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4904 'off', 'on', 'order',
4905 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4906 'stock', 'resize', 'service', 'stats',
4907 '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',
4908 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4909 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4910 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4911 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4912 'technic', 'ticket',
4913 'error', 'warning',
4914 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4915 'shapes', 'skill', 'square', 'sort-numeric-down', 'status', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4916 'terminal', 'tick', 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda', 'trip',
4917 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4918 'conferenceorbooth', 'eventorganization',
4919 'stamp', 'signature',
4920 'webportal'
4921 ))) {
4922 $fakey = $pictowithouttext;
4923 $facolor = '';
4924 $fasize = '';
4925 $fa = getDolGlobalString('MAIN_FONTAWESOME_ICON_STYLE', 'fas');
4926 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'))) {
4927 $fa = 'far';
4928 }
4929 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4930 $fa = 'fab';
4931 }
4932
4933 $arrayconvpictotofa = array(
4934 'account' => 'university', 'accounting_account' => 'clipboard-list', 'accountline' => 'receipt', 'accountancy' => 'search-dollar', 'action' => 'calendar-alt', 'add' => 'plus-circle', 'address' => 'address-book', 'ai' => 'magic',
4935 'asset' => 'money-check-alt', 'autofill' => 'fill',
4936 'bank_account' => 'university',
4937 'bill' => 'file-invoice-dollar', 'billa' => 'file-excel', 'billr' => 'file-invoice-dollar', 'billd' => 'file-medical',
4938 'bookcal' => 'calendar-check',
4939 'supplier_invoice' => 'file-invoice-dollar', 'supplier_invoicea' => 'file-excel', 'supplier_invoicer' => 'file-invoice-dollar', 'supplier_invoiced' => 'file-medical',
4940 'bom' => 'shapes',
4941 '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',
4942 'chevron-double-left' => 'angle-double-left', 'chevron-double-right' => 'angle-double-right', 'chevron-double-down' => 'angle-double-down', 'chevron-double-top' => 'angle-double-up',
4943 'donation' => 'file-alt', 'dynamicprice' => 'hand-holding-usd',
4944 'setup' => 'cog', 'companies' => 'building', 'products' => 'cube', 'commercial' => 'suitcase', 'invoicing' => 'coins',
4945 'accounting' => 'search-dollar', 'category' => 'tag', 'dollyrevert' => 'dolly',
4946 'file-o' => 'file', 'generate' => 'plus-square', 'hrm' => 'user-tie', 'incoterm' => 'truck-loading',
4947 'margin' => 'calculator', 'members' => 'user-friends', 'ticket' => 'ticket-alt', 'globe' => 'external-link-alt', 'lot' => 'barcode',
4948 'email' => 'at', 'establishment' => 'building', 'edit' => 'pencil-alt', 'entity' => 'globe',
4949 'graph' => 'chart-line', 'grip_title' => 'arrows-alt', 'grip' => 'arrows-alt', 'help' => 'question-circle',
4950 'generic' => 'file', 'holiday' => 'umbrella-beach',
4951 'info' => 'info-circle', 'inventory' => 'boxes', 'intracommreport' => 'globe-europe', 'jobprofile' => 'cogs',
4952 'knowledgemanagement' => 'ticket-alt', 'label' => 'layer-group', 'layout' => 'columns', 'line' => 'bars', 'loan' => 'money-bill-alt',
4953 'member' => 'user-alt', 'meeting' => 'chalkboard-teacher', 'mrp' => 'cubes', 'next' => 'arrow-alt-circle-right',
4954 'trip' => 'wallet', 'expensereport' => 'wallet', 'group' => 'users', 'movement' => 'people-carry',
4955 'sign-out' => 'sign-out-alt',
4956 'switch_off' => 'toggle-off', 'switch_on' => 'toggle-on', 'switch_on_warning' => 'toggle-on', 'switch_on_red' => 'toggle-on', 'check' => 'check', 'bookmark' => 'star',
4957 'bank' => 'university', 'close_title' => 'times', 'delete' => 'trash', 'filter' => 'filter',
4958 'list-alt' => 'list-alt', 'calendarlist' => 'bars', 'calendar' => 'calendar-alt', 'calendarmonth' => 'calendar-alt', 'calendarweek' => 'calendar-week', 'calendarday' => 'calendar-day', 'calendarperuser' => 'table',
4959 'intervention' => 'ambulance', 'invoice' => 'file-invoice-dollar', 'order' => 'file-invoice',
4960 'error' => 'exclamation-triangle', 'warning' => 'exclamation-triangle',
4961 'other' => 'square',
4962 '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',
4963 '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',
4964 'recent' => 'check-square', 'reception' => 'dolly', 'recruitmentjobposition' => 'id-card-alt', 'recruitmentcandidature' => 'id-badge',
4965 'resize' => 'crop', 'supplier_order' => 'dol-order_supplier', 'supplier_proposal' => 'file-signature',
4966 'refresh' => 'redo', 'region' => 'map-marked', 'replacement' => 'exchange-alt', 'resource' => 'laptop-house', 'recurring' => 'history',
4967 'service' => 'concierge-bell',
4968 'skill' => 'shapes', 'state' => 'map-marked-alt', 'security' => 'key', 'salary' => 'wallet', 'shipment' => 'dolly', 'stock' => 'box-open', 'stats' => 'chart-bar', 'split' => 'code-branch',
4969 'status' => 'stop-circle',
4970 'stripe' => 'stripe-s', 'supplier' => 'building',
4971 'technic' => 'cogs', 'tick' => 'check', 'timespent' => 'clock', 'title_setup' => 'tools', 'title_accountancy' => 'money-check-alt', 'title_bank' => 'university', 'title_hrm' => 'umbrella-beach',
4972 'title_agenda' => 'calendar-alt',
4973 'uncheck' => 'times', 'uparrow' => 'share', 'url' => 'external-link-alt', 'vat' => 'money-check-alt', 'vcard' => 'arrow-alt-circle-down',
4974 'jabber' => 'comment-o',
4975 'website' => 'globe-americas', 'workstation' => 'pallet', 'webhook' => 'bullseye', 'world' => 'globe', 'private' => 'user-lock',
4976 'conferenceorbooth' => 'chalkboard-teacher', 'eventorganization' => 'project-diagram',
4977 'webportal' => 'door-open'
4978 );
4979 if ($conf->currency == 'EUR') {
4980 $arrayconvpictotofa['currency'] = 'euro-sign';
4981 $arrayconvpictotofa['multicurrency'] = 'dollar-sign';
4982 } else {
4983 $arrayconvpictotofa['currency'] = 'dollar-sign';
4984 $arrayconvpictotofa['multicurrency'] = 'euro-sign';
4985 }
4986 if ($pictowithouttext == 'off') {
4987 $fakey = 'fa-square';
4988 $fasize = '1.3em';
4989 } elseif ($pictowithouttext == 'on') {
4990 $fakey = 'fa-check-square';
4991 $fasize = '1.3em';
4992 } elseif ($pictowithouttext == 'listlight') {
4993 $fakey = 'fa-download';
4994 $marginleftonlyshort = 1;
4995 } elseif ($pictowithouttext == 'printer') {
4996 $fakey = 'fa-print';
4997 $fasize = '1.2em';
4998 } elseif ($pictowithouttext == 'note') {
4999 $fakey = 'fa-sticky-note';
5000 $marginleftonlyshort = 1;
5001 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
5002 $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');
5003 $fakey = 'fa-'.$convertarray[$pictowithouttext];
5004 if (preg_match('/selected/', $pictowithouttext)) {
5005 $facolor = '#888';
5006 }
5007 $marginleftonlyshort = 1;
5008 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
5009 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
5010 } else {
5011 $fakey = 'fa-'.$pictowithouttext;
5012 }
5013
5014 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment', 'reception'))) {
5015 $morecss .= ' em092';
5016 }
5017 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
5018 $morecss .= ' em088';
5019 }
5020 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
5021 $morecss .= ' em080';
5022 }
5023
5024 // Define $marginleftonlyshort
5025 $arrayconvpictotomarginleftonly = array(
5026 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
5027 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
5028 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
5029 );
5030 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
5031 $marginleftonlyshort = 0;
5032 }
5033
5034 // Add CSS
5035 $arrayconvpictotomorcess = array(
5036 'action' => 'infobox-action', 'account' => 'infobox-bank_account', 'accounting_account' => 'infobox-bank_account', 'accountline' => 'infobox-bank_account', 'accountancy' => 'infobox-bank_account', 'asset' => 'infobox-bank_account',
5037 'bank_account' => 'infobox-bank_account',
5038 'bill' => 'infobox-commande', 'billa' => 'infobox-commande', 'billr' => 'infobox-commande', 'billd' => 'infobox-commande',
5039 'bookcal' => 'infobox-action',
5040 'margin' => 'infobox-bank_account', 'conferenceorbooth' => 'infobox-project',
5041 'cash-register' => 'infobox-bank_account', 'contract' => 'infobox-contrat', 'check' => 'font-status4', 'collab' => 'infobox-action', 'conversation' => 'infobox-contrat',
5042 'donation' => 'infobox-commande', 'dolly' => 'infobox-commande', 'dollyrevert' => 'flip infobox-order_supplier',
5043 'ecm' => 'infobox-action', 'eventorganization' => 'infobox-project',
5044 'hrm' => 'infobox-adherent', 'group' => 'infobox-adherent', 'intervention' => 'infobox-contrat',
5045 'incoterm' => 'infobox-supplier_proposal',
5046 'currency' => 'infobox-bank_account', 'multicurrency' => 'infobox-bank_account',
5047 'members' => 'infobox-adherent', 'member' => 'infobox-adherent', 'money-bill-alt' => 'infobox-bank_account',
5048 'order' => 'infobox-commande',
5049 'user' => 'infobox-adherent', 'users' => 'infobox-adherent',
5050 'error' => 'pictoerror', 'warning' => 'pictowarning', 'switch_on' => 'font-status4', 'switch_on_warning' => 'font-status4 warning', 'switch_on_red' => 'font-status8',
5051 'holiday' => 'infobox-holiday', 'info' => 'opacityhigh', 'invoice' => 'infobox-commande',
5052 'knowledgemanagement' => 'infobox-contrat rotate90', 'loan' => 'infobox-bank_account',
5053 'payment' => 'infobox-bank_account', 'payment_vat' => 'infobox-bank_account', 'poll' => 'infobox-adherent', 'pos' => 'infobox-bank_account', 'project' => 'infobox-project', 'projecttask' => 'infobox-project',
5054 'propal' => 'infobox-propal', 'proposal' => 'infobox-propal','private' => 'infobox-project',
5055 'reception' => 'flip infobox-order_supplier', 'recruitmentjobposition' => 'infobox-adherent', 'recruitmentcandidature' => 'infobox-adherent',
5056 'resource' => 'infobox-action',
5057 'salary' => 'infobox-bank_account', 'shapes' => 'infobox-adherent', 'shipment' => 'infobox-commande', 'stripe' => 'infobox-bank_account', 'supplier_invoice' => 'infobox-order_supplier', 'supplier_invoicea' => 'infobox-order_supplier', 'supplier_invoiced' => 'infobox-order_supplier',
5058 'supplier' => 'infobox-order_supplier', 'supplier_order' => 'infobox-order_supplier', 'supplier_proposal' => 'infobox-supplier_proposal',
5059 'ticket' => 'infobox-contrat', 'title_accountancy' => 'infobox-bank_account', 'title_hrm' => 'infobox-holiday', 'expensereport' => 'infobox-expensereport', 'trip' => 'infobox-expensereport', 'title_agenda' => 'infobox-action',
5060 'vat' => 'infobox-bank_account',
5061 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
5062 'list-alt' => 'imgforviewmode', 'calendar' => 'imgforviewmode', 'calendarweek' => 'imgforviewmode', 'calendarmonth' => 'imgforviewmode', 'calendarday' => 'imgforviewmode', 'calendarperuser' => 'imgforviewmode'
5063 );
5064 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
5065 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
5066 }
5067
5068 // Define $color
5069 $arrayconvpictotocolor = array(
5070 'address' => '#6c6aa8', 'building' => '#6c6aa8', 'bom' => '#a69944',
5071 'clone' => '#999', 'cog' => '#999', 'companies' => '#6c6aa8', 'company' => '#6c6aa8', 'contact' => '#6c6aa8', 'cron' => '#555',
5072 'dynamicprice' => '#a69944',
5073 'edit' => '#444', 'note' => '#999', 'error' => '', 'help' => '#bbb', 'listlight' => '#999', 'language' => '#555',
5074 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
5075 'lock' => '#ddd', 'lot' => '#a69944',
5076 'map-marker-alt' => '#aaa', 'mrp' => '#a69944', 'product' => '#a69944', 'service' => '#a69944', 'inventory' => '#a69944', 'stock' => '#a69944', 'movement' => '#a69944',
5077 'other' => '#ddd', 'world' => '#986c6a',
5078 'partnership' => '#6c6aa8', 'playdisabled' => '#ccc', 'printer' => '#444', 'projectpub' => '#986c6a', 'resize' => '#444', 'rss' => '#cba',
5079 //'shipment'=>'#a69944',
5080 'security' => '#999', 'square' => '#888', 'stop-circle' => '#888', 'stats' => '#444', 'switch_off' => '#999',
5081 'technic' => '#999', 'tick' => '#282', 'timespent' => '#555',
5082 'uncheck' => '#800', 'uparrow' => '#555', 'user-cog' => '#999', 'country' => '#aaa', 'globe-americas' => '#aaa', 'region' => '#aaa', 'state' => '#aaa',
5083 'website' => '#304', 'workstation' => '#a69944'
5084 );
5085 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
5086 $facolor = $arrayconvpictotocolor[$pictowithouttext];
5087 }
5088
5089 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
5090 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
5091 $morestyle = '';
5092 $reg = array();
5093 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
5094 $morecss .= ($morecss ? ' ' : '').$reg[1];
5095 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
5096 }
5097 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
5098 $morestyle = $reg[1];
5099 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
5100 }
5101 $moreatt = trim($moreatt);
5102
5103 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
5104 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
5105 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
5106 $enabledisablehtml .= $titlealt;
5107 }*/
5108 $enabledisablehtml .= '</span>';
5109
5110 return $enabledisablehtml;
5111 }
5112
5113 if (getDolGlobalString('MAIN_OVERWRITE_THEME_PATH')) {
5114 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_PATH') . '/theme/'.$theme; // If the theme does not have the same name as the module
5115 } elseif (getDolGlobalString('MAIN_OVERWRITE_THEME_RES')) {
5116 $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
5117 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
5118 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
5119 }
5120
5121 // If we ask an image into $url/$mymodule/img (instead of default path)
5122 $regs = array();
5123 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
5124 $picto = $regs[1];
5125 $path = $regs[2]; // $path is $mymodule
5126 }
5127
5128 // Clean parameters
5129 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
5130 $picto .= '.png';
5131 }
5132 // If alt path are defined, define url where img file is, according to physical path
5133 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
5134 foreach ($conf->file->dol_document_root as $type => $dirroot) {
5135 if ($type == 'main') {
5136 continue;
5137 }
5138 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommended
5139 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
5140 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
5141 break;
5142 }
5143 }
5144
5145 // $url is '' or '/custom', $path is current theme or
5146 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
5147 }
5148
5149 if ($srconly) {
5150 return $fullpathpicto;
5151 }
5152
5153 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
5154 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
5155}
5156
5170function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $srconly = 0, $notitle = 0)
5171{
5172 if (strpos($picto, '^') === 0) {
5173 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
5174 } else {
5175 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
5176 }
5177}
5178
5190function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
5191{
5192 global $conf;
5193
5194 if (is_numeric($picto)) {
5195 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
5196 //$picto = $leveltopicto[$picto];
5197 return '<i class="fa fa-weather-level'.$picto.'"></i>';
5198 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
5199 $picto .= '.png';
5200 }
5201
5202 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
5203
5204 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
5205}
5206
5218function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
5219{
5220 global $conf;
5221
5222 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
5223 $picto .= '.png';
5224 }
5225
5226 if ($pictoisfullpath) {
5227 $path = $picto;
5228 } else {
5229 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
5230
5231 if (getDolGlobalInt('MAIN_MODULE_CAN_OVERWRITE_COMMONICONS')) {
5232 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
5233
5234 if (file_exists($themepath)) {
5235 $path = $themepath;
5236 }
5237 }
5238 }
5239
5240 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
5241}
5242
5256function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
5257{
5258 global $langs;
5259
5260 if (empty($titlealt) || $titlealt == 'default') {
5261 if ($numaction == '-1' || $numaction == 'ST_NO') {
5262 $numaction = -1;
5263 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
5264 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
5265 $numaction = 0;
5266 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
5267 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
5268 $numaction = 1;
5269 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
5270 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
5271 $numaction = 2;
5272 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
5273 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
5274 $numaction = 3;
5275 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
5276 } else {
5277 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
5278 $numaction = 0;
5279 }
5280 }
5281 if (!is_numeric($numaction)) {
5282 $numaction = 0;
5283 }
5284
5285 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
5286}
5287
5295function img_pdf($titlealt = 'default', $size = 3)
5296{
5297 global $langs;
5298
5299 if ($titlealt == 'default') {
5300 $titlealt = $langs->trans('Show');
5301 }
5302
5303 return img_picto($titlealt, 'pdf'.$size.'.png');
5304}
5305
5313function img_edit_add($titlealt = 'default', $other = '')
5314{
5315 global $langs;
5316
5317 if ($titlealt == 'default') {
5318 $titlealt = $langs->trans('Add');
5319 }
5320
5321 return img_picto($titlealt, 'edit_add.png', $other);
5322}
5330function img_edit_remove($titlealt = 'default', $other = '')
5331{
5332 global $langs;
5333
5334 if ($titlealt == 'default') {
5335 $titlealt = $langs->trans('Remove');
5336 }
5337
5338 return img_picto($titlealt, 'edit_remove.png', $other);
5339}
5340
5349function img_edit($titlealt = 'default', $float = 0, $other = '')
5350{
5351 global $langs;
5352
5353 if ($titlealt == 'default') {
5354 $titlealt = $langs->trans('Modify');
5355 }
5356
5357 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
5358}
5359
5368function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
5369{
5370 global $langs;
5371
5372 if ($titlealt == 'default') {
5373 $titlealt = $langs->trans('View');
5374 }
5375
5376 $moreatt = ($float ? 'style="float: right" ' : '').$other;
5377
5378 return img_picto($titlealt, 'eye', $moreatt);
5379}
5380
5389function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
5390{
5391 global $langs;
5392
5393 if ($titlealt == 'default') {
5394 $titlealt = $langs->trans('Delete');
5395 }
5396
5397 return img_picto($titlealt, 'delete.png', $other, 0, 0, 0, '', $morecss);
5398}
5399
5407function img_printer($titlealt = "default", $other = '')
5408{
5409 global $langs;
5410 if ($titlealt == "default") {
5411 $titlealt = $langs->trans("Print");
5412 }
5413 return img_picto($titlealt, 'printer.png', $other);
5414}
5415
5423function img_split($titlealt = 'default', $other = 'class="pictosplit"')
5424{
5425 global $langs;
5426
5427 if ($titlealt == 'default') {
5428 $titlealt = $langs->trans('Split');
5429 }
5430
5431 return img_picto($titlealt, 'split.png', $other);
5432}
5433
5441function img_help($usehelpcursor = 1, $usealttitle = 1)
5442{
5443 global $langs;
5444
5445 if ($usealttitle) {
5446 if (is_string($usealttitle)) {
5447 $usealttitle = dol_escape_htmltag($usealttitle);
5448 } else {
5449 $usealttitle = $langs->trans('Info');
5450 }
5451 }
5452
5453 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
5454}
5455
5462function img_info($titlealt = 'default')
5463{
5464 global $langs;
5465
5466 if ($titlealt == 'default') {
5467 $titlealt = $langs->trans('Informations');
5468 }
5469
5470 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
5471}
5472
5481function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
5482{
5483 global $langs;
5484
5485 if ($titlealt == 'default') {
5486 $titlealt = $langs->trans('Warning');
5487 }
5488
5489 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
5490 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
5491}
5492
5499function img_error($titlealt = 'default')
5500{
5501 global $langs;
5502
5503 if ($titlealt == 'default') {
5504 $titlealt = $langs->trans('Error');
5505 }
5506
5507 return img_picto($titlealt, 'error.png');
5508}
5509
5517function img_next($titlealt = 'default', $moreatt = '')
5518{
5519 global $langs;
5520
5521 if ($titlealt == 'default') {
5522 $titlealt = $langs->trans('Next');
5523 }
5524
5525 //return img_picto($titlealt, 'next.png', $moreatt);
5526 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5527}
5528
5536function img_previous($titlealt = 'default', $moreatt = '')
5537{
5538 global $langs;
5539
5540 if ($titlealt == 'default') {
5541 $titlealt = $langs->trans('Previous');
5542 }
5543
5544 //return img_picto($titlealt, 'previous.png', $moreatt);
5545 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5546}
5547
5556function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
5557{
5558 global $langs;
5559
5560 if ($titlealt == 'default') {
5561 $titlealt = $langs->trans('Down');
5562 }
5563
5564 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
5565}
5566
5575function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
5576{
5577 global $langs;
5578
5579 if ($titlealt == 'default') {
5580 $titlealt = $langs->trans('Up');
5581 }
5582
5583 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
5584}
5585
5594function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
5595{
5596 global $langs;
5597
5598 if ($titlealt == 'default') {
5599 $titlealt = $langs->trans('Left');
5600 }
5601
5602 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
5603}
5604
5613function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
5614{
5615 global $langs;
5616
5617 if ($titlealt == 'default') {
5618 $titlealt = $langs->trans('Right');
5619 }
5620
5621 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
5622}
5623
5631function img_allow($allow, $titlealt = 'default')
5632{
5633 global $langs;
5634
5635 if ($titlealt == 'default') {
5636 $titlealt = $langs->trans('Active');
5637 }
5638
5639 if ($allow == 1) {
5640 return img_picto($titlealt, 'tick.png');
5641 }
5642
5643 return '-';
5644}
5645
5653function img_credit_card($brand, $morecss = null)
5654{
5655 if (is_null($morecss)) {
5656 $morecss = 'fa-2x';
5657 }
5658
5659 if ($brand == 'visa' || $brand == 'Visa') {
5660 $brand = 'cc-visa';
5661 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5662 $brand = 'cc-mastercard';
5663 } elseif ($brand == 'amex' || $brand == 'American Express') {
5664 $brand = 'cc-amex';
5665 } elseif ($brand == 'discover' || $brand == 'Discover') {
5666 $brand = 'cc-discover';
5667 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5668 $brand = 'cc-jcb';
5669 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5670 $brand = 'cc-diners-club';
5671 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5672 $brand = 'credit-card';
5673 }
5674
5675 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5676}
5677
5686function img_mime($file, $titlealt = '', $morecss = '')
5687{
5688 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5689
5690 $mimetype = dol_mimetype($file, '', 1);
5691 $mimeimg = dol_mimetype($file, '', 2);
5692 $mimefa = dol_mimetype($file, '', 4);
5693
5694 if (empty($titlealt)) {
5695 $titlealt = 'Mime type: '.$mimetype;
5696 }
5697
5698 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5699 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5700}
5701
5702
5710function img_search($titlealt = 'default', $other = '')
5711{
5712 global $langs;
5713
5714 if ($titlealt == 'default') {
5715 $titlealt = $langs->trans('Search');
5716 }
5717
5718 $img = img_picto($titlealt, 'search.png', $other, 0, 1);
5719
5720 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5721 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5722
5723 return $input;
5724}
5725
5733function img_searchclear($titlealt = 'default', $other = '')
5734{
5735 global $langs;
5736
5737 if ($titlealt == 'default') {
5738 $titlealt = $langs->trans('Search');
5739 }
5740
5741 $img = img_picto($titlealt, 'searchclear.png', $other, 0, 1);
5742
5743 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5744 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5745
5746 return $input;
5747}
5748
5761function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '', $picto = '')
5762{
5763 global $conf, $langs;
5764
5765 if ($infoonimgalt) {
5766 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5767 } else {
5768 if (empty($conf->use_javascript_ajax)) {
5769 $textfordropdown = '';
5770 }
5771
5772 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5773 $fa = 'info-circle';
5774 if ($picto == 'warning') {
5775 $fa = 'exclamation-triangle';
5776 }
5777 $result = ($nodiv ? '' : '<div class="wordbreak '.$class.($morecss ? ' '.$morecss : '').($textfordropdown ? ' hidden' : '').'">').'<span class="fa fa-'.$fa.'" title="'.dol_escape_htmltag($admin ? $langs->trans('InfoAdmin') : $langs->trans('Note')).'"></span> ';
5778 $result .= dol_escape_htmltag($text, 1, 0, 'div,span,b,br,a');
5779 $result .= ($nodiv ? '' : '</div>');
5780
5781 if ($textfordropdown) {
5782 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5783 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5784 jQuery(document).ready(function() {
5785 jQuery(".'.$class.'text").click(function() {
5786 console.log("toggle text");
5787 jQuery(".'.$class.'").toggle();
5788 });
5789 });
5790 </script>';
5791
5792 $result = $tmpresult.$result;
5793 }
5794 }
5795
5796 return $result;
5797}
5798
5799
5811function dol_print_error($db = null, $error = '', $errors = null)
5812{
5813 global $conf, $langs, $user, $argv;
5814 global $dolibarr_main_prod;
5815
5816 $out = '';
5817 $syslog = '';
5818
5819 // If error occurs before the $lang object was loaded
5820 if (!$langs) {
5821 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5822 $langs = new Translate('', $conf);
5823 $langs->load("main");
5824 }
5825
5826 // Load translation files required by the error messages
5827 $langs->loadLangs(array('main', 'errors'));
5828
5829 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5830 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5831 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5832 $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";
5833 }
5834 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5835
5836 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5837 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5838 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5839 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5840 }
5841 if ($user instanceof User) {
5842 $out .= "<b>".$langs->trans("Login").":</b> ".$user->login."<br>\n";
5843 }
5844 if (function_exists("phpversion")) {
5845 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5846 }
5847 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5848 if (function_exists("php_uname")) {
5849 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5850 }
5851 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5852 $out .= "<br>\n";
5853 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5854 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5855 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5856 $out .= "<br>\n";
5857 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5858 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5859 } else { // Mode CLI
5860 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5861 $syslog .= "pid=".dol_getmypid();
5862 }
5863
5864 if (!empty($conf->modules)) {
5865 $out .= "<b>".$langs->trans("Modules").":</b> ".implode(', ', $conf->modules)."<br>\n";
5866 }
5867
5868 if (is_object($db)) {
5869 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5870 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5871 $lastqueryerror = $db->lastqueryerror();
5872 if (!utf8_check($lastqueryerror)) {
5873 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5874 }
5875 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5876 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5877 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5878 $out .= "<br>\n";
5879 } else { // Mode CLI
5880 // No dol_escape_htmltag for output, we are in CLI mode
5881 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5882 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5883 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5884 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5885 }
5886 $syslog .= ", sql=".$db->lastquery();
5887 $syslog .= ", db_error=".$db->lasterror();
5888 }
5889
5890 if ($error || $errors) {
5891 // Merge all into $errors array
5892 if (is_array($error) && is_array($errors)) {
5893 $errors = array_merge($error, $errors);
5894 } elseif (is_array($error)) { // deprecated, use second parameters
5895 $errors = $error;
5896 } elseif (is_array($errors) && !empty($error)) {
5897 $errors = array_merge(array($error), $errors);
5898 } elseif (!empty($error)) {
5899 $errors = array_merge(array($error), array($errors));
5900 }
5901
5902 $langs->load("errors");
5903
5904 foreach ($errors as $msg) {
5905 if (empty($msg)) {
5906 continue;
5907 }
5908 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5909 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5910 } else { // Mode CLI
5911 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5912 }
5913 $syslog .= ", msg=".$msg;
5914 }
5915 }
5916 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5917 xdebug_print_function_stack();
5918 $out .= '<b>XDebug information:</b>'."<br>\n";
5919 $out .= 'File: '.xdebug_call_file()."<br>\n";
5920 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5921 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5922 $out .= "<br>\n";
5923 }
5924
5925 // Return a http header with error code if possible
5926 if (!headers_sent()) {
5927 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5928 top_httphead();
5929 }
5930 //http_response_code(500); // If we use 500, message is not output with some command line tools
5931 http_response_code(202); // If we use 202, this is not really an error message, but this allow to output message on command line tools
5932 }
5933
5934 if (empty($dolibarr_main_prod)) {
5935 print $out;
5936 } else {
5937 if (empty($langs->defaultlang)) {
5938 $langs->setDefaultLang();
5939 }
5940 $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.
5941 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5942 print 'This website or feature is currently temporarily 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";
5943 print $langs->trans("DolibarrHasDetectedError").'. ';
5944 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5945 if (!defined("MAIN_CORE_ERROR")) {
5946 define("MAIN_CORE_ERROR", 1);
5947 }
5948 }
5949
5950 dol_syslog("Error ".$syslog, LOG_ERR);
5951}
5952
5963function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5964{
5965 global $langs;
5966
5967 if (empty($email)) {
5968 $email = getDolGlobalString('MAIN_INFO_SOCIETE_MAIL');
5969 }
5970
5971 $langs->load("errors");
5972 $now = dol_now();
5973
5974 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5975 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5976 if ($errormessage) {
5977 print '<br><br>'.$errormessage;
5978 }
5979 if (is_array($errormessages) && count($errormessages)) {
5980 foreach ($errormessages as $mesgtoshow) {
5981 print '<br><br>'.$mesgtoshow;
5982 }
5983 }
5984 print '</div></div>';
5985}
5986
6003function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
6004{
6005 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
6006}
6007
6026function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
6027{
6028 global $langs, $form;
6029 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
6030
6031 if ($moreattrib == 'class="right"') {
6032 $prefix .= 'right '; // For backward compatibility
6033 }
6034
6035 $sortorder = strtoupper($sortorder);
6036 $out = '';
6037 $sortimg = '';
6038
6039 $tag = 'th';
6040 if ($thead == 2) {
6041 $tag = 'div';
6042 }
6043
6044 $tmpsortfield = explode(',', $sortfield);
6045 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
6046 $tmpfield = explode(',', $field);
6047 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
6048
6049 if (!getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle)) {
6050 $prefix = 'wrapcolumntitle '.$prefix;
6051 }
6052
6053 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
6054 // If field is used as sort criteria we use a specific css class liste_titre_sel
6055 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
6056 $liste_titre = 'liste_titre';
6057 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
6058 $liste_titre = 'liste_titre_sel';
6059 }
6060
6061 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
6062 //$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)).'"' : '');
6063 $tagstart .= ($name && !getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
6064 $tagstart .= '>';
6065
6066 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
6067 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
6068 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
6069 $options = preg_replace('/&+/i', '&', $options);
6070 if (!preg_match('/^&/', $options)) {
6071 $options = '&'.$options;
6072 }
6073
6074 $sortordertouseinlink = '';
6075 if ($field1 != $sortfield1) { // We are on another field than current sorted field
6076 if (preg_match('/^DESC/i', $sortorder)) {
6077 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
6078 } else { // We reverse the var $sortordertouseinlink
6079 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
6080 }
6081 } else { // We are on field that is the first current sorting criteria
6082 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
6083 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
6084 } else {
6085 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
6086 }
6087 }
6088 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
6089 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
6090 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
6091 $out .= '>';
6092 }
6093 if ($tooltip) {
6094 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
6095 if (preg_match('/:\w+$/', $tooltip)) {
6096 $tmptooltip = explode(':', $tooltip);
6097 } else {
6098 $tmptooltip = array($tooltip);
6099 }
6100 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
6101 } else {
6102 $out .= $langs->trans($name);
6103 }
6104
6105 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
6106 $out .= '</a>';
6107 }
6108
6109 if (empty($thead) && $field) { // If this is a sort field
6110 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
6111 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
6112 $options = preg_replace('/&+/i', '&', $options);
6113 if (!preg_match('/^&/', $options)) {
6114 $options = '&'.$options;
6115 }
6116
6117 if (!$sortorder || ($field1 != $sortfield1)) {
6118 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
6119 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
6120 } else {
6121 if (preg_match('/^DESC/', $sortorder)) {
6122 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
6123 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
6124 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
6125 }
6126 if (preg_match('/^ASC/', $sortorder)) {
6127 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
6128 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
6129 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
6130 }
6131 }
6132 }
6133
6134 $tagend = '</'.$tag.'>';
6135
6136 $out = $tagstart.$sortimg.$out.$tagend;
6137
6138 return $out;
6139}
6140
6149function print_titre($title)
6150{
6151 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
6152
6153 print '<div class="titre">'.$title.'</div>';
6154}
6155
6167function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
6168{
6169 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
6170}
6171
6185function load_fiche_titre($title, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
6186{
6187 $return = '';
6188
6189 if ($picto == 'setup') {
6190 $picto = 'generic';
6191 }
6192
6193 $return .= "\n";
6194 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
6195 $return .= '<tr class="titre">';
6196 if ($picto) {
6197 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
6198 }
6199 $return .= '<td class="nobordernopadding valignmiddle col-title">';
6200 $return .= '<div class="titre inline-block">';
6201 $return .= $title; // $title is already HTML sanitized content
6202 $return .= '</div>';
6203 $return .= '</td>';
6204 if (dol_strlen($morehtmlcenter)) {
6205 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
6206 }
6207 if (dol_strlen($morehtmlright)) {
6208 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
6209 }
6210 $return .= '</tr></table>'."\n";
6211
6212 return $return;
6213}
6214
6238function print_barre_liste($title, $page, $file, $options = '', $sortfield = '', $sortorder = '', $morehtmlcenter = '', $num = -1, $totalnboflines = '', $picto = 'generic', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limit = -1, $hideselectlimit = 0, $hidenavigation = 0, $pagenavastextinput = 0, $morehtmlrightbeforearrow = '')
6239{
6240 global $conf;
6241
6242 $savlimit = $limit;
6243 $savtotalnboflines = $totalnboflines;
6244 if (is_numeric($totalnboflines)) {
6245 $totalnboflines = abs($totalnboflines);
6246 }
6247
6248 $page = (int) $page;
6249
6250 if ($picto == 'setup') {
6251 $picto = 'title_setup.png';
6252 }
6253 if (($conf->browser->name == 'ie') && $picto == 'generic') {
6254 $picto = 'title.gif';
6255 }
6256 if ($limit < 0) {
6257 $limit = $conf->liste_limit;
6258 }
6259
6260 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
6261 $nextpage = 1;
6262 } else {
6263 $nextpage = 0;
6264 }
6265 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
6266
6267 print "\n";
6268 print "<!-- Begin title -->\n";
6269 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
6270
6271 // Left
6272
6273 if ($picto && $title) {
6274 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
6275 }
6276
6277 print '<td class="nobordernopadding valignmiddle col-title">';
6278 print '<div class="titre inline-block">';
6279 print $title; // $title may contains HTML
6280 if (!empty($title) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
6281 print '<span class="opacitymedium colorblack paddingleft totalnboflines">('.$totalnboflines.')</span>';
6282 }
6283 print '</div></td>';
6284
6285 // Center
6286 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
6287 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
6288 }
6289
6290 // Right
6291 print '<td class="nobordernopadding valignmiddle right col-right">';
6292 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
6293 if ($sortfield) {
6294 $options .= "&sortfield=".urlencode($sortfield);
6295 }
6296 if ($sortorder) {
6297 $options .= "&sortorder=".urlencode($sortorder);
6298 }
6299 // Show navigation bar
6300 $pagelist = '';
6301 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
6302 if ($totalnboflines) { // If we know total nb of lines
6303 // Define nb of extra page links before and after selected page + ... + first or last
6304 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
6305
6306 if ($limit > 0) {
6307 $nbpages = ceil($totalnboflines / $limit);
6308 } else {
6309 $nbpages = 1;
6310 }
6311 $cpt = ($page - $maxnbofpage);
6312 if ($cpt < 0) {
6313 $cpt = 0;
6314 }
6315
6316 if ($cpt >= 1) {
6317 if (empty($pagenavastextinput)) {
6318 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=0'.$options.'">1</a></li>';
6319 if ($cpt > 2) {
6320 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
6321 } elseif ($cpt == 2) {
6322 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=1'.$options.'">2</a></li>';
6323 }
6324 }
6325 }
6326
6327 do {
6328 if ($pagenavastextinput) {
6329 if ($cpt == $page) {
6330 $pagelist .= '<li class="pagination pageplusone"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
6331 $pagelist .= '/';
6332 }
6333 } else {
6334 if ($cpt == $page) {
6335 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
6336 } else {
6337 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
6338 }
6339 }
6340 $cpt++;
6341 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
6342
6343 if (empty($pagenavastextinput)) {
6344 if ($cpt < $nbpages) {
6345 if ($cpt < $nbpages - 2) {
6346 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
6347 } elseif ($cpt == $nbpages - 2) {
6348 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
6349 }
6350 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
6351 }
6352 } else {
6353 //var_dump($page.' '.$cpt.' '.$nbpages);
6354 $pagelist .= '<li class="pagination paginationlastpage"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
6355 }
6356 } else {
6357 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
6358 }
6359 }
6360
6361 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
6362 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
6363 }
6364
6365 // js to autoselect page field on focus
6366 if ($pagenavastextinput) {
6367 print ajax_autoselect('.pageplusone');
6368 }
6369
6370 print '</td>';
6371 print '</tr>';
6372
6373 print '</table>'."\n";
6374
6375 // Center
6376 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
6377 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
6378 }
6379
6380 print "<!-- End title -->\n\n";
6381}
6382
6399function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
6400{
6401 global $conf, $langs;
6402
6403 print '<div class="pagination"><ul>';
6404 if ($beforearrows) {
6405 print '<li class="paginationbeforearrows">';
6406 print $beforearrows;
6407 print '</li>';
6408 }
6409
6410 if (empty($hidenavigation)) {
6411 if ((int) $limit > 0 && empty($hideselectlimit)) {
6412 $pagesizechoices = '10:10,15:15,20:20,25:25,50:50,100:100,250:250,500:500,1000:1000';
6413 $pagesizechoices .= ',5000:5000,10000:10000';
6414 //$pagesizechoices .= ',20000:20000'; // Memory trouble on browsers
6415 //$pagesizechoices .= ',0:'.$langs->trans("All"); // Not yet supported
6416 //$pagesizechoices .= ',2:2';
6417 if (getDolGlobalString('MAIN_PAGESIZE_CHOICES')) {
6418 $pagesizechoices = getDolGlobalString('MAIN_PAGESIZE_CHOICES');
6419 }
6420
6421 if (getDolGlobalString('MAIN_USE_HTML5_LIMIT_SELECTOR')) {
6422 print '<li class="pagination">';
6423 print '<input onfocus="this.value=null;" onchange="this.blur();" class="flat selectlimit nopadding maxwidth75 right pageplusone" id="limit" name="limit" list="limitlist" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'" value="'.$limit.'">';
6424 print '<datalist id="limitlist">';
6425 } else {
6426 print '<li class="paginationcombolimit valignmiddle">';
6427 print '<select id="limit" class="flat selectlimit nopadding maxwidth75 center" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
6428 }
6429 $tmpchoice = explode(',', $pagesizechoices);
6430 $tmpkey = $limit.':'.$limit;
6431 if (!in_array($tmpkey, $tmpchoice)) {
6432 $tmpchoice[] = $tmpkey;
6433 }
6434 $tmpkey = $conf->liste_limit.':'.$conf->liste_limit;
6435 if (!in_array($tmpkey, $tmpchoice)) {
6436 $tmpchoice[] = $tmpkey;
6437 }
6438 asort($tmpchoice, SORT_NUMERIC);
6439 foreach ($tmpchoice as $val) {
6440 $selected = '';
6441 $tmp = explode(':', $val);
6442 $key = $tmp[0];
6443 $val = $tmp[1];
6444 if ($key != '' && $val != '') {
6445 if ((int) $key == (int) $limit) {
6446 $selected = ' selected="selected"';
6447 }
6448 print '<option name="'.$key.'"'.$selected.'>'.dol_escape_htmltag($val).'</option>'."\n";
6449 }
6450 }
6451 if (getDolGlobalString('MAIN_USE_HTML5_LIMIT_SELECTOR')) {
6452 print '</datalist>';
6453 } else {
6454 print '</select>';
6455 print ajax_combobox("limit", array(), 0, 0, 'resolve', -1, 'limit');
6456 //print ajax_combobox("limit");
6457 }
6458
6459 if ($conf->use_javascript_ajax) {
6460 print '<!-- JS CODE TO ENABLE select limit to launch submit of page -->
6461 <script>
6462 jQuery(document).ready(function () {
6463 jQuery(".selectlimit").change(function() {
6464 console.log("Change limit. Send submit");
6465 $(this).parents(\'form:first\').submit();
6466 });
6467 });
6468 </script>
6469 ';
6470 }
6471 print '</li>';
6472 }
6473 if ($page > 0) {
6474 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>';
6475 }
6476 if ($betweenarrows) {
6477 print '<!--<div class="betweenarrows nowraponall inline-block">-->';
6478 print $betweenarrows;
6479 print '<!--</div>-->';
6480 }
6481 if ($nextpage > 0) {
6482 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>';
6483 }
6484 if ($afterarrows) {
6485 print '<li class="paginationafterarrows">';
6486 print $afterarrows;
6487 print '</li>';
6488 }
6489 }
6490 print '</ul></div>'."\n";
6491}
6492
6493
6505function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, $html = 0)
6506{
6507 $morelabel = '';
6508
6509 if (preg_match('/%/', $rate)) {
6510 $rate = str_replace('%', '', $rate);
6511 $addpercent = true;
6512 }
6513 $reg = array();
6514 if (preg_match('/\‍((.*)\‍)/', $rate, $reg)) {
6515 $morelabel = ' ('.$reg[1].')';
6516 $rate = preg_replace('/\s*'.preg_quote($morelabel, '/').'/', '', $rate);
6517 $morelabel = ' '.($html ? '<span class="opacitymedium">' : '').'('.$reg[1].')'.($html ? '</span>' : '');
6518 }
6519 if (preg_match('/\*/', $rate)) {
6520 $rate = str_replace('*', '', $rate);
6521 $info_bits |= 1;
6522 }
6523
6524 // If rate is '9/9/9' we don't change it. If rate is '9.000' we apply price()
6525 if (!preg_match('/\//', $rate)) {
6526 $ret = price($rate, 0, '', 0, 0).($addpercent ? '%' : '');
6527 } else {
6528 // TODO Split on / and output with a price2num to have clean numbers without ton of 000.
6529 $ret = $rate.($addpercent ? '%' : '');
6530 }
6531 if (($info_bits & 1) && $usestarfornpr >= 0) {
6532 $ret .= ' *';
6533 }
6534 $ret .= $morelabel;
6535 return $ret;
6536}
6537
6538
6554function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1, $currency_code = '')
6555{
6556 global $langs, $conf;
6557
6558 // Clean parameters
6559 if (empty($amount)) {
6560 $amount = 0; // To have a numeric value if amount not defined or = ''
6561 }
6562 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occurred when amount value = o (letter) instead 0 (number)
6563 if ($rounding == -1) {
6564 $rounding = min(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), getDolGlobalString('MAIN_MAX_DECIMALS_TOT'));
6565 }
6566 $nbdecimal = $rounding;
6567
6568 if ($outlangs === 'none') {
6569 // Use international separators
6570 $dec = '.';
6571 $thousand = '';
6572 } else {
6573 // Output separators by default (french)
6574 $dec = ',';
6575 $thousand = ' ';
6576
6577 // If $outlangs not forced, we use use language
6578 if (!($outlangs instanceof Translate)) {
6579 $outlangs = $langs;
6580 }
6581
6582 if ($outlangs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6583 $dec = $outlangs->transnoentitiesnoconv("SeparatorDecimal");
6584 }
6585 if ($outlangs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6586 $thousand = $outlangs->transnoentitiesnoconv("SeparatorThousand");
6587 }
6588 if ($thousand == 'None') {
6589 $thousand = '';
6590 } elseif ($thousand == 'Space') {
6591 $thousand = ' ';
6592 }
6593 }
6594 //print "outlangs=".$outlangs->defaultlang." amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6595
6596 //print "amount=".$amount."-";
6597 $amount = str_replace(',', '.', $amount); // should be useless
6598 //print $amount."-";
6599 $data = explode('.', $amount);
6600 $decpart = isset($data[1]) ? $data[1] : '';
6601 $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
6602 //print "decpart=".$decpart."<br>";
6603 $end = '';
6604
6605 // We increase nbdecimal if there is more decimal than asked (to not loose information)
6606 if (dol_strlen($decpart) > $nbdecimal) {
6607 $nbdecimal = dol_strlen($decpart);
6608 }
6609 // Si on depasse max
6610 $max_nbdecimal = (int) str_replace('...', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'));
6611 if ($trunc && $nbdecimal > $max_nbdecimal) {
6612 $nbdecimal = $max_nbdecimal;
6613 if (preg_match('/\.\.\./i', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'))) {
6614 // If output is truncated, we show ...
6615 $end = '...';
6616 }
6617 }
6618
6619 // If force rounding
6620 if ((string) $forcerounding != '-1') {
6621 if ($forcerounding === 'MU') {
6622 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_UNIT');
6623 } elseif ($forcerounding === 'MT') {
6624 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_TOT');
6625 } elseif ($forcerounding >= 0) {
6626 $nbdecimal = $forcerounding;
6627 }
6628 }
6629
6630 // Format number
6631 $output = number_format((float) $amount, $nbdecimal, $dec, $thousand);
6632 if ($form) {
6633 $output = preg_replace('/\s/', '&nbsp;', $output);
6634 $output = preg_replace('/\'/', '&#039;', $output);
6635 }
6636 // Add symbol of currency if requested
6637 $cursymbolbefore = $cursymbolafter = '';
6638 if ($currency_code && is_object($outlangs)) {
6639 if ($currency_code == 'auto') {
6640 $currency_code = $conf->currency;
6641 }
6642
6643 $listofcurrenciesbefore = array('AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD', 'CRC', 'ZAR');
6644 $listoflanguagesbefore = array('nl_NL');
6645 if (in_array($currency_code, $listofcurrenciesbefore) || in_array($outlangs->defaultlang, $listoflanguagesbefore)) {
6646 $cursymbolbefore .= $outlangs->getCurrencySymbol($currency_code);
6647 } else {
6648 $tmpcur = $outlangs->getCurrencySymbol($currency_code);
6649 $cursymbolafter .= ($tmpcur == $currency_code ? ' '.$tmpcur : $tmpcur);
6650 }
6651 }
6652 $output = $cursymbolbefore.$output.$end.($cursymbolafter ? ' ' : '').$cursymbolafter;
6653
6654 return $output;
6655}
6656
6681function price2num($amount, $rounding = '', $option = 0)
6682{
6683 global $langs, $conf;
6684
6685 // Clean parameters
6686 if (is_null($amount)) {
6687 $amount = '';
6688 }
6689
6690 // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
6691 // Numbers must be '1234.56'
6692 // Decimal delimiter for PHP and database SQL requests must be '.'
6693 $dec = ',';
6694 $thousand = ' ';
6695 if (is_null($langs)) { // $langs is not defined, we use english values.
6696 $dec = '.';
6697 $thousand = ',';
6698 } else {
6699 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6700 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
6701 }
6702 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6703 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
6704 }
6705 }
6706 if ($thousand == 'None') {
6707 $thousand = '';
6708 } elseif ($thousand == 'Space') {
6709 $thousand = ' ';
6710 }
6711 //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6712
6713 // Convert value to universal number format (no thousand separator, '.' as decimal separator)
6714 if ($option != 1) { // If not a PHP number or unknown, we change or clean format
6715 //print "\n".'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'<br>';
6716 if (!is_numeric($amount)) {
6717 $amount = preg_replace('/[a-zA-Z\/\\\*\‍(\‍)<>\_]/', '', $amount);
6718 }
6719
6720 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
6721 $amount = str_replace($thousand, '', $amount);
6722 }
6723
6724 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6725 // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
6726 // So if number was already a good number, it is converted into local Dolibarr setup.
6727 if (is_numeric($amount)) {
6728 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6729 $temps = sprintf("%10.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6730 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6731 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6732 $amount = number_format($amount, $nbofdec, $dec, $thousand);
6733 }
6734 //print "QQ".$amount."<br>\n";
6735
6736 // Now make replace (the main goal of function)
6737 if ($thousand != ',' && $thousand != '.') {
6738 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6739 }
6740
6741 $amount = str_replace(' ', '', $amount); // To avoid spaces
6742 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6743 $amount = str_replace($dec, '.', $amount);
6744
6745 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6746 }
6747 //print ' XX'.$amount.' '.$rounding;
6748
6749 // Now, $amount is a real PHP float number. We make a rounding if required.
6750 if ($rounding) {
6751 $nbofdectoround = '';
6752 if ($rounding == 'MU') {
6753 $nbofdectoround = getDolGlobalString('MAIN_MAX_DECIMALS_UNIT');
6754 } elseif ($rounding == 'MT') {
6755 $nbofdectoround = getDolGlobalString('MAIN_MAX_DECIMALS_TOT');
6756 } elseif ($rounding == 'MS') {
6757 $nbofdectoround = isset($conf->global->MAIN_MAX_DECIMALS_STOCK) ? $conf->global->MAIN_MAX_DECIMALS_STOCK : 5;
6758 } elseif ($rounding == 'CU') {
6759 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), 8); // TODO Use param of currency
6760 } elseif ($rounding == 'CT') {
6761 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_TOT'), 8); // TODO Use param of currency
6762 } elseif (is_numeric($rounding)) {
6763 $nbofdectoround = (int) $rounding;
6764 }
6765
6766 //print " RR".$amount.' - '.$nbofdectoround.'<br>';
6767 if (dol_strlen($nbofdectoround)) {
6768 $amount = round(is_string($amount) ? (float) $amount : $amount, $nbofdectoround); // $nbofdectoround can be 0.
6769 } else {
6770 return 'ErrorBadParameterProvidedToFunction';
6771 }
6772 //print ' SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
6773
6774 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6775 // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
6776 if (is_numeric($amount)) {
6777 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6778 $temps = sprintf("%10.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6779 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6780 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6781 $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
6782 }
6783 //print "TT".$amount.'<br>';
6784
6785 // Always make replace because each math function (like round) replace
6786 // with local values and we want a number that has a SQL string format x.y
6787 if ($thousand != ',' && $thousand != '.') {
6788 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6789 }
6790
6791 $amount = str_replace(' ', '', $amount); // To avoid spaces
6792 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6793 $amount = str_replace($dec, '.', $amount);
6794
6795 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6796 }
6797
6798 return $amount;
6799}
6800
6813function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round = -1, $forceunitoutput = 'no', $use_short_label = 0)
6814{
6815 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
6816
6817 if (($forceunitoutput == 'no' && $dimension < 1 / 10000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -6)) {
6818 $dimension *= 1000000;
6819 $unit -= 6;
6820 } elseif (($forceunitoutput == 'no' && $dimension < 1 / 10 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -3)) {
6821 $dimension *= 1000;
6822 $unit -= 3;
6823 } elseif (($forceunitoutput == 'no' && $dimension > 100000000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 6)) {
6824 $dimension /= 1000000;
6825 $unit += 6;
6826 } elseif (($forceunitoutput == 'no' && $dimension > 100000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 3)) {
6827 $dimension /= 1000;
6828 $unit += 3;
6829 }
6830 // Special case when we want output unit into pound or ounce
6831 /* TODO
6832 if ($unit < 90 && $type == 'weight' && is_numeric($forceunitoutput) && (($forceunitoutput == 98) || ($forceunitoutput == 99))
6833 {
6834 $dimension = // convert dimension from standard unit into ounce or pound
6835 $unit = $forceunitoutput;
6836 }
6837 if ($unit > 90 && $type == 'weight' && is_numeric($forceunitoutput) && $forceunitoutput < 90)
6838 {
6839 $dimension = // convert dimension from standard unit into ounce or pound
6840 $unit = $forceunitoutput;
6841 }*/
6842
6843 $ret = price($dimension, 0, $outputlangs, 0, 0, $round);
6844 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
6845 $ret .= ' '.measuringUnitString(0, $type, $unit, $use_short_label, $outputlangs);
6846
6847 return $ret;
6848}
6849
6850
6863function get_localtax($vatrate, $local, $thirdparty_buyer = null, $thirdparty_seller = null, $vatnpr = 0)
6864{
6865 global $db, $conf, $mysoc;
6866
6867 if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
6868 $thirdparty_seller = $mysoc;
6869 }
6870
6871 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);
6872
6873 $vatratecleaned = $vatrate;
6874 $reg = array();
6875 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', (string) $vatrate, $reg)) { // If vat is "xx (yy)"
6876 $vatratecleaned = trim($reg[1]);
6877 $vatratecode = $reg[2];
6878 }
6879
6880 /*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
6881 {
6882 return 0;
6883 }*/
6884
6885 // Some test to guess with no need to make database access
6886 if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
6887 if ($local == 1) {
6888 if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
6889 return 0;
6890 }
6891 if ($thirdparty_seller->id == $mysoc->id) {
6892 if (!$thirdparty_buyer->localtax1_assuj) {
6893 return 0;
6894 }
6895 } else {
6896 if (!$thirdparty_seller->localtax1_assuj) {
6897 return 0;
6898 }
6899 }
6900 }
6901
6902 if ($local == 2) {
6903 //if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
6904 if (!$mysoc->localtax2_assuj) {
6905 return 0; // If main vat is 0, IRPF may be different than 0.
6906 }
6907 if ($thirdparty_seller->id == $mysoc->id) {
6908 if (!$thirdparty_buyer->localtax2_assuj) {
6909 return 0;
6910 }
6911 } else {
6912 if (!$thirdparty_seller->localtax2_assuj) {
6913 return 0;
6914 }
6915 }
6916 }
6917 } else {
6918 if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
6919 return 0;
6920 }
6921 if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
6922 return 0;
6923 }
6924 }
6925
6926 // For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
6927 if (in_array($mysoc->country_code, array('ES'))) {
6928 $conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
6929 }
6930
6931 // Search local taxes
6932 if (getDolGlobalString('MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY')) {
6933 if ($local == 1) {
6934 if ($thirdparty_seller != $mysoc) {
6935 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6936 return $thirdparty_seller->localtax1_value;
6937 }
6938 } else { // i am the seller
6939 if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
6940 return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
6941 }
6942 }
6943 }
6944 if ($local == 2) {
6945 if ($thirdparty_seller != $mysoc) {
6946 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6947 // TODO We should also return value defined on thirdparty only if defined
6948 return $thirdparty_seller->localtax2_value;
6949 }
6950 } else { // i am the seller
6951 if (in_array($mysoc->country_code, array('ES'))) {
6952 return $thirdparty_buyer->localtax2_value;
6953 } else {
6954 return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
6955 }
6956 }
6957 }
6958 }
6959
6960 // By default, search value of local tax on line of common tax
6961 $sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
6962 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6963 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
6964 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6965 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6966 if (!empty($vatratecode)) {
6967 $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
6968 } else {
6969 $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
6970 }
6971
6972 $resql = $db->query($sql);
6973
6974 if ($resql) {
6975 $obj = $db->fetch_object($resql);
6976 if ($obj) {
6977 if ($local == 1) {
6978 return $obj->localtax1;
6979 } elseif ($local == 2) {
6980 return $obj->localtax2;
6981 }
6982 }
6983 }
6984
6985 return 0;
6986}
6987
6988
6997function isOnlyOneLocalTax($local)
6998{
6999 $tax = get_localtax_by_third($local);
7000
7001 $valors = explode(":", $tax);
7002
7003 if (count($valors) > 1) {
7004 return false;
7005 } else {
7006 return true;
7007 }
7008}
7009
7016function get_localtax_by_third($local)
7017{
7018 global $db, $mysoc;
7019
7020 $sql = " SELECT t.localtax".$local." as localtax";
7021 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_pays";
7022 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.active = 1 AND t.entity IN (".getEntity('c_tva').") AND t.taux = (";
7023 $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";
7024 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.entity IN (".getEntity('c_tva').") AND tt.active = 1)";
7025 $sql .= " AND t.localtax".$local."_type <> '0'";
7026 $sql .= " ORDER BY t.rowid DESC";
7027
7028 $resql = $db->query($sql);
7029 if ($resql) {
7030 $obj = $db->fetch_object($resql);
7031 if ($obj) {
7032 return $obj->localtax;
7033 } else {
7034 return '0';
7035 }
7036 }
7037
7038 return 'Error';
7039}
7040
7041
7053function getTaxesFromId($vatrate, $buyer = null, $seller = null, $firstparamisid = 1)
7054{
7055 global $db;
7056
7057 dol_syslog("getTaxesFromId vat id or rate = ".$vatrate);
7058
7059 // Search local taxes
7060 $sql = "SELECT t.rowid, t.code, t.taux as rate, t.recuperableonly as npr, t.accountancy_code_sell, t.accountancy_code_buy,";
7061 $sql .= " t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type";
7062 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
7063 if ($firstparamisid) {
7064 $sql .= " WHERE t.rowid = ".(int) $vatrate;
7065 } else {
7066 $vatratecleaned = $vatrate;
7067 $vatratecode = '';
7068 $reg = array();
7069 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
7070 $vatratecleaned = $reg[1];
7071 $vatratecode = $reg[2];
7072 }
7073
7074 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
7075 /*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 ??
7076 else $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";*/
7077 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";
7078 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
7079 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
7080 if ($vatratecode) {
7081 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
7082 }
7083 }
7084
7085 $resql = $db->query($sql);
7086 if ($resql) {
7087 $obj = $db->fetch_object($resql);
7088 if ($obj) {
7089 return array(
7090 'rowid' => $obj->rowid,
7091 'code' => $obj->code,
7092 'rate' => $obj->rate,
7093 'localtax1' => $obj->localtax1,
7094 'localtax1_type' => $obj->localtax1_type,
7095 'localtax2' => $obj->localtax2,
7096 'localtax2_type' => $obj->localtax2_type,
7097 'npr' => $obj->npr,
7098 'accountancy_code_sell' => $obj->accountancy_code_sell,
7099 'accountancy_code_buy' => $obj->accountancy_code_buy
7100 );
7101 } else {
7102 return array();
7103 }
7104 } else {
7105 dol_print_error($db);
7106 }
7107
7108 return array();
7109}
7110
7127function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid = 0)
7128{
7129 global $db, $mysoc;
7130
7131 dol_syslog("getLocalTaxesFromRate vatrate=".$vatrate." local=".$local);
7132
7133 // Search local taxes
7134 $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";
7135 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
7136 if ($firstparamisid) {
7137 $sql .= " WHERE t.rowid = ".(int) $vatrate;
7138 } else {
7139 $vatratecleaned = $vatrate;
7140 $vatratecode = '';
7141 $reg = array();
7142 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "x.x (yy)"
7143 $vatratecleaned = $reg[1];
7144 $vatratecode = $reg[2];
7145 }
7146
7147 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
7148 if (!empty($mysoc) && $mysoc->country_code == 'ES') {
7149 $countrycodetouse = ((empty($buyer) || empty($buyer->country_code)) ? $mysoc->country_code : $buyer->country_code);
7150 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'"; // local tax in spain use the buyer country ??
7151 } else {
7152 $countrycodetouse = ((empty($seller) || empty($seller->country_code)) ? $mysoc->country_code : $seller->country_code);
7153 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'";
7154 }
7155 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
7156 if ($vatratecode) {
7157 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
7158 }
7159 }
7160
7161 $resql = $db->query($sql);
7162 if ($resql) {
7163 $obj = $db->fetch_object($resql);
7164
7165 if ($obj) {
7166 $vateratestring = $obj->rate.($obj->code ? ' ('.$obj->code.')' : '');
7167
7168 if ($local == 1) {
7169 return array($obj->localtax1_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
7170 } elseif ($local == 2) {
7171 return array($obj->localtax2_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
7172 } else {
7173 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);
7174 }
7175 }
7176 }
7177
7178 return array();
7179}
7180
7191function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice = 0)
7192{
7193 global $db, $mysoc;
7194
7195 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
7196
7197 $ret = 0;
7198 $found = 0;
7199
7200 if ($idprod > 0) {
7201 // Load product
7202 $product = new Product($db);
7203 $product->fetch($idprod);
7204
7205 if (($mysoc->country_code == $thirdpartytouse->country_code)
7206 || (in_array($mysoc->country_code, array('FR', 'MC')) && in_array($thirdpartytouse->country_code, array('FR', 'MC')))
7207 || (in_array($mysoc->country_code, array('MQ', 'GP')) && in_array($thirdpartytouse->country_code, array('MQ', 'GP')))
7208 ) {
7209 // If country of thirdparty to consider is ours
7210 if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object
7211 $result = $product->get_buyprice($idprodfournprice, 0, 0, 0);
7212 if ($result > 0) {
7213 $ret = $product->vatrate_supplier;
7214 if ($product->default_vat_code_supplier) {
7215 $ret .= ' ('.$product->default_vat_code_supplier.')';
7216 }
7217 $found = 1;
7218 }
7219 }
7220 if (!$found) {
7221 $ret = $product->tva_tx; // Default sales vat of product
7222 if ($product->default_vat_code) {
7223 $ret .= ' ('.$product->default_vat_code.')';
7224 }
7225 $found = 1;
7226 }
7227 } else {
7228 // TODO Read default product vat according to product and an other countrycode.
7229 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
7230 }
7231 }
7232
7233 if (!$found) {
7234 if (!getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS')) {
7235 // 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).
7236 $sql = "SELECT t.taux as vat_rate, t.code as default_vat_code";
7237 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
7238 $sql .= " WHERE t.active = 1 AND t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdpartytouse->country_code)."'";
7239 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
7240 $sql .= " ORDER BY t.use_default DESC, t.taux DESC, t.code ASC, t.recuperableonly ASC";
7241 $sql .= $db->plimit(1);
7242
7243 $resql = $db->query($sql);
7244 if ($resql) {
7245 $obj = $db->fetch_object($resql);
7246 if ($obj) {
7247 $ret = $obj->vat_rate;
7248 if ($obj->default_vat_code) {
7249 $ret .= ' ('.$obj->default_vat_code.')';
7250 }
7251 }
7252 $db->free($resql);
7253 } else {
7254 dol_print_error($db);
7255 }
7256 } else {
7257 // Forced value if autodetect fails. MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS can be
7258 // '1.23'
7259 // or '1.23 (CODE)'
7260 $defaulttx = '';
7261 if (getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS') != 'none') {
7262 $defaulttx = getDolGlobalString('MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS');
7263 }
7264 /*if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
7265 $defaultcode = $reg[1];
7266 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
7267 }*/
7268
7269 $ret = $defaulttx;
7270 }
7271 }
7272
7273 dol_syslog("get_product_vat_for_country: ret=".$ret);
7274 return $ret;
7275}
7276
7286function get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
7287{
7288 global $db, $mysoc;
7289
7290 if (!class_exists('Product')) {
7291 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
7292 }
7293
7294 $ret = 0;
7295 $found = 0;
7296
7297 if ($idprod > 0) {
7298 // Load product
7299 $product = new Product($db);
7300 $result = $product->fetch($idprod);
7301
7302 if ($mysoc->country_code == $thirdpartytouse->country_code) { // If selling country is ours
7303 /* Not defined yet, so we don't use this
7304 if ($local==1) $ret=$product->localtax1_tx;
7305 elseif ($local==2) $ret=$product->localtax2_tx;
7306 $found=1;
7307 */
7308 } else {
7309 // TODO Read default product vat according to product and another countrycode.
7310 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
7311 }
7312 }
7313
7314 if (!$found) {
7315 // If vat of product for the country not found or not defined, we return higher vat of country.
7316 $sql = "SELECT taux as vat_rate, localtax1, localtax2";
7317 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
7318 $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code='".$db->escape($thirdpartytouse->country_code)."'";
7319 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
7320 $sql .= " ORDER BY t.taux DESC, t.recuperableonly ASC";
7321 $sql .= $db->plimit(1);
7322
7323 $resql = $db->query($sql);
7324 if ($resql) {
7325 $obj = $db->fetch_object($resql);
7326 if ($obj) {
7327 if ($local == 1) {
7328 $ret = $obj->localtax1;
7329 } elseif ($local == 2) {
7330 $ret = $obj->localtax2;
7331 }
7332 }
7333 } else {
7334 dol_print_error($db);
7335 }
7336 }
7337
7338 dol_syslog("get_product_localtax_for_country: ret=".$ret);
7339 return $ret;
7340}
7341
7358function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
7359{
7360 global $conf;
7361
7362 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
7363
7364 // Note: possible values for tva_assuj are 0/1 or franchise/reel
7365 $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;
7366
7367 $seller_country_code = $thirdparty_seller->country_code;
7368 $seller_in_cee = isInEEC($thirdparty_seller);
7369
7370 $buyer_country_code = $thirdparty_buyer->country_code;
7371 $buyer_in_cee = isInEEC($thirdparty_buyer);
7372
7373 dol_syslog("get_default_tva: seller use vat=".$seller_use_vat.", seller country=".$seller_country_code.", seller in cee=".((string) (int) $seller_in_cee).", buyer vat number=".$thirdparty_buyer->tva_intra." buyer country=".$buyer_country_code.", buyer in cee=".((string) (int) $buyer_in_cee).", idprod=".$idprod.", idprodfournprice=".$idprodfournprice.", SERVICE_ARE_ECOMMERCE_200238EC=".(getDolGlobalString('SERVICES_ARE_ECOMMERCE_200238EC') ? $conf->global->SERVICES_ARE_ECOMMERCE_200238EC : ''));
7374
7375 // 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)
7376 // we use the buyer VAT.
7377 if (getDolGlobalString('SERVICE_ARE_ECOMMERCE_200238EC')) {
7378 if ($seller_in_cee && $buyer_in_cee) {
7379 $isacompany = $thirdparty_buyer->isACompany();
7380 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
7381 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
7382 if (!isValidVATID($thirdparty_buyer)) {
7383 $isacompany = 0;
7384 }
7385 }
7386
7387 if (!$isacompany) {
7388 //print 'VATRULE 0';
7389 return get_product_vat_for_country($idprod, $thirdparty_buyer, $idprodfournprice);
7390 }
7391 }
7392 }
7393
7394 // If seller does not use VAT, default VAT is 0. End of rule.
7395 if (!$seller_use_vat) {
7396 //print 'VATRULE 1';
7397 return 0;
7398 }
7399
7400 // If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule.
7401 if (($seller_country_code == $buyer_country_code)
7402 || (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC')))
7403 || (in_array($seller_country_code, array('MQ', 'GP')) && in_array($buyer_country_code, array('MQ', 'GP')))
7404 ) { // Warning ->country_code not always defined
7405 //print 'VATRULE 2';
7406 $tmpvat = get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
7407
7408 if ($seller_country_code == 'IN' && getDolGlobalString('MAIN_SALETAX_AUTOSWITCH_I_CS_FOR_INDIA')) {
7409 // Special case for india.
7410 //print 'VATRULE 2b';
7411 $reg = array();
7412 if (preg_match('/C+S-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id != $thirdparty_buyer->state_id) {
7413 // we must revert the C+S into I
7414 $tmpvat = str_replace("C+S", "I", $tmpvat);
7415 } elseif (preg_match('/I-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id == $thirdparty_buyer->state_id) {
7416 // we must revert the I into C+S
7417 $tmpvat = str_replace("I", "C+S", $tmpvat);
7418 }
7419 }
7420
7421 return $tmpvat;
7422 }
7423
7424 // 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.
7425 // 'VATRULE 3' - Not supported
7426
7427 // If (seller and buyer in the European Community) and (buyer = individual) then VAT by default = VAT of the product sold. End of rule
7428 // If (seller and buyer in European Community) and (buyer = company) then VAT by default=0. End of rule
7429 if (($seller_in_cee && $buyer_in_cee)) {
7430 $isacompany = $thirdparty_buyer->isACompany();
7431 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
7432 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
7433 if (!isValidVATID($thirdparty_buyer)) {
7434 $isacompany = 0;
7435 }
7436 }
7437
7438 if (!$isacompany) {
7439 //print 'VATRULE 4';
7440 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
7441 } else {
7442 //print 'VATRULE 5';
7443 return 0;
7444 }
7445 }
7446
7447 // 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
7448 // I don't see any use case that need this rule.
7449 if (getDolGlobalString('MAIN_USE_VAT_OF_PRODUCT_FOR_INDIVIDUAL_CUSTOMER_OUT_OF_EEC') && empty($buyer_in_cee)) {
7450 $isacompany = $thirdparty_buyer->isACompany();
7451 if (!$isacompany) {
7452 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
7453 //print 'VATRULE extra';
7454 }
7455 }
7456
7457 // Otherwise the VAT proposed by default=0. End of rule.
7458 // Rem: This means that at least one of the 2 is outside the European Community and the country differs
7459 //print 'VATRULE 6';
7460 return 0;
7461}
7462
7463
7474function get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
7475{
7476 global $db;
7477
7478 if ($idprodfournprice > 0) {
7479 if (!class_exists('ProductFournisseur')) {
7480 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
7481 }
7482 $prodprice = new ProductFournisseur($db);
7483 $prodprice->fetch_product_fournisseur_price($idprodfournprice);
7484 return $prodprice->fourn_tva_npr;
7485 } elseif ($idprod > 0) {
7486 if (!class_exists('Product')) {
7487 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
7488 }
7489 $prod = new Product($db);
7490 $prod->fetch($idprod);
7491 return $prod->tva_npr;
7492 }
7493
7494 return 0;
7495}
7496
7510function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod = 0)
7511{
7512 global $mysoc;
7513
7514 if (!is_object($thirdparty_seller)) {
7515 return -1;
7516 }
7517 if (!is_object($thirdparty_buyer)) {
7518 return -1;
7519 }
7520
7521 if ($local == 1) { // Localtax 1
7522 if ($mysoc->country_code == 'ES') {
7523 if (is_numeric($thirdparty_buyer->localtax1_assuj) && !$thirdparty_buyer->localtax1_assuj) {
7524 return 0;
7525 }
7526 } else {
7527 // Si vendeur non assujeti a Localtax1, localtax1 par default=0
7528 if (is_numeric($thirdparty_seller->localtax1_assuj) && !$thirdparty_seller->localtax1_assuj) {
7529 return 0;
7530 }
7531 if (!is_numeric($thirdparty_seller->localtax1_assuj) && $thirdparty_seller->localtax1_assuj == 'localtax1off') {
7532 return 0;
7533 }
7534 }
7535 } elseif ($local == 2) { //I Localtax 2
7536 // Si vendeur non assujeti a Localtax2, localtax2 par default=0
7537 if (is_numeric($thirdparty_seller->localtax2_assuj) && !$thirdparty_seller->localtax2_assuj) {
7538 return 0;
7539 }
7540 if (!is_numeric($thirdparty_seller->localtax2_assuj) && $thirdparty_seller->localtax2_assuj == 'localtax2off') {
7541 return 0;
7542 }
7543 }
7544
7545 if ($thirdparty_seller->country_code == $thirdparty_buyer->country_code) {
7546 return get_product_localtax_for_country($idprod, $local, $thirdparty_seller);
7547 }
7548
7549 return 0;
7550}
7551
7560function yn($yesno, $case = 1, $color = 0)
7561{
7562 global $langs;
7563
7564 $result = 'unknown';
7565 $classname = '';
7566 if ($yesno == 1 || (isset($yesno) && (strtolower($yesno) == 'yes' || strtolower($yesno) == 'true'))) { // To set to 'no' before the test because of the '== 0'
7567 $result = $langs->trans('yes');
7568 if ($case == 1 || $case == 3) {
7569 $result = $langs->trans("Yes");
7570 }
7571 if ($case == 2) {
7572 $result = '<input type="checkbox" value="1" checked disabled>';
7573 }
7574 if ($case == 3) {
7575 $result = '<input type="checkbox" value="1" checked disabled> '.$result;
7576 }
7577 if ($case == 4) {
7578 $result = img_picto('check', 'check');
7579 }
7580
7581 $classname = 'ok';
7582 } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') {
7583 $result = $langs->trans("no");
7584 if ($case == 1 || $case == 3) {
7585 $result = $langs->trans("No");
7586 }
7587 if ($case == 2) {
7588 $result = '<input type="checkbox" value="0" disabled>';
7589 }
7590 if ($case == 3) {
7591 $result = '<input type="checkbox" value="0" disabled> '.$result;
7592 }
7593 if ($case == 4) {
7594 $result = img_picto('uncheck', 'uncheck');
7595 }
7596
7597 if ($color == 2) {
7598 $classname = 'ok';
7599 } else {
7600 $classname = 'error';
7601 }
7602 }
7603 if ($color) {
7604 return '<span class="'.$classname.'">'.$result.'</span>';
7605 }
7606 return $result;
7607}
7608
7627function get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart = '')
7628{
7629 if (empty($modulepart) && is_object($object)) {
7630 if (!empty($object->module)) {
7631 $modulepart = $object->module;
7632 } elseif (!empty($object->element)) {
7633 $modulepart = $object->element;
7634 }
7635 }
7636
7637 $path = '';
7638
7639 // Define $arrayforoldpath that is module path using a hierarchy on more than 1 level.
7640 $arrayforoldpath = array('cheque' => 2, 'category' => 2, 'holiday' => 2, 'supplier_invoice' => 2, 'invoice_supplier' => 2, 'mailing' => 2, 'supplier_payment' => 2);
7641 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
7642 $arrayforoldpath['product'] = 2;
7643 }
7644
7645 if (empty($level) && array_key_exists($modulepart, $arrayforoldpath)) {
7646 $level = $arrayforoldpath[$modulepart];
7647 }
7648
7649 if (!empty($level) && array_key_exists($modulepart, $arrayforoldpath)) {
7650 // This part should be removed once all code is using "get_exdir" to forge path, with parameter $object and $modulepart provided.
7651 if (empty($num) && is_object($object)) {
7652 $num = $object->id;
7653 }
7654 if (empty($alpha)) {
7655 $num = preg_replace('/([^0-9])/i', '', $num);
7656 } else {
7657 $num = preg_replace('/^.*\-/i', '', $num);
7658 }
7659 $num = substr("000".$num, -$level);
7660 if ($level == 1) {
7661 $path = substr($num, 0, 1);
7662 }
7663 if ($level == 2) {
7664 $path = substr($num, 1, 1).'/'.substr($num, 0, 1);
7665 }
7666 if ($level == 3) {
7667 $path = substr($num, 2, 1).'/'.substr($num, 1, 1).'/'.substr($num, 0, 1);
7668 }
7669 } else {
7670 // We will enhance here a common way of forging path for document storage.
7671 // In a future, we may distribute directories on several levels depending on setup and object.
7672 // Here, $object->id, $object->ref and $modulepart are required.
7673 //var_dump($modulepart);
7674 $path = dol_sanitizeFileName(empty($object->ref) ? (string) ((is_object($object) && property_exists($object, 'id')) ? $object->id : '') : $object->ref);
7675 }
7676
7677 if (empty($withoutslash) && !empty($path)) {
7678 $path .= '/';
7679 }
7680
7681 return $path;
7682}
7683
7692function dol_mkdir($dir, $dataroot = '', $newmask = '')
7693{
7694 global $conf;
7695
7696 dol_syslog("functions.lib::dol_mkdir: dir=".$dir, LOG_INFO);
7697
7698 $dir_osencoded = dol_osencode($dir);
7699 if (@is_dir($dir_osencoded)) {
7700 return 0;
7701 }
7702
7703 $nberr = 0;
7704 $nbcreated = 0;
7705
7706 $ccdir = '';
7707 if (!empty($dataroot)) {
7708 // Remove data root from loop
7709 $dir = str_replace($dataroot.'/', '', $dir);
7710 $ccdir = $dataroot.'/';
7711 }
7712
7713 $cdir = explode("/", $dir);
7714 $num = count($cdir);
7715 for ($i = 0; $i < $num; $i++) {
7716 if ($i > 0) {
7717 $ccdir .= '/'.$cdir[$i];
7718 } else {
7719 $ccdir .= $cdir[$i];
7720 }
7721 $regs = array();
7722 if (preg_match("/^.:$/", $ccdir, $regs)) {
7723 continue; // If the Windows path is incomplete, continue with next directory
7724 }
7725
7726 // Attention, is_dir() can fail event if the directory exists
7727 // (i.e. according the open_basedir configuration)
7728 if ($ccdir) {
7729 $ccdir_osencoded = dol_osencode($ccdir);
7730 if (!@is_dir($ccdir_osencoded)) {
7731 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.", LOG_DEBUG);
7732
7733 umask(0);
7734 $dirmaskdec = octdec((string) $newmask);
7735 if (empty($newmask)) {
7736 $dirmaskdec = !getDolGlobalString('MAIN_UMASK') ? octdec('0755') : octdec($conf->global->MAIN_UMASK);
7737 }
7738 $dirmaskdec |= octdec('0111'); // Set x bit required for directories
7739 if (!@mkdir($ccdir_osencoded, $dirmaskdec)) {
7740 // If the is_dir has returned a false information, we arrive here
7741 dol_syslog("functions.lib::dol_mkdir: Fails to create directory '".$ccdir."' or directory already exists.", LOG_WARNING);
7742 $nberr++;
7743 } else {
7744 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' created", LOG_DEBUG);
7745 $nberr = 0; // At this point in the code, the previous failures can be ignored -> set $nberr to 0
7746 $nbcreated++;
7747 }
7748 } else {
7749 $nberr = 0; // At this point in the code, the previous failures can be ignored -> set $nberr to 0
7750 }
7751 }
7752 }
7753 return ($nberr ? -$nberr : $nbcreated);
7754}
7755
7756
7764function dolChmod($filepath, $newmask = '')
7765{
7766 global $conf;
7767
7768 if (!empty($newmask)) {
7769 @chmod($filepath, octdec($newmask));
7770 } elseif (getDolGlobalString('MAIN_UMASK')) {
7771 @chmod($filepath, octdec($conf->global->MAIN_UMASK));
7772 }
7773}
7774
7775
7781function picto_required()
7782{
7783 return '<span class="fieldrequired">*</span>';
7784}
7785
7786
7803function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = 'UTF-8', $strip_tags = 0, $removedoublespaces = 1)
7804{
7805 if (is_null($stringtoclean)) {
7806 return '';
7807 }
7808
7809 if ($removelinefeed == 2) {
7810 $stringtoclean = preg_replace('/<br[^>]*>(\n|\r)+/ims', '<br>', $stringtoclean);
7811 }
7812 $temp = preg_replace('/<br[^>]*>/i', "\n", $stringtoclean);
7813
7814 // 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)
7815 $temp = dol_html_entity_decode($temp, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7816
7817 $temp = str_replace('< ', '__ltspace__', $temp);
7818 $temp = str_replace('<:', '__lttwopoints__', $temp);
7819
7820 if ($strip_tags) {
7821 $temp = strip_tags($temp);
7822 } else {
7823 // 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).
7824 $pattern = "/<[^<>]+>/";
7825 // Example of $temp: <a href="/myurl" title="<u>A title</u>">0000-021</a>
7826 // pass 1 - $temp after pass 1: <a href="/myurl" title="A title">0000-021
7827 // pass 2 - $temp after pass 2: 0000-021
7828 $tempbis = $temp;
7829 do {
7830 $temp = $tempbis;
7831 $tempbis = str_replace('<>', '', $temp); // No reason to have this into a text, except if value is to try bypass the next html cleaning
7832 $tempbis = preg_replace($pattern, '', $tempbis);
7833 //$idowhile++; print $temp.'-'.$tempbis."\n"; if ($idowhile > 100) break;
7834 } while ($tempbis != $temp);
7835
7836 $temp = $tempbis;
7837
7838 // 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).
7839 $temp = preg_replace('/<+([a-z]+)/i', '\1', $temp);
7840 }
7841
7842 $temp = dol_html_entity_decode($temp, ENT_COMPAT, $pagecodeto);
7843
7844 // Remove also carriage returns
7845 if ($removelinefeed == 1) {
7846 $temp = str_replace(array("\r\n", "\r", "\n"), " ", $temp);
7847 }
7848
7849 // And double quotes
7850 if ($removedoublespaces) {
7851 while (strpos($temp, " ")) {
7852 $temp = str_replace(" ", " ", $temp);
7853 }
7854 }
7855
7856 $temp = str_replace('__ltspace__', '< ', $temp);
7857 $temp = str_replace('__lttwopoints__', '<:', $temp);
7858
7859 return trim($temp);
7860}
7861
7877function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1, $cleanalsojavascript = 0, $allowiframe = 0, $allowed_tags = array(), $allowlink = 0)
7878{
7879 if (empty($allowed_tags)) {
7880 $allowed_tags = array(
7881 "html", "head", "meta", "body", "article", "a", "abbr", "b", "blockquote", "br", "cite", "div", "dl", "dd", "dt", "em", "font", "img", "ins", "hr", "i", "li",
7882 "ol", "p", "q", "s", "span", "strike", "strong", "title", "table", "tr", "th", "td", "u", "ul", "sup", "sub", "blockquote", "pre", "h1", "h2", "h3", "h4", "h5", "h6",
7883 "header", "footer", "nav", "section", "menu", "menuitem" // html5 tags
7884 );
7885 }
7886 $allowed_tags[] = "comment"; // this tags is added to manage comment <!--...--> that are replaced into <comment>...</comment>
7887 if ($allowiframe) {
7888 if (!in_array('iframe', $allowed_tags)) {
7889 $allowed_tags[] = "iframe";
7890 }
7891 }
7892 if ($allowlink) {
7893 if (!in_array('link', $allowed_tags)) {
7894 $allowed_tags[] = "link";
7895 }
7896 }
7897
7898 $allowed_tags_string = implode("><", $allowed_tags);
7899 $allowed_tags_string = '<'.$allowed_tags_string.'>';
7900
7901 $stringtoclean = str_replace('<!DOCTYPE html>', '__!DOCTYPE_HTML__', $stringtoclean); // Replace DOCTYPE to avoid to have it removed by the strip_tags
7902
7903 $stringtoclean = dol_string_nounprintableascii($stringtoclean, 0);
7904
7905 //$stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
7906 $stringtoclean = preg_replace('/<!--([^>]*)-->/', '<comment>\1</comment>', $stringtoclean);
7907
7908 $stringtoclean = preg_replace('/&colon;/i', ':', $stringtoclean);
7909 $stringtoclean = preg_replace('/&#58;|&#0+58|&#x3A/i', '', $stringtoclean); // refused string ':' encoded (no reason to have a : encoded like this) to disable 'javascript:...'
7910
7911 // Remove all HTML tags
7912 $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
7913
7914 if ($cleanalsosomestyles) { // Clean for remaining html tags
7915 $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
7916 }
7917 if ($removeclassattribute) { // Clean for remaining html tags
7918 $temp = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $temp);
7919 }
7920
7921 // Remove 'javascript:' that we should not find into a text with
7922 // 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)).
7923 if ($cleanalsojavascript) {
7924 $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);
7925 }
7926
7927 $temp = str_replace('__!DOCTYPE_HTML__', '<!DOCTYPE html>', $temp); // Restore the DOCTYPE
7928
7929 $temp = preg_replace('/<comment>([^>]*)<\/comment>/', '<!--\1-->', $temp); // Restore html comments
7930
7931
7932 return $temp;
7933}
7934
7935
7948function dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes = null)
7949{
7950 if (is_null($allowed_attributes)) {
7951 $allowed_attributes = array(
7952 "allow", "allowfullscreen", "alt", "class", "contenteditable", "data-html", "frameborder", "height", "href", "id", "name", "src", "style", "target", "title", "width",
7953 // HTML5
7954 "header", "footer", "nav", "section", "menu", "menuitem"
7955 );
7956 }
7957
7958 if (class_exists('DOMDocument') && !empty($stringtoclean)) {
7959 $stringtoclean = '<?xml encoding="UTF-8"><html><body>'.$stringtoclean.'</body></html>';
7960
7961 // Warning: loadHTML does not support HTML5 on old libxml versions.
7962 $dom = new DOMDocument('', 'UTF-8');
7963 // If $stringtoclean is wrong, it will generates warnings. So we disable warnings and restore them later.
7964 $savwarning = error_reporting();
7965 error_reporting(E_ALL & ~E_WARNING & ~E_NOTICE);
7966 $dom->loadHTML($stringtoclean, LIBXML_ERR_NONE | LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_NOXMLDECL);
7967 error_reporting($savwarning);
7968
7969 if ($dom instanceof DOMDocument) {
7970 for ($els = $dom->getElementsByTagname('*'), $i = $els->length - 1; $i >= 0; $i--) {
7971 $el = $els->item($i);
7972 if (!$el instanceof DOMElement) {
7973 continue;
7974 }
7975 $attrs = $el->attributes;
7976 for ($ii = $attrs->length - 1; $ii >= 0; $ii--) {
7977 //var_dump($attrs->item($ii));
7978 if (!empty($attrs->item($ii)->name)) {
7979 if (! in_array($attrs->item($ii)->name, $allowed_attributes)) {
7980 // Delete attribute if not into allowed_attributes @phan-suppress-next-line PhanUndeclaredMethod
7981 $els->item($i)->removeAttribute($attrs->item($ii)->name);
7982 } elseif (in_array($attrs->item($ii)->name, array('style'))) {
7983 // If attribute is 'style'
7984 $valuetoclean = $attrs->item($ii)->value;
7985
7986 if (isset($valuetoclean)) {
7987 do {
7988 $oldvaluetoclean = $valuetoclean;
7989 $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments
7990 $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean);
7991 if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags.
7992 $valuetoclean = preg_replace('/display\s*:/mi', '', $valuetoclean);
7993 $valuetoclean = preg_replace('/z-index\s*:/mi', '', $valuetoclean);
7994 $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*:/mi', '', $valuetoclean);
7995 }
7996
7997 // We do not allow logout|passwordforgotten.php and action= into the content of a "style" tag
7998 $valuetoclean = preg_replace('/(logout|passwordforgotten)\.php/mi', '', $valuetoclean);
7999 $valuetoclean = preg_replace('/action=/mi', '', $valuetoclean);
8000 } while ($oldvaluetoclean != $valuetoclean);
8001 }
8002
8003 $attrs->item($ii)->value = $valuetoclean;
8004 }
8005 }
8006 }
8007 }
8008 }
8009
8010 $return = $dom->saveHTML(); // This may add a LF at end of lines, so we will trim later
8011 //$return = '<html><body>aaaa</p>bb<p>ssdd</p>'."\n<p>aaa</p>aa<p>bb</p>";
8012
8013 $return = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $return);
8014 $return = preg_replace('/^'.preg_quote('<html><body>', '/').'/', '', $return);
8015 $return = preg_replace('/'.preg_quote('</body></html>', '/').'$/', '', $return);
8016 return trim($return);
8017 } else {
8018 return $stringtoclean;
8019 }
8020}
8021
8033function dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags = array('textarea'), $cleanalsosomestyles = 0)
8034{
8035 $temp = $stringtoclean;
8036 foreach ($disallowed_tags as $tagtoremove) {
8037 $temp = preg_replace('/<\/?'.$tagtoremove.'>/', '', $temp);
8038 $temp = preg_replace('/<\/?'.$tagtoremove.'\s+[^>]*>/', '', $temp);
8039 }
8040
8041 if ($cleanalsosomestyles) {
8042 $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
8043 }
8044
8045 return $temp;
8046}
8047
8048
8058function dolGetFirstLineOfText($text, $nboflines = 1, $charset = 'UTF-8')
8059{
8060 if ($nboflines == 1) {
8061 if (dol_textishtml($text)) {
8062 $firstline = preg_replace('/<br[^>]*>.*$/s', '', $text); // The s pattern modifier means the . can match newline characters
8063 $firstline = preg_replace('/<div[^>]*>.*$/s', '', $firstline); // The s pattern modifier means the . can match newline characters
8064 } else {
8065 if (isset($text)) {
8066 $firstline = preg_replace('/[\n\r].*/', '', $text);
8067 } else {
8068 $firstline = '';
8069 }
8070 }
8071 return $firstline.(isset($firstline) && isset($text) && (strlen($firstline) != strlen($text)) ? '...' : '');
8072 } else {
8073 $ishtml = 0;
8074 if (dol_textishtml($text)) {
8075 $text = preg_replace('/\n/', '', $text);
8076 $ishtml = 1;
8077 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
8078 } else {
8079 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
8080 }
8081
8082 $text = strtr($text, $repTable);
8083 if ($charset == 'UTF-8') {
8084 $pattern = '/(<br[^>]*>)/Uu';
8085 } else {
8086 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
8087 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
8088 }
8089 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
8090
8091 $firstline = '';
8092 $i = 0;
8093 $countline = 0;
8094 $lastaddediscontent = 1;
8095 while ($countline < $nboflines && isset($a[$i])) {
8096 if (preg_match('/<br[^>]*>/', $a[$i])) {
8097 if (array_key_exists($i + 1, $a) && !empty($a[$i + 1])) {
8098 $firstline .= ($ishtml ? "<br>\n" : "\n");
8099 // Is it a br for a new line of after a printed line ?
8100 if (!$lastaddediscontent) {
8101 $countline++;
8102 }
8103 $lastaddediscontent = 0;
8104 }
8105 } else {
8106 $firstline .= $a[$i];
8107 $lastaddediscontent = 1;
8108 $countline++;
8109 }
8110 $i++;
8111 }
8112
8113 $adddots = (isset($a[$i]) && (!preg_match('/<br[^>]*>/', $a[$i]) || (array_key_exists($i + 1, $a) && !empty($a[$i + 1]))));
8114 //unset($a);
8115 $ret = $firstline.($adddots ? '...' : '');
8116 //exit;
8117 return $ret;
8118 }
8119}
8120
8121
8133function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false)
8134{
8135 if (is_null($stringtoencode)) {
8136 return '';
8137 }
8138
8139 if (!$nl2brmode) {
8140 return nl2br($stringtoencode, $forxml);
8141 } else {
8142 $ret = preg_replace('/(\r\n|\r|\n)/i', ($forxml ? '<br />' : '<br>'), $stringtoencode);
8143 return $ret;
8144 }
8145}
8146
8156function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = 'restricthtml')
8157{
8158 if (empty($nouseofiframesandbox) && getDolGlobalString('MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS')) {
8159 // TODO using sandbox on inline html content is not possible yet with current browsers
8160 //$s = '<iframe class="iframewithsandbox" sandbox><html><body>';
8161 //$s .= $stringtoencode;
8162 //$s .= '</body></html></iframe>';
8163 return $stringtoencode;
8164 } else {
8165 $out = $stringtoencode;
8166
8167 // First clean HTML content
8168 do {
8169 $oldstringtoclean = $out;
8170
8171 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML') && $check != 'restricthtmlallowunvalid') {
8172 try {
8173 libxml_use_internal_errors(false); // Avoid to fill memory with xml errors
8174 if (LIBXML_VERSION < 20900) {
8175 // Avoid load of external entities (security problem).
8176 // Required only if LIBXML_VERSION < 20900
8177 // @phan-suppress-next-line PhanDeprecatedFunctionInternal
8178 libxml_disable_entity_loader(true);
8179 }
8180
8181 $dom = new DOMDocument();
8182 // Add a trick to solve pb with text without parent tag
8183 // like '<h1>Foo</h1><p>bar</p>' that wrongly ends up, without the trick, with '<h1>Foo<p>bar</p></h1>'
8184 // like 'abc' that wrongly ends up, without the trick, with '<p>abc</p>'
8185
8186 if (dol_textishtml($out)) {
8187 $out = '<?xml encoding="UTF-8"><div class="tricktoremove">'.$out.'</div>';
8188 } else {
8189 $out = '<?xml encoding="UTF-8"><div class="tricktoremove">'.dol_nl2br($out).'</div>';
8190 }
8191
8192 $dom->loadHTML($out, LIBXML_HTML_NODEFDTD | LIBXML_ERR_NONE | LIBXML_HTML_NOIMPLIED | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_NOERROR | LIBXML_NOXMLDECL);
8193 $out = trim($dom->saveHTML());
8194
8195 // Remove the trick added to solve pb with text without parent tag
8196 $out = preg_replace('/^<\?xml encoding="UTF-8"><div class="tricktoremove">/', '', $out);
8197 $out = preg_replace('/<\/div>$/', '', $out);
8198 } catch (Exception $e) {
8199 // If error, invalid HTML string with no way to clean it
8200 //print $e->getMessage();
8201 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
8202 }
8203 }
8204
8205 if (!empty($out) && getDolGlobalString('MAIN_RESTRICTHTML_ONLY_VALID_HTML_TIDY') && $check != 'restricthtmlallowunvalid') {
8206 try {
8207 // Try cleaning using tidy
8208 if (extension_loaded('tidy') && class_exists("tidy")) {
8209 //print "aaa".$out."\n";
8210
8211 // See options at https://tidy.sourceforge.net/docs/quickref.html
8212 $config = array(
8213 'clean' => false,
8214 'quote-marks' => false, // do not replace " that are used for real text content (not a string symbol for html attribute) into &quot;
8215 'doctype' => 'strict',
8216 'show-body-only' => true,
8217 "indent-attributes" => false,
8218 "vertical-space" => false,
8219 //'ident' => false, // Not always supported
8220 "wrap" => 0
8221 // HTML5 tags
8222 //'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',
8223 //'new-blocklevel-tags' => 'footer header section menu menuitem'
8224 //'new-empty-tags' => 'command embed keygen source track wbr',
8225 //'new-inline-tags' => 'audio command datalist embed keygen mark menuitem meter output progress source time video wbr',
8226 );
8227
8228 // Tidy
8229 $tidy = new tidy();
8230 $out = $tidy->repairString($out, $config, 'utf8');
8231
8232 //print "xxx".$out;exit;
8233 }
8234 } catch (Exception $e) {
8235 // If error, invalid HTML string with no way to clean it
8236 //print $e->getMessage();
8237 $out = 'InvalidHTMLStringCantBeCleaned '.$e->getMessage();
8238 }
8239 }
8240
8241 // Clear ZERO WIDTH NO-BREAK SPACE, ZERO WIDTH SPACE, ZERO WIDTH JOINER
8242 $out = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $out);
8243
8244 // Clean some html entities that are useless so text is cleaner
8245 $out = preg_replace('/&(tab|newline);/i', ' ', $out);
8246
8247 // Ckeditor uses the numeric entity for apostrophe so we force it to text entity (all other special chars are
8248 // encoded using text entities) so we can then exclude all numeric entities.
8249 $out = preg_replace('/&#39;/i', '&apos;', $out);
8250
8251 // 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).
8252 // 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
8253 // using a non conventionnal way to be encoded, to not have them sanitized just after)
8254 $out = preg_replace_callback(
8255 '/&#(x?[0-9][0-9a-f]+;?)/i',
8260 static function ($m) {
8261 return realCharForNumericEntities($m);
8262 },
8263 $out
8264 );
8265
8266 // Now we remove all remaining HTML entities starting with a number. We don't want such entities.
8267 $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'.
8268
8269 // Keep only some html tags and remove also some 'javascript:' strings
8270 $out = dol_string_onlythesehtmltags($out, 0, ($check == 'restricthtmlallowclass' ? 0 : 1), 1);
8271
8272 // Keep only some html attributes and exclude non expected HTML attributes and clean content of some attributes (keep only alt=, title=...).
8273 if (getDolGlobalString('MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES')) {
8275 }
8276
8277 // Restore entity &apos; into &#39; (restricthtml is for html content so we can use html entity)
8278 $out = preg_replace('/&apos;/i', "&#39;", $out);
8279
8280 // Now remove js
8281 // List of dom events is on https://www.w3schools.com/jsref/dom_obj_event.asp and https://developer.mozilla.org/en-US/docs/Web/Events
8282 $out = preg_replace('/on(mouse|drag|key|load|touch|pointer|select|transition)[a-z]*\s*=/i', '', $out); // onmousexxx can be set on img or any html tag like <img title='...' onmouseover=alert(1)>
8283 $out = preg_replace('/on(abort|after|animation|auxclick|before|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|copy|cut)[a-z]*\s*=/i', '', $out);
8284 $out = preg_replace('/on(dblclick|drop|durationchange|emptied|end|ended|error|focus|focusin|focusout|formdata|gotpointercapture|hashchange|input|invalid)[a-z]*\s*=/i', '', $out);
8285 $out = preg_replace('/on(lostpointercapture|offline|online|pagehide|pageshow)[a-z]*\s*=/i', '', $out);
8286 $out = preg_replace('/on(paste|pause|play|playing|progress|ratechange|reset|resize|scroll|search|seeked|seeking|show|stalled|start|submit|suspend)[a-z]*\s*=/i', '', $out);
8287 $out = preg_replace('/on(timeupdate|toggle|unload|volumechange|waiting|wheel)[a-z]*\s*=/i', '', $out);
8288 // More not into the previous list
8289 $out = preg_replace('/on(repeat|begin|finish|beforeinput)[a-z]*\s*=/i', '', $out);
8290 } while ($oldstringtoclean != $out);
8291
8292 // Check the limit of external links that are automatically executed in a Rich text content. We count:
8293 // '<img' to avoid <img src="http...">, we can only accept "<img src="data:..."
8294 // 'url(' to avoid inline style like background: url(http...
8295 // '<link' to avoid <link href="http...">
8296 $reg = array();
8297 $tmpout = preg_replace('/<img src="data:/mi', '<__IMG_SRC_DATA__ src="data:', $out);
8298 preg_match_all('/(<img|url\‍(|<link)/i', $tmpout, $reg);
8299 $nblinks = count($reg[0]);
8300 if ($nblinks > getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) {
8301 $out = 'ErrorTooManyLinksIntoHTMLString';
8302 }
8303
8304 if (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 2 || $check == 'restricthtmlnolink') {
8305 if ($nblinks > 0) {
8306 $out = 'ErrorHTMLLinksNotAllowed';
8307 }
8308 } elseif (getDolGlobalInt('MAIN_DISALLOW_URL_INTO_DESCRIPTIONS') == 1) {
8309 $nblinks = 0;
8310 // Loop on each url in src= and url(
8311 $pattern = '/src=["\']?(http[^"\']+)|url\‍(["\']?(http[^\‍)]+)/';
8312
8313 $matches = array();
8314 if (preg_match_all($pattern, $out, $matches)) {
8315 // URLs are into $matches[1]
8316 $urls = $matches[1];
8317
8318 // Affiche les URLs
8319 foreach ($urls as $url) {
8320 $nblinks++;
8321 echo "Found url = ".$url . "\n";
8322 }
8323 if ($nblinks > 0) {
8324 $out = 'ErrorHTMLExternalLinksNotAllowed';
8325 }
8326 }
8327 }
8328
8329 return $out;
8330 }
8331}
8332
8353function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UTF-8', $removelasteolbr = 1)
8354{
8355 if (is_null($stringtoencode)) {
8356 return '';
8357 }
8358
8359 $newstring = $stringtoencode;
8360 if (dol_textishtml($stringtoencode)) { // Check if text is already HTML or not
8361 $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.
8362 if ($removelasteolbr) {
8363 $newstring = preg_replace('/<br>$/i', '', $newstring); // Remove last <br> (remove only last one)
8364 }
8365 $newstring = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}]/u', ' ', $newstring);
8366 $newstring = strtr($newstring, array('&' => '__and__', '<' => '__lt__', '>' => '__gt__', '"' => '__dquot__'));
8367 $newstring = dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom); // Make entity encoding
8368 $newstring = strtr($newstring, array('__and__' => '&', '__lt__' => '<', '__gt__' => '>', '__dquot__' => '"'));
8369 } else {
8370 if ($removelasteolbr) {
8371 $newstring = preg_replace('/(\r\n|\r|\n)$/i', '', $newstring); // Remove last \n (may remove several)
8372 }
8373 $newstring = dol_nl2br(dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom), $nl2brmode);
8374 }
8375 // Other substitutions that htmlentities does not do
8376 //$newstring=str_replace(chr(128),'&euro;',$newstring); // 128 = 0x80. Not in html entity table. // Seems useles with TCPDF. Make bug with UTF8 languages
8377 return $newstring;
8378}
8379
8387function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8')
8388{
8389 $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT | ENT_HTML5, $pagecodeto);
8390 $ret = preg_replace('/'."\r\n".'<br(\s[\sa-zA-Z_="]*)?\/?>/i', "<br>", $ret);
8391 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\r\n".'/i', "\r\n", $ret);
8392 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\n".'/i', "\n", $ret);
8393 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', "\n", $ret);
8394 return $ret;
8395}
8396
8403function dol_htmlcleanlastbr($stringtodecode)
8404{
8405 $ret = preg_replace('/&nbsp;$/i', "", $stringtodecode); // Because wysiwyg editor may add a &nbsp; at end of last line
8406 $ret = preg_replace('/(<br>|<br(\s[\sa-zA-Z_="]*)?\/?>|'."\n".'|'."\r".')+$/i', "", $ret);
8407 return $ret;
8408}
8409
8419function dol_html_entity_decode($a, $b, $c = 'UTF-8', $keepsomeentities = 0)
8420{
8421 $newstring = $a;
8422 if ($keepsomeentities) {
8423 $newstring = strtr($newstring, array('&amp;' => '__andamp__', '&lt;' => '__andlt__', '&gt;' => '__andgt__', '"' => '__dquot__'));
8424 }
8425 $newstring = html_entity_decode((string) $newstring, (int) $b, (string) $c);
8426 if ($keepsomeentities) {
8427 $newstring = strtr($newstring, array('__andamp__' => '&amp;', '__andlt__' => '&lt;', '__andgt__' => '&gt;', '__dquot__' => '"'));
8428 }
8429 return $newstring;
8430}
8431
8443function dol_htmlentities($string, $flags = ENT_QUOTES | ENT_SUBSTITUTE, $encoding = 'UTF-8', $double_encode = false)
8444{
8445 return htmlentities($string, $flags, $encoding, $double_encode);
8446}
8447
8459function dol_string_is_good_iso($s, $clean = 0)
8460{
8461 $len = dol_strlen($s);
8462 $out = '';
8463 $ok = 1;
8464 for ($scursor = 0; $scursor < $len; $scursor++) {
8465 $ordchar = ord($s[$scursor]);
8466 //print $scursor.'-'.$ordchar.'<br>';
8467 if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) {
8468 $ok = 0;
8469 break;
8470 } elseif ($ordchar > 126 && $ordchar < 160) {
8471 $ok = 0;
8472 break;
8473 } elseif ($clean) {
8474 $out .= $s[$scursor];
8475 }
8476 }
8477 if ($clean) {
8478 return $out;
8479 }
8480 return $ok;
8481}
8482
8491function dol_nboflines($s, $maxchar = 0)
8492{
8493 if ($s == '') {
8494 return 0;
8495 }
8496 $arraystring = explode("\n", $s);
8497 $nb = count($arraystring);
8498
8499 return $nb;
8500}
8501
8502
8512function dol_nboflines_bis($text, $maxlinesize = 0, $charset = 'UTF-8')
8513{
8514 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
8515 if (dol_textishtml($text)) {
8516 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
8517 }
8518
8519 $text = strtr($text, $repTable);
8520 if ($charset == 'UTF-8') {
8521 $pattern = '/(<br[^>]*>)/Uu';
8522 } else {
8523 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
8524 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
8525 }
8526 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
8527
8528 $nblines = (int) floor((count($a) + 1) / 2);
8529 // count possible auto line breaks
8530 if ($maxlinesize) {
8531 foreach ($a as $line) {
8532 if (dol_strlen($line) > $maxlinesize) {
8533 //$line_dec = html_entity_decode(strip_tags($line));
8534 $line_dec = html_entity_decode($line);
8535 if (dol_strlen($line_dec) > $maxlinesize) {
8536 $line_dec = wordwrap($line_dec, $maxlinesize, '\n', true);
8537 $nblines += substr_count($line_dec, '\n');
8538 }
8539 }
8540 }
8541 }
8542
8543 unset($a);
8544 return $nblines;
8545}
8546
8555function dol_textishtml($msg, $option = 0)
8556{
8557 if (is_null($msg)) {
8558 return false;
8559 }
8560
8561 if ($option == 1) {
8562 if (preg_match('/<html/i', $msg)) {
8563 return true;
8564 } elseif (preg_match('/<body/i', $msg)) {
8565 return true;
8566 } elseif (preg_match('/<\/textarea/i', $msg)) {
8567 return true;
8568 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8569 return true;
8570 } elseif (preg_match('/<br/i', $msg)) {
8571 return true;
8572 }
8573 return false;
8574 } else {
8575 // Remove all urls because 'http://aa?param1=abc&amp;param2=def' must not be used inside detection
8576 $msg = preg_replace('/https?:\/\/[^"\'\s]+/i', '', $msg);
8577 if (preg_match('/<html/i', $msg)) {
8578 return true;
8579 } elseif (preg_match('/<body/i', $msg)) {
8580 return true;
8581 } elseif (preg_match('/<\/textarea/i', $msg)) {
8582 return true;
8583 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
8584 return true;
8585 } elseif (preg_match('/<(br|hr)\/>/i', $msg)) {
8586 return true;
8587 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)>/i', $msg)) {
8588 return true;
8589 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)\s+[^<>\/]*\/?>/i', $msg)) {
8590 return true;
8591 } elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i', $msg)) {
8592 return true; // must accept <img src="http://example.com/aaa.png" />
8593 } elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i', $msg)) {
8594 return true; // must accept <a href="http://example.com/aaa.png" />
8595 } elseif (preg_match('/<h[0-9]>/i', $msg)) {
8596 return true;
8597 } elseif (preg_match('/&[A-Z0-9]{1,6};/i', $msg)) {
8598 // TODO If content is 'A link https://aaa?param=abc&amp;param2=def', it return true but must be false
8599 return true; // Html entities names (http://www.w3schools.com/tags/ref_entities.asp)
8600 } elseif (preg_match('/&#[0-9]{2,3};/i', $msg)) {
8601 return true; // Html entities numbers (http://www.w3schools.com/tags/ref_entities.asp)
8602 }
8603
8604 return false;
8605 }
8606}
8607
8622function dol_concatdesc($text1, $text2, $forxml = false, $invert = false)
8623{
8624 if (!empty($invert)) {
8625 $tmp = $text1;
8626 $text1 = $text2;
8627 $text2 = $tmp;
8628 }
8629
8630 $ret = '';
8631 $ret .= (!dol_textishtml($text1) && dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text1, 0, 1, '', 1), 0, $forxml) : $text1;
8632 $ret .= (!empty($text1) && !empty($text2)) ? ((dol_textishtml($text1) || dol_textishtml($text2)) ? ($forxml ? "<br >\n" : "<br>\n") : "\n") : "";
8633 $ret .= (dol_textishtml($text1) && !dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text2, 0, 1, '', 1), 0, $forxml) : $text2;
8634 return $ret;
8635}
8636
8637
8638
8652function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null)
8653{
8654 global $db, $conf, $mysoc, $user, $extrafields;
8655
8656 $substitutionarray = array();
8657
8658 if ((empty($exclude) || !in_array('user', $exclude)) && (empty($include) || in_array('user', $include))) {
8659 // Add SIGNATURE into substitutionarray first, so, when we will make the substitution,
8660 // this will include signature content first and then replace var found into content of signature
8661 //var_dump($onlykey);
8662 $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()
8663 $usersignature = $user->signature;
8664 $substitutionarray = array_merge($substitutionarray, array(
8665 '__SENDEREMAIL_SIGNATURE__' => (string) ((!getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc('SignatureFromTheSelectedSenderProfile', 30) : $emailsendersignature) : ''),
8666 '__USER_SIGNATURE__' => (string) (($usersignature && !getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN')) ? ($onlykey == 2 ? dol_trunc(dol_string_nohtmltag($usersignature), 30) : $usersignature) : '')
8667 ));
8668
8669 if (is_object($user) && ($user instanceof User)) {
8670 $substitutionarray = array_merge($substitutionarray, array(
8671 '__USER_ID__' => (string) $user->id,
8672 '__USER_LOGIN__' => (string) $user->login,
8673 '__USER_EMAIL__' => (string) $user->email,
8674 '__USER_PHONE__' => (string) dol_print_phone($user->office_phone, '', 0, 0, '', " ", '', '', -1),
8675 '__USER_PHONEPRO__' => (string) dol_print_phone($user->user_mobile, '', 0, 0, '', " ", '', '', -1),
8676 '__USER_PHONEMOBILE__' => (string) dol_print_phone($user->personal_mobile, '', 0, 0, '', " ", '', '', -1),
8677 '__USER_FAX__' => (string) $user->office_fax,
8678 '__USER_LASTNAME__' => (string) $user->lastname,
8679 '__USER_FIRSTNAME__' => (string) $user->firstname,
8680 '__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
8681 '__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
8682 '__USER_JOB__' => (string) $user->job,
8683 '__USER_REMOTE_IP__' => (string) getUserRemoteIP(),
8684 '__USER_VCARD_URL__' => (string) $user->getOnlineVirtualCardUrl('', 'external')
8685 ));
8686 }
8687 }
8688 if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc) && (empty($include) || in_array('mycompany', $include))) {
8689 $substitutionarray = array_merge($substitutionarray, array(
8690 '__MYCOMPANY_NAME__' => $mysoc->name,
8691 '__MYCOMPANY_EMAIL__' => $mysoc->email,
8692 '__MYCOMPANY_PHONE__' => dol_print_phone($mysoc->phone, '', 0, 0, '', " ", '', '', -1),
8693 '__MYCOMPANY_FAX__' => dol_print_phone($mysoc->fax, '', 0, 0, '', " ", '', '', -1),
8694 '__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
8695 '__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
8696 '__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
8697 '__MYCOMPANY_PROFID4__' => $mysoc->idprof4,
8698 '__MYCOMPANY_PROFID5__' => $mysoc->idprof5,
8699 '__MYCOMPANY_PROFID6__' => $mysoc->idprof6,
8700 '__MYCOMPANY_PROFID7__' => $mysoc->idprof7,
8701 '__MYCOMPANY_PROFID8__' => $mysoc->idprof8,
8702 '__MYCOMPANY_PROFID9__' => $mysoc->idprof9,
8703 '__MYCOMPANY_PROFID10__' => $mysoc->idprof10,
8704 '__MYCOMPANY_CAPITAL__' => $mysoc->capital,
8705 '__MYCOMPANY_FULLADDRESS__' => (method_exists($mysoc, 'getFullAddress') ? $mysoc->getFullAddress(1, ', ') : ''), // $mysoc may be stdClass
8706 '__MYCOMPANY_ADDRESS__' => $mysoc->address,
8707 '__MYCOMPANY_ZIP__' => $mysoc->zip,
8708 '__MYCOMPANY_TOWN__' => $mysoc->town,
8709 '__MYCOMPANY_COUNTRY__' => $mysoc->country,
8710 '__MYCOMPANY_COUNTRY_ID__' => $mysoc->country_id,
8711 '__MYCOMPANY_COUNTRY_CODE__' => $mysoc->country_code,
8712 '__MYCOMPANY_CURRENCY_CODE__' => $conf->currency
8713 ));
8714 }
8715
8716 if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude)) && (empty($include) || in_array('object', $include))) {
8717 if ($onlykey) {
8718 $substitutionarray['__ID__'] = '__ID__';
8719 $substitutionarray['__REF__'] = '__REF__';
8720 $substitutionarray['__NEWREF__'] = '__NEWREF__';
8721 $substitutionarray['__LABEL__'] = '__LABEL__';
8722 $substitutionarray['__REF_CLIENT__'] = '__REF_CLIENT__';
8723 $substitutionarray['__REF_SUPPLIER__'] = '__REF_SUPPLIER__';
8724 $substitutionarray['__NOTE_PUBLIC__'] = '__NOTE_PUBLIC__';
8725 $substitutionarray['__NOTE_PRIVATE__'] = '__NOTE_PRIVATE__';
8726 $substitutionarray['__EXTRAFIELD_XXX__'] = '__EXTRAFIELD_XXX__';
8727
8728 if (isModEnabled("societe")) { // Most objects are concerned
8729 $substitutionarray['__THIRDPARTY_ID__'] = '__THIRDPARTY_ID__';
8730 $substitutionarray['__THIRDPARTY_NAME__'] = '__THIRDPARTY_NAME__';
8731 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = '__THIRDPARTY_NAME_ALIAS__';
8732 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = '__THIRDPARTY_CODE_CLIENT__';
8733 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = '__THIRDPARTY_CODE_FOURNISSEUR__';
8734 $substitutionarray['__THIRDPARTY_EMAIL__'] = '__THIRDPARTY_EMAIL__';
8735 //$substitutionarray['__THIRDPARTY_EMAIL_URLENCODED__'] = '__THIRDPARTY_EMAIL_URLENCODED__'; // We hide this one
8736 $substitutionarray['__THIRDPARTY_PHONE__'] = '__THIRDPARTY_PHONE__';
8737 $substitutionarray['__THIRDPARTY_FAX__'] = '__THIRDPARTY_FAX__';
8738 $substitutionarray['__THIRDPARTY_ADDRESS__'] = '__THIRDPARTY_ADDRESS__';
8739 $substitutionarray['__THIRDPARTY_ZIP__'] = '__THIRDPARTY_ZIP__';
8740 $substitutionarray['__THIRDPARTY_TOWN__'] = '__THIRDPARTY_TOWN__';
8741 $substitutionarray['__THIRDPARTY_IDPROF1__'] = '__THIRDPARTY_IDPROF1__';
8742 $substitutionarray['__THIRDPARTY_IDPROF2__'] = '__THIRDPARTY_IDPROF2__';
8743 $substitutionarray['__THIRDPARTY_IDPROF3__'] = '__THIRDPARTY_IDPROF3__';
8744 $substitutionarray['__THIRDPARTY_IDPROF4__'] = '__THIRDPARTY_IDPROF4__';
8745 $substitutionarray['__THIRDPARTY_IDPROF5__'] = '__THIRDPARTY_IDPROF5__';
8746 $substitutionarray['__THIRDPARTY_IDPROF6__'] = '__THIRDPARTY_IDPROF6__';
8747 $substitutionarray['__THIRDPARTY_IDPROF7__'] = '__THIRDPARTY_IDPROF7__';
8748 $substitutionarray['__THIRDPARTY_IDPROF8__'] = '__THIRDPARTY_IDPROF8__';
8749 $substitutionarray['__THIRDPARTY_IDPROF9__'] = '__THIRDPARTY_IDPROF9__';
8750 $substitutionarray['__THIRDPARTY_IDPROF10__'] = '__THIRDPARTY_IDPROF10__';
8751 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = '__THIRDPARTY_TVAINTRA__';
8752 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = '__THIRDPARTY_NOTE_PUBLIC__';
8753 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = '__THIRDPARTY_NOTE_PRIVATE__';
8754 }
8755 if (isModEnabled('member') && (!is_object($object) || $object->element == 'adherent') && (empty($exclude) || !in_array('member', $exclude)) && (empty($include) || in_array('member', $include))) {
8756 $substitutionarray['__MEMBER_ID__'] = '__MEMBER_ID__';
8757 $substitutionarray['__MEMBER_CIVILITY__'] = '__MEMBER_CIVILITY__';
8758 $substitutionarray['__MEMBER_FIRSTNAME__'] = '__MEMBER_FIRSTNAME__';
8759 $substitutionarray['__MEMBER_LASTNAME__'] = '__MEMBER_LASTNAME__';
8760 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = 'Login and pass of the external user account';
8761 /*$substitutionarray['__MEMBER_NOTE_PUBLIC__'] = '__MEMBER_NOTE_PUBLIC__';
8762 $substitutionarray['__MEMBER_NOTE_PRIVATE__'] = '__MEMBER_NOTE_PRIVATE__';*/
8763 }
8764 // add substitution variables for ticket
8765 if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket') && (empty($exclude) || !in_array('ticket', $exclude)) && (empty($include) || in_array('ticket', $include))) {
8766 $substitutionarray['__TICKET_TRACKID__'] = '__TICKET_TRACKID__';
8767 $substitutionarray['__TICKET_SUBJECT__'] = '__TICKET_SUBJECT__';
8768 $substitutionarray['__TICKET_TYPE__'] = '__TICKET_TYPE__';
8769 $substitutionarray['__TICKET_SEVERITY__'] = '__TICKET_SEVERITY__';
8770 $substitutionarray['__TICKET_CATEGORY__'] = '__TICKET_CATEGORY__';
8771 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = '__TICKET_ANALYTIC_CODE__';
8772 $substitutionarray['__TICKET_MESSAGE__'] = '__TICKET_MESSAGE__';
8773 $substitutionarray['__TICKET_PROGRESSION__'] = '__TICKET_PROGRESSION__';
8774 $substitutionarray['__TICKET_USER_ASSIGN__'] = '__TICKET_USER_ASSIGN__';
8775 }
8776
8777 if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature') && (empty($exclude) || !in_array('recruitment', $exclude)) && (empty($include) || in_array('recruitment', $include))) {
8778 $substitutionarray['__CANDIDATE_FULLNAME__'] = '__CANDIDATE_FULLNAME__';
8779 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = '__CANDIDATE_FIRSTNAME__';
8780 $substitutionarray['__CANDIDATE_LASTNAME__'] = '__CANDIDATE_LASTNAME__';
8781 }
8782 if (isModEnabled('project') && (empty($exclude) || !in_array('project', $exclude)) && (empty($include) || in_array('project', $include))) { // Most objects
8783 $substitutionarray['__PROJECT_ID__'] = '__PROJECT_ID__';
8784 $substitutionarray['__PROJECT_REF__'] = '__PROJECT_REF__';
8785 $substitutionarray['__PROJECT_NAME__'] = '__PROJECT_NAME__';
8786 /*$substitutionarray['__PROJECT_NOTE_PUBLIC__'] = '__PROJECT_NOTE_PUBLIC__';
8787 $substitutionarray['__PROJECT_NOTE_PRIVATE__'] = '__PROJECT_NOTE_PRIVATE__';*/
8788 }
8789 if (isModEnabled('contract') && (!is_object($object) || $object->element == 'contract') && (empty($exclude) || !in_array('contract', $exclude)) && (empty($include) || in_array('contract', $include))) {
8790 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = 'Highest date planned for a service start';
8791 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = 'Highest date and hour planned for service start';
8792 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = 'Lowest data for planned expiration of service';
8793 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = 'Lowest date and hour for planned expiration of service';
8794 }
8795 if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal') && (empty($exclude) || !in_array('propal', $exclude)) && (empty($include) || in_array('propal', $include))) {
8796 $substitutionarray['__ONLINE_SIGN_URL__'] = 'ToOfferALinkForOnlineSignature';
8797 }
8798 if (isModEnabled("intervention") && (!is_object($object) || $object->element == 'fichinter') && (empty($exclude) || !in_array('intervention', $exclude)) && (empty($include) || in_array('intervention', $include))) {
8799 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = 'ToOfferALinkForOnlineSignature';
8800 }
8801 $substitutionarray['__ONLINE_PAYMENT_URL__'] = 'UrlToPayOnlineIfApplicable';
8802 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = 'TextAndUrlToPayOnlineIfApplicable';
8803 $substitutionarray['__SECUREKEYPAYMENT__'] = 'Security key (if key is not unique per record)';
8804 $substitutionarray['__SECUREKEYPAYMENT_MEMBER__'] = 'Security key for payment on a member subscription (one key per member)';
8805 $substitutionarray['__SECUREKEYPAYMENT_ORDER__'] = 'Security key for payment on an order';
8806 $substitutionarray['__SECUREKEYPAYMENT_INVOICE__'] = 'Security key for payment on an invoice';
8807 $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'Security key for payment on a service of a contract';
8808
8809 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = 'Direct download url of a proposal';
8810 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = 'Direct download url of an order';
8811 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = 'Direct download url of an invoice';
8812 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = 'Direct download url of a contract';
8813 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = 'Direct download url of a supplier proposal';
8814
8815 if (isModEnabled("shipping") && (!is_object($object) || $object->element == 'shipping')) {
8816 $substitutionarray['__SHIPPINGTRACKNUM__'] = 'Shipping tracking number';
8817 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = 'Shipping tracking url';
8818 $substitutionarray['__SHIPPINGMETHOD__'] = 'Shipping method';
8819 }
8820 if (isModEnabled("reception") && (!is_object($object) || $object->element == 'reception')) {
8821 $substitutionarray['__RECEPTIONTRACKNUM__'] = 'Shipping tracking number of shipment';
8822 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = 'Shipping tracking url';
8823 }
8824 } else {
8825 '@phan-var-force Adherent|Delivery $object';
8826 $substitutionarray['__ID__'] = $object->id;
8827 $substitutionarray['__REF__'] = $object->ref;
8828 $substitutionarray['__NEWREF__'] = $object->newref;
8829 $substitutionarray['__LABEL__'] = (isset($object->label) ? $object->label : (isset($object->title) ? $object->title : null));
8830 $substitutionarray['__REF_CLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8831 $substitutionarray['__REF_SUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8832 $substitutionarray['__NOTE_PUBLIC__'] = (isset($object->note_public) ? $object->note_public : null);
8833 $substitutionarray['__NOTE_PRIVATE__'] = (isset($object->note_private) ? $object->note_private : null);
8834 $substitutionarray['__DATE_CREATION__'] = (isset($object->date_creation) ? dol_print_date($object->date_creation, 'day', 0, $outputlangs) : '');
8835 $substitutionarray['__DATE_MODIFICATION__'] = (isset($object->date_modification) ? dol_print_date($object->date_modification, 'day', 0, $outputlangs) : '');
8836 $substitutionarray['__DATE_VALIDATION__'] = (isset($object->date_validation) ? dol_print_date($object->date_validation, 'day', 0, $outputlangs) : '');
8837 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, 'day', 0, $outputlangs) : '');
8838 $substitutionarray['__DATE_DELIVERY_DAY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%d") : '');
8839 $substitutionarray['__DATE_DELIVERY_DAY_TEXT__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%A") : '');
8840 $substitutionarray['__DATE_DELIVERY_MON__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%m") : '');
8841 $substitutionarray['__DATE_DELIVERY_MON_TEXT__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%b") : '');
8842 $substitutionarray['__DATE_DELIVERY_YEAR__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%Y") : '');
8843 $substitutionarray['__DATE_DELIVERY_HH__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%H") : '');
8844 $substitutionarray['__DATE_DELIVERY_MM__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%M") : '');
8845 $substitutionarray['__DATE_DELIVERY_SS__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, "%S") : '');
8846
8847 // For backward compatibility (deprecated)
8848 $substitutionarray['__REFCLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8849 $substitutionarray['__REFSUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8850 $substitutionarray['__SUPPLIER_ORDER_DATE_DELIVERY__'] = (isset($object->delivery_date) ? dol_print_date($object->delivery_date, 'day', 0, $outputlangs) : '');
8851 $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 : '')) : '');
8852 $substitutionarray['__EXPIRATION_DATE__'] = (isset($object->fin_validite) ? dol_print_date($object->fin_validite, 'daytext') : '');
8853
8854 if (is_object($object) && ($object->element == 'adherent' || $object->element == 'member') && $object->id > 0) {
8855 '@phan-var-force Adherent $object';
8856 $birthday = (empty($object->birth) ? '' : dol_print_date($object->birth, 'day'));
8857
8858 $substitutionarray['__MEMBER_ID__'] = (isset($object->id) ? $object->id : '');
8859 if (method_exists($object, 'getCivilityLabel')) {
8860 $substitutionarray['__MEMBER_CIVILITY__'] = $object->getCivilityLabel();
8861 }
8862 $substitutionarray['__MEMBER_FIRSTNAME__'] = (isset($object->firstname) ? $object->firstname : '');
8863 $substitutionarray['__MEMBER_LASTNAME__'] = (isset($object->lastname) ? $object->lastname : '');
8864 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = '';
8865 if (method_exists($object, 'getFullName')) {
8866 $substitutionarray['__MEMBER_FULLNAME__'] = $object->getFullName($outputlangs);
8867 }
8868 $substitutionarray['__MEMBER_COMPANY__'] = (isset($object->societe) ? $object->societe : '');
8869 $substitutionarray['__MEMBER_ADDRESS__'] = (isset($object->address) ? $object->address : '');
8870 $substitutionarray['__MEMBER_ZIP__'] = (isset($object->zip) ? $object->zip : '');
8871 $substitutionarray['__MEMBER_TOWN__'] = (isset($object->town) ? $object->town : '');
8872 $substitutionarray['__MEMBER_COUNTRY__'] = (isset($object->country) ? $object->country : '');
8873 $substitutionarray['__MEMBER_EMAIL__'] = (isset($object->email) ? $object->email : '');
8874 $substitutionarray['__MEMBER_BIRTH__'] = (isset($birthday) ? $birthday : '');
8875 $substitutionarray['__MEMBER_PHOTO__'] = (isset($object->photo) ? $object->photo : '');
8876 $substitutionarray['__MEMBER_LOGIN__'] = (isset($object->login) ? $object->login : '');
8877 $substitutionarray['__MEMBER_PASSWORD__'] = (isset($object->pass) ? $object->pass : '');
8878 $substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? dol_print_phone($object->phone) : '');
8879 $substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? dol_print_phone($object->phone_perso) : '');
8880 $substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? dol_print_phone($object->phone_mobile) : '');
8881 $substitutionarray['__MEMBER_TYPE__'] = (isset($object->type) ? $object->type : '');
8882 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__'] = dol_print_date($object->first_subscription_date, 'day');
8883
8884 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_RFC__'] = dol_print_date($object->first_subscription_date, 'dayrfc');
8885 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = (isset($object->first_subscription_date_start) ? dol_print_date($object->first_subscription_date_start, 'day') : '');
8886 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START_RFC__'] = (isset($object->first_subscription_date_start) ? dol_print_date($object->first_subscription_date_start, 'dayrfc') : '');
8887 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END__'] = (isset($object->first_subscription_date_end) ? dol_print_date($object->first_subscription_date_end, 'day') : '');
8888 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END_RFC__'] = (isset($object->first_subscription_date_end) ? dol_print_date($object->first_subscription_date_end, 'dayrfc') : '');
8889 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE__'] = dol_print_date($object->last_subscription_date, 'day');
8890 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_RFC__'] = dol_print_date($object->last_subscription_date, 'dayrfc');
8891 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->last_subscription_date_start, 'day');
8892 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START_RFC__'] = dol_print_date($object->last_subscription_date_start, 'dayrfc');
8893 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END__'] = dol_print_date($object->last_subscription_date_end, 'day');
8894 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END_RFC__'] = dol_print_date($object->last_subscription_date_end, 'dayrfc');
8895 }
8896
8897 if (is_object($object) && $object->element == 'societe') {
8898 '@phan-var-force Societe $object';
8899 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object) ? $object->id : '');
8900 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object) ? $object->name : '');
8901 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object) ? $object->name_alias : '');
8902 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object) ? $object->code_client : '');
8903 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object) ? $object->code_fournisseur : '');
8904 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object) ? $object->email : '');
8905 $substitutionarray['__THIRDPARTY_EMAIL_URLENCODED__'] = urlencode(is_object($object) ? $object->email : '');
8906 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? dol_print_phone($object->phone) : '');
8907 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? dol_print_phone($object->fax) : '');
8908 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object) ? $object->address : '');
8909 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object) ? $object->zip : '');
8910 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object) ? $object->town : '');
8911 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object) ? $object->country_id : '');
8912 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object) ? $object->country_code : '');
8913 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object) ? $object->idprof1 : '');
8914 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object) ? $object->idprof2 : '');
8915 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object) ? $object->idprof3 : '');
8916 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object) ? $object->idprof4 : '');
8917 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object) ? $object->idprof5 : '');
8918 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object) ? $object->idprof6 : '');
8919 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object) ? $object->tva_intra : '');
8920 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_public) : '');
8921 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_private) : '');
8922 } elseif (is_object($object->thirdparty)) {
8923 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->id : '');
8924 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object->thirdparty) ? $object->thirdparty->name : '');
8925 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object->thirdparty) ? $object->thirdparty->name_alias : '');
8926 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_client : '');
8927 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_fournisseur : '');
8928 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object->thirdparty) ? $object->thirdparty->email : '');
8929 $substitutionarray['__THIRDPARTY_EMAIL_URLENCODED__'] = urlencode(is_object($object->thirdparty) ? $object->thirdparty->email : '');
8930 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->phone) : '');
8931 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->fax) : '');
8932 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object->thirdparty) ? $object->thirdparty->address : '');
8933 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object->thirdparty) ? $object->thirdparty->zip : '');
8934 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object->thirdparty) ? $object->thirdparty->town : '');
8935 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_id : '');
8936 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_code : '');
8937 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof1 : '');
8938 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof2 : '');
8939 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof3 : '');
8940 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof4 : '');
8941 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof5 : '');
8942 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof6 : '');
8943 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object->thirdparty) ? $object->thirdparty->tva_intra : '');
8944 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_public) : '');
8945 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_private) : '');
8946 }
8947
8948 if (is_object($object) && $object->element == 'recruitmentcandidature') {
8949 '@phan-var-force RecruitmentCandidature $object';
8950 $substitutionarray['__CANDIDATE_FULLNAME__'] = $object->getFullName($outputlangs);
8951 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8952 $substitutionarray['__CANDIDATE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8953 }
8954 if (is_object($object) && $object->element == 'conferenceorboothattendee') {
8955 '@phan-var-force ConferenceOrBoothAttendee $object';
8956 $substitutionarray['__ATTENDEE_FULLNAME__'] = $object->getFullName($outputlangs);
8957 $substitutionarray['__ATTENDEE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8958 $substitutionarray['__ATTENDEE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8959 }
8960
8961 if (is_object($object) && $object->element == 'project') {
8962 '@phan-var-force Project $object';
8963 $substitutionarray['__PROJECT_ID__'] = $object->id;
8964 $substitutionarray['__PROJECT_REF__'] = $object->ref;
8965 $substitutionarray['__PROJECT_NAME__'] = $object->title;
8966 } elseif (is_object($object)) {
8967 $project = null;
8968 if (!empty($object->project)) {
8969 $project = $object->project;
8970 } elseif (!empty($object->projet)) { // Deprecated, for backward compatibility
8971 $project = $object->projet;
8972 }
8973 if (!is_null($project) && is_object($project)) {
8974 $substitutionarray['__PROJECT_ID__'] = $project->id;
8975 $substitutionarray['__PROJECT_REF__'] = $project->ref;
8976 $substitutionarray['__PROJECT_NAME__'] = $project->title;
8977 } else {
8978 // can substitute variables for project : uses lazy load in "make_substitutions" method
8979 $project_id = 0;
8980 if (!empty($object->fk_project) && $object->fk_project > 0) {
8981 $project_id = $object->fk_project;
8982 } elseif (!empty($object->fk_projet) && $object->fk_projet > 0) {
8983 $project_id = $object->fk_project;
8984 }
8985 if ($project_id > 0) {
8986 // path:class:method:id
8987 $substitutionarray['__PROJECT_ID__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8988 $substitutionarray['__PROJECT_REF__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8989 $substitutionarray['__PROJECT_NAME__@lazyload'] = '/projet/class/project.class.php:Project:fetchAndSetSubstitution:' . $project_id;
8990 }
8991 }
8992 }
8993
8994 if (is_object($object) && $object->element == 'facture') {
8995 '@phan-var-force Facture $object';
8996 $substitutionarray['__INVOICE_SITUATION_NUMBER__'] = isset($object->situation_counter) ? $object->situation_counter : '';
8997 }
8998 if (is_object($object) && $object->element == 'shipping') {
8999 '@phan-var-force Expedition $object';
9000 $substitutionarray['__SHIPPINGTRACKNUM__'] = $object->tracking_number;
9001 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = $object->tracking_url;
9002 $substitutionarray['__SHIPPINGMETHOD__'] = $object->shipping_method;
9003 }
9004 if (is_object($object) && $object->element == 'reception') {
9005 '@phan-var-force Reception $object';
9006 $substitutionarray['__RECEPTIONTRACKNUM__'] = $object->tracking_number;
9007 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = $object->tracking_url;
9008 }
9009
9010 if (is_object($object) && $object->element == 'contrat' && $object->id > 0 && is_array($object->lines)) {
9011 '@phan-var-force Contrat $object';
9012 $dateplannedstart = '';
9013 $datenextexpiration = '';
9014 foreach ($object->lines as $line) {
9015 if ($line->date_start > $dateplannedstart) {
9016 $dateplannedstart = $line->date_start;
9017 }
9018 if ($line->statut == 4 && $line->date_end && (!$datenextexpiration || $line->date_end < $datenextexpiration)) {
9019 $datenextexpiration = $line->date_end;
9020 }
9021 }
9022 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = dol_print_date($dateplannedstart, 'day');
9023 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE_RFC__'] = dol_print_date($dateplannedstart, 'dayrfc');
9024 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = dol_print_date($dateplannedstart, 'standard');
9025
9026 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = dol_print_date($datenextexpiration, 'day');
9027 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE_RFC__'] = dol_print_date($datenextexpiration, 'dayrfc');
9028 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = dol_print_date($datenextexpiration, 'standard');
9029 }
9030 // add substitution variables for ticket
9031 if (is_object($object) && $object->element == 'ticket') {
9032 '@phan-var-force Ticket $object';
9033 $substitutionarray['__TICKET_TRACKID__'] = $object->track_id;
9034 $substitutionarray['__TICKET_SUBJECT__'] = $object->subject;
9035 $substitutionarray['__TICKET_TYPE__'] = $object->type_code;
9036 $substitutionarray['__TICKET_SEVERITY__'] = $object->severity_code;
9037 $substitutionarray['__TICKET_CATEGORY__'] = $object->category_code; // For backward compatibility
9038 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = $object->category_code;
9039 $substitutionarray['__TICKET_MESSAGE__'] = $object->message;
9040 $substitutionarray['__TICKET_PROGRESSION__'] = $object->progress;
9041 $userstat = new User($db);
9042 if ($object->fk_user_assign > 0) {
9043 $userstat->fetch($object->fk_user_assign);
9044 $substitutionarray['__TICKET_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
9045 }
9046
9047 if ($object->fk_user_create > 0) {
9048 $userstat->fetch($object->fk_user_create);
9049 $substitutionarray['__USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
9050 }
9051 }
9052
9053 // Create dynamic tags for __EXTRAFIELD_FIELD__
9054 if ($object->table_element && $object->id > 0) {
9055 if (!is_object($extrafields)) {
9056 $extrafields = new ExtraFields($db);
9057 }
9058 $extrafields->fetch_name_optionals_label($object->table_element, true);
9059
9060 if ($object->fetch_optionals() > 0) {
9061 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) {
9062 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
9063 if ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
9064 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_date($object->array_options['options_'.$key], 'day');
9065 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = dol_print_date($object->array_options['options_'.$key], 'day', 'tzserver', $outputlangs);
9066 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = dol_print_date($object->array_options['options_'.$key], 'dayrfc');
9067 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'datetime') {
9068 $datetime = $object->array_options['options_'.$key];
9069 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour') : '');
9070 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : '');
9071 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_DAY_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'day', 'tzserver', $outputlangs) : '');
9072 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : '');
9073 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'phone') {
9074 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_phone($object->array_options['options_'.$key]);
9075 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
9076 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = $object->array_options['options_'.$key];
9077 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATED__'] = price($object->array_options['options_'.$key]); // For compatibility
9078 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATTED__'] = price($object->array_options['options_'.$key]);
9079 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] != 'separator') {
9080 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = !empty($object->array_options['options_'.$key]) ? $object->array_options['options_'.$key] : '';
9081 }
9082 }
9083 }
9084 }
9085 }
9086
9087 // Complete substitution array with the url to make online payment
9088 if (empty($substitutionarray['__REF__'])) {
9089 $paymenturl = '';
9090 } else {
9091 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
9092 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
9093 $outputlangs->loadLangs(array('paypal', 'other'));
9094
9095 $amounttouse = 0;
9096 $typeforonlinepayment = 'free';
9097 if (is_object($object) && $object->element == 'commande') {
9098 $typeforonlinepayment = 'order';
9099 }
9100 if (is_object($object) && $object->element == 'facture') {
9101 $typeforonlinepayment = 'invoice';
9102 }
9103 if (is_object($object) && $object->element == 'member') {
9104 $typeforonlinepayment = 'member';
9105 if (!empty($object->last_subscription_amount)) {
9106 $amounttouse = $object->last_subscription_amount;
9107 }
9108 }
9109 if (is_object($object) && $object->element == 'contrat') {
9110 $typeforonlinepayment = 'contract';
9111 }
9112 if (is_object($object) && $object->element == 'fichinter') {
9113 $typeforonlinepayment = 'ficheinter';
9114 }
9115
9116 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__'], $amounttouse);
9117 $paymenturl = $url;
9118 }
9119
9120 if ($object->id > 0) {
9121 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ? str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : '');
9122 $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl;
9123
9124 if (getDolGlobalString('PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'propal') {
9125 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
9126 } else {
9127 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = '';
9128 }
9129 if (getDolGlobalString('ORDER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'commande') {
9130 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = $object->getLastMainDocLink($object->element);
9131 } else {
9132 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = '';
9133 }
9134 if (getDolGlobalString('INVOICE_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'facture') {
9135 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = $object->getLastMainDocLink($object->element);
9136 } else {
9137 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = '';
9138 }
9139 if (getDolGlobalString('CONTRACT_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'contrat') {
9140 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = $object->getLastMainDocLink($object->element);
9141 } else {
9142 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = '';
9143 }
9144 if (getDolGlobalString('FICHINTER_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'fichinter') {
9145 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = $object->getLastMainDocLink($object->element);
9146 } else {
9147 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = '';
9148 }
9149 if (getDolGlobalString('SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD') && is_object($object) && $object->element == 'supplier_proposal') {
9150 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
9151 } else {
9152 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = '';
9153 }
9154
9155 if (is_object($object) && $object->element == 'propal') {
9156 '@phan-var-force Propal $object';
9157 $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id;
9158 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
9159 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref, 1, $object);
9160 }
9161 if (is_object($object) && $object->element == 'commande') {
9162 '@phan-var-force Commande $object';
9163 $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id;
9164 }
9165 if (is_object($object) && $object->element == 'facture') {
9166 '@phan-var-force Facture $object';
9167 $substitutionarray['__URL_INVOICE__'] = DOL_MAIN_URL_ROOT."/compta/facture/card.php?id=".$object->id;
9168 }
9169 if (is_object($object) && $object->element == 'contrat') {
9170 '@phan-var-force Contrat $object';
9171 $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id;
9172 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
9173 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref, 1, $object);
9174 }
9175 if (is_object($object) && $object->element == 'fichinter') {
9176 '@phan-var-force Fichinter $object';
9177 $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id;
9178 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
9179 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref, 1, $object);
9180 }
9181 if (is_object($object) && $object->element == 'supplier_proposal') {
9182 '@phan-var-force SupplierProposal $object';
9183 $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id;
9184 }
9185 if (is_object($object) && $object->element == 'invoice_supplier') {
9186 '@phan-var-force FactureFournisseur $object';
9187 $substitutionarray['__URL_SUPPLIER_INVOICE__'] = DOL_MAIN_URL_ROOT."/fourn/facture/card.php?id=".$object->id;
9188 }
9189 if (is_object($object) && $object->element == 'shipping') {
9190 '@phan-var-force Expedition $object';
9191 $substitutionarray['__URL_SHIPMENT__'] = DOL_MAIN_URL_ROOT."/expedition/card.php?id=".$object->id;
9192 }
9193 }
9194
9195 if (is_object($object) && $object->element == 'action') {
9196 '@phan-var-force ActionComm $object';
9197 $substitutionarray['__EVENT_LABEL__'] = $object->label;
9198 $substitutionarray['__EVENT_TYPE__'] = $outputlangs->trans("Action".$object->type_code);
9199 $substitutionarray['__EVENT_DATE__'] = dol_print_date($object->datep, 'day', 'auto', $outputlangs);
9200 $substitutionarray['__EVENT_TIME__'] = dol_print_date($object->datep, 'hour', 'auto', $outputlangs);
9201 }
9202 }
9203 }
9204 if ((empty($exclude) || !in_array('objectamount', $exclude)) && (empty($include) || in_array('objectamount', $include))) {
9205 '@phan-var-force Facture|FactureRec $object';
9206 include_once DOL_DOCUMENT_ROOT.'/core/lib/functionsnumtoword.lib.php';
9207
9208 $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : '';
9209 $substitutionarray['__DATE_DUE_YMD__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs) : null) : '';
9210 $substitutionarray['__DATE_YMD_TEXT__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'daytext', 0, $outputlangs) : null) : '';
9211 $substitutionarray['__DATE_DUE_YMD_TEXT__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'daytext', 0, $outputlangs) : null) : '';
9212
9213 $already_payed_all = 0;
9214 if (is_object($object) && ($object instanceof Facture)) {
9215 $already_payed_all = $object->sumpayed + $object->sumdeposit + $object->sumcreditnote;
9216 }
9217
9218 $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : '';
9219 $substitutionarray['__AMOUNT_EXCL_TAX_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ht, $outputlangs, '', true) : '';
9220 $substitutionarray['__AMOUNT_EXCL_TAX_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ht, $outputlangs, $conf->currency, true) : '';
9221
9222 $substitutionarray['__AMOUNT__'] = is_object($object) ? $object->total_ttc : '';
9223 $substitutionarray['__AMOUNT_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, '', true) : '';
9224 $substitutionarray['__AMOUNT_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, $conf->currency, true) : '';
9225
9226 $substitutionarray['__AMOUNT_REMAIN__'] = is_object($object) ? price2num($object->total_ttc - $already_payed_all, 'MT') : '';
9227
9228 $substitutionarray['__AMOUNT_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
9229 $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)) : '';
9230 $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)) : '';
9231
9232 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
9233 $substitutionarray['__AMOUNT_TAX2__'] = is_object($object) ? $object->total_localtax1 : '';
9234 }
9235 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
9236 $substitutionarray['__AMOUNT_TAX3__'] = is_object($object) ? $object->total_localtax2 : '';
9237 }
9238
9239 // Amount keys formatted in a currency
9240 $substitutionarray['__AMOUNT_EXCL_TAX_FORMATTED__'] = is_object($object) ? ($object->total_ht ? price($object->total_ht, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
9241 $substitutionarray['__AMOUNT_FORMATTED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
9242 $substitutionarray['__AMOUNT_REMAIN_FORMATTED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc - $already_payed_all, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
9243 $substitutionarray['__AMOUNT_VAT_FORMATTED__'] = 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)) : '';
9244 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
9245 $substitutionarray['__AMOUNT_TAX2_FORMATTED__'] = is_object($object) ? ($object->total_localtax1 ? price($object->total_localtax1, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
9246 }
9247 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
9248 $substitutionarray['__AMOUNT_TAX3_FORMATTED__'] = is_object($object) ? ($object->total_localtax2 ? price($object->total_localtax2, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
9249 }
9250 // Amount keys formatted in a currency (with the typo error for backward compatibility)
9251 if ($onlykey != 2) {
9252 $substitutionarray['__AMOUNT_EXCL_TAX_FORMATED__'] = $substitutionarray['__AMOUNT_EXCL_TAX_FORMATTED__'];
9253 $substitutionarray['__AMOUNT_FORMATED__'] = $substitutionarray['__AMOUNT_FORMATTED__'];
9254 $substitutionarray['__AMOUNT_REMAIN_FORMATED__'] = $substitutionarray['__AMOUNT_REMAIN_FORMATTED__'];
9255 $substitutionarray['__AMOUNT_VAT_FORMATED__'] = $substitutionarray['__AMOUNT_VAT_FORMATTED__'];
9256 if ($mysoc instanceof Societe && $mysoc->useLocalTax(1)) {
9257 $substitutionarray['__AMOUNT_TAX2_FORMATED__'] = $substitutionarray['__AMOUNT_TAX2_FORMATTED__'];
9258 }
9259 if ($mysoc instanceof Societe && $mysoc->useLocalTax(2)) {
9260 $substitutionarray['__AMOUNT_TAX3_FORMATED__'] = $substitutionarray['__AMOUNT_TAX3_FORMATTED__'];
9261 }
9262 }
9263
9264 $substitutionarray['__AMOUNT_MULTICURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? $object->multicurrency_total_ttc : '';
9265 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXT__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, '', true) : '';
9266 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXTCURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, $object->multicurrency_code, true) : '';
9267 // TODO Add other keys for foreign multicurrency
9268
9269 // For backward compatibility
9270 if ($onlykey != 2) {
9271 $substitutionarray['__TOTAL_TTC__'] = is_object($object) ? $object->total_ttc : '';
9272 $substitutionarray['__TOTAL_HT__'] = is_object($object) ? $object->total_ht : '';
9273 $substitutionarray['__TOTAL_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
9274 }
9275 }
9276
9277
9278 if ((empty($exclude) || !in_array('date', $exclude)) && (empty($include) || in_array('date', $include))) {
9279 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
9280
9281 $now = dol_now();
9282
9283 $tmp = dol_getdate($now, true);
9284 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
9285 $tmp3 = dol_get_prev_month($tmp['mon'], $tmp['year']);
9286 $tmp4 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
9287 $tmp5 = dol_get_next_month($tmp['mon'], $tmp['year']);
9288
9289 $daytext = $outputlangs->trans('Day'.$tmp['wday']);
9290
9291 $substitutionarray = array_merge($substitutionarray, array(
9292 '__NOW_TMS__' => (string) $now, // Must be the string that represent the int
9293 '__NOW_TMS_YMD__' => dol_print_date($now, 'day', 'auto', $outputlangs),
9294 '__DAY__' => (string) $tmp['mday'],
9295 '__DAY_TEXT__' => $daytext, // Monday
9296 '__DAY_TEXT_SHORT__' => dol_trunc($daytext, 3, 'right', 'UTF-8', 1), // Mon
9297 '__DAY_TEXT_MIN__' => dol_trunc($daytext, 1, 'right', 'UTF-8', 1), // M
9298 '__MONTH__' => (string) $tmp['mon'],
9299 '__MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp['mon'])),
9300 '__MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp['mon'])),
9301 '__MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp['mon'])),
9302 '__YEAR__' => (string) $tmp['year'],
9303 '__PREVIOUS_DAY__' => (string) $tmp2['day'],
9304 '__PREVIOUS_MONTH__' => (string) $tmp3['month'],
9305 '__PREVIOUS_YEAR__' => (string) ($tmp['year'] - 1),
9306 '__NEXT_DAY__' => (string) $tmp4['day'],
9307 '__NEXT_MONTH__' => (string) $tmp5['month'],
9308 '__NEXT_MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp5['month'])),
9309 '__NEXT_MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp5['month'])),
9310 '__NEXT_MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp5['month'])),
9311 '__NEXT_YEAR__' => (string) ($tmp['year'] + 1),
9312 ));
9313 }
9314
9315 if (isModEnabled('multicompany')) {
9316 $substitutionarray = array_merge($substitutionarray, array('__ENTITY_ID__' => $conf->entity));
9317 }
9318 if ((empty($exclude) || !in_array('system', $exclude)) && (empty($include) || in_array('user', $include))) {
9319 $substitutionarray['__DOL_MAIN_URL_ROOT__'] = DOL_MAIN_URL_ROOT;
9320 $substitutionarray['__(AnyTranslationKey)__'] = $outputlangs->trans('TranslationOfKey');
9321 $substitutionarray['__(AnyTranslationKey|langfile)__'] = $outputlangs->trans('TranslationOfKey').' (load also language file before)';
9322 $substitutionarray['__[AnyConstantKey]__'] = $outputlangs->trans('ValueOfConstantKey');
9323 }
9324
9325 // Note: The lazyload variables are replaced only during the call by make_substitutions, and only if necessary
9326
9327 return $substitutionarray;
9328}
9329
9346function make_substitutions($text, $substitutionarray, $outputlangs = null, $converttextinhtmlifnecessary = 0)
9347{
9348 global $conf, $db, $langs;
9349
9350 if (!is_array($substitutionarray)) {
9351 return 'ErrorBadParameterSubstitutionArrayWhenCalling_make_substitutions';
9352 }
9353
9354 if (empty($outputlangs)) {
9355 $outputlangs = $langs;
9356 }
9357
9358 // Is initial text HTML or simple text ?
9359 $msgishtml = 0;
9360 if (dol_textishtml($text, 1)) {
9361 $msgishtml = 1;
9362 }
9363
9364 // Make substitution for language keys: __(AnyTranslationKey)__ or __(AnyTranslationKey|langfile)__
9365 if (is_object($outputlangs)) {
9366 $reg = array();
9367 while (preg_match('/__\‍(([^\‍)]+)\‍)__/', $text, $reg)) {
9368 // If key is __(TranslationKey|langfile)__, then force load of langfile.lang
9369 $tmp = explode('|', $reg[1]);
9370 if (!empty($tmp[1])) {
9371 $outputlangs->load($tmp[1]);
9372 }
9373
9374 $value = $outputlangs->transnoentitiesnoconv($reg[1]);
9375
9376 if (empty($converttextinhtmlifnecessary)) {
9377 // convert $newval into HTML is necessary
9378 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
9379 } else {
9380 if (! $msgishtml) {
9381 $valueishtml = dol_textishtml($value, 1);
9382 //var_dump("valueishtml=".$valueishtml);
9383
9384 if ($valueishtml) {
9385 $text = dol_htmlentitiesbr($text);
9386 $msgishtml = 1;
9387 }
9388 } else {
9389 $value = dol_nl2br("$value");
9390 }
9391
9392 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $value, $text);
9393 }
9394 }
9395 }
9396
9397 // Make substitution for constant keys.
9398 // Must be after the substitution of translation, so if the text of translation contains a string __[xxx]__, it is also converted.
9399 $reg = array();
9400 while (preg_match('/__\[([^\]]+)\]__/', $text, $reg)) {
9401 $keyfound = $reg[1];
9402 if (isASecretKey($keyfound)) {
9403 $value = '*****forbidden*****';
9404 } else {
9405 $value = empty($conf->global->$keyfound) ? '' : $conf->global->$keyfound;
9406 }
9407
9408 if (empty($converttextinhtmlifnecessary)) {
9409 // convert $newval into HTML is necessary
9410 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
9411 } else {
9412 if (! $msgishtml) {
9413 $valueishtml = dol_textishtml($value, 1);
9414
9415 if ($valueishtml) {
9416 $text = dol_htmlentitiesbr($text);
9417 $msgishtml = 1;
9418 }
9419 } else {
9420 $value = dol_nl2br("$value");
9421 }
9422
9423 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $value, $text);
9424 }
9425 }
9426
9427 // Make substitution for array $substitutionarray
9428 foreach ($substitutionarray as $key => $value) {
9429 if (!isset($value)) {
9430 continue; // If value is null, it same than not having substitution key at all into array, we do not replace.
9431 }
9432
9433 if (($key == '__USER_SIGNATURE__' || $key == '__SENDEREMAIL_SIGNATURE__') && (getDolGlobalString('MAIN_MAIL_DO_NOT_USE_SIGN'))) {
9434 $value = ''; // Protection
9435 }
9436
9437 if (empty($converttextinhtmlifnecessary)) {
9438 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
9439 } else {
9440 if (! $msgishtml) {
9441 $valueishtml = dol_textishtml($value, 1);
9442
9443 if ($valueishtml) {
9444 $text = dol_htmlentitiesbr($text);
9445 $msgishtml = 1;
9446 }
9447 } else {
9448 $value = dol_nl2br("$value");
9449 }
9450 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
9451 }
9452 }
9453
9454 // TODO Implement the lazyload substitution
9455 /*
9456 add a loop to scan $substitutionarray:
9457 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.
9458 If no, we don't need to make replacement, so we do nothing.
9459 If yes, we can make the substitution:
9460
9461 include_once $path;
9462 $tmpobj = new $class($db);
9463 $valuetouseforsubstitution = $tmpobj->$method($id, '__XXX__');
9464 And make the replacement of "__XXX__@lazyload" with $valuetouseforsubstitution
9465 */
9466 $memory_object_list = array();
9467 foreach ($substitutionarray as $key => $value) {
9468 $lazy_load_arr = array();
9469 if (preg_match('/(__[A-Z\_]+__)@lazyload$/', $key, $lazy_load_arr)) {
9470 if (isset($lazy_load_arr[1]) && !empty($lazy_load_arr[1])) {
9471 $key_to_substitute = $lazy_load_arr[1];
9472 if (preg_match('/' . preg_quote($key_to_substitute, '/') . '/', $text)) {
9473 $param_arr = explode(':', $value);
9474 // path:class:method:id
9475 if (count($param_arr) == 4) {
9476 $path = $param_arr[0];
9477 $class = $param_arr[1];
9478 $method = $param_arr[2];
9479 $id = (int) $param_arr[3];
9480
9481 // load class file and init object list in memory
9482 if (!isset($memory_object_list[$class])) {
9483 if (dol_is_file(DOL_DOCUMENT_ROOT . $path)) {
9484 require_once DOL_DOCUMENT_ROOT . $path;
9485 if (class_exists($class)) {
9486 $memory_object_list[$class] = array(
9487 'list' => array(),
9488 );
9489 }
9490 }
9491 }
9492
9493 // fetch object and set substitution
9494 if (isset($memory_object_list[$class]) && isset($memory_object_list[$class]['list'])) {
9495 if (method_exists($class, $method)) {
9496 if (!isset($memory_object_list[$class]['list'][$id])) {
9497 $tmpobj = new $class($db);
9498 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
9499 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute);
9500 $memory_object_list[$class]['list'][$id] = $tmpobj;
9501 } else {
9502 // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
9503 $tmpobj = $memory_object_list[$class]['list'][$id];
9504 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
9505 $valuetouseforsubstitution = $tmpobj->$method($id, $key_to_substitute, true);
9506 }
9507
9508 $text = str_replace("$key_to_substitute", "$valuetouseforsubstitution", $text); // We must keep the " to work when value is 123.5 for example
9509 }
9510 }
9511 }
9512 }
9513 }
9514 }
9515 }
9516
9517 return $text;
9518}
9519
9532function complete_substitutions_array(&$substitutionarray, $outputlangs, $object = null, $parameters = null, $callfunc = "completesubstitutionarray")
9533{
9534 global $conf, $user;
9535
9536 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
9537
9538 // Note: substitution key for each extrafields, using key __EXTRA_XXX__ is already available into the getCommonSubstitutionArray used to build the substitution array.
9539
9540 // Check if there is external substitution to do, requested by plugins
9541 $dirsubstitutions = array_merge(array(), (array) $conf->modules_parts['substitutions']);
9542
9543 foreach ($dirsubstitutions as $reldir) {
9544 $dir = dol_buildpath($reldir, 0);
9545
9546 // Check if directory exists
9547 if (!dol_is_dir($dir)) {
9548 continue;
9549 }
9550
9551 $substitfiles = dol_dir_list($dir, 'files', 0, 'functions_');
9552 foreach ($substitfiles as $substitfile) {
9553 $reg = array();
9554 if (preg_match('/functions_(.*)\.lib\.php/i', $substitfile['name'], $reg)) {
9555 $module = $reg[1];
9556
9557 dol_syslog("Library ".$substitfile['name']." found into ".$dir);
9558 // Include the user's functions file
9559 require_once $dir.$substitfile['name'];
9560 // Call the user's function, and only if it is defined
9561 $function_name = $module."_".$callfunc;
9562 if (function_exists($function_name)) {
9563 $function_name($substitutionarray, $outputlangs, $object, $parameters);
9564 }
9565 }
9566 }
9567 }
9568 if (getDolGlobalString('ODT_ENABLE_ALL_TAGS_IN_SUBSTITUTIONS')) {
9569 // to list all tags in odt template
9570 $tags = '';
9571 foreach ($substitutionarray as $key => $value) {
9572 $tags .= '{'.$key.'} => '.$value."\n";
9573 }
9574 $substitutionarray = array_merge($substitutionarray, array('__ALL_TAGS__' => $tags));
9575 }
9576}
9577
9587function print_date_range($date_start, $date_end, $format = '', $outputlangs = null)
9588{
9589 print get_date_range($date_start, $date_end, $format, $outputlangs);
9590}
9591
9602function get_date_range($date_start, $date_end, $format = '', $outputlangs = null, $withparenthesis = 1)
9603{
9604 global $langs;
9605
9606 $out = '';
9607
9608 if (!is_object($outputlangs)) {
9609 $outputlangs = $langs;
9610 }
9611
9612 if ($date_start && $date_end) {
9613 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFromTo', dol_print_date($date_start, $format, false, $outputlangs), dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9614 }
9615 if ($date_start && !$date_end) {
9616 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($date_start, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9617 }
9618 if (!$date_start && $date_end) {
9619 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
9620 }
9621
9622 return $out;
9623}
9624
9633function dolGetFirstLastname($firstname, $lastname, $nameorder = -1)
9634{
9635 global $conf;
9636
9637 $ret = '';
9638 // If order not defined, we use the setup
9639 if ($nameorder < 0) {
9640 $nameorder = (!getDolGlobalString('MAIN_FIRSTNAME_NAME_POSITION') ? 1 : 0);
9641 }
9642 if ($nameorder == 1) {
9643 $ret .= $firstname;
9644 if ($firstname && $lastname) {
9645 $ret .= ' ';
9646 }
9647 $ret .= $lastname;
9648 } elseif ($nameorder == 2 || $nameorder == 3) {
9649 $ret .= $firstname;
9650 if (empty($ret) && $nameorder == 3) {
9651 $ret .= $lastname;
9652 }
9653 } else { // 0, 4 or 5
9654 $ret .= $lastname;
9655 if (empty($ret) && $nameorder == 5) {
9656 $ret .= $firstname;
9657 }
9658 if ($nameorder == 0) {
9659 if ($firstname && $lastname) {
9660 $ret .= ' ';
9661 }
9662 $ret .= $firstname;
9663 }
9664 }
9665 return $ret;
9666}
9667
9668
9680function setEventMessage($mesgs, $style = 'mesgs', $noduplicate = 0)
9681{
9682 //dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING); This is not deprecated, it is used by setEventMessages function
9683 if (!is_array($mesgs)) {
9684 $mesgs = trim((string) $mesgs);
9685 // If mesgs is a not an empty string
9686 if ($mesgs) {
9687 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesgs, $_SESSION['dol_events'][$style])) {
9688 return;
9689 }
9690 $_SESSION['dol_events'][$style][] = $mesgs;
9691 }
9692 } else {
9693 // If mesgs is an array
9694 foreach ($mesgs as $mesg) {
9695 $mesg = trim((string) $mesg);
9696 if ($mesg) {
9697 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesg, $_SESSION['dol_events'][$style])) {
9698 return;
9699 }
9700 $_SESSION['dol_events'][$style][] = $mesg;
9701 }
9702 }
9703 }
9704}
9705
9718function setEventMessages($mesg, $mesgs, $style = 'mesgs', $messagekey = '', $noduplicate = 0)
9719{
9720 if (empty($mesg) && empty($mesgs)) {
9721 dol_syslog("Try to add a message in stack, but value to add is empty message", LOG_WARNING);
9722 } else {
9723 if ($messagekey) {
9724 // Complete message with a js link to set a cookie "DOLHIDEMESSAGE".$messagekey;
9725 // TODO
9726 $mesg .= '';
9727 }
9728 if (empty($messagekey) || empty($_COOKIE["DOLHIDEMESSAGE".$messagekey])) {
9729 if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
9730 dol_print_error(null, 'Bad parameter style='.$style.' for setEventMessages');
9731 }
9732 if (empty($mesgs)) {
9733 setEventMessage($mesg, $style, $noduplicate);
9734 } else {
9735 if (!empty($mesg) && !in_array($mesg, $mesgs)) {
9736 setEventMessage($mesg, $style, $noduplicate); // Add message string if not already into array
9737 }
9738 setEventMessage($mesgs, $style, $noduplicate);
9739 }
9740 }
9741 }
9742}
9743
9753function dol_htmloutput_events($disabledoutputofmessages = 0)
9754{
9755 // Show mesgs
9756 if (isset($_SESSION['dol_events']['mesgs'])) {
9757 if (empty($disabledoutputofmessages)) {
9758 dol_htmloutput_mesg('', $_SESSION['dol_events']['mesgs']);
9759 }
9760 unset($_SESSION['dol_events']['mesgs']);
9761 }
9762 // Show errors
9763 if (isset($_SESSION['dol_events']['errors'])) {
9764 if (empty($disabledoutputofmessages)) {
9765 dol_htmloutput_mesg('', $_SESSION['dol_events']['errors'], 'error');
9766 }
9767 unset($_SESSION['dol_events']['errors']);
9768 }
9769
9770 // Show warnings
9771 if (isset($_SESSION['dol_events']['warnings'])) {
9772 if (empty($disabledoutputofmessages)) {
9773 dol_htmloutput_mesg('', $_SESSION['dol_events']['warnings'], 'warning');
9774 }
9775 unset($_SESSION['dol_events']['warnings']);
9776 }
9777}
9778
9793function get_htmloutput_mesg($mesgstring = '', $mesgarray = [], $style = 'ok', $keepembedded = 0)
9794{
9795 global $conf, $langs;
9796
9797 $ret = 0;
9798 $return = '';
9799 $out = '';
9800 $divstart = $divend = '';
9801
9802 // If inline message with no format, we add it.
9803 if ((empty($conf->use_javascript_ajax) || getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') || $keepembedded) && !preg_match('/<div class=".*">/i', $out)) {
9804 $divstart = '<div class="'.$style.' clearboth">';
9805 $divend = '</div>';
9806 }
9807
9808 if ((is_array($mesgarray) && count($mesgarray)) || $mesgstring) {
9809 $langs->load("errors");
9810 $out .= $divstart;
9811 if (is_array($mesgarray) && count($mesgarray)) {
9812 foreach ($mesgarray as $message) {
9813 $ret++;
9814 $out .= $langs->trans($message);
9815 if ($ret < count($mesgarray)) {
9816 $out .= "<br>\n";
9817 }
9818 }
9819 }
9820 if ($mesgstring) {
9821 $ret++;
9822 $out .= $langs->trans($mesgstring);
9823 }
9824 $out .= $divend;
9825 }
9826
9827 if ($out) {
9828 if (!empty($conf->use_javascript_ajax) && !getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') && empty($keepembedded)) {
9829 $return = '<script nonce="'.getNonce().'">
9830 $(document).ready(function() {
9831 var block = '.(getDolGlobalString('MAIN_USE_JQUERY_BLOCKUI') ? "true" : "false").'
9832 if (block) {
9833 $.dolEventValid("","'.dol_escape_js($out).'");
9834 } else {
9835 /* jnotify(message, preset of message type, keepmessage) */
9836 $.jnotify("'.dol_escape_js($out).'",
9837 "'.($style == "ok" ? 3000 : $style).'",
9838 '.($style == "ok" ? "false" : "true").',
9839 { remove: function (){} } );
9840 }
9841 });
9842 </script>';
9843 } else {
9844 $return = $out;
9845 }
9846 }
9847
9848 return $return;
9849}
9850
9862function get_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9863{
9864 return get_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9865}
9866
9880function dol_htmloutput_mesg($mesgstring = '', $mesgarray = array(), $style = 'ok', $keepembedded = 0)
9881{
9882 if (empty($mesgstring) && (!is_array($mesgarray) || count($mesgarray) == 0)) {
9883 return;
9884 }
9885
9886 $iserror = 0;
9887 $iswarning = 0;
9888 if (is_array($mesgarray)) {
9889 foreach ($mesgarray as $val) {
9890 if ($val && preg_match('/class="error"/i', $val)) {
9891 $iserror++;
9892 break;
9893 }
9894 if ($val && preg_match('/class="warning"/i', $val)) {
9895 $iswarning++;
9896 break;
9897 }
9898 }
9899 } elseif ($mesgstring && preg_match('/class="error"/i', $mesgstring)) {
9900 $iserror++;
9901 } elseif ($mesgstring && preg_match('/class="warning"/i', $mesgstring)) {
9902 $iswarning++;
9903 }
9904 if ($style == 'error') {
9905 $iserror++;
9906 }
9907 if ($style == 'warning') {
9908 $iswarning++;
9909 }
9910
9911 if ($iserror || $iswarning) {
9912 // Remove div from texts
9913 $mesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $mesgstring);
9914 $mesgstring = preg_replace('/<div class="(error|warning)">/', '', $mesgstring);
9915 $mesgstring = preg_replace('/<\/div>/', '', $mesgstring);
9916 // Remove div from texts array
9917 if (is_array($mesgarray)) {
9918 $newmesgarray = array();
9919 foreach ($mesgarray as $val) {
9920 if (is_string($val)) {
9921 $tmpmesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $val);
9922 $tmpmesgstring = preg_replace('/<div class="(error|warning)">/', '', $tmpmesgstring);
9923 $tmpmesgstring = preg_replace('/<\/div>/', '', $tmpmesgstring);
9924 $newmesgarray[] = $tmpmesgstring;
9925 } else {
9926 dol_syslog("Error call of dol_htmloutput_mesg with an array with a value that is not a string", LOG_WARNING);
9927 }
9928 }
9929 $mesgarray = $newmesgarray;
9930 }
9931 print get_htmloutput_mesg($mesgstring, $mesgarray, ($iserror ? 'error' : 'warning'), $keepembedded);
9932 } else {
9933 print get_htmloutput_mesg($mesgstring, $mesgarray, 'ok', $keepembedded);
9934 }
9935}
9936
9948function dol_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9949{
9950 dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9951}
9952
9966function dol_sort_array(&$array, $index, $order = 'asc', $natsort = 0, $case_sensitive = 0, $keepindex = 0)
9967{
9968 // Clean parameters
9969 $order = strtolower($order);
9970
9971 if (is_array($array)) {
9972 $sizearray = count($array);
9973 if ($sizearray > 0) {
9974 $temp = array();
9975 foreach (array_keys($array) as $key) {
9976 if (is_object($array[$key])) {
9977 $temp[$key] = empty($array[$key]->$index) ? 0 : $array[$key]->$index;
9978 } else {
9979 // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
9980 $temp[$key] = empty($array[$key][$index]) ? 0 : $array[$key][$index];
9981 }
9982 if ($natsort == -1) {
9983 $temp[$key] = '___'.$temp[$key]; // We add a string at begin of value to force an alpha order when using asort.
9984 }
9985 }
9986
9987 if (empty($natsort) || $natsort == -1) {
9988 if ($order == 'asc') {
9989 asort($temp);
9990 } else {
9991 arsort($temp);
9992 }
9993 } else {
9994 if ($case_sensitive) {
9995 natsort($temp);
9996 } else {
9997 natcasesort($temp); // natecasesort is not sensible to case
9998 }
9999 if ($order != 'asc') {
10000 $temp = array_reverse($temp, true);
10001 }
10002 }
10003
10004 $sorted = array();
10005
10006 foreach (array_keys($temp) as $key) {
10007 (is_numeric($key) && empty($keepindex)) ? $sorted[] = $array[$key] : $sorted[$key] = $array[$key];
10008 }
10009
10010 return $sorted;
10011 }
10012 }
10013 return $array;
10014}
10015
10016
10024function utf8_check($str)
10025{
10026 $str = (string) $str; // Sometimes string is an int.
10027
10028 // We must use here a binary strlen function (so not dol_strlen)
10029 $strLength = strlen($str);
10030 for ($i = 0; $i < $strLength; $i++) {
10031 if (ord($str[$i]) < 0x80) {
10032 continue; // 0bbbbbbb
10033 } elseif ((ord($str[$i]) & 0xE0) == 0xC0) {
10034 $n = 1; // 110bbbbb
10035 } elseif ((ord($str[$i]) & 0xF0) == 0xE0) {
10036 $n = 2; // 1110bbbb
10037 } elseif ((ord($str[$i]) & 0xF8) == 0xF0) {
10038 $n = 3; // 11110bbb
10039 } elseif ((ord($str[$i]) & 0xFC) == 0xF8) {
10040 $n = 4; // 111110bb
10041 } elseif ((ord($str[$i]) & 0xFE) == 0xFC) {
10042 $n = 5; // 1111110b
10043 } else {
10044 return false; // Does not match any model
10045 }
10046 for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
10047 if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80)) {
10048 return false;
10049 }
10050 }
10051 }
10052 return true;
10053}
10054
10062function utf8_valid($str)
10063{
10064 /* 2 other methods to test if string is utf8
10065 $validUTF8 = mb_check_encoding($messagetext, 'UTF-8');
10066 $validUTF8b = ! (false === mb_detect_encoding($messagetext, 'UTF-8', true));
10067 */
10068 return preg_match('//u', $str) ? true : false;
10069}
10070
10071
10078function ascii_check($str)
10079{
10080 if (function_exists('mb_check_encoding')) {
10081 //if (mb_detect_encoding($str, 'ASCII', true) return false;
10082 if (!mb_check_encoding($str, 'ASCII')) {
10083 return false;
10084 }
10085 } else {
10086 if (preg_match('/[^\x00-\x7f]/', $str)) {
10087 return false; // Contains a byte > 7f
10088 }
10089 }
10090
10091 return true;
10092}
10093
10094
10102function dol_osencode($str)
10103{
10104 $tmp = ini_get("unicode.filesystem_encoding");
10105 if (empty($tmp) && !empty($_SERVER["WINDIR"])) {
10106 $tmp = 'iso-8859-1'; // By default for windows
10107 }
10108 if (empty($tmp)) {
10109 $tmp = 'utf-8'; // By default for other
10110 }
10111 if (getDolGlobalString('MAIN_FILESYSTEM_ENCODING')) {
10112 $tmp = getDolGlobalString('MAIN_FILESYSTEM_ENCODING');
10113 }
10114
10115 if ($tmp == 'iso-8859-1') {
10116 return mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8');
10117 }
10118 return $str;
10119}
10120
10121
10136function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '')
10137{
10138 global $conf;
10139
10140 // If key empty
10141 if ($key == '') {
10142 return 0;
10143 }
10144
10145 // Check in cache
10146 if (isset($conf->cache['codeid'][$tablename][$key][$fieldid])) { // Can be defined to 0 or ''
10147 return $conf->cache['codeid'][$tablename][$key][$fieldid]; // Found in cache
10148 }
10149
10150 dol_syslog('dol_getIdFromCode (value for field '.$fieldid.' from key '.$key.' not found into cache)', LOG_DEBUG);
10151
10152 $sql = "SELECT ".$fieldid." as valuetoget";
10153 $sql .= " FROM ".MAIN_DB_PREFIX.$tablename;
10154 $sql .= " WHERE ".$fieldkey." = '".$db->escape($key)."'";
10155 if (!empty($entityfilter)) {
10156 $sql .= " AND entity IN (".getEntity($tablename).")";
10157 }
10158 if ($filters) {
10159 $sql .= $filters;
10160 }
10161
10162 $resql = $db->query($sql);
10163 if ($resql) {
10164 $obj = $db->fetch_object($resql);
10165 if ($obj) {
10166 $conf->cache['codeid'][$tablename][$key][$fieldid] = $obj->valuetoget;
10167 } else {
10168 $conf->cache['codeid'][$tablename][$key][$fieldid] = '';
10169 }
10170 $db->free($resql);
10171
10172 return $conf->cache['codeid'][$tablename][$key][$fieldid];
10173 } else {
10174 return -1;
10175 }
10176}
10177
10187function isStringVarMatching($var, $regextext, $matchrule = 1)
10188{
10189 if ($matchrule == 1) {
10190 if ($var == 'mainmenu') {
10191 global $mainmenu;
10192 return (preg_match('/^'.$regextext.'/', $mainmenu));
10193 } elseif ($var == 'leftmenu') {
10194 global $leftmenu;
10195 return (preg_match('/^'.$regextext.'/', $leftmenu));
10196 } else {
10197 return 'This variable is not accessible with dol_eval';
10198 }
10199 } else {
10200 return 'This value for matchrule is not implemented';
10201 }
10202}
10203
10204
10214function verifCond($strToEvaluate, $onlysimplestring = '1')
10215{
10216 //print $strToEvaluate."<br>\n";
10217 $rights = true;
10218 if (isset($strToEvaluate) && $strToEvaluate !== '') {
10219 //var_dump($strToEvaluate);
10220 //$rep = dol_eval($strToEvaluate, 1, 0, '1'); // to show the error
10221 $rep = dol_eval($strToEvaluate, 1, 1, $onlysimplestring); // The dol_eval() must contains all the "global $xxx;" for all variables $xxx found into the string condition
10222 $rights = (bool) $rep && (!is_string($rep) || strpos($rep, 'Bad string syntax to evaluate') === false);
10223 //var_dump($rights);
10224 }
10225 return $rights;
10226}
10227
10242function dol_eval($s, $returnvalue = 1, $hideerrors = 1, $onlysimplestring = '1')
10243{
10244 // Only this global variables can be read by eval function and returned to caller
10245 global $conf; // Read of const is done with getDolGlobalString() but we need $conf->currency for example
10246 global $db, $langs, $user, $website, $websitepage;
10247 global $action, $mainmenu, $leftmenu;
10248 global $mysoc;
10249 global $objectoffield; // To allow the use of $objectoffield in computed fields
10250
10251 // Old variables used
10252 global $object;
10253 global $obj; // To get $obj used into list when dol_eval() is used for computed fields and $obj is not yet $object
10254
10255 $isObBufferActive = false; // When true, the ObBuffer must be cleaned in the exception handler
10256 if (!in_array($onlysimplestring, array('0', '1', '2'))) {
10257 return "Bad call of dol_eval. Parameter onlysimplestring must be '0' (deprecated), '1' or '2'";
10258 }
10259
10260 try {
10261 // Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing
10262 if ($onlysimplestring == '1' || $onlysimplestring == '2') {
10263 // We must accept with 1: '1 && getDolGlobalInt("doesnotexist1") && getDolGlobalString("MAIN_FEATURES_LEVEL")'
10264 // We must accept with 1: '$user->hasRight("cabinetmed", "read") && !$object->canvas=="patient@cabinetmed"'
10265 // We must accept with 2: (($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"
10266
10267 // Check if there is dynamic call (first we check chars are all into use a whitelist chars)
10268 $specialcharsallowed = '^$_+-.*>&|=!?():"\',/@';
10269 if ($onlysimplestring == '2') {
10270 $specialcharsallowed .= '[]';
10271 }
10272 if (getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL')) {
10273 $specialcharsallowed .= getDolGlobalString('MAIN_ALLOW_UNSECURED_SPECIAL_CHARS_IN_DOL_EVAL');
10274 }
10275 if (preg_match('/[^a-z0-9\s'.preg_quote($specialcharsallowed, '/').']/i', $s)) {
10276 if ($returnvalue) {
10277 return 'Bad string syntax to evaluate (found chars that are not chars for a simple clean eval string): '.$s;
10278 } else {
10279 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for a simple clean eval string): '.$s, LOG_WARNING);
10280 return '';
10281 }
10282 }
10283
10284 // Check if there is dynamic call (first we use black list patterns)
10285 if (preg_match('/\$[\w]*\s*\‍(/', $s)) {
10286 if ($returnvalue) {
10287 return 'Bad string syntax to evaluate (mode '.$onlysimplestring.', found a call using of "$abc(" or "$abc (" instead of using the direct name of the function): '.$s;
10288 } else {
10289 dol_syslog('Bad string syntax to evaluate (mode '.$onlysimplestring.', found a call using of "$abc(" or "$abc (" instead of using the direct name of the function): '.$s, LOG_WARNING);
10290 return '';
10291 }
10292 }
10293
10294 // Now we check if we try dynamic call (by removing white list pattern of using parenthesis then testing if a parenthesis exists)
10295 $savescheck = '';
10296 $scheck = $s;
10297 while ($scheck && $savescheck != $scheck) {
10298 $savescheck = $scheck;
10299 $scheck = preg_replace('/->[a-zA-Z0-9_]+\‍(/', '->__METHOD__', $scheck); // accept parenthesis in '...->method(...'
10300 $scheck = preg_replace('/^\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '(...'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
10301 $scheck = preg_replace('/\s\‍(/', '__PARENTHESIS__ ', $scheck); // accept parenthesis in '... (' like in 'if ($a == 1)'. Must replace with __PARENTHESIS__ with a space after to allow following substitutions
10302 $scheck = preg_replace('/^!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in 'function(' and '!function('
10303 $scheck = preg_replace('/\s!?[a-zA-Z0-9_]+\‍(/', '__FUNCTION__', $scheck); // accept parenthesis in '... function(' and '... !function('
10304 $scheck = preg_replace('/(\^|\')\‍(/', '__REGEXSTART__', $scheck); // To allow preg_match('/^(aaa|bbb)/'... or isStringVarMatching('leftmenu', '(aaa|bbb)')
10305 }
10306 //print 'scheck='.$scheck." : ".strpos($scheck, '(')."<br>\n";
10307 if (strpos($scheck, '(') !== false) {
10308 if ($returnvalue) {
10309 return 'Bad string syntax to evaluate (mode '.$onlysimplestring.', found call of a function or method without using the direct name of the function): '.$s;
10310 } else {
10311 dol_syslog('Bad string syntax to evaluate (mode '.$onlysimplestring.', found call of a function or method without using the direct name of the function): '.$s, LOG_WARNING);
10312 return '';
10313 }
10314 }
10315
10316 // TODO
10317 // We can exclude $ char that are not:
10318 // $db, $langs, $leftmenu, $topmenu, $user, $langs, $objectoffield, $object...,
10319 }
10320 if (is_array($s) || $s === 'Array') {
10321 if ($returnvalue) {
10322 return 'Bad string syntax to evaluate (value is Array): '.var_export($s, true);
10323 } else {
10324 dol_syslog('Bad string syntax to evaluate (value is Array): '.var_export($s, true), LOG_WARNING);
10325 return '';
10326 }
10327 }
10328 if (strpos($s, '::') !== false) {
10329 if ($returnvalue) {
10330 return 'Bad string syntax to evaluate (double : char is forbidden): '.$s;
10331 } else {
10332 dol_syslog('Bad string syntax to evaluate (double : char is forbidden): '.$s, LOG_WARNING);
10333 return '';
10334 }
10335 }
10336 if (strpos($s, '`') !== false) {
10337 if ($returnvalue) {
10338 return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
10339 } else {
10340 dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s, LOG_WARNING);
10341 return '';
10342 }
10343 }
10344 if (preg_match('/[^0-9]+\.[^0-9]+/', $s)) { // We refuse . if not between 2 numbers
10345 if ($returnvalue) {
10346 return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
10347 } else {
10348 dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s, LOG_WARNING);
10349 return '';
10350 }
10351 }
10352
10353 // We block use of php exec or php file functions
10354 $forbiddenphpstrings = array('$$', '$_', '}[');
10355 $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
10356
10357 $forbiddenphpfunctions = array();
10358 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64_decode", "rawurldecode", "urldecode", "str_rot13", "hex2bin")); // decode string functions used to obfuscated function name
10359 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
10360 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("override_function", "session_id", "session_create_id", "session_regenerate_id"));
10361 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
10362 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));
10363 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
10364 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("exec", "passthru", "shell_exec", "system", "proc_open", "popen"));
10365 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
10366 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
10367 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_compress_dir", "dol_decode", "dol_delete_file", "dol_delete_dir", "dol_delete_dir_recursive", "dol_copy", "archiveOrBackupFile")); // more dolibarr functions
10368
10369 $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
10370
10371 $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
10372
10373 $forbiddenphpmethodsregex = '->('.implode('|', $forbiddenphpmethods).')';
10374
10375 do {
10376 $oldstringtoclean = $s;
10377 $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);
10378 $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);
10379 $s = preg_replace('/'.$forbiddenphpmethodsregex.'/i', '__forbiddenstring__', $s);
10380 //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\‍(/i', '', $s); // Remove $function( call and $mycall->mymethod(
10381 } while ($oldstringtoclean != $s);
10382
10383
10384 if (strpos($s, '__forbiddenstring__') !== false) {
10385 dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
10386 if ($returnvalue) {
10387 return 'Bad string syntax to evaluate: '.$s;
10388 } else {
10389 dol_syslog('Bad string syntax to evaluate: '.$s);
10390 return '';
10391 }
10392 }
10393
10394 //print $s."<br>\n";
10395 if ($returnvalue) {
10396 if ($hideerrors) {
10397 ob_start(); // An evaluation has no reason to output data
10398 $isObBufferActive = true;
10399 $tmps = @eval('return '.$s.';');
10400 $tmpo = ob_get_clean();
10401 $isObBufferActive = false;
10402 if ($tmpo) {
10403 print 'Bad string syntax to evaluate. Some data were output when it should not when evaluating: '.$s;
10404 }
10405 return $tmps;
10406 } else {
10407 ob_start(); // An evaluation has no reason to output data
10408 $isObBufferActive = true;
10409 $tmps = eval('return '.$s.';');
10410 $tmpo = ob_get_clean();
10411 $isObBufferActive = false;
10412 if ($tmpo) {
10413 print 'Bad string syntax to evaluate. Some data were output when it should not when evaluating: '.$s;
10414 }
10415 return $tmps;
10416 }
10417 } else {
10418 dol_syslog('Do not use anymore dol_eval with param returnvalue=0', LOG_WARNING);
10419 if ($hideerrors) {
10420 @eval($s);
10421 } else {
10422 eval($s);
10423 }
10424 return '';
10425 }
10426 } catch (Error $e) {
10427 if ($isObBufferActive) {
10428 // Clean up buffer which was left behind due to exception.
10429 $tmpo = ob_get_clean();
10430 $isObBufferActive = false;
10431 }
10432 $error = 'dol_eval try/catch error : ';
10433 $error .= $e->getMessage();
10434 dol_syslog($error, LOG_WARNING);
10435 if ($returnvalue) {
10436 return 'Exception during evaluation: '.$s;
10437 } else {
10438 return '';
10439 }
10440 }
10441}
10442
10450function dol_validElement($element)
10451{
10452 return (trim($element) != '');
10453}
10454
10463function picto_from_langcode($codelang, $moreatt = '', $notitlealt = 0)
10464{
10465 if (empty($codelang)) {
10466 return '';
10467 }
10468
10469 if ($codelang == 'auto') {
10470 return '<span class="fa fa-language"></span>';
10471 }
10472
10473 $langtocountryflag = array(
10474 'ar_AR' => '',
10475 'ca_ES' => 'catalonia',
10476 'da_DA' => 'dk',
10477 'fr_CA' => 'mq',
10478 'sv_SV' => 'se',
10479 'sw_SW' => 'unknown',
10480 'AQ' => 'unknown',
10481 'CW' => 'unknown',
10482 'IM' => 'unknown',
10483 'JE' => 'unknown',
10484 'MF' => 'unknown',
10485 'BL' => 'unknown',
10486 'SX' => 'unknown'
10487 );
10488
10489 if (isset($langtocountryflag[$codelang])) {
10490 $flagImage = $langtocountryflag[$codelang];
10491 } else {
10492 $tmparray = explode('_', $codelang);
10493 $flagImage = empty($tmparray[1]) ? $tmparray[0] : $tmparray[1];
10494 }
10495
10496 $morecss = '';
10497 $reg = array();
10498 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
10499 $morecss = $reg[1];
10500 $moreatt = "";
10501 }
10502
10503 // return img_picto_common($codelang, 'flags/'.strtolower($flagImage).'.png', $moreatt, 0, $notitlealt);
10504 return '<span class="flag-sprite '.strtolower($flagImage).($morecss ? ' '.$morecss : '').'"'.($moreatt ? ' '.$moreatt : '').(!$notitlealt ? ' title="'.$codelang.'"' : '').'></span>';
10505}
10506
10514function getLanguageCodeFromCountryCode($countrycode)
10515{
10516 global $mysoc;
10517
10518 if (empty($countrycode)) {
10519 return null;
10520 }
10521
10522 if (strtoupper($countrycode) == 'MQ') {
10523 return 'fr_CA';
10524 }
10525 if (strtoupper($countrycode) == 'SE') {
10526 return 'sv_SE'; // se_SE is Sami/Sweden, and we want in priority sv_SE for SE country
10527 }
10528 if (strtoupper($countrycode) == 'CH') {
10529 if ($mysoc->country_code == 'FR') {
10530 return 'fr_CH';
10531 }
10532 if ($mysoc->country_code == 'DE') {
10533 return 'de_CH';
10534 }
10535 if ($mysoc->country_code == 'IT') {
10536 return 'it_CH';
10537 }
10538 }
10539
10540 // Locale list taken from:
10541 // http://stackoverflow.com/questions/3191664/
10542 // list-of-all-locales-and-their-short-codes
10543 $locales = array(
10544 'af-ZA',
10545 'am-ET',
10546 'ar-AE',
10547 'ar-BH',
10548 'ar-DZ',
10549 'ar-EG',
10550 'ar-IQ',
10551 'ar-JO',
10552 'ar-KW',
10553 'ar-LB',
10554 'ar-LY',
10555 'ar-MA',
10556 'ar-OM',
10557 'ar-QA',
10558 'ar-SA',
10559 'ar-SY',
10560 'ar-TN',
10561 'ar-YE',
10562 //'as-IN', // Moved after en-IN
10563 'ba-RU',
10564 'be-BY',
10565 'bg-BG',
10566 'bn-BD',
10567 //'bn-IN', // Moved after en-IN
10568 'bo-CN',
10569 'br-FR',
10570 'ca-ES',
10571 'co-FR',
10572 'cs-CZ',
10573 'cy-GB',
10574 'da-DK',
10575 'de-AT',
10576 'de-CH',
10577 'de-DE',
10578 'de-LI',
10579 'de-LU',
10580 'dv-MV',
10581 'el-GR',
10582 'en-AU',
10583 'en-BZ',
10584 'en-CA',
10585 'en-GB',
10586 'en-IE',
10587 'en-IN',
10588 'as-IN', // as-IN must be after en-IN (en in priority if country is IN)
10589 'bn-IN', // bn-IN must be after en-IN (en in priority if country is IN)
10590 'en-JM',
10591 'en-MY',
10592 'en-NZ',
10593 'en-PH',
10594 'en-SG',
10595 'en-TT',
10596 'en-US',
10597 'en-ZA',
10598 'en-ZW',
10599 'es-AR',
10600 'es-BO',
10601 'es-CL',
10602 'es-CO',
10603 'es-CR',
10604 'es-DO',
10605 'es-EC',
10606 'es-ES',
10607 'es-GT',
10608 'es-HN',
10609 'es-MX',
10610 'es-NI',
10611 'es-PA',
10612 'es-PE',
10613 'es-PR',
10614 'es-PY',
10615 'es-SV',
10616 'es-US',
10617 'es-UY',
10618 'es-VE',
10619 'et-EE',
10620 'eu-ES',
10621 'fa-IR',
10622 'fi-FI',
10623 'fo-FO',
10624 'fr-BE',
10625 'fr-CA',
10626 'fr-CH',
10627 'fr-FR',
10628 'fr-LU',
10629 'fr-MC',
10630 'fy-NL',
10631 'ga-IE',
10632 'gd-GB',
10633 'gl-ES',
10634 'gu-IN',
10635 'he-IL',
10636 'hi-IN',
10637 'hr-BA',
10638 'hr-HR',
10639 'hu-HU',
10640 'hy-AM',
10641 'id-ID',
10642 'ig-NG',
10643 'ii-CN',
10644 'is-IS',
10645 'it-CH',
10646 'it-IT',
10647 'ja-JP',
10648 'ka-GE',
10649 'kk-KZ',
10650 'kl-GL',
10651 'km-KH',
10652 'kn-IN',
10653 'ko-KR',
10654 'ky-KG',
10655 'lb-LU',
10656 'lo-LA',
10657 'lt-LT',
10658 'lv-LV',
10659 'mi-NZ',
10660 'mk-MK',
10661 'ml-IN',
10662 'mn-MN',
10663 'mr-IN',
10664 'ms-BN',
10665 'ms-MY',
10666 'mt-MT',
10667 'nb-NO',
10668 'ne-NP',
10669 'nl-BE',
10670 'nl-NL',
10671 'nn-NO',
10672 'oc-FR',
10673 'or-IN',
10674 'pa-IN',
10675 'pl-PL',
10676 'ps-AF',
10677 'pt-BR',
10678 'pt-PT',
10679 'rm-CH',
10680 'ro-MD',
10681 'ro-RO',
10682 'ru-RU',
10683 'rw-RW',
10684 'sa-IN',
10685 'se-FI',
10686 'se-NO',
10687 'se-SE',
10688 'si-LK',
10689 'sk-SK',
10690 'sl-SI',
10691 'sq-AL',
10692 'sv-FI',
10693 'sv-SE',
10694 'sw-KE',
10695 'ta-IN',
10696 'te-IN',
10697 'th-TH',
10698 'tk-TM',
10699 'tn-ZA',
10700 'tr-TR',
10701 'tt-RU',
10702 'ug-CN',
10703 'uk-UA',
10704 'ur-PK',
10705 'vi-VN',
10706 'wo-SN',
10707 'xh-ZA',
10708 'yo-NG',
10709 'zh-CN',
10710 'zh-HK',
10711 'zh-MO',
10712 'zh-SG',
10713 'zh-TW',
10714 'zu-ZA',
10715 );
10716
10717 $buildprimarykeytotest = strtolower($countrycode).'-'.strtoupper($countrycode);
10718 if (in_array($buildprimarykeytotest, $locales)) {
10719 return strtolower($countrycode).'_'.strtoupper($countrycode);
10720 }
10721
10722 if (function_exists('locale_get_primary_language') && function_exists('locale_get_region')) { // Need extension php-intl
10723 foreach ($locales as $locale) {
10724 $locale_language = locale_get_primary_language($locale);
10725 $locale_region = locale_get_region($locale);
10726 if (strtoupper($countrycode) == $locale_region) {
10727 //var_dump($locale.' - '.$locale_language.' - '.$locale_region);
10728 return strtolower($locale_language).'_'.strtoupper($locale_region);
10729 }
10730 }
10731 } else {
10732 dol_syslog("Warning Extension php-intl is not available", LOG_WARNING);
10733 }
10734
10735 return null;
10736}
10737
10768function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode = 'add', $filterorigmodule = '')
10769{
10770 global $hookmanager, $db;
10771
10772 if (isset($conf->modules_parts['tabs'][$type]) && is_array($conf->modules_parts['tabs'][$type])) {
10773 foreach ($conf->modules_parts['tabs'][$type] as $value) {
10774 $values = explode(':', $value);
10775
10776 $reg = array();
10777 if ($mode == 'add' && !preg_match('/^\-/', $values[1])) {
10778 $newtab = array();
10779 $postab = $h;
10780 // detect if position set in $values[1] ie : +(2)mytab@mymodule (first tab is 0, second is one, ...)
10781 $str = $values[1];
10782 $posstart = strpos($str, '(');
10783 if ($posstart > 0) {
10784 $posend = strpos($str, ')');
10785 if ($posstart > 0) {
10786 $res1 = substr($str, $posstart + 1, $posend - $posstart - 1);
10787 if (is_numeric($res1)) {
10788 $postab = (int) $res1;
10789 $values[1] = '+' . substr($str, $posend + 1);
10790 }
10791 }
10792 }
10793 if (count($values) == 6) {
10794 // new declaration with permissions:
10795 // $value='objecttype:+tabname1:Title1:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10796 // $value='objecttype:+tabname1:Title1,class,pathfile,method:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
10797 if ($values[0] != $type) {
10798 continue;
10799 }
10800
10801 if (verifCond($values[4], '2')) {
10802 if ($values[3]) {
10803 if ($filterorigmodule) { // If a filter of module origin has been requested
10804 if (strpos($values[3], '@')) { // This is an external module
10805 if ($filterorigmodule != 'external') {
10806 continue;
10807 }
10808 } else { // This looks a core module
10809 if ($filterorigmodule != 'core') {
10810 continue;
10811 }
10812 }
10813 }
10814 $langs->load($values[3]);
10815 }
10816 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10817 // If label is "SUBSTITUION_..."
10818 $substitutionarray = array();
10819 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey' => $values[2]));
10820 $label = make_substitutions($reg[1], $substitutionarray);
10821 } else {
10822 // If label is "Label,Class,File,Method", we call the method to show content inside the badge
10823 $labeltemp = explode(',', $values[2]);
10824 $label = $langs->trans($labeltemp[0]);
10825
10826 if (!empty($labeltemp[1]) && is_object($object) && !empty($object->id)) {
10827 dol_include_once($labeltemp[2]);
10828 $classtoload = $labeltemp[1];
10829 if (class_exists($classtoload)) {
10830 $obj = new $classtoload($db);
10831 $function = $labeltemp[3];
10832 if ($obj && $function && method_exists($obj, $function)) {
10833 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
10834 $nbrec = $obj->$function($object->id, $obj);
10835 if (!empty($nbrec)) {
10836 $label .= '<span class="badge marginleftonlyshort">'.$nbrec.'</span>';
10837 }
10838 }
10839 }
10840 }
10841 }
10842
10843 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[5]), 1);
10844 $newtab[1] = $label;
10845 $newtab[2] = str_replace('+', '', $values[1]);
10846 $h++;
10847 } else {
10848 continue;
10849 }
10850 } elseif (count($values) == 5) { // case deprecated
10851 dol_syslog('Passing 5 values in tabs module_parts is deprecated. Please update to 6 with permissions.', LOG_WARNING);
10852
10853 if ($values[0] != $type) {
10854 continue;
10855 }
10856 if ($values[3]) {
10857 if ($filterorigmodule) { // If a filter of module origin has been requested
10858 if (strpos($values[3], '@')) { // This is an external module
10859 if ($filterorigmodule != 'external') {
10860 continue;
10861 }
10862 } else { // This looks a core module
10863 if ($filterorigmodule != 'core') {
10864 continue;
10865 }
10866 }
10867 }
10868 $langs->load($values[3]);
10869 }
10870 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
10871 $substitutionarray = array();
10872 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey' => $values[2]));
10873 $label = make_substitutions($reg[1], $substitutionarray);
10874 } else {
10875 $label = $langs->trans($values[2]);
10876 }
10877
10878 $newtab[0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[4]), 1);
10879 $newtab[1] = $label;
10880 $newtab[2] = str_replace('+', '', $values[1]);
10881 $h++;
10882 }
10883 // set tab at its position
10884 $head = array_merge(array_slice($head, 0, $postab), array($newtab), array_slice($head, $postab));
10885 } elseif ($mode == 'remove' && preg_match('/^\-/', $values[1])) {
10886 if ($values[0] != $type) {
10887 continue;
10888 }
10889 $tabname = str_replace('-', '', $values[1]);
10890 foreach ($head as $key => $val) {
10891 $condition = (!empty($values[3]) ? verifCond($values[3], '2') : 1);
10892 //var_dump($key.' - '.$tabname.' - '.$head[$key][2].' - '.$values[3].' - '.$condition);
10893 if ($head[$key][2] == $tabname && $condition) {
10894 unset($head[$key]);
10895 break;
10896 }
10897 }
10898 }
10899 }
10900 }
10901
10902 // No need to make a return $head. Var is modified as a reference
10903 if (!empty($hookmanager)) {
10904 $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule);
10905 $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters, $object);
10906 if ($reshook > 0) { // Hook ask to replace completely the array
10907 $head = $hookmanager->resArray;
10908 } else { // Hook
10909 $head = array_merge($head, $hookmanager->resArray);
10910 }
10911 $h = count($head);
10912 }
10913}
10914
10926function printCommonFooter($zone = 'private')
10927{
10928 global $conf, $hookmanager, $user, $debugbar;
10929 global $action;
10930 global $micro_start_time;
10931
10932 if ($zone == 'private') {
10933 print "\n".'<!-- Common footer for private page -->'."\n";
10934 } else {
10935 print "\n".'<!-- Common footer for public page -->'."\n";
10936 }
10937
10938 // A div to store page_y POST parameter so we can read it using javascript
10939 print "\n<!-- A div to store page_y POST parameter -->\n";
10940 print '<div id="page_y" style="display: none;">'.(GETPOST('page_y') ? GETPOST('page_y') : '').'</div>'."\n";
10941
10942 $parameters = array();
10943 $reshook = $hookmanager->executeHooks('printCommonFooter', $parameters); // Note that $action and $object may have been modified by some hooks
10944 if (empty($reshook)) {
10945 if (getDolGlobalString('MAIN_HTML_FOOTER')) {
10946 print getDolGlobalString('MAIN_HTML_FOOTER') . "\n";
10947 }
10948
10949 print "\n";
10950 if (!empty($conf->use_javascript_ajax)) {
10951 print "\n<!-- A script section to add menuhider handler on backoffice, manage focus and mandatory fields, tuning info, ... -->\n";
10952 print '<script>'."\n";
10953 print 'jQuery(document).ready(function() {'."\n";
10954
10955 if ($zone == 'private' && empty($conf->dol_use_jmobile)) {
10956 print "\n";
10957 print '/* JS CODE TO ENABLE to manage handler to switch left menu page (menuhider) */'."\n";
10958 print 'jQuery("li.menuhider").click(function(event) {';
10959 print ' if (!$( "body" ).hasClass( "sidebar-collapse" )){ event.preventDefault(); }'."\n";
10960 print ' console.log("We click on .menuhider");'."\n";
10961 print ' $("body").toggleClass("sidebar-collapse")'."\n";
10962 print '});'."\n";
10963 }
10964
10965 // Management of focus and mandatory for fields
10966 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"])))) {
10967 print '/* JS CODE TO ENABLE to manage focus and mandatory form fields */'."\n";
10968 $relativepathstring = $_SERVER["PHP_SELF"];
10969 // Clean $relativepathstring
10970 if (constant('DOL_URL_ROOT')) {
10971 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
10972 }
10973 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
10974 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
10975 //$tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
10976 if (!empty($user->default_values[$relativepathstring]['focus'])) {
10977 foreach ($user->default_values[$relativepathstring]['focus'] as $defkey => $defval) {
10978 $qualified = 0;
10979 if ($defkey != '_noquery_') {
10980 $tmpqueryarraytohave = explode('&', $defkey);
10981 $foundintru = 0;
10982 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
10983 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
10984 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
10985 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
10986 $foundintru = 1;
10987 }
10988 }
10989 if (!$foundintru) {
10990 $qualified = 1;
10991 }
10992 //var_dump($defkey.'-'.$qualified);
10993 } else {
10994 $qualified = 1;
10995 }
10996
10997 if ($qualified) {
10998 foreach ($defval as $paramkey => $paramval) {
10999 // Set focus on field
11000 print 'jQuery("input[name=\''.$paramkey.'\']").focus();'."\n";
11001 print 'jQuery("textarea[name=\''.$paramkey.'\']").focus();'."\n";
11002 print 'jQuery("select[name=\''.$paramkey.'\']").focus();'."\n"; // Not really useful, but we keep it in case of.
11003 }
11004 }
11005 }
11006 }
11007 if (!empty($user->default_values[$relativepathstring]['mandatory'])) {
11008 foreach ($user->default_values[$relativepathstring]['mandatory'] as $defkey => $defval) {
11009 $qualified = 0;
11010 if ($defkey != '_noquery_') {
11011 $tmpqueryarraytohave = explode('&', $defkey);
11012 $foundintru = 0;
11013 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
11014 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
11015 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
11016 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
11017 $foundintru = 1;
11018 }
11019 }
11020 if (!$foundintru) {
11021 $qualified = 1;
11022 }
11023 //var_dump($defkey.'-'.$qualified);
11024 } else {
11025 $qualified = 1;
11026 }
11027
11028 if ($qualified) {
11029 foreach ($defval as $paramkey => $paramval) {
11030 // Add property 'required' on input
11031 print 'jQuery("input[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
11032 print 'jQuery("textarea[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
11033 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";
11034 print 'jQuery("select[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
11035 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'-1\']").prop(\'value\', \'\');'."\n";
11036 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'0\']").prop(\'value\', \'\');'."\n";
11037
11038 // Add 'field required' class on closest td for all input elements : input, textarea and select
11039 print 'jQuery(":input[name=\'' . $paramkey . '\']").closest("tr").find("td:first").addClass("fieldrequired");' . "\n";
11040 }
11041 // If we submit the cancel button we remove the required attributes
11042 print 'jQuery("input[name=\'cancel\']").click(function() {
11043 console.log("We click on cancel button so removed all required attribute");
11044 jQuery("input, textarea, select").each(function(){this.removeAttribute(\'required\');});
11045 });'."\n";
11046 }
11047 }
11048 }
11049 }
11050
11051 print '});'."\n";
11052
11053 // End of tuning
11054 if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO']) || getDolGlobalString('MAIN_SHOW_TUNING_INFO')) {
11055 print "\n";
11056 print "/* JS CODE TO ENABLE to add memory info */\n";
11057 print 'window.console && console.log("';
11058 if (getDolGlobalString('MEMCACHED_SERVER')) {
11059 print 'MEMCACHED_SERVER=' . getDolGlobalString('MEMCACHED_SERVER').' - ';
11060 }
11061 print 'MAIN_OPTIMIZE_SPEED=' . getDolGlobalString('MAIN_OPTIMIZE_SPEED', 'off');
11062 if (!empty($micro_start_time)) { // Works only if MAIN_SHOW_TUNING_INFO is defined at $_SERVER level. Not in global variable.
11063 $micro_end_time = microtime(true);
11064 print ' - Build time: '.ceil(1000 * ($micro_end_time - $micro_start_time)).' ms';
11065 }
11066
11067 if (function_exists("memory_get_usage")) {
11068 print ' - Mem: '.memory_get_usage(); // Do not use true here, it seems it takes the peak amount
11069 }
11070 if (function_exists("memory_get_peak_usage")) {
11071 print ' - Real mem peak: '.memory_get_peak_usage(true);
11072 }
11073 if (function_exists("zend_loader_file_encoded")) {
11074 print ' - Zend encoded file: '.(zend_loader_file_encoded() ? 'yes' : 'no');
11075 }
11076 print '");'."\n";
11077 }
11078
11079 print "\n".'</script>'."\n";
11080
11081 // Google Analytics
11082 // TODO Add a hook here
11083 if (isModEnabled('google') && getDolGlobalString('MAIN_GOOGLE_AN_ID')) {
11084 $tmptagarray = explode(',', getDolGlobalString('MAIN_GOOGLE_AN_ID'));
11085 foreach ($tmptagarray as $tmptag) {
11086 print "\n";
11087 print "<!-- JS CODE TO ENABLE for google analtics tag -->\n";
11088 print '
11089 <!-- Global site tag (gtag.js) - Google Analytics -->
11090 <script nonce="'.getNonce().'" async src="https://www.googletagmanager.com/gtag/js?id='.trim($tmptag).'"></script>
11091 <script>
11092 window.dataLayer = window.dataLayer || [];
11093 function gtag(){dataLayer.push(arguments);}
11094 gtag(\'js\', new Date());
11095
11096 gtag(\'config\', \''.trim($tmptag).'\');
11097 </script>';
11098 print "\n";
11099 }
11100 }
11101 }
11102
11103 // Add Xdebug coverage of code
11104 if (defined('XDEBUGCOVERAGE')) {
11105 print_r(xdebug_get_code_coverage());
11106 }
11107
11108 // Add DebugBar data
11109 if ($user->hasRight('debugbar', 'read') && $debugbar instanceof DebugBar\DebugBar) {
11110 if (isset($debugbar['time'])) {
11111 // @phan-suppress-next-line PhanPluginUnknownObjectMethodCall
11112 $debugbar['time']->stopMeasure('pageaftermaster');
11113 }
11114 print '<!-- Output debugbar data -->'."\n";
11115 $renderer = $debugbar->getJavascriptRenderer();
11116 print $renderer->render();
11117 } elseif (count($conf->logbuffer)) { // If there is some logs in buffer to show
11118 print "\n";
11119 print "<!-- Start of log output\n";
11120 //print '<div class="hidden">'."\n";
11121 foreach ($conf->logbuffer as $logline) {
11122 print $logline."<br>\n";
11123 }
11124 //print '</div>'."\n";
11125 print "End of log output -->\n";
11126 }
11127 }
11128}
11129
11139function dolExplodeIntoArray($string, $delimiter = ';', $kv = '=')
11140{
11141 if (is_null($string)) {
11142 return array();
11143 }
11144
11145 if (preg_match('/^\[.*\]$/sm', $delimiter) || preg_match('/^\‍(.*\‍)$/sm', $delimiter)) {
11146 // This is a regex string
11147 $newdelimiter = $delimiter;
11148 } else {
11149 // This is a simple string
11150 // @phan-suppress-next-line PhanPluginSuspiciousParamPositionInternal
11151 $newdelimiter = preg_quote($delimiter, '/');
11152 }
11153
11154 if ($a = preg_split('/'.$newdelimiter.'/', $string)) {
11155 $ka = array();
11156 foreach ($a as $s) { // each part
11157 if ($s) {
11158 if ($pos = strpos($s, $kv)) { // key/value delimiter
11159 $ka[trim(substr($s, 0, $pos))] = trim(substr($s, $pos + strlen($kv)));
11160 } else { // key delimiter not found
11161 $ka[] = trim($s);
11162 }
11163 }
11164 }
11165 return $ka;
11166 }
11167
11168 return array();
11169}
11170
11171
11178function dol_set_focus($selector)
11179{
11180 print "\n".'<!-- Set focus onto a specific field -->'."\n";
11181 print '<script nonce="'.getNonce().'">jQuery(document).ready(function() { jQuery("'.dol_escape_js($selector).'").focus(); });</script>'."\n";
11182}
11183
11184
11192function dol_getmypid()
11193{
11194 if (!function_exists('getmypid')) {
11195 return mt_rand(99900000, 99965535);
11196 } else {
11197 return getmypid(); // May be a number on 64 bits (depending on OS)
11198 }
11199}
11200
11201
11223function natural_search($fields, $value, $mode = 0, $nofirstand = 0)
11224{
11225 global $db, $langs;
11226
11227 $value = trim($value);
11228
11229 if ($mode == 0) {
11230 $value = preg_replace('/\*/', '%', $value); // Replace * with %
11231 }
11232 if ($mode == 1) {
11233 $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
11234 }
11235
11236 $value = preg_replace('/\s*\|\s*/', '|', $value);
11237
11238 $crits = explode(' ', $value);
11239 $res = '';
11240 if (!is_array($fields)) {
11241 $fields = array($fields);
11242 }
11243
11244 $i1 = 0; // count the nb of and criteria added (all fields / criteria)
11245 foreach ($crits as $crit) { // Loop on each AND criteria
11246 $crit = trim($crit);
11247 $i2 = 0; // count the nb of valid criteria added for this this first criteria
11248 $newres = '';
11249 foreach ($fields as $field) {
11250 if ($mode == 1) {
11251 $tmpcrits = explode('|', $crit);
11252 $i3 = 0; // count the nb of valid criteria added for this current field
11253 foreach ($tmpcrits as $tmpcrit) {
11254 if ($tmpcrit !== '0' && empty($tmpcrit)) {
11255 continue;
11256 }
11257 $tmpcrit = trim($tmpcrit);
11258
11259 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
11260
11261 $operator = '=';
11262 $newcrit = preg_replace('/([!<>=]+)/', '', $tmpcrit);
11263
11264 $reg = array();
11265 preg_match('/([!<>=]+)/', $tmpcrit, $reg);
11266 if (!empty($reg[1])) {
11267 $operator = $reg[1];
11268 }
11269 if ($newcrit != '') {
11270 $numnewcrit = price2num($newcrit);
11271 if (is_numeric($numnewcrit)) {
11272 $newres .= $field.' '.$operator.' '.((float) $numnewcrit); // should be a numeric
11273 } else {
11274 $newres .= '1 = 2'; // force false, we received a corrupted data
11275 }
11276 $i3++; // a criteria was added to string
11277 }
11278 }
11279 $i2++; // a criteria for 1 more field was added to string
11280 } elseif ($mode == 2 || $mode == -2) {
11281 $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer
11282 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -2 ? 'NOT ' : '');
11283 $newres .= $crit ? "IN (".$db->sanitize($db->escape($crit)).")" : "IN (0)";
11284 if ($mode == -2) {
11285 $newres .= ' OR '.$field.' IS NULL';
11286 }
11287 $i2++; // a criteria for 1 more field was added to string
11288 } elseif ($mode == 3 || $mode == -3) {
11289 $tmparray = explode(',', $crit);
11290 if (count($tmparray)) {
11291 $listofcodes = '';
11292 foreach ($tmparray as $val) {
11293 $val = trim($val);
11294 if ($val) {
11295 $listofcodes .= ($listofcodes ? ',' : '');
11296 $listofcodes .= "'".$db->escape($val)."'";
11297 }
11298 }
11299 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -3 ? 'NOT ' : '')."IN (".$db->sanitize($listofcodes, 1).")";
11300 $i2++; // a criteria for 1 more field was added to string
11301 }
11302 if ($mode == -3) {
11303 $newres .= ' OR '.$field.' IS NULL';
11304 }
11305 } elseif ($mode == 4) {
11306 $tmparray = explode(',', $crit);
11307 if (count($tmparray)) {
11308 $listofcodes = '';
11309 foreach ($tmparray as $val) {
11310 $val = trim($val);
11311 if ($val) {
11312 $newres .= ($i2 > 0 ? " OR (" : "(").$field." LIKE '".$db->escape($val).",%'";
11313 $newres .= ' OR '.$field." = '".$db->escape($val)."'";
11314 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val)."'";
11315 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val).",%'";
11316 $newres .= ')';
11317 $i2++; // a criteria for 1 more field was added to string (we can add several criteria for the same field as it is a multiselect search criteria)
11318 }
11319 }
11320 }
11321 } else { // $mode=0
11322 $tmpcrits = explode('|', $crit);
11323 $i3 = 0; // count the nb of valid criteria added for the current couple criteria/field
11324 foreach ($tmpcrits as $tmpcrit) { // loop on each OR criteria
11325 if ($tmpcrit !== '0' && empty($tmpcrit)) {
11326 continue;
11327 }
11328 $tmpcrit = trim($tmpcrit);
11329
11330 if ($tmpcrit == '^$' || strpos($crit, '!') === 0) { // If we search empty, we must combined different OR fields with AND
11331 $newres .= (($i2 > 0 || $i3 > 0) ? ' AND ' : '');
11332 } else {
11333 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
11334 }
11335
11336 if (preg_match('/\.(id|rowid)$/', $field)) { // Special case for rowid that is sometimes a ref so used as a search field
11337 $newres .= $field." = ".(is_numeric($tmpcrit) ? ((float) $tmpcrit) : '0');
11338 } else {
11339 $tmpcrit2 = $tmpcrit;
11340 $tmpbefore = '%';
11341 $tmpafter = '%';
11342 $tmps = '';
11343
11344 if (preg_match('/^!/', $tmpcrit)) {
11345 $tmps .= $field." NOT LIKE "; // ! as exclude character
11346 $tmpcrit2 = preg_replace('/^!/', '', $tmpcrit2);
11347 } else {
11348 $tmps .= $field." LIKE ";
11349 }
11350 $tmps .= "'";
11351
11352 if (preg_match('/^[\^\$]/', $tmpcrit)) {
11353 $tmpbefore = '';
11354 $tmpcrit2 = preg_replace('/^[\^\$]/', '', $tmpcrit2);
11355 }
11356 if (preg_match('/[\^\$]$/', $tmpcrit)) {
11357 $tmpafter = '';
11358 $tmpcrit2 = preg_replace('/[\^\$]$/', '', $tmpcrit2);
11359 }
11360
11361 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
11362 $tmps = "(".$tmps;
11363 }
11364 $newres .= $tmps;
11365 $newres .= $tmpbefore;
11366 $newres .= $db->escape($tmpcrit2);
11367 $newres .= $tmpafter;
11368 $newres .= "'";
11369 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
11370 $newres .= " OR ".$field." IS NULL)";
11371 }
11372 }
11373
11374 $i3++;
11375 }
11376
11377 $i2++; // a criteria for 1 more field was added to string
11378 }
11379 }
11380
11381 if ($newres) {
11382 $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : '');
11383 }
11384 $i1++;
11385 }
11386 $res = ($nofirstand ? "" : " AND ")."(".$res.")";
11387
11388 return $res;
11389}
11390
11397function showDirectDownloadLink($object)
11398{
11399 global $conf, $langs;
11400
11401 $out = '';
11402 $url = $object->getLastMainDocLink($object->element);
11403
11404 $out .= img_picto($langs->trans("PublicDownloadLinkDesc"), 'globe').' <span class="opacitymedium">'.$langs->trans("DirectDownloadLink").'</span><br>';
11405 if ($url) {
11406 $out .= '<div class="urllink"><input type="text" id="directdownloadlink" class="quatrevingtpercent" value="'.$url.'"></div>';
11407 $out .= ajax_autoselect("directdownloadlink", 0);
11408 } else {
11409 $out .= '<div class="urllink">'.$langs->trans("FileNotShared").'</div>';
11410 }
11411
11412 return $out;
11413}
11414
11423function getImageFileNameForSize($file, $extName, $extImgTarget = '')
11424{
11425 $dirName = dirname($file);
11426 if ($dirName == '.') {
11427 $dirName = '';
11428 }
11429
11430 $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.webp)$/i', '', $file); // We remove extension, whatever is its case
11431 $fileName = basename($fileName);
11432
11433 if (empty($extImgTarget)) {
11434 $extImgTarget = (preg_match('/\.jpg$/i', $file) ? '.jpg' : '');
11435 }
11436 if (empty($extImgTarget)) {
11437 $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '');
11438 }
11439 if (empty($extImgTarget)) {
11440 $extImgTarget = (preg_match('/\.gif$/i', $file) ? '.gif' : '');
11441 }
11442 if (empty($extImgTarget)) {
11443 $extImgTarget = (preg_match('/\.png$/i', $file) ? '.png' : '');
11444 }
11445 if (empty($extImgTarget)) {
11446 $extImgTarget = (preg_match('/\.bmp$/i', $file) ? '.bmp' : '');
11447 }
11448 if (empty($extImgTarget)) {
11449 $extImgTarget = (preg_match('/\.webp$/i', $file) ? '.webp' : '');
11450 }
11451
11452 if (!$extImgTarget) {
11453 return $file;
11454 }
11455
11456 $subdir = '';
11457 if ($extName) {
11458 $subdir = 'thumbs/';
11459 }
11460
11461 return ($dirName ? $dirName.'/' : '').$subdir.$fileName.$extName.$extImgTarget; // New filename for thumb
11462}
11463
11464
11474function getAdvancedPreviewUrl($modulepart, $relativepath, $alldata = 0, $param = '')
11475{
11476 global $conf, $langs;
11477
11478 if (empty($conf->use_javascript_ajax)) {
11479 return '';
11480 }
11481
11482 $isAllowedForPreview = dolIsAllowedForPreview($relativepath);
11483
11484 if ($alldata == 1) {
11485 if ($isAllowedForPreview) {
11486 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));
11487 } else {
11488 return array();
11489 }
11490 }
11491
11492 // old behavior, return a string
11493 if ($isAllowedForPreview) {
11494 $tmpurl = DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : '');
11495 $title = $langs->transnoentities("Preview");
11496 //$title = '%27-alert(document.domain)-%27';
11497 //$tmpurl = 'file='.urlencode("'-alert(document.domain)-'_small.jpg");
11498
11499 // 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.
11500 // and when we click on href with this javascript string, a urlcode is done by browser, converted the %27 of file param
11501 return 'javascript:document_preview(\''.urlencode(dol_escape_js($tmpurl)).'\', \''.urlencode(dol_mimetype($relativepath)).'\', \''.urlencode(dol_escape_js($title)).'\')';
11502 } else {
11503 return '';
11504 }
11505}
11506
11507
11516function ajax_autoselect($htmlname, $addlink = '', $textonlink = 'Link')
11517{
11518 global $langs;
11519 $out = '<script nonce="'.getNonce().'">
11520 jQuery(document).ready(function () {
11521 jQuery("'.((strpos($htmlname, '.') === 0 ? '' : '#').$htmlname).'").click(function() { jQuery(this).select(); } );
11522 });
11523 </script>';
11524 if ($addlink) {
11525 if ($textonlink === 'image') {
11526 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.img_picto('', 'globe').'</a>';
11527 } else {
11528 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.$langs->trans("Link").'</a>';
11529 }
11530 }
11531 return $out;
11532}
11533
11541function dolIsAllowedForPreview($file)
11542{
11543 // Check .noexe extension in filename
11544 if (preg_match('/\.noexe$/i', $file)) {
11545 return 0;
11546 }
11547
11548 // Check mime types
11549 $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'webp');
11550 if (getDolGlobalString('MAIN_ALLOW_SVG_FILES_AS_IMAGES')) {
11551 $mime_preview[] = 'svg+xml';
11552 }
11553 //$mime_preview[]='vnd.oasis.opendocument.presentation';
11554 //$mime_preview[]='archive';
11555 $num_mime = array_search(dol_mimetype($file, '', 1), $mime_preview);
11556 if ($num_mime !== false) {
11557 return 1;
11558 }
11559
11560 // By default, not allowed for preview
11561 return 0;
11562}
11563
11564
11574function dol_mimetype($file, $default = 'application/octet-stream', $mode = 0)
11575{
11576 $mime = $default;
11577 $imgmime = 'other.png';
11578 $famime = 'file-o';
11579 $srclang = '';
11580
11581 $tmpfile = preg_replace('/\.noexe$/', '', $file);
11582
11583 // Plain text files
11584 if (preg_match('/\.txt$/i', $tmpfile)) {
11585 $mime = 'text/plain';
11586 $imgmime = 'text.png';
11587 $famime = 'file-alt';
11588 } elseif (preg_match('/\.rtx$/i', $tmpfile)) {
11589 $mime = 'text/richtext';
11590 $imgmime = 'text.png';
11591 $famime = 'file-alt';
11592 } elseif (preg_match('/\.csv$/i', $tmpfile)) {
11593 $mime = 'text/csv';
11594 $imgmime = 'text.png';
11595 $famime = 'file-csv';
11596 } elseif (preg_match('/\.tsv$/i', $tmpfile)) {
11597 $mime = 'text/tab-separated-values';
11598 $imgmime = 'text.png';
11599 $famime = 'file-alt';
11600 } elseif (preg_match('/\.(cf|conf|log)$/i', $tmpfile)) {
11601 $mime = 'text/plain';
11602 $imgmime = 'text.png';
11603 $famime = 'file-alt';
11604 } elseif (preg_match('/\.ini$/i', $tmpfile)) {
11605 $mime = 'text/plain';
11606 $imgmime = 'text.png';
11607 $srclang = 'ini';
11608 $famime = 'file-alt';
11609 } elseif (preg_match('/\.md$/i', $tmpfile)) {
11610 $mime = 'text/plain';
11611 $imgmime = 'text.png';
11612 $srclang = 'md';
11613 $famime = 'file-alt';
11614 } elseif (preg_match('/\.css$/i', $tmpfile)) {
11615 $mime = 'text/css';
11616 $imgmime = 'css.png';
11617 $srclang = 'css';
11618 $famime = 'file-alt';
11619 } elseif (preg_match('/\.lang$/i', $tmpfile)) {
11620 $mime = 'text/plain';
11621 $imgmime = 'text.png';
11622 $srclang = 'lang';
11623 $famime = 'file-alt';
11624 } elseif (preg_match('/\.(crt|cer|key|pub)$/i', $tmpfile)) { // Certificate files
11625 $mime = 'text/plain';
11626 $imgmime = 'text.png';
11627 $famime = 'file-alt';
11628 } elseif (preg_match('/\.(html|htm|shtml)$/i', $tmpfile)) { // XML based (HTML/XML/XAML)
11629 $mime = 'text/html';
11630 $imgmime = 'html.png';
11631 $srclang = 'html';
11632 $famime = 'file-alt';
11633 } elseif (preg_match('/\.(xml|xhtml)$/i', $tmpfile)) {
11634 $mime = 'text/xml';
11635 $imgmime = 'other.png';
11636 $srclang = 'xml';
11637 $famime = 'file-alt';
11638 } elseif (preg_match('/\.xaml$/i', $tmpfile)) {
11639 $mime = 'text/xml';
11640 $imgmime = 'other.png';
11641 $srclang = 'xaml';
11642 $famime = 'file-alt';
11643 } elseif (preg_match('/\.bas$/i', $tmpfile)) { // Languages
11644 $mime = 'text/plain';
11645 $imgmime = 'text.png';
11646 $srclang = 'bas';
11647 $famime = 'file-code';
11648 } elseif (preg_match('/\.(c)$/i', $tmpfile)) {
11649 $mime = 'text/plain';
11650 $imgmime = 'text.png';
11651 $srclang = 'c';
11652 $famime = 'file-code';
11653 } elseif (preg_match('/\.(cpp)$/i', $tmpfile)) {
11654 $mime = 'text/plain';
11655 $imgmime = 'text.png';
11656 $srclang = 'cpp';
11657 $famime = 'file-code';
11658 } elseif (preg_match('/\.cs$/i', $tmpfile)) {
11659 $mime = 'text/plain';
11660 $imgmime = 'text.png';
11661 $srclang = 'cs';
11662 $famime = 'file-code';
11663 } elseif (preg_match('/\.(h)$/i', $tmpfile)) {
11664 $mime = 'text/plain';
11665 $imgmime = 'text.png';
11666 $srclang = 'h';
11667 $famime = 'file-code';
11668 } elseif (preg_match('/\.(java|jsp)$/i', $tmpfile)) {
11669 $mime = 'text/plain';
11670 $imgmime = 'text.png';
11671 $srclang = 'java';
11672 $famime = 'file-code';
11673 } elseif (preg_match('/\.php([0-9]{1})?$/i', $tmpfile)) {
11674 $mime = 'text/plain';
11675 $imgmime = 'php.png';
11676 $srclang = 'php';
11677 $famime = 'file-code';
11678 } elseif (preg_match('/\.phtml$/i', $tmpfile)) {
11679 $mime = 'text/plain';
11680 $imgmime = 'php.png';
11681 $srclang = 'php';
11682 $famime = 'file-code';
11683 } elseif (preg_match('/\.(pl|pm)$/i', $tmpfile)) {
11684 $mime = 'text/plain';
11685 $imgmime = 'pl.png';
11686 $srclang = 'perl';
11687 $famime = 'file-code';
11688 } elseif (preg_match('/\.sql$/i', $tmpfile)) {
11689 $mime = 'text/plain';
11690 $imgmime = 'text.png';
11691 $srclang = 'sql';
11692 $famime = 'file-code';
11693 } elseif (preg_match('/\.js$/i', $tmpfile)) {
11694 $mime = 'text/x-javascript';
11695 $imgmime = 'jscript.png';
11696 $srclang = 'js';
11697 $famime = 'file-code';
11698 } elseif (preg_match('/\.odp$/i', $tmpfile)) { // Open office
11699 $mime = 'application/vnd.oasis.opendocument.presentation';
11700 $imgmime = 'ooffice.png';
11701 $famime = 'file-powerpoint';
11702 } elseif (preg_match('/\.ods$/i', $tmpfile)) {
11703 $mime = 'application/vnd.oasis.opendocument.spreadsheet';
11704 $imgmime = 'ooffice.png';
11705 $famime = 'file-excel';
11706 } elseif (preg_match('/\.odt$/i', $tmpfile)) {
11707 $mime = 'application/vnd.oasis.opendocument.text';
11708 $imgmime = 'ooffice.png';
11709 $famime = 'file-word';
11710 } elseif (preg_match('/\.mdb$/i', $tmpfile)) { // MS Office
11711 $mime = 'application/msaccess';
11712 $imgmime = 'mdb.png';
11713 $famime = 'file';
11714 } elseif (preg_match('/\.doc[xm]?$/i', $tmpfile)) {
11715 $mime = 'application/msword';
11716 $imgmime = 'doc.png';
11717 $famime = 'file-word';
11718 } elseif (preg_match('/\.dot[xm]?$/i', $tmpfile)) {
11719 $mime = 'application/msword';
11720 $imgmime = 'doc.png';
11721 $famime = 'file-word';
11722 } elseif (preg_match('/\.xlt(x)?$/i', $tmpfile)) {
11723 $mime = 'application/vnd.ms-excel';
11724 $imgmime = 'xls.png';
11725 $famime = 'file-excel';
11726 } elseif (preg_match('/\.xla(m)?$/i', $tmpfile)) {
11727 $mime = 'application/vnd.ms-excel';
11728 $imgmime = 'xls.png';
11729 $famime = 'file-excel';
11730 } elseif (preg_match('/\.xls$/i', $tmpfile)) {
11731 $mime = 'application/vnd.ms-excel';
11732 $imgmime = 'xls.png';
11733 $famime = 'file-excel';
11734 } elseif (preg_match('/\.xls[bmx]$/i', $tmpfile)) {
11735 $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
11736 $imgmime = 'xls.png';
11737 $famime = 'file-excel';
11738 } elseif (preg_match('/\.pps[mx]?$/i', $tmpfile)) {
11739 $mime = 'application/vnd.ms-powerpoint';
11740 $imgmime = 'ppt.png';
11741 $famime = 'file-powerpoint';
11742 } elseif (preg_match('/\.ppt[mx]?$/i', $tmpfile)) {
11743 $mime = 'application/x-mspowerpoint';
11744 $imgmime = 'ppt.png';
11745 $famime = 'file-powerpoint';
11746 } elseif (preg_match('/\.pdf$/i', $tmpfile)) { // Other
11747 $mime = 'application/pdf';
11748 $imgmime = 'pdf.png';
11749 $famime = 'file-pdf';
11750 } elseif (preg_match('/\.bat$/i', $tmpfile)) { // Scripts
11751 $mime = 'text/x-bat';
11752 $imgmime = 'script.png';
11753 $srclang = 'dos';
11754 $famime = 'file-code';
11755 } elseif (preg_match('/\.sh$/i', $tmpfile)) {
11756 $mime = 'text/x-sh';
11757 $imgmime = 'script.png';
11758 $srclang = 'bash';
11759 $famime = 'file-code';
11760 } elseif (preg_match('/\.ksh$/i', $tmpfile)) {
11761 $mime = 'text/x-ksh';
11762 $imgmime = 'script.png';
11763 $srclang = 'bash';
11764 $famime = 'file-code';
11765 } elseif (preg_match('/\.bash$/i', $tmpfile)) {
11766 $mime = 'text/x-bash';
11767 $imgmime = 'script.png';
11768 $srclang = 'bash';
11769 $famime = 'file-code';
11770 } elseif (preg_match('/\.ico$/i', $tmpfile)) { // Images
11771 $mime = 'image/x-icon';
11772 $imgmime = 'image.png';
11773 $famime = 'file-image';
11774 } elseif (preg_match('/\.(jpg|jpeg)$/i', $tmpfile)) {
11775 $mime = 'image/jpeg';
11776 $imgmime = 'image.png';
11777 $famime = 'file-image';
11778 } elseif (preg_match('/\.png$/i', $tmpfile)) {
11779 $mime = 'image/png';
11780 $imgmime = 'image.png';
11781 $famime = 'file-image';
11782 } elseif (preg_match('/\.gif$/i', $tmpfile)) {
11783 $mime = 'image/gif';
11784 $imgmime = 'image.png';
11785 $famime = 'file-image';
11786 } elseif (preg_match('/\.bmp$/i', $tmpfile)) {
11787 $mime = 'image/bmp';
11788 $imgmime = 'image.png';
11789 $famime = 'file-image';
11790 } elseif (preg_match('/\.(tif|tiff)$/i', $tmpfile)) {
11791 $mime = 'image/tiff';
11792 $imgmime = 'image.png';
11793 $famime = 'file-image';
11794 } elseif (preg_match('/\.svg$/i', $tmpfile)) {
11795 $mime = 'image/svg+xml';
11796 $imgmime = 'image.png';
11797 $famime = 'file-image';
11798 } elseif (preg_match('/\.webp$/i', $tmpfile)) {
11799 $mime = 'image/webp';
11800 $imgmime = 'image.png';
11801 $famime = 'file-image';
11802 } elseif (preg_match('/\.vcs$/i', $tmpfile)) { // Calendar
11803 $mime = 'text/calendar';
11804 $imgmime = 'other.png';
11805 $famime = 'file-alt';
11806 } elseif (preg_match('/\.ics$/i', $tmpfile)) {
11807 $mime = 'text/calendar';
11808 $imgmime = 'other.png';
11809 $famime = 'file-alt';
11810 } elseif (preg_match('/\.torrent$/i', $tmpfile)) { // Other
11811 $mime = 'application/x-bittorrent';
11812 $imgmime = 'other.png';
11813 $famime = 'file-o';
11814 } elseif (preg_match('/\.(mp3|ogg|au|wav|wma|mid)$/i', $tmpfile)) { // Audio
11815 $mime = 'audio';
11816 $imgmime = 'audio.png';
11817 $famime = 'file-audio';
11818 } elseif (preg_match('/\.mp4$/i', $tmpfile)) { // Video
11819 $mime = 'video/mp4';
11820 $imgmime = 'video.png';
11821 $famime = 'file-video';
11822 } elseif (preg_match('/\.ogv$/i', $tmpfile)) {
11823 $mime = 'video/ogg';
11824 $imgmime = 'video.png';
11825 $famime = 'file-video';
11826 } elseif (preg_match('/\.webm$/i', $tmpfile)) {
11827 $mime = 'video/webm';
11828 $imgmime = 'video.png';
11829 $famime = 'file-video';
11830 } elseif (preg_match('/\.avi$/i', $tmpfile)) {
11831 $mime = 'video/x-msvideo';
11832 $imgmime = 'video.png';
11833 $famime = 'file-video';
11834 } elseif (preg_match('/\.divx$/i', $tmpfile)) {
11835 $mime = 'video/divx';
11836 $imgmime = 'video.png';
11837 $famime = 'file-video';
11838 } elseif (preg_match('/\.xvid$/i', $tmpfile)) {
11839 $mime = 'video/xvid';
11840 $imgmime = 'video.png';
11841 $famime = 'file-video';
11842 } elseif (preg_match('/\.(wmv|mpg|mpeg)$/i', $tmpfile)) {
11843 $mime = 'video';
11844 $imgmime = 'video.png';
11845 $famime = 'file-video';
11846 } elseif (preg_match('/\.(zip|rar|gz|tgz|xz|z|cab|bz2|7z|tar|lzh|zst)$/i', $tmpfile)) { // Archive
11847 // application/xxx where zzz is zip, ...
11848 $mime = 'archive';
11849 $imgmime = 'archive.png';
11850 $famime = 'file-archive';
11851 } elseif (preg_match('/\.(exe|com)$/i', $tmpfile)) { // Exe
11852 $mime = 'application/octet-stream';
11853 $imgmime = 'other.png';
11854 $famime = 'file-o';
11855 } elseif (preg_match('/\.(dll|lib|o|so|a)$/i', $tmpfile)) { // Lib
11856 $mime = 'library';
11857 $imgmime = 'library.png';
11858 $famime = 'file-o';
11859 } elseif (preg_match('/\.err$/i', $tmpfile)) { // phpcs:ignore
11860 $mime = 'error';
11861 $imgmime = 'error.png';
11862 $famime = 'file-alt';
11863 }
11864
11865 // Return mimetype string
11866 switch ((int) $mode) {
11867 case 1:
11868 $tmp = explode('/', $mime);
11869 return (!empty($tmp[1]) ? $tmp[1] : $tmp[0]);
11870 case 2:
11871 return $imgmime;
11872 case 3:
11873 return $srclang;
11874 case 4:
11875 return $famime;
11876 }
11877 return $mime;
11878}
11879
11891function getDictionaryValue($tablename, $field, $id, $checkentity = false, $rowidfield = 'rowid')
11892{
11893 global $conf, $db;
11894
11895 $tablename = preg_replace('/^'.preg_quote(MAIN_DB_PREFIX, '/').'/', '', $tablename); // Clean name of table for backward compatibility.
11896
11897 $dictvalues = (isset($conf->cache['dictvalues_'.$tablename]) ? $conf->cache['dictvalues_'.$tablename] : null);
11898
11899 if (is_null($dictvalues)) {
11900 $dictvalues = array();
11901
11902 $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
11903 if ($checkentity) {
11904 $sql .= ' AND entity IN (0,'.getEntity($tablename).')';
11905 }
11906
11907 $resql = $db->query($sql);
11908 if ($resql) {
11909 while ($obj = $db->fetch_object($resql)) {
11910 $dictvalues[$obj->$rowidfield] = $obj; // $obj is stdClass
11911 }
11912 } else {
11913 dol_print_error($db);
11914 }
11915
11916 $conf->cache['dictvalues_'.$tablename] = $dictvalues;
11917 }
11918
11919 if (!empty($dictvalues[$id])) {
11920 // Found
11921 $tmp = $dictvalues[$id];
11922 return (property_exists($tmp, $field) ? $tmp->$field : '');
11923 } else {
11924 // Not found
11925 return '';
11926 }
11927}
11928
11935function colorIsLight($stringcolor)
11936{
11937 $stringcolor = str_replace('#', '', $stringcolor);
11938 $res = -1;
11939 if (!empty($stringcolor)) {
11940 $res = 0;
11941 $tmp = explode(',', $stringcolor);
11942 if (count($tmp) > 1) { // This is a comma RGB ('255','255','255')
11943 $r = $tmp[0];
11944 $g = $tmp[1];
11945 $b = $tmp[2];
11946 } else {
11947 $hexr = $stringcolor[0].$stringcolor[1];
11948 $hexg = $stringcolor[2].$stringcolor[3];
11949 $hexb = $stringcolor[4].$stringcolor[5];
11950 $r = hexdec($hexr);
11951 $g = hexdec($hexg);
11952 $b = hexdec($hexb);
11953 }
11954 $bright = (max($r, $g, $b) + min($r, $g, $b)) / 510.0; // HSL algorithm
11955 if ($bright > 0.6) {
11956 $res = 1;
11957 }
11958 }
11959 return $res;
11960}
11961
11970function isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
11971{
11972 global $conf;
11973
11974 //print 'type_user='.$type_user.' module='.$menuentry['module'].' enabled='.$menuentry['enabled'].' perms='.$menuentry['perms'];
11975 //print 'ok='.in_array($menuentry['module'], $listofmodulesforexternal);
11976 if (empty($menuentry['enabled'])) {
11977 return 0; // Entry disabled by condition
11978 }
11979 if ($type_user && $menuentry['module']) {
11980 $tmploops = explode('|', $menuentry['module']);
11981 $found = 0;
11982 foreach ($tmploops as $tmploop) {
11983 if (in_array($tmploop, $listofmodulesforexternal)) {
11984 $found++;
11985 break;
11986 }
11987 }
11988 if (!$found) {
11989 return 0; // Entry is for menus all excluded to external users
11990 }
11991 }
11992 if (!$menuentry['perms'] && $type_user) {
11993 return 0; // No permissions and user is external
11994 }
11995 if (!$menuentry['perms'] && getDolGlobalString('MAIN_MENU_HIDE_UNAUTHORIZED')) {
11996 return 0; // No permissions and option to hide when not allowed, even for internal user, is on
11997 }
11998 if (!$menuentry['perms']) {
11999 return 2; // No permissions and user is external
12000 }
12001 return 1;
12002}
12003
12011function roundUpToNextMultiple($n, $x = 5)
12012{
12013 $result = (ceil($n) % $x === 0) ? ceil($n) : (round(($n + $x / 2) / $x) * $x);
12014 return (int) $result;
12015}
12016
12028function dolGetBadge($label, $html = '', $type = 'primary', $mode = '', $url = '', $params = array())
12029{
12030 $csstouse = 'badge';
12031 $csstouse .= (!empty($mode) ? ' badge-'.$mode : '');
12032 $csstouse .= (!empty($type) ? ' badge-'.$type : '');
12033 $csstouse .= (empty($params['css']) ? '' : ' '.$params['css']);
12034
12035 $attr = array(
12036 'class' => $csstouse
12037 );
12038
12039 if (empty($html)) {
12040 $html = $label;
12041 }
12042
12043 if (!empty($url)) {
12044 $attr['href'] = $url;
12045 }
12046
12047 if ($mode === 'dot') {
12048 $attr['class'] .= ' classfortooltip';
12049 $attr['title'] = $html;
12050 $attr['aria-label'] = $label;
12051 $html = '';
12052 }
12053
12054 // Override attr
12055 if (!empty($params['attr']) && is_array($params['attr'])) {
12056 foreach ($params['attr'] as $key => $value) {
12057 if ($key == 'class') {
12058 $attr['class'] .= ' '.$value;
12059 } elseif ($key == 'classOverride') {
12060 $attr['class'] = $value;
12061 } else {
12062 $attr[$key] = $value;
12063 }
12064 }
12065 }
12066
12067 // TODO: add hook
12068
12069 // escape all attribute
12070 $attr = array_map('dol_escape_htmltag', $attr);
12071
12072 $TCompiledAttr = array();
12073 foreach ($attr as $key => $value) {
12074 $TCompiledAttr[] = $key.'="'.$value.'"';
12075 }
12076
12077 $compiledAttributes = !empty($TCompiledAttr) ? implode(' ', $TCompiledAttr) : '';
12078
12079 $tag = !empty($url) ? 'a' : 'span';
12080
12081 return '<'.$tag.' '.$compiledAttributes.'>'.$html.'</'.$tag.'>';
12082}
12083
12084
12097function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $statusType = 'status0', $displayMode = 0, $url = '', $params = array())
12098{
12099 global $conf;
12100
12101 $return = '';
12102 $dolGetBadgeParams = array();
12103
12104 if (!empty($params['badgeParams'])) {
12105 $dolGetBadgeParams = $params['badgeParams'];
12106 }
12107
12108 // TODO : add a hook
12109 if ($displayMode == 0) {
12110 $return = !empty($html) ? $html : (empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort));
12111 } elseif ($displayMode == 1) {
12112 $return = !empty($html) ? $html : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
12113 } elseif (getDolGlobalString('MAIN_STATUS_USES_IMAGES')) {
12114 // Use status with images (for backward compatibility)
12115 $return = '';
12116 $htmlLabel = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : $statusLabel).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
12117 $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>' : '');
12118
12119 // For small screen, we always use the short label instead of long label.
12120 if (!empty($conf->dol_optimize_smallscreen)) {
12121 if ($displayMode == 0) {
12122 $displayMode = 1;
12123 } elseif ($displayMode == 4) {
12124 $displayMode = 2;
12125 } elseif ($displayMode == 6) {
12126 $displayMode = 5;
12127 }
12128 }
12129
12130 // For backward compatibility. Image's filename are still in French, so we use this array to convert
12131 $statusImg = array(
12132 'status0' => 'statut0',
12133 'status1' => 'statut1',
12134 'status2' => 'statut2',
12135 'status3' => 'statut3',
12136 'status4' => 'statut4',
12137 'status5' => 'statut5',
12138 'status6' => 'statut6',
12139 'status7' => 'statut7',
12140 'status8' => 'statut8',
12141 'status9' => 'statut9'
12142 );
12143
12144 if (!empty($statusImg[$statusType])) {
12145 $htmlImg = img_picto($statusLabel, $statusImg[$statusType]);
12146 } else {
12147 $htmlImg = img_picto($statusLabel, $statusType);
12148 }
12149
12150 if ($displayMode === 2) {
12151 $return = $htmlImg.' '.$htmlLabelShort;
12152 } elseif ($displayMode === 3) {
12153 $return = $htmlImg;
12154 } elseif ($displayMode === 4) {
12155 $return = $htmlImg.' '.$htmlLabel;
12156 } elseif ($displayMode === 5) {
12157 $return = $htmlLabelShort.' '.$htmlImg;
12158 } else { // $displayMode >= 6
12159 $return = $htmlLabel.' '.$htmlImg;
12160 }
12161 } elseif (!getDolGlobalString('MAIN_STATUS_USES_IMAGES') && !empty($displayMode)) {
12162 // Use new badge
12163 $statusLabelShort = (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
12164
12165 $dolGetBadgeParams['attr']['class'] = 'badge-status';
12166 if (empty($dolGetBadgeParams['attr']['title'])) {
12167 $dolGetBadgeParams['attr']['title'] = empty($params['tooltip']) ? $statusLabel : ($params['tooltip'] != 'no' ? $params['tooltip'] : '');
12168 } else { // If a title was forced from $params['badgeParams']['attr']['title'], we set the class to get it as a tooltip.
12169 $dolGetBadgeParams['attr']['class'] .= ' classfortooltip';
12170 // And if we use tooltip, we can output title in HTML
12171 $dolGetBadgeParams['attr']['title'] = dol_htmlentitiesbr($dolGetBadgeParams['attr']['title'], 1);
12172 }
12173
12174 if ($displayMode == 3) {
12175 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), '', $statusType, 'dot', $url, $dolGetBadgeParams);
12176 } elseif ($displayMode === 5) {
12177 $return = dolGetBadge($statusLabelShort, $html, $statusType, '', $url, $dolGetBadgeParams);
12178 } else {
12179 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), $html, $statusType, '', $url, $dolGetBadgeParams);
12180 }
12181 }
12182
12183 return $return;
12184}
12185
12186
12223function dolGetButtonAction($label, $text = '', $actionType = 'default', $url = '', $id = '', $userRight = 1, $params = array())
12224{
12225 global $hookmanager, $action, $object, $langs;
12226
12227 // If $url is an array, we must build a dropdown button or recursively iterate over each value
12228 if (is_array($url)) {
12229 // Loop on $url array to remove entries of disabled modules
12230 foreach ($url as $key => $subbutton) {
12231 if (isset($subbutton['enabled']) && empty($subbutton['enabled'])) {
12232 unset($url[$key]);
12233 }
12234 }
12235
12236 $out = '';
12237
12238 if (isset($params["areDropdownButtons"]) && $params["areDropdownButtons"] === false) {
12239 foreach ($url as $button) {
12240 if (!empty($button['lang'])) {
12241 $langs->load($button['lang']);
12242 }
12243 $label = $langs->trans($button['label']);
12244 $text = $button['text'] ?? '';
12245 $actionType = $button['actionType'] ?? '';
12246 $tmpUrl = DOL_URL_ROOT.$button['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
12247 $id = $button['$id'] ?? '';
12248 $userRight = $button['perm'] ?? 1;
12249 $params = $button['$params'] ?? [];
12250
12251 $out .= dolGetButtonAction($label, $text, $actionType, $tmpUrl, $id, $userRight, $params);
12252 }
12253 return $out;
12254 }
12255
12256 if (count($url) > 1) {
12257 $out .= '<div class="dropdown inline-block dropdown-holder">';
12258 $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>';
12259 $out .= '<div class="dropdown-content">';
12260 foreach ($url as $subbutton) {
12261 if (!empty($subbutton['lang'])) {
12262 $langs->load($subbutton['lang']);
12263 }
12264 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
12265 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm'], array('isDropDown' => true));
12266 }
12267 $out .= "</div>";
12268 $out .= "</div>";
12269 } else {
12270 foreach ($url as $subbutton) { // Should loop on 1 record only
12271 if (!empty($subbutton['lang'])) {
12272 $langs->load($subbutton['lang']);
12273 }
12274 $tmpurl = DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage']));
12275 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', $tmpurl, '', $subbutton['perm']);
12276 }
12277 }
12278
12279 return $out;
12280 }
12281
12282 // Here, $url is a simple link
12283
12284 if (!empty($params['isDropdown'])) {
12285 $class = "dropdown-item";
12286 } else {
12287 $class = 'butAction';
12288 if ($actionType == 'danger' || $actionType == 'delete') {
12289 $class = 'butActionDelete';
12290 if (!empty($url) && strpos($url, 'token=') === false) {
12291 $url .= '&token='.newToken();
12292 }
12293 }
12294 }
12295 $attr = array(
12296 'class' => $class,
12297 'href' => empty($url) ? '' : $url,
12298 'title' => $label
12299 );
12300
12301 if (empty($text)) {
12302 $text = $label;
12303 $attr['title'] = ''; // if html not set, leave label on title is redundant
12304 } else {
12305 $attr['title'] = $label;
12306 $attr['aria-label'] = $label;
12307 }
12308
12309 if (empty($userRight)) {
12310 $attr['class'] = 'butActionRefused';
12311 $attr['href'] = '';
12312 $attr['title'] = (($label && $text && $label != $text) ? $label : '');
12313 $attr['title'] = ($attr['title'] ? $attr['title'].'<br>' : '').$langs->trans('NotEnoughPermissions');
12314 }
12315
12316 if (!empty($id)) {
12317 $attr['id'] = $id;
12318 }
12319
12320 // Override attr
12321 if (!empty($params['attr']) && is_array($params['attr'])) {
12322 foreach ($params['attr'] as $key => $value) {
12323 if ($key == 'class') {
12324 $attr['class'] .= ' '.$value;
12325 } elseif ($key == 'classOverride') {
12326 $attr['class'] = $value;
12327 } else {
12328 $attr[$key] = $value;
12329 }
12330 }
12331 }
12332
12333 // automatic add tooltip when title is detected
12334 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
12335 $attr['class'] .= ' classfortooltip';
12336 }
12337
12338 // Js Confirm button
12339 if ($userRight && !empty($params['confirm'])) {
12340 if (!is_array($params['confirm'])) {
12341 $params['confirm'] = array();
12342 }
12343
12344 if (empty($params['confirm']['url'])) {
12345 $params['confirm']['url'] = $url . (strpos($url, '?') > 0 ? '&' : '?') . 'confirm=yes';
12346 }
12347
12348 // for js disabled compatibility set $url as call to confirm action and $params['confirm']['url'] to confirmed action
12349 $attr['data-confirm-url'] = $params['confirm']['url'];
12350 $attr['data-confirm-title'] = !empty($params['confirm']['title']) ? $params['confirm']['title'] : $langs->trans('ConfirmBtnCommonTitle', $label);
12351 $attr['data-confirm-content'] = !empty($params['confirm']['content']) ? $params['confirm']['content'] : $langs->trans('ConfirmBtnCommonContent', $label);
12352 $attr['data-confirm-content'] = preg_replace("/\r|\n/", "", $attr['data-confirm-content']);
12353 $attr['data-confirm-action-btn-label'] = !empty($params['confirm']['action-btn-label']) ? $params['confirm']['action-btn-label'] : $langs->trans('Confirm');
12354 $attr['data-confirm-cancel-btn-label'] = !empty($params['confirm']['cancel-btn-label']) ? $params['confirm']['cancel-btn-label'] : $langs->trans('CloseDialog');
12355 $attr['data-confirm-modal'] = !empty($params['confirm']['modal']) ? $params['confirm']['modal'] : true;
12356
12357 $attr['class'] .= ' butActionConfirm';
12358 }
12359
12360 if (isset($attr['href']) && empty($attr['href'])) {
12361 unset($attr['href']);
12362 }
12363
12364 // escape all attribute
12365 $attr = array_map('dol_escape_htmltag', $attr);
12366
12367 $TCompiledAttr = array();
12368 foreach ($attr as $key => $value) {
12369 $TCompiledAttr[] = $key.'= "'.$value.'"';
12370 }
12371
12372 $compiledAttributes = empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr);
12373
12374 $tag = !empty($attr['href']) ? 'a' : 'span';
12375
12376
12377 $parameters = array(
12378 'TCompiledAttr' => $TCompiledAttr, // array
12379 'compiledAttributes' => $compiledAttributes, // string
12380 'attr' => $attr,
12381 'tag' => $tag,
12382 'label' => $label,
12383 'html' => $text,
12384 'actionType' => $actionType,
12385 'url' => $url,
12386 'id' => $id,
12387 'userRight' => $userRight,
12388 'params' => $params
12389 );
12390
12391 $reshook = $hookmanager->executeHooks('dolGetButtonAction', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
12392 if ($reshook < 0) {
12393 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
12394 }
12395
12396 if (empty($reshook)) {
12397 if (dol_textishtml($text)) { // If content already HTML encoded
12398 return '<' . $tag . ' ' . $compiledAttributes . '>' . $text . '</' . $tag . '>';
12399 } else {
12400 return '<' . $tag . ' ' . $compiledAttributes . '>' . dol_escape_htmltag($text) . '</' . $tag . '>';
12401 }
12402 } else {
12403 return $hookmanager->resPrint;
12404 }
12405}
12406
12413function dolGetButtonTitleSeparator($moreClass = "")
12414{
12415 return '<span class="button-title-separator '.$moreClass.'" ></span>';
12416}
12417
12424function getFieldErrorIcon($fieldValidationErrorMsg)
12425{
12426 $out = '';
12427 if (!empty($fieldValidationErrorMsg)) {
12428 $out .= '<span class="field-error-icon classfortooltip" title="'.dol_escape_htmltag($fieldValidationErrorMsg, 1).'" role="alert" >'; // role alert is used for accessibility
12429 $out .= '<span class="fa fa-exclamation-circle" aria-hidden="true" ></span>'; // For accessibility icon is separated and aria-hidden
12430 $out .= '</span>';
12431 }
12432
12433 return $out;
12434}
12435
12448function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $url = '', $id = '', $status = 1, $params = array())
12449{
12450 global $langs, $conf, $user;
12451
12452 // Actually this conf is used in css too for external module compatibility and smooth transition to this function
12453 if (getDolGlobalString('MAIN_BUTTON_HIDE_UNAUTHORIZED') && (!$user->admin) && $status <= 0) {
12454 return '';
12455 }
12456
12457 $class = 'btnTitle';
12458 if (in_array($iconClass, array('fa fa-plus-circle', 'fa fa-plus-circle size15x', 'fa fa-comment-dots', 'fa fa-paper-plane'))) {
12459 $class .= ' btnTitlePlus';
12460 }
12461 $useclassfortooltip = 1;
12462
12463 if (!empty($params['morecss'])) {
12464 $class .= ' '.$params['morecss'];
12465 }
12466
12467 $attr = array(
12468 'class' => $class,
12469 'href' => empty($url) ? '' : $url
12470 );
12471
12472 if (!empty($helpText)) {
12473 $attr['title'] = dol_escape_htmltag($helpText);
12474 } elseif (empty($attr['title']) && $label) {
12475 $attr['title'] = $label;
12476 $useclassfortooltip = 0;
12477 }
12478
12479 if ($status == 2) {
12480 $attr['class'] .= ' btnTitleSelected';
12481 } elseif ($status <= 0) {
12482 $attr['class'] .= ' refused';
12483
12484 $attr['href'] = '';
12485
12486 if ($status == -1) { // disable
12487 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("FeatureDisabled"));
12488 } elseif ($status == 0) { // Not enough permissions
12489 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions"));
12490 }
12491 }
12492
12493 if (!empty($attr['title']) && $useclassfortooltip) {
12494 $attr['class'] .= ' classfortooltip';
12495 }
12496
12497 if (!empty($id)) {
12498 $attr['id'] = $id;
12499 }
12500
12501 // Override attr
12502 if (!empty($params['attr']) && is_array($params['attr'])) {
12503 foreach ($params['attr'] as $key => $value) {
12504 if ($key == 'class') {
12505 $attr['class'] .= ' '.$value;
12506 } elseif ($key == 'classOverride') {
12507 $attr['class'] = $value;
12508 } else {
12509 $attr[$key] = $value;
12510 }
12511 }
12512 }
12513
12514 if (isset($attr['href']) && empty($attr['href'])) {
12515 unset($attr['href']);
12516 }
12517
12518 // TODO : add a hook
12519
12520 // escape all attribute
12521 $attr = array_map('dol_escape_htmltag', $attr);
12522
12523 $TCompiledAttr = array();
12524 foreach ($attr as $key => $value) {
12525 $TCompiledAttr[] = $key.'="'.$value.'"';
12526 }
12527
12528 $compiledAttributes = (empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr));
12529
12530 $tag = (empty($attr['href']) ? 'span' : 'a');
12531
12532 $button = '<'.$tag.' '.$compiledAttributes.'>';
12533 $button .= '<span class="'.$iconClass.' valignmiddle btnTitle-icon"></span>';
12534 if (!empty($params['forcenohideoftext'])) {
12535 $button .= '<span class="valignmiddle text-plus-circle btnTitle-label'.(empty($params['forcenohideoftext']) ? ' hideonsmartphone' : '').'">'.$label.'</span>';
12536 }
12537 $button .= '</'.$tag.'>';
12538
12539 return $button;
12540}
12541
12551function getElementProperties($elementType)
12552{
12553 global $conf, $db, $hookmanager;
12554
12555 $regs = array();
12556
12557 //$element_type='facture';
12558
12559 $classfile = $classname = $classpath = $subdir = $dir_output = '';
12560
12561 // Parse element/subelement
12562 $module = $elementType;
12563 $element = $elementType;
12564 $subelement = $elementType;
12565 $table_element = $elementType;
12566
12567 // If we ask a resource form external module (instead of default path)
12568 if (preg_match('/^([^@]+)@([^@]+)$/i', $elementType, $regs)) { // 'myobject@mymodule'
12569 $element = $subelement = $regs[1];
12570 $module = $regs[2];
12571 }
12572
12573 // If we ask a resource for a string with an element and a subelement
12574 // Example 'project_task'
12575 if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { // 'myobject_mysubobject' with myobject=mymodule
12576 $module = $element = $regs[1];
12577 $subelement = $regs[2];
12578 }
12579
12580 // Object lines will use parent classpath and module ref
12581 if (substr($elementType, -3) == 'det') {
12582 $module = preg_replace('/det$/', '', $element);
12583 $subelement = preg_replace('/det$/', '', $subelement);
12584 $classpath = $module.'/class';
12585 $classfile = $module;
12586 $classname = preg_replace('/det$/', 'Line', $element);
12587 if (in_array($module, array('expedition', 'propale', 'facture', 'contrat', 'fichinter', 'commandefournisseur'))) {
12588 $classname = preg_replace('/det$/', 'Ligne', $element);
12589 }
12590 }
12591 // For compatibility and to work with non standard path
12592 if ($elementType == "action" || $elementType == "actioncomm") {
12593 $classpath = 'comm/action/class';
12594 $subelement = 'Actioncomm';
12595 $module = 'agenda';
12596 $table_element = 'actioncomm';
12597 } elseif ($elementType == 'cronjob') {
12598 $classpath = 'cron/class';
12599 $module = 'cron';
12600 $table_element = 'cron';
12601 } elseif ($elementType == 'adherent_type') {
12602 $classpath = 'adherents/class';
12603 $classfile = 'adherent_type';
12604 $module = 'adherent';
12605 $subelement = 'adherent_type';
12606 $classname = 'AdherentType';
12607 $table_element = 'adherent_type';
12608 } elseif ($elementType == 'bank_account') {
12609 $classpath = 'compta/bank/class';
12610 $module = 'bank'; // We need $conf->bank->dir_output and not $conf->banque->dir_output
12611 $classfile = 'account';
12612 $classname = 'Account';
12613 } elseif ($elementType == 'category') {
12614 $classpath = 'categories/class';
12615 $module = 'categorie';
12616 $subelement = 'categorie';
12617 $table_element = 'categorie';
12618 } elseif ($elementType == 'contact') {
12619 $classpath = 'contact/class';
12620 $classfile = 'contact';
12621 $module = 'societe';
12622 $subelement = 'contact';
12623 $table_element = 'socpeople';
12624 } elseif ($elementType == 'inventory') {
12625 $module = 'product';
12626 $classpath = 'product/inventory/class';
12627 } elseif ($elementType == 'stock' || $elementType == 'entrepot') {
12628 $module = 'stock';
12629 $classpath = 'product/stock/class';
12630 $classfile = 'entrepot';
12631 $classname = 'Entrepot';
12632 $table_element = 'entrepot';
12633 } elseif ($elementType == 'project') {
12634 $classpath = 'projet/class';
12635 $module = 'projet';
12636 $table_element = 'projet';
12637 } elseif ($elementType == 'project_task') {
12638 $classpath = 'projet/class';
12639 $module = 'projet';
12640 $subelement = 'task';
12641 $table_element = 'projet_task';
12642 } elseif ($elementType == 'facture' || $elementType == 'invoice') {
12643 $classpath = 'compta/facture/class';
12644 $module = 'facture';
12645 $subelement = 'facture';
12646 $table_element = 'facture';
12647 } elseif ($elementType == 'facturerec') {
12648 $classpath = 'compta/facture/class';
12649 $module = 'facture';
12650 $classname = 'FactureRec';
12651 } elseif ($elementType == 'commande' || $elementType == 'order') {
12652 $classpath = 'commande/class';
12653 $module = 'commande';
12654 $subelement = 'commande';
12655 $table_element = 'commande';
12656 } elseif ($elementType == 'propal') {
12657 $classpath = 'comm/propal/class';
12658 $table_element = 'propal';
12659 } elseif ($elementType == 'shipping') {
12660 $classpath = 'expedition/class';
12661 $classfile = 'expedition';
12662 $classname = 'Expedition';
12663 $module = 'expedition';
12664 $table_element = 'expedition';
12665 } elseif ($elementType == 'delivery_note') {
12666 $classpath = 'delivery/class';
12667 $subelement = 'delivery';
12668 $module = 'expedition';
12669 } elseif ($elementType == 'delivery') {
12670 $classpath = 'delivery/class';
12671 $subelement = 'delivery';
12672 $module = 'expedition';
12673 } elseif ($elementType == 'supplier_proposal') {
12674 $classpath = 'supplier_proposal/class';
12675 $module = 'supplier_proposal';
12676 $element = 'supplierproposal';
12677 $classfile = 'supplier_proposal';
12678 $subelement = 'supplierproposal';
12679 } elseif ($elementType == 'contract') {
12680 $classpath = 'contrat/class';
12681 $module = 'contrat';
12682 $subelement = 'contrat';
12683 $table_element = 'contract';
12684 } elseif ($elementType == 'mailing') {
12685 $classpath = 'comm/mailing/class';
12686 $module = 'mailing';
12687 $classfile = 'mailing';
12688 $classname = 'Mailing';
12689 $subelement = '';
12690 } elseif ($elementType == 'member') {
12691 $classpath = 'adherents/class';
12692 $module = 'adherent';
12693 $subelement = 'adherent';
12694 $table_element = 'adherent';
12695 } elseif ($elementType == 'usergroup') {
12696 $classpath = 'user/class';
12697 $module = 'user';
12698 } elseif ($elementType == 'mo') {
12699 $classpath = 'mrp/class';
12700 $classfile = 'mo';
12701 $classname = 'Mo';
12702 $module = 'mrp';
12703 $subelement = '';
12704 $table_element = 'mrp_mo';
12705 } elseif ($elementType == 'cabinetmed_cons') {
12706 $classpath = 'cabinetmed/class';
12707 $module = 'cabinetmed';
12708 $subelement = 'cabinetmedcons';
12709 $table_element = 'cabinetmedcons';
12710 } elseif ($elementType == 'fichinter') {
12711 $classpath = 'fichinter/class';
12712 $module = 'ficheinter';
12713 $subelement = 'fichinter';
12714 $table_element = 'fichinter';
12715 } elseif ($elementType == 'dolresource' || $elementType == 'resource') {
12716 $classpath = 'resource/class';
12717 $module = 'resource';
12718 $subelement = 'dolresource';
12719 $table_element = 'resource';
12720 } elseif ($elementType == 'propaldet') {
12721 $classpath = 'comm/propal/class';
12722 $module = 'propal';
12723 $subelement = 'propaleligne';
12724 } elseif ($elementType == 'opensurvey_sondage') {
12725 $classpath = 'opensurvey/class';
12726 $module = 'opensurvey';
12727 $subelement = 'opensurveysondage';
12728 } elseif ($elementType == 'order_supplier') {
12729 $classpath = 'fourn/class';
12730 $module = 'fournisseur';
12731 $classfile = 'fournisseur.commande';
12732 $element = 'order_supplier';
12733 $subelement = '';
12734 $classname = 'CommandeFournisseur';
12735 $table_element = 'commande_fournisseur';
12736 } elseif ($elementType == 'commande_fournisseurdet') {
12737 $classpath = 'fourn/class';
12738 $module = 'fournisseur';
12739 $classfile = 'fournisseur.commande';
12740 $element = 'commande_fournisseurdet';
12741 $subelement = '';
12742 $classname = 'CommandeFournisseurLigne';
12743 $table_element = 'commande_fournisseurdet';
12744 } elseif ($elementType == 'invoice_supplier') {
12745 $classpath = 'fourn/class';
12746 $module = 'fournisseur';
12747 $classfile = 'fournisseur.facture';
12748 $element = 'invoice_supplier';
12749 $subelement = '';
12750 $classname = 'FactureFournisseur';
12751 $table_element = 'facture_fourn';
12752 } elseif ($elementType == "service") {
12753 $classpath = 'product/class';
12754 $subelement = 'product';
12755 $table_element = 'product';
12756 } elseif ($elementType == 'salary') {
12757 $classpath = 'salaries/class';
12758 $module = 'salaries';
12759 } elseif ($elementType == 'payment_salary') {
12760 $classpath = 'salaries/class';
12761 $classfile = 'paymentsalary';
12762 $classname = 'PaymentSalary';
12763 $module = 'salaries';
12764 } elseif ($elementType == 'productlot') {
12765 $module = 'productbatch';
12766 $classpath = 'product/stock/class';
12767 $classfile = 'productlot';
12768 $classname = 'Productlot';
12769 $element = 'productlot';
12770 $subelement = '';
12771 $table_element = 'product_lot';
12772 } elseif ($elementType == 'societeaccount') {
12773 $classpath = 'societe/class';
12774 $classfile = 'societeaccount';
12775 $classname = 'SocieteAccount';
12776 $module = 'societe';
12777 } elseif ($elementType == 'websitepage') {
12778 $classpath = 'website/class';
12779 $classfile = 'websitepage';
12780 $classname = 'Websitepage';
12781 $module = 'website';
12782 $subelement = 'websitepage';
12783 $table_element = 'website_page';
12784 } elseif ($elementType == 'fiscalyear') {
12785 $classpath = 'core/class';
12786 $module = 'accounting';
12787 $subelement = 'fiscalyear';
12788 } elseif ($elementType == 'chargesociales') {
12789 $classpath = 'compta/sociales/class';
12790 $module = 'tax';
12791 $table_element = 'chargesociales';
12792 } elseif ($elementType == 'tva') {
12793 $classpath = 'compta/tva/class';
12794 $module = 'tax';
12795 $subdir = '/vat';
12796 $table_element = 'tva';
12797 } elseif ($elementType == 'emailsenderprofile') {
12798 $module = '';
12799 $classpath = 'core/class';
12800 $classfile = 'emailsenderprofile';
12801 $classname = 'EmailSenderProfile';
12802 $table_element = 'c_email_senderprofile';
12803 $subelement = '';
12804 } elseif ($elementType == 'conferenceorboothattendee') {
12805 $classpath = 'eventorganization/class';
12806 $classfile = 'conferenceorboothattendee';
12807 $classname = 'ConferenceOrBoothAttendee';
12808 $module = 'eventorganization';
12809 } elseif ($elementType == 'conferenceorbooth') {
12810 $classpath = 'eventorganization/class';
12811 $classfile = 'conferenceorbooth';
12812 $classname = 'ConferenceOrBooth';
12813 $module = 'eventorganization';
12814 } elseif ($elementType == 'ccountry') {
12815 $module = '';
12816 $classpath = 'core/class';
12817 $classfile = 'ccountry';
12818 $classname = 'Ccountry';
12819 $table_element = 'c_country';
12820 $subelement = '';
12821 }
12822
12823 if (empty($classfile)) {
12824 $classfile = strtolower($subelement);
12825 }
12826 if (empty($classname)) {
12827 $classname = ucfirst($subelement);
12828 }
12829 if (empty($classpath)) {
12830 $classpath = $module.'/class';
12831 }
12832
12833 //print 'getElementProperties subdir='.$subdir;
12834
12835 // Set dir_output
12836 if ($module && isset($conf->$module)) { // The generic case
12837 if (!empty($conf->$module->multidir_output[$conf->entity])) {
12838 $dir_output = $conf->$module->multidir_output[$conf->entity];
12839 } elseif (!empty($conf->$module->output[$conf->entity])) {
12840 $dir_output = $conf->$module->output[$conf->entity];
12841 } elseif (!empty($conf->$module->dir_output)) {
12842 $dir_output = $conf->$module->dir_output;
12843 }
12844 }
12845
12846 // Overwrite value for special cases
12847 if ($element == 'order_supplier') {
12848 $dir_output = $conf->fournisseur->commande->dir_output;
12849 } elseif ($element == 'invoice_supplier') {
12850 $dir_output = $conf->fournisseur->facture->dir_output;
12851 }
12852 $dir_output .= $subdir;
12853
12854 $elementProperties = array(
12855 'module' => $module,
12856 'element' => $element,
12857 'table_element' => $table_element,
12858 'subelement' => $subelement,
12859 'classpath' => $classpath,
12860 'classfile' => $classfile,
12861 'classname' => $classname,
12862 'dir_output' => $dir_output
12863 );
12864
12865
12866 // Add hook
12867 if (!is_object($hookmanager)) {
12868 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
12869 $hookmanager = new HookManager($db);
12870 }
12871 $hookmanager->initHooks(array('elementproperties'));
12872
12873
12874 // Hook params
12875 $parameters = array(
12876 'elementType' => $elementType,
12877 'elementProperties' => $elementProperties
12878 );
12879
12880 $reshook = $hookmanager->executeHooks('getElementProperties', $parameters);
12881
12882 if ($reshook) {
12883 $elementProperties = $hookmanager->resArray;
12884 } elseif (!empty($hookmanager->resArray) && is_array($hookmanager->resArray)) { // resArray is always an array but for sécurity against misconfigured external modules
12885 $elementProperties = array_replace($elementProperties, $hookmanager->resArray);
12886 }
12887
12888 // context of elementproperties doesn't need to exist out of this function so delete it to avoid elementproperties context is equal to all
12889 if (($key = array_search('elementproperties', $hookmanager->contextarray)) !== false) {
12890 unset($hookmanager->contextarray[$key]);
12891 }
12892
12893 return $elementProperties;
12894}
12895
12908function fetchObjectByElement($element_id, $element_type, $element_ref = '', $useCache = 0, $maxCacheByType = 10)
12909{
12910 global $db, $globalCacheForGetObjectFromCache;
12911
12912 $ret = 0;
12913
12914 $element_prop = getElementProperties($element_type);
12915
12916 if ($element_prop['module'] == 'product' || $element_prop['module'] == 'service') {
12917 // For example, for an extrafield 'product' (shared for both product and service) that is a link to an object,
12918 // this is called with $element_type = 'product' when we need element properties of a service, we must return a product. If we create the
12919 // extrafield for a service, it is not supported and not found when editing the product/service card. So we must keep 'product' for extrafields
12920 // of service and we will return properties of a product.
12921 $ismodenabled = (isModEnabled('product') || isModEnabled('service'));
12922 } elseif ($element_prop['module'] == 'societeaccount') {
12923 $ismodenabled = isModEnabled('website') || isModEnabled('webportal');
12924 } else {
12925 $ismodenabled = isModEnabled($element_prop['module']);
12926 }
12927 //var_dump('element_type='.$element_type);
12928 //var_dump($element_prop);
12929 //var_dump($element_prop['module'].' '.$ismodenabled);
12930 if (is_array($element_prop) && (empty($element_prop['module']) || $ismodenabled)) {
12931 if ($useCache === 1
12932 && !empty($globalCacheForGetObjectFromCache[$element_type])
12933 && !empty($globalCacheForGetObjectFromCache[$element_type][$element_id])
12934 && is_object($globalCacheForGetObjectFromCache[$element_type][$element_id])
12935 ) {
12936 return $globalCacheForGetObjectFromCache[$element_type][$element_id];
12937 }
12938
12939 dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php');
12940
12941 if (class_exists($element_prop['classname'])) {
12942 $className = $element_prop['classname'];
12943 $objecttmp = new $className($db);
12944 '@phan-var-force CommonObject $objecttmp';
12945
12946 if ($element_id > 0 || !empty($element_ref)) {
12947 $ret = $objecttmp->fetch($element_id, $element_ref);
12948 if ($ret >= 0) {
12949 if (empty($objecttmp->module)) {
12950 $objecttmp->module = $element_prop['module'];
12951 }
12952
12953 if ($useCache > 0) {
12954 if (!isset($globalCacheForGetObjectFromCache[$element_type])) {
12955 $globalCacheForGetObjectFromCache[$element_type] = [];
12956 }
12957
12958 // Manage cache limit
12959 if (! empty($globalCacheForGetObjectFromCache[$element_type]) && is_array($globalCacheForGetObjectFromCache[$element_type]) && count($globalCacheForGetObjectFromCache[$element_type]) >= $maxCacheByType) {
12960 array_shift($globalCacheForGetObjectFromCache[$element_type]);
12961 }
12962
12963 $globalCacheForGetObjectFromCache[$element_type][$element_id] = $objecttmp;
12964 }
12965
12966 return $objecttmp;
12967 }
12968 } else {
12969 return $objecttmp; // returned an object without fetch
12970 }
12971 } else {
12972 return -1;
12973 }
12974 }
12975
12976 return $ret;
12977}
12978
12985function isAFileWithExecutableContent($filename)
12986{
12987 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)) {
12988 return true;
12989 }
12990
12991 return false;
12992}
12993
13001function newToken()
13002{
13003 return empty($_SESSION['newtoken']) ? '' : $_SESSION['newtoken'];
13004}
13005
13013function currentToken()
13014{
13015 return isset($_SESSION['token']) ? $_SESSION['token'] : '';
13016}
13017
13023function getNonce()
13024{
13025 global $conf;
13026
13027 if (empty($conf->cache['nonce'])) {
13028 $conf->cache['nonce'] = dolGetRandomBytes(8);
13029 }
13030
13031 return $conf->cache['nonce'];
13032}
13033
13034
13048function startSimpleTable($header, $link = "", $arguments = "", $emptyColumns = 0, $number = -1, $pictofulllist = '')
13049{
13050 global $langs;
13051
13052 print '<div class="div-table-responsive-no-min">';
13053 print '<table class="noborder centpercent">';
13054 print '<tr class="liste_titre">';
13055
13056 print ($emptyColumns < 1) ? '<th>' : '<th colspan="'.($emptyColumns + 1).'">';
13057
13058 print '<span class="valignmiddle">'.$langs->trans($header).'</span>';
13059
13060 if (!empty($link)) {
13061 if (!empty($arguments)) {
13062 print '<a href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
13063 } else {
13064 print '<a href="'.DOL_URL_ROOT.'/'.$link.'">';
13065 }
13066 }
13067
13068 if ($number > -1) {
13069 print '<span class="badge marginleftonlyshort">'.$number.'</span>';
13070 } elseif (!empty($link)) {
13071 print '<span class="badge marginleftonlyshort">...</span>';
13072 }
13073
13074 if (!empty($link)) {
13075 print '</a>';
13076 }
13077
13078 print '</th>';
13079
13080 if ($number < 0 && !empty($link)) {
13081 print '<th class="right">';
13082 print '</th>';
13083 }
13084
13085 print '</tr>';
13086}
13087
13096function finishSimpleTable($addLineBreak = false)
13097{
13098 print '</table>';
13099 print '</div>';
13100
13101 if ($addLineBreak) {
13102 print '<br>';
13103 }
13104}
13105
13117function addSummaryTableLine($tableColumnCount, $num, $nbofloop = 0, $total = 0, $noneWord = "None", $extraRightColumn = false)
13118{
13119 global $langs;
13120
13121 if ($num === 0) {
13122 print '<tr class="oddeven">';
13123 print '<td colspan="'.$tableColumnCount.'"><span class="opacitymedium">'.$langs->trans($noneWord).'</span></td>';
13124 print '</tr>';
13125 return;
13126 }
13127
13128 if ($nbofloop === 0) {
13129 // don't show a summary line
13130 return;
13131 }
13132
13133 if ($num === 0) {
13134 $colspan = $tableColumnCount;
13135 } elseif ($num > $nbofloop) {
13136 $colspan = $tableColumnCount;
13137 } else {
13138 $colspan = $tableColumnCount - 1;
13139 }
13140
13141 if ($extraRightColumn) {
13142 $colspan--;
13143 }
13144
13145 print '<tr class="liste_total">';
13146
13147 if ($nbofloop > 0 && $num > $nbofloop) {
13148 print '<td colspan="'.$colspan.'" class="right">'.$langs->trans("XMoreLines", ($num - $nbofloop)).'</td>';
13149 } else {
13150 print '<td colspan="'.$colspan.'" class="right"> '.$langs->trans("Total").'</td>';
13151 print '<td class="right centpercent">'.price($total).'</td>';
13152 }
13153
13154 if ($extraRightColumn) {
13155 print '<td></td>';
13156 }
13157
13158 print '</tr>';
13159}
13160
13169function readfileLowMemory($fullpath_original_file_osencoded, $method = -1)
13170{
13171 if ($method == -1) {
13172 $method = 0;
13173 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_FREAD')) {
13174 $method = 1;
13175 }
13176 if (getDolGlobalString('MAIN_FORCE_READFILE_WITH_STREAM_COPY')) {
13177 $method = 2;
13178 }
13179 }
13180
13181 // Be sure we don't have output buffering enabled to have readfile working correctly
13182 while (ob_get_level()) {
13183 ob_end_flush();
13184 }
13185
13186 // Solution 0
13187 if ($method == 0) {
13188 readfile($fullpath_original_file_osencoded);
13189 } elseif ($method == 1) {
13190 // Solution 1
13191 $handle = fopen($fullpath_original_file_osencoded, "rb");
13192 while (!feof($handle)) {
13193 print fread($handle, 8192);
13194 }
13195 fclose($handle);
13196 } elseif ($method == 2) {
13197 // Solution 2
13198 $handle1 = fopen($fullpath_original_file_osencoded, "rb");
13199 $handle2 = fopen("php://output", "wb");
13200 stream_copy_to_stream($handle1, $handle2);
13201 fclose($handle1);
13202 fclose($handle2);
13203 }
13204}
13205
13215function showValueWithClipboardCPButton($valuetocopy, $showonlyonhover = 1, $texttoshow = '')
13216{
13217 /*
13218 global $conf;
13219
13220 if (!empty($conf->dol_no_mouse_hover)) {
13221 $showonlyonhover = 0;
13222 }*/
13223
13224 $tag = 'span'; // Using div (like any style of type 'block') does not work when using the js copy code.
13225 if ($texttoshow === 'none') {
13226 $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>';
13227 } elseif ($texttoshow) {
13228 $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>';
13229 } else {
13230 $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>';
13231 }
13232
13233 return $result;
13234}
13235
13236
13243function jsonOrUnserialize($stringtodecode)
13244{
13245 $result = json_decode($stringtodecode);
13246 if ($result === null) {
13247 $result = unserialize($stringtodecode);
13248 }
13249
13250 return $result;
13251}
13252
13253
13270function forgeSQLFromUniversalSearchCriteria($filter, &$errorstr = '', $noand = 0, $nopar = 0, $noerror = 0)
13271{
13272 global $db, $user;
13273
13274 if ($filter === '') {
13275 return '';
13276 }
13277 if (!preg_match('/^\‍(.*\‍)$/', $filter)) { // If $filter does not start and end with ()
13278 $filter = '(' . $filter . ')';
13279 }
13280
13281 $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'
13282 $firstandlastparenthesis = 0;
13283
13284 if (!dolCheckFilters($filter, $errorstr, $firstandlastparenthesis)) {
13285 if ($noerror) {
13286 return '1 = 2';
13287 } else {
13288 return 'Filter syntax error - '.$errorstr; // Bad balance of parenthesis, we return an error message or force a SQL not found
13289 }
13290 }
13291
13292 // Test the filter syntax
13293 $t = preg_replace_callback('/'.$regexstring.'/i', 'dolForgeDummyCriteriaCallback', $filter);
13294 $t = str_replace(array('and','or','AND','OR',' '), '', $t); // Remove the only strings allowed between each () criteria
13295 // If the string result contains something else than '()', the syntax was wrong
13296
13297 if (preg_match('/[^\‍(\‍)]/', $t)) {
13298 $tmperrorstr = 'Bad syntax of the search string';
13299 $errorstr = 'Bad syntax of the search string: '.$filter;
13300 if ($noerror) {
13301 return '1 = 2';
13302 } else {
13303 return 'Filter error - '.$tmperrorstr; // Bad syntax of the search string, we return an error message or force a SQL not found
13304 }
13305 }
13306
13307 $ret = ($noand ? "" : " AND ").($nopar ? "" : '(').preg_replace_callback('/'.$regexstring.'/i', 'dolForgeCriteriaCallback', $filter).($nopar ? "" : ')');
13308
13309 if (is_object($db)) {
13310 $ret = str_replace('__NOW__', $db->idate(dol_now()), $ret);
13311 }
13312 if (is_object($user)) {
13313 $ret = str_replace('__USER_ID__', (string) $user->id, $ret);
13314 }
13315
13316 return $ret;
13317}
13318
13326function dolForgeExplodeAnd($sqlfilters)
13327{
13328 $arrayofandtags = array();
13329 $nbofchars = dol_strlen($sqlfilters);
13330
13331 $error = '';
13332 $parenthesislevel = 0;
13333 $result = dolCheckFilters($sqlfilters, $error, $parenthesislevel);
13334 if (!$result) {
13335 return array();
13336 }
13337 if ($parenthesislevel >= 1) {
13338 $sqlfilters = preg_replace('/^\‍(/', '', preg_replace('/\‍)$/', '', $sqlfilters));
13339 }
13340
13341 $i = 0;
13342 $s = '';
13343 $countparenthesis = 0;
13344 while ($i < $nbofchars) {
13345 $char = dol_substr($sqlfilters, $i, 1);
13346
13347 if ($char == '(') {
13348 $countparenthesis++;
13349 } elseif ($char == ')') {
13350 $countparenthesis--;
13351 }
13352
13353 if ($countparenthesis == 0) {
13354 $char2 = dol_substr($sqlfilters, $i + 1, 1);
13355 $char3 = dol_substr($sqlfilters, $i + 2, 1);
13356 if ($char == 'A' && $char2 == 'N' && $char3 == 'D') {
13357 // We found a AND
13358 $s = trim($s);
13359 if (!preg_match('/^\‍(.*\‍)$/', $s)) {
13360 $s = '('.$s.')';
13361 }
13362 $arrayofandtags[] = $s;
13363 $s = '';
13364 $i += 2;
13365 } else {
13366 $s .= $char;
13367 }
13368 } else {
13369 $s .= $char;
13370 }
13371 $i++;
13372 }
13373 if ($s) {
13374 $s = trim($s);
13375 if (!preg_match('/^\‍(.*\‍)$/', $s)) {
13376 $s = '('.$s.')';
13377 }
13378 $arrayofandtags[] = $s;
13379 }
13380
13381 return $arrayofandtags;
13382}
13383
13393function dolCheckFilters($sqlfilters, &$error = '', &$parenthesislevel = 0)
13394{
13395 //$regexstring='\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^:\‍(\‍)]+)\‍)';
13396 //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
13397 $tmp = $sqlfilters;
13398
13399 $nb = dol_strlen($tmp);
13400 $counter = 0;
13401 $parenthesislevel = 0;
13402
13403 $error = '';
13404
13405 $i = 0;
13406 while ($i < $nb) {
13407 $char = dol_substr($tmp, $i, 1);
13408
13409 if ($char == '(') {
13410 if ($i == $parenthesislevel && $parenthesislevel == $counter) {
13411 // We open a parenthesis and it is the first char
13412 $parenthesislevel++;
13413 }
13414 $counter++;
13415 } elseif ($char == ')') {
13416 $nbcharremaining = ($nb - $i - 1);
13417 if ($nbcharremaining >= $counter) {
13418 $parenthesislevel = min($parenthesislevel, $counter - 1);
13419 }
13420 if ($parenthesislevel > $counter && $nbcharremaining >= $counter) {
13421 $parenthesislevel = $counter;
13422 }
13423 $counter--;
13424 }
13425
13426 if ($counter < 0) {
13427 $error = "Wrong balance of parenthesis in sqlfilters=".$sqlfilters;
13428 $parenthesislevel = 0;
13429 dol_syslog($error, LOG_WARNING);
13430 return false;
13431 }
13432
13433 $i++;
13434 }
13435
13436 if ($counter > 0) {
13437 $error = "Wrong balance of parenthesis in sqlfilters=".$sqlfilters;
13438 $parenthesislevel = 0;
13439 dol_syslog($error, LOG_WARNING);
13440 return false;
13441 }
13442
13443 return true;
13444}
13445
13453function dolForgeDummyCriteriaCallback($matches)
13454{
13455 //dol_syslog("Convert matches ".$matches[1]);
13456 if (empty($matches[1])) {
13457 return '';
13458 }
13459 $tmp = explode(':', $matches[1]);
13460 if (count($tmp) < 3) {
13461 return '';
13462 }
13463
13464 return '()'; // An empty criteria
13465}
13466
13475function dolForgeCriteriaCallback($matches)
13476{
13477 global $db;
13478
13479 //dol_syslog("Convert matches ".$matches[1]);
13480 if (empty($matches[1])) {
13481 return '';
13482 }
13483 $tmp = explode(':', $matches[1], 3);
13484 if (count($tmp) < 3) {
13485 return '';
13486 }
13487
13488 $operand = preg_replace('/[^a-z0-9\._]/i', '', trim($tmp[0]));
13489
13490 $operator = strtoupper(preg_replace('/[^a-z<>!=]/i', '', trim($tmp[1])));
13491
13492 $realOperator = [
13493 'NOTLIKE' => 'NOT LIKE',
13494 'ISNOT' => 'IS NOT',
13495 'NOTIN' => 'NOT IN',
13496 '!=' => '<>',
13497 ];
13498
13499 if (array_key_exists($operator, $realOperator)) {
13500 $operator = $realOperator[$operator];
13501 }
13502
13503 $tmpescaped = $tmp[2];
13504
13505 //print "Case: ".$operator." ".$operand." ".$tmpescaped."\n";
13506
13507 $regbis = array();
13508
13509 if ($operator == 'IN' || $operator == 'NOT IN') { // IN is allowed for list of ID or code only
13510 //if (!preg_match('/^\‍(.*\‍)$/', $tmpescaped)) {
13511 $tmpescaped2 = '(';
13512 // Explode and sanitize each element in list
13513 $tmpelemarray = explode(',', $tmpescaped);
13514 foreach ($tmpelemarray as $tmpkey => $tmpelem) {
13515 $reg = array();
13516 if (preg_match('/^\'(.*)\'$/', $tmpelem, $reg)) {
13517 $tmpelemarray[$tmpkey] = "'".$db->escape($db->sanitize($reg[1], 1, 1, 1))."'";
13518 } else {
13519 $tmpelemarray[$tmpkey] = $db->escape($db->sanitize($tmpelem, 1, 1, 1));
13520 }
13521 }
13522 $tmpescaped2 .= implode(',', $tmpelemarray);
13523 $tmpescaped2 .= ')';
13524
13525 $tmpescaped = $tmpescaped2;
13526 } elseif ($operator == 'LIKE' || $operator == 'NOT LIKE') {
13527 if (preg_match('/^\'([^\']*)\'$/', $tmpescaped, $regbis)) {
13528 $tmpescaped = $regbis[1];
13529 }
13530 //$tmpescaped = "'".$db->escape($db->escapeforlike($regbis[1]))."'";
13531 $tmpescaped = "'".$db->escape($tmpescaped)."'"; // We do not escape the _ and % so the LIKE will work as expected
13532 } elseif (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
13533 // TODO Retrieve type of field for $operand field name.
13534 // So we can complete format. For example we could complete a year with month and day.
13535 $tmpescaped = "'".$db->escape($regbis[1])."'";
13536 } else {
13537 if (strtoupper($tmpescaped) == 'NULL') {
13538 $tmpescaped = 'NULL';
13539 } elseif (is_int($tmpescaped)) {
13540 $tmpescaped = (int) $tmpescaped;
13541 } else {
13542 $tmpescaped = (float) $tmpescaped;
13543 }
13544 }
13545
13546 return '('.$db->escape($operand).' '.strtoupper($operator).' '.$tmpescaped.')';
13547}
13548
13549
13559function getTimelineIcon($actionstatic, &$histo, $key)
13560{
13561 global $langs;
13562
13563 $out = '<!-- timeline icon -->'."\n";
13564 $iconClass = 'fa fa-comments';
13565 $img_picto = '';
13566 $colorClass = '';
13567 $pictoTitle = '';
13568
13569 if ($histo[$key]['percent'] == -1) {
13570 $colorClass = 'timeline-icon-not-applicble';
13571 $pictoTitle = $langs->trans('StatusNotApplicable');
13572 } elseif ($histo[$key]['percent'] == 0) {
13573 $colorClass = 'timeline-icon-todo';
13574 $pictoTitle = $langs->trans('StatusActionToDo').' (0%)';
13575 } elseif ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100) {
13576 $colorClass = 'timeline-icon-in-progress';
13577 $pictoTitle = $langs->trans('StatusActionInProcess').' ('.$histo[$key]['percent'].'%)';
13578 } elseif ($histo[$key]['percent'] >= 100) {
13579 $colorClass = 'timeline-icon-done';
13580 $pictoTitle = $langs->trans('StatusActionDone').' (100%)';
13581 }
13582
13583 if ($actionstatic->code == 'AC_TICKET_CREATE') {
13584 $iconClass = 'fa fa-ticket';
13585 } elseif ($actionstatic->code == 'AC_TICKET_MODIFY') {
13586 $iconClass = 'fa fa-pencilxxx';
13587 } elseif (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
13588 $iconClass = 'fa fa-comments';
13589 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
13590 $iconClass = 'fa fa-mask';
13591 } elseif (getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
13592 if ($actionstatic->type_picto) {
13593 $img_picto = img_picto('', $actionstatic->type_picto);
13594 } else {
13595 if ($actionstatic->type_code == 'AC_RDV') {
13596 $iconClass = 'fa fa-handshake';
13597 } elseif ($actionstatic->type_code == 'AC_TEL') {
13598 $iconClass = 'fa fa-phone';
13599 } elseif ($actionstatic->type_code == 'AC_FAX') {
13600 $iconClass = 'fa fa-fax';
13601 } elseif ($actionstatic->type_code == 'AC_EMAIL') {
13602 $iconClass = 'fa fa-envelope';
13603 } elseif ($actionstatic->type_code == 'AC_INT') {
13604 $iconClass = 'fa fa-shipping-fast';
13605 } elseif ($actionstatic->type_code == 'AC_OTH_AUTO') {
13606 $iconClass = 'fa fa-robot';
13607 } elseif (!preg_match('/_AUTO/', $actionstatic->type_code)) {
13608 $iconClass = 'fa fa-robot';
13609 }
13610 }
13611 }
13612
13613 $out .= '<i class="'.$iconClass.' '.$colorClass.'" title="'.$pictoTitle.'">'.$img_picto.'</i>'."\n";
13614 return $out;
13615}
13616
13624{
13625 global $conf, $db;
13626
13627 $documents = array();
13628
13629 $sql = 'SELECT ecm.rowid as id, ecm.src_object_type, ecm.src_object_id, ecm.filepath, ecm.filename';
13630 $sql .= ' FROM '.MAIN_DB_PREFIX.'ecm_files ecm';
13631 $sql .= " WHERE ecm.filepath = 'agenda/".((int) $object->id)."'";
13632 //$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
13633 $sql .= ' ORDER BY ecm.position ASC';
13634
13635 $resql = $db->query($sql);
13636 if ($resql) {
13637 if ($db->num_rows($resql)) {
13638 while ($obj = $db->fetch_object($resql)) {
13639 $documents[$obj->id] = $obj;
13640 }
13641 }
13642 }
13643
13644 return $documents;
13645}
13646
13647
13665function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = null, $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
13666{
13667 global $user, $conf;
13668 global $form;
13669
13670 global $param, $massactionbutton;
13671
13672 require_once DOL_DOCUMENT_ROOT . '/comm/action/class/actioncomm.class.php';
13673
13674 // Check parameters
13675 if (!is_object($filterobj) && !is_object($objcon)) {
13676 dol_print_error(null, 'BadParameter');
13677 }
13678
13679 $histo = array();
13680 '@phan-var-force array<int,array{type:string,tododone:string,id:string,datestart:int|string,dateend:int|string,note:string,message:string,percent:string,userid:string,login:string,userfirstname:string,userlastname:string,userphoto:string,msg_from?:string,contact_id?:string,socpeopleassigned?:int[],lastname?:string,firstname?:string,fk_element?:int,elementtype?:string,acode:string,alabel?:string,libelle?:string,apicto?:string}> $histo';
13681
13682 $numaction = 0;
13683 $now = dol_now();
13684
13685 $sortfield_list = explode(',', $sortfield);
13686 $sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent');
13687 $sortfield_new_list = array();
13688 foreach ($sortfield_list as $sortfield_value) {
13689 $sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)];
13690 }
13691 $sortfield_new = implode(',', $sortfield_new_list);
13692
13693 $sql = null;
13694 $sql2 = null;
13695
13696 if (isModEnabled('agenda')) {
13697 // Search histo on actioncomm
13698 if (is_object($objcon) && $objcon->id > 0) {
13699 $sql = "SELECT DISTINCT a.id, a.label as label,";
13700 } else {
13701 $sql = "SELECT a.id, a.label as label,";
13702 }
13703 $sql .= " a.datep as dp,";
13704 $sql .= " a.note as message,";
13705 $sql .= " a.datep2 as dp2,";
13706 $sql .= " a.percent as percent, 'action' as type,";
13707 $sql .= " a.fk_element, a.elementtype,";
13708 $sql .= " a.fk_contact,";
13709 $sql .= " a.email_from as msg_from,";
13710 $sql .= " c.code as acode, c.libelle as alabel, c.picto as apicto,";
13711 $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";
13712 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
13713 $sql .= ", sp.lastname, sp.firstname";
13714 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
13715 $sql .= ", m.lastname, m.firstname";
13716 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
13717 $sql .= ", o.ref";
13718 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
13719 $sql .= ", o.ref";
13720 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
13721 $sql .= ", o.ref";
13722 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
13723 $sql .= ", o.ref";
13724 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
13725 $sql .= ", o.ref";
13726 }
13727 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
13728 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
13729 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
13730
13731 $force_filter_contact = $filterobj instanceof User;
13732
13733 if (is_object($objcon) && $objcon->id > 0) {
13734 $force_filter_contact = true;
13735 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
13736 $sql .= " AND r.element_type = '".$db->escape($objcon->table_element)."' AND r.fk_element = ".((int) $objcon->id);
13737 }
13738
13739 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
13740 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
13741 } elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
13742 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er";
13743 $sql .= " ON er.resource_type = 'dolresource'";
13744 $sql .= " AND er.element_id = a.id";
13745 $sql .= " AND er.resource_id = ".((int) $filterobj->id);
13746 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
13747 $sql .= ", ".MAIN_DB_PREFIX."adherent as m";
13748 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
13749 $sql .= ", ".MAIN_DB_PREFIX."commande_fournisseur as o";
13750 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
13751 $sql .= ", ".MAIN_DB_PREFIX."product as o";
13752 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
13753 $sql .= ", ".MAIN_DB_PREFIX."ticket as o";
13754 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
13755 $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o";
13756 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
13757 $sql .= ", ".MAIN_DB_PREFIX."contrat as o";
13758 }
13759
13760 $sql .= " WHERE a.entity IN (".getEntity('agenda').")";
13761 if (!$force_filter_contact) {
13762 if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) {
13763 $sql .= " AND a.fk_soc = ".((int) $filterobj->id);
13764 } elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) {
13765 $sql .= " AND a.fk_project = ".((int) $filterobj->id);
13766 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
13767 $sql .= " AND a.fk_element = m.rowid AND a.elementtype = 'member'";
13768 if ($filterobj->id) {
13769 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13770 }
13771 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
13772 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'order_supplier'";
13773 if ($filterobj->id) {
13774 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13775 }
13776 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
13777 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
13778 if ($filterobj->id) {
13779 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13780 }
13781 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
13782 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'ticket'";
13783 if ($filterobj->id) {
13784 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13785 }
13786 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
13787 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'bom'";
13788 if ($filterobj->id) {
13789 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13790 }
13791 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
13792 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'contract'";
13793 if ($filterobj->id) {
13794 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
13795 }
13796 }
13797 } else {
13798 $sql .= " AND u.rowid = ". ((int) $filterobj->id);
13799 }
13800
13801 // Condition on actioncode
13802 if (!empty($actioncode)) {
13803 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE')) {
13804 if ($actioncode == 'AC_NON_AUTO') {
13805 $sql .= " AND c.type != 'systemauto'";
13806 } elseif ($actioncode == 'AC_ALL_AUTO') {
13807 $sql .= " AND c.type = 'systemauto'";
13808 } else {
13809 if ($actioncode == 'AC_OTH') {
13810 $sql .= " AND c.type != 'systemauto'";
13811 } elseif ($actioncode == 'AC_OTH_AUTO') {
13812 $sql .= " AND c.type = 'systemauto'";
13813 }
13814 }
13815 } else {
13816 if ($actioncode == 'AC_NON_AUTO') {
13817 $sql .= " AND c.type != 'systemauto'";
13818 } elseif ($actioncode == 'AC_ALL_AUTO') {
13819 $sql .= " AND c.type = 'systemauto'";
13820 } else {
13821 $sql .= " AND c.code = '".$db->escape($actioncode)."'";
13822 }
13823 }
13824 }
13825 if ($donetodo == 'todo') {
13826 $sql .= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
13827 } elseif ($donetodo == 'done') {
13828 $sql .= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
13829 }
13830 if (is_array($filters) && $filters['search_agenda_label']) {
13831 $sql .= natural_search('a.label', $filters['search_agenda_label']);
13832 }
13833 }
13834
13835 // Add also event from emailings. TODO This should be replaced by an automatic event ? May be it's too much for very large emailing.
13836 if (isModEnabled('mailing') && !empty($objcon->email)
13837 && (empty($actioncode) || $actioncode == 'AC_OTH_AUTO' || $actioncode == 'AC_EMAILING')) {
13838 $langs->load("mails");
13839
13840 $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";
13841 $sql2 .= ", null as fk_element, '' as elementtype, null as contact_id";
13842 $sql2 .= ", 'AC_EMAILING' as acode, '' as alabel, '' as apicto";
13843 $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
13844 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
13845 $sql2 .= ", '' as lastname, '' as firstname";
13846 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
13847 $sql2 .= ", '' as lastname, '' as firstname";
13848 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
13849 $sql2 .= ", '' as ref";
13850 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
13851 $sql2 .= ", '' as ref";
13852 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
13853 $sql2 .= ", '' as ref";
13854 }
13855 $sql2 .= " FROM ".MAIN_DB_PREFIX."mailing as m, ".MAIN_DB_PREFIX."mailing_cibles as mc, ".MAIN_DB_PREFIX."user as u";
13856 $sql2 .= " WHERE mc.email = '".$db->escape($objcon->email)."'"; // Search is done on email.
13857 $sql2 .= " AND mc.statut = 1";
13858 $sql2 .= " AND u.rowid = m.fk_user_valid";
13859 $sql2 .= " AND mc.fk_mailing=m.rowid";
13860 }
13861
13862 if ($sql || $sql2) { // May not be defined if module Agenda is not enabled and mailing module disabled too
13863 if (!empty($sql) && !empty($sql2)) {
13864 $sql = $sql." UNION ".$sql2;
13865 } elseif (empty($sql) && !empty($sql2)) {
13866 $sql = $sql2;
13867 }
13868
13869 //TODO Add navigation with this limits...
13870 $offset = 0;
13871 $limit = 1000;
13872
13873 // Complete request and execute it with limit
13874 $sql .= $db->order($sortfield_new, $sortorder);
13875 if ($limit) {
13876 $sql .= $db->plimit($limit + 1, $offset);
13877 }
13878
13879 dol_syslog("function.lib::show_actions_messaging", LOG_DEBUG);
13880 $resql = $db->query($sql);
13881 if ($resql) {
13882 $i = 0;
13883 $num = $db->num_rows($resql);
13884
13885 $imaxinloop = ($limit ? min($num, $limit) : $num);
13886 while ($i < $imaxinloop) {
13887 $obj = $db->fetch_object($resql);
13888
13889 if ($obj->type == 'action') {
13890 $contactaction = new ActionComm($db);
13891 $contactaction->id = $obj->id;
13892 $result = $contactaction->fetchResources();
13893 if ($result < 0) {
13894 dol_print_error($db);
13895 setEventMessage("actions.lib::show_actions_messaging Error fetch resource", 'errors');
13896 }
13897
13898 //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
13899 //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
13900 $tododone = '';
13901 if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && $obj->dp > $now)) {
13902 $tododone = 'todo';
13903 }
13904
13905 $histo[$numaction] = array(
13906 'type' => $obj->type,
13907 'tododone' => $tododone,
13908 'id' => $obj->id,
13909 'datestart' => $db->jdate($obj->dp),
13910 'dateend' => $db->jdate($obj->dp2),
13911 'note' => $obj->label,
13912 'message' => dol_htmlentitiesbr($obj->message),
13913 'percent' => $obj->percent,
13914
13915 'userid' => $obj->user_id,
13916 'login' => $obj->user_login,
13917 'userfirstname' => $obj->user_firstname,
13918 'userlastname' => $obj->user_lastname,
13919 'userphoto' => $obj->user_photo,
13920 'msg_from' => $obj->msg_from,
13921
13922 'contact_id' => $obj->fk_contact,
13923 'socpeopleassigned' => $contactaction->socpeopleassigned,
13924 'lastname' => (empty($obj->lastname) ? '' : $obj->lastname),
13925 'firstname' => (empty($obj->firstname) ? '' : $obj->firstname),
13926 'fk_element' => $obj->fk_element,
13927 'elementtype' => $obj->elementtype,
13928 // Type of event
13929 'acode' => $obj->acode,
13930 'alabel' => $obj->alabel,
13931 'libelle' => $obj->alabel, // deprecated
13932 'apicto' => $obj->apicto
13933 );
13934 } else {
13935 $histo[$numaction] = array(
13936 'type' => $obj->type,
13937 'tododone' => 'done',
13938 'id' => $obj->id,
13939 'datestart' => $db->jdate($obj->dp),
13940 'dateend' => $db->jdate($obj->dp2),
13941 'note' => $obj->label,
13942 'message' => dol_htmlentitiesbr($obj->message),
13943 'percent' => $obj->percent,
13944 'acode' => $obj->acode,
13945
13946 'userid' => $obj->user_id,
13947 'login' => $obj->user_login,
13948 'userfirstname' => $obj->user_firstname,
13949 'userlastname' => $obj->user_lastname,
13950 'userphoto' => $obj->user_photo
13951 );
13952 }
13953
13954 $numaction++;
13955 $i++;
13956 }
13957 } else {
13958 dol_print_error($db);
13959 }
13960 }
13961
13962 // Set $out to show events
13963 $out = '';
13964
13965 if (!isModEnabled('agenda')) {
13966 $langs->loadLangs(array("admin", "errors"));
13967 $out = info_admin($langs->trans("WarningModuleXDisabledSoYouMayMissEventHere", $langs->transnoentitiesnoconv("Module2400Name")), 0, 0, 'warning');
13968 }
13969
13970 if (isModEnabled('agenda') || (isModEnabled('mailing') && !empty($objcon->email))) {
13971 $delay_warning = $conf->global->MAIN_DELAY_ACTIONS_TODO * 24 * 60 * 60;
13972
13973 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
13974 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
13975 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
13976 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
13977
13978 $formactions = new FormActions($db);
13979
13980 $actionstatic = new ActionComm($db);
13981 $userstatic = new User($db);
13982 $contactstatic = new Contact($db);
13983 $userGetNomUrlCache = array();
13984 $contactGetNomUrlCache = array();
13985
13986 $out .= '<div class="filters-container" >';
13987 $out .= '<form name="listactionsfilter" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
13988 $out .= '<input type="hidden" name="token" value="'.newToken().'">';
13989
13990 if ($objcon && get_class($objcon) == 'Contact' &&
13991 (is_null($filterobj) || get_class($filterobj) == 'Societe')) {
13992 $out .= '<input type="hidden" name="id" value="'.$objcon->id.'" />';
13993 } else {
13994 $out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
13995 }
13996 if (($filterobj && get_class($filterobj) == 'Societe')) {
13997 $out .= '<input type="hidden" name="socid" value="'.$filterobj->id.'" />';
13998 } else {
13999 $out .= '<input type="hidden" name="userid" value="'.$filterobj->id.'" />';
14000 }
14001
14002 $out .= "\n";
14003
14004 $out .= '<div class="div-table-responsive-no-min">';
14005 $out .= '<table class="noborder borderbottom centpercent">';
14006
14007 $out .= '<tr class="liste_titre">';
14008
14009 // Action column
14010 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
14011 $out .= '<th class="liste_titre width50 middle">';
14012 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
14013 $out .= $searchpicto;
14014 $out .= '</th>';
14015 }
14016
14017 $out .= getTitleFieldOfList('Date', 0, $_SERVER["PHP_SELF"], 'a.datep', '', $param, '', $sortfield, $sortorder, '')."\n";
14018
14019 $out .= '<th class="liste_titre"><strong class="hideonsmartphone">'.$langs->trans("Search").' : </strong></th>';
14020 if ($donetodo) {
14021 $out .= '<th class="liste_titre"></th>';
14022 }
14023 $out .= '<th class="liste_titre">';
14024 $out .= '<span class="fas fa-square inline-block fawidth30" style=" color: #ddd;" title="'.$langs->trans("ActionType").'"></span>';
14025 //$out .= img_picto($langs->trans("Type"), 'type');
14026 $out .= $formactions->select_type_actions($actioncode, "actioncode", '', !getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : -1, 0, 0, 1, 'minwidth200imp');
14027 $out .= '</th>';
14028 $out .= '<th class="liste_titre maxwidth100onsmartphone">';
14029 $out .= '<input type="text" class="maxwidth100onsmartphone" name="search_agenda_label" value="'.$filters['search_agenda_label'].'" placeholder="'.$langs->trans("Label").'">';
14030 $out .= '</th>';
14031
14032 // Action column
14033 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
14034 $out .= '<th class="liste_titre width50 middle">';
14035 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
14036 $out .= $searchpicto;
14037 $out .= '</th>';
14038 }
14039
14040 $out .= '</tr>';
14041
14042
14043 $out .= '</table>';
14044
14045 $out .= '</form>';
14046 $out .= '</div>';
14047
14048 $out .= "\n";
14049
14050 $out .= '<ul class="timeline">';
14051
14052 if ($donetodo) {
14053 $tmp = '';
14054 if ($filterobj instanceof Societe) {
14055 $tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&socid='.$filterobj->id.'&status=done">';
14056 }
14057 if ($filterobj instanceof User) {
14058 $tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&socid='.$filterobj->id.'&status=done">';
14059 }
14060 $tmp .= ($donetodo != 'done' ? $langs->trans("ActionsToDoShort") : '');
14061 $tmp .= ($donetodo != 'done' && $donetodo != 'todo' ? ' / ' : '');
14062 $tmp .= ($donetodo != 'todo' ? $langs->trans("ActionsDoneShort") : '');
14063 //$out.=$langs->trans("ActionsToDoShort").' / '.$langs->trans("ActionsDoneShort");
14064 if ($filterobj instanceof Societe) {
14065 $tmp .= '</a>';
14066 }
14067 if ($filterobj instanceof User) {
14068 $tmp .= '</a>';
14069 }
14070 $out .= getTitleFieldOfList($tmp);
14071 }
14072
14073 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
14074 $caction = new CActionComm($db);
14075 $arraylist = $caction->liste_array(1, 'code', '', (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') ? 1 : 0), '', 1);
14076
14077 $actualCycleDate = false;
14078
14079 // Loop on each event to show it
14080 foreach ($histo as $key => $value) {
14081 $actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo
14082
14083 $actionstatic->type_picto = $histo[$key]['apicto'];
14084 $actionstatic->type_code = $histo[$key]['acode'];
14085
14086 $labeltype = $actionstatic->type_code;
14087 if (!getDolGlobalString('AGENDA_USE_EVENT_TYPE') && empty($arraylist[$labeltype])) {
14088 $labeltype = 'AC_OTH';
14089 }
14090 if (!empty($actionstatic->code) && preg_match('/^TICKET_MSG/', $actionstatic->code)) {
14091 $labeltype = $langs->trans("Message");
14092 } else {
14093 if (!empty($arraylist[$labeltype])) {
14094 $labeltype = $arraylist[$labeltype];
14095 }
14096 if ($actionstatic->type_code == 'AC_OTH_AUTO' && ($actionstatic->type_code != $actionstatic->code) && $labeltype && !empty($arraylist[$actionstatic->code])) {
14097 $labeltype .= ' - '.$arraylist[$actionstatic->code]; // Use code in priority on type_code
14098 }
14099 }
14100
14101 $url = DOL_URL_ROOT.'/comm/action/card.php?id='.$histo[$key]['id'];
14102
14103 $tmpa = dol_getdate($histo[$key]['datestart'], false);
14104
14105 if (isset($tmpa['year']) && isset($tmpa['yday']) && $actualCycleDate !== $tmpa['year'].'-'.$tmpa['yday']) {
14106 $actualCycleDate = $tmpa['year'].'-'.$tmpa['yday'];
14107 $out .= '<!-- timeline time label -->';
14108 $out .= '<li class="time-label">';
14109 $out .= '<span class="timeline-badge-date">';
14110 $out .= dol_print_date($histo[$key]['datestart'], 'daytext', 'tzuserrel', $langs);
14111 $out .= '</span>';
14112 $out .= '</li>';
14113 $out .= '<!-- /.timeline-label -->';
14114 }
14115
14116
14117 $out .= '<!-- timeline item -->'."\n";
14118 $out .= '<li class="timeline-code-'.strtolower($actionstatic->code).'">';
14119
14120 //$timelineicon = getTimelineIcon($actionstatic, $histo, $key);
14121 $typeicon = $actionstatic->getTypePicto('pictofixedwidth timeline-icon-not-applicble', $labeltype);
14122 //$out .= $timelineicon;
14123 //var_dump($timelineicon);
14124 $out .= $typeicon;
14125
14126 $out .= '<div class="timeline-item">'."\n";
14127
14128 $out .= '<span class="time timeline-header-action2">';
14129
14130 if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
14131 $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").' ';
14132 $out .= $histo[$key]['id'];
14133 $out .= '</a> ';
14134 } else {
14135 $out .= $actionstatic->getNomUrl(1, -1, 'valignmiddle').' ';
14136 }
14137
14138 if ($user->hasRight('agenda', 'allactions', 'create') ||
14139 (($actionstatic->authorid == $user->id || $actionstatic->userownerid == $user->id) && $user->hasRight('agenda', 'myactions', 'create'))) {
14140 $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).'">';
14141 //$out .= '<i class="fa fa-pencil" title="'.$langs->trans("Modify").'" ></i>';
14142 $out .= img_picto($langs->trans("Modify"), 'edit', 'class="edita"');
14143 $out .= '</a>';
14144 }
14145
14146 $out .= '</span>';
14147
14148 // Date
14149 $out .= '<span class="time"><i class="fa fa-clock-o valignmiddle"></i> <span class="valignmiddle">';
14150 $out .= dol_print_date($histo[$key]['datestart'], 'dayhour', 'tzuserrel');
14151 if ($histo[$key]['dateend'] && $histo[$key]['dateend'] != $histo[$key]['datestart']) {
14152 $tmpa = dol_getdate($histo[$key]['datestart'], true);
14153 $tmpb = dol_getdate($histo[$key]['dateend'], true);
14154 if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
14155 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'hour', 'tzuserrel');
14156 } else {
14157 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'dayhour', 'tzuserrel');
14158 }
14159 }
14160 $late = 0;
14161 if ($histo[$key]['percent'] == 0 && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
14162 $late = 1;
14163 }
14164 if ($histo[$key]['percent'] == 0 && !$histo[$key]['datestart'] && $histo[$key]['dateend'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
14165 $late = 1;
14166 }
14167 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && $histo[$key]['dateend'] && $histo[$key]['dateend'] < ($now - $delay_warning)) {
14168 $late = 1;
14169 }
14170 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && !$histo[$key]['dateend'] && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
14171 $late = 1;
14172 }
14173 if ($late) {
14174 $out .= img_warning($langs->trans("Late")).' ';
14175 }
14176 $out .= "</span></span>\n";
14177
14178 // Ref
14179 $out .= '<h3 class="timeline-header">';
14180
14181 // Author of event
14182 $out .= '<div class="messaging-author inline-block tdoverflowmax150 valignmiddle marginrightonly">';
14183 if ($histo[$key]['userid'] > 0) {
14184 if (!isset($userGetNomUrlCache[$histo[$key]['userid']])) { // is in cache ?
14185 $userstatic->fetch($histo[$key]['userid']);
14186 $userGetNomUrlCache[$histo[$key]['userid']] = $userstatic->getNomUrl(-1, '', 0, 0, 16, 0, 'firstelselast', '');
14187 }
14188 $out .= $userGetNomUrlCache[$histo[$key]['userid']];
14189 } elseif (!empty($histo[$key]['msg_from']) && $actionstatic->code == 'TICKET_MSG') {
14190 if (!isset($contactGetNomUrlCache[$histo[$key]['msg_from']])) {
14191 if ($contactstatic->fetch(0, null, '', $histo[$key]['msg_from']) > 0) {
14192 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $contactstatic->getNomUrl(-1, '', 16);
14193 } else {
14194 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $histo[$key]['msg_from'];
14195 }
14196 }
14197 $out .= $contactGetNomUrlCache[$histo[$key]['msg_from']];
14198 }
14199 $out .= '</div>';
14200
14201 // Title
14202 $out .= ' <div class="messaging-title inline-block">';
14203 //$out .= $actionstatic->getTypePicto();
14204 if (empty($conf->dol_optimize_smallscreen) && $actionstatic->type_code != 'AC_OTH_AUTO') {
14205 $out .= $labeltype.' - ';
14206 }
14207
14208 $libelle = '';
14209 if (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
14210 $out .= $langs->trans('TicketNewMessage');
14211 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
14212 $out .= $langs->trans('TicketNewMessage').' <em>('.$langs->trans('Private').')</em>';
14213 } elseif (isset($histo[$key]['type'])) {
14214 if ($histo[$key]['type'] == 'action') {
14215 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
14216 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : $histo[$key]['alabel']);
14217 $libelle = $histo[$key]['note'];
14218 $actionstatic->id = $histo[$key]['id'];
14219 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
14220 } elseif ($histo[$key]['type'] == 'mailing') {
14221 $out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
14222 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
14223 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : 'Send mass mailing');
14224 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
14225 } else {
14226 $libelle .= $histo[$key]['note'];
14227 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
14228 }
14229 }
14230
14231 if (isset($histo[$key]['elementtype']) && !empty($histo[$key]['fk_element'])) {
14232 if (isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']]) && isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']])) {
14233 $link = $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']];
14234 } else {
14235 if (!isset($conf->cache['elementlinkcache'][$histo[$key]['elementtype']])) {
14236 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']] = array();
14237 }
14238 $link = dolGetElementUrl($histo[$key]['fk_element'], $histo[$key]['elementtype'], 1);
14239 $conf->cache['elementlinkcache'][$histo[$key]['elementtype']][$histo[$key]['fk_element']] = $link;
14240 }
14241 if ($link) {
14242 $out .= ' - '.$link;
14243 }
14244 }
14245
14246 $out .= '</div>';
14247
14248 $out .= '</h3>';
14249
14250 // Message
14251 if (!empty($histo[$key]['message'] && $histo[$key]['message'] != $libelle)
14252 && $actionstatic->code != 'AC_TICKET_CREATE'
14253 && $actionstatic->code != 'AC_TICKET_MODIFY'
14254 ) {
14255 $out .= '<div class="timeline-body wordbreak small">';
14256 $truncateLines = getDolGlobalInt('MAIN_TRUNCATE_TIMELINE_MESSAGE', 3);
14257 $truncatedText = dolGetFirstLineOfText($histo[$key]['message'], $truncateLines);
14258 if ($truncateLines > 0 && strlen($histo[$key]['message']) > strlen($truncatedText)) {
14259 $out .= '<div class="readmore-block --closed" >';
14260 $out .= ' <div class="readmore-block__excerpt">';
14261 $out .= dolPrintHTML($truncatedText);
14262 $out .= ' <br><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>';
14263 $out .= ' </div>';
14264 $out .= ' <div class="readmore-block__full-text" >';
14265 $out .= dolPrintHTML($histo[$key]['message']);
14266 $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>';
14267 $out .= ' </div>';
14268 $out .= '</div>';
14269 } else {
14270 $out .= dolPrintHTML($histo[$key]['message']);
14271 }
14272
14273 $out .= '</div>';
14274 }
14275
14276 // Timeline footer
14277 $footer = '';
14278
14279 // Contact for this action
14280 if (isset($histo[$key]['socpeopleassigned']) && is_array($histo[$key]['socpeopleassigned']) && count($histo[$key]['socpeopleassigned']) > 0) {
14281 $contactList = '';
14282 foreach ($histo[$key]['socpeopleassigned'] as $cid => $Tab) {
14283 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
14284 $contact = new Contact($db);
14285 $contact->fetch($cid);
14286 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
14287 } else {
14288 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
14289 }
14290
14291 if ($contact) {
14292 $contactList .= !empty($contactList) ? ', ' : '';
14293 $contactList .= $contact->getNomUrl(1);
14294 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
14295 if (!empty($contact->phone_pro)) {
14296 $contactList .= '('.dol_print_phone($contact->phone_pro).')';
14297 }
14298 }
14299 }
14300 }
14301
14302 $footer .= $langs->trans('ActionOnContact').' : '.$contactList;
14303 } elseif (empty($objcon->id) && isset($histo[$key]['contact_id']) && $histo[$key]['contact_id'] > 0) {
14304 if (empty($conf->cache['contact'][$histo[$key]['contact_id']])) {
14305 $contact = new Contact($db);
14306 $result = $contact->fetch($histo[$key]['contact_id']);
14307 $conf->cache['contact'][$histo[$key]['contact_id']] = $contact;
14308 } else {
14309 $contact = $conf->cache['contact'][$histo[$key]['contact_id']];
14310 $result = ($contact instanceof Contact) ? $contact->id : 0;
14311 }
14312
14313 if ($result > 0) {
14314 $footer .= $contact->getNomUrl(1);
14315 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
14316 if (!empty($contact->phone_pro)) {
14317 $footer .= '('.dol_print_phone($contact->phone_pro).')';
14318 }
14319 }
14320 }
14321 }
14322
14323 $documents = getActionCommEcmList($actionstatic);
14324 if (!empty($documents)) {
14325 $footer .= '<div class="timeline-documents-container">';
14326 foreach ($documents as $doc) {
14327 $footer .= '<span id="document_'.$doc->id.'" class="timeline-documents" ';
14328 $footer .= ' data-id="'.$doc->id.'" ';
14329 $footer .= ' data-path="'.$doc->filepath.'"';
14330 $footer .= ' data-filename="'.dol_escape_htmltag($doc->filename).'" ';
14331 $footer .= '>';
14332
14333 $filePath = DOL_DATA_ROOT.'/'.$doc->filepath.'/'.$doc->filename;
14334 $mime = dol_mimetype($filePath);
14335 $file = $actionstatic->id.'/'.$doc->filename;
14336 $thumb = $actionstatic->id.'/thumbs/'.substr($doc->filename, 0, strrpos($doc->filename, '.')).'_mini'.substr($doc->filename, strrpos($doc->filename, '.'));
14337 $doclink = dol_buildpath('document.php', 1).'?modulepart=actions&attachment=0&file='.urlencode($file).'&entity='.$conf->entity;
14338 $viewlink = dol_buildpath('viewimage.php', 1).'?modulepart=actions&file='.urlencode($thumb).'&entity='.$conf->entity;
14339
14340 $mimeAttr = ' mime="'.$mime.'" ';
14341 $class = '';
14342 if (in_array($mime, array('image/png', 'image/jpeg', 'application/pdf'))) {
14343 $class .= ' documentpreview';
14344 }
14345
14346 $footer .= '<a href="'.$doclink.'" class="btn-link '.$class.'" target="_blank" rel="noopener noreferrer" '.$mimeAttr.' >';
14347 $footer .= img_mime($filePath).' '.$doc->filename;
14348 $footer .= '</a>';
14349
14350 $footer .= '</span>';
14351 }
14352 $footer .= '</div>';
14353 }
14354
14355 if (!empty($footer)) {
14356 $out .= '<div class="timeline-footer">'.$footer.'</div>';
14357 }
14358
14359 $out .= '</div>'."\n"; // end timeline-item
14360
14361 $out .= '</li>';
14362 $out .= '<!-- END timeline item -->';
14363 }
14364
14365 $out .= "</ul>\n";
14366
14367 $out .= '<script>
14368 jQuery(document).ready(function () {
14369 $(document).on("click", "[data-read-more-action]", function(e){
14370 let readMoreBloc = $(this).closest(".readmore-block");
14371 if(readMoreBloc.length > 0){
14372 e.preventDefault();
14373 if($(this).attr("data-read-more-action") == "close"){
14374 readMoreBloc.addClass("--closed").removeClass("--open");
14375 $("html, body").animate({
14376 scrollTop: readMoreBloc.offset().top - 200
14377 }, 100);
14378 }else{
14379 readMoreBloc.addClass("--open").removeClass("--closed");
14380 }
14381 }
14382 });
14383 });
14384 </script>';
14385
14386
14387 if (empty($histo)) {
14388 $out .= '<span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span>';
14389 }
14390 }
14391
14392 if ($noprint) {
14393 return $out;
14394 } else {
14395 print $out;
14396 }
14397}
14398
14409function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto')
14410{
14411 $m = array();
14412 if ($hourTime === 'getpost') {
14413 $hour = GETPOSTINT($prefix . 'hour');
14414 $minute = GETPOSTINT($prefix . 'minute');
14415 $second = GETPOSTINT($prefix . 'second');
14416 } elseif (preg_match('/^(\d\d):(\d\d):(\d\d)$/', $hourTime, $m)) {
14417 $hour = intval($m[1]);
14418 $minute = intval($m[2]);
14419 $second = intval($m[3]);
14420 } else {
14421 $hour = $minute = $second = 0;
14422 }
14423 // normalize out of range values
14424 $hour = min($hour, 23);
14425 $minute = min($minute, 59);
14426 $second = min($second, 59);
14427 return dol_mktime($hour, $minute, $second, GETPOSTINT($prefix . 'month'), GETPOSTINT($prefix . 'day'), GETPOSTINT($prefix . 'year'), $gm);
14428}
14429
14441function buildParamDate($prefix, $timestamp = null, $hourTime = '', $gm = 'auto')
14442{
14443 if ($timestamp === null) {
14444 $timestamp = GETPOSTDATE($prefix, $hourTime, $gm);
14445 }
14446 $TParam = array(
14447 $prefix . 'day' => intval(dol_print_date($timestamp, '%d')),
14448 $prefix . 'month' => intval(dol_print_date($timestamp, '%m')),
14449 $prefix . 'year' => intval(dol_print_date($timestamp, '%Y')),
14450 );
14451 if ($hourTime === 'getpost' || ($timestamp !== null && dol_print_date($timestamp, '%H:%M:%S') !== '00:00:00')) {
14452 $TParam = array_merge($TParam, array(
14453 $prefix . 'hour' => intval(dol_print_date($timestamp, '%H')),
14454 $prefix . 'minute' => intval(dol_print_date($timestamp, '%M')),
14455 $prefix . 'second' => intval(dol_print_date($timestamp, '%S'))
14456 ));
14457 }
14458
14459 return '&' . http_build_query($TParam);
14460}
14461
14481function recordNotFound($message = '', $printheader = 1, $printfooter = 1, $showonlymessage = 0, $params = null)
14482{
14483 global $conf, $db, $langs, $hookmanager;
14484 global $action, $object;
14485
14486 if (!is_object($langs)) {
14487 include_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
14488 $langs = new Translate('', $conf);
14489 $langs->setDefaultLang();
14490 }
14491
14492 $langs->load("errors");
14493
14494 if ($printheader) {
14495 if (function_exists("llxHeader")) {
14496 llxHeader('');
14497 } elseif (function_exists("llxHeaderVierge")) {
14498 llxHeaderVierge('');
14499 }
14500 }
14501
14502 print '<div class="error">';
14503 if (empty($message)) {
14504 print $langs->trans("ErrorRecordNotFound");
14505 } else {
14506 print $langs->trans($message);
14507 }
14508 print '</div>';
14509 print '<br>';
14510
14511 if (empty($showonlymessage)) {
14512 if (empty($hookmanager)) {
14513 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
14514 $hookmanager = new HookManager($db);
14515 // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
14516 $hookmanager->initHooks(array('main'));
14517 }
14518
14519 $parameters = array('message' => $message, 'params' => $params);
14520 $reshook = $hookmanager->executeHooks('getErrorRecordNotFound', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
14521 print $hookmanager->resPrint;
14522 }
14523
14524 if ($printfooter && function_exists("llxFooter")) {
14525 llxFooter();
14526 }
14527 exit(0);
14528}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
if(!defined( 'NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined( 'NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) if(!defined( 'NOLOGIN')) if(!defined('NOCSRFCHECK')) if(!defined( 'NOIPCHECK')) llxHeaderVierge()
Header function.
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:456
ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input=array(), $morecss='', $htmlname='', $forcenojs=0, $moreparam='')
On/off button to change a property status of an object This uses the ajax service objectonoff....
Definition ajax.lib.php:725
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader()
Empty header.
Definition wrapper.php:55
llxFooter()
Empty footer.
Definition wrapper.php:69
$object ref
Definition info.php:79
Class to manage agenda events (actions)
Class to manage different types of events.
Class to manage contact/addresses.
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 generation of HTML components Only common components must be here.
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...)
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:85
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($utf8_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:63
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.
verifCond($strToEvaluate, $onlysimplestring='1')
Verify if condition in string is ok or not.
recordNotFound($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Displays an error page when a record is not found.
dol_print_size($size, $shortvalue=0, $shortunit=0)
Return string with formatted size.
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 information (by default a local PHP server timestamp) Rep...
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) If ...
img_weather($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $morecss='')
Show weather picto.
dolCheckFilters($sqlfilters, &$error='', &$parenthesislevel=0)
Return if a $sqlfilters parameter has a valid balance of parenthesis.
finishSimpleTable($addLineBreak=false)
Add the correct HTML close tags for "startSimpleTable(...)" (use after the last table line)
show_actions_messaging($conf, $langs, $db, $filterobj, $objcon=null, $noprint=0, $actioncode='', $donetodo='done', $filters=array(), $sortfield='a.datep, a.id', $sortorder='DESC')
Show html area with actions in messaging format.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
getLanguageCodeFromCountryCode($countrycode)
Return default language from country code.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
setEntity($currentobject)
Set entity id to use when to create an object.
dolForgeExplodeAnd($sqlfilters)
Explode an universal search string with AND parts.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='')
Format phone numbers according to country.
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.
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 formatted 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.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
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.
dol_format_address($object, $withcountry=0, $sep="\n", $outputlangs=null, $mode=0, $extralangcode='')
Return a formatted address (part address/zip/town/state) according to country rules.
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 (that can be on several lines) ready to be output on a HTML page.
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.
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_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Get formatted error messages to output (Used to show messages on html output).
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.
dol_user_country()
Return country code for current user.
dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes=null)
Clean a string from some undesirable HTML tags.
getMultidirTemp($object, $module='', $forobject=0)
Return the full path of the directory where a module (or an object of a module) stores its temporary ...
isHTTPS()
Return if we are using a HTTPS connection 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.
isDolTms($timestamp)
isDolTms check if a timestamp is valid.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
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.
getPictoForType($key, $morecss='')
Return the picto for a data type.
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.
dolButtonToOpenExportDialog($name, $label, $buttonstring, $exportSiteName, $overwriteGitUrl, $website)
Create a dialog with two buttons for export and overwrite of a website.
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
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.
getElementProperties($elementType)
Get an array with properties of an element.
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_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_get_object_properties($obj, $properties=[])
Get properties for an object - including magic properties when requested.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
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_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.
getMultidirVersion($object, $module='', $forobject=0)
Return the full path of the directory where a module (or an object of a module) stores its versioned ...
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 formatted 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.
get_date_range($date_start, $date_end, $format='', $outputlangs=null, $withparenthesis=1)
Format output for start and end date.
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
print_date_range($date_start, $date_end, $format='', $outputlangs=null)
Format output for start and end date.
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.
print_barre_liste($title, $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.
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.
GETPOSTFLOAT($paramname, $rounding='')
Return the value of a $_GET or $_POST supervariable, converted into float.
readfileLowMemory($fullpath_original_file_osencoded, $method=-1)
Return a file on output using a low memory.
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='', $forobject=0, $mode='output')
Return the full path of the directory where a module (or an object of a module) stores its files,...
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.
dol_bc($var, $moreclass='')
Return string to add class property on html element with pair/impair.
fetchObjectByElement($element_id, $element_type, $element_ref='', $useCache=0, $maxCacheByType=10)
Fetch an object from its id and element_type Inclusion of classes is automatic.
print_titre($title)
Show a title.
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).
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 formatted 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,...
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
img_next($titlealt='default', $moreatt='')
Show next logo.
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 startx 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).
get_htmloutput_mesg($mesgstring='', $mesgarray=[], $style='ok', $keepembedded=0)
Get formatted messages to output (Used to show messages on html output).
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 +.
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.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
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...
utf8_check($str)
Check if a string is in UTF8.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
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 formatted error messages to output (Used to show messages on html output).
startSimpleTable($header, $link="", $arguments="", $emptyColumns=0, $number=-1, $pictofulllist='')
Start a table with headers and a optional clickable number (don't forget to use "finishSimpleTable()"...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
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 formatted text with and (WARNING: string must not have mixed and br sep...
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...
const MODULE_MAPPING
This mapping defines the conversion to the current internal names from the alternative allowed names ...
dol_convertToWord($num, $langs, $currency='', $centimes=false)
Function to return a number into a text.
ui state ui widget content ui state ui widget header ui state a ui button
0 = Do not include form tag and submit button -1 = Do not include form tag but include submit button
table table fiche title col title div col center btnTitle icon
Automatically calls the icon named with the corresponding "object_" prefix.
conf($dolibarr_main_document_root)
Load conf file (file must exists)
Definition inc.php:420
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.
realCharForNumericEntities($matches)
Return the real char for a numeric entities.
Definition main.inc.php:86
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:139
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:142
dolGetRandomBytes($length)
Return a string of random bytes (hexa string) with length = $length for cryptographic purposes.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall TAKEPOS_SHOW_SUBPRICE right right right takeposterminal SELECT e rowid
Definition invoice.php:1991