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) (isset($tmpuser->conf->$key) ? $tmpuser->conf->$key : $default);
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) (isset($tmpuser->conf->$key) ? $tmpuser->conf->$key: $default);
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', 'c_holiday_types', '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
1347function dol_buildpath($path, $type = 0, $returnemptyifnotfound = 0)
1348{
1349 global $conf;
1350
1351 $path = preg_replace('/^\//', '', $path);
1352
1353 if (empty($type)) { // For a filesystem path
1354 $res = DOL_DOCUMENT_ROOT.'/'.$path; // Standard default path
1355 if (is_array($conf->file->dol_document_root)) {
1356 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array("main"=>"/home/main/htdocs", "alt0"=>"/home/dirmod/htdocs", ...)
1357 if ($key == 'main') {
1358 continue;
1359 }
1360 // if (@file_exists($dirroot.'/'.$path)) {
1361 if (@file_exists($dirroot.'/'.$path)) { // avoid [php:warn]
1362 $res = $dirroot.'/'.$path;
1363 return $res;
1364 }
1365 }
1366 }
1367 if ($returnemptyifnotfound) {
1368 // Not found into alternate dir
1369 if ($returnemptyifnotfound == 1 || !file_exists($res)) {
1370 return '';
1371 }
1372 }
1373 } else {
1374 // For an url path
1375 // We try to get local path of file on filesystem from url
1376 // Note that trying to know if a file on disk exist by forging path on disk from url
1377 // works only for some web server and some setup. This is bugged when
1378 // using proxy, rewriting, virtual path, etc...
1379 $res = '';
1380 if ($type == 1) {
1381 $res = DOL_URL_ROOT.'/'.$path; // Standard value
1382 }
1383 if ($type == 2) {
1384 $res = DOL_MAIN_URL_ROOT.'/'.$path; // Standard value
1385 }
1386 if ($type == 3) {
1387 $res = DOL_URL_ROOT.'/'.$path;
1388 }
1389
1390 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array(["main"]=>"/home/main/htdocs", ["alt0"]=>"/home/dirmod/htdocs", ...)
1391 if ($key == 'main') {
1392 if ($type == 3) {
1393 /*global $dolibarr_main_url_root;*/
1394
1395 // Define $urlwithroot
1396 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1397 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1398 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1399
1400 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).'/'.$path; // Test on start with http is for old conf syntax
1401 }
1402 continue;
1403 }
1404 $regs = array();
1405 preg_match('/^([^\?]+(\.css\.php|\.css|\.js\.php|\.js|\.png|\.jpg|\.php)?)/i', $path, $regs); // Take part before '?'
1406 if (!empty($regs[1])) {
1407 //print $key.'-'.$dirroot.'/'.$path.'-'.$conf->file->dol_url_root[$type].'<br>'."\n";
1408 //if (file_exists($dirroot.'/'.$regs[1])) {
1409 if (@file_exists($dirroot.'/'.$regs[1])) { // avoid [php:warn]
1410 if ($type == 1) {
1411 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1412 } elseif ($type == 2) {
1413 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_MAIN_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1414 } elseif ($type == 3) {
1415 /*global $dolibarr_main_url_root;*/
1416
1417 // Define $urlwithroot
1418 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1419 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1420 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1421
1422 $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
1423 }
1424 break;
1425 }
1426 }
1427 }
1428 }
1429
1430 return $res;
1431}
1432
1443function dol_get_object_properties($obj, $properties = [])
1444{
1445 // Get real properties using get_object_vars() if $properties is empty
1446 if (empty($properties)) {
1447 return get_object_vars($obj);
1448 }
1449
1450 $existingProperties = [];
1451 $realProperties = get_object_vars($obj);
1452
1453 // Get the real or magic property values
1454 foreach ($properties as $property) {
1455 if (array_key_exists($property, $realProperties)) {
1456 // Real property, add the value
1457 $existingProperties[$property] = $obj->{$property};
1458 } elseif (property_exists($obj, $property)) {
1459 // Magic property
1460 $existingProperties[$property] = $obj->{$property};
1461 }
1462 }
1463
1464 return $existingProperties;
1465}
1466
1467
1482function dol_clone($object, $native = 0)
1483{
1484 if ($native == 0) {
1485 // deprecated method, use the method with native = 2 instead
1486 $tmpsavdb = null;
1487 if (isset($object->db) && isset($object->db->db) && is_object($object->db->db) && get_class($object->db->db) == 'PgSql\Connection') {
1488 $tmpsavdb = $object->db;
1489 unset($object->db); // Such property can not be serialized with pgsl (when object->db->db = 'PgSql\Connection')
1490 }
1491
1492 $myclone = unserialize(serialize($object)); // serialize then unserialize is a hack to be sure to have a new object for all fields
1493
1494 if (!empty($tmpsavdb)) {
1495 $object->db = $tmpsavdb;
1496 }
1497 } elseif ($native == 2) {
1498 // recommended method to have a full isolated cloned object
1499 $myclone = new stdClass();
1500 $tmparray = get_object_vars($object); // return only public properties
1501
1502 if (is_array($tmparray)) {
1503 foreach ($tmparray as $propertykey => $propertyval) {
1504 if (is_scalar($propertyval) || is_array($propertyval)) {
1505 $myclone->$propertykey = $propertyval;
1506 }
1507 }
1508 }
1509 } else {
1510 $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)
1511 }
1512
1513 return $myclone;
1514}
1515
1525function dol_size($size, $type = '')
1526{
1527 global $conf;
1528 if (empty($conf->dol_optimize_smallscreen)) {
1529 return $size;
1530 }
1531 if ($type == 'width' && $size > 250) {
1532 return 250;
1533 } else {
1534 return 10;
1535 }
1536}
1537
1538
1550function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1)
1551{
1552 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1553 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1554 // Char '/' and '\' are file delimiters.
1555 // 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
1556 $filesystem_forbidden_chars = array('<', '>', '/', '\\', '?', '*', '|', '"', ':', '°', '$', ';', '`');
1557 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1558 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1559 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1560 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1561 $tmp = str_replace('..', '', $tmp);
1562 return $tmp;
1563}
1564
1565
1577function dol_sanitizePathName($str, $newstr = '_', $unaccent = 1)
1578{
1579 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1580 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1581 // 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
1582 $filesystem_forbidden_chars = array('<', '>', '?', '*', '|', '"', '°', '$', ';', '`');
1583 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1584 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1585 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1586 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1587 $tmp = str_replace('..', '', $tmp);
1588 return $tmp;
1589}
1590
1598function dol_sanitizeUrl($stringtoclean, $type = 1)
1599{
1600 // 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)
1601 // We should use dol_string_nounprintableascii but function may not be yet loaded/available
1602 $stringtoclean = preg_replace('/[\x00-\x1F\x7F]/u', '', $stringtoclean); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1603 // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: on<!-- -->error=alert(1)
1604 $stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
1605
1606 $stringtoclean = str_replace('\\', '/', $stringtoclean);
1607 if ($type == 1) {
1608 // removing : should disable links to external url like http:aaa)
1609 // removing ';' should disable "named" html entities encode into an url (we should not have this into an url)
1610 $stringtoclean = str_replace(array(':', ';', '@'), '', $stringtoclean);
1611 }
1612
1613 do {
1614 $oldstringtoclean = $stringtoclean;
1615 // removing '&colon' should disable links to external url like http:aaa)
1616 // removing '&#' should disable "numeric" html entities encode into an url (we should not have this into an url)
1617 $stringtoclean = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $stringtoclean);
1618 } while ($oldstringtoclean != $stringtoclean);
1619
1620 if ($type == 1) {
1621 // removing '//' should disable links to external url like //aaa or http//)
1622 $stringtoclean = preg_replace(array('/^[a-z]*\/\/+/i'), '', $stringtoclean);
1623 }
1624
1625 return $stringtoclean;
1626}
1627
1634function dol_sanitizeEmail($stringtoclean)
1635{
1636 do {
1637 $oldstringtoclean = $stringtoclean;
1638 $stringtoclean = str_ireplace(array('"', ':', '[', ']',"\n", "\r", '\\', '\/'), '', $stringtoclean);
1639 } while ($oldstringtoclean != $stringtoclean);
1640
1641 return $stringtoclean;
1642}
1643
1652function dol_string_unaccent($str)
1653{
1654 global $conf;
1655
1656 if (is_null($str)) {
1657 return '';
1658 }
1659
1660 if (utf8_check($str)) {
1661 if (extension_loaded('intl') && getDolGlobalString('MAIN_UNACCENT_USE_TRANSLITERATOR')) {
1662 $transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: NFC;', Transliterator::FORWARD);
1663 return $transliterator->transliterate($str);
1664 }
1665 // See http://www.utf8-chartable.de/
1666 $string = rawurlencode($str);
1667 $replacements = array(
1668 '%C3%80' => 'A', '%C3%81' => 'A', '%C3%82' => 'A', '%C3%83' => 'A', '%C3%84' => 'A', '%C3%85' => 'A',
1669 '%C3%87' => 'C',
1670 '%C3%88' => 'E', '%C3%89' => 'E', '%C3%8A' => 'E', '%C3%8B' => 'E',
1671 '%C3%8C' => 'I', '%C3%8D' => 'I', '%C3%8E' => 'I', '%C3%8F' => 'I',
1672 '%C3%91' => 'N',
1673 '%C3%92' => 'O', '%C3%93' => 'O', '%C3%94' => 'O', '%C3%95' => 'O', '%C3%96' => 'O',
1674 '%C5%A0' => 'S',
1675 '%C3%99' => 'U', '%C3%9A' => 'U', '%C3%9B' => 'U', '%C3%9C' => 'U',
1676 '%C3%9D' => 'Y', '%C5%B8' => 'y',
1677 '%C3%A0' => 'a', '%C3%A1' => 'a', '%C3%A2' => 'a', '%C3%A3' => 'a', '%C3%A4' => 'a', '%C3%A5' => 'a',
1678 '%C3%A7' => 'c',
1679 '%C3%A8' => 'e', '%C3%A9' => 'e', '%C3%AA' => 'e', '%C3%AB' => 'e',
1680 '%C3%AC' => 'i', '%C3%AD' => 'i', '%C3%AE' => 'i', '%C3%AF' => 'i',
1681 '%C3%B1' => 'n',
1682 '%C3%B2' => 'o', '%C3%B3' => 'o', '%C3%B4' => 'o', '%C3%B5' => 'o', '%C3%B6' => 'o',
1683 '%C5%A1' => 's',
1684 '%C3%B9' => 'u', '%C3%BA' => 'u', '%C3%BB' => 'u', '%C3%BC' => 'u',
1685 '%C3%BD' => 'y', '%C3%BF' => 'y'
1686 );
1687 $string = strtr($string, $replacements);
1688 return rawurldecode($string);
1689 } else {
1690 // See http://www.ascii-code.com/
1691 $string = strtr(
1692 $str,
1693 "\xC0\xC1\xC2\xC3\xC4\xC5\xC7
1694 \xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1
1695 \xD2\xD3\xD4\xD5\xD8\xD9\xDA\xDB\xDD
1696 \xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB
1697 \xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF8
1698 \xF9\xFA\xFB\xFC\xFD\xFF",
1699 "AAAAAAC
1700 EEEEIIIIDN
1701 OOOOOUUUY
1702 aaaaaaceeee
1703 iiiidnooooo
1704 uuuuyy"
1705 );
1706 $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"));
1707 return $string;
1708 }
1709}
1710
1724function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '', $badcharstoremove = '', $keepspaces = 0)
1725{
1726 $forbidden_chars_to_replace = array("'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=", '°', '$', ';'); // more complete than dol_sanitizeFileName
1727 if (empty($keepspaces)) {
1728 $forbidden_chars_to_replace[] = " ";
1729 }
1730 $forbidden_chars_to_remove = array();
1731 //$forbidden_chars_to_remove=array("(",")");
1732
1733 if (is_array($badcharstoreplace)) {
1734 $forbidden_chars_to_replace = $badcharstoreplace;
1735 }
1736 if (is_array($badcharstoremove)) {
1737 $forbidden_chars_to_remove = $badcharstoremove;
1738 }
1739
1740 // @phan-suppress-next-line PhanPluginSuspiciousParamOrderInternal
1741 return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str));
1742}
1743
1744
1758function dol_string_nounprintableascii($str, $removetabcrlf = 1)
1759{
1760 if ($removetabcrlf) {
1761 return preg_replace('/[\x00-\x1F\x7F]/u', '', $str); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1762 } else {
1763 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
1764 }
1765}
1766
1775function dol_escape_js($stringtoescape, $mode = 0, $noescapebackslashn = 0)
1776{
1777 if (is_null($stringtoescape)) {
1778 return '';
1779 }
1780
1781 // escape quotes and backslashes, newlines, etc.
1782 $substitjs = array("&#039;" => "\\'", "\r" => '\\r');
1783 //$substitjs['</']='<\/'; // We removed this. Should be useless.
1784 if (empty($noescapebackslashn)) {
1785 $substitjs["\n"] = '\\n';
1786 $substitjs['\\'] = '\\\\';
1787 }
1788 if (empty($mode)) {
1789 $substitjs["'"] = "\\'";
1790 $substitjs['"'] = "\\'";
1791 } elseif ($mode == 1) {
1792 $substitjs["'"] = "\\'";
1793 } elseif ($mode == 2) {
1794 $substitjs['"'] = '\\"';
1795 } elseif ($mode == 3) {
1796 $substitjs["'"] = "\\'";
1797 $substitjs['"'] = "\\\"";
1798 }
1799 return strtr($stringtoescape, $substitjs);
1800}
1801
1808function dol_escape_json($stringtoescape)
1809{
1810 return str_replace('"', '\"', $stringtoescape);
1811}
1812
1820function dol_escape_php($stringtoescape, $stringforquotes = 2)
1821{
1822 if (is_null($stringtoescape)) {
1823 return '';
1824 }
1825
1826 if ($stringforquotes == 2) {
1827 return str_replace('"', "'", $stringtoescape);
1828 } elseif ($stringforquotes == 1) {
1829 // We remove the \ char.
1830 // If we allow the \ char, we can have $stringtoescape =
1831 // abc\';phpcodedanger; so the escapement will become
1832 // abc\\';phpcodedanger; and injecting this into
1833 // $a='...' will give $ac='abc\\';phpcodedanger;
1834 $stringtoescape = str_replace('\\', '', $stringtoescape);
1835 return str_replace("'", "\'", str_replace('"', "'", $stringtoescape));
1836 }
1837
1838 return 'Bad parameter for stringforquotes in dol_escape_php';
1839}
1840
1847function dol_escape_xml($stringtoescape)
1848{
1849 return $stringtoescape;
1850}
1851
1859function dolPrintLabel($s)
1860{
1861 return dol_escape_htmltag(dol_string_nohtmltag($s, 1, 'UTF-8', 0, 0), 0, 0, '', 0, 1);
1862}
1863
1873function dolPrintHTML($s, $allowiframe = 0)
1874{
1875 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, 'common', 0, 1);
1876}
1877
1885function dolPrintHTMLForAttribute($s)
1886{
1887 // The dol_htmlentitiesbr will convert simple text into html
1888 // The dol_escape_htmltag will escape html chars.
1889 return dol_escape_htmltag(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 0, 0, 0, array('br', 'b', 'font', 'span')), 1, -1, '', 0, 1);
1890}
1891
1900function dolPrintHTMLForTextArea($s, $allowiframe = 0)
1901{
1902 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, '', 0, 1);
1903}
1904
1911function dolPrintPassword($s)
1912{
1913 return htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
1914}
1915
1916
1933function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapetags = '', $escapeonlyhtmltags = 0, $cleanalsojavascript = 0)
1934{
1935 if ($noescapetags == 'common') {
1936 $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';
1937 // Add also html5 tags
1938 $noescapetags .= ',header,footer,nav,section,menu,menuitem';
1939 }
1940 if ($cleanalsojavascript) {
1941 $stringtoescape = dol_string_onlythesehtmltags($stringtoescape, 0, 0, $cleanalsojavascript, 0, array(), 0);
1942 }
1943
1944 // escape quotes and backslashes, newlines, etc.
1945 if ($escapeonlyhtmltags) {
1946 $tmp = htmlspecialchars_decode((string) $stringtoescape, ENT_COMPAT);
1947 } else {
1948 $tmp = html_entity_decode((string) $stringtoescape, ENT_COMPAT, 'UTF-8'); // This decode &egrave; into è so string is UTF8 (but &#39; is not decoded).
1949 $tmp = str_ireplace('&#39;', '__SIMPLEQUOTE', $tmp);
1950 }
1951 if (!$keepb) {
1952 $tmp = strtr($tmp, array("<b>" => '', '</b>' => '', '<strong>' => '', '</strong>' => ''));
1953 }
1954 if (!$keepn) {
1955 $tmp = strtr($tmp, array("\r" => '\\r', "\n" => '\\n'));
1956 } elseif ($keepn == -1) {
1957 $tmp = strtr($tmp, array("\r" => '', "\n" => ''));
1958 }
1959
1960 if ($escapeonlyhtmltags) {
1961 return htmlspecialchars($tmp, ENT_COMPAT, 'UTF-8');
1962 } else {
1963 // Escape tags to keep
1964 $tmparrayoftags = array();
1965 if ($noescapetags) {
1966 $tmparrayoftags = explode(',', $noescapetags);
1967 }
1968 if (count($tmparrayoftags)) {
1969 $reg = array();
1970 $tmp = str_ireplace('__DOUBLEQUOTE', '', $tmp); // The keyword DOUBLEQUOTE is forbidden. Reserved, so we removed it if we find it.
1971
1972 foreach ($tmparrayoftags as $tagtoreplace) {
1973 $tmp = preg_replace('/<'.preg_quote($tagtoreplace, '/').'>/', '__BEGINTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1974 $tmp = str_ireplace('</'.$tagtoreplace.'>', '__ENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1975 $tmp = preg_replace('/<'.preg_quote($tagtoreplace, '/').' \/>/', '__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1976
1977 // For case of tag with attribute
1978 do {
1979 $tmpold = $tmp;
1980
1981 if (preg_match('/<'.preg_quote($tagtoreplace, '/').'\s+([^>]+)>/', $tmp, $reg)) {
1982 $tmpattributes = str_ireplace(array('[', ']'), '_', $reg[1]); // We must never have [ ] inside the attribute string
1983 $tmpattributes = str_ireplace('href="http:', '__HREFHTTPA', $tmpattributes);
1984 $tmpattributes = str_ireplace('href="https:', '__HREFHTTPSA', $tmpattributes);
1985 $tmpattributes = str_ireplace('src="http:', '__SRCHTTPIMG', $tmpattributes);
1986 $tmpattributes = str_ireplace('src="https:', '__SRCHTTPSIMG', $tmpattributes);
1987 $tmpattributes = str_ireplace('"', '__DOUBLEQUOTE', $tmpattributes);
1988 $tmpattributes = preg_replace('/[^a-z0-9_\/\?\;\s=&\.\-@:\.#\+]/i', '', $tmpattributes);
1989 //$tmpattributes = preg_replace("/float:\s*(left|right)/", "", $tmpattributes); // Disabled: we must not remove content
1990 $tmp = preg_replace('/<'.preg_quote($tagtoreplace, '/').'\s+'.preg_quote($reg[1], '/').'>/', '__BEGINTAGTOREPLACE'.$tagtoreplace.'['.$tmpattributes.']__', $tmp);
1991 }
1992 if (preg_match('/<'.preg_quote($tagtoreplace, '/').'\s+([^>]+)\s+\/>/', $tmp, $reg)) {
1993 $tmpattributes = str_ireplace(array('[', ']'), '_', $reg[1]); // We must not have [ ] inside the attribute string
1994 $tmpattributes = str_ireplace('"', '__DOUBLEQUOTE', $tmpattributes);
1995 $tmpattributes = preg_replace('/[^a-z0-9_\/\?\;\s=&\.\-@:\.#\+]/i', '', $tmpattributes);
1996 //$tmpattributes = preg_replace("/float:\s*(left|right)/", "", $tmpattributes); // Disabled: we must not remove content.
1997 $tmp = preg_replace('/<'.preg_quote($tagtoreplace, '/').'\s+'.preg_quote($reg[1], '/').'\s+\/>/', '__BEGINENDTAGTOREPLACE'.$tagtoreplace.'['.$tmpattributes.']__', $tmp);
1998 }
1999
2000 $diff = strcmp($tmpold, $tmp);
2001 } while ($diff);
2002 }
2003 }
2004
2005 $result = htmlentities($tmp, ENT_COMPAT, 'UTF-8'); // Convert & into &amp; and more...
2006
2007 //print $result;
2008
2009 if (count($tmparrayoftags)) {
2010 foreach ($tmparrayoftags as $tagtoreplace) {
2011 $result = str_ireplace('__BEGINTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.'>', $result);
2012 $result = preg_replace('/__BEGINTAGTOREPLACE'.$tagtoreplace.'\[([^\]]*)\]__/', '<'.$tagtoreplace.' \1>', $result);
2013 $result = str_ireplace('__ENDTAGTOREPLACE'.$tagtoreplace.'__', '</'.$tagtoreplace.'>', $result);
2014 $result = str_ireplace('__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.' />', $result);
2015 $result = preg_replace('/__BEGINENDTAGTOREPLACE'.$tagtoreplace.'\[([^\]]*)\]__/', '<'.$tagtoreplace.' \1 />', $result);
2016 }
2017
2018 $result = str_ireplace('__HREFHTTPA', 'href="http:', $result);
2019 $result = str_ireplace('__HREFHTTPSA', 'href="https:', $result);
2020 $result = str_ireplace('__SRCHTTPIMG', 'src="http:', $result);
2021 $result = str_ireplace('__SRCHTTPSIMG', 'src="https:', $result);
2022 $result = str_ireplace('__DOUBLEQUOTE', '"', $result);
2023 }
2024
2025 $result = str_ireplace('__SIMPLEQUOTE', '&#39;', $result);
2026
2027 //$result="\n\n\n".var_export($tmp, true)."\n\n\n".var_export($result, true);
2028
2029 return $result;
2030 }
2031}
2032
2040function dol_strtolower($string, $encoding = "UTF-8")
2041{
2042 if (function_exists('mb_strtolower')) {
2043 return mb_strtolower($string, $encoding);
2044 } else {
2045 return strtolower($string);
2046 }
2047}
2048
2057function dol_strtoupper($string, $encoding = "UTF-8")
2058{
2059 if (function_exists('mb_strtoupper')) {
2060 return mb_strtoupper($string, $encoding);
2061 } else {
2062 return strtoupper($string);
2063 }
2064}
2065
2074function dol_ucfirst($string, $encoding = "UTF-8")
2075{
2076 if (function_exists('mb_substr')) {
2077 return mb_strtoupper(mb_substr($string, 0, 1, $encoding), $encoding).mb_substr($string, 1, null, $encoding);
2078 } else {
2079 return ucfirst($string);
2080 }
2081}
2082
2091function dol_ucwords($string, $encoding = "UTF-8")
2092{
2093 if (function_exists('mb_convert_case')) {
2094 return mb_convert_case($string, MB_CASE_TITLE, $encoding);
2095 } else {
2096 return ucwords($string);
2097 }
2098}
2099
2122function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = '', $restricttologhandler = '', $logcontext = null)
2123{
2124 global $conf, $user, $debugbar;
2125
2126 // If syslog module enabled
2127 if (!isModEnabled('syslog')) {
2128 return;
2129 }
2130
2131 // Check if we are into execution of code of a website
2132 if (defined('USEEXTERNALSERVER') && !defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) {
2133 global $website, $websitekey;
2134 if (is_object($website) && !empty($website->ref)) {
2135 $suffixinfilename .= '_website_'.$website->ref;
2136 } elseif (!empty($websitekey)) {
2137 $suffixinfilename .= '_website_'.$websitekey;
2138 }
2139 }
2140
2141 // Check if we have a forced suffix
2142 if (defined('USESUFFIXINLOG')) {
2143 $suffixinfilename .= constant('USESUFFIXINLOG');
2144 }
2145
2146 if ($ident < 0) {
2147 foreach ($conf->loghandlers as $loghandlerinstance) {
2148 $loghandlerinstance->setIdent($ident);
2149 }
2150 }
2151
2152 if (!empty($message)) {
2153 // Test log level
2154 // @phan-suppress-next-line PhanPluginDuplicateArrayKey
2155 $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');
2156 if (!array_key_exists($level, $logLevels)) {
2157 throw new Exception('Incorrect log level');
2158 }
2159 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
2160 return;
2161 }
2162
2163 if (!getDolGlobalString('MAIN_SHOW_PASSWORD_INTO_LOG')) {
2164 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
2165 }
2166
2167 // If adding log inside HTML page is required
2168 if ((!empty($_REQUEST['logtohtml']) && getDolGlobalString('MAIN_ENABLE_LOG_TO_HTML'))
2169 || (is_object($user) && $user->hasRight('debugbar', 'read') && is_object($debugbar))) {
2170 $ospid = sprintf("%7s", dol_trunc(getmypid(), 7, 'right', 'UTF-8', 1));
2171 $osuser = " ".sprintf("%6s", dol_trunc(function_exists('posix_getuid') ? posix_getuid() : '', 6, 'right', 'UTF-8', 1));
2172
2173 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".sprintf("%-7s", $logLevels[$level])." ".$ospid." ".$osuser." ".$message;
2174 }
2175
2176 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
2177 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
2178 if (getDolGlobalString('MAIN_ENABLE_LOG_INLINE_HTML') && GETPOSTINT("log")) {
2179 print "\n\n<!-- Log start\n";
2180 print dol_escape_htmltag($message)."\n";
2181 print "Log end -->\n";
2182 }
2183
2184 $data = array(
2185 'message' => $message,
2186 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
2187 'level' => $level,
2188 'user' => ((is_object($user) && $user->id) ? $user->login : false),
2189 'ip' => false,
2190 'osuser' => function_exists('posix_getuid') ? posix_getuid() : false,
2191 'ospid' => getmypid() // on linux, max value is defined into cat /proc/sys/kernel/pid_max
2192 );
2193
2194 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
2195 if (!empty($remoteip)) {
2196 $data['ip'] = $remoteip;
2197 // This is when server run behind a reverse proxy
2198 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
2199 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
2200 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
2201 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
2202 }
2203 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
2204 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
2205 $data['ip'] = $_SERVER['SERVER_ADDR'];
2206 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
2207 // 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).
2208 $data['ip'] = $_SERVER['COMPUTERNAME'];
2209 } else {
2210 $data['ip'] = '???';
2211 }
2212
2213 if (!empty($_SERVER['USERNAME'])) {
2214 // 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).
2215 $data['osuser'] = $_SERVER['USERNAME'];
2216 } elseif (!empty($_SERVER['LOGNAME'])) {
2217 // 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).
2218 $data['osuser'] = $_SERVER['LOGNAME'];
2219 }
2220
2221 // Loop on each log handler and send output
2222 foreach ($conf->loghandlers as $loghandlerinstance) {
2223 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
2224 continue;
2225 }
2226 $loghandlerinstance->export($data, $suffixinfilename);
2227 }
2228 unset($data);
2229 }
2230
2231 if ($ident > 0) {
2232 foreach ($conf->loghandlers as $loghandlerinstance) {
2233 $loghandlerinstance->setIdent($ident);
2234 }
2235 }
2236}
2237
2249function dolButtonToOpenExportDialog($name, $label, $buttonstring, $exportSiteName, $overwriteGitUrl, $website)
2250{
2251 global $langs, $db;
2252
2253 $form = new Form($db);
2254
2255 $templatenameforexport = $website->name_template; // Example 'website_template-corporate'
2256 if (empty($templatenameforexport)) {
2257 $templatenameforexport = 'website_'.$website->ref;
2258 }
2259
2260 $out = '';
2261 $out .= '<input type="button" class="cursorpointer button bordertransp" id="open-dialog-' . $name . '" value="'.dol_escape_htmltag($buttonstring).'"/>';
2262
2263 // for generate popup
2264 $out .= '<script nonce="' . getNonce() . '" type="text/javascript">';
2265 $out .= 'jQuery(document).ready(function () {';
2266 $out .= ' jQuery("#open-dialog-' . $name . '").click(function () {';
2267 $out .= ' var dialogHtml = \'';
2268
2269 $dialogcontent = ' <div id="custom-dialog-' . $name . '">';
2270 $dialogcontent .= ' <div style="margin-top: 20px;">';
2271 $dialogcontent .= ' <label for="export-site-' . $name . '"><strong>'.$langs->trans("ExportSiteLabel").'...</label><br>';
2272 $dialogcontent .= ' <button class="button smallpaddingimp" id="export-site-' . $name . '">' . dol_escape_htmltag($langs->trans("DownloadZip")) . '</button>';
2273 $dialogcontent .= ' </div>';
2274 $dialogcontent .= ' <br>';
2275 $dialogcontent .= ' <div style="margin-top: 20px;">';
2276 $dialogcontent .= ' <strong>'.$langs->trans("ExportSiteGitLabel").' '.$form->textwithpicto('', $langs->trans("SourceFiles"), 1, 'help', '', 0, 3, '').'</strong><br>';
2277 $dialogcontent .= ' <form action="'.dol_escape_htmltag($overwriteGitUrl).'" method="POST">';
2278 $dialogcontent .= ' <input type="hidden" name="action" value="overwritesite">';
2279 $dialogcontent .= ' <input type="hidden" name="token" value="'.newToken().'">';
2280 $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>';
2281 $dialogcontent .= ' <button type="submit" class="button smallpaddingimp" id="overwrite-git-' . $name . '">' . dol_escape_htmltag($langs->trans("ExportIntoGIT")) . '</button>';
2282 $dialogcontent .= ' </form>';
2283 $dialogcontent .= ' </div>';
2284 $dialogcontent .= ' </div>';
2285
2286 $out .= dol_escape_js($dialogcontent);
2287
2288 $out .= '\';';
2289
2290
2291 // Add the content of the dialog to the body of the page
2292 $out .= ' var $dialog = jQuery("#custom-dialog-' . $name . '");';
2293 $out .= ' if ($dialog.length > 0) {
2294 $dialog.remove();
2295 }
2296 jQuery("body").append(dialogHtml);';
2297
2298 // Configuration of popup
2299 $out .= ' jQuery("#custom-dialog-' . $name . '").dialog({';
2300 $out .= ' autoOpen: false,';
2301 $out .= ' modal: true,';
2302 $out .= ' height: 290,';
2303 $out .= ' width: "40%",';
2304 $out .= ' title: "' . dol_escape_js($label) . '",';
2305 $out .= ' });';
2306
2307 // Simulate a click on the original "submit" input to export the site.
2308 $out .= ' jQuery("#export-site-' . $name . '").click(function () {';
2309 $out .= ' console.log("Clic on exportsite.");';
2310 $out .= ' var target = jQuery("input[name=\'' . dol_escape_js($exportSiteName) . '\']");';
2311 $out .= ' console.log("element founded:", target.length > 0);';
2312 $out .= ' if (target.length > 0) { target.click(); }';
2313 $out .= ' jQuery("#custom-dialog-' . $name . '").dialog("close");';
2314 $out .= ' });';
2315
2316 // open popup
2317 $out .= ' jQuery("#custom-dialog-' . $name . '").dialog("open");';
2318 $out .= ' return false;';
2319 $out .= ' });';
2320 $out .= '});';
2321 $out .= '</script>';
2322
2323 return $out;
2324}
2325
2326
2343function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
2344{
2345 global $conf;
2346
2347 if (strpos($url, '?') > 0) {
2348 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2349 } else {
2350 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2351 }
2352
2353 $out = '';
2354
2355 $backtopagejsfieldsid = '';
2356 $backtopagejsfieldslabel = '';
2357 if ($backtopagejsfields) {
2358 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
2359 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
2360 $backtopagejsfields = $name.":".$backtopagejsfields;
2361 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
2362 } else {
2363 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
2364 }
2365 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
2366 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
2367 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
2368 }
2369
2370 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
2371 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
2372 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
2373 if (empty($conf->use_javascript_ajax)) {
2374 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
2375 } elseif ($jsonopen) {
2376 $out .= ' href="#" onclick="'.$jsonopen.'"';
2377 } else {
2378 $out .= ' href="#"';
2379 }
2380 $out .= '>'.$buttonstring.'</a>';
2381
2382 if (!empty($conf->use_javascript_ajax)) {
2383 // Add code to open url using the popup. Add also hidden field to retrieve the returned variables
2384 $out .= '<!-- code to open popup and variables to retrieve returned variables -->';
2385 $out .= '<div id="idfordialog'.$name.'" class="hidden">'.(getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2 ? 'div for dialog' : '').'</div>';
2386 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">'.(getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2 ? 'div for returned id' : '').'</div>';
2387 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">'.(getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2 ? 'div for returned label' : '').'</div>';
2388
2389 $out .= '<!-- Add js code to open dialog popup on dialog -->';
2390 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
2391 jQuery(document).ready(function () {
2392 jQuery(".button_'.$name.'").click(function () {
2393 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
2394 var $tmpdialog = $(\'#idfordialog'.$name.'\');
2395 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
2396 $tmpdialog.dialog({
2397 autoOpen: false,
2398 modal: true,
2399 height: (window.innerHeight - 150),
2400 width: \'80%\',
2401 title: \''.dol_escape_js($label).'\',
2402 open: function (event, ui) {
2403 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
2404 },
2405 close: function (event, ui) {
2406 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
2407 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
2408 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
2409 if (returnedid != "" && returnedid != "div for returned id") {
2410 jQuery("#'.(empty($backtopagejsfieldsid) ? "none" : $backtopagejsfieldsid).'").val(returnedid);
2411 }
2412 if (returnedlabel != "" && returnedlabel != "div for returned label") {
2413 jQuery("#'.(empty($backtopagejsfieldslabel) ? "none" : $backtopagejsfieldslabel).'").val(returnedlabel);
2414 }
2415 }
2416 });
2417
2418 $tmpdialog.dialog(\'open\');
2419 return false;
2420 });
2421 });
2422 </script>';
2423 }
2424 return $out;
2425}
2426
2443function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2444{
2445 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2446}
2447
2464function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2465{
2466 global $conf, $langs, $hookmanager;
2467
2468 // Show title
2469 $showtitle = 1;
2470 if (!empty($conf->dol_optimize_smallscreen)) {
2471 $showtitle = 0;
2472 }
2473
2474 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2475
2476 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2477 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2478 }
2479
2480 // Show right part
2481 if ($morehtmlright) {
2482 $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.
2483 }
2484
2485 // Show title
2486 if (!empty($title) && $showtitle && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2487 $limittitle = 30;
2488 $out .= '<a class="tabTitle">';
2489 if ($picto) {
2490 $noprefix = $pictoisfullpath;
2491 if (strpos($picto, 'fontawesome_') !== false) {
2492 $noprefix = 1;
2493 }
2494 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2495 }
2496 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2497 $out .= '</a>';
2498 }
2499
2500 // Show tabs
2501
2502 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2503 $maxkey = -1;
2504 if (is_array($links) && !empty($links)) {
2505 $keys = array_keys($links);
2506 if (count($keys)) {
2507 $maxkey = max($keys);
2508 }
2509 }
2510
2511 // Show tabs
2512 // if =0 we don't use the feature
2513 if (empty($limittoshow)) {
2514 $limittoshow = (!getDolGlobalString('MAIN_MAXTABS_IN_CARD') ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2515 }
2516 if (!empty($conf->dol_optimize_smallscreen)) {
2517 $limittoshow = 2;
2518 }
2519
2520 $displaytab = 0;
2521 $nbintab = 0;
2522 $popuptab = 0;
2523 $outmore = '';
2524 for ($i = 0; $i <= $maxkey; $i++) {
2525 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2526 // If active tab is already present
2527 if ($i >= $limittoshow) {
2528 $limittoshow--;
2529 }
2530 }
2531 }
2532
2533 for ($i = 0; $i <= $maxkey; $i++) {
2534 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2535 $isactive = true;
2536 } else {
2537 $isactive = false;
2538 }
2539
2540 if ($i < $limittoshow || $isactive) {
2541 // Output entry with a visible tab
2542 $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])).' -->';
2543
2544 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2545 if (!empty($links[$i][0])) {
2546 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2547 } else {
2548 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2549 }
2550 } elseif (!empty($links[$i][1])) {
2551 //print "x $i $active ".$links[$i][2]." z";
2552 $out .= '<div class="tab tab'.($isactive ? 'active' : 'unactive').'" style="margin: 0 !important">';
2553 if (!empty($links[$i][0])) {
2554 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2555 $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).'">';
2556 }
2557 $out .= $links[$i][1];
2558 if (!empty($links[$i][0])) {
2559 $out .= '</a>'."\n";
2560 }
2561 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2562 $out .= '</div>';
2563 }
2564
2565 $out .= '</div>';
2566 } else {
2567 // Add entry into the combo popup with the other tabs
2568 if (!$popuptab) {
2569 $popuptab = 1;
2570 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2571 }
2572 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2573 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2574 if (!empty($links[$i][0])) {
2575 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2576 } else {
2577 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2578 }
2579 } elseif (!empty($links[$i][1])) {
2580 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2581 $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.
2582 $outmore .= '</a>'."\n";
2583 }
2584 $outmore .= '</div>';
2585
2586 $nbintab++;
2587 }
2588 $displaytab = $i;
2589 }
2590 if ($popuptab) {
2591 $outmore .= '</div>';
2592 }
2593
2594 if ($popuptab) { // If there is some tabs not shown
2595 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2596 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2597 $widthofpopup = 200;
2598
2599 $tabsname = $moretabssuffix;
2600 if (empty($tabsname)) {
2601 $tabsname = str_replace("@", "", $picto);
2602 }
2603 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2604 if (getDolGlobalInt('MAIN_OPTIMIZEFORTEXTBROWSER') < 2) {
2605 $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".
2606 }
2607 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2608 $out .= $outmore;
2609 $out .= '</div>';
2610 $out .= '<div></div>';
2611 $out .= "</div>\n";
2612
2613 $out .= '<script nonce="'.getNonce().'">';
2614 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2615 var x = this.offsetLeft, y = this.offsetTop;
2616 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2617 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2618 $('#moretabsList".$tabsname."').css('".$right."','8px');
2619 }
2620 $('#moretabsList".$tabsname."').css('".$left."','auto');
2621 });
2622 ";
2623 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2624 $out .= "</script>";
2625 }
2626
2627 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2628 $out .= "</div>\n";
2629 }
2630
2631 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2632 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom')));
2633 $out .= '">'."\n";
2634 }
2635 if (!empty($dragdropfile)) {
2636 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2637 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2638 }
2639 $parameters = array('tabname' => $active, 'out' => $out);
2640 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2641 if ($reshook > 0) {
2642 $out = $hookmanager->resPrint;
2643 }
2644
2645 return $out;
2646}
2647
2655function dol_fiche_end($notab = 0)
2656{
2657 print dol_get_fiche_end($notab);
2658}
2659
2666function dol_get_fiche_end($notab = 0)
2667{
2668 if (!$notab || $notab == -1) {
2669 return "\n</div>\n";
2670 } else {
2671 return '';
2672 }
2673}
2674
2694function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2695{
2696 global $conf, $form, $user, $langs, $hookmanager, $action;
2697
2698 $error = 0;
2699
2700 $maxvisiblephotos = 1;
2701 $showimage = 1;
2702 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2703 // @phan-suppress-next-line PhanUndeclaredMethod
2704 $showbarcode = !isModEnabled('barcode') ? 0 : (empty($object->barcode) ? 0 : 1);
2705 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2706 $showbarcode = 0;
2707 }
2708 $modulepart = 'unknown';
2709
2710 if (in_array($object->element, ['societe', 'contact', 'product', 'ticket', 'bom'])) {
2711 $modulepart = $object->element;
2712 } elseif ($object->element == 'member') {
2713 $modulepart = 'memberphoto';
2714 } elseif ($object->element == 'user') {
2715 $modulepart = 'userphoto';
2716 }
2717
2718 if (class_exists("Imagick")) {
2719 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2720 $modulepart = $object->element;
2721 } elseif ($object->element == 'fichinter' || $object->element == 'intervention') {
2722 $modulepart = 'ficheinter';
2723 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2724 $modulepart = 'contract';
2725 } elseif ($object->element == 'order_supplier') {
2726 $modulepart = 'supplier_order';
2727 } elseif ($object->element == 'invoice_supplier') {
2728 $modulepart = 'supplier_invoice';
2729 }
2730 }
2731
2732 if ($object->element == 'product') {
2734 '@phan-var-force Product $object';
2735 $width = 80;
2736 $cssclass = 'photowithmargin photoref';
2737 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2738 $maxvisiblephotos = getDolGlobalInt('PRODUCT_MAX_VISIBLE_PHOTO', 5);
2739 if ($conf->browser->layout == 'phone') {
2740 $maxvisiblephotos = 1;
2741 }
2742 if ($showimage) {
2743 $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>';
2744 } else {
2745 if (getDolGlobalString('PRODUCT_NODISPLAYIFNOPHOTO')) {
2746 $nophoto = '';
2747 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2748 } else { // Show no photo link
2749 $nophoto = '/public/theme/common/nophoto.png';
2750 $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>';
2751 }
2752 }
2753 } elseif ($object->element == 'category') {
2755 '@phan-var-force Categorie $object';
2756 $width = 80;
2757 $cssclass = 'photowithmargin photoref';
2758 $showimage = $object->isAnyPhotoAvailable($conf->categorie->multidir_output[$entity]);
2759 $maxvisiblephotos = getDolGlobalInt('CATEGORY_MAX_VISIBLE_PHOTO', 5);
2760 if ($conf->browser->layout == 'phone') {
2761 $maxvisiblephotos = 1;
2762 }
2763 if ($showimage) {
2764 $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>';
2765 } else {
2766 if (getDolGlobalString('CATEGORY_NODISPLAYIFNOPHOTO')) {
2767 $nophoto = '';
2768 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2769 } else { // Show no photo link
2770 $nophoto = '/public/theme/common/nophoto.png';
2771 $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>';
2772 }
2773 }
2774 } elseif ($object->element == 'bom') {
2776 '@phan-var-force Bom $object';
2777 $width = 80;
2778 $cssclass = 'photowithmargin photoref';
2779 $showimage = $object->is_photo_available($conf->bom->multidir_output[$entity]);
2780 $maxvisiblephotos = getDolGlobalInt('BOM_MAX_VISIBLE_PHOTO', 5);
2781 if ($conf->browser->layout == 'phone') {
2782 $maxvisiblephotos = 1;
2783 }
2784 if ($showimage) {
2785 $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>';
2786 } else {
2787 if (getDolGlobalString('BOM_NODISPLAYIFNOPHOTO')) {
2788 $nophoto = '';
2789 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2790 } else { // Show no photo link
2791 $nophoto = '/public/theme/common/nophoto.png';
2792 $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>';
2793 }
2794 }
2795 } elseif ($object->element == 'ticket') {
2796 $width = 80;
2797 $cssclass = 'photoref';
2799 '@phan-var-force Ticket $object';
2800 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2801 $maxvisiblephotos = getDolGlobalInt('TICKET_MAX_VISIBLE_PHOTO', 2);
2802 if ($conf->browser->layout == 'phone') {
2803 $maxvisiblephotos = 1;
2804 }
2805
2806 if ($showimage) {
2807 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2808 if ($object->nbphoto > 0) {
2809 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2810 } else {
2811 $showimage = 0;
2812 }
2813 }
2814 if (!$showimage) {
2815 if (getDolGlobalString('TICKET_NODISPLAYIFNOPHOTO')) {
2816 $nophoto = '';
2817 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2818 } else { // Show no photo link
2819 $nophoto = img_picto('No photo', 'object_ticket');
2820 $morehtmlleft .= '<!-- No photo to show -->';
2821 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2822 $morehtmlleft .= $nophoto;
2823 $morehtmlleft .= '</div></div>';
2824 }
2825 }
2826 } else {
2827 if ($showimage) {
2828 if ($modulepart != 'unknown' || method_exists($object, 'getDataToShowPhoto')) {
2829 $phototoshow = '';
2830 // Check if a preview file is available
2831 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2832 $objectref = dol_sanitizeFileName($object->ref);
2833 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2834 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2835 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2836 $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
2837 } else {
2838 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2839 }
2840 if (empty($subdir)) {
2841 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2842 }
2843
2844 $filepath = $dir_output.$subdir."/";
2845
2846 $filepdf = $filepath.$objectref.".pdf";
2847 $relativepath = $subdir.'/'.$objectref.'.pdf';
2848
2849 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2850 $fileimage = $filepdf.'_preview.png';
2851 $relativepathimage = $relativepath.'_preview.png';
2852
2853 $pdfexists = file_exists($filepdf);
2854
2855 // If PDF file exists
2856 if ($pdfexists) {
2857 // Conversion du PDF en image png si fichier png non existent
2858 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2859 if (!getDolGlobalString('MAIN_DISABLE_PDF_THUMBS')) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2860 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2861 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2862 if ($ret < 0) {
2863 $error++;
2864 }
2865 }
2866 }
2867 }
2868
2869 if ($pdfexists && !$error) {
2870 $heightforphotref = 80;
2871 if (!empty($conf->dol_optimize_smallscreen)) {
2872 $heightforphotref = 60;
2873 }
2874 // If the preview file is found
2875 if (file_exists($fileimage)) {
2876 $phototoshow = '<div class="photoref">';
2877 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2878 $phototoshow .= '</div>';
2879 }
2880 }
2881 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo' or 'memberphoto'
2882 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2883 }
2884
2885 if ($phototoshow) {
2886 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2887 $morehtmlleft .= $phototoshow;
2888 $morehtmlleft .= '</div>';
2889 }
2890 }
2891
2892 if (empty($phototoshow)) { // Show No photo link (picto of object)
2893 if ($object->element == 'action') {
2894 $width = 80;
2895 $cssclass = 'photorefcenter';
2896 $nophoto = img_picto('No photo', 'title_agenda');
2897 } else {
2898 $width = 14;
2899 $cssclass = 'photorefcenter';
2900 $picto = $object->picto; // @phan-suppress-current-line PhanUndeclaredProperty
2901 $prefix = 'object_';
2902 if ($object->element == 'project' && !$object->public) { // @phan-suppress-current-line PhanUndeclaredProperty
2903 $picto = 'project'; // instead of projectpub
2904 }
2905 if (strpos($picto, 'fontawesome_') !== false) {
2906 $prefix = '';
2907 }
2908 $nophoto = img_picto('No photo', $prefix.$picto);
2909 }
2910 $morehtmlleft .= '<!-- No photo to show -->';
2911 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2912 $morehtmlleft .= $nophoto;
2913 $morehtmlleft .= '</div></div>';
2914 }
2915 }
2916 }
2917
2918 // Show barcode
2919 if ($showbarcode) {
2920 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2921 }
2922
2923 if ($object->element == 'societe') {
2924 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2925 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2926 } else {
2927 $morehtmlstatus .= $object->getLibStatut(6);
2928 }
2929 } elseif ($object->element == 'product') {
2930 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2931 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2932 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2933 } else {
2934 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2935 }
2936 $morehtmlstatus .= ' &nbsp; ';
2937 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2938 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2939 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2940 } else {
2941 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2942 }
2943 } elseif (in_array($object->element, array('salary'))) {
2944 $tmptxt = $object->getLibStatut(6, $object->alreadypaid);
2945 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2946 $tmptxt = $object->getLibStatut(5, $object->alreadypaid);
2947 }
2948 $morehtmlstatus .= $tmptxt;
2949 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier', 'chargesociales', 'loan', 'tva'))) { // TODO Move this to use ->alreadypaid
2950 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2951 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2952 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2953 }
2954 $morehtmlstatus .= $tmptxt;
2955 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2956 if ($object->statut == 0) {
2957 $morehtmlstatus .= $object->getLibStatut(5);
2958 } else {
2959 $morehtmlstatus .= $object->getLibStatut(4);
2960 }
2961 } elseif ($object->element == 'facturerec') {
2962 '@phan-var-force FactureRec $object';
2963 if ($object->frequency == 0) {
2964 $morehtmlstatus .= $object->getLibStatut(2);
2965 } else {
2966 $morehtmlstatus .= $object->getLibStatut(5);
2967 }
2968 } elseif ($object->element == 'project_task') {
2969 $object->fk_statut = 1;
2970 if ($object->progress > 0) {
2971 $object->fk_statut = 2;
2972 }
2973 if ($object->progress >= 100) {
2974 $object->fk_statut = 3;
2975 }
2976 $tmptxt = $object->getLibStatut(5);
2977 $morehtmlstatus .= $tmptxt; // No status on task
2978 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2979 $tmptxt = $object->getLibStatut(6);
2980 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2981 $tmptxt = $object->getLibStatut(5);
2982 }
2983 $morehtmlstatus .= $tmptxt;
2984 }
2985
2986 // Add if object was dispatched "into accountancy"
2987 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2988 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2989 if (method_exists($object, 'getVentilExportCompta')) {
2990 $accounted = $object->getVentilExportCompta();
2991 $langs->load("accountancy");
2992 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2993 }
2994 }
2995
2996 // Add alias for thirdparty
2997 if (!empty($object->name_alias)) {
2998 '@phan-var-force Societe $object';
2999 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
3000 }
3001
3002 // Add label
3003 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
3004 if (!empty($object->label)) {
3005 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
3006 }
3007 }
3008 // Show address and email
3009 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
3010 $moreaddress = $object->getBannerAddress('refaddress', $object); // address, email, url, social networks
3011 if ($moreaddress) {
3012 $morehtmlref .= '<div class="refidno refaddress">';
3013 $morehtmlref .= $moreaddress;
3014 $morehtmlref .= '</div>';
3015 }
3016 }
3017 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)) {
3018 $morehtmlref .= '<div style="clear: both;"></div>';
3019 $morehtmlref .= '<div class="refidno opacitymedium">';
3020 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
3021 $morehtmlref .= '</div>';
3022 }
3023
3024 $parameters = array('morehtmlref' => &$morehtmlref, 'moreparam' => &$moreparam, 'morehtmlleft' => &$morehtmlleft, 'morehtmlstatus' => &$morehtmlstatus, 'morehtmlright' => &$morehtmlright);
3025 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
3026 if ($reshook < 0) {
3027 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
3028 } elseif (empty($reshook)) {
3029 $morehtmlref .= $hookmanager->resPrint;
3030 } elseif ($reshook > 0) {
3031 $morehtmlref = $hookmanager->resPrint;
3032 }
3033
3034 // $morehtml is the right part (link "Back to list")
3035 // $morehtmlleft is the picto or photo of banner
3036 // $morehtmlstatus is part under the status
3037 // $morehtmlright is part of htmlright
3038
3039 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
3040 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
3041 print '</div>';
3042 print '<div class="underrefbanner clearboth"></div>';
3043}
3044
3054function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
3055{
3056 global $langs;
3057 $ret = '';
3058 if ($fieldrequired) {
3059 $ret .= '<span class="fieldrequired">';
3060 }
3061 $ret .= '<label for="'.$fieldkey.'">';
3062 $ret .= $langs->trans($langkey);
3063 $ret .= '</label>';
3064 if ($fieldrequired) {
3065 $ret .= '</span>';
3066 }
3067 return $ret;
3068}
3069
3077function dol_bc($var, $moreclass = '')
3078{
3079 global $bc;
3080 $ret = ' '.$bc[$var];
3081 if ($moreclass) {
3082 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
3083 }
3084 return $ret;
3085}
3086
3100function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = null, $mode = 0, $extralangcode = '')
3101{
3102 global $langs, $hookmanager;
3103
3104 $ret = '';
3105 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
3106
3107 // See format of addresses on https://en.wikipedia.org/wiki/Address
3108 // Address
3109 if (empty($mode)) {
3110 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
3111 }
3112 // Zip/Town/State
3113 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || getDolGlobalString('MAIN_FORCE_STATE_INTO_ADDRESS')) {
3114 // US: title firstname name \n address lines \n town, state, zip \n country
3115 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3116 $ret .= (($ret && $town) ? $sep : '').$town;
3117
3118 if (!empty($object->state)) {
3119 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
3120 }
3121 if (!empty($object->zip)) {
3122 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
3123 }
3124 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
3125 // UK: title firstname name \n address lines \n town state \n zip \n country
3126 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3127 $ret .= ($ret ? $sep : '').$town;
3128 if (!empty($object->state)) {
3129 $ret .= ($ret ? ", " : '').$object->state;
3130 }
3131 if (!empty($object->zip)) {
3132 $ret .= ($ret ? $sep : '').$object->zip;
3133 }
3134 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
3135 // ES: title firstname name \n address lines \n zip town \n state \n country
3136 $ret .= ($ret ? $sep : '').$object->zip;
3137 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3138 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
3139 if (!empty($object->state)) {
3140 $ret .= $sep.$object->state;
3141 }
3142 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
3143 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
3144 // See https://www.sljfaq.org/afaq/addresses.html
3145 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3146 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
3147 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
3148 // IT: title firstname name\n address lines \n zip town state_code \n country
3149 $ret .= ($ret ? $sep : '').$object->zip;
3150 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3151 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
3152 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
3153 } else {
3154 // Other: title firstname name \n address lines \n zip town[, state] \n country
3155 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
3156 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
3157 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
3158 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
3159 $ret .= ($ret ? ", " : '').$object->state;
3160 }
3161 }
3162
3163 if (!is_object($outputlangs)) {
3164 $outputlangs = $langs;
3165 }
3166 if ($withcountry) {
3167 $langs->load("dict");
3168 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
3169 }
3170 if ($hookmanager) {
3171 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
3172 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
3173 if ($reshook > 0) {
3174 $ret = '';
3175 }
3176 $ret .= $hookmanager->resPrint;
3177 }
3178
3179 return $ret;
3180}
3181
3182
3183
3193function dol_strftime($fmt, $ts = false, $is_gmt = false)
3194{
3195 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
3196 return dol_print_date($ts, $fmt, $is_gmt);
3197 } else {
3198 return 'Error date outside supported range';
3199 }
3200}
3201
3223function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = null, $encodetooutput = false)
3224{
3225 global $conf, $langs;
3226
3227 // If date undefined or "", we return ""
3228 if (dol_strlen($time) == 0) {
3229 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
3230 }
3231
3232 if ($tzoutput === 'auto') {
3233 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
3234 }
3235
3236 // Clean parameters
3237 $to_gmt = false;
3238 $offsettz = $offsetdst = 0;
3239 if ($tzoutput) {
3240 $to_gmt = true; // For backward compatibility
3241 if (is_string($tzoutput)) {
3242 if ($tzoutput == 'tzserver') {
3243 $to_gmt = false;
3244 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
3245 // @phan-suppress-next-line PhanPluginRedundantAssignment
3246 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
3247 // @phan-suppress-next-line PhanPluginRedundantAssignment
3248 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
3249 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
3250 $to_gmt = true;
3251 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
3252
3253 if (class_exists('DateTimeZone')) {
3254 $user_date_tz = new DateTimeZone($offsettzstring);
3255 $user_dt = new DateTime();
3256 $user_dt->setTimezone($user_date_tz);
3257 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
3258 $offsettz = $user_dt->getOffset(); // should include dst ?
3259 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
3260 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
3261 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
3262 }
3263 }
3264 }
3265 }
3266 if (!is_object($outputlangs)) {
3267 $outputlangs = $langs;
3268 }
3269 if (!$format) {
3270 $format = 'daytextshort';
3271 }
3272
3273 // Do we have to reduce the length of date (year on 2 chars) to save space.
3274 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
3275 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour', 'dayhoursec'))) ? 1 : 0; // Test on original $format param.
3276 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
3277 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
3278 if ($formatwithoutreduce != $format) {
3279 $format = $formatwithoutreduce;
3280 $reduceformat = 1;
3281 } // so format 'dayreduceformat' is processed like day
3282
3283 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
3284 // TODO Add format daysmallyear and dayhoursmallyear
3285 if ($format == 'day') {
3286 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
3287 } elseif ($format == 'hour') {
3288 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
3289 } elseif ($format == 'hourduration') {
3290 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
3291 } elseif ($format == 'daytext') {
3292 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
3293 } elseif ($format == 'daytextshort') {
3294 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
3295 } elseif ($format == 'dayhour') {
3296 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
3297 } elseif ($format == 'dayhoursec') {
3298 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
3299 } elseif ($format == 'dayhourtext') {
3300 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
3301 } elseif ($format == 'dayhourtextshort') {
3302 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
3303 } elseif ($format == 'dayhourlog') {
3304 // Format not sensitive to language
3305 $format = '%Y%m%d%H%M%S';
3306 } elseif ($format == 'dayhourlogsmall') {
3307 // Format not sensitive to language
3308 $format = '%y%m%d%H%M';
3309 } elseif ($format == 'dayhourldap') {
3310 $format = '%Y%m%d%H%M%SZ';
3311 } elseif ($format == 'dayhourxcard') {
3312 $format = '%Y%m%dT%H%M%SZ';
3313 } elseif ($format == 'dayxcard') {
3314 $format = '%Y%m%d';
3315 } elseif ($format == 'dayrfc') {
3316 $format = '%Y-%m-%d'; // DATE_RFC3339
3317 } elseif ($format == 'dayhourrfc') {
3318 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
3319 } elseif ($format == 'standard') {
3320 $format = '%Y-%m-%d %H:%M:%S';
3321 }
3322
3323 if ($reduceformat) {
3324 $format = str_replace('%Y', '%y', $format);
3325 $format = str_replace('yyyy', 'yy', $format);
3326 }
3327
3328 // Clean format
3329 if (preg_match('/%b/i', $format)) { // There is some text to translate
3330 // We inhibit translation to text made by strftime functions. We will use trans instead later.
3331 $format = str_replace('%b', '__b__', $format);
3332 $format = str_replace('%B', '__B__', $format);
3333 }
3334 if (preg_match('/%a/i', $format)) { // There is some text to translate
3335 // We inhibit translation to text made by strftime functions. We will use trans instead later.
3336 $format = str_replace('%a', '__a__', $format);
3337 $format = str_replace('%A', '__A__', $format);
3338 }
3339
3340 // Analyze date
3341 $reg = array();
3342 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
3343 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"]));
3344 return '';
3345 } 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
3346 // This part of code should not be used anymore.
3347 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);
3348 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
3349 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
3350 $syear = (!empty($reg[1]) ? $reg[1] : '');
3351 $smonth = (!empty($reg[2]) ? $reg[2] : '');
3352 $sday = (!empty($reg[3]) ? $reg[3] : '');
3353 $shour = (!empty($reg[4]) ? $reg[4] : '');
3354 $smin = (!empty($reg[5]) ? $reg[5] : '');
3355 $ssec = (!empty($reg[6]) ? $reg[6] : '');
3356
3357 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
3358
3359 if ($to_gmt) {
3360 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
3361 } else {
3362 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
3363 }
3364 $dtts = new DateTime();
3365 $dtts->setTimestamp($time);
3366 $dtts->setTimezone($tzo);
3367 $newformat = str_replace(
3368 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
3369 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
3370 $format
3371 );
3372 $ret = $dtts->format($newformat);
3373 $ret = str_replace(
3374 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
3375 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
3376 $ret
3377 );
3378 } else {
3379 // Date is a timestamps
3380 if ($time < 100000000000) { // Protection against bad date values
3381 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
3382
3383 if ($to_gmt) {
3384 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
3385 } else {
3386 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
3387 }
3388 $dtts = new DateTime();
3389 $dtts->setTimestamp($timetouse);
3390 $dtts->setTimezone($tzo);
3391 $newformat = str_replace(
3392 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
3393 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
3394 $format
3395 );
3396 $ret = $dtts->format($newformat);
3397 $ret = str_replace(
3398 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
3399 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
3400 $ret
3401 );
3402 //var_dump($ret);exit;
3403 } else {
3404 $ret = 'Bad value '.$time.' for date';
3405 }
3406 }
3407
3408 if (preg_match('/__b__/i', $format)) {
3409 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
3410
3411 if ($to_gmt) {
3412 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
3413 } else {
3414 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
3415 }
3416 $dtts = new DateTime();
3417 $dtts->setTimestamp($timetouse);
3418 $dtts->setTimezone($tzo);
3419 $month = (int) $dtts->format("m");
3420 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
3421 if ($encodetooutput) {
3422 $monthtext = $outputlangs->transnoentities('Month'.$month);
3423 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
3424 } else {
3425 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
3426 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
3427 }
3428 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
3429 $ret = str_replace('__b__', $monthtextshort, $ret);
3430 $ret = str_replace('__B__', $monthtext, $ret);
3431 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
3432 //return $ret;
3433 }
3434 if (preg_match('/__a__/i', $format)) {
3435 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
3436 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
3437
3438 if ($to_gmt) {
3439 $tzo = new DateTimeZone('UTC');
3440 } else {
3441 $tzo = new DateTimeZone(date_default_timezone_get());
3442 }
3443 $dtts = new DateTime();
3444 $dtts->setTimestamp($timetouse);
3445 $dtts->setTimezone($tzo);
3446 $w = $dtts->format("w");
3447 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
3448
3449 $ret = str_replace('__A__', $dayweek, $ret);
3450 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
3451 }
3452
3453 return $ret;
3454}
3455
3456
3477function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
3478{
3479 if ($timestamp === '') {
3480 return array();
3481 }
3482
3483 $datetimeobj = new DateTime();
3484 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
3485 if ($forcetimezone) {
3486 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
3487 }
3488 $arrayinfo = array(
3489 'year' => ((int) date_format($datetimeobj, 'Y')),
3490 'mon' => ((int) date_format($datetimeobj, 'm')),
3491 'mday' => ((int) date_format($datetimeobj, 'd')),
3492 'wday' => ((int) date_format($datetimeobj, 'w')),
3493 'yday' => ((int) date_format($datetimeobj, 'z')),
3494 'hours' => ((int) date_format($datetimeobj, 'H')),
3495 'minutes' => ((int) date_format($datetimeobj, 'i')),
3496 'seconds' => ((int) date_format($datetimeobj, 's')),
3497 '0' => $timestamp
3498 );
3499
3500 return $arrayinfo;
3501}
3502
3524function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3525{
3526 global $conf;
3527 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3528
3529 if ($gm === 'auto') {
3530 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3531 }
3532 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3533
3534 // Clean parameters
3535 if ($hour == -1 || empty($hour)) {
3536 $hour = 0;
3537 }
3538 if ($minute == -1 || empty($minute)) {
3539 $minute = 0;
3540 }
3541 if ($second == -1 || empty($second)) {
3542 $second = 0;
3543 }
3544
3545 // Check parameters
3546 if ($check) {
3547 if (!$month || !$day) {
3548 return '';
3549 }
3550 if ($day > 31) {
3551 return '';
3552 }
3553 if ($month > 12) {
3554 return '';
3555 }
3556 if ($hour < 0 || $hour > 24) {
3557 return '';
3558 }
3559 if ($minute < 0 || $minute > 60) {
3560 return '';
3561 }
3562 if ($second < 0 || $second > 60) {
3563 return '';
3564 }
3565 }
3566
3567 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3568 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3569 $localtz = new DateTimeZone($default_timezone);
3570 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3571 // We use dol_tz_string first because it is more reliable.
3572 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3573 try {
3574 $localtz = new DateTimeZone($default_timezone);
3575 } catch (Exception $e) {
3576 dol_syslog("Warning dol_tz_string contains an invalid value ".json_encode($_SESSION["dol_tz_string"] ?? null), LOG_WARNING);
3577 $default_timezone = @date_default_timezone_get();
3578 }
3579 } elseif (strrpos($gm, "tz,") !== false) {
3580 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3581 try {
3582 $localtz = new DateTimeZone($timezone);
3583 } catch (Exception $e) {
3584 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3585 }
3586 }
3587
3588 if (empty($localtz)) {
3589 $localtz = new DateTimeZone('UTC');
3590 }
3591 //var_dump($localtz);
3592 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3593 $dt = new DateTime('now', $localtz);
3594 $dt->setDate((int) $year, (int) $month, (int) $day);
3595 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3596 $date = $dt->getTimestamp(); // should include daylight saving time
3597 //var_dump($date);
3598 return $date;
3599}
3600
3601
3612function dol_now($mode = 'auto')
3613{
3614 $ret = 0;
3615
3616 if ($mode === 'auto') {
3617 $mode = 'gmt';
3618 }
3619
3620 if ($mode == 'gmt') {
3621 $ret = time(); // Time for now at greenwich.
3622 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3623 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3624 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3625 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3626 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3627 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3628 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3629 // $ret=dol_now('gmt')+($tzsecond*3600);
3630 //}
3631 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3632 // Time for now with user timezone added
3633 //print 'time: '.time();
3634 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3635 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3636 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3637 }
3638
3639 return $ret;
3640}
3641
3642
3651function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3652{
3653 global $conf, $langs;
3654 $level = 1024;
3655
3656 if (!empty($conf->dol_optimize_smallscreen)) {
3657 $shortunit = 1;
3658 }
3659
3660 // Set value text
3661 if (empty($shortvalue) || $size < ($level * 10)) {
3662 $ret = $size;
3663 $textunitshort = $langs->trans("b");
3664 $textunitlong = $langs->trans("Bytes");
3665 } else {
3666 $ret = round($size / $level, 0);
3667 $textunitshort = $langs->trans("Kb");
3668 $textunitlong = $langs->trans("KiloBytes");
3669 }
3670 // Use long or short text unit
3671 if (empty($shortunit)) {
3672 $ret .= ' '.$textunitlong;
3673 } else {
3674 $ret .= ' '.$textunitshort;
3675 }
3676
3677 return $ret;
3678}
3679
3690function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = '')
3691{
3692 global $langs;
3693
3694 if (empty($url)) {
3695 return '';
3696 }
3697
3698 $linkstart = '<a href="';
3699 if (!preg_match('/^http/i', $url)) {
3700 $linkstart .= 'http://';
3701 }
3702 $linkstart .= $url;
3703 $linkstart .= '"';
3704 if ($target) {
3705 $linkstart .= ' target="'.$target.'"';
3706 }
3707 $linkstart .= ' title="'.$langs->trans("URL").': '.$url.'"';
3708 $linkstart .= '>';
3709
3710 $link = '';
3711 if (!preg_match('/^http/i', $url)) {
3712 $link .= 'http://';
3713 }
3714 $link .= dol_trunc($url, $max);
3715
3716 $linkend = '</a>';
3717
3718 if ($morecss == 'float') { // deprecated
3719 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto($langs->trans("Url"), 'globe', 'class="paddingrightonly"') : '').$link.'</div>';
3720 } else {
3721 return $linkstart.'<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto('', 'globe', 'class="paddingrightonly"') : '').$link.'</span>'.$linkend;
3722 }
3723}
3724
3737function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3738{
3739 global $user, $langs, $hookmanager;
3740
3741 //global $conf; $conf->global->AGENDA_ADDACTIONFOREMAIL = 1;
3742 //$showinvalid = 1; $email = 'rrrrr';
3743
3744 $newemail = dol_escape_htmltag($email);
3745
3746 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && $withpicto) {
3747 $withpicto = 0;
3748 }
3749
3750 if (empty($email)) {
3751 return '&nbsp;';
3752 }
3753
3754 if (!empty($addlink)) {
3755 $newemail = '<a class="paddingrightonly" style="text-overflow: ellipsis;" href="';
3756 if (!preg_match('/^mailto:/i', $email)) {
3757 $newemail .= 'mailto:';
3758 }
3759 $newemail .= $email;
3760 $newemail .= '">';
3761
3762 $newemail .= ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '');
3763
3764 $newemail .= dol_trunc($email, $max);
3765 $newemail .= '</a>';
3766 if ($showinvalid && !isValidEmail($email)) {
3767 $langs->load("errors");
3768 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email), '', 'paddingrightonly');
3769 }
3770
3771 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3772 $type = 'AC_EMAIL';
3773 $linktoaddaction = '';
3774 if (getDolGlobalString('AGENDA_ADDACTIONFOREMAIL')) {
3775 $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>';
3776 }
3777 if ($linktoaddaction) {
3778 $newemail = '<div>'.$newemail.' '.$linktoaddaction.'</div>';
3779 }
3780 }
3781 } else {
3782 $newemail = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3783
3784 if ($showinvalid && !isValidEmail($email)) {
3785 $langs->load("errors");
3786 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3787 }
3788 }
3789
3790 //$rep = '<div class="nospan" style="margin-right: 10px">';
3791 //$rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3792 //$rep .= '</div>';
3793 $rep = $newemail;
3794
3795 if ($hookmanager) {
3796 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3797
3798 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3799 if ($reshook > 0) {
3800 $rep = '';
3801 }
3802 $rep .= $hookmanager->resPrint;
3803 }
3804
3805 return $rep;
3806}
3807
3813function getArrayOfSocialNetworks()
3814{
3815 global $conf, $db;
3816
3817 $socialnetworks = array();
3818 // Enable caching of array
3819 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3820 $cachekey = 'socialnetworks_' . $conf->entity;
3821 $dataretrieved = dol_getcache($cachekey);
3822 if (!is_null($dataretrieved)) {
3823 $socialnetworks = $dataretrieved;
3824 } else {
3825 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3826 $sql .= " WHERE entity=".$conf->entity;
3827 $resql = $db->query($sql);
3828 if ($resql) {
3829 while ($obj = $db->fetch_object($resql)) {
3830 $socialnetworks[$obj->code] = array(
3831 'rowid' => $obj->rowid,
3832 'label' => $obj->label,
3833 'url' => $obj->url,
3834 'icon' => $obj->icon,
3835 'active' => $obj->active,
3836 );
3837 }
3838 }
3839 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3840 }
3841 return $socialnetworks;
3842}
3843
3854function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3855{
3856 global $user, $langs;
3857
3858 $htmllink = $value;
3859
3860 if (empty($value)) {
3861 return '&nbsp;';
3862 }
3863
3864 if (!empty($type)) {
3865 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3866 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3867 $htmllink .= '<span class="fab pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3868 if ($type == 'skype') {
3869 $htmllink .= dol_escape_htmltag($value);
3870 $htmllink .= '&nbsp; <a href="skype:';
3871 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3872 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3873 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3874 $htmllink .= '</a><a href="skype:';
3875 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3876 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3877 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3878 $htmllink .= '</a>';
3879 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3880 $addlink = 'AC_SKYPE';
3881 $link = '';
3882 if (getDolGlobalString('AGENDA_ADDACTIONFORSKYPE')) {
3883 $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>';
3884 }
3885 $htmllink .= ($link ? ' '.$link : '');
3886 }
3887 } else {
3888 $networkconstname = 'MAIN_INFO_SOCIETE_'.strtoupper($type).'_URL';
3889 if (getDolGlobalString($networkconstname)) {
3890 $link = str_replace('{socialid}', $value, getDolGlobalString($networkconstname));
3891 if (preg_match('/^https?:\/\//i', $link)) {
3892 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3893 } else {
3894 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3895 }
3896 } elseif (!empty($dictsocialnetworks[$type]['url'])) {
3897 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3898 if ($tmpvirginurl) {
3899 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3900 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3901
3902 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3903 if ($tmpvirginurl3) {
3904 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3905 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3906 }
3907
3908 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3909 if ($tmpvirginurl2) {
3910 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3911 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3912 }
3913 }
3914 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3915 if (preg_match('/^https?:\/\//i', $link)) {
3916 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3917 } else {
3918 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3919 }
3920 } else {
3921 $htmllink .= dol_escape_htmltag($value);
3922 }
3923 }
3924 $htmllink .= '</div>';
3925 } else {
3926 $langs->load("errors");
3927 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3928 }
3929 return $htmllink;
3930}
3931
3941function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1)
3942{
3943 global $mysoc;
3944
3945 if (empty($profID) || empty($profIDtype)) {
3946 return '';
3947 }
3948 if (empty($countrycode)) {
3949 $countrycode = $mysoc->country_code;
3950 }
3951 $newProfID = $profID;
3952 $id = substr($profIDtype, -1);
3953 $ret = '';
3954 if (strtoupper($countrycode) == 'FR') {
3955 // France
3956 // (see https://www.economie.gouv.fr/entreprises/numeros-identification-entreprise)
3957
3958 if ($id == 1 && dol_strlen($newProfID) == 9) {
3959 // SIREN (ex: 123 123 123)
3960 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3);
3961 }
3962 if ($id == 2 && dol_strlen($newProfID) == 14) {
3963 // SIRET (ex: 123 123 123 12345)
3964 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3).' '.substr($newProfID, 9, 5);
3965 }
3966 if ($id == 3 && dol_strlen($newProfID) == 5) {
3967 // NAF/APE (ex: 69.20Z)
3968 $newProfID = substr($newProfID, 0, 2).'.'.substr($newProfID, 2, 3);
3969 }
3970 if ($profIDtype === 'VAT' && dol_strlen($newProfID) == 13) {
3971 // TVA intracommunautaire (ex: FR12 123 123 123)
3972 $newProfID = substr($newProfID, 0, 4).' '.substr($newProfID, 4, 3).' '.substr($newProfID, 7, 3).' '.substr($newProfID, 10, 3);
3973 }
3974 }
3975 if (!empty($addcpButton)) {
3976 $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3977 } else {
3978 $ret = $newProfID;
3979 }
3980 return $ret;
3981}
3982
3998function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0, $morecss = '')
3999{
4000 global $conf, $user, $langs, $mysoc, $hookmanager;
4001
4002 // Clean phone parameter
4003 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
4004 if (empty($phone)) {
4005 return '';
4006 }
4007 if (getDolGlobalString('MAIN_PHONE_SEPAR')) {
4008 $separ = getDolGlobalString('MAIN_PHONE_SEPAR');
4009 }
4010 if (empty($countrycode) && is_object($mysoc)) {
4011 $countrycode = $mysoc->country_code;
4012 }
4013
4014 // Short format for small screens
4015 if (!empty($conf->dol_optimize_smallscreen) && $separ != 'hidenum') {
4016 $separ = '';
4017 }
4018
4019 $newphone = $phone;
4020 $newphonewa = $phone;
4021 if (strtoupper($countrycode) == "FR") {
4022 // France
4023 if (dol_strlen($phone) == 10) {
4024 $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);
4025 } elseif (dol_strlen($phone) == 7) {
4026 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
4027 } elseif (dol_strlen($phone) == 9) {
4028 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
4029 } elseif (dol_strlen($phone) == 11) {
4030 $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);
4031 } elseif (dol_strlen($phone) == 12) {
4032 $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);
4033 } elseif (dol_strlen($phone) == 13) {
4034 $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);
4035 }
4036 } elseif (strtoupper($countrycode) == "CA") {
4037 if (dol_strlen($phone) == 10) {
4038 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
4039 }
4040 } elseif (strtoupper($countrycode) == "PT") {//Portugal
4041 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
4042 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
4043 }
4044 } elseif (strtoupper($countrycode) == "SR") {//Suriname
4045 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
4046 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
4047 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
4048 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
4049 }
4050 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
4051 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
4052 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
4053 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
4054 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
4055 }
4056 } elseif (strtoupper($countrycode) == "ES") {//Espagne
4057 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
4058 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
4059 }
4060 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
4061 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
4062 $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);
4063 }
4064 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
4065 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
4066 $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);
4067 }
4068 } elseif (strtoupper($countrycode) == "TR") {//Turquie
4069 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
4070 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
4071 }
4072 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
4073 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
4074 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
4075 }
4076 } elseif (strtoupper($countrycode) == "MX") {//Mexique
4077 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
4078 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
4079 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
4080 $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);
4081 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
4082 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
4083 }
4084 } elseif (strtoupper($countrycode) == "ML") {//Mali
4085 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
4086 $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);
4087 }
4088 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
4089 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
4090 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
4091 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
4092 $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);
4093 }
4094 } elseif (strtoupper($countrycode) == "MU") {
4095 //Maurice
4096 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
4097 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
4098 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
4099 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
4100 }
4101 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
4102 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
4103 $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);
4104 }
4105 } elseif (strtoupper($countrycode) == "SY") {//Syrie
4106 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
4107 $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);
4108 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
4109 $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);
4110 }
4111 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
4112 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
4113 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
4114 } elseif (dol_strlen($phone) == 13) {//ex: +971_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 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
4117 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
4118 }
4119 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
4120 if (dol_strlen($phone) == 13) {//ex: +213_ABC_DEF_GHI
4121 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
4122 }
4123 } elseif (strtoupper($countrycode) == "BE") {//Belgique
4124 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
4125 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
4126 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
4127 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
4128 }
4129 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
4130 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
4131 $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);
4132 }
4133 } elseif (strtoupper($countrycode) == "CO") {//Colombie
4134 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
4135 $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);
4136 }
4137 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
4138 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
4139 $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);
4140 }
4141 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
4142 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
4143 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
4144 }
4145 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
4146 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
4147 $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);
4148 }
4149 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
4150 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
4151 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
4152 }
4153 } elseif (strtoupper($countrycode) == "CH") {//Suisse
4154 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
4155 $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);
4156 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
4157 $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);
4158 }
4159 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
4160 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
4161 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
4162 }
4163 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
4164 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
4165 $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);
4166 }
4167 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
4168 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
4169 $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);
4170 }
4171 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
4172 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
4173 $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);
4174 }
4175 } elseif (strtoupper($countrycode) == "IT") {//Italie
4176 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
4177 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
4178 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
4179 $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);
4180 }
4181 } elseif (strtoupper($countrycode) == "AU") {
4182 //Australie
4183 if (dol_strlen($phone) == 12) {
4184 //ex: +61_A_BCDE_FGHI
4185 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
4186 }
4187 } elseif (strtoupper($countrycode) == "LU") {
4188 // Luxembourg
4189 if (dol_strlen($phone) == 10) {// fix 6 digits +352_AA_BB_CC
4190 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
4191 } elseif (dol_strlen($phone) == 11) {// fix 7 digits +352_AA_BB_CC_D
4192 $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);
4193 } elseif (dol_strlen($phone) == 12) {// fix 8 digits +352_AA_BB_CC_DD
4194 $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);
4195 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
4196 $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);
4197 }
4198 } elseif (strtoupper($countrycode) == "PE") {
4199 // Peru
4200 if (dol_strlen($phone) == 7) {// fix 7 chiffres without code AAA_BBBB
4201 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4);
4202 } elseif (dol_strlen($phone) == 9) {// mobile add code and fix 9 chiffres +51_AAA_BBB_CCC
4203 $newphonewa = '+51'.$newphone;
4204 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 10, 3);
4205 } elseif (dol_strlen($phone) == 11) {// fix 11 chiffres +511_AAA_BBBB
4206 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 8, 4);
4207 } elseif (dol_strlen($phone) == 12) {// mobile +51_AAA_BBB_CCC
4208 $newphonewa = $newphone;
4209 $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);
4210 }
4211 }
4212
4213 $newphoneastart = $newphoneaend = '';
4214 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
4215 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
4216 $newphoneastart = '<a href="tel:'.urlencode($phone).'">';
4217 $newphoneaend .= '</a>';
4218 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
4219 if (empty($user->clicktodial_loaded)) {
4220 $user->fetch_clicktodial();
4221 }
4222
4223 // Define urlmask
4224 $urlmask = getDolGlobalString('CLICKTODIAL_URL', 'ErrorClickToDialModuleNotConfigured');
4225 if (!empty($user->clicktodial_url)) {
4226 $urlmask = $user->clicktodial_url;
4227 }
4228
4229 $clicktodial_poste = (!empty($user->clicktodial_poste) ? urlencode($user->clicktodial_poste) : '');
4230 $clicktodial_login = (!empty($user->clicktodial_login) ? urlencode($user->clicktodial_login) : '');
4231 $clicktodial_password = (!empty($user->clicktodial_password) ? urlencode($user->clicktodial_password) : '');
4232 // This line is for backward compatibility @phan-suppress-next-line PhanPluginPrintfVariableFormatString
4233 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
4234 // Those lines are for substitution
4235 $substitarray = array('__PHONEFROM__' => $clicktodial_poste,
4236 '__PHONETO__' => urlencode($phone),
4237 '__LOGIN__' => $clicktodial_login,
4238 '__PASS__' => $clicktodial_password);
4239 $url = make_substitutions($url, $substitarray);
4240 if (!getDolGlobalString('CLICKTODIAL_DO_NOT_USE_AJAX_CALL')) {
4241 // Default and recommended: New method using ajax without submitting a page making a javascript history.go(-1) back
4242 $newphoneastart = '<a href="'.$url.'" class="cssforclicktodial">'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
4243 $newphoneaend = '</a>';
4244 } else {
4245 // Old method
4246 $newphoneastart = '<a href="'.$url.'"';
4247 if (getDolGlobalString('CLICKTODIAL_FORCENEWTARGET')) {
4248 $newphoneastart .= ' target="_blank" rel="noopener noreferrer"';
4249 }
4250 $newphoneastart .= '>';
4251 $newphoneaend .= '</a>';
4252 }
4253 }
4254
4255 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
4256 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
4257 $type = 'AC_TEL';
4258 $addlinktoagenda = '';
4259 if ($addlink == 'AC_FAX') {
4260 $type = 'AC_FAX';
4261 }
4262 if (getDolGlobalString('AGENDA_ADDACTIONFORPHONE')) {
4263 $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>';
4264 }
4265 if ($addlinktoagenda) {
4266 $newphone = '<span>'.$newphone.' '.$addlinktoagenda.'</span>';
4267 }
4268 }
4269 }
4270
4271 if (getDolGlobalString('CONTACT_PHONEMOBILE_SHOW_LINK_TO_WHATSAPP') && $withpicto == 'mobile') {
4272 // Link to Whatsapp
4273 $newphone .= ' <a href="https://wa.me/'.$newphonewa.'" target="_blank"';// Use api to whatasapp contacts
4274 $newphone .= '><span class="paddingright fab fa-whatsapp" style="color:#25D366;" title="WhatsApp"></span></a>';
4275 }
4276
4277 if (empty($titlealt)) {
4278 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
4279 }
4280 $rep = '';
4281
4282 if ($hookmanager) {
4283 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
4284 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
4285 $rep .= $hookmanager->resPrint;
4286 }
4287 if (empty($reshook)) {
4288 $picto = '';
4289 if ($withpicto) {
4290 if ($withpicto == 'fax') {
4291 $picto = 'phoning_fax';
4292 } elseif ($withpicto == 'phone') {
4293 $picto = 'phoning';
4294 } elseif ($withpicto == 'mobile') {
4295 $picto = 'phoning_mobile';
4296 } else {
4297 $picto = '';
4298 }
4299 }
4300 if ($adddivfloat == 1) {
4301 $rep .= '<div class="nospan float'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">';
4302 } elseif (empty($adddivfloat)) {
4303 $rep .= '<span'.($morecss ? ' class="'.$morecss.'"' : '').' style="margin-right: 10px;">';
4304 }
4305
4306 $rep .= $newphoneastart;
4307 $rep .= ($withpicto ? img_picto($titlealt, 'object_'.$picto.'.png') : '');
4308 if ($separ != 'hidenum') {
4309 $rep .= ($withpicto ? ' ' : '').$newphone;
4310 }
4311 $rep .= $newphoneaend;
4312
4313 if ($adddivfloat == 1) {
4314 $rep .= '</div>';
4315 } elseif (empty($adddivfloat)) {
4316 $rep .= '</span>';
4317 }
4318 }
4319
4320 return $rep;
4321}
4322
4330function dol_print_ip($ip, $mode = 0)
4331{
4332 global $langs;
4333
4334 $ret = '';
4335
4336 if (empty($mode)) {
4337 $ret .= $ip;
4338 }
4339
4340 if ($mode != 2) {
4341 $countrycode = dolGetCountryCodeFromIp($ip);
4342 if ($countrycode) { // If success, countrycode is us, fr, ...
4343 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
4344 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
4345 } else {
4346 $ret .= ' ('.$countrycode.')';
4347 }
4348 } else {
4349 // Nothing
4350 }
4351 }
4352
4353 return $ret;
4354}
4355
4364function getUserRemoteIP()
4365{
4366 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
4367 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
4368 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
4369 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
4370 } else {
4371 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
4372 }
4373 } else {
4374 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
4375 }
4376 } else {
4377 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
4378 }
4379 return $ip;
4380}
4381
4390function isHTTPS()
4391{
4392 $isSecure = false;
4393 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
4394 $isSecure = true;
4395 } 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') {
4396 $isSecure = true;
4397 }
4398 return $isSecure;
4399}
4400
4407function dolGetCountryCodeFromIp($ip)
4408{
4409 global $conf;
4410
4411 $countrycode = '';
4412
4413 if (!empty($conf->geoipmaxmind->enabled)) {
4414 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
4415 //$ip='24.24.24.24';
4416 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
4417 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
4418 $geoip = new DolGeoIP('country', $datafile);
4419 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
4420 $countrycode = $geoip->getCountryCodeFromIP($ip);
4421 }
4422
4423 return $countrycode;
4424}
4425
4426
4433function dol_user_country()
4434{
4435 global $conf, $langs, $user;
4436
4437 //$ret=$user->xxx;
4438 $ret = '';
4439 if (!empty($conf->geoipmaxmind->enabled)) {
4440 $ip = getUserRemoteIP();
4441 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
4442 //$ip='24.24.24.24';
4443 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
4444 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
4445 $geoip = new DolGeoIP('country', $datafile);
4446 $countrycode = $geoip->getCountryCodeFromIP($ip);
4447 $ret = $countrycode;
4448 }
4449 return $ret;
4450}
4451
4464function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
4465{
4466 global $conf, $user, $langs, $hookmanager;
4467
4468 $out = '';
4469
4470 if ($address) {
4471 if ($hookmanager) {
4472 $parameters = array('element' => $element, 'id' => $id);
4473 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
4474 $out .= $hookmanager->resPrint;
4475 }
4476 if (empty($reshook)) {
4477 if (empty($charfornl)) {
4478 $out .= nl2br($address);
4479 } else {
4480 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
4481 }
4482
4483 // TODO Remove this block, we can add this using the hook now
4484 $showgmap = $showomap = 0;
4485 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS')) {
4486 $showgmap = 1;
4487 }
4488 if ($element == 'contact' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_CONTACTS')) {
4489 $showgmap = 1;
4490 }
4491 if ($element == 'member' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_MEMBERS')) {
4492 $showgmap = 1;
4493 }
4494 if ($element == 'user' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_USERS')) {
4495 $showgmap = 1;
4496 }
4497 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS')) {
4498 $showomap = 1;
4499 }
4500 if ($element == 'contact' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_CONTACTS')) {
4501 $showomap = 1;
4502 }
4503 if ($element == 'member' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_MEMBERS')) {
4504 $showomap = 1;
4505 }
4506 if ($element == 'user' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_USERS')) {
4507 $showomap = 1;
4508 }
4509 if ($showgmap) {
4510 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
4511 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4512 }
4513 if ($showomap) {
4514 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
4515 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4516 }
4517 }
4518 }
4519 if ($noprint) {
4520 return $out;
4521 } else {
4522 print $out;
4523 }
4524}
4525
4526
4536function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
4537{
4538 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
4539 return true;
4540 }
4541 if ($acceptuserkey && $address == '__USER_EMAIL__') {
4542 return true;
4543 }
4544 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
4545 return true;
4546 }
4547
4548 return false;
4549}
4550
4560function isValidMXRecord($domain)
4561{
4562 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
4563 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
4564 return 0;
4565 }
4566 if (function_exists('getmxrr')) {
4567 $mxhosts = array();
4568 $weight = array();
4569 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
4570 if (count($mxhosts) > 1) {
4571 return 1;
4572 }
4573 if (count($mxhosts) == 1 && !in_array((string) $mxhosts[0], array('', '.'))) {
4574 return 1;
4575 }
4576
4577 return 0;
4578 }
4579 }
4580
4581 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4582 return -1;
4583}
4584
4592function isValidPhone($phone)
4593{
4594 return true;
4595}
4596
4597
4607function dolGetFirstLetters($s, $nbofchar = 1)
4608{
4609 $ret = '';
4610 $tmparray = explode(' ', $s);
4611 foreach ($tmparray as $tmps) {
4612 $ret .= dol_substr($tmps, 0, $nbofchar);
4613 }
4614
4615 return $ret;
4616}
4617
4618
4626function dol_strlen($string, $stringencoding = 'UTF-8')
4627{
4628 if (is_null($string)) {
4629 return 0;
4630 }
4631
4632 if (function_exists('mb_strlen')) {
4633 return mb_strlen($string, $stringencoding);
4634 } else {
4635 return strlen($string);
4636 }
4637}
4638
4649function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4650{
4651 global $langs;
4652
4653 if (empty($stringencoding)) {
4654 $stringencoding = (empty($langs) ? 'UTF-8' : $langs->charset_output);
4655 }
4656
4657 $ret = '';
4658 if (empty($trunconbytes)) {
4659 if (function_exists('mb_substr')) {
4660 $ret = mb_substr($string, $start, $length, $stringencoding);
4661 } else {
4662 $ret = substr($string, $start, $length);
4663 }
4664 } else {
4665 if (function_exists('mb_strcut')) {
4666 $ret = mb_strcut($string, $start, $length, $stringencoding);
4667 } else {
4668 $ret = substr($string, $start, $length);
4669 }
4670 }
4671 return $ret;
4672}
4673
4674
4688function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4689{
4690 global $conf;
4691
4692 if (empty($size) || getDolGlobalString('MAIN_DISABLE_TRUNC')) {
4693 return $string;
4694 }
4695
4696 if (empty($stringencoding)) {
4697 $stringencoding = 'UTF-8';
4698 }
4699 // reduce for small screen
4700 if (!empty($conf->dol_optimize_smallscreen) && $conf->dol_optimize_smallscreen == 1 && $display == 1) {
4701 $size = round($size / 3);
4702 }
4703
4704 // We go always here
4705 if ($trunc == 'right') {
4706 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4707 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4708 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4709 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4710 } else {
4711 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4712 return $string;
4713 }
4714 } elseif ($trunc == 'middle') {
4715 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4716 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4717 $size1 = round($size / 2);
4718 $size2 = round($size / 2);
4719 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4720 } else {
4721 return $string;
4722 }
4723 } elseif ($trunc == 'left') {
4724 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4725 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4726 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4727 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4728 } else {
4729 return $string;
4730 }
4731 } elseif ($trunc == 'wrap') {
4732 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4733 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4734 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4735 } else {
4736 return $string;
4737 }
4738 } else {
4739 return 'BadParam3CallingDolTrunc';
4740 }
4741}
4742
4750function getPictoForType($key, $morecss = '')
4751{
4752 // Set array with type -> picto
4753 $type2picto = array(
4754 'varchar' => 'font',
4755 'text' => 'font',
4756 'html' => 'code',
4757 'int' => 'sort-numeric-down',
4758 'double' => 'sort-numeric-down',
4759 'price' => 'currency',
4760 'pricecy' => 'multicurrency',
4761 'password' => 'key',
4762 'boolean' => 'check-square',
4763 'date' => 'calendar',
4764 'datetime' => 'calendar',
4765 'phone' => 'phone',
4766 'mail' => 'email',
4767 'url' => 'url',
4768 'ip' => 'country',
4769 'select' => 'list',
4770 'sellist' => 'list',
4771 'radio' => 'check-circle',
4772 'checkbox' => 'list',
4773 'chkbxlst' => 'list',
4774 'link' => 'link',
4775 'icon' => "question",
4776 'point' => "country",
4777 'multipts' => 'country',
4778 'linestrg' => "country",
4779 'polygon' => "country",
4780 'separate' => 'minus'
4781 );
4782
4783 if (!empty($type2picto[$key])) {
4784 return img_picto('', $type2picto[$key], 'class="pictofixedwidth'.($morecss ? ' '.$morecss : '').'"');
4785 }
4786
4787 return img_picto('', 'generic', 'class="pictofixedwidth'.($morecss ? ' '.$morecss : '').'"');
4788}
4789
4790
4812function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4813{
4814 global $conf;
4815
4816 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4817 $url = DOL_URL_ROOT;
4818 $theme = isset($conf->theme) ? $conf->theme : null;
4819 $path = 'theme/'.$theme;
4820 if (empty($picto)) {
4821 $picto = 'generic';
4822 }
4823
4824 // Define fullpathpicto to use into src
4825 if ($pictoisfullpath) {
4826 // Clean parameters
4827 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4828 $picto .= '.png';
4829 }
4830 $fullpathpicto = $picto;
4831 $reg = array();
4832 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4833 $morecss .= ($morecss ? ' ' : '').$reg[1];
4834 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4835 }
4836 } else {
4837 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', (is_null($picto) ? '' : $picto));
4838 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4839 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4840
4841 if (strpos($pictowithouttext, 'fontawesome_') === 0 || strpos($pictowithouttext, 'fa-') === 0) {
4842 // This is a font awesome image 'fontawesome_xxx' or 'fa-xxx'
4843 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4844 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4845
4846 // Compatibility with old fontawesome versions
4847 if ($pictowithouttext == 'file-o') {
4848 $pictowithouttext = 'file';
4849 }
4850
4851 $pictowithouttextarray = explode('_', $pictowithouttext);
4852 $marginleftonlyshort = 0;
4853
4854 if (!empty($pictowithouttextarray[1])) {
4855 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4856 $fakey = 'fa-'.$pictowithouttextarray[0];
4857 $faprefix = empty($pictowithouttextarray[1]) ? 'fas' : $pictowithouttextarray[1];
4858 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4859 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4860 } else {
4861 $fakey = 'fa-'.$pictowithouttext;
4862 $faprefix = 'fas';
4863 $facolor = '';
4864 $fasize = '';
4865 }
4866
4867 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4868 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4869 $morestyle = '';
4870 $reg = array();
4871 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4872 $morecss .= ($morecss ? ' ' : '').$reg[1];
4873 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4874 }
4875 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4876 $morestyle = $reg[1];
4877 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4878 }
4879 $moreatt = trim($moreatt);
4880
4881 $enabledisablehtml = '<span class="'.$faprefix.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4882 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4883 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4884 $enabledisablehtml .= $titlealt;
4885 }*/
4886 $enabledisablehtml .= '</span>';
4887
4888 return $enabledisablehtml;
4889 }
4890
4891 if (empty($srconly) && in_array($pictowithouttext, array(
4892 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4893 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'ai', 'angle-double-down', 'angle-double-up', 'asset',
4894 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bom', 'bookcal', 'bookmark', 'briefcase-medical', 'bug', 'building',
4895 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4896 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'code', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4897 'check-circle', 'check-square', 'circle', 'stop-circle', 'currency', 'multicurrency',
4898 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top',
4899 'chevron-double-left', 'chevron-double-right', 'chevron-double-down', 'chevron-double-top',
4900 'commercial', 'companies',
4901 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4902 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4903 'filter', 'file', 'file-o', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus', 'font',
4904 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4905 'hands-helping', 'help', 'holiday',
4906 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4907 'key', 'knowledgemanagement',
4908 'label', 'language', 'layout', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4909 'margin', 'map-marker-alt', 'member', 'meeting', 'minus', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4910 'off', 'on', 'order',
4911 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4912 'stock', 'resize', 'service', 'stats',
4913 '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',
4914 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4915 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4916 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4917 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4918 'technic', 'ticket',
4919 'error', 'warning',
4920 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4921 'shapes', 'skill', 'square', 'sort-numeric-down', 'status', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4922 'terminal', 'tick', 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda', 'trip',
4923 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4924 'conferenceorbooth', 'eventorganization',
4925 'stamp', 'signature',
4926 'webportal'
4927 ))) {
4928 $fakey = $pictowithouttext;
4929 $facolor = '';
4930 $fasize = '';
4931 $fa = getDolGlobalString('MAIN_FONTAWESOME_ICON_STYLE', 'fas');
4932 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'))) {
4933 $fa = 'far';
4934 }
4935 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4936 $fa = 'fab';
4937 }
4938
4939 $arrayconvpictotofa = array(
4940 'account' => 'university', 'accounting_account' => 'clipboard-list', 'accountline' => 'receipt', 'accountancy' => 'search-dollar', 'action' => 'calendar-alt', 'add' => 'plus-circle', 'address' => 'address-book', 'ai' => 'magic',
4941 'asset' => 'money-check-alt', 'autofill' => 'fill',
4942 'bank_account' => 'university',
4943 'bill' => 'file-invoice-dollar', 'billa' => 'file-excel', 'billr' => 'file-invoice-dollar', 'billd' => 'file-medical',
4944 'bookcal' => 'calendar-check',
4945 'supplier_invoice' => 'file-invoice-dollar', 'supplier_invoicea' => 'file-excel', 'supplier_invoicer' => 'file-invoice-dollar', 'supplier_invoiced' => 'file-medical',
4946 'bom' => 'shapes',
4947 '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',
4948 'chevron-double-left' => 'angle-double-left', 'chevron-double-right' => 'angle-double-right', 'chevron-double-down' => 'angle-double-down', 'chevron-double-top' => 'angle-double-up',
4949 'donation' => 'file-alt', 'dynamicprice' => 'hand-holding-usd',
4950 'setup' => 'cog', 'companies' => 'building', 'products' => 'cube', 'commercial' => 'suitcase', 'invoicing' => 'coins',
4951 'accounting' => 'search-dollar', 'category' => 'tag', 'dollyrevert' => 'dolly',
4952 'file-o' => 'file', 'generate' => 'plus-square', 'hrm' => 'user-tie', 'incoterm' => 'truck-loading',
4953 'margin' => 'calculator', 'members' => 'user-friends', 'ticket' => 'ticket-alt', 'globe' => 'external-link-alt', 'lot' => 'barcode',
4954 'email' => 'at', 'establishment' => 'building', 'edit' => 'pencil-alt', 'entity' => 'globe',
4955 'graph' => 'chart-line', 'grip_title' => 'arrows-alt', 'grip' => 'arrows-alt', 'help' => 'question-circle',
4956 'generic' => 'file', 'holiday' => 'umbrella-beach',
4957 'info' => 'info-circle', 'inventory' => 'boxes', 'intracommreport' => 'globe-europe', 'jobprofile' => 'cogs',
4958 'knowledgemanagement' => 'ticket-alt', 'label' => 'layer-group', 'layout' => 'columns', 'line' => 'bars', 'loan' => 'money-bill-alt',
4959 'member' => 'user-alt', 'meeting' => 'chalkboard-teacher', 'mrp' => 'cubes', 'next' => 'arrow-alt-circle-right',
4960 'trip' => 'wallet', 'expensereport' => 'wallet', 'group' => 'users', 'movement' => 'people-carry',
4961 'sign-out' => 'sign-out-alt',
4962 'switch_off' => 'toggle-off', 'switch_on' => 'toggle-on', 'switch_on_warning' => 'toggle-on', 'switch_on_red' => 'toggle-on', 'check' => 'check', 'bookmark' => 'star',
4963 'bank' => 'university', 'close_title' => 'times', 'delete' => 'trash', 'filter' => 'filter',
4964 'list-alt' => 'list-alt', 'calendarlist' => 'bars', 'calendar' => 'calendar-alt', 'calendarmonth' => 'calendar-alt', 'calendarweek' => 'calendar-week', 'calendarday' => 'calendar-day', 'calendarperuser' => 'table',
4965 'intervention' => 'ambulance', 'invoice' => 'file-invoice-dollar', 'order' => 'file-invoice',
4966 'error' => 'exclamation-triangle', 'warning' => 'exclamation-triangle',
4967 'other' => 'square',
4968 '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',
4969 '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',
4970 'recent' => 'check-square', 'reception' => 'dolly', 'recruitmentjobposition' => 'id-card-alt', 'recruitmentcandidature' => 'id-badge',
4971 'resize' => 'crop', 'supplier_order' => 'dol-order_supplier', 'supplier_proposal' => 'file-signature',
4972 'refresh' => 'redo', 'region' => 'map-marked', 'replacement' => 'exchange-alt', 'resource' => 'laptop-house', 'recurring' => 'history',
4973 'service' => 'concierge-bell',
4974 'skill' => 'shapes', 'state' => 'map-marked-alt', 'security' => 'key', 'salary' => 'wallet', 'shipment' => 'dolly', 'stock' => 'box-open', 'stats' => 'chart-bar', 'split' => 'code-branch',
4975 'status' => 'stop-circle',
4976 'stripe' => 'stripe-s', 'supplier' => 'building',
4977 'technic' => 'cogs', 'tick' => 'check', 'timespent' => 'clock', 'title_setup' => 'tools', 'title_accountancy' => 'money-check-alt', 'title_bank' => 'university', 'title_hrm' => 'umbrella-beach',
4978 'title_agenda' => 'calendar-alt',
4979 'uncheck' => 'times', 'uparrow' => 'share', 'url' => 'external-link-alt', 'vat' => 'money-check-alt', 'vcard' => 'arrow-alt-circle-down',
4980 'jabber' => 'comment-o',
4981 'website' => 'globe-americas', 'workstation' => 'pallet', 'webhook' => 'bullseye', 'world' => 'globe', 'private' => 'user-lock',
4982 'conferenceorbooth' => 'chalkboard-teacher', 'eventorganization' => 'project-diagram',
4983 'webportal' => 'door-open'
4984 );
4985 if ($conf->currency == 'EUR') {
4986 $arrayconvpictotofa['currency'] = 'euro-sign';
4987 $arrayconvpictotofa['multicurrency'] = 'dollar-sign';
4988 } else {
4989 $arrayconvpictotofa['currency'] = 'dollar-sign';
4990 $arrayconvpictotofa['multicurrency'] = 'euro-sign';
4991 }
4992 if ($pictowithouttext == 'off') {
4993 $fakey = 'fa-square';
4994 $fasize = '1.3em';
4995 } elseif ($pictowithouttext == 'on') {
4996 $fakey = 'fa-check-square';
4997 $fasize = '1.3em';
4998 } elseif ($pictowithouttext == 'listlight') {
4999 $fakey = 'fa-download';
5000 $marginleftonlyshort = 1;
5001 } elseif ($pictowithouttext == 'printer') {
5002 $fakey = 'fa-print';
5003 $fasize = '1.2em';
5004 } elseif ($pictowithouttext == 'note') {
5005 $fakey = 'fa-sticky-note';
5006 $marginleftonlyshort = 1;
5007 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
5008 $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');
5009 $fakey = 'fa-'.$convertarray[$pictowithouttext];
5010 if (preg_match('/selected/', $pictowithouttext)) {
5011 $facolor = '#888';
5012 }
5013 $marginleftonlyshort = 1;
5014 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
5015 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
5016 } else {
5017 $fakey = 'fa-'.$pictowithouttext;
5018 }
5019
5020 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment', 'reception'))) {
5021 $morecss .= ' em092';
5022 }
5023 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
5024 $morecss .= ' em088';
5025 }
5026 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
5027 $morecss .= ' em080';
5028 }
5029
5030 // Define $marginleftonlyshort
5031 $arrayconvpictotomarginleftonly = array(
5032 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
5033 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
5034 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
5035 );
5036 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
5037 $marginleftonlyshort = 0;
5038 }
5039
5040 // Add CSS
5041 $arrayconvpictotomorcess = array(
5042 'action' => 'infobox-action', 'account' => 'infobox-bank_account', 'accounting_account' => 'infobox-bank_account', 'accountline' => 'infobox-bank_account', 'accountancy' => 'infobox-bank_account', 'asset' => 'infobox-bank_account',
5043 'bank_account' => 'infobox-bank_account',
5044 'bill' => 'infobox-commande', 'billa' => 'infobox-commande', 'billr' => 'infobox-commande', 'billd' => 'infobox-commande',
5045 'bookcal' => 'infobox-action',
5046 'margin' => 'infobox-bank_account', 'conferenceorbooth' => 'infobox-project',
5047 'cash-register' => 'infobox-bank_account', 'contract' => 'infobox-contrat', 'check' => 'font-status4', 'collab' => 'infobox-action', 'conversation' => 'infobox-contrat',
5048 'donation' => 'infobox-commande', 'dolly' => 'infobox-commande', 'dollyrevert' => 'flip infobox-order_supplier',
5049 'ecm' => 'infobox-action', 'eventorganization' => 'infobox-project',
5050 'hrm' => 'infobox-adherent', 'group' => 'infobox-adherent', 'intervention' => 'infobox-contrat',
5051 'incoterm' => 'infobox-supplier_proposal',
5052 'currency' => 'infobox-bank_account', 'multicurrency' => 'infobox-bank_account',
5053 'members' => 'infobox-adherent', 'member' => 'infobox-adherent', 'money-bill-alt' => 'infobox-bank_account',
5054 'order' => 'infobox-commande',
5055 'user' => 'infobox-adherent', 'users' => 'infobox-adherent',
5056 'error' => 'pictoerror', 'warning' => 'pictowarning', 'switch_on' => 'font-status4', 'switch_on_warning' => 'font-status4 warning', 'switch_on_red' => 'font-status8',
5057 'holiday' => 'infobox-holiday', 'info' => 'opacityhigh', 'invoice' => 'infobox-commande',
5058 'knowledgemanagement' => 'infobox-contrat rotate90', 'loan' => 'infobox-bank_account',
5059 'payment' => 'infobox-bank_account', 'payment_vat' => 'infobox-bank_account', 'poll' => 'infobox-adherent', 'pos' => 'infobox-bank_account', 'project' => 'infobox-project', 'projecttask' => 'infobox-project',
5060 'propal' => 'infobox-propal', 'proposal' => 'infobox-propal','private' => 'infobox-project',
5061 'reception' => 'flip infobox-order_supplier', 'recruitmentjobposition' => 'infobox-adherent', 'recruitmentcandidature' => 'infobox-adherent',
5062 'resource' => 'infobox-action',
5063 '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',
5064 'supplier' => 'infobox-order_supplier', 'supplier_order' => 'infobox-order_supplier', 'supplier_proposal' => 'infobox-supplier_proposal',
5065 'ticket' => 'infobox-contrat', 'title_accountancy' => 'infobox-bank_account', 'title_hrm' => 'infobox-holiday', 'expensereport' => 'infobox-expensereport', 'trip' => 'infobox-expensereport', 'title_agenda' => 'infobox-action',
5066 'vat' => 'infobox-bank_account',
5067 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
5068 'list-alt' => 'imgforviewmode', 'calendar' => 'imgforviewmode', 'calendarweek' => 'imgforviewmode', 'calendarmonth' => 'imgforviewmode', 'calendarday' => 'imgforviewmode', 'calendarperuser' => 'imgforviewmode'
5069 );
5070 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
5071 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
5072 }
5073
5074 // Define $color
5075 $arrayconvpictotocolor = array(
5076 'address' => '#6c6aa8', 'building' => '#6c6aa8', 'bom' => '#a69944',
5077 'clone' => '#999', 'cog' => '#999', 'companies' => '#6c6aa8', 'company' => '#6c6aa8', 'contact' => '#6c6aa8', 'cron' => '#555',
5078 'dynamicprice' => '#a69944',
5079 'edit' => '#444', 'note' => '#999', 'error' => '', 'help' => '#bbb', 'listlight' => '#999', 'language' => '#555',
5080 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
5081 'lock' => '#ddd', 'lot' => '#a69944',
5082 'map-marker-alt' => '#aaa', 'mrp' => '#a69944', 'product' => '#a69944', 'service' => '#a69944', 'inventory' => '#a69944', 'stock' => '#a69944', 'movement' => '#a69944',
5083 'other' => '#ddd', 'world' => '#986c6a',
5084 'partnership' => '#6c6aa8', 'playdisabled' => '#ccc', 'printer' => '#444', 'projectpub' => '#986c6a', 'resize' => '#444', 'rss' => '#cba',
5085 //'shipment'=>'#a69944',
5086 'security' => '#999', 'square' => '#888', 'stop-circle' => '#888', 'stats' => '#444', 'switch_off' => '#999',
5087 'technic' => '#999', 'tick' => '#282', 'timespent' => '#555',
5088 'uncheck' => '#800', 'uparrow' => '#555', 'user-cog' => '#999', 'country' => '#aaa', 'globe-americas' => '#aaa', 'region' => '#aaa', 'state' => '#aaa',
5089 'website' => '#304', 'workstation' => '#a69944'
5090 );
5091 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
5092 $facolor = $arrayconvpictotocolor[$pictowithouttext];
5093 }
5094
5095 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
5096 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
5097 $morestyle = '';
5098 $reg = array();
5099 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
5100 $morecss .= ($morecss ? ' ' : '').$reg[1];
5101 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
5102 }
5103 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
5104 $morestyle = $reg[1];
5105 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
5106 }
5107 $moreatt = trim($moreatt);
5108
5109 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
5110 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
5111 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
5112 $enabledisablehtml .= $titlealt;
5113 }*/
5114 $enabledisablehtml .= '</span>';
5115
5116 return $enabledisablehtml;
5117 }
5118
5119 if (getDolGlobalString('MAIN_OVERWRITE_THEME_PATH')) {
5120 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_PATH') . '/theme/'.$theme; // If the theme does not have the same name as the module
5121 } elseif (getDolGlobalString('MAIN_OVERWRITE_THEME_RES')) {
5122 $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
5123 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
5124 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
5125 }
5126
5127 // If we ask an image into $url/$mymodule/img (instead of default path)
5128 $regs = array();
5129 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
5130 $picto = $regs[1];
5131 $path = $regs[2]; // $path is $mymodule
5132 }
5133
5134 // Clean parameters
5135 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
5136 $picto .= '.png';
5137 }
5138 // If alt path are defined, define url where img file is, according to physical path
5139 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
5140 foreach ($conf->file->dol_document_root as $type => $dirroot) {
5141 if ($type == 'main') {
5142 continue;
5143 }
5144 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommended
5145 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
5146 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
5147 break;
5148 }
5149 }
5150
5151 // $url is '' or '/custom', $path is current theme or
5152 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
5153 }
5154
5155 if ($srconly) {
5156 return $fullpathpicto;
5157 }
5158
5159 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
5160 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
5161}
5162
5176function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $srconly = 0, $notitle = 0)
5177{
5178 if (strpos($picto, '^') === 0) {
5179 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
5180 } else {
5181 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
5182 }
5183}
5184
5196function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
5197{
5198 global $conf;
5199
5200 if (is_numeric($picto)) {
5201 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
5202 //$picto = $leveltopicto[$picto];
5203 return '<i class="fa fa-weather-level'.$picto.'"></i>';
5204 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
5205 $picto .= '.png';
5206 }
5207
5208 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
5209
5210 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
5211}
5212
5224function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
5225{
5226 global $conf;
5227
5228 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
5229 $picto .= '.png';
5230 }
5231
5232 if ($pictoisfullpath) {
5233 $path = $picto;
5234 } else {
5235 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
5236
5237 if (getDolGlobalInt('MAIN_MODULE_CAN_OVERWRITE_COMMONICONS')) {
5238 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
5239
5240 if (file_exists($themepath)) {
5241 $path = $themepath;
5242 }
5243 }
5244 }
5245
5246 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
5247}
5248
5262function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
5263{
5264 global $langs;
5265
5266 if (empty($titlealt) || $titlealt == 'default') {
5267 if ($numaction == '-1' || $numaction == 'ST_NO') {
5268 $numaction = -1;
5269 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
5270 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
5271 $numaction = 0;
5272 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
5273 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
5274 $numaction = 1;
5275 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
5276 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
5277 $numaction = 2;
5278 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
5279 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
5280 $numaction = 3;
5281 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
5282 } else {
5283 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
5284 $numaction = 0;
5285 }
5286 }
5287 if (!is_numeric($numaction)) {
5288 $numaction = 0;
5289 }
5290
5291 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
5292}
5293
5301function img_pdf($titlealt = 'default', $size = 3)
5302{
5303 global $langs;
5304
5305 if ($titlealt == 'default') {
5306 $titlealt = $langs->trans('Show');
5307 }
5308
5309 return img_picto($titlealt, 'pdf'.$size.'.png');
5310}
5311
5319function img_edit_add($titlealt = 'default', $other = '')
5320{
5321 global $langs;
5322
5323 if ($titlealt == 'default') {
5324 $titlealt = $langs->trans('Add');
5325 }
5326
5327 return img_picto($titlealt, 'edit_add.png', $other);
5328}
5336function img_edit_remove($titlealt = 'default', $other = '')
5337{
5338 global $langs;
5339
5340 if ($titlealt == 'default') {
5341 $titlealt = $langs->trans('Remove');
5342 }
5343
5344 return img_picto($titlealt, 'edit_remove.png', $other);
5345}
5346
5355function img_edit($titlealt = 'default', $float = 0, $other = '')
5356{
5357 global $langs;
5358
5359 if ($titlealt == 'default') {
5360 $titlealt = $langs->trans('Modify');
5361 }
5362
5363 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
5364}
5365
5374function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
5375{
5376 global $langs;
5377
5378 if ($titlealt == 'default') {
5379 $titlealt = $langs->trans('View');
5380 }
5381
5382 $moreatt = ($float ? 'style="float: right" ' : '').$other;
5383
5384 return img_picto($titlealt, 'eye', $moreatt);
5385}
5386
5395function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
5396{
5397 global $langs;
5398
5399 if ($titlealt == 'default') {
5400 $titlealt = $langs->trans('Delete');
5401 }
5402
5403 return img_picto($titlealt, 'delete.png', $other, 0, 0, 0, '', $morecss);
5404}
5405
5413function img_printer($titlealt = "default", $other = '')
5414{
5415 global $langs;
5416 if ($titlealt == "default") {
5417 $titlealt = $langs->trans("Print");
5418 }
5419 return img_picto($titlealt, 'printer.png', $other);
5420}
5421
5429function img_split($titlealt = 'default', $other = 'class="pictosplit"')
5430{
5431 global $langs;
5432
5433 if ($titlealt == 'default') {
5434 $titlealt = $langs->trans('Split');
5435 }
5436
5437 return img_picto($titlealt, 'split.png', $other);
5438}
5439
5447function img_help($usehelpcursor = 1, $usealttitle = 1)
5448{
5449 global $langs;
5450
5451 if ($usealttitle) {
5452 if (is_string($usealttitle)) {
5453 $usealttitle = dol_escape_htmltag($usealttitle);
5454 } else {
5455 $usealttitle = $langs->trans('Info');
5456 }
5457 }
5458
5459 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
5460}
5461
5468function img_info($titlealt = 'default')
5469{
5470 global $langs;
5471
5472 if ($titlealt == 'default') {
5473 $titlealt = $langs->trans('Informations');
5474 }
5475
5476 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
5477}
5478
5487function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
5488{
5489 global $langs;
5490
5491 if ($titlealt == 'default') {
5492 $titlealt = $langs->trans('Warning');
5493 }
5494
5495 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
5496 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
5497}
5498
5505function img_error($titlealt = 'default')
5506{
5507 global $langs;
5508
5509 if ($titlealt == 'default') {
5510 $titlealt = $langs->trans('Error');
5511 }
5512
5513 return img_picto($titlealt, 'error.png');
5514}
5515
5523function img_next($titlealt = 'default', $moreatt = '')
5524{
5525 global $langs;
5526
5527 if ($titlealt == 'default') {
5528 $titlealt = $langs->trans('Next');
5529 }
5530
5531 //return img_picto($titlealt, 'next.png', $moreatt);
5532 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5533}
5534
5542function img_previous($titlealt = 'default', $moreatt = '')
5543{
5544 global $langs;
5545
5546 if ($titlealt == 'default') {
5547 $titlealt = $langs->trans('Previous');
5548 }
5549
5550 //return img_picto($titlealt, 'previous.png', $moreatt);
5551 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5552}
5553
5562function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
5563{
5564 global $langs;
5565
5566 if ($titlealt == 'default') {
5567 $titlealt = $langs->trans('Down');
5568 }
5569
5570 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
5571}
5572
5581function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
5582{
5583 global $langs;
5584
5585 if ($titlealt == 'default') {
5586 $titlealt = $langs->trans('Up');
5587 }
5588
5589 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
5590}
5591
5600function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
5601{
5602 global $langs;
5603
5604 if ($titlealt == 'default') {
5605 $titlealt = $langs->trans('Left');
5606 }
5607
5608 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
5609}
5610
5619function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
5620{
5621 global $langs;
5622
5623 if ($titlealt == 'default') {
5624 $titlealt = $langs->trans('Right');
5625 }
5626
5627 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
5628}
5629
5637function img_allow($allow, $titlealt = 'default')
5638{
5639 global $langs;
5640
5641 if ($titlealt == 'default') {
5642 $titlealt = $langs->trans('Active');
5643 }
5644
5645 if ($allow == 1) {
5646 return img_picto($titlealt, 'tick.png');
5647 }
5648
5649 return '-';
5650}
5651
5659function img_credit_card($brand, $morecss = null)
5660{
5661 if (is_null($morecss)) {
5662 $morecss = 'fa-2x';
5663 }
5664
5665 if ($brand == 'visa' || $brand == 'Visa') {
5666 $brand = 'cc-visa';
5667 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5668 $brand = 'cc-mastercard';
5669 } elseif ($brand == 'amex' || $brand == 'American Express') {
5670 $brand = 'cc-amex';
5671 } elseif ($brand == 'discover' || $brand == 'Discover') {
5672 $brand = 'cc-discover';
5673 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5674 $brand = 'cc-jcb';
5675 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5676 $brand = 'cc-diners-club';
5677 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5678 $brand = 'credit-card';
5679 }
5680
5681 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5682}
5683
5692function img_mime($file, $titlealt = '', $morecss = '')
5693{
5694 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5695
5696 $mimetype = dol_mimetype($file, '', 1);
5697 $mimeimg = dol_mimetype($file, '', 2);
5698 $mimefa = dol_mimetype($file, '', 4);
5699
5700 if (empty($titlealt)) {
5701 $titlealt = 'Mime type: '.$mimetype;
5702 }
5703
5704 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5705 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5706}
5707
5708
5716function img_search($titlealt = 'default', $other = '')
5717{
5718 global $langs;
5719
5720 if ($titlealt == 'default') {
5721 $titlealt = $langs->trans('Search');
5722 }
5723
5724 $img = img_picto($titlealt, 'search.png', $other, 0, 1);
5725
5726 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5727 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5728
5729 return $input;
5730}
5731
5739function img_searchclear($titlealt = 'default', $other = '')
5740{
5741 global $langs;
5742
5743 if ($titlealt == 'default') {
5744 $titlealt = $langs->trans('Search');
5745 }
5746
5747 $img = img_picto($titlealt, 'searchclear.png', $other, 0, 1);
5748
5749 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5750 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5751
5752 return $input;
5753}
5754
5767function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '', $picto = '')
5768{
5769 global $conf, $langs;
5770
5771 if ($infoonimgalt) {
5772 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5773 } else {
5774 if (empty($conf->use_javascript_ajax)) {
5775 $textfordropdown = '';
5776 }
5777
5778 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5779 $fa = 'info-circle';
5780 if ($picto == 'warning') {
5781 $fa = 'exclamation-triangle';
5782 }
5783 $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> ';
5784 $result .= dol_escape_htmltag($text, 1, 0, 'div,span,b,br,a');
5785 $result .= ($nodiv ? '' : '</div>');
5786
5787 if ($textfordropdown) {
5788 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5789 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5790 jQuery(document).ready(function() {
5791 jQuery(".'.$class.'text").click(function() {
5792 console.log("toggle text");
5793 jQuery(".'.$class.'").toggle();
5794 });
5795 });
5796 </script>';
5797
5798 $result = $tmpresult.$result;
5799 }
5800 }
5801
5802 return $result;
5803}
5804
5805
5817function dol_print_error($db = null, $error = '', $errors = null)
5818{
5819 global $conf, $langs, $user, $argv;
5820 global $dolibarr_main_prod;
5821
5822 $out = '';
5823 $syslog = '';
5824
5825 // If error occurs before the $lang object was loaded
5826 if (!$langs) {
5827 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5828 $langs = new Translate('', $conf);
5829 $langs->load("main");
5830 }
5831
5832 // Load translation files required by the error messages
5833 $langs->loadLangs(array('main', 'errors'));
5834
5835 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5836 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5837 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5838 $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";
5839 }
5840 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5841
5842 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5843 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5844 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5845 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5846 }
5847 if ($user instanceof User) {
5848 $out .= "<b>".$langs->trans("Login").":</b> ".$user->login."<br>\n";
5849 }
5850 if (function_exists("phpversion")) {
5851 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5852 }
5853 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5854 if (function_exists("php_uname")) {
5855 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5856 }
5857 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5858 $out .= "<br>\n";
5859 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5860 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5861 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5862 $out .= "<br>\n";
5863 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5864 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5865 } else { // Mode CLI
5866 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5867 $syslog .= "pid=".dol_getmypid();
5868 }
5869
5870 if (!empty($conf->modules)) {
5871 $out .= "<b>".$langs->trans("Modules").":</b> ".implode(', ', $conf->modules)."<br>\n";
5872 }
5873
5874 if (is_object($db)) {
5875 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5876 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5877 $lastqueryerror = $db->lastqueryerror();
5878 if (!utf8_check($lastqueryerror)) {
5879 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5880 }
5881 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5882 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5883 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5884 $out .= "<br>\n";
5885 } else { // Mode CLI
5886 // No dol_escape_htmltag for output, we are in CLI mode
5887 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5888 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5889 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5890 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5891 }
5892 $syslog .= ", sql=".$db->lastquery();
5893 $syslog .= ", db_error=".$db->lasterror();
5894 }
5895
5896 if ($error || $errors) {
5897 // Merge all into $errors array
5898 if (is_array($error) && is_array($errors)) {
5899 $errors = array_merge($error, $errors);
5900 } elseif (is_array($error)) { // deprecated, use second parameters
5901 $errors = $error;
5902 } elseif (is_array($errors) && !empty($error)) {
5903 $errors = array_merge(array($error), $errors);
5904 } elseif (!empty($error)) {
5905 $errors = array_merge(array($error), array($errors));
5906 }
5907
5908 $langs->load("errors");
5909
5910 foreach ($errors as $msg) {
5911 if (empty($msg)) {
5912 continue;
5913 }
5914 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5915 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5916 } else { // Mode CLI
5917 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5918 }
5919 $syslog .= ", msg=".$msg;
5920 }
5921 }
5922 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5923 xdebug_print_function_stack();
5924 $out .= '<b>XDebug information:</b>'."<br>\n";
5925 $out .= 'File: '.xdebug_call_file()."<br>\n";
5926 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5927 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5928 $out .= "<br>\n";
5929 }
5930
5931 // Return a http header with error code if possible
5932 if (!headers_sent()) {
5933 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5934 top_httphead();
5935 }
5936 //http_response_code(500); // If we use 500, message is not output with some command line tools
5937 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
5938 }
5939
5940 if (empty($dolibarr_main_prod)) {
5941 print $out;
5942 } else {
5943 if (empty($langs->defaultlang)) {
5944 $langs->setDefaultLang();
5945 }
5946 $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.
5947 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5948 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";
5949 print $langs->trans("DolibarrHasDetectedError").'. ';
5950 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5951 if (!defined("MAIN_CORE_ERROR")) {
5952 define("MAIN_CORE_ERROR", 1);
5953 }
5954 }
5955
5956 dol_syslog("Error ".$syslog, LOG_ERR);
5957}
5958
5969function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5970{
5971 global $langs;
5972
5973 if (empty($email)) {
5974 $email = getDolGlobalString('MAIN_INFO_SOCIETE_MAIL');
5975 }
5976
5977 $langs->load("errors");
5978 $now = dol_now();
5979
5980 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5981 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5982 if ($errormessage) {
5983 print '<br><br>'.$errormessage;
5984 }
5985 if (is_array($errormessages) && count($errormessages)) {
5986 foreach ($errormessages as $mesgtoshow) {
5987 print '<br><br>'.$mesgtoshow;
5988 }
5989 }
5990 print '</div></div>';
5991}
5992
6009function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
6010{
6011 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
6012}
6013
6032function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
6033{
6034 global $langs, $form;
6035 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
6036
6037 if ($moreattrib == 'class="right"') {
6038 $prefix .= 'right '; // For backward compatibility
6039 }
6040
6041 $sortorder = strtoupper($sortorder);
6042 $out = '';
6043 $sortimg = '';
6044
6045 $tag = 'th';
6046 if ($thead == 2) {
6047 $tag = 'div';
6048 }
6049
6050 $tmpsortfield = explode(',', $sortfield);
6051 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
6052 $tmpfield = explode(',', $field);
6053 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
6054
6055 if (!getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle)) {
6056 $prefix = 'wrapcolumntitle '.$prefix;
6057 }
6058
6059 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
6060 // If field is used as sort criteria we use a specific css class liste_titre_sel
6061 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
6062 $liste_titre = 'liste_titre';
6063 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
6064 $liste_titre = 'liste_titre_sel';
6065 }
6066
6067 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
6068 //$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)).'"' : '');
6069 $tagstart .= ($name && !getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
6070 $tagstart .= '>';
6071
6072 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
6073 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
6074 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
6075 $options = preg_replace('/&+/i', '&', $options);
6076 if (!preg_match('/^&/', $options)) {
6077 $options = '&'.$options;
6078 }
6079
6080 $sortordertouseinlink = '';
6081 if ($field1 != $sortfield1) { // We are on another field than current sorted field
6082 if (preg_match('/^DESC/i', $sortorder)) {
6083 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
6084 } else { // We reverse the var $sortordertouseinlink
6085 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
6086 }
6087 } else { // We are on field that is the first current sorting criteria
6088 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
6089 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
6090 } else {
6091 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
6092 }
6093 }
6094 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
6095 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
6096 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
6097 $out .= '>';
6098 }
6099 if ($tooltip) {
6100 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
6101 if (preg_match('/:\w+$/', $tooltip)) {
6102 $tmptooltip = explode(':', $tooltip);
6103 } else {
6104 $tmptooltip = array($tooltip);
6105 }
6106 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
6107 } else {
6108 $out .= $langs->trans($name);
6109 }
6110
6111 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
6112 $out .= '</a>';
6113 }
6114
6115 if (empty($thead) && $field) { // If this is a sort field
6116 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
6117 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
6118 $options = preg_replace('/&+/i', '&', $options);
6119 if (!preg_match('/^&/', $options)) {
6120 $options = '&'.$options;
6121 }
6122
6123 if (!$sortorder || ($field1 != $sortfield1)) {
6124 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
6125 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
6126 } else {
6127 if (preg_match('/^DESC/', $sortorder)) {
6128 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
6129 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
6130 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
6131 }
6132 if (preg_match('/^ASC/', $sortorder)) {
6133 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
6134 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
6135 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
6136 }
6137 }
6138 }
6139
6140 $tagend = '</'.$tag.'>';
6141
6142 $out = $tagstart.$sortimg.$out.$tagend;
6143
6144 return $out;
6145}
6146
6155function print_titre($title)
6156{
6157 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
6158
6159 print '<div class="titre">'.$title.'</div>';
6160}
6161
6173function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
6174{
6175 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
6176}
6177
6191function load_fiche_titre($title, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
6192{
6193 $return = '';
6194
6195 if ($picto == 'setup') {
6196 $picto = 'generic';
6197 }
6198
6199 $return .= "\n";
6200 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
6201 $return .= '<tr class="titre">';
6202 if ($picto) {
6203 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
6204 }
6205 $return .= '<td class="nobordernopadding valignmiddle col-title">';
6206 $return .= '<div class="titre inline-block">';
6207 $return .= $title; // $title is already HTML sanitized content
6208 $return .= '</div>';
6209 $return .= '</td>';
6210 if (dol_strlen($morehtmlcenter)) {
6211 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
6212 }
6213 if (dol_strlen($morehtmlright)) {
6214 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
6215 }
6216 $return .= '</tr></table>'."\n";
6217
6218 return $return;
6219}
6220
6244function 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 = '')
6245{
6246 global $conf;
6247
6248 $savlimit = $limit;
6249 $savtotalnboflines = $totalnboflines;
6250 if (is_numeric($totalnboflines)) {
6251 $totalnboflines = abs($totalnboflines);
6252 }
6253
6254 $page = (int) $page;
6255
6256 if ($picto == 'setup') {
6257 $picto = 'title_setup.png';
6258 }
6259 if (($conf->browser->name == 'ie') && $picto == 'generic') {
6260 $picto = 'title.gif';
6261 }
6262 if ($limit < 0) {
6263 $limit = $conf->liste_limit;
6264 }
6265
6266 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
6267 $nextpage = 1;
6268 } else {
6269 $nextpage = 0;
6270 }
6271 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
6272
6273 print "\n";
6274 print "<!-- Begin title -->\n";
6275 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
6276
6277 // Left
6278
6279 if ($picto && $title) {
6280 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
6281 }
6282
6283 print '<td class="nobordernopadding valignmiddle col-title">';
6284 print '<div class="titre inline-block">';
6285 print $title; // $title may contains HTML
6286 if (!empty($title) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
6287 print '<span class="opacitymedium colorblack paddingleft totalnboflines">('.$totalnboflines.')</span>';
6288 }
6289 print '</div></td>';
6290
6291 // Center
6292 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
6293 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
6294 }
6295
6296 // Right
6297 print '<td class="nobordernopadding valignmiddle right col-right">';
6298 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
6299 if ($sortfield) {
6300 $options .= "&sortfield=".urlencode($sortfield);
6301 }
6302 if ($sortorder) {
6303 $options .= "&sortorder=".urlencode($sortorder);
6304 }
6305 // Show navigation bar
6306 $pagelist = '';
6307 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
6308 if ($totalnboflines) { // If we know total nb of lines
6309 // Define nb of extra page links before and after selected page + ... + first or last
6310 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
6311
6312 if ($limit > 0) {
6313 $nbpages = ceil($totalnboflines / $limit);
6314 } else {
6315 $nbpages = 1;
6316 }
6317 $cpt = ($page - $maxnbofpage);
6318 if ($cpt < 0) {
6319 $cpt = 0;
6320 }
6321
6322 if ($cpt >= 1) {
6323 if (empty($pagenavastextinput)) {
6324 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=0'.$options.'">1</a></li>';
6325 if ($cpt > 2) {
6326 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
6327 } elseif ($cpt == 2) {
6328 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=1'.$options.'">2</a></li>';
6329 }
6330 }
6331 }
6332
6333 do {
6334 if ($pagenavastextinput) {
6335 if ($cpt == $page) {
6336 $pagelist .= '<li class="pagination pageplusone"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
6337 $pagelist .= '/';
6338 }
6339 } else {
6340 if ($cpt == $page) {
6341 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
6342 } else {
6343 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
6344 }
6345 }
6346 $cpt++;
6347 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
6348
6349 if (empty($pagenavastextinput)) {
6350 if ($cpt < $nbpages) {
6351 if ($cpt < $nbpages - 2) {
6352 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
6353 } elseif ($cpt == $nbpages - 2) {
6354 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
6355 }
6356 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
6357 }
6358 } else {
6359 //var_dump($page.' '.$cpt.' '.$nbpages);
6360 $pagelist .= '<li class="pagination paginationlastpage"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
6361 }
6362 } else {
6363 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
6364 }
6365 }
6366
6367 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
6368 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
6369 }
6370
6371 // js to autoselect page field on focus
6372 if ($pagenavastextinput) {
6373 print ajax_autoselect('.pageplusone');
6374 }
6375
6376 print '</td>';
6377 print '</tr>';
6378
6379 print '</table>'."\n";
6380
6381 // Center
6382 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
6383 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
6384 }
6385
6386 print "<!-- End title -->\n\n";
6387}
6388
6405function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
6406{
6407 global $conf, $langs;
6408
6409 print '<div class="pagination"><ul>';
6410 if ($beforearrows) {
6411 print '<li class="paginationbeforearrows">';
6412 print $beforearrows;
6413 print '</li>';
6414 }
6415
6416 if (empty($hidenavigation)) {
6417 if ((int) $limit > 0 && empty($hideselectlimit)) {
6418 $pagesizechoices = '10:10,15:15,20:20,25:25,50:50,100:100,250:250,500:500,1000:1000';
6419 $pagesizechoices .= ',5000:5000,10000:10000';
6420 //$pagesizechoices .= ',20000:20000'; // Memory trouble on browsers
6421 //$pagesizechoices .= ',0:'.$langs->trans("All"); // Not yet supported
6422 //$pagesizechoices .= ',2:2';
6423 if (getDolGlobalString('MAIN_PAGESIZE_CHOICES')) {
6424 $pagesizechoices = getDolGlobalString('MAIN_PAGESIZE_CHOICES');
6425 }
6426
6427 if (getDolGlobalString('MAIN_USE_HTML5_LIMIT_SELECTOR')) {
6428 print '<li class="pagination">';
6429 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.'">';
6430 print '<datalist id="limitlist">';
6431 } else {
6432 print '<li class="paginationcombolimit valignmiddle">';
6433 print '<select id="limit" class="flat selectlimit nopadding maxwidth75 center" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
6434 }
<