dolibarr 19.0.4
functions.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2000-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2003 Jean-Louis Bergamo <jlb@j1b.org>
4 * Copyright (C) 2004-2022 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
7 * Copyright (C) 2004 Christophe Combelles <ccomb@free.fr>
8 * Copyright (C) 2005-2019 Regis Houssin <regis.houssin@inodbox.com>
9 * Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr>
10 * Copyright (C) 2010-2018 Juanjo Menent <jmenent@2byte.es>
11 * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
12 * Copyright (C) 2013-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
13 * Copyright (C) 2014 Cédric GROSS <c.gross@kreiz-it.fr>
14 * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
15 * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
16 * Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
17 * Copyright (C) 2019-2023 Thibault Foucart <support@ptibogxiv.net>
18 * Copyright (C) 2020 Open-Dsi <support@open-dsi.fr>
19 * Copyright (C) 2021 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
20 * Copyright (C) 2022 Anthony Berton <anthony.berton@bb2a.fr>
21 * Copyright (C) 2022 Ferran Marcet <fmarcet@2byte.es>
22 * Copyright (C) 2022 Charlene Benke <charlene@patas-monkey.com>
23 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 3 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program. If not, see <https://www.gnu.org/licenses/>.
37 * or see https://www.gnu.org/
38 */
39
46include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
47
48// Function for better PHP x compatibility
49if (!function_exists('utf8_encode')) {
56 function utf8_encode($elements)
57 {
58 return mb_convert_encoding($elements, 'UTF-8', 'ISO-8859-1');
59 }
60}
61
62if (!function_exists('utf8_decode')) {
69 function utf8_decode($elements)
70 {
71 return mb_convert_encoding($elements, 'ISO-8859-1', 'UTF-8');
72 }
73}
74if (!function_exists('str_starts_with')) {
82 function str_starts_with($haystack, $needle)
83 {
84 return (string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0;
85 }
86}
87if (!function_exists('str_ends_with')) {
95 function str_ends_with($haystack, $needle)
96 {
97 return $needle !== '' && substr($haystack, -strlen($needle)) === (string) $needle;
98 }
99}
100if (!function_exists('str_contains')) {
108 function str_contains($haystack, $needle)
109 {
110 return $needle !== '' && mb_strpos($haystack, $needle) !== false;
111 }
112}
113
114
123function getMultidirOutput($object, $module = '')
124{
125 global $conf;
126
127 if (!is_object($object) && empty($module)) {
128 return null;
129 }
130 if (empty($module) && !empty($object->element)) {
131 $module = $object->element;
132 }
133 // Special case for backward compatibility
134 if ($module == 'fichinter') {
135 $module = 'ficheinter';
136 }
137 if (isset($conf->$module) && property_exists($conf->$module, 'multidir_output')) {
138 return $conf->$module->multidir_output[(empty($object->entity) ? $conf->entity : $object->entity)];
139 } else {
140 return 'error-diroutput-not-defined-for-this-object='.$module;
141 }
142}
143
151function getDolGlobalString($key, $default = '')
152{
153 global $conf;
154 return (string) (isset($conf->global->$key) ? $conf->global->$key : $default);
155}
156
165function getDolGlobalInt($key, $default = 0)
166{
167 global $conf;
168 return (int) (isset($conf->global->$key) ? $conf->global->$key : $default);
169}
170
179function getDolUserString($key, $default = '', $tmpuser = null)
180{
181 if (empty($tmpuser)) {
182 global $user;
183 $tmpuser = $user;
184 }
185
186 return (string) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
187}
188
197function getDolUserInt($key, $default = 0, $tmpuser = null)
198{
199 if (empty($tmpuser)) {
200 global $user;
201 $tmpuser = $user;
202 }
203
204 return (int) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
205}
206
213function isModEnabled($module)
214{
215 global $conf;
216
217 // Fix special cases
218 $arrayconv = array(
219 'bank' => 'banque',
220 'category' => 'categorie',
221 'contract' => 'contrat',
222 'project' => 'projet',
223 'delivery_note' => 'expedition'
224 );
225 if (!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD')) {
226 $arrayconv['supplier_order'] = 'fournisseur';
227 $arrayconv['supplier_invoice'] = 'fournisseur';
228 }
229 if (!empty($arrayconv[$module])) {
230 $module = $arrayconv[$module];
231 }
232
233 return !empty($conf->modules[$module]);
234 //return !empty($conf->$module->enabled);
235}
236
248function getDoliDBInstance($type, $host, $user, $pass, $name, $port)
249{
250 require_once DOL_DOCUMENT_ROOT."/core/db/".$type.'.class.php';
251
252 $class = 'DoliDB'.ucfirst($type);
253 $dolidb = new $class($type, $host, $user, $pass, $name, $port);
254 return $dolidb;
255}
256
274function getEntity($element, $shared = 1, $currentobject = null)
275{
276 global $conf, $mc, $hookmanager, $object, $action, $db;
277
278 if (!is_object($hookmanager)) {
279 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
280 $hookmanager = new HookManager($db);
281 }
282
283 // fix different element names (France to English)
284 switch ($element) {
285 case 'projet':
286 $element = 'project';
287 break;
288 case 'contrat':
289 $element = 'contract';
290 break; // "/contrat/class/contrat.class.php"
291 case 'order_supplier':
292 $element = 'supplier_order';
293 break; // "/fourn/class/fournisseur.commande.class.php"
294 case 'invoice_supplier':
295 $element = 'supplier_invoice';
296 break; // "/fourn/class/fournisseur.facture.class.php"
297 }
298
299 if (is_object($mc)) {
300 $out = $mc->getEntity($element, $shared, $currentobject);
301 } else {
302 $out = '';
303 $addzero = array('user', 'usergroup', 'cronjob', 'c_email_templates', 'email_template', 'default_values', 'overwrite_trans');
304 if (in_array($element, $addzero)) {
305 $out .= '0,';
306 }
307 $out .= ((int) $conf->entity);
308 }
309
310 // Manipulate entities to query on the fly
311 $parameters = array(
312 'element' => $element,
313 'shared' => $shared,
314 'object' => $object,
315 'currentobject' => $currentobject,
316 'out' => $out
317 );
318 $reshook = $hookmanager->executeHooks('hookGetEntity', $parameters, $currentobject, $action); // Note that $action and $object may have been modified by some hooks
319
320 if (is_numeric($reshook)) {
321 if ($reshook == 0 && !empty($hookmanager->resPrint)) {
322 $out .= ','.$hookmanager->resPrint; // add
323 } elseif ($reshook == 1) {
324 $out = $hookmanager->resPrint; // replace
325 }
326 }
327
328 return $out;
329}
330
337function setEntity($currentobject)
338{
339 global $conf, $mc;
340
341 if (is_object($mc) && method_exists($mc, 'setEntity')) {
342 return $mc->setEntity($currentobject);
343 } else {
344 return ((is_object($currentobject) && $currentobject->id > 0 && $currentobject->entity > 0) ? $currentobject->entity : $conf->entity);
345 }
346}
347
354function isASecretKey($keyname)
355{
356 return preg_match('/(_pass|password|_pw|_key|securekey|serverkey|secret\d?|p12key|exportkey|_PW_[a-z]+|token)$/i', $keyname);
357}
358
359
366function num2Alpha($n)
367{
368 for ($r = ""; $n >= 0; $n = intval($n / 26) - 1) {
369 $r = chr($n % 26 + 0x41) . $r;
370 }
371 return $r;
372}
373
374
391function getBrowserInfo($user_agent)
392{
393 include_once DOL_DOCUMENT_ROOT.'/includes/mobiledetect/mobiledetectlib/Mobile_Detect.php';
394
395 $name = 'unknown';
396 $version = '';
397 $os = 'unknown';
398 $phone = '';
399
400 $user_agent = substr($user_agent, 0, 512); // Avoid to process too large user agent
401
402 $detectmobile = new Mobile_Detect(null, $user_agent);
403 $tablet = $detectmobile->isTablet();
404
405 if ($detectmobile->isMobile()) {
406 $phone = 'unknown';
407
408 // If phone/smartphone, we set phone os name.
409 if ($detectmobile->is('AndroidOS')) {
410 $os = $phone = 'android';
411 } elseif ($detectmobile->is('BlackBerryOS')) {
412 $os = $phone = 'blackberry';
413 } elseif ($detectmobile->is('iOS')) {
414 $os = 'ios';
415 $phone = 'iphone';
416 } elseif ($detectmobile->is('PalmOS')) {
417 $os = $phone = 'palm';
418 } elseif ($detectmobile->is('SymbianOS')) {
419 $os = 'symbian';
420 } elseif ($detectmobile->is('webOS')) {
421 $os = 'webos';
422 } elseif ($detectmobile->is('MaemoOS')) {
423 $os = 'maemo';
424 } elseif ($detectmobile->is('WindowsMobileOS') || $detectmobile->is('WindowsPhoneOS')) {
425 $os = 'windows';
426 }
427 }
428
429 // OS
430 if (preg_match('/linux/i', $user_agent)) {
431 $os = 'linux';
432 } elseif (preg_match('/macintosh/i', $user_agent)) {
433 $os = 'macintosh';
434 } elseif (preg_match('/windows/i', $user_agent)) {
435 $os = 'windows';
436 }
437
438 // Name
439 $reg = array();
440 if (preg_match('/firefox(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
441 $name = 'firefox';
442 $version = empty($reg[2]) ? '' : $reg[2];
443 } elseif (preg_match('/edge(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
444 $name = 'edge';
445 $version = empty($reg[2]) ? '' : $reg[2];
446 } elseif (preg_match('/chrome(\/|\s)([\d\.]+)/i', $user_agent, $reg)) {
447 $name = 'chrome';
448 $version = empty($reg[2]) ? '' : $reg[2];
449 } elseif (preg_match('/chrome/i', $user_agent, $reg)) {
450 // we can have 'chrome (Mozilla...) chrome x.y' in one string
451 $name = 'chrome';
452 } elseif (preg_match('/iceweasel/i', $user_agent)) {
453 $name = 'iceweasel';
454 } elseif (preg_match('/epiphany/i', $user_agent)) {
455 $name = 'epiphany';
456 } elseif (preg_match('/safari(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
457 $name = 'safari';
458 $version = empty($reg[2]) ? '' : $reg[2];
459 } elseif (preg_match('/opera(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
460 // Safari is often present in string for mobile but its not.
461 $name = 'opera';
462 $version = empty($reg[2]) ? '' : $reg[2];
463 } elseif (preg_match('/(MSIE\s([0-9]+\.[0-9]))|.*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
464 $name = 'ie';
465 $version = end($reg);
466 } elseif (preg_match('/(Windows NT\s([0-9]+\.[0-9])).*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
467 // MS products at end
468 $name = 'ie';
469 $version = end($reg);
470 } elseif (preg_match('/l[iy]n(x|ks)(\‍(|\/|\s)*([\d\.]+)/i', $user_agent, $reg)) {
471 // MS products at end
472 $name = 'lynxlinks';
473 $version = empty($reg[3]) ? '' : $reg[3];
474 }
475
476 if ($tablet) {
477 $layout = 'tablet';
478 } elseif ($phone) {
479 $layout = 'phone';
480 } else {
481 $layout = 'classic';
482 }
483
484 return array(
485 'browsername' => $name,
486 'browserversion' => $version,
487 'browseros' => $os,
488 'browserua' => $user_agent,
489 'layout' => $layout, // tablet, phone, classic
490 'phone' => $phone, // deprecated
491 'tablet' => $tablet // deprecated
492 );
493}
494
500function dol_shutdown()
501{
502 global $db;
503 $disconnectdone = false;
504 $depth = 0;
505 if (is_object($db) && !empty($db->connected)) {
506 $depth = $db->transaction_opened;
507 $disconnectdone = $db->close();
508 }
509 dol_syslog("--- End access to ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]).(($disconnectdone && $depth) ? ' (Warn: db disconnection forced, transaction depth was '.$depth.')' : ''), (($disconnectdone && $depth) ? LOG_WARNING : LOG_INFO));
510}
511
521function GETPOSTISSET($paramname)
522{
523 $isset = false;
524
525 $relativepathstring = $_SERVER["PHP_SELF"];
526 // Clean $relativepathstring
527 if (constant('DOL_URL_ROOT')) {
528 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
529 }
530 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
531 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
532 //var_dump($relativepathstring);
533 //var_dump($user->default_values);
534
535 // Code for search criteria persistence.
536 // Retrieve values if restore_lastsearch_values
537 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
538 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
539 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
540 if (is_array($tmp)) {
541 foreach ($tmp as $key => $val) {
542 if ($key == $paramname) { // We are on the requested parameter
543 $isset = true;
544 break;
545 }
546 }
547 }
548 }
549 // If there is saved contextpage, limit, page or mode
550 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
551 $isset = true;
552 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
553 $isset = true;
554 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
555 $isset = true;
556 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
557 $isset = true;
558 }
559 } else {
560 $isset = (isset($_POST[$paramname]) || isset($_GET[$paramname])); // We must keep $_POST and $_GET here
561 }
562
563 return $isset;
564}
565
574function GETPOSTISARRAY($paramname, $method = 0)
575{
576 // for $method test need return the same $val as GETPOST
577 if (empty($method)) {
578 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
579 } elseif ($method == 1) {
580 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
581 } elseif ($method == 2) {
582 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
583 } elseif ($method == 3) {
584 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
585 } else {
586 $val = 'BadFirstParameterForGETPOST';
587 }
588
589 return is_array($val);
590}
591
621function GETPOST($paramname, $check = 'alphanohtml', $method = 0, $filter = null, $options = null, $noreplace = 0)
622{
623 global $mysoc, $user, $conf;
624
625 if (empty($paramname)) {
626 return 'BadFirstParameterForGETPOST';
627 }
628 if (empty($check)) {
629 dol_syslog("Deprecated use of GETPOST, called with 1st param = ".$paramname." and a 2nd param that is '', when calling page ".$_SERVER["PHP_SELF"], LOG_WARNING);
630 // Enable this line to know who call the GETPOST with '' $check parameter.
631 //var_dump(debug_backtrace()[0]);
632 }
633
634 if (empty($method)) {
635 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
636 } elseif ($method == 1) {
637 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
638 } elseif ($method == 2) {
639 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
640 } elseif ($method == 3) {
641 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
642 } else {
643 return 'BadThirdParameterForGETPOST';
644 }
645
646 if (empty($method) || $method == 3 || $method == 4) {
647 $relativepathstring = (empty($_SERVER["PHP_SELF"]) ? '' : $_SERVER["PHP_SELF"]);
648 // Clean $relativepathstring
649 if (constant('DOL_URL_ROOT')) {
650 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
651 }
652 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
653 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
654 //var_dump($relativepathstring);
655 //var_dump($user->default_values);
656
657 // Code for search criteria persistence.
658 // Retrieve saved values if restore_lastsearch_values is set
659 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
660 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
661 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
662 if (is_array($tmp)) {
663 foreach ($tmp as $key => $val) {
664 if ($key == $paramname) { // We are on the requested parameter
665 $out = $val;
666 break;
667 }
668 }
669 }
670 }
671 // If there is saved contextpage, page or limit
672 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
673 $out = $_SESSION['lastsearch_contextpage_'.$relativepathstring];
674 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
675 $out = $_SESSION['lastsearch_limit_'.$relativepathstring];
676 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
677 $out = $_SESSION['lastsearch_page_'.$relativepathstring];
678 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
679 $out = $_SESSION['lastsearch_mode_'.$relativepathstring];
680 }
681 } elseif (!isset($_GET['sortfield'])) {
682 // Else, retrieve default values if we are not doing a sort
683 // If we did a click on a field to sort, we do no apply default values. Same if option MAIN_ENABLE_DEFAULT_VALUES is not set
684 if (!empty($_GET['action']) && $_GET['action'] == 'create' && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
685 // Search default value from $object->field
686 global $object;
687 if (is_object($object) && isset($object->fields[$paramname]['default'])) {
688 $out = $object->fields[$paramname]['default'];
689 }
690 }
691 if (getDolGlobalString('MAIN_ENABLE_DEFAULT_VALUES')) {
692 if (!empty($_GET['action']) && (preg_match('/^create/', $_GET['action']) || preg_match('/^presend/', $_GET['action'])) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
693 // Now search in setup to overwrite default values
694 if (!empty($user->default_values)) { // $user->default_values defined from menu 'Setup - Default values'
695 if (isset($user->default_values[$relativepathstring]['createform'])) {
696 foreach ($user->default_values[$relativepathstring]['createform'] as $defkey => $defval) {
697 $qualified = 0;
698 if ($defkey != '_noquery_') {
699 $tmpqueryarraytohave = explode('&', $defkey);
700 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
701 $foundintru = 0;
702 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
703 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
704 $foundintru = 1;
705 }
706 }
707 if (!$foundintru) {
708 $qualified = 1;
709 }
710 //var_dump($defkey.'-'.$qualified);
711 } else {
712 $qualified = 1;
713 }
714
715 if ($qualified) {
716 if (isset($user->default_values[$relativepathstring]['createform'][$defkey][$paramname])) {
717 $out = $user->default_values[$relativepathstring]['createform'][$defkey][$paramname];
718 break;
719 }
720 }
721 }
722 }
723 }
724 } elseif (!empty($paramname) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
725 // Management of default search_filters and sort order
726 if (!empty($user->default_values)) {
727 // $user->default_values defined from menu 'Setup - Default values'
728 //var_dump($user->default_values[$relativepathstring]);
729 if ($paramname == 'sortfield' || $paramname == 'sortorder') {
730 // Sorted on which fields ? ASC or DESC ?
731 if (isset($user->default_values[$relativepathstring]['sortorder'])) {
732 // Even if paramname is sortfield, data are stored into ['sortorder...']
733 foreach ($user->default_values[$relativepathstring]['sortorder'] as $defkey => $defval) {
734 $qualified = 0;
735 if ($defkey != '_noquery_') {
736 $tmpqueryarraytohave = explode('&', $defkey);
737 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
738 $foundintru = 0;
739 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
740 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
741 $foundintru = 1;
742 }
743 }
744 if (!$foundintru) {
745 $qualified = 1;
746 }
747 //var_dump($defkey.'-'.$qualified);
748 } else {
749 $qualified = 1;
750 }
751
752 if ($qualified) {
753 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
754 foreach ($user->default_values[$relativepathstring]['sortorder'][$defkey] as $key => $val) {
755 if ($out) {
756 $out .= ', ';
757 }
758 if ($paramname == 'sortfield') {
759 $out .= dol_string_nospecial($key, '', $forbidden_chars_to_replace);
760 }
761 if ($paramname == 'sortorder') {
762 $out .= dol_string_nospecial($val, '', $forbidden_chars_to_replace);
763 }
764 }
765 //break; // No break for sortfield and sortorder so we can cumulate fields (is it realy usefull ?)
766 }
767 }
768 }
769 } elseif (isset($user->default_values[$relativepathstring]['filters'])) {
770 foreach ($user->default_values[$relativepathstring]['filters'] as $defkey => $defval) { // $defkey is a querystring like 'a=b&c=d', $defval is key of user
771 if (!empty($_GET['disabledefaultvalues'])) { // If set of default values has been disabled by a request parameter
772 continue;
773 }
774 $qualified = 0;
775 if ($defkey != '_noquery_') {
776 $tmpqueryarraytohave = explode('&', $defkey);
777 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
778 $foundintru = 0;
779 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
780 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
781 $foundintru = 1;
782 }
783 }
784 if (!$foundintru) {
785 $qualified = 1;
786 }
787 //var_dump($defkey.'-'.$qualified);
788 } else {
789 $qualified = 1;
790 }
791
792 if ($qualified && isset($user->default_values[$relativepathstring]['filters'][$defkey][$paramname])) {
793 // We must keep $_POST and $_GET here
794 if (isset($_POST['sall']) || isset($_POST['search_all']) || isset($_GET['sall']) || isset($_GET['search_all'])) {
795 // We made a search from quick search menu, do we still use default filter ?
796 if (!getDolGlobalString('MAIN_DISABLE_DEFAULT_FILTER_FOR_QUICK_SEARCH')) {
797 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
798 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
799 }
800 } else {
801 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
802 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
803 }
804 break;
805 }
806 }
807 }
808 }
809 }
810 }
811 }
812 }
813
814 // Substitution variables for GETPOST (used to get final url with variable parameters or final default value, when using variable parameters __XXX__ in the GET URL)
815 // Example of variables: __DAY__, __MONTH__, __YEAR__, __MYCOMPANY_COUNTRY_ID__, __USER_ID__, ...
816 // We do this only if var is a GET. If it is a POST, may be we want to post the text with vars as the setup text.
817 if (!is_array($out) && empty($_POST[$paramname]) && empty($noreplace)) {
818 $reg = array();
819 $maxloop = 20;
820 $loopnb = 0; // Protection against infinite loop
821 while (preg_match('/__([A-Z0-9]+_?[A-Z0-9]+)__/i', $out, $reg) && ($loopnb < $maxloop)) { // Detect '__ABCDEF__' as key 'ABCDEF' and '__ABC_DEF__' as key 'ABC_DEF'. Detection is also correct when 2 vars are side by side.
822 $loopnb++;
823 $newout = '';
824
825 if ($reg[1] == 'DAY') {
826 $tmp = dol_getdate(dol_now(), true);
827 $newout = $tmp['mday'];
828 } elseif ($reg[1] == 'MONTH') {
829 $tmp = dol_getdate(dol_now(), true);
830 $newout = $tmp['mon'];
831 } elseif ($reg[1] == 'YEAR') {
832 $tmp = dol_getdate(dol_now(), true);
833 $newout = $tmp['year'];
834 } elseif ($reg[1] == 'PREVIOUS_DAY') {
835 $tmp = dol_getdate(dol_now(), true);
836 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
837 $newout = $tmp2['day'];
838 } elseif ($reg[1] == 'PREVIOUS_MONTH') {
839 $tmp = dol_getdate(dol_now(), true);
840 $tmp2 = dol_get_prev_month($tmp['mon'], $tmp['year']);
841 $newout = $tmp2['month'];
842 } elseif ($reg[1] == 'PREVIOUS_YEAR') {
843 $tmp = dol_getdate(dol_now(), true);
844 $newout = ($tmp['year'] - 1);
845 } elseif ($reg[1] == 'NEXT_DAY') {
846 $tmp = dol_getdate(dol_now(), true);
847 $tmp2 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
848 $newout = $tmp2['day'];
849 } elseif ($reg[1] == 'NEXT_MONTH') {
850 $tmp = dol_getdate(dol_now(), true);
851 $tmp2 = dol_get_next_month($tmp['mon'], $tmp['year']);
852 $newout = $tmp2['month'];
853 } elseif ($reg[1] == 'NEXT_YEAR') {
854 $tmp = dol_getdate(dol_now(), true);
855 $newout = ($tmp['year'] + 1);
856 } elseif ($reg[1] == 'MYCOMPANY_COUNTRY_ID' || $reg[1] == 'MYCOUNTRY_ID' || $reg[1] == 'MYCOUNTRYID') {
857 $newout = $mysoc->country_id;
858 } elseif ($reg[1] == 'USER_ID' || $reg[1] == 'USERID') {
859 $newout = $user->id;
860 } elseif ($reg[1] == 'USER_SUPERVISOR_ID' || $reg[1] == 'SUPERVISOR_ID' || $reg[1] == 'SUPERVISORID') {
861 $newout = $user->fk_user;
862 } elseif ($reg[1] == 'ENTITY_ID' || $reg[1] == 'ENTITYID') {
863 $newout = $conf->entity;
864 } else {
865 $newout = ''; // Key not found, we replace with empty string
866 }
867 //var_dump('__'.$reg[1].'__ -> '.$newout);
868 $out = preg_replace('/__'.preg_quote($reg[1], '/').'__/', $newout, $out);
869 }
870 }
871
872 // Check type of variable and make sanitization according to this
873 if (preg_match('/^array/', $check)) { // If 'array' or 'array:restricthtml' or 'array:aZ09' or 'array:intcomma'
874 if (!is_array($out) || empty($out)) {
875 $out = array();
876 } else {
877 $tmparray = explode(':', $check);
878 if (!empty($tmparray[1])) {
879 $tmpcheck = $tmparray[1];
880 } else {
881 $tmpcheck = 'alphanohtml';
882 }
883 foreach ($out as $outkey => $outval) {
884 $out[$outkey] = sanitizeVal($outval, $tmpcheck, $filter, $options);
885 }
886 }
887 } else {
888 // If field name is 'search_xxx' then we force the add of space after each < and > (when following char is numeric) because it means
889 // we use the < or > to make a search on a numeric value to do higher or lower so we can add a space to break html tags
890 if (strpos($paramname, 'search_') === 0) {
891 $out = preg_replace('/([<>])([-+]?\d)/', '\1 \2', $out);
892 }
893
894 $out = sanitizeVal($out, $check, $filter, $options);
895 }
896
897 // Sanitizing for special parameters.
898 // Note: There is no reason to allow the backtopage, backtolist or backtourl parameter to contains an external URL. Only relative URLs are allowed.
899 if ($paramname == 'backtopage' || $paramname == 'backtolist' || $paramname == 'backtourl') {
900 $out = str_replace('\\', '/', $out); // Can be before the loop because only 1 char is replaced. No risk to get it after other replacements.
901 $out = str_replace(array(':', ';', '@', "\t", ' '), '', $out); // Can be before the loop because only 1 char is replaced. No risk to retreive it after other replacements.
902 do {
903 $oldstringtoclean = $out;
904 $out = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $out);
905 $out = preg_replace(array('/^[^\?]*%/'), '', $out); // We remove any % chars before the ?. Example in url: '/product/stock/card.php?action=create&backtopage=%2Fdolibarr_dev%2Fhtdocs%2Fpro%25duct%2Fcard.php%3Fid%3Dabc'
906 $out = preg_replace(array('/^[a-z]*\/\s*\/+/i'), '', $out); // We remove schema*// to remove external URL
907 } while ($oldstringtoclean != $out);
908 }
909
910 // Code for search criteria persistence.
911 // Save data into session if key start with 'search_' or is 'smonth', 'syear', 'month', 'year'
912 if (empty($method) || $method == 3 || $method == 4) {
913 if (preg_match('/^search_/', $paramname) || in_array($paramname, array('sortorder', 'sortfield'))) {
914 //var_dump($paramname.' - '.$out.' '.$user->default_values[$relativepathstring]['filters'][$paramname]);
915
916 // We save search key only if $out not empty that means:
917 // - posted value not empty, or
918 // - if posted value is empty and a default value exists that is not empty (it means we did a filter to an empty value when default was not).
919
920 if ($out != '' && isset($user)) {// $out = '0' or 'abc', it is a search criteria to keep
921 $user->lastsearch_values_tmp[$relativepathstring][$paramname] = $out;
922 }
923 }
924 }
925
926 return $out;
927}
928
938function GETPOSTINT($paramname, $method = 0)
939{
940 return (int) GETPOST($paramname, 'int', $method, null, null, 0);
941}
942
943
954function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
955{
956 return sanitizeVal($out, $check, $filter, $options);
957}
958
968function sanitizeVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
969{
970 // TODO : use class "Validate" to perform tests (and add missing tests) if needed for factorize
971 // Check is done after replacement
972 switch ($check) {
973 case 'none':
974 break;
975 case 'int': // Check param is a numeric value (integer but also float or hexadecimal)
976 if (!is_numeric($out)) {
977 $out = '';
978 }
979 break;
980 case 'intcomma':
981 if (is_array($out)) {
982 $out = implode(',', $out);
983 }
984 if (preg_match('/[^0-9,-]+/i', $out)) {
985 $out = '';
986 }
987 break;
988 case 'san_alpha':
989 $out = filter_var($out, FILTER_SANITIZE_STRING);
990 break;
991 case 'email':
992 $out = filter_var($out, FILTER_SANITIZE_EMAIL);
993 break;
994 case 'aZ':
995 if (!is_array($out)) {
996 $out = trim($out);
997 if (preg_match('/[^a-z]+/i', $out)) {
998 $out = '';
999 }
1000 }
1001 break;
1002 case 'aZ09':
1003 if (!is_array($out)) {
1004 $out = trim($out);
1005 if (preg_match('/[^a-z0-9_\-\.]+/i', $out)) {
1006 $out = '';
1007 }
1008 }
1009 break;
1010 case 'aZ09arobase': // great to sanitize $objecttype parameter
1011 if (!is_array($out)) {
1012 $out = trim($out);
1013 if (preg_match('/[^a-z0-9_\-\.@]+/i', $out)) {
1014 $out = '';
1015 }
1016 }
1017 break;
1018 case 'aZ09comma': // great to sanitize $sortfield or $sortorder params that can be 't.abc,t.def_gh'
1019 if (!is_array($out)) {
1020 $out = trim($out);
1021 if (preg_match('/[^a-z0-9_\-\.,]+/i', $out)) {
1022 $out = '';
1023 }
1024 }
1025 break;
1026 case 'alpha': // No html and no ../ and "
1027 case 'alphanohtml': // Recommended for most scalar parameters and search parameters
1028 if (!is_array($out)) {
1029 $out = trim($out);
1030 do {
1031 $oldstringtoclean = $out;
1032 // Remove html tags
1033 $out = dol_string_nohtmltag($out, 0);
1034 // Remove also other dangerous string sequences
1035 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1036 // '../' or '..\' is dangerous because it allows dir transversals
1037 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1038 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1039 } while ($oldstringtoclean != $out);
1040 // keep lines feed
1041 }
1042 break;
1043 case 'alphawithlgt': // No " and no ../ but we keep balanced < > tags with no special chars inside. Can be used for email string like "Name <email>". Less secured than 'alphanohtml'
1044 if (!is_array($out)) {
1045 $out = trim($out);
1046 do {
1047 $oldstringtoclean = $out;
1048 // Remove html tags
1049 $out = dol_html_entity_decode($out, ENT_COMPAT | ENT_HTML5, 'UTF-8');
1050 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1051 // '../' or '..\' is dangerous because it allows dir transversals
1052 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1053 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1054 } while ($oldstringtoclean != $out);
1055 }
1056 break;
1057 case 'nohtml': // No html
1058 $out = dol_string_nohtmltag($out, 0);
1059 break;
1060 case 'restricthtmlnolink':
1061 case 'restricthtml': // Recommended for most html textarea
1062 case 'restricthtmlallowclass':
1063 case 'restricthtmlallowunvalid':
1064 $out = dol_htmlwithnojs($out, 1, $check);
1065 break;
1066 case 'custom':
1067 if (!empty($out)) {
1068 if (empty($filter)) {
1069 return 'BadParameterForGETPOST - Param 3 of sanitizeVal()';
1070 }
1071 /*if (empty($options)) {
1072 return 'BadParameterForGETPOST - Param 4 of sanitizeVal()';
1073 }*/
1074 $out = filter_var($out, $filter, $options);
1075 }
1076 break;
1077 default:
1078 dol_syslog("Error, you call sanitizeVal() with a bad value for the check type. Data can't be sanitized.", LOG_ERR);
1079 break;
1080 }
1081
1082 return $out;
1083}
1084
1085
1086if (!function_exists('dol_getprefix')) {
1096 function dol_getprefix($mode = '')
1097 {
1098 // If prefix is for email (we need to have $conf already loaded for this case)
1099 if ($mode == 'email') {
1100 global $conf;
1101
1102 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID')) { // If MAIL_PREFIX_FOR_EMAIL_ID is set
1103 if (getDolGlobalString('MAIL_PREFIX_FOR_EMAIL_ID') != 'SERVER_NAME') {
1104 return $conf->global->MAIL_PREFIX_FOR_EMAIL_ID;
1105 } elseif (isset($_SERVER["SERVER_NAME"])) { // If MAIL_PREFIX_FOR_EMAIL_ID is set to 'SERVER_NAME'
1106 return $_SERVER["SERVER_NAME"];
1107 }
1108 }
1109
1110 // The recommended value if MAIL_PREFIX_FOR_EMAIL_ID is not defined (may be not defined for old versions)
1111 if (!empty($conf->file->instance_unique_id)) {
1112 return sha1('dolibarr'.$conf->file->instance_unique_id);
1113 }
1114
1115 // For backward compatibility when instance_unique_id is not set
1116 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1117 }
1118
1119 // If prefix is for session (no need to have $conf loaded)
1120 global $dolibarr_main_instance_unique_id, $dolibarr_main_cookie_cryptkey; // This is loaded by filefunc.inc.php
1121 $tmp_instance_unique_id = empty($dolibarr_main_instance_unique_id) ? (empty($dolibarr_main_cookie_cryptkey) ? '' : $dolibarr_main_cookie_cryptkey) : $dolibarr_main_instance_unique_id; // Unique id of instance
1122
1123 // The recommended value (may be not defined for old versions)
1124 if (!empty($tmp_instance_unique_id)) {
1125 return sha1('dolibarr'.$tmp_instance_unique_id);
1126 }
1127
1128 // For backward compatibility when instance_unique_id is not set
1129 if (isset($_SERVER["SERVER_NAME"]) && isset($_SERVER["DOCUMENT_ROOT"])) {
1130 return sha1($_SERVER["SERVER_NAME"].$_SERVER["DOCUMENT_ROOT"].DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1131 } else {
1132 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1133 }
1134 }
1135}
1136
1147function dol_include_once($relpath, $classname = '')
1148{
1149 global $conf, $langs, $user, $mysoc; // Do not remove this. They must be defined for files we include. Other globals var must be retrieved with $GLOBALS['var']
1150
1151 $fullpath = dol_buildpath($relpath);
1152
1153 if (!file_exists($fullpath)) {
1154 dol_syslog('functions::dol_include_once Tried to load unexisting file: '.$relpath, LOG_WARNING);
1155 return false;
1156 }
1157
1158 if (!empty($classname) && !class_exists($classname)) {
1159 return include $fullpath;
1160 } else {
1161 return include_once $fullpath;
1162 }
1163}
1164
1165
1176function dol_buildpath($path, $type = 0, $returnemptyifnotfound = 0)
1177{
1178 global $conf;
1179
1180 $path = preg_replace('/^\//', '', $path);
1181
1182 if (empty($type)) { // For a filesystem path
1183 $res = DOL_DOCUMENT_ROOT.'/'.$path; // Standard default path
1184 if (is_array($conf->file->dol_document_root)) {
1185 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array("main"=>"/home/main/htdocs", "alt0"=>"/home/dirmod/htdocs", ...)
1186 if ($key == 'main') {
1187 continue;
1188 }
1189 // if (@file_exists($dirroot.'/'.$path)) {
1190 if (@file_exists($dirroot.'/'.$path)) { // avoid [php:warn]
1191 $res = $dirroot.'/'.$path;
1192 return $res;
1193 }
1194 }
1195 }
1196 if ($returnemptyifnotfound) {
1197 // Not found into alternate dir
1198 if ($returnemptyifnotfound == 1 || !file_exists($res)) {
1199 return '';
1200 }
1201 }
1202 } else {
1203 // For an url path
1204 // We try to get local path of file on filesystem from url
1205 // Note that trying to know if a file on disk exist by forging path on disk from url
1206 // works only for some web server and some setup. This is bugged when
1207 // using proxy, rewriting, virtual path, etc...
1208 $res = '';
1209 if ($type == 1) {
1210 $res = DOL_URL_ROOT.'/'.$path; // Standard value
1211 }
1212 if ($type == 2) {
1213 $res = DOL_MAIN_URL_ROOT.'/'.$path; // Standard value
1214 }
1215 if ($type == 3) {
1216 $res = DOL_URL_ROOT.'/'.$path;
1217 }
1218
1219 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array(["main"]=>"/home/main/htdocs", ["alt0"]=>"/home/dirmod/htdocs", ...)
1220 if ($key == 'main') {
1221 if ($type == 3) {
1222 /*global $dolibarr_main_url_root;*/
1223
1224 // Define $urlwithroot
1225 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1226 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1227 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1228
1229 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).'/'.$path; // Test on start with http is for old conf syntax
1230 }
1231 continue;
1232 }
1233 $regs = array();
1234 preg_match('/^([^\?]+(\.css\.php|\.css|\.js\.php|\.js|\.png|\.jpg|\.php)?)/i', $path, $regs); // Take part before '?'
1235 if (!empty($regs[1])) {
1236 //print $key.'-'.$dirroot.'/'.$path.'-'.$conf->file->dol_url_root[$type].'<br>'."\n";
1237 //if (file_exists($dirroot.'/'.$regs[1])) {
1238 if (@file_exists($dirroot.'/'.$regs[1])) { // avoid [php:warn]
1239 if ($type == 1) {
1240 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1241 }
1242 if ($type == 2) {
1243 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_MAIN_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1244 }
1245 if ($type == 3) {
1246 /*global $dolibarr_main_url_root;*/
1247
1248 // Define $urlwithroot
1249 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($conf->file->dol_main_url_root));
1250 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1251 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1252
1253 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).$conf->file->dol_url_root[$key].'/'.$path; // Test on start with http is for old conf syntax
1254 }
1255 break;
1256 }
1257 }
1258 }
1259 }
1260
1261 return $res;
1262}
1263
1275function dol_clone($object, $native = 0)
1276{
1277 if ($native == 0) {
1278 // deprecated method, use the method with native = 2 instead
1279 $tmpsavdb = null;
1280 if (isset($object->db) && isset($object->db->db) && is_object($object->db->db) && get_class($object->db->db) == 'PgSql\Connection') {
1281 $tmpsavdb = $object->db;
1282 unset($object->db); // Such property can not be serialized with pgsl (when object->db->db = 'PgSql\Connection')
1283 }
1284
1285 $myclone = unserialize(serialize($object)); // serialize then unserialize is a hack to be sure to have a new object for all fields
1286
1287 if (!empty($tmpsavdb)) {
1288 $object->db = $tmpsavdb;
1289 }
1290 } elseif ($native == 2) {
1291 // recommended method to have a full isolated cloned object
1292 $myclone = new stdClass();
1293 $tmparray = get_object_vars($object); // return only public properties
1294
1295 if (is_array($tmparray)) {
1296 foreach ($tmparray as $propertykey => $propertyval) {
1297 if (is_scalar($propertyval) || is_array($propertyval)) {
1298 $myclone->$propertykey = $propertyval;
1299 }
1300 }
1301 }
1302 } else {
1303 $myclone = clone $object; // PHP clone is a shallow copy only, not a real clone, so properties of references will keep the reference (refering to the same target/variable)
1304 }
1305
1306 return $myclone;
1307}
1308
1318function dol_size($size, $type = '')
1319{
1320 global $conf;
1321 if (empty($conf->dol_optimize_smallscreen)) {
1322 return $size;
1323 }
1324 if ($type == 'width' && $size > 250) {
1325 return 250;
1326 } else {
1327 return 10;
1328 }
1329}
1330
1331
1343function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1)
1344{
1345 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1346 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1347 // Char '/' and '\' are file delimiters.
1348 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1349 $filesystem_forbidden_chars = array('<', '>', '/', '\\', '?', '*', '|', '"', ':', '°', '$', ';', '`');
1350 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1351 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1352 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1353 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1354 $tmp = str_replace('..', '', $tmp);
1355 return $tmp;
1356}
1357
1369function dol_sanitizePathName($str, $newstr = '_', $unaccent = 1)
1370{
1371 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1372 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1373 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1374 $filesystem_forbidden_chars = array('<', '>', '?', '*', '|', '"', '°', '$', ';', '`');
1375 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1376 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1377 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1378 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1379 $tmp = str_replace('..', '', $tmp);
1380 return $tmp;
1381}
1382
1390function dol_sanitizeUrl($stringtoclean, $type = 1)
1391{
1392 // We clean string because some hacks try to obfuscate evil strings by inserting non printable chars. Example: 'java(ascci09)scr(ascii00)ipt' is processed like 'javascript' (whatever is place of evil ascii char)
1393 // We should use dol_string_nounprintableascii but function may not be yet loaded/available
1394 $stringtoclean = preg_replace('/[\x00-\x1F\x7F]/u', '', $stringtoclean); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1395 // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: on<!-- -->error=alert(1)
1396 $stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
1397
1398 $stringtoclean = str_replace('\\', '/', $stringtoclean);
1399 if ($type == 1) {
1400 // removing : should disable links to external url like http:aaa)
1401 // removing ';' should disable "named" html entities encode into an url (we should not have this into an url)
1402 $stringtoclean = str_replace(array(':', ';', '@'), '', $stringtoclean);
1403 }
1404
1405 do {
1406 $oldstringtoclean = $stringtoclean;
1407 // removing '&colon' should disable links to external url like http:aaa)
1408 // removing '&#' should disable "numeric" html entities encode into an url (we should not have this into an url)
1409 $stringtoclean = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $stringtoclean);
1410 } while ($oldstringtoclean != $stringtoclean);
1411
1412 if ($type == 1) {
1413 // removing '//' should disable links to external url like //aaa or http//)
1414 $stringtoclean = preg_replace(array('/^[a-z]*\/\/+/i'), '', $stringtoclean);
1415 }
1416
1417 return $stringtoclean;
1418}
1419
1426function dol_sanitizeEmail($stringtoclean)
1427{
1428 do {
1429 $oldstringtoclean = $stringtoclean;
1430 $stringtoclean = str_ireplace(array('"', ':', '[', ']',"\n", "\r", '\\', '\/'), '', $stringtoclean);
1431 } while ($oldstringtoclean != $stringtoclean);
1432
1433 return $stringtoclean;
1434}
1435
1445{
1446 global $conf;
1447
1448 if (is_null($str)) {
1449 return '';
1450 }
1451
1452 if (utf8_check($str)) {
1453 if (extension_loaded('intl') && getDolGlobalString('MAIN_UNACCENT_USE_TRANSLITERATOR')) {
1454 $transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: NFC;', Transliterator::FORWARD);
1455 return $transliterator->transliterate($str);
1456 }
1457 // See http://www.utf8-chartable.de/
1458 $string = rawurlencode($str);
1459 $replacements = array(
1460 '%C3%80' => 'A', '%C3%81' => 'A', '%C3%82' => 'A', '%C3%83' => 'A', '%C3%84' => 'A', '%C3%85' => 'A',
1461 '%C3%87' => 'C',
1462 '%C3%88' => 'E', '%C3%89' => 'E', '%C3%8A' => 'E', '%C3%8B' => 'E',
1463 '%C3%8C' => 'I', '%C3%8D' => 'I', '%C3%8E' => 'I', '%C3%8F' => 'I',
1464 '%C3%91' => 'N',
1465 '%C3%92' => 'O', '%C3%93' => 'O', '%C3%94' => 'O', '%C3%95' => 'O', '%C3%96' => 'O',
1466 '%C5%A0' => 'S',
1467 '%C3%99' => 'U', '%C3%9A' => 'U', '%C3%9B' => 'U', '%C3%9C' => 'U',
1468 '%C3%9D' => 'Y', '%C5%B8' => 'y',
1469 '%C3%A0' => 'a', '%C3%A1' => 'a', '%C3%A2' => 'a', '%C3%A3' => 'a', '%C3%A4' => 'a', '%C3%A5' => 'a',
1470 '%C3%A7' => 'c',
1471 '%C3%A8' => 'e', '%C3%A9' => 'e', '%C3%AA' => 'e', '%C3%AB' => 'e',
1472 '%C3%AC' => 'i', '%C3%AD' => 'i', '%C3%AE' => 'i', '%C3%AF' => 'i',
1473 '%C3%B1' => 'n',
1474 '%C3%B2' => 'o', '%C3%B3' => 'o', '%C3%B4' => 'o', '%C3%B5' => 'o', '%C3%B6' => 'o',
1475 '%C5%A1' => 's',
1476 '%C3%B9' => 'u', '%C3%BA' => 'u', '%C3%BB' => 'u', '%C3%BC' => 'u',
1477 '%C3%BD' => 'y', '%C3%BF' => 'y'
1478 );
1479 $string = strtr($string, $replacements);
1480 return rawurldecode($string);
1481 } else {
1482 // See http://www.ascii-code.com/
1483 $string = strtr(
1484 $str,
1485 "\xC0\xC1\xC2\xC3\xC4\xC5\xC7
1486 \xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1
1487 \xD2\xD3\xD4\xD5\xD8\xD9\xDA\xDB\xDD
1488 \xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB
1489 \xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF8
1490 \xF9\xFA\xFB\xFC\xFD\xFF",
1491 "AAAAAAC
1492 EEEEIIIIDN
1493 OOOOOUUUY
1494 aaaaaaceeee
1495 iiiidnooooo
1496 uuuuyy"
1497 );
1498 $string = strtr($string, array("\xC4"=>"Ae", "\xC6"=>"AE", "\xD6"=>"Oe", "\xDC"=>"Ue", "\xDE"=>"TH", "\xDF"=>"ss", "\xE4"=>"ae", "\xE6"=>"ae", "\xF6"=>"oe", "\xFC"=>"ue", "\xFE"=>"th"));
1499 return $string;
1500 }
1501}
1502
1516function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '', $badcharstoremove = '', $keepspaces = 0)
1517{
1518 $forbidden_chars_to_replace = array("'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=", '°', '$', ';'); // more complete than dol_sanitizeFileName
1519 if (empty($keepspaces)) {
1520 $forbidden_chars_to_replace[] = " ";
1521 }
1522 $forbidden_chars_to_remove = array();
1523 //$forbidden_chars_to_remove=array("(",")");
1524
1525 if (is_array($badcharstoreplace)) {
1526 $forbidden_chars_to_replace = $badcharstoreplace;
1527 }
1528 if (is_array($badcharstoremove)) {
1529 $forbidden_chars_to_remove = $badcharstoremove;
1530 }
1531
1532 return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str));
1533}
1534
1535
1549function dol_string_nounprintableascii($str, $removetabcrlf = 1)
1550{
1551 if ($removetabcrlf) {
1552 return preg_replace('/[\x00-\x1F\x7F]/u', '', $str); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1553 } else {
1554 return preg_replace('/[\x00-\x08\x11-\x12\x14-\x1F\x7F]/u', '', $str); // /u operator should make UTF8 valid characters being ignored so are not included into the replace
1555 }
1556}
1557
1566function dol_escape_js($stringtoescape, $mode = 0, $noescapebackslashn = 0)
1567{
1568 if (is_null($stringtoescape)) {
1569 return '';
1570 }
1571
1572 // escape quotes and backslashes, newlines, etc.
1573 $substitjs = array("&#039;"=>"\\'", "\r"=>'\\r');
1574 //$substitjs['</']='<\/'; // We removed this. Should be useless.
1575 if (empty($noescapebackslashn)) {
1576 $substitjs["\n"] = '\\n';
1577 $substitjs['\\'] = '\\\\';
1578 }
1579 if (empty($mode)) {
1580 $substitjs["'"] = "\\'";
1581 $substitjs['"'] = "\\'";
1582 } elseif ($mode == 1) {
1583 $substitjs["'"] = "\\'";
1584 } elseif ($mode == 2) {
1585 $substitjs['"'] = '\\"';
1586 } elseif ($mode == 3) {
1587 $substitjs["'"] = "\\'";
1588 $substitjs['"'] = "\\\"";
1589 }
1590 return strtr($stringtoescape, $substitjs);
1591}
1592
1599function dol_escape_json($stringtoescape)
1600{
1601 return str_replace('"', '\"', $stringtoescape);
1602}
1603
1611function dol_escape_php($stringtoescape, $stringforquotes = 2)
1612{
1613 if (is_null($stringtoescape)) {
1614 return '';
1615 }
1616
1617 if ($stringforquotes == 2) {
1618 return str_replace('"', "'", $stringtoescape);
1619 }
1620 if ($stringforquotes == 1) {
1621 return str_replace("'", "\'", str_replace('"', "'", $stringtoescape));
1622 }
1623
1624 return 'Bad parameter for stringforquotes in dol_escape_php';
1625}
1626
1633function dol_escape_all($stringtoescape)
1634{
1635 return preg_replace('/[^a-z0-9_]/i', '', $stringtoescape);
1636}
1637
1644function dol_escape_xml($stringtoescape)
1645{
1646 return $stringtoescape;
1647}
1648
1656function dolPrintLabel($s)
1657{
1659}
1660
1669function dolPrintHTML($s, $allowiframe = 0)
1670{
1671 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, 'common', 0, 1);
1672}
1673
1681{
1682 // The dol_htmlentitiesbr will convert simple text into html
1683 // The dol_escape_htmltag will escape html chars.
1684 return dol_escape_htmltag(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 0, 0, 0, array('br', 'b', 'font', 'span')), 1, -1, '', 0, 1);
1685}
1686
1695function dolPrintHTMLForTextArea($s, $allowiframe = 0)
1696{
1697 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1, $allowiframe)), 1, 1, '', 0, 1);
1698}
1699
1707{
1708 return htmlspecialchars($s, ENT_COMPAT, 'UTF-8');
1709}
1710
1711
1728function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapetags = '', $escapeonlyhtmltags = 0, $cleanalsojavascript = 0)
1729{
1730 if ($noescapetags == 'common') {
1731 $noescapetags = 'html,body,a,b,em,hr,i,u,ul,li,br,div,img,font,p,span,strong,table,tr,td,th,tbody,h1,h2,h3,h4,h5,h6,h7,h8,h9';
1732 // Add also html5 tags
1733 $noescapetags .= ',header,footer,nav,section,menu,menuitem';
1734 }
1735 if ($cleanalsojavascript) {
1736 $stringtoescape = dol_string_onlythesehtmltags($stringtoescape, 0, 0, $cleanalsojavascript, 0, array(), 0);
1737 }
1738
1739 // escape quotes and backslashes, newlines, etc.
1740 if ($escapeonlyhtmltags) {
1741 $tmp = htmlspecialchars_decode((string) $stringtoescape, ENT_COMPAT);
1742 } else {
1743 $tmp = html_entity_decode((string) $stringtoescape, ENT_COMPAT, 'UTF-8');
1744 }
1745 if (!$keepb) {
1746 $tmp = strtr($tmp, array("<b>"=>'', '</b>'=>'', '<strong>'=>'', '</strong>'=>''));
1747 }
1748 if (!$keepn) {
1749 $tmp = strtr($tmp, array("\r"=>'\\r', "\n"=>'\\n'));
1750 } elseif ($keepn == -1) {
1751 $tmp = strtr($tmp, array("\r"=>'', "\n"=>''));
1752 }
1753
1754 if ($escapeonlyhtmltags) {
1755 return htmlspecialchars($tmp, ENT_COMPAT, 'UTF-8');
1756 } else {
1757 // Escape tags to keep
1758 $tmparrayoftags = array();
1759 if ($noescapetags) {
1760 $tmparrayoftags = explode(',', $noescapetags);
1761 }
1762 if (count($tmparrayoftags)) {
1763 // TODO Does not works yet when there is attributes into tag
1764 foreach ($tmparrayoftags as $tagtoreplace) {
1765 $tmp = str_ireplace('<'.$tagtoreplace.'>', '__BEGINTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1766 $tmp = str_ireplace('</'.$tagtoreplace.'>', '__ENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1767 $tmp = str_ireplace('<'.$tagtoreplace.' />', '__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1768 }
1769 }
1770
1771 $result = htmlentities($tmp, ENT_COMPAT, 'UTF-8');
1772
1773 if (count($tmparrayoftags)) {
1774 foreach ($tmparrayoftags as $tagtoreplace) {
1775 $result = str_ireplace('__BEGINTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.'>', $result);
1776 $result = str_ireplace('__ENDTAGTOREPLACE'.$tagtoreplace.'__', '</'.$tagtoreplace.'>', $result);
1777 $result = str_ireplace('__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.' />', $result);
1778 }
1779 }
1780
1781 return $result;
1782 }
1783}
1784
1792function dol_strtolower($string, $encoding = "UTF-8")
1793{
1794 if (function_exists('mb_strtolower')) {
1795 return mb_strtolower($string, $encoding);
1796 } else {
1797 return strtolower($string);
1798 }
1799}
1800
1809function dol_strtoupper($string, $encoding = "UTF-8")
1810{
1811 if (function_exists('mb_strtoupper')) {
1812 return mb_strtoupper($string, $encoding);
1813 } else {
1814 return strtoupper($string);
1815 }
1816}
1817
1826function dol_ucfirst($string, $encoding = "UTF-8")
1827{
1828 if (function_exists('mb_substr')) {
1829 return mb_strtoupper(mb_substr($string, 0, 1, $encoding), $encoding).mb_substr($string, 1, null, $encoding);
1830 } else {
1831 return ucfirst($string);
1832 }
1833}
1834
1843function dol_ucwords($string, $encoding = "UTF-8")
1844{
1845 if (function_exists('mb_convert_case')) {
1846 return mb_convert_case($string, MB_CASE_TITLE, $encoding);
1847 } else {
1848 return ucwords($string);
1849 }
1850}
1851
1873function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = '', $restricttologhandler = '', $logcontext = null)
1874{
1875 global $conf, $user, $debugbar;
1876
1877 // If syslog module enabled
1878 if (!isModEnabled('syslog')) {
1879 return;
1880 }
1881
1882 // Check if we are into execution of code of a website
1883 if (defined('USEEXTERNALSERVER') && !defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) {
1884 global $website, $websitekey;
1885 if (is_object($website) && !empty($website->ref)) {
1886 $suffixinfilename .= '_website_'.$website->ref;
1887 } elseif (!empty($websitekey)) {
1888 $suffixinfilename .= '_website_'.$websitekey;
1889 }
1890 }
1891
1892 // Check if we have a forced suffix
1893 if (defined('USESUFFIXINLOG')) {
1894 $suffixinfilename .= constant('USESUFFIXINLOG');
1895 }
1896
1897 if ($ident < 0) {
1898 foreach ($conf->loghandlers as $loghandlerinstance) {
1899 $loghandlerinstance->setIdent($ident);
1900 }
1901 }
1902
1903 if (!empty($message)) {
1904 // Test log level
1905 $logLevels = array(LOG_EMERG=>'EMERG', LOG_ALERT=>'ALERT', LOG_CRIT=>'CRITICAL', LOG_ERR=>'ERR', LOG_WARNING=>'WARN', LOG_NOTICE=>'NOTICE', LOG_INFO=>'INFO', LOG_DEBUG=>'DEBUG');
1906
1907 if (!array_key_exists($level, $logLevels)) {
1908 dol_syslog('Error Bad Log Level '.$level, LOG_ERR);
1909 $level = $logLevels[LOG_ERR];
1910 }
1911 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
1912 return;
1913 }
1914
1915 if (!getDolGlobalString('MAIN_SHOW_PASSWORD_INTO_LOG')) {
1916 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
1917 }
1918
1919 // If adding log inside HTML page is required
1920 if ((!empty($_REQUEST['logtohtml']) && getDolGlobalString('MAIN_ENABLE_LOG_TO_HTML'))
1921 || (is_object($user) && $user->hasRight('debugbar', 'read') && is_object($debugbar))) {
1922 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".$logLevels[$level]." ".$message;
1923 }
1924
1925 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
1926 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
1927 if (getDolGlobalString('MAIN_ENABLE_LOG_INLINE_HTML') && !empty($_GET["log"])) {
1928 print "\n\n<!-- Log start\n";
1929 print dol_escape_htmltag($message)."\n";
1930 print "Log end -->\n";
1931 }
1932
1933 $data = array(
1934 'message' => $message,
1935 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
1936 'level' => $level,
1937 'user' => ((is_object($user) && $user->id) ? $user->login : false),
1938 'ip' => false
1939 );
1940
1941 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
1942 if (!empty($remoteip)) {
1943 $data['ip'] = $remoteip;
1944 // This is when server run behind a reverse proxy
1945 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
1946 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
1947 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
1948 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
1949 }
1950 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
1951 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
1952 $data['ip'] = $_SERVER['SERVER_ADDR'];
1953 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
1954 // This is when PHP session is ran outside a web server, like from Windows command line (Not always defined, but useful if OS defined it).
1955 $data['ip'] = $_SERVER['COMPUTERNAME'].(empty($_SERVER['USERNAME']) ? '' : '@'.$_SERVER['USERNAME']);
1956 } elseif (!empty($_SERVER['LOGNAME'])) {
1957 // This is when PHP session is ran outside a web server, like from Linux command line (Not always defined, but usefull if OS defined it).
1958 $data['ip'] = '???@'.$_SERVER['LOGNAME'];
1959 }
1960
1961 // Loop on each log handler and send output
1962 foreach ($conf->loghandlers as $loghandlerinstance) {
1963 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
1964 continue;
1965 }
1966 $loghandlerinstance->export($data, $suffixinfilename);
1967 }
1968 unset($data);
1969 }
1970
1971 if ($ident > 0) {
1972 foreach ($conf->loghandlers as $loghandlerinstance) {
1973 $loghandlerinstance->setIdent($ident);
1974 }
1975 }
1976}
1977
1994function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
1995{
1996 global $conf;
1997
1998 if (strpos($url, '?') > 0) {
1999 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2000 } else {
2001 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
2002 }
2003
2004 $out = '';
2005
2006 $backtopagejsfieldsid = '';
2007 $backtopagejsfieldslabel = '';
2008 if ($backtopagejsfields) {
2009 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
2010 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
2011 $backtopagejsfields = $name.":".$backtopagejsfields;
2012 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
2013 } else {
2014 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
2015 }
2016 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
2017 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
2018 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
2019 }
2020
2021 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
2022 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
2023 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
2024 if (empty($conf->use_javascript_ajax)) {
2025 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
2026 } elseif ($jsonopen) {
2027 $out .= ' href="#" onclick="'.$jsonopen.'"';
2028 } else {
2029 $out .= ' href="#"';
2030 }
2031 $out .= '>'.$buttonstring.'</a>';
2032
2033 if (!empty($conf->use_javascript_ajax)) {
2034 // Add code to open url using the popup. Add also hidden field to retreive the returned variables
2035 $out .= '<!-- code to open popup and variables to retreive returned variables -->';
2036 $out .= '<div id="idfordialog'.$name.'" class="hidden">div for dialog</div>';
2037 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">div for returned id</div>';
2038 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">div for returned label</div>';
2039 $out .= '<!-- Add js code to open dialog popup on dialog -->';
2040 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
2041 jQuery(document).ready(function () {
2042 jQuery(".button_'.$name.'").click(function () {
2043 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
2044 var $tmpdialog = $(\'#idfordialog'.$name.'\');
2045 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
2046 $tmpdialog.dialog({
2047 autoOpen: false,
2048 modal: true,
2049 height: (window.innerHeight - 150),
2050 width: \'80%\',
2051 title: \''.dol_escape_js($label).'\',
2052 open: function (event, ui) {
2053 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
2054 },
2055 close: function (event, ui) {
2056 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
2057 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
2058 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
2059 if (returnedid != "" && returnedid != "div for returned id") {
2060 jQuery("#'.(empty($backtopagejsfieldsid) ? "none" : $backtopagejsfieldsid).'").val(returnedid);
2061 }
2062 if (returnedlabel != "" && returnedlabel != "div for returned label") {
2063 jQuery("#'.(empty($backtopagejsfieldslabel) ? "none" : $backtopagejsfieldslabel).'").val(returnedlabel);
2064 }
2065 }
2066 });
2067
2068 $tmpdialog.dialog(\'open\');
2069 return false;
2070 });
2071 });
2072 </script>';
2073 }
2074 return $out;
2075}
2076
2093function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2094{
2095 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2096}
2097
2114function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2115{
2116 global $conf, $langs, $hookmanager;
2117
2118 // Show title
2119 $showtitle = 1;
2120 if (!empty($conf->dol_optimize_smallscreen)) {
2121 $showtitle = 0;
2122 }
2123
2124 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2125
2126 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2127 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2128 }
2129
2130 // Show right part
2131 if ($morehtmlright) {
2132 $out .= '<div class="inline-block floatright tabsElem">'.$morehtmlright.'</div>'; // Output right area first so when space is missing, text is in front of tabs and not under.
2133 }
2134
2135 // Show title
2136 if (!empty($title) && $showtitle && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2137 $limittitle = 30;
2138 $out .= '<a class="tabTitle">';
2139 if ($picto) {
2140 $noprefix = $pictoisfullpath;
2141 if (strpos($picto, 'fontawesome_') !== false) {
2142 $noprefix = 1;
2143 }
2144 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2145 }
2146 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2147 $out .= '</a>';
2148 }
2149
2150 // Show tabs
2151
2152 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2153 $maxkey = -1;
2154 if (is_array($links) && !empty($links)) {
2155 $keys = array_keys($links);
2156 if (count($keys)) {
2157 $maxkey = max($keys);
2158 }
2159 }
2160
2161 // Show tabs
2162 // if =0 we don't use the feature
2163 if (empty($limittoshow)) {
2164 $limittoshow = (!getDolGlobalString('MAIN_MAXTABS_IN_CARD') ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2165 }
2166 if (!empty($conf->dol_optimize_smallscreen)) {
2167 $limittoshow = 2;
2168 }
2169
2170 $displaytab = 0;
2171 $nbintab = 0;
2172 $popuptab = 0;
2173 $outmore = '';
2174 for ($i = 0; $i <= $maxkey; $i++) {
2175 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2176 // If active tab is already present
2177 if ($i >= $limittoshow) {
2178 $limittoshow--;
2179 }
2180 }
2181 }
2182
2183 for ($i = 0; $i <= $maxkey; $i++) {
2184 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2185 $isactive = true;
2186 } else {
2187 $isactive = false;
2188 }
2189
2190 if ($i < $limittoshow || $isactive) {
2191 // Output entry with a visible tab
2192 $out .= '<div class="inline-block tabsElem'.($isactive ? ' tabsElemActive' : '').((!$isactive && getDolGlobalString('MAIN_HIDE_INACTIVETAB_ON_PRINT')) ? ' hideonprint' : '').'"><!-- id tab = '.(empty($links[$i][2]) ? '' : dol_escape_htmltag($links[$i][2])).' -->';
2193
2194 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2195 if (!empty($links[$i][0])) {
2196 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2197 } else {
2198 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2199 }
2200 } elseif (!empty($links[$i][1])) {
2201 //print "x $i $active ".$links[$i][2]." z";
2202 $out .= '<div class="tab tab'.($isactive ? 'active' : 'unactive').'" style="margin: 0 !important">';
2203 if (!empty($links[$i][0])) {
2204 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2205 $out .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="tab inline-block valignmiddle'.($morecss ? ' '.$morecss : '').(!empty($links[$i][5]) ? ' '.$links[$i][5] : '').'" href="'.$links[$i][0].'" title="'.dol_escape_htmltag($titletoshow).'">';
2206 }
2207 $out .= $links[$i][1];
2208 if (!empty($links[$i][0])) {
2209 $out .= '</a>'."\n";
2210 }
2211 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2212 $out .= '</div>';
2213 }
2214
2215 $out .= '</div>';
2216 } else {
2217 // Add entry into the combo popup with the other tabs
2218 if (!$popuptab) {
2219 $popuptab = 1;
2220 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2221 }
2222 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2223 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2224 if (!empty($links[$i][0])) {
2225 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2226 } else {
2227 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2228 }
2229 } elseif (!empty($links[$i][1])) {
2230 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2231 $outmore .= preg_replace('/([a-z])\|([a-z])/i', '\\1 | \\2', $links[$i][1]); // Replace x|y with x | y to allow wrap on long composed texts.
2232 $outmore .= '</a>'."\n";
2233 }
2234 $outmore .= '</div>';
2235
2236 $nbintab++;
2237 }
2238 $displaytab = $i;
2239 }
2240 if ($popuptab) {
2241 $outmore .= '</div>';
2242 }
2243
2244 if ($popuptab) { // If there is some tabs not shown
2245 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2246 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2247 $widthofpopup = 200;
2248
2249 $tabsname = $moretabssuffix;
2250 if (empty($tabsname)) {
2251 $tabsname = str_replace("@", "", $picto);
2252 }
2253 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2254 $out .= '<div class="tab valignmiddle"><a href="#" class="tab moretab inline-block tabunactive valignmiddle"><span class="hideonsmartphone">'.$langs->trans("More").'</span>... ('.$nbintab.')</a></div>'; // Do not use "reposition" class in the "More".
2255 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2256 $out .= $outmore;
2257 $out .= '</div>';
2258 $out .= '<div></div>';
2259 $out .= "</div>\n";
2260
2261 $out .= '<script nonce="'.getNonce().'">';
2262 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2263 var x = this.offsetLeft, y = this.offsetTop;
2264 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2265 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2266 $('#moretabsList".$tabsname."').css('".$right."','8px');
2267 }
2268 $('#moretabsList".$tabsname."').css('".$left."','auto');
2269 });
2270 ";
2271 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2272 $out .= "</script>";
2273 }
2274
2275 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2276 $out .= "</div>\n";
2277 }
2278
2279 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2280 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom'))).'">'."\n";
2281 }
2282 if (!empty($dragdropfile)) {
2283 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2284 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2285 }
2286 $parameters = array('tabname' => $active, 'out' => $out);
2287 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2288 if ($reshook > 0) {
2289 $out = $hookmanager->resPrint;
2290 }
2291
2292 return $out;
2293}
2294
2302function dol_fiche_end($notab = 0)
2303{
2304 print dol_get_fiche_end($notab);
2305}
2306
2313function dol_get_fiche_end($notab = 0)
2314{
2315 if (!$notab || $notab == -1) {
2316 return "\n</div>\n";
2317 } else {
2318 return '';
2319 }
2320}
2321
2341function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2342{
2343 global $conf, $form, $user, $langs, $hookmanager, $action;
2344
2345 $error = 0;
2346
2347 $maxvisiblephotos = 1;
2348 $showimage = 1;
2349 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2350 $showbarcode = empty($conf->barcode->enabled) ? 0 : (empty($object->barcode) ? 0 : 1);
2351 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2352 $showbarcode = 0;
2353 }
2354 $modulepart = 'unknown';
2355
2356 if ($object->element == 'societe' || $object->element == 'contact' || $object->element == 'product' || $object->element == 'ticket') {
2357 $modulepart = $object->element;
2358 } elseif ($object->element == 'member') {
2359 $modulepart = 'memberphoto';
2360 } elseif ($object->element == 'user') {
2361 $modulepart = 'userphoto';
2362 }
2363
2364 if (class_exists("Imagick")) {
2365 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2366 $modulepart = $object->element;
2367 } elseif ($object->element == 'fichinter') {
2368 $modulepart = 'ficheinter';
2369 } elseif ($object->element == 'contrat') {
2370 $modulepart = 'contract';
2371 } elseif ($object->element == 'order_supplier') {
2372 $modulepart = 'supplier_order';
2373 } elseif ($object->element == 'invoice_supplier') {
2374 $modulepart = 'supplier_invoice';
2375 }
2376 }
2377
2378 if ($object->element == 'product') {
2379 $width = 80;
2380 $cssclass = 'photowithmargin photoref';
2381 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2382 $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : 5);
2383 if ($conf->browser->layout == 'phone') {
2384 $maxvisiblephotos = 1;
2385 }
2386 if ($showimage) {
2387 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$object->show_photos('product', $conf->product->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, 0, $width, 0, '').'</div>';
2388 } else {
2389 if (getDolGlobalString('PRODUCT_NODISPLAYIFNOPHOTO')) {
2390 $nophoto = '';
2391 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2392 } else { // Show no photo link
2393 $nophoto = '/public/theme/common/nophoto.png';
2394 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" title="'.dol_escape_htmltag($langs->trans("UploadAnImageToSeeAPhotoHere", $langs->transnoentitiesnoconv("Documents"))).'" alt="No photo"'.($width ? ' style="width: '.$width.'px"' : '').' src="'.DOL_URL_ROOT.$nophoto.'"></div>';
2395 }
2396 }
2397 } elseif ($object->element == 'ticket') {
2398 $width = 80;
2399 $cssclass = 'photoref';
2400 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2401 $maxvisiblephotos = (isset($conf->global->TICKET_MAX_VISIBLE_PHOTO) ? $conf->global->TICKET_MAX_VISIBLE_PHOTO : 2);
2402 if ($conf->browser->layout == 'phone') {
2403 $maxvisiblephotos = 1;
2404 }
2405
2406 if ($showimage) {
2407 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2408 if ($object->nbphoto > 0) {
2409 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2410 } else {
2411 $showimage = 0;
2412 }
2413 }
2414 if (!$showimage) {
2415 if (getDolGlobalString('TICKET_NODISPLAYIFNOPHOTO')) {
2416 $nophoto = '';
2417 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2418 } else { // Show no photo link
2419 $nophoto = img_picto('No photo', 'object_ticket');
2420 $morehtmlleft .= '<!-- No photo to show -->';
2421 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2422 $morehtmlleft .= $nophoto;
2423 $morehtmlleft .= '</div></div>';
2424 }
2425 }
2426 } else {
2427 if ($showimage) {
2428 if ($modulepart != 'unknown') {
2429 $phototoshow = '';
2430 // Check if a preview file is available
2431 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2432 $objectref = dol_sanitizeFileName($object->ref);
2433 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2434 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2435 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2436 $subdir .= ((!empty($subdir) && !preg_match('/\/$/', $subdir)) ? '/' : '').$objectref; // the objectref dir is not included into get_exdir when used with level=2, so we add it at end
2437 } else {
2438 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2439 }
2440 if (empty($subdir)) {
2441 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2442 }
2443
2444 $filepath = $dir_output.$subdir."/";
2445
2446 $filepdf = $filepath.$objectref.".pdf";
2447 $relativepath = $subdir.'/'.$objectref.'.pdf';
2448
2449 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2450 $fileimage = $filepdf.'_preview.png';
2451 $relativepathimage = $relativepath.'_preview.png';
2452
2453 $pdfexists = file_exists($filepdf);
2454
2455 // If PDF file exists
2456 if ($pdfexists) {
2457 // Conversion du PDF en image png si fichier png non existant
2458 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2459 if (!getDolGlobalString('MAIN_DISABLE_PDF_THUMBS')) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2460 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2461 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2462 if ($ret < 0) {
2463 $error++;
2464 }
2465 }
2466 }
2467 }
2468
2469 if ($pdfexists && !$error) {
2470 $heightforphotref = 80;
2471 if (!empty($conf->dol_optimize_smallscreen)) {
2472 $heightforphotref = 60;
2473 }
2474 // If the preview file is found
2475 if (file_exists($fileimage)) {
2476 $phototoshow = '<div class="photoref">';
2477 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2478 $phototoshow .= '</div>';
2479 }
2480 }
2481 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo'
2482 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2483 }
2484
2485 if ($phototoshow) {
2486 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2487 $morehtmlleft .= $phototoshow;
2488 $morehtmlleft .= '</div>';
2489 }
2490 }
2491
2492 if (empty($phototoshow)) { // Show No photo link (picto of object)
2493 if ($object->element == 'action') {
2494 $width = 80;
2495 $cssclass = 'photorefcenter';
2496 $nophoto = img_picto('No photo', 'title_agenda');
2497 } else {
2498 $width = 14;
2499 $cssclass = 'photorefcenter';
2500 $picto = $object->picto;
2501 $prefix = 'object_';
2502 if ($object->element == 'project' && !$object->public) {
2503 $picto = 'project'; // instead of projectpub
2504 }
2505 if (strpos($picto, 'fontawesome_') !== false) {
2506 $prefix = '';
2507 }
2508 $nophoto = img_picto('No photo', $prefix.$picto);
2509 }
2510 $morehtmlleft .= '<!-- No photo to show -->';
2511 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2512 $morehtmlleft .= $nophoto;
2513 $morehtmlleft .= '</div></div>';
2514 }
2515 }
2516 }
2517
2518 // Show barcode
2519 if ($showbarcode) {
2520 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2521 }
2522
2523 if ($object->element == 'societe') {
2524 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2525 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2526 } else {
2527 $morehtmlstatus .= $object->getLibStatut(6);
2528 }
2529 } elseif ($object->element == 'product') {
2530 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2531 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2532 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2533 } else {
2534 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2535 }
2536 $morehtmlstatus .= ' &nbsp; ';
2537 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2538 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && getDolGlobalString('MAIN_DIRECT_STATUS_UPDATE')) {
2539 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2540 } else {
2541 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2542 }
2543 } elseif (in_array($object->element, array('salary'))) {
2544 $tmptxt = $object->getLibStatut(6, $object->alreadypaid);
2545 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2546 $tmptxt = $object->getLibStatut(5, $object->alreadypaid);
2547 }
2548 $morehtmlstatus .= $tmptxt;
2549 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier'))) { // TODO Move this to use ->alreadypaid
2550 $totalallpayments = $object->getSommePaiement(0);
2551 $totalallpayments += $object->getSumCreditNotesUsed(0);
2552 $totalallpayments += $object->getSumDepositsUsed(0);
2553 $tmptxt = $object->getLibStatut(6, $totalallpayments);
2554 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2555 $tmptxt = $object->getLibStatut(5, $totalallpayments);
2556 }
2557 $morehtmlstatus .= $tmptxt;
2558 } elseif (in_array($object->element, array('chargesociales', 'loan', 'tva'))) { // TODO Move this to use ->alreadypaid
2559 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2560 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2561 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2562 }
2563 $morehtmlstatus .= $tmptxt;
2564 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2565 if ($object->statut == 0) {
2566 $morehtmlstatus .= $object->getLibStatut(5);
2567 } else {
2568 $morehtmlstatus .= $object->getLibStatut(4);
2569 }
2570 } elseif ($object->element == 'facturerec') {
2571 if ($object->frequency == 0) {
2572 $morehtmlstatus .= $object->getLibStatut(2);
2573 } else {
2574 $morehtmlstatus .= $object->getLibStatut(5);
2575 }
2576 } elseif ($object->element == 'project_task') {
2577 $object->fk_statut = 1;
2578 if ($object->progress > 0) {
2579 $object->fk_statut = 2;
2580 }
2581 if ($object->progress >= 100) {
2582 $object->fk_statut = 3;
2583 }
2584 $tmptxt = $object->getLibStatut(5);
2585 $morehtmlstatus .= $tmptxt; // No status on task
2586 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2587 $tmptxt = $object->getLibStatut(6);
2588 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2589 $tmptxt = $object->getLibStatut(5);
2590 }
2591 $morehtmlstatus .= $tmptxt;
2592 }
2593
2594 // Add if object was dispatched "into accountancy"
2595 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2596 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2597 if (method_exists($object, 'getVentilExportCompta')) {
2598 $accounted = $object->getVentilExportCompta();
2599 $langs->load("accountancy");
2600 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2601 }
2602 }
2603
2604 // Add alias for thirdparty
2605 if (!empty($object->name_alias)) {
2606 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
2607 }
2608
2609 // Add label
2610 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
2611 if (!empty($object->label)) {
2612 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
2613 }
2614 }
2615
2616 // Show address and email
2617 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
2618 $moreaddress = $object->getBannerAddress('refaddress', $object); // address, email, url, social networks
2619 if ($moreaddress) {
2620 $morehtmlref .= '<div class="refidno refaddress">';
2621 $morehtmlref .= $moreaddress;
2622 $morehtmlref .= '</div>';
2623 }
2624 }
2625 if (getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') && (getDolGlobalString('MAIN_SHOW_TECHNICAL_ID') == '1' || preg_match('/'.preg_quote($object->element, '/').'/i', $conf->global->MAIN_SHOW_TECHNICAL_ID)) && !empty($object->id)) {
2626 $morehtmlref .= '<div style="clear: both;"></div>';
2627 $morehtmlref .= '<div class="refidno opacitymedium">';
2628 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
2629 $morehtmlref .= '</div>';
2630 }
2631
2632 $parameters=array('morehtmlref'=>$morehtmlref);
2633 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
2634 if ($reshook < 0) {
2635 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2636 } elseif (empty($reshook)) {
2637 $morehtmlref .= $hookmanager->resPrint;
2638 } elseif ($reshook > 0) {
2639 $morehtmlref = $hookmanager->resPrint;
2640 }
2641
2642 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
2643 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
2644 print '</div>';
2645 print '<div class="underrefbanner clearboth"></div>';
2646}
2647
2657function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
2658{
2659 global $langs;
2660 $ret = '';
2661 if ($fieldrequired) {
2662 $ret .= '<span class="fieldrequired">';
2663 }
2664 $ret .= '<label for="'.$fieldkey.'">';
2665 $ret .= $langs->trans($langkey);
2666 $ret .= '</label>';
2667 if ($fieldrequired) {
2668 $ret .= '</span>';
2669 }
2670 return $ret;
2671}
2672
2680function dol_bc($var, $moreclass = '')
2681{
2682 global $bc;
2683 $ret = ' '.$bc[$var];
2684 if ($moreclass) {
2685 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
2686 }
2687 return $ret;
2688}
2689
2703function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = '', $mode = 0, $extralangcode = '')
2704{
2705 global $conf, $langs, $hookmanager;
2706
2707 $ret = '';
2708 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
2709
2710 // See format of addresses on https://en.wikipedia.org/wiki/Address
2711 // Address
2712 if (empty($mode)) {
2713 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
2714 }
2715 // Zip/Town/State
2716 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || getDolGlobalString('MAIN_FORCE_STATE_INTO_ADDRESS')) {
2717 // US: title firstname name \n address lines \n town, state, zip \n country
2718 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2719 $ret .= (($ret && $town) ? $sep : '').$town;
2720
2721 if (!empty($object->state)) {
2722 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
2723 }
2724 if (!empty($object->zip)) {
2725 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
2726 }
2727 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
2728 // UK: title firstname name \n address lines \n town state \n zip \n country
2729 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2730 $ret .= ($ret ? $sep : '').$town;
2731 if (!empty($object->state)) {
2732 $ret .= ($ret ? ", " : '').$object->state;
2733 }
2734 if (!empty($object->zip)) {
2735 $ret .= ($ret ? $sep : '').$object->zip;
2736 }
2737 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
2738 // ES: title firstname name \n address lines \n zip town \n state \n country
2739 $ret .= ($ret ? $sep : '').$object->zip;
2740 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2741 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2742 if (!empty($object->state)) {
2743 $ret .= $sep.$object->state;
2744 }
2745 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
2746 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
2747 // See https://www.sljfaq.org/afaq/addresses.html
2748 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2749 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
2750 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
2751 // IT: title firstname name\n address lines \n zip town state_code \n country
2752 $ret .= ($ret ? $sep : '').$object->zip;
2753 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2754 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2755 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
2756 } else {
2757 // Other: title firstname name \n address lines \n zip town[, state] \n country
2758 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2759 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
2760 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
2761 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
2762 $ret .= ($ret ? ", " : '').$object->state;
2763 }
2764 }
2765
2766 if (!is_object($outputlangs)) {
2767 $outputlangs = $langs;
2768 }
2769 if ($withcountry) {
2770 $langs->load("dict");
2771 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
2772 }
2773 if ($hookmanager) {
2774 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
2775 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
2776 if ($reshook > 0) {
2777 $ret = '';
2778 }
2779 $ret .= $hookmanager->resPrint;
2780 }
2781
2782 return $ret;
2783}
2784
2785
2786
2795function dol_strftime($fmt, $ts = false, $is_gmt = false)
2796{
2797 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
2798 return ($is_gmt) ? @gmstrftime($fmt, $ts) : @strftime($fmt, $ts);
2799 } else {
2800 return 'Error date into a not supported range';
2801 }
2802}
2803
2825function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = '', $encodetooutput = false)
2826{
2827 global $conf, $langs;
2828
2829 // If date undefined or "", we return ""
2830 if (dol_strlen($time) == 0) {
2831 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
2832 }
2833
2834 if ($tzoutput === 'auto') {
2835 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
2836 }
2837
2838 // Clean parameters
2839 $to_gmt = false;
2840 $offsettz = $offsetdst = 0;
2841 if ($tzoutput) {
2842 $to_gmt = true; // For backward compatibility
2843 if (is_string($tzoutput)) {
2844 if ($tzoutput == 'tzserver') {
2845 $to_gmt = false;
2846 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
2847 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
2848 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
2849 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
2850 $to_gmt = true;
2851 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
2852
2853 if (class_exists('DateTimeZone')) {
2854 $user_date_tz = new DateTimeZone($offsettzstring);
2855 $user_dt = new DateTime();
2856 $user_dt->setTimezone($user_date_tz);
2857 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
2858 $offsettz = $user_dt->getOffset(); // should include dst ?
2859 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
2860 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
2861 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
2862 }
2863 }
2864 }
2865 }
2866 if (!is_object($outputlangs)) {
2867 $outputlangs = $langs;
2868 }
2869 if (!$format) {
2870 $format = 'daytextshort';
2871 }
2872
2873 // Do we have to reduce the length of date (year on 2 chars) to save space.
2874 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
2875 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour', 'dayhoursec'))) ? 1 : 0; // Test on original $format param.
2876 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
2877 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
2878 if ($formatwithoutreduce != $format) {
2879 $format = $formatwithoutreduce;
2880 $reduceformat = 1;
2881 } // so format 'dayreduceformat' is processed like day
2882
2883 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
2884 // TODO Add format daysmallyear and dayhoursmallyear
2885 if ($format == 'day') {
2886 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
2887 } elseif ($format == 'hour') {
2888 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
2889 } elseif ($format == 'hourduration') {
2890 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
2891 } elseif ($format == 'daytext') {
2892 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
2893 } elseif ($format == 'daytextshort') {
2894 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
2895 } elseif ($format == 'dayhour') {
2896 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
2897 } elseif ($format == 'dayhoursec') {
2898 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
2899 } elseif ($format == 'dayhourtext') {
2900 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
2901 } elseif ($format == 'dayhourtextshort') {
2902 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
2903 } elseif ($format == 'dayhourlog') {
2904 // Format not sensitive to language
2905 $format = '%Y%m%d%H%M%S';
2906 } elseif ($format == 'dayhourlogsmall') {
2907 // Format not sensitive to language
2908 $format = '%y%m%d%H%M';
2909 } elseif ($format == 'dayhourldap') {
2910 $format = '%Y%m%d%H%M%SZ';
2911 } elseif ($format == 'dayhourxcard') {
2912 $format = '%Y%m%dT%H%M%SZ';
2913 } elseif ($format == 'dayxcard') {
2914 $format = '%Y%m%d';
2915 } elseif ($format == 'dayrfc') {
2916 $format = '%Y-%m-%d'; // DATE_RFC3339
2917 } elseif ($format == 'dayhourrfc') {
2918 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
2919 } elseif ($format == 'standard') {
2920 $format = '%Y-%m-%d %H:%M:%S';
2921 }
2922
2923 if ($reduceformat) {
2924 $format = str_replace('%Y', '%y', $format);
2925 $format = str_replace('yyyy', 'yy', $format);
2926 }
2927
2928 // Clean format
2929 if (preg_match('/%b/i', $format)) { // There is some text to translate
2930 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2931 $format = str_replace('%b', '__b__', $format);
2932 $format = str_replace('%B', '__B__', $format);
2933 }
2934 if (preg_match('/%a/i', $format)) { // There is some text to translate
2935 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2936 $format = str_replace('%a', '__a__', $format);
2937 $format = str_replace('%A', '__A__', $format);
2938 }
2939
2940 // Analyze date
2941 $reg = array();
2942 if (preg_match('/^([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])$/i', $time, $reg)) { // Deprecated. Ex: 1970-01-01, 1970-01-01 01:00:00, 19700101010000
2943 dol_print_error('', "Functions.lib::dol_print_date function called with a bad value from page ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]));
2944 return '';
2945 } elseif (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?/i', $time, $reg)) { // Still available to solve problems in extrafields of type date
2946 // This part of code should not be used anymore.
2947 dol_syslog("Functions.lib::dol_print_date function called with a bad value from page ".(empty($_SERVER["PHP_SELF"]) ? 'unknown' : $_SERVER["PHP_SELF"]), LOG_WARNING);
2948 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
2949 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
2950 $syear = (!empty($reg[1]) ? $reg[1] : '');
2951 $smonth = (!empty($reg[2]) ? $reg[2] : '');
2952 $sday = (!empty($reg[3]) ? $reg[3] : '');
2953 $shour = (!empty($reg[4]) ? $reg[4] : '');
2954 $smin = (!empty($reg[5]) ? $reg[5] : '');
2955 $ssec = (!empty($reg[6]) ? $reg[6] : '');
2956
2957 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
2958
2959 if ($to_gmt) {
2960 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2961 } else {
2962 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2963 }
2964 $dtts = new DateTime();
2965 $dtts->setTimestamp($time);
2966 $dtts->setTimezone($tzo);
2967 $newformat = str_replace(
2968 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2969 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2970 $format
2971 );
2972 $ret = $dtts->format($newformat);
2973 $ret = str_replace(
2974 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2975 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2976 $ret
2977 );
2978 } else {
2979 // Date is a timestamps
2980 if ($time < 100000000000) { // Protection against bad date values
2981 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2982
2983 if ($to_gmt) {
2984 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2985 } else {
2986 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2987 }
2988 $dtts = new DateTime();
2989 $dtts->setTimestamp($timetouse);
2990 $dtts->setTimezone($tzo);
2991 $newformat = str_replace(
2992 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2993 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2994 $format
2995 );
2996 $ret = $dtts->format($newformat);
2997 $ret = str_replace(
2998 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2999 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
3000 $ret
3001 );
3002 //var_dump($ret);exit;
3003 } else {
3004 $ret = 'Bad value '.$time.' for date';
3005 }
3006 }
3007
3008 if (preg_match('/__b__/i', $format)) {
3009 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
3010
3011 if ($to_gmt) {
3012 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
3013 } else {
3014 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
3015 }
3016 $dtts = new DateTime();
3017 $dtts->setTimestamp($timetouse);
3018 $dtts->setTimezone($tzo);
3019 $month = $dtts->format("m");
3020 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
3021 if ($encodetooutput) {
3022 $monthtext = $outputlangs->transnoentities('Month'.$month);
3023 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
3024 } else {
3025 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
3026 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
3027 }
3028 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
3029 $ret = str_replace('__b__', $monthtextshort, $ret);
3030 $ret = str_replace('__B__', $monthtext, $ret);
3031 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
3032 //return $ret;
3033 }
3034 if (preg_match('/__a__/i', $format)) {
3035 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
3036 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
3037
3038 if ($to_gmt) {
3039 $tzo = new DateTimeZone('UTC');
3040 } else {
3041 $tzo = new DateTimeZone(date_default_timezone_get());
3042 }
3043 $dtts = new DateTime();
3044 $dtts->setTimestamp($timetouse);
3045 $dtts->setTimezone($tzo);
3046 $w = $dtts->format("w");
3047 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
3048
3049 $ret = str_replace('__A__', $dayweek, $ret);
3050 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
3051 }
3052
3053 return $ret;
3054}
3055
3056
3077function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
3078{
3079 if ($timestamp === '') {
3080 return array();
3081 }
3082
3083 $datetimeobj = new DateTime();
3084 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
3085 if ($forcetimezone) {
3086 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
3087 }
3088 $arrayinfo = array(
3089 'year'=>((int) date_format($datetimeobj, 'Y')),
3090 'mon'=>((int) date_format($datetimeobj, 'm')),
3091 'mday'=>((int) date_format($datetimeobj, 'd')),
3092 'wday'=>((int) date_format($datetimeobj, 'w')),
3093 'yday'=>((int) date_format($datetimeobj, 'z')),
3094 'hours'=>((int) date_format($datetimeobj, 'H')),
3095 'minutes'=>((int) date_format($datetimeobj, 'i')),
3096 'seconds'=>((int) date_format($datetimeobj, 's')),
3097 '0'=>$timestamp
3098 );
3099
3100 return $arrayinfo;
3101}
3102
3124function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3125{
3126 global $conf;
3127 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3128
3129 if ($gm === 'auto') {
3130 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3131 }
3132 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3133
3134 // Clean parameters
3135 if ($hour == -1 || empty($hour)) {
3136 $hour = 0;
3137 }
3138 if ($minute == -1 || empty($minute)) {
3139 $minute = 0;
3140 }
3141 if ($second == -1 || empty($second)) {
3142 $second = 0;
3143 }
3144
3145 // Check parameters
3146 if ($check) {
3147 if (!$month || !$day) {
3148 return '';
3149 }
3150 if ($day > 31) {
3151 return '';
3152 }
3153 if ($month > 12) {
3154 return '';
3155 }
3156 if ($hour < 0 || $hour > 24) {
3157 return '';
3158 }
3159 if ($minute < 0 || $minute > 60) {
3160 return '';
3161 }
3162 if ($second < 0 || $second > 60) {
3163 return '';
3164 }
3165 }
3166
3167 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3168 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3169 $localtz = new DateTimeZone($default_timezone);
3170 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3171 // We use dol_tz_string first because it is more reliable.
3172 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3173 try {
3174 $localtz = new DateTimeZone($default_timezone);
3175 } catch (Exception $e) {
3176 dol_syslog("Warning dol_tz_string contains an invalid value ".$_SESSION["dol_tz_string"], LOG_WARNING);
3177 $default_timezone = @date_default_timezone_get();
3178 }
3179 } elseif (strrpos($gm, "tz,") !== false) {
3180 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3181 try {
3182 $localtz = new DateTimeZone($timezone);
3183 } catch (Exception $e) {
3184 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3185 }
3186 }
3187
3188 if (empty($localtz)) {
3189 $localtz = new DateTimeZone('UTC');
3190 }
3191 //var_dump($localtz);
3192 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3193 $dt = new DateTime('now', $localtz);
3194 $dt->setDate((int) $year, (int) $month, (int) $day);
3195 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3196 $date = $dt->getTimestamp(); // should include daylight saving time
3197 //var_dump($date);
3198 return $date;
3199}
3200
3201
3212function dol_now($mode = 'auto')
3213{
3214 $ret = 0;
3215
3216 if ($mode === 'auto') {
3217 $mode = 'gmt';
3218 }
3219
3220 if ($mode == 'gmt') {
3221 $ret = time(); // Time for now at greenwich.
3222 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3223 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3224 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3225 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3226 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3227 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3228 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3229 // $ret=dol_now('gmt')+($tzsecond*3600);
3230 //}
3231 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3232 // Time for now with user timezone added
3233 //print 'time: '.time();
3234 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3235 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3236 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3237 }
3238
3239 return $ret;
3240}
3241
3242
3251function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3252{
3253 global $conf, $langs;
3254 $level = 1024;
3255
3256 if (!empty($conf->dol_optimize_smallscreen)) {
3257 $shortunit = 1;
3258 }
3259
3260 // Set value text
3261 if (empty($shortvalue) || $size < ($level * 10)) {
3262 $ret = $size;
3263 $textunitshort = $langs->trans("b");
3264 $textunitlong = $langs->trans("Bytes");
3265 } else {
3266 $ret = round($size / $level, 0);
3267 $textunitshort = $langs->trans("Kb");
3268 $textunitlong = $langs->trans("KiloBytes");
3269 }
3270 // Use long or short text unit
3271 if (empty($shortunit)) {
3272 $ret .= ' '.$textunitlong;
3273 } else {
3274 $ret .= ' '.$textunitshort;
3275 }
3276
3277 return $ret;
3278}
3279
3290function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = '')
3291{
3292 global $langs;
3293
3294 if (empty($url)) {
3295 return '';
3296 }
3297
3298 $linkstart = '<a href="';
3299 if (!preg_match('/^http/i', $url)) {
3300 $linkstart .= 'http://';
3301 }
3302 $linkstart .= $url;
3303 $linkstart .= '"';
3304 if ($target) {
3305 $linkstart .= ' target="'.$target.'"';
3306 }
3307 $linkstart .= ' title="'.$langs->trans("URL").': '.$url.'"';
3308 $linkstart .= '>';
3309
3310 $link = '';
3311 if (!preg_match('/^http/i', $url)) {
3312 $link .= 'http://';
3313 }
3314 $link .= dol_trunc($url, $max);
3315
3316 $linkend = '</a>';
3317
3318 if ($morecss == 'float') { // deprecated
3319 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto($langs->trans("Url"), 'globe', 'class="paddingrightonly"') : '').$link.'</div>';
3320 } else {
3321 return $linkstart.'<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ? img_picto('', 'globe', 'class="paddingrightonly"') : '').$link.'</span>'.$linkend;
3322 }
3323}
3324
3337function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3338{
3339 global $user, $langs, $hookmanager;
3340
3341 //global $conf; $conf->global->AGENDA_ADDACTIONFOREMAIL = 1;
3342 //$showinvalid = 1; $email = 'rrrrr';
3343
3344 $newemail = dol_escape_htmltag($email);
3345
3346 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && $withpicto) {
3347 $withpicto = 0;
3348 }
3349
3350 if (empty($email)) {
3351 return '&nbsp;';
3352 }
3353
3354 if (!empty($addlink)) {
3355 $newemail = '<a class="paddingrightonly" style="text-overflow: ellipsis;" href="';
3356 if (!preg_match('/^mailto:/i', $email)) {
3357 $newemail .= 'mailto:';
3358 }
3359 $newemail .= $email;
3360 $newemail .= '">';
3361
3362 $newemail .= ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '');
3363
3364 $newemail .= dol_trunc($email, $max);
3365 $newemail .= '</a>';
3366 if ($showinvalid && !isValidEmail($email)) {
3367 $langs->load("errors");
3368 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email), '', 'paddingrightonly');
3369 }
3370
3371 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3372 $type = 'AC_EMAIL';
3373 $linktoaddaction = '';
3374 if (getDolGlobalString('AGENDA_ADDACTIONFOREMAIL')) {
3375 $linktoaddaction = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.urlencode($type).'&amp;contactid='.((int) $cid).'&amp;socid='.((int) $socid).'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3376 }
3377 if ($linktoaddaction) {
3378 $newemail = '<div>'.$newemail.' '.$linktoaddaction.'</div>';
3379 }
3380 }
3381 } else {
3382 $newemail = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3383
3384 if ($showinvalid && !isValidEmail($email)) {
3385 $langs->load("errors");
3386 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3387 }
3388 }
3389
3390 //$rep = '<div class="nospan" style="margin-right: 10px">';
3391 //$rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto), 'class="paddingrightonly"') : '').$newemail;
3392 //$rep .= '</div>';
3393 $rep = $newemail;
3394
3395 if ($hookmanager) {
3396 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3397
3398 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3399 if ($reshook > 0) {
3400 $rep = '';
3401 }
3402 $rep .= $hookmanager->resPrint;
3403 }
3404
3405 return $rep;
3406}
3407
3414{
3415 global $conf, $db;
3416
3417 $socialnetworks = array();
3418 // Enable caching of array
3419 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3420 $cachekey = 'socialnetworks_' . $conf->entity;
3421 $dataretrieved = dol_getcache($cachekey);
3422 if (!is_null($dataretrieved)) {
3423 $socialnetworks = $dataretrieved;
3424 } else {
3425 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3426 $sql .= " WHERE entity=".$conf->entity;
3427 $resql = $db->query($sql);
3428 if ($resql) {
3429 while ($obj = $db->fetch_object($resql)) {
3430 $socialnetworks[$obj->code] = array(
3431 'rowid' => $obj->rowid,
3432 'label' => $obj->label,
3433 'url' => $obj->url,
3434 'icon' => $obj->icon,
3435 'active' => $obj->active,
3436 );
3437 }
3438 }
3439 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3440 }
3441
3442 return $socialnetworks;
3443}
3444
3455function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3456{
3457 global $conf, $user, $langs;
3458
3459 $htmllink = $value;
3460
3461 if (empty($value)) {
3462 return '&nbsp;';
3463 }
3464
3465 if (!empty($type)) {
3466 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3467 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3468 $htmllink .= '<span class="fab pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3469 if ($type == 'skype') {
3470 $htmllink .= dol_escape_htmltag($value);
3471 $htmllink .= '&nbsp; <a href="skype:';
3472 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3473 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3474 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3475 $htmllink .= '</a><a href="skype:';
3476 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3477 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3478 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3479 $htmllink .= '</a>';
3480 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3481 $addlink = 'AC_SKYPE';
3482 $link = '';
3483 if (getDolGlobalString('AGENDA_ADDACTIONFORSKYPE')) {
3484 $link = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.$addlink.'&amp;contactid='.$cid.'&amp;socid='.$socid.'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3485 }
3486 $htmllink .= ($link ? ' '.$link : '');
3487 }
3488 } else {
3489 $networkconstname = 'MAIN_INFO_SOCIETE_'.strtoupper($type).'_URL';
3490 if (getDolGlobalString($networkconstname)) {
3491 $link = str_replace('{socialid}', $value, getDolGlobalString($networkconstname));
3492 if (preg_match('/^https?:\/\//i', $link)) {
3493 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3494 } else {
3495 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3496 }
3497 } elseif (!empty($dictsocialnetworks[$type]['url'])) {
3498 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3499 if ($tmpvirginurl) {
3500 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3501 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3502
3503 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3504 if ($tmpvirginurl3) {
3505 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3506 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3507 }
3508
3509 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3510 if ($tmpvirginurl2) {
3511 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3512 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3513 }
3514 }
3515 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3516 if (preg_match('/^https?:\/\//i', $link)) {
3517 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3518 } else {
3519 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3520 }
3521 } else {
3522 $htmllink .= dol_escape_htmltag($value);
3523 }
3524 }
3525 $htmllink .= '</div>';
3526 } else {
3527 $langs->load("errors");
3528 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3529 }
3530 return $htmllink;
3531}
3532
3542function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1)
3543{
3544 global $mysoc;
3545
3546 if (empty($profID) || empty($profIDtype)) {
3547 return '';
3548 }
3549 if (empty($countrycode)) {
3550 $countrycode = $mysoc->country_code;
3551 }
3552 $newProfID = $profID;
3553 $id = substr($profIDtype, -1);
3554 $ret = '';
3555 if (strtoupper($countrycode) == 'FR') {
3556 // France
3557 // (see https://www.economie.gouv.fr/entreprises/numeros-identification-entreprise)
3558
3559 if ($id == 1 && dol_strlen($newProfID) == 9) {
3560 // SIREN (ex: 123 123 123)
3561 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3);
3562 }
3563 if ($id == 2 && dol_strlen($newProfID) == 14) {
3564 // SIRET (ex: 123 123 123 12345)
3565 $newProfID = substr($newProfID, 0, 3).' '.substr($newProfID, 3, 3).' '.substr($newProfID, 6, 3).' '.substr($newProfID, 9, 5);
3566 }
3567 if ($id == 3 && dol_strlen($newProfID) == 5) {
3568 // NAF/APE (ex: 69.20Z)
3569 $newProfID = substr($newProfID, 0, 2).'.'.substr($newProfID, 2, 3);
3570 }
3571 if ($profIDtype === 'VAT' && dol_strlen($newProfID) == 13) {
3572 // TVA intracommunautaire (ex: FR12 123 123 123)
3573 $newProfID = substr($newProfID, 0, 4).' '.substr($newProfID, 4, 3).' '.substr($newProfID, 7, 3).' '.substr($newProfID, 10, 3);
3574 }
3575 }
3576 if (!empty($addcpButton)) {
3577 $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3578 } else {
3579 $ret = $newProfID;
3580 }
3581 return $ret;
3582}
3583
3598function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0)
3599{
3600 global $conf, $user, $langs, $mysoc, $hookmanager;
3601
3602 // Clean phone parameter
3603 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
3604 if (empty($phone)) {
3605 return '';
3606 }
3607 if (getDolGlobalString('MAIN_PHONE_SEPAR')) {
3608 $separ = $conf->global->MAIN_PHONE_SEPAR;
3609 }
3610 if (empty($countrycode) && is_object($mysoc)) {
3611 $countrycode = $mysoc->country_code;
3612 }
3613
3614 // Short format for small screens
3615 if ($conf->dol_optimize_smallscreen) {
3616 $separ = '';
3617 }
3618
3619 $newphone = $phone;
3620 if (strtoupper($countrycode) == "FR") {
3621 // France
3622 if (dol_strlen($phone) == 10) {
3623 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 2).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3624 } elseif (dol_strlen($phone) == 7) {
3625 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
3626 } elseif (dol_strlen($phone) == 9) {
3627 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
3628 } elseif (dol_strlen($phone) == 11) {
3629 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3630 } elseif (dol_strlen($phone) == 12) {
3631 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3632 } elseif (dol_strlen($phone) == 13) {
3633 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 2);
3634 }
3635 } elseif (strtoupper($countrycode) == "CA") {
3636 if (dol_strlen($phone) == 10) {
3637 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
3638 }
3639 } elseif (strtoupper($countrycode) == "PT") {//Portugal
3640 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
3641 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3642 }
3643 } elseif (strtoupper($countrycode) == "SR") {//Suriname
3644 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
3645 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
3646 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
3647 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
3648 }
3649 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
3650 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
3651 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
3652 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
3653 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
3654 }
3655 } elseif (strtoupper($countrycode) == "ES") {//Espagne
3656 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
3657 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3658 }
3659 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
3660 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
3661 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3662 }
3663 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
3664 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
3665 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3666 }
3667 } elseif (strtoupper($countrycode) == "TR") {//Turquie
3668 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
3669 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3670 }
3671 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
3672 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
3673 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3674 }
3675 } elseif (strtoupper($countrycode) == "MX") {//Mexique
3676 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
3677 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3678 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
3679 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3680 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
3681 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3682 }
3683 } elseif (strtoupper($countrycode) == "ML") {//Mali
3684 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
3685 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3686 }
3687 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
3688 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
3689 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3690 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
3691 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 3);
3692 }
3693 } elseif (strtoupper($countrycode) == "MU") {
3694 //Maurice
3695 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
3696 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3697 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
3698 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3699 }
3700 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
3701 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
3702 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3703 }
3704 } elseif (strtoupper($countrycode) == "SY") {//Syrie
3705 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
3706 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3707 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
3708 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 3);
3709 }
3710 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
3711 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
3712 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3713 } elseif (dol_strlen($phone) == 13) {//ex: +971_ABC_DEF_GHI
3714 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3715 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
3716 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
3717 }
3718 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
3719 if (dol_strlen($phone) == 13) {//ex: +213_ABC_DEF_GHI
3720 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3721 }
3722 } elseif (strtoupper($countrycode) == "BE") {//Belgique
3723 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
3724 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3725 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
3726 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3727 }
3728 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
3729 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
3730 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3731 }
3732 } elseif (strtoupper($countrycode) == "CO") {//Colombie
3733 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
3734 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3735 }
3736 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
3737 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
3738 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 1).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3739 }
3740 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
3741 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
3742 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3743 }
3744 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
3745 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
3746 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 2);
3747 }
3748 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
3749 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
3750 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3751 }
3752 } elseif (strtoupper($countrycode) == "CH") {//Suisse
3753 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
3754 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3755 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
3756 $newphone = $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 4);
3757 }
3758 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
3759 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
3760 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3761 }
3762 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
3763 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
3764 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3765 }
3766 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
3767 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
3768 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3769 }
3770 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
3771 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
3772 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3773 }
3774 } elseif (strtoupper($countrycode) == "IT") {//Italie
3775 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
3776 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3777 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
3778 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3779 }
3780 } elseif (strtoupper($countrycode) == "AU") {
3781 //Australie
3782 if (dol_strlen($phone) == 12) {
3783 //ex: +61_A_BCDE_FGHI
3784 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
3785 }
3786 } elseif (strtoupper($countrycode) == "LU") {
3787 // Luxembourg
3788 if (dol_strlen($phone) == 10) {// fixe 6 chiffres +352_AA_BB_CC
3789 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3790 } elseif (dol_strlen($phone) == 11) {// fixe 7 chiffres +352_AA_BB_CC_D
3791 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 1);
3792 } elseif (dol_strlen($phone) == 12) {// fixe 8 chiffres +352_AA_BB_CC_DD
3793 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3794 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
3795 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3796 }
3797 }
3798
3799 $newphoneastart = $newphoneaend = '';
3800 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
3801 if ($addlink == 'tel' || $conf->browser->layout == 'phone' || (isModEnabled('clicktodial') && getDolGlobalString('CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS'))) { // If phone or option for, we use link of phone
3802 $newphoneastart = '<a href="tel:'.$phone.'">';
3803 $newphoneaend .= '</a>';
3804 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
3805 if (empty($user->clicktodial_loaded)) {
3806 $user->fetch_clicktodial();
3807 }
3808
3809 // Define urlmask
3810 $urlmask = getDolGlobalString('CLICKTODIAL_URL', 'ErrorClickToDialModuleNotConfigured');
3811 if (!empty($user->clicktodial_url)) {
3812 $urlmask = $user->clicktodial_url;
3813 }
3814
3815 $clicktodial_poste = (!empty($user->clicktodial_poste) ? urlencode($user->clicktodial_poste) : '');
3816 $clicktodial_login = (!empty($user->clicktodial_login) ? urlencode($user->clicktodial_login) : '');
3817 $clicktodial_password = (!empty($user->clicktodial_password) ? urlencode($user->clicktodial_password) : '');
3818 // This line is for backward compatibility
3819 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
3820 // Thoose lines are for substitution
3821 $substitarray = array('__PHONEFROM__'=>$clicktodial_poste,
3822 '__PHONETO__'=>urlencode($phone),
3823 '__LOGIN__'=>$clicktodial_login,
3824 '__PASS__'=>$clicktodial_password);
3825 $url = make_substitutions($url, $substitarray);
3826 if (!getDolGlobalString('CLICKTODIAL_DO_NOT_USE_AJAX_CALL')) {
3827 // Default and recommended: New method using ajax without submiting a page making a javascript history.go(-1) back
3828 $newphoneastart = '<a href="'.$url.'" class="cssforclicktodial">'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
3829 $newphoneaend = '</a>';
3830 } else {
3831 // Old method
3832 $newphoneastart = '<a href="'.$url.'"';
3833 if (getDolGlobalString('CLICKTODIAL_FORCENEWTARGET')) {
3834 $newphoneastart .= ' target="_blank" rel="noopener noreferrer"';
3835 }
3836 $newphoneastart .= '>';
3837 $newphoneaend .= '</a>';
3838 }
3839 }
3840
3841 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
3842 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3843 $type = 'AC_TEL';
3844 $addlinktoagenda = '';
3845 if ($addlink == 'AC_FAX') {
3846 $type = 'AC_FAX';
3847 }
3848 if (getDolGlobalString('AGENDA_ADDACTIONFORPHONE')) {
3849 $addlinktoagenda = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage='. urlencode($_SERVER['REQUEST_URI']) .'&amp;actioncode='.$type.($cid ? '&amp;contactid='.$cid : '').($socid ? '&amp;socid='.$socid : '').'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3850 }
3851 if ($addlinktoagenda) {
3852 $newphone = '<span>'.$newphone.' '.$addlinktoagenda.'</span>';
3853 }
3854 }
3855 }
3856
3857 if (empty($titlealt)) {
3858 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
3859 }
3860 $rep = '';
3861
3862 if ($hookmanager) {
3863 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
3864 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
3865 $rep .= $hookmanager->resPrint;
3866 }
3867 if (empty($reshook)) {
3868 $picto = '';
3869 if ($withpicto) {
3870 if ($withpicto == 'fax') {
3871 $picto = 'phoning_fax';
3872 } elseif ($withpicto == 'phone') {
3873 $picto = 'phoning';
3874 } elseif ($withpicto == 'mobile') {
3875 $picto = 'phoning_mobile';
3876 } else {
3877 $picto = '';
3878 }
3879 }
3880 if ($adddivfloat == 1) {
3881 $rep .= '<div class="nospan float" style="margin-right: 10px">';
3882 } elseif (empty($adddivfloat)) {
3883 $rep .= '<span style="margin-right: 10px;">';
3884 }
3885
3886 $rep .= $newphoneastart;
3887 $rep .= ($withpicto ? img_picto($titlealt, 'object_'.$picto.'.png') : '');
3888 if ($separ != 'hidenum') {
3889 $rep .= ($withpicto ? ' ' : '').$newphone;
3890 }
3891 $rep .= $newphoneaend;
3892
3893 if ($adddivfloat == 1) {
3894 $rep .= '</div>';
3895 } elseif (empty($adddivfloat)) {
3896 $rep .= '</span>';
3897 }
3898 }
3899
3900 return $rep;
3901}
3902
3910function dol_print_ip($ip, $mode = 0)
3911{
3912 global $langs;
3913
3914 $ret = '';
3915
3916 if (empty($mode)) {
3917 $ret .= $ip;
3918 }
3919
3920 if ($mode != 2) {
3921 $countrycode = dolGetCountryCodeFromIp($ip);
3922 if ($countrycode) { // If success, countrycode is us, fr, ...
3923 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
3924 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
3925 } else {
3926 $ret .= ' ('.$countrycode.')';
3927 }
3928 } else {
3929 // Nothing
3930 }
3931 }
3932
3933 return $ret;
3934}
3935
3945{
3946 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
3947 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
3948 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
3949 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
3950 } else {
3951 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
3952 }
3953 } else {
3954 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
3955 }
3956 } else {
3957 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
3958 }
3959 return $ip;
3960}
3961
3970function isHTTPS()
3971{
3972 $isSecure = false;
3973 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
3974 $isSecure = true;
3975 } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
3976 $isSecure = true;
3977 }
3978 return $isSecure;
3979}
3980
3988{
3989 global $conf;
3990
3991 $countrycode = '';
3992
3993 if (!empty($conf->geoipmaxmind->enabled)) {
3994 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3995 //$ip='24.24.24.24';
3996 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
3997 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3998 $geoip = new DolGeoIP('country', $datafile);
3999 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
4000 $countrycode = $geoip->getCountryCodeFromIP($ip);
4001 }
4002
4003 return $countrycode;
4004}
4005
4006
4014{
4015 global $conf, $langs, $user;
4016
4017 //$ret=$user->xxx;
4018 $ret = '';
4019 if (!empty($conf->geoipmaxmind->enabled)) {
4020 $ip = getUserRemoteIP();
4021 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
4022 //$ip='24.24.24.24';
4023 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
4024 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
4025 $geoip = new DolGeoIP('country', $datafile);
4026 $countrycode = $geoip->getCountryCodeFromIP($ip);
4027 $ret = $countrycode;
4028 }
4029 return $ret;
4030}
4031
4044function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
4045{
4046 global $conf, $user, $langs, $hookmanager;
4047
4048 $out = '';
4049
4050 if ($address) {
4051 if ($hookmanager) {
4052 $parameters = array('element' => $element, 'id' => $id);
4053 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
4054 $out .= $hookmanager->resPrint;
4055 }
4056 if (empty($reshook)) {
4057 if (empty($charfornl)) {
4058 $out .= nl2br($address);
4059 } else {
4060 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
4061 }
4062
4063 // TODO Remove this block, we can add this using the hook now
4064 $showgmap = $showomap = 0;
4065 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS')) {
4066 $showgmap = 1;
4067 }
4068 if ($element == 'contact' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_CONTACTS')) {
4069 $showgmap = 1;
4070 }
4071 if ($element == 'member' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_MEMBERS')) {
4072 $showgmap = 1;
4073 }
4074 if ($element == 'user' && isModEnabled('google') && getDolGlobalString('GOOGLE_ENABLE_GMAPS_USERS')) {
4075 $showgmap = 1;
4076 }
4077 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS')) {
4078 $showomap = 1;
4079 }
4080 if ($element == 'contact' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_CONTACTS')) {
4081 $showomap = 1;
4082 }
4083 if ($element == 'member' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_MEMBERS')) {
4084 $showomap = 1;
4085 }
4086 if ($element == 'user' && isModEnabled('openstreetmap') && getDolGlobalString('OPENSTREETMAP_ENABLE_MAPS_USERS')) {
4087 $showomap = 1;
4088 }
4089 if ($showgmap) {
4090 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
4091 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4092 }
4093 if ($showomap) {
4094 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
4095 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
4096 }
4097 }
4098 }
4099 if ($noprint) {
4100 return $out;
4101 } else {
4102 print $out;
4103 }
4104}
4105
4106
4116function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
4117{
4118 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
4119 return true;
4120 }
4121 if ($acceptuserkey && $address == '__USER_EMAIL__') {
4122 return true;
4123 }
4124 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
4125 return true;
4126 }
4127
4128 return false;
4129}
4130
4139function isValidMXRecord($domain)
4140{
4141 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
4142 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
4143 return 0;
4144 }
4145 if (function_exists('getmxrr')) {
4146 $mxhosts = array();
4147 $weight = array();
4148 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
4149 if (count($mxhosts) > 1) {
4150 return 1;
4151 }
4152 if (count($mxhosts) == 1 && !empty($mxhosts[0])) {
4153 return 1;
4154 }
4155
4156 return 0;
4157 }
4158 }
4159
4160 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4161 return -1;
4162}
4163
4171function isValidPhone($phone)
4172{
4173 return true;
4174}
4175
4176
4186function dolGetFirstLetters($s, $nbofchar = 1)
4187{
4188 $ret = '';
4189 $tmparray = explode(' ', $s);
4190 foreach ($tmparray as $tmps) {
4191 $ret .= dol_substr($tmps, 0, $nbofchar);
4192 }
4193
4194 return $ret;
4195}
4196
4197
4205function dol_strlen($string, $stringencoding = 'UTF-8')
4206{
4207 if (is_null($string)) {
4208 return 0;
4209 }
4210
4211 if (function_exists('mb_strlen')) {
4212 return mb_strlen($string, $stringencoding);
4213 } else {
4214 return strlen($string);
4215 }
4216}
4217
4228function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4229{
4230 global $langs;
4231
4232 if (empty($stringencoding)) {
4233 $stringencoding = $langs->charset_output;
4234 }
4235
4236 $ret = '';
4237 if (empty($trunconbytes)) {
4238 if (function_exists('mb_substr')) {
4239 $ret = mb_substr($string, $start, $length, $stringencoding);
4240 } else {
4241 $ret = substr($string, $start, $length);
4242 }
4243 } else {
4244 if (function_exists('mb_strcut')) {
4245 $ret = mb_strcut($string, $start, $length, $stringencoding);
4246 } else {
4247 $ret = substr($string, $start, $length);
4248 }
4249 }
4250 return $ret;
4251}
4252
4253
4267function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4268{
4269 global $conf;
4270
4271 if (empty($size) || getDolGlobalString('MAIN_DISABLE_TRUNC')) {
4272 return $string;
4273 }
4274
4275 if (empty($stringencoding)) {
4276 $stringencoding = 'UTF-8';
4277 }
4278 // reduce for small screen
4279 if ($conf->dol_optimize_smallscreen == 1 && $display == 1) {
4280 $size = round($size / 3);
4281 }
4282
4283 // We go always here
4284 if ($trunc == 'right') {
4285 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4286 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4287 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4288 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4289 } else {
4290 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4291 return $string;
4292 }
4293 } elseif ($trunc == 'middle') {
4294 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4295 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4296 $size1 = round($size / 2);
4297 $size2 = round($size / 2);
4298 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4299 } else {
4300 return $string;
4301 }
4302 } elseif ($trunc == 'left') {
4303 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4304 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4305 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4306 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4307 } else {
4308 return $string;
4309 }
4310 } elseif ($trunc == 'wrap') {
4311 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4312 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4313 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4314 } else {
4315 return $string;
4316 }
4317 } else {
4318 return 'BadParam3CallingDolTrunc';
4319 }
4320}
4321
4328function getPictoForType($key)
4329{
4330 // Set array with type -> picto
4331 $type2picto = array(
4332 'varchar'=>'font',
4333 'text'=>'font',
4334 'html'=>'code',
4335 'int'=>'sort-numeric-down',
4336 'double'=>'sort-numeric-down',
4337 'price'=>'currency',
4338 'pricecy'=>'multicurrency',
4339 'password' => 'key',
4340 'boolean'=>'check-square',
4341 'date'=>'calendar',
4342 'datetime'=>'calendar',
4343 'phone'=> 'phone',
4344 'mail'=> 'email',
4345 'url'=> 'url',
4346 'ip'=> 'country',
4347 'select' => 'list',
4348 'sellist' => 'list',
4349 'radio' => 'check-circle',
4350 'checkbox' => 'check-square',
4351 'chkbxlst' => 'check-square',
4352 'link' => 'link',
4353 'separate'=> 'minus'
4354 );
4355
4356 if (!empty($type2picto[$key])) {
4357 return img_picto('', $type2picto[$key], 'class="pictofixedwidth"');
4358 }
4359
4360 return img_picto('', 'generic', 'class="pictofixedwidth"');
4361}
4362
4363
4385function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4386{
4387 global $conf, $langs;
4388
4389 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4390 $url = DOL_URL_ROOT;
4391 $theme = isset($conf->theme) ? $conf->theme : null;
4392 $path = 'theme/'.$theme;
4393 if (empty($picto)) {
4394 $picto = 'generic';
4395 }
4396
4397 // Define fullpathpicto to use into src
4398 if ($pictoisfullpath) {
4399 // Clean parameters
4400 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4401 $picto .= '.png';
4402 }
4403 $fullpathpicto = $picto;
4404 $reg = array();
4405 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4406 $morecss .= ($morecss ? ' ' : '').$reg[1];
4407 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4408 }
4409 } else {
4410 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', (is_null($picto) ? '' : $picto));
4411 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4412 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4413
4414 if (strpos($pictowithouttext, 'fontawesome_') === 0 || strpos($pictowithouttext, 'fa-') === 0) {
4415 // This is a font awesome image 'fontawesome_xxx' or 'fa-xxx'
4416 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4417 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4418
4419 // Compatibility with old fontawesome versions
4420 if ($pictowithouttext == 'file-o') {
4421 $pictowithouttext = 'file';
4422 }
4423
4424 $pictowithouttextarray = explode('_', $pictowithouttext);
4425 $marginleftonlyshort = 0;
4426
4427 if (!empty($pictowithouttextarray[1])) {
4428 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4429 $fakey = 'fa-'.$pictowithouttextarray[0];
4430 $faprefix = empty($pictowithouttextarray[1]) ? 'fas' : $pictowithouttextarray[1];
4431 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4432 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4433 } else {
4434 $fakey = 'fa-'.$pictowithouttext;
4435 $faprefix = 'fas';
4436 $facolor = '';
4437 $fasize = '';
4438 }
4439
4440 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4441 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4442 $morestyle = '';
4443 $reg = array();
4444 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4445 $morecss .= ($morecss ? ' ' : '').$reg[1];
4446 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4447 }
4448 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4449 $morestyle = $reg[1];
4450 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4451 }
4452 $moreatt = trim($moreatt);
4453
4454 $enabledisablehtml = '<span class="'.$faprefix.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4455 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4456 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4457 $enabledisablehtml .= $titlealt;
4458 }*/
4459 $enabledisablehtml .= '</span>';
4460
4461 return $enabledisablehtml;
4462 }
4463
4464 if (empty($srconly) && in_array($pictowithouttext, array(
4465 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4466 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'angle-double-down', 'angle-double-up', 'asset',
4467 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building',
4468 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4469 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'code', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4470 'check-circle', 'check-square', 'currency', 'multicurrency',
4471 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies',
4472 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4473 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4474 'filter', 'file', 'file-o', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus', 'font',
4475 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4476 'hands-helping', 'help', 'holiday',
4477 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4478 'key', 'knowledgemanagement',
4479 'label', 'language', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4480 'margin', 'map-marker-alt', 'member', 'meeting', 'minus', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4481 'off', 'on', 'order',
4482 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4483 'stock', 'resize', 'service', 'stats',
4484 'security', 'setup', 'share-alt', 'sign-out', 'split', 'stripe', 'stripe-s', 'switch_off', 'switch_on', 'switch_on_warning', 'switch_on_red', 'tools', 'unlink', 'uparrow', 'user', 'user-tie', 'vcard', 'wrench',
4485 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4486 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4487 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4488 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4489 'technic', 'ticket',
4490 'error', 'warning',
4491 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4492 'shapes', 'skill', 'square', 'sort-numeric-down', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4493 'tick', 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda',
4494 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4495 'conferenceorbooth', 'eventorganization',
4496 'stamp', 'signature'
4497 ))) {
4498 $fakey = $pictowithouttext;
4499 $facolor = '';
4500 $fasize = '';
4501 $fa = getDolGlobalString('MAIN_FONTAWESOME_ICON_STYLE', 'fas');
4502 if (in_array($pictowithouttext, array('card', 'bell', 'clock', 'establishment', 'file', 'file-o', 'generic', 'minus-square', 'object_generic', 'pdf', 'plus-square', 'timespent', 'note', 'off', 'on', 'object_bookmark', 'bookmark', 'vcard'))) {
4503 $fa = 'far';
4504 }
4505 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4506 $fa = 'fab';
4507 }
4508
4509 $arrayconvpictotofa = array(
4510 'account'=>'university', 'accounting_account'=>'clipboard-list', 'accountline'=>'receipt', 'accountancy'=>'search-dollar', 'action'=>'calendar-alt', 'add'=>'plus-circle', 'address'=> 'address-book', 'asset'=>'money-check-alt', 'autofill'=>'fill',
4511 'bank_account'=>'university',
4512 'bill'=>'file-invoice-dollar', 'billa'=>'file-excel', 'billr'=>'file-invoice-dollar', 'billd'=>'file-medical',
4513 'supplier_invoice'=>'file-invoice-dollar', 'supplier_invoicea'=>'file-excel', 'supplier_invoicer'=>'file-invoice-dollar', 'supplier_invoiced'=>'file-medical',
4514 'bom'=>'shapes',
4515 'card'=>'address-card', 'chart'=>'chart-line', 'company'=>'building', 'contact'=>'address-book', 'contract'=>'suitcase', 'collab'=>'people-arrows', 'conversation'=>'comments', 'country'=>'globe-americas', 'cron'=>'business-time', 'cross'=>'times',
4516 'donation'=>'file-alt', 'dynamicprice'=>'hand-holding-usd',
4517 'setup'=>'cog', 'companies'=>'building', 'products'=>'cube', 'commercial'=>'suitcase', 'invoicing'=>'coins',
4518 'accounting'=>'search-dollar', 'category'=>'tag', 'dollyrevert'=>'dolly',
4519 'file-o'=>'file', 'generate'=>'plus-square', 'hrm'=>'user-tie', 'incoterm'=>'truck-loading',
4520 'margin'=>'calculator', 'members'=>'user-friends', 'ticket'=>'ticket-alt', 'globe'=>'external-link-alt', 'lot'=>'barcode',
4521 'email'=>'at', 'establishment'=>'building', 'edit'=>'pencil-alt', 'entity'=>'globe',
4522 'graph'=>'chart-line', 'grip_title'=>'arrows-alt', 'grip'=>'arrows-alt', 'help'=>'question-circle',
4523 'generic'=>'file', 'holiday'=>'umbrella-beach',
4524 'info'=>'info-circle', 'inventory'=>'boxes', 'intracommreport'=>'globe-europe', 'jobprofile'=>'cogs',
4525 'knowledgemanagement'=>'ticket-alt', 'label'=>'layer-group', 'line'=>'bars', 'loan'=>'money-bill-alt',
4526 'member'=>'user-alt', 'meeting'=>'chalkboard-teacher', 'mrp'=>'cubes', 'next'=>'arrow-alt-circle-right',
4527 'trip'=>'wallet', 'expensereport'=>'wallet', 'group'=>'users', 'movement'=>'people-carry',
4528 'sign-out'=>'sign-out-alt',
4529 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_warning'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star',
4530 'bank'=>'university', 'close_title'=>'times', 'delete'=>'trash', 'filter'=>'filter',
4531 'list-alt'=>'list-alt', 'calendarlist'=>'bars', 'calendar'=>'calendar-alt', 'calendarmonth'=>'calendar-alt', 'calendarweek'=>'calendar-week', 'calendarday'=>'calendar-day', 'calendarperuser'=>'table',
4532 'intervention'=>'ambulance', 'invoice'=>'file-invoice-dollar', 'order'=>'file-invoice',
4533 'error'=>'exclamation-triangle', 'warning'=>'exclamation-triangle',
4534 'other'=>'square',
4535 'playdisabled'=>'play', 'pdf'=>'file-pdf', 'poll'=>'check-double', 'pos'=>'cash-register', 'preview'=>'binoculars', 'project'=>'project-diagram', 'projectpub'=>'project-diagram', 'projecttask'=>'tasks', 'propal'=>'file-signature', 'proposal'=>'file-signature',
4536 'partnership'=>'handshake', 'payment'=>'money-check-alt', 'payment_vat'=>'money-check-alt', 'pictoconfirm'=>'check-square', 'phoning'=>'phone', 'phoning_mobile'=>'mobile-alt', 'phoning_fax'=>'fax', 'previous'=>'arrow-alt-circle-left', 'printer'=>'print', 'product'=>'cube', 'puce'=>'angle-right',
4537 'recent' => 'check-square', 'reception'=>'dolly', 'recruitmentjobposition'=>'id-card-alt', 'recruitmentcandidature'=>'id-badge',
4538 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature',
4539 'refresh'=>'redo', 'region'=>'map-marked', 'replacement'=>'exchange-alt', 'resource'=>'laptop-house', 'recurring'=>'history',
4540 'service'=>'concierge-bell',
4541 'skill'=>'shapes', 'state'=>'map-marked-alt', 'security'=>'key', 'salary'=>'wallet', 'shipment'=>'dolly', 'stock'=>'box-open', 'stats' => 'chart-bar', 'split'=>'code-branch', 'stripe'=>'stripe-s',
4542 'supplier'=>'building', 'technic'=>'cogs',
4543 'timespent'=>'clock', 'tick' => 'check', 'title_setup'=>'tools', 'title_accountancy'=>'money-check-alt', 'title_bank'=>'university', 'title_hrm'=>'umbrella-beach',
4544 'title_agenda'=>'calendar-alt',
4545 'uncheck'=>'times', 'uparrow'=>'share', 'url'=>'external-link-alt', 'vat'=>'money-check-alt', 'vcard'=>'arrow-alt-circle-down',
4546 'jabber'=>'comment-o',
4547 'website'=>'globe-americas', 'workstation'=>'pallet', 'webhook'=>'bullseye', 'world'=>'globe', 'private'=>'user-lock',
4548 'conferenceorbooth'=>'chalkboard-teacher', 'eventorganization'=>'project-diagram'
4549 );
4550 if ($conf->currency == 'EUR') {
4551 $arrayconvpictotofa['currency'] = 'euro-sign';
4552 $arrayconvpictotofa['multicurrency'] = 'dollar-sign';
4553 } else {
4554 $arrayconvpictotofa['currency'] = 'dollar-sign';
4555 $arrayconvpictotofa['multicurrency'] = 'euro-sign';
4556 }
4557 if ($pictowithouttext == 'off') {
4558 $fakey = 'fa-square';
4559 $fasize = '1.3em';
4560 } elseif ($pictowithouttext == 'on') {
4561 $fakey = 'fa-check-square';
4562 $fasize = '1.3em';
4563 } elseif ($pictowithouttext == 'listlight') {
4564 $fakey = 'fa-download';
4565 $marginleftonlyshort = 1;
4566 } elseif ($pictowithouttext == 'printer') {
4567 $fakey = 'fa-print';
4568 $fasize = '1.2em';
4569 } elseif ($pictowithouttext == 'note') {
4570 $fakey = 'fa-sticky-note';
4571 $marginleftonlyshort = 1;
4572 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
4573 $convertarray = array('1uparrow'=>'caret-up', '1downarrow'=>'caret-down', '1leftarrow'=>'caret-left', '1rightarrow'=>'caret-right', '1uparrow_selected'=>'caret-up', '1downarrow_selected'=>'caret-down', '1leftarrow_selected'=>'caret-left', '1rightarrow_selected'=>'caret-right');
4574 $fakey = 'fa-'.$convertarray[$pictowithouttext];
4575 if (preg_match('/selected/', $pictowithouttext)) {
4576 $facolor = '#888';
4577 }
4578 $marginleftonlyshort = 1;
4579 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
4580 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
4581 } else {
4582 $fakey = 'fa-'.$pictowithouttext;
4583 }
4584
4585 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment'))) {
4586 $morecss .= ' em092';
4587 }
4588 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
4589 $morecss .= ' em088';
4590 }
4591 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
4592 $morecss .= ' em080';
4593 }
4594
4595 // Define $marginleftonlyshort
4596 $arrayconvpictotomarginleftonly = array(
4597 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
4598 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
4599 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
4600 );
4601 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
4602 $marginleftonlyshort = 0;
4603 }
4604
4605 // Add CSS
4606 $arrayconvpictotomorcess = array(
4607 'action'=>'infobox-action', 'account'=>'infobox-bank_account', 'accounting_account'=>'infobox-bank_account', 'accountline'=>'infobox-bank_account', 'accountancy'=>'infobox-bank_account', 'asset'=>'infobox-bank_account',
4608 'bank_account'=>'infobox-bank_account',
4609 'bill'=>'infobox-commande', 'billa'=>'infobox-commande', 'billr'=>'infobox-commande', 'billd'=>'infobox-commande',
4610 'margin'=>'infobox-bank_account', 'conferenceorbooth'=>'infobox-project',
4611 'cash-register'=>'infobox-bank_account', 'contract'=>'infobox-contrat', 'check'=>'font-status4', 'collab'=>'infobox-action', 'conversation'=>'infobox-contrat',
4612 'donation'=>'infobox-commande', 'dolly'=>'infobox-commande', 'dollyrevert'=>'flip infobox-order_supplier',
4613 'ecm'=>'infobox-action', 'eventorganization'=>'infobox-project',
4614 'hrm'=>'infobox-adherent', 'group'=>'infobox-adherent', 'intervention'=>'infobox-contrat',
4615 'incoterm'=>'infobox-supplier_proposal',
4616 'currency'=>'infobox-bank_account', 'multicurrency'=>'infobox-bank_account',
4617 'members'=>'infobox-adherent', 'member'=>'infobox-adherent', 'money-bill-alt'=>'infobox-bank_account',
4618 'order'=>'infobox-commande',
4619 'user'=>'infobox-adherent', 'users'=>'infobox-adherent',
4620 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_warning'=>'font-status4 warning', 'switch_on_red'=>'font-status8',
4621 'holiday'=>'infobox-holiday', 'info'=>'opacityhigh', 'invoice'=>'infobox-commande',
4622 'knowledgemanagement'=>'infobox-contrat rotate90', 'loan'=>'infobox-bank_account',
4623 'payment'=>'infobox-bank_account', 'payment_vat'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'pos'=>'infobox-bank_account', 'project'=>'infobox-project', 'projecttask'=>'infobox-project',
4624 'propal'=>'infobox-propal', 'proposal'=>'infobox-propal','private'=>'infobox-project',
4625 'reception'=>'flip', 'recruitmentjobposition'=>'infobox-adherent', 'recruitmentcandidature'=>'infobox-adherent',
4626 'resource'=>'infobox-action',
4627 'salary'=>'infobox-bank_account', 'shapes'=>'infobox-adherent', 'shipment'=>'infobox-commande', 'supplier_invoice'=>'infobox-order_supplier', 'supplier_invoicea'=>'infobox-order_supplier', 'supplier_invoiced'=>'infobox-order_supplier',
4628 'supplier'=>'infobox-order_supplier', 'supplier_order'=>'infobox-order_supplier', 'supplier_proposal'=>'infobox-supplier_proposal',
4629 'ticket'=>'infobox-contrat', 'title_accountancy'=>'infobox-bank_account', 'title_hrm'=>'infobox-holiday', 'expensereport'=>'infobox-expensereport', 'trip'=>'infobox-expensereport', 'title_agenda'=>'infobox-action',
4630 'vat'=>'infobox-bank_account',
4631 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
4632 'list-alt'=>'imgforviewmode', 'calendar'=>'imgforviewmode', 'calendarweek'=>'imgforviewmode', 'calendarmonth'=>'imgforviewmode', 'calendarday'=>'imgforviewmode', 'calendarperuser'=>'imgforviewmode'
4633 );
4634 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4635 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
4636 }
4637
4638 // Define $color
4639 $arrayconvpictotocolor = array(
4640 'address'=>'#6c6aa8', 'building'=>'#6c6aa8', 'bom'=>'#a69944',
4641 'clone'=>'#999', 'cog'=>'#999', 'companies'=>'#6c6aa8', 'company'=>'#6c6aa8', 'contact'=>'#6c6aa8', 'cron'=>'#555',
4642 'dynamicprice'=>'#a69944',
4643 'edit'=>'#444', 'note'=>'#999', 'error'=>'', 'help'=>'#bbb', 'listlight'=>'#999', 'language'=>'#555',
4644 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
4645 'lock'=>'#ddd', 'lot'=>'#a69944',
4646 'map-marker-alt'=>'#aaa', 'mrp'=>'#a69944', 'product'=>'#a69944', 'service'=>'#a69944', 'inventory'=>'#a69944', 'stock'=>'#a69944', 'movement'=>'#a69944',
4647 'other'=>'#ddd', 'world'=>'#986c6a',
4648 'partnership'=>'#6c6aa8', 'playdisabled'=>'#ccc', 'printer'=>'#444', 'projectpub'=>'#986c6a', 'reception'=>'#a69944', 'resize'=>'#444', 'rss'=>'#cba',
4649 //'shipment'=>'#a69944',
4650 'security'=>'#999', 'square'=>'#888', 'stop-circle'=>'#888', 'stats'=>'#444', 'switch_off'=>'#999',
4651 'technic' => '#999', 'tick' => '#282', 'timespent' => '#555',
4652 'uncheck'=>'#800', 'uparrow'=>'#555', 'user-cog'=>'#999', 'country'=>'#aaa', 'globe-americas'=>'#aaa', 'region'=>'#aaa', 'state'=>'#aaa',
4653 'website'=>'#304', 'workstation'=>'#a69944'
4654 );
4655 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4656 $facolor = $arrayconvpictotocolor[$pictowithouttext];
4657 }
4658
4659 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4660 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4661 $morestyle = '';
4662 $reg = array();
4663 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4664 $morecss .= ($morecss ? ' ' : '').$reg[1];
4665 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4666 }
4667 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4668 $morestyle = $reg[1];
4669 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4670 }
4671 $moreatt = trim($moreatt);
4672
4673 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4674 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4675 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4676 $enabledisablehtml .= $titlealt;
4677 }*/
4678 $enabledisablehtml .= '</span>';
4679
4680 return $enabledisablehtml;
4681 }
4682
4683 if (getDolGlobalString('MAIN_OVERWRITE_THEME_PATH')) {
4684 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_PATH') . '/theme/'.$theme; // If the theme does not have the same name as the module
4685 } elseif (getDolGlobalString('MAIN_OVERWRITE_THEME_RES')) {
4686 $path = getDolGlobalString('MAIN_OVERWRITE_THEME_RES') . '/theme/' . getDolGlobalString('MAIN_OVERWRITE_THEME_RES'); // To allow an external module to overwrite image resources whatever is activated theme
4687 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
4688 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
4689 }
4690
4691 // If we ask an image into $url/$mymodule/img (instead of default path)
4692 $regs = array();
4693 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
4694 $picto = $regs[1];
4695 $path = $regs[2]; // $path is $mymodule
4696 }
4697
4698 // Clean parameters
4699 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4700 $picto .= '.png';
4701 }
4702 // If alt path are defined, define url where img file is, according to physical path
4703 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
4704 foreach ($conf->file->dol_document_root as $type => $dirroot) {
4705 if ($type == 'main') {
4706 continue;
4707 }
4708 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommanded
4709 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
4710 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
4711 break;
4712 }
4713 }
4714
4715 // $url is '' or '/custom', $path is current theme or
4716 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
4717 }
4718
4719 if ($srconly) {
4720 return $fullpathpicto;
4721 }
4722
4723 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
4724 return '<img src="'.$fullpathpicto.'"'.($notitle ? '' : ' alt="'.dol_escape_htmltag($alt).'"').(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt.($morecss ? ' class="'.$morecss.'"' : '') : ' class="inline-block'.($morecss ? ' '.$morecss : '').'"').'>'; // Alt is used for accessibility, title for popup
4725}
4726
4740function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0)
4741{
4742 if (strpos($picto, '^') === 0) {
4743 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
4744 } else {
4745 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
4746 }
4747}
4748
4760function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
4761{
4762 global $conf;
4763
4764 if (is_numeric($picto)) {
4765 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
4766 //$picto = $leveltopicto[$picto];
4767 return '<i class="fa fa-weather-level'.$picto.'"></i>';
4768 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4769 $picto .= '.png';
4770 }
4771
4772 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
4773
4774 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
4775}
4776
4788function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
4789{
4790 global $conf;
4791
4792 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4793 $picto .= '.png';
4794 }
4795
4796 if ($pictoisfullpath) {
4797 $path = $picto;
4798 } else {
4799 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
4800
4801 if (getDolGlobalInt('MAIN_MODULE_CAN_OVERWRITE_COMMONICONS')) {
4802 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
4803
4804 if (file_exists($themepath)) {
4805 $path = $themepath;
4806 }
4807 }
4808 }
4809
4810 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
4811}
4812
4826function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
4827{
4828 global $langs;
4829
4830 if (empty($titlealt) || $titlealt == 'default') {
4831 if ($numaction == '-1' || $numaction == 'ST_NO') {
4832 $numaction = -1;
4833 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
4834 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
4835 $numaction = 0;
4836 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
4837 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
4838 $numaction = 1;
4839 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
4840 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
4841 $numaction = 2;
4842 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
4843 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
4844 $numaction = 3;
4845 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
4846 } else {
4847 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
4848 $numaction = 0;
4849 }
4850 }
4851 if (!is_numeric($numaction)) {
4852 $numaction = 0;
4853 }
4854
4855 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
4856}
4857
4865function img_pdf($titlealt = 'default', $size = 3)
4866{
4867 global $langs;
4868
4869 if ($titlealt == 'default') {
4870 $titlealt = $langs->trans('Show');
4871 }
4872
4873 return img_picto($titlealt, 'pdf'.$size.'.png');
4874}
4875
4883function img_edit_add($titlealt = 'default', $other = '')
4884{
4885 global $langs;
4886
4887 if ($titlealt == 'default') {
4888 $titlealt = $langs->trans('Add');
4889 }
4890
4891 return img_picto($titlealt, 'edit_add.png', $other);
4892}
4900function img_edit_remove($titlealt = 'default', $other = '')
4901{
4902 global $langs;
4903
4904 if ($titlealt == 'default') {
4905 $titlealt = $langs->trans('Remove');
4906 }
4907
4908 return img_picto($titlealt, 'edit_remove.png', $other);
4909}
4910
4919function img_edit($titlealt = 'default', $float = 0, $other = '')
4920{
4921 global $langs;
4922
4923 if ($titlealt == 'default') {
4924 $titlealt = $langs->trans('Modify');
4925 }
4926
4927 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
4928}
4929
4938function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
4939{
4940 global $langs;
4941
4942 if ($titlealt == 'default') {
4943 $titlealt = $langs->trans('View');
4944 }
4945
4946 $moreatt = ($float ? 'style="float: right" ' : '').$other;
4947
4948 return img_picto($titlealt, 'eye', $moreatt);
4949}
4950
4959function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
4960{
4961 global $langs;
4962
4963 if ($titlealt == 'default') {
4964 $titlealt = $langs->trans('Delete');
4965 }
4966
4967 return img_picto($titlealt, 'delete.png', $other, false, 0, 0, '', $morecss);
4968}
4969
4977function img_printer($titlealt = "default", $other = '')
4978{
4979 global $langs;
4980 if ($titlealt == "default") {
4981 $titlealt = $langs->trans("Print");
4982 }
4983 return img_picto($titlealt, 'printer.png', $other);
4984}
4985
4993function img_split($titlealt = 'default', $other = 'class="pictosplit"')
4994{
4995 global $langs;
4996
4997 if ($titlealt == 'default') {
4998 $titlealt = $langs->trans('Split');
4999 }
5000
5001 return img_picto($titlealt, 'split.png', $other);
5002}
5003
5011function img_help($usehelpcursor = 1, $usealttitle = 1)
5012{
5013 global $langs;
5014
5015 if ($usealttitle) {
5016 if (is_string($usealttitle)) {
5017 $usealttitle = dol_escape_htmltag($usealttitle);
5018 } else {
5019 $usealttitle = $langs->trans('Info');
5020 }
5021 }
5022
5023 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
5024}
5025
5032function img_info($titlealt = 'default')
5033{
5034 global $langs;
5035
5036 if ($titlealt == 'default') {
5037 $titlealt = $langs->trans('Informations');
5038 }
5039
5040 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
5041}
5042
5051function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
5052{
5053 global $langs;
5054
5055 if ($titlealt == 'default') {
5056 $titlealt = $langs->trans('Warning');
5057 }
5058
5059 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
5060 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
5061}
5062
5069function img_error($titlealt = 'default')
5070{
5071 global $langs;
5072
5073 if ($titlealt == 'default') {
5074 $titlealt = $langs->trans('Error');
5075 }
5076
5077 return img_picto($titlealt, 'error.png');
5078}
5079
5087function img_next($titlealt = 'default', $moreatt = '')
5088{
5089 global $langs;
5090
5091 if ($titlealt == 'default') {
5092 $titlealt = $langs->trans('Next');
5093 }
5094
5095 //return img_picto($titlealt, 'next.png', $moreatt);
5096 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5097}
5098
5106function img_previous($titlealt = 'default', $moreatt = '')
5107{
5108 global $langs;
5109
5110 if ($titlealt == 'default') {
5111 $titlealt = $langs->trans('Previous');
5112 }
5113
5114 //return img_picto($titlealt, 'previous.png', $moreatt);
5115 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
5116}
5117
5126function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
5127{
5128 global $langs;
5129
5130 if ($titlealt == 'default') {
5131 $titlealt = $langs->trans('Down');
5132 }
5133
5134 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
5135}
5136
5145function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
5146{
5147 global $langs;
5148
5149 if ($titlealt == 'default') {
5150 $titlealt = $langs->trans('Up');
5151 }
5152
5153 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
5154}
5155
5164function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
5165{
5166 global $langs;
5167
5168 if ($titlealt == 'default') {
5169 $titlealt = $langs->trans('Left');
5170 }
5171
5172 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
5173}
5174
5183function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
5184{
5185 global $langs;
5186
5187 if ($titlealt == 'default') {
5188 $titlealt = $langs->trans('Right');
5189 }
5190
5191 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
5192}
5193
5201function img_allow($allow, $titlealt = 'default')
5202{
5203 global $langs;
5204
5205 if ($titlealt == 'default') {
5206 $titlealt = $langs->trans('Active');
5207 }
5208
5209 if ($allow == 1) {
5210 return img_picto($titlealt, 'tick.png');
5211 }
5212
5213 return '-';
5214}
5215
5223function img_credit_card($brand, $morecss = null)
5224{
5225 if (is_null($morecss)) {
5226 $morecss = 'fa-2x';
5227 }
5228
5229 if ($brand == 'visa' || $brand == 'Visa') {
5230 $brand = 'cc-visa';
5231 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5232 $brand = 'cc-mastercard';
5233 } elseif ($brand == 'amex' || $brand == 'American Express') {
5234 $brand = 'cc-amex';
5235 } elseif ($brand == 'discover' || $brand == 'Discover') {
5236 $brand = 'cc-discover';
5237 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5238 $brand = 'cc-jcb';
5239 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5240 $brand = 'cc-diners-club';
5241 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5242 $brand = 'credit-card';
5243 }
5244
5245 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5246}
5247
5256function img_mime($file, $titlealt = '', $morecss = '')
5257{
5258 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5259
5260 $mimetype = dol_mimetype($file, '', 1);
5261 $mimeimg = dol_mimetype($file, '', 2);
5262 $mimefa = dol_mimetype($file, '', 4);
5263
5264 if (empty($titlealt)) {
5265 $titlealt = 'Mime type: '.$mimetype;
5266 }
5267
5268 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5269 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5270}
5271
5272
5280function img_search($titlealt = 'default', $other = '')
5281{
5282 global $conf, $langs;
5283
5284 if ($titlealt == 'default') {
5285 $titlealt = $langs->trans('Search');
5286 }
5287
5288 $img = img_picto($titlealt, 'search.png', $other, false, 1);
5289
5290 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5291 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5292
5293 return $input;
5294}
5295
5303function img_searchclear($titlealt = 'default', $other = '')
5304{
5305 global $conf, $langs;
5306
5307 if ($titlealt == 'default') {
5308 $titlealt = $langs->trans('Search');
5309 }
5310
5311 $img = img_picto($titlealt, 'searchclear.png', $other, false, 1);
5312
5313 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5314 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5315
5316 return $input;
5317}
5318
5330function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '')
5331{
5332 global $conf, $langs;
5333
5334 if ($infoonimgalt) {
5335 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5336 } else {
5337 if (empty($conf->use_javascript_ajax)) {
5338 $textfordropdown = '';
5339 }
5340
5341 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5342 $result = ($nodiv ? '' : '<div class="'.$class.($morecss ? ' '.$morecss : '').($textfordropdown ? ' hidden' : '').'">').'<span class="fa fa-info-circle" title="'.dol_escape_htmltag($admin ? $langs->trans('InfoAdmin') : $langs->trans('Note')).'"></span> '.$text.($nodiv ? '' : '</div>');
5343
5344 if ($textfordropdown) {
5345 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5346 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5347 jQuery(document).ready(function() {
5348 jQuery(".'.$class.'text").click(function() {
5349 console.log("toggle text");
5350 jQuery(".'.$class.'").toggle();
5351 });
5352 });
5353 </script>';
5354
5355 $result = $tmpresult.$result;
5356 }
5357 }
5358
5359 return $result;
5360}
5361
5362
5374function dol_print_error($db = '', $error = '', $errors = null)
5375{
5376 global $conf, $langs, $argv;
5377 global $dolibarr_main_prod;
5378
5379 $out = '';
5380 $syslog = '';
5381
5382 // If error occurs before the $lang object was loaded
5383 if (!$langs) {
5384 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5385 $langs = new Translate('', $conf);
5386 $langs->load("main");
5387 }
5388
5389 // Load translation files required by the error messages
5390 $langs->loadLangs(array('main', 'errors'));
5391
5392 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5393 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5394 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5395 $out .= "You use an experimental or develop level of features, so please do NOT report any bugs or vulnerability, except if problem is confirmed after moving option MAIN_FEATURES_LEVEL back to 0.<br>\n";
5396 }
5397 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5398
5399 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5400 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5401 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5402 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5403 }
5404 if (function_exists("phpversion")) {
5405 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5406 }
5407 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5408 if (function_exists("php_uname")) {
5409 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5410 }
5411 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5412 $out .= "<br>\n";
5413 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5414 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5415 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5416 $out .= "<br>\n";
5417 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5418 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5419 } else { // Mode CLI
5420 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5421 $syslog .= "pid=".dol_getmypid();
5422 }
5423
5424 if (!empty($conf->modules)) {
5425 $out .= "<b>".$langs->trans("Modules").":</b> ".join(', ', $conf->modules)."<br>\n";
5426 }
5427
5428 if (is_object($db)) {
5429 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5430 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5431 $lastqueryerror = $db->lastqueryerror();
5432 if (!utf8_check($lastqueryerror)) {
5433 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5434 }
5435 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5436 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5437 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5438 $out .= "<br>\n";
5439 } else { // Mode CLI
5440 // No dol_escape_htmltag for output, we are in CLI mode
5441 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5442 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5443 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5444 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5445 }
5446 $syslog .= ", sql=".$db->lastquery();
5447 $syslog .= ", db_error=".$db->lasterror();
5448 }
5449
5450 if ($error || $errors) {
5451 $langs->load("errors");
5452
5453 // Merge all into $errors array
5454 if (is_array($error) && is_array($errors)) {
5455 $errors = array_merge($error, $errors);
5456 } elseif (is_array($error)) {
5457 $errors = $error;
5458 } elseif (is_array($errors)) {
5459 $errors = array_merge(array($error), $errors);
5460 } else {
5461 $errors = array_merge(array($error), array($errors));
5462 }
5463
5464 foreach ($errors as $msg) {
5465 if (empty($msg)) {
5466 continue;
5467 }
5468 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5469 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5470 } else { // Mode CLI
5471 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5472 }
5473 $syslog .= ", msg=".$msg;
5474 }
5475 }
5476 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5477 xdebug_print_function_stack();
5478 $out .= '<b>XDebug informations:</b>'."<br>\n";
5479 $out .= 'File: '.xdebug_call_file()."<br>\n";
5480 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5481 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5482 $out .= "<br>\n";
5483 }
5484
5485 // Return a http header with error code if possible
5486 if (!headers_sent()) {
5487 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5488 top_httphead();
5489 }
5490 //http_response_code(500); // If we use 500, message is not ouput with some command line tools
5491 http_response_code(202); // If we use 202, this is not really an error message, but this allow to ouput message on command line tools
5492 }
5493
5494 if (empty($dolibarr_main_prod)) {
5495 print $out;
5496 } else {
5497 if (empty($langs->defaultlang)) {
5498 $langs->setDefaultLang();
5499 }
5500 $langs->loadLangs(array("main", "errors")); // Reload main because language may have been set only on previous line so we have to reload files we need.
5501 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5502 print 'This website or feature is currently temporarly not available or failed after a technical error.<br><br>This may be due to a maintenance operation. Current status of operation ('.dol_print_date(dol_now(), 'dayhourrfc').') are on next line...<br><br>'."\n";
5503 print $langs->trans("DolibarrHasDetectedError").'. ';
5504 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5505 if (!defined("MAIN_CORE_ERROR")) {
5506 define("MAIN_CORE_ERROR", 1);
5507 }
5508 }
5509
5510 dol_syslog("Error ".$syslog, LOG_ERR);
5511}
5512
5523function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5524{
5525 global $langs, $conf;
5526
5527 if (empty($email)) {
5528 $email = $conf->global->MAIN_INFO_SOCIETE_MAIL;
5529 }
5530
5531 $langs->load("errors");
5532 $now = dol_now();
5533
5534 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5535 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5536 if ($errormessage) {
5537 print '<br><br>'.$errormessage;
5538 }
5539 if (is_array($errormessages) && count($errormessages)) {
5540 foreach ($errormessages as $mesgtoshow) {
5541 print '<br><br>'.$mesgtoshow;
5542 }
5543 }
5544 print '</div></div>';
5545}
5546
5563function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
5564{
5565 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
5566}
5567
5586function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
5587{
5588 global $conf, $langs, $form;
5589 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
5590
5591 if ($moreattrib == 'class="right"') {
5592 $prefix .= 'right '; // For backward compatibility
5593 }
5594
5595 $sortorder = strtoupper($sortorder);
5596 $out = '';
5597 $sortimg = '';
5598
5599 $tag = 'th';
5600 if ($thead == 2) {
5601 $tag = 'div';
5602 }
5603
5604 $tmpsortfield = explode(',', $sortfield);
5605 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
5606 $tmpfield = explode(',', $field);
5607 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
5608
5609 if (!getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle)) {
5610 $prefix = 'wrapcolumntitle '.$prefix;
5611 }
5612
5613 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
5614 // If field is used as sort criteria we use a specific css class liste_titre_sel
5615 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
5616 $liste_titre = 'liste_titre';
5617 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
5618 $liste_titre = 'liste_titre_sel';
5619 }
5620
5621 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
5622 //$out .= (($field && empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && preg_match('/^[a-zA-Z_0-9\s\.\-:&;]*$/', $name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5623 $tagstart .= ($name && !getDolGlobalString('MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE') && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
5624 $tagstart .= '>';
5625
5626 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5627 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5628 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5629 $options = preg_replace('/&+/i', '&', $options);
5630 if (!preg_match('/^&/', $options)) {
5631 $options = '&'.$options;
5632 }
5633
5634 $sortordertouseinlink = '';
5635 if ($field1 != $sortfield1) { // We are on another field than current sorted field
5636 if (preg_match('/^DESC/i', $sortorder)) {
5637 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5638 } else { // We reverse the var $sortordertouseinlink
5639 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5640 }
5641 } else { // We are on field that is the first current sorting criteria
5642 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
5643 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5644 } else {
5645 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5646 }
5647 }
5648 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
5649 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
5650 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5651 $out .= '>';
5652 }
5653 if ($tooltip) {
5654 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
5655 if (preg_match('/:\w+$/', $tooltip)) {
5656 $tmptooltip = explode(':', $tooltip);
5657 } else {
5658 $tmptooltip = array($tooltip);
5659 }
5660 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
5661 } else {
5662 $out .= $langs->trans($name);
5663 }
5664
5665 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5666 $out .= '</a>';
5667 }
5668
5669 if (empty($thead) && $field) { // If this is a sort field
5670 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5671 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5672 $options = preg_replace('/&+/i', '&', $options);
5673 if (!preg_match('/^&/', $options)) {
5674 $options = '&'.$options;
5675 }
5676
5677 if (!$sortorder || ($field1 != $sortfield1)) {
5678 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5679 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5680 } else {
5681 if (preg_match('/^DESC/', $sortorder)) {
5682 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5683 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
5684 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
5685 }
5686 if (preg_match('/^ASC/', $sortorder)) {
5687 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
5688 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5689 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
5690 }
5691 }
5692 }
5693
5694 $tagend = '</'.$tag.'>';
5695
5696 $out = $tagstart.$sortimg.$out.$tagend;
5697
5698 return $out;
5699}
5700
5709function print_titre($title)
5710{
5711 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
5712
5713 print '<div class="titre">'.$title.'</div>';
5714}
5715
5727function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
5728{
5729 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
5730}
5731
5745function load_fiche_titre($titre, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
5746{
5747 global $conf;
5748
5749 $return = '';
5750
5751 if ($picto == 'setup') {
5752 $picto = 'generic';
5753 }
5754
5755 $return .= "\n";
5756 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
5757 $return .= '<tr class="titre">';
5758 if ($picto) {
5759 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
5760 }
5761 $return .= '<td class="nobordernopadding valignmiddle col-title">';
5762 $return .= '<div class="titre inline-block">'.$titre.'</div>';
5763 $return .= '</td>';
5764 if (dol_strlen($morehtmlcenter)) {
5765 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5766 }
5767 if (dol_strlen($morehtmlright)) {
5768 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
5769 }
5770 $return .= '</tr></table>'."\n";
5771
5772 return $return;
5773}
5774
5798function print_barre_liste($titre, $page, $file, $options = '', $sortfield = '', $sortorder = '', $morehtmlcenter = '', $num = -1, $totalnboflines = '', $picto = 'generic', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limit = -1, $hideselectlimit = 0, $hidenavigation = 0, $pagenavastextinput = 0, $morehtmlrightbeforearrow = '')
5799{
5800 global $conf;
5801
5802 $savlimit = $limit;
5803 $savtotalnboflines = $totalnboflines;
5804 $totalnboflines = abs((int) $totalnboflines);
5805
5806 $page = (int) $page;
5807
5808 if ($picto == 'setup') {
5809 $picto = 'title_setup.png';
5810 }
5811 if (($conf->browser->name == 'ie') && $picto == 'generic') {
5812 $picto = 'title.gif';
5813 }
5814 if ($limit < 0) {
5815 $limit = $conf->liste_limit;
5816 }
5817
5818 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
5819 $nextpage = 1;
5820 } else {
5821 $nextpage = 0;
5822 }
5823 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
5824
5825 print "\n";
5826 print "<!-- Begin title -->\n";
5827 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
5828
5829 // Left
5830
5831 if ($picto && $titre) {
5832 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
5833 }
5834
5835 print '<td class="nobordernopadding valignmiddle col-title">';
5836 print '<div class="titre inline-block">'.$titre;
5837 if (!empty($titre) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
5838 print '<span class="opacitymedium colorblack paddingleft">('.$totalnboflines.')</span>';
5839 }
5840 print '</div></td>';
5841
5842 // Center
5843 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
5844 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5845 }
5846
5847 // Right
5848 print '<td class="nobordernopadding valignmiddle right col-right">';
5849 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
5850 if ($sortfield) {
5851 $options .= "&sortfield=".urlencode($sortfield);
5852 }
5853 if ($sortorder) {
5854 $options .= "&sortorder=".urlencode($sortorder);
5855 }
5856 // Show navigation bar
5857 $pagelist = '';
5858 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
5859 if ($totalnboflines) { // If we know total nb of lines
5860 // Define nb of extra page links before and after selected page + ... + first or last
5861 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
5862
5863 if ($limit > 0) {
5864 $nbpages = ceil($totalnboflines / $limit);
5865 } else {
5866 $nbpages = 1;
5867 }
5868 $cpt = ($page - $maxnbofpage);
5869 if ($cpt < 0) {
5870 $cpt = 0;
5871 }
5872
5873 if ($cpt >= 1) {
5874 if (empty($pagenavastextinput)) {
5875 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=0'.$options.'">1</a></li>';
5876 if ($cpt > 2) {
5877 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5878 } elseif ($cpt == 2) {
5879 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page=1'.$options.'">2</a></li>';
5880 }
5881 }
5882 }
5883
5884 do {
5885 if ($pagenavastextinput) {
5886 if ($cpt == $page) {
5887 $pagelist .= '<li class="pagination"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
5888 $pagelist .= '/';
5889 }
5890 } else {
5891 if ($cpt == $page) {
5892 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
5893 } else {
5894 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
5895 }
5896 }
5897 $cpt++;
5898 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
5899
5900 if (empty($pagenavastextinput)) {
5901 if ($cpt < $nbpages) {
5902 if ($cpt < $nbpages - 2) {
5903 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5904 } elseif ($cpt == $nbpages - 2) {
5905 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
5906 }
5907 $pagelist .= '<li class="pagination"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5908 }
5909 } else {
5910 //var_dump($page.' '.$cpt.' '.$nbpages);
5911 $pagelist .= '<li class="pagination paginationlastpage"><a class="reposition" href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5912 }
5913 } else {
5914 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
5915 }
5916 }
5917
5918 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
5919 print_fleche_navigation($page, $file, $options, $nextpage, $pagelist, $morehtmlright, $savlimit, $totalnboflines, $hideselectlimit, $morehtmlrightbeforearrow, $hidenavigation); // output the div and ul for previous/last completed with page numbers into $pagelist
5920 }
5921
5922 // js to autoselect page field on focus
5923 if ($pagenavastextinput) {
5924 print ajax_autoselect('.pageplusone');
5925 }
5926
5927 print '</td>';
5928 print '</tr>';
5929
5930 print '</table>'."\n";
5931
5932 // Center
5933 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
5934 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
5935 }
5936
5937 print "<!-- End title -->\n\n";
5938}
5939
5956function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
5957{
5958 global $conf, $langs;
5959
5960 print '<div class="pagination"><ul>';
5961 if ($beforearrows) {
5962 print '<li class="paginationbeforearrows">';
5963 print $beforearrows;
5964 print '</li>';
5965 }
5966
5967 if (empty($hidenavigation)) {
5968 if ((int) $limit > 0 && empty($hideselectlimit)) {
5969 $pagesizechoices = '10:10,15:15,20:20,30:30,40:40,50:50,100:100,250:250,500:500,1000:1000';
5970 $pagesizechoices .= ',5000:5000,10000:10000,20000:20000';
5971 //$pagesizechoices.=',0:'.$langs->trans("All"); // Not yet supported
5972 //$pagesizechoices.=',2:2';
5973 if (getDolGlobalString('MAIN_PAGESIZE_CHOICES')) {
5974 $pagesizechoices = $conf->global->MAIN_PAGESIZE_CHOICES;
5975 }
5976
5977 print '<li class="pagination">';
5978 print '<select class="flat selectlimit" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
5979 $tmpchoice = explode(',', $pagesizechoices);
5980 $tmpkey = $limit.':'.$limit;
5981 if (!in_array($tmpkey, $tmpchoice)) {
5982 $tmpchoice[] = $tmpkey;
5983 }
5984 $tmpkey = $conf->liste_limit.':'.$conf->liste_limit;
5985 if (!in_array($tmpkey, $tmpchoice)) {
5986 $tmpchoice[] = $tmpkey;
5987 }
5988 asort($tmpchoice, SORT_NUMERIC);
5989 foreach ($tmpchoice as $val) {
5990 $selected = '';
5991 $tmp = explode(':', $val);
5992 $key = $tmp[0];
5993 $val = $tmp[1];
5994 if ($key != '' && $val != '') {
5995 if ((int) $key == (int) $limit) {
5996 $selected = ' selected="selected"';
5997 }
5998 print '<option name="'.$key.'"'.$selected.'>'.dol_escape_htmltag($val).'</option>'."\n";
5999 }
6000 }
6001 print '</select>';
6002 if ($conf->use_javascript_ajax) {
6003 print '<!-- JS CODE TO ENABLE select limit to launch submit of page -->
6004 <script>
6005 jQuery(document).ready(function () {
6006 jQuery(".selectlimit").change(function() {
6007 console.log("Change limit. Send submit");
6008 $(this).parents(\'form:first\').submit();
6009 });
6010 });
6011 </script>
6012 ';
6013 }
6014 print '</li>';
6015 }
6016 if ($page > 0) {
6017 print '<li class="pagination paginationpage paginationpageleft"><a class="paginationprevious reposition" href="'.$file.'?page='.($page - 1).$options.'"><i class="fa fa-chevron-left" title="'.dol_escape_htmltag($langs->trans("Previous")).'"></i></a></li>';
6018 }
6019 if ($betweenarrows) {
6020 print '<!--<div class="betweenarrows nowraponall inline-block">-->';
6021 print $betweenarrows;
6022 print '<!--</div>-->';
6023 }
6024 if ($nextpage > 0) {
6025 print '<li class="pagination paginationpage paginationpageright"><a class="paginationnext reposition" href="'.$file.'?page='.($page + 1).$options.'"><i class="fa fa-chevron-right" title="'.dol_escape_htmltag($langs->trans("Next")).'"></i></a></li>';
6026 }
6027 if ($afterarrows) {
6028 print '<li class="paginationafterarrows">';
6029 print $afterarrows;
6030 print '</li>';
6031 }
6032 }
6033 print '</ul></div>'."\n";
6034}
6035
6036
6048function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, $html = 0)
6049{
6050 $morelabel = '';
6051
6052 if (preg_match('/%/', $rate)) {
6053 $rate = str_replace('%', '', $rate);
6054 $addpercent = true;
6055 }
6056 $reg = array();
6057 if (preg_match('/\‍((.*)\‍)/', $rate, $reg)) {
6058 $morelabel = ' ('.$reg[1].')';
6059 $rate = preg_replace('/\s*'.preg_quote($morelabel, '/').'/', '', $rate);
6060 $morelabel = ' '.($html ? '<span class="opacitymedium">' : '').'('.$reg[1].')'.($html ? '</span>' : '');
6061 }
6062 if (preg_match('/\*/', $rate)) {
6063 $rate = str_replace('*', '', $rate);
6064 $info_bits |= 1;
6065 }
6066
6067 // If rate is '9/9/9' we don't change it. If rate is '9.000' we apply price()
6068 if (!preg_match('/\//', $rate)) {
6069 $ret = price($rate, 0, '', 0, 0).($addpercent ? '%' : '');
6070 } else {
6071 // TODO Split on / and output with a price2num to have clean numbers without ton of 000.
6072 $ret = $rate.($addpercent ? '%' : '');
6073 }
6074 if (($info_bits & 1) && $usestarfornpr >= 0) {
6075 $ret .= ' *';
6076 }
6077 $ret .= $morelabel;
6078 return $ret;
6079}
6080
6081
6097function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1, $currency_code = '')
6098{
6099 global $langs, $conf;
6100
6101 // Clean parameters
6102 if (empty($amount)) {
6103 $amount = 0; // To have a numeric value if amount not defined or = ''
6104 }
6105 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number)
6106 if ($rounding == -1) {
6107 $rounding = min(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), getDolGlobalString('MAIN_MAX_DECIMALS_TOT'));
6108 }
6109 $nbdecimal = $rounding;
6110
6111 if ($outlangs === 'none') {
6112 // Use international separators
6113 $dec = '.';
6114 $thousand = '';
6115 } else {
6116 // Output separators by default (french)
6117 $dec = ',';
6118 $thousand = ' ';
6119
6120 // If $outlangs not forced, we use use language
6121 if (!is_object($outlangs)) {
6122 $outlangs = $langs;
6123 }
6124
6125 if ($outlangs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6126 $dec = $outlangs->transnoentitiesnoconv("SeparatorDecimal");
6127 }
6128 if ($outlangs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6129 $thousand = $outlangs->transnoentitiesnoconv("SeparatorThousand");
6130 }
6131 if ($thousand == 'None') {
6132 $thousand = '';
6133 } elseif ($thousand == 'Space') {
6134 $thousand = ' ';
6135 }
6136 }
6137 //print "outlangs=".$outlangs->defaultlang." amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6138
6139 //print "amount=".$amount."-";
6140 $amount = str_replace(',', '.', $amount); // should be useless
6141 //print $amount."-";
6142 $datas = explode('.', $amount);
6143 $decpart = isset($datas[1]) ? $datas[1] : '';
6144 $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
6145 //print "decpart=".$decpart."<br>";
6146 $end = '';
6147
6148 // We increase nbdecimal if there is more decimal than asked (to not loose information)
6149 if (dol_strlen($decpart) > $nbdecimal) {
6150 $nbdecimal = dol_strlen($decpart);
6151 }
6152
6153 // If nbdecimal is higher than max to show
6154 $nbdecimalmaxshown = (int) str_replace('...', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'));
6155 if ($trunc && $nbdecimal > $nbdecimalmaxshown) {
6156 $nbdecimal = $nbdecimalmaxshown;
6157 if (preg_match('/\.\.\./i', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'))) {
6158 // If output is truncated, we show ...
6159 $end = '...';
6160 }
6161 }
6162
6163 // If force rounding
6164 if ((string) $forcerounding != '-1') {
6165 if ($forcerounding === 'MU') {
6166 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_UNIT');
6167 } elseif ($forcerounding === 'MT') {
6168 $nbdecimal = getDolGlobalInt('MAIN_MAX_DECIMALS_TOT');
6169 } elseif ($forcerounding >= 0) {
6170 $nbdecimal = $forcerounding;
6171 }
6172 }
6173
6174 // Format number
6175 $output = number_format($amount, $nbdecimal, $dec, $thousand);
6176 if ($form) {
6177 $output = preg_replace('/\s/', '&nbsp;', $output);
6178 $output = preg_replace('/\'/', '&#039;', $output);
6179 }
6180 // Add symbol of currency if requested
6181 $cursymbolbefore = $cursymbolafter = '';
6182 if ($currency_code && is_object($outlangs)) {
6183 if ($currency_code == 'auto') {
6184 $currency_code = $conf->currency;
6185 }
6186
6187 $listofcurrenciesbefore = array('AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD', 'CRC', 'ZAR');
6188 $listoflanguagesbefore = array('nl_NL');
6189 if (in_array($currency_code, $listofcurrenciesbefore) || in_array($outlangs->defaultlang, $listoflanguagesbefore)) {
6190 $cursymbolbefore .= $outlangs->getCurrencySymbol($currency_code);
6191 } else {
6192 $tmpcur = $outlangs->getCurrencySymbol($currency_code);
6193 $cursymbolafter .= ($tmpcur == $currency_code ? ' '.$tmpcur : $tmpcur);
6194 }
6195 }
6196 $output = $cursymbolbefore.$output.$end.($cursymbolafter ? ' ' : '').$cursymbolafter;
6197
6198 return $output;
6199}
6200
6225function price2num($amount, $rounding = '', $option = 0)
6226{
6227 global $langs, $conf;
6228
6229 // Clean parameters
6230 if (is_null($amount)) {
6231 $amount = '';
6232 }
6233
6234 // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
6235 // Numbers must be '1234.56'
6236 // Decimal delimiter for PHP and database SQL requests must be '.'
6237 $dec = ',';
6238 $thousand = ' ';
6239 if (is_null($langs)) { // $langs is not defined, we use english values.
6240 $dec = '.';
6241 $thousand = ',';
6242 } else {
6243 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6244 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
6245 }
6246 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6247 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
6248 }
6249 }
6250 if ($thousand == 'None') {
6251 $thousand = '';
6252 } elseif ($thousand == 'Space') {
6253 $thousand = ' ';
6254 }
6255 //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6256
6257 // Convert value to universal number format (no thousand separator, '.' as decimal separator)
6258 if ($option != 1) { // If not a PHP number or unknown, we change or clean format
6259 //print "\n".'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'<br>';
6260 if (!is_numeric($amount)) {
6261 $amount = preg_replace('/[a-zA-Z\/\\\*\‍(\‍)<>\_]/', '', $amount);
6262 }
6263
6264 if ($option == 2 && $thousand == '.' && preg_match('/\.(\d\d\d)$/', (string) $amount)) { // It means the . is used as a thousand separator and string come from input data, so 1.123 is 1123
6265 $amount = str_replace($thousand, '', $amount);
6266 }
6267
6268 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6269 // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
6270 // So if number was already a good number, it is converted into local Dolibarr setup.
6271 if (is_numeric($amount)) {
6272 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6273 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6274 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6275 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6276 $amount = number_format($amount, $nbofdec, $dec, $thousand);
6277 }
6278 //print "QQ".$amount."<br>\n";
6279
6280 // Now make replace (the main goal of function)
6281 if ($thousand != ',' && $thousand != '.') {
6282 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6283 }
6284
6285 $amount = str_replace(' ', '', $amount); // To avoid spaces
6286 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6287 $amount = str_replace($dec, '.', $amount);
6288
6289 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6290 }
6291 //print ' XX'.$amount.' '.$rounding;
6292
6293 // Now, $amount is a real PHP float number. We make a rounding if required.
6294 if ($rounding) {
6295 $nbofdectoround = '';
6296 if ($rounding == 'MU') {
6297 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_UNIT;
6298 } elseif ($rounding == 'MT') {
6299 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_TOT;
6300 } elseif ($rounding == 'MS') {
6301 $nbofdectoround = isset($conf->global->MAIN_MAX_DECIMALS_STOCK) ? $conf->global->MAIN_MAX_DECIMALS_STOCK : 5;
6302 } elseif ($rounding == 'CU') {
6303 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_UNIT'), 8); // TODO Use param of currency
6304 } elseif ($rounding == 'CT') {
6305 $nbofdectoround = max(getDolGlobalString('MAIN_MAX_DECIMALS_TOT'), 8); // TODO Use param of currency
6306 } elseif (is_numeric($rounding)) {
6307 $nbofdectoround = (int) $rounding;
6308 }
6309
6310 //print " RR".$amount.' - '.$nbofdectoround.'<br>';
6311 if (dol_strlen($nbofdectoround)) {
6312 $amount = round(is_string($amount) ? (float) $amount : $amount, $nbofdectoround); // $nbofdectoround can be 0.
6313 } else {
6314 return 'ErrorBadParameterProvidedToFunction';
6315 }
6316 //print ' SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
6317
6318 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6319 // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
6320 if (is_numeric($amount)) {
6321 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6322 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6323 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6324 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6325 $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
6326 }
6327 //print "TT".$amount.'<br>';
6328
6329 // Always make replace because each math function (like round) replace
6330 // with local values and we want a number that has a SQL string format x.y
6331 if ($thousand != ',' && $thousand != '.') {
6332 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6333 }
6334
6335 $amount = str_replace(' ', '', $amount); // To avoid spaces
6336 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6337 $amount = str_replace($dec, '.', $amount);
6338
6339 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6340 }
6341
6342 return $amount;
6343}
6344
6357function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round = -1, $forceunitoutput = 'no', $use_short_label = 0)
6358{
6359 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
6360
6361 if (($forceunitoutput == 'no' && $dimension < 1 / 10000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -6)) {
6362 $dimension = $dimension * 1000000;
6363 $unit = $unit - 6;
6364 } elseif (($forceunitoutput == 'no' && $dimension < 1 / 10 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -3)) {
6365 $dimension = $dimension * 1000;
6366 $unit = $unit - 3;
6367 } elseif (($forceunitoutput == 'no' && $dimension > 100000000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 6)) {
6368 $dimension = $dimension / 1000000;
6369 $unit = $unit + 6;
6370 } elseif (($forceunitoutput == 'no' && $dimension > 100000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 3)) {
6371 $dimension = $dimension / 1000;
6372 $unit = $unit + 3;
6373 }
6374 // Special case when we want output unit into pound or ounce
6375 /* TODO
6376 if ($unit < 90 && $type == 'weight' && is_numeric($forceunitoutput) && (($forceunitoutput == 98) || ($forceunitoutput == 99))
6377 {
6378 $dimension = // convert dimension from standard unit into ounce or pound
6379 $unit = $forceunitoutput;
6380 }
6381 if ($unit > 90 && $type == 'weight' && is_numeric($forceunitoutput) && $forceunitoutput < 90)
6382 {
6383 $dimension = // convert dimension from standard unit into ounce or pound
6384 $unit = $forceunitoutput;
6385 }*/
6386
6387 $ret = price($dimension, 0, $outputlangs, 0, 0, $round);
6388 $ret .= ' '.measuringUnitString(0, $type, $unit, $use_short_label, $outputlangs);
6389
6390 return $ret;
6391}
6392
6393
6406function get_localtax($vatrate, $local, $thirdparty_buyer = "", $thirdparty_seller = "", $vatnpr = 0)
6407{
6408 global $db, $conf, $mysoc;
6409
6410 if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
6411 $thirdparty_seller = $mysoc;
6412 }
6413
6414 dol_syslog("get_localtax tva=".$vatrate." local=".$local." thirdparty_buyer id=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->id : '')."/country_code=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->country_code : '')." thirdparty_seller id=".$thirdparty_seller->id."/country_code=".$thirdparty_seller->country_code." thirdparty_seller localtax1_assuj=".$thirdparty_seller->localtax1_assuj." thirdparty_seller localtax2_assuj=".$thirdparty_seller->localtax2_assuj);
6415
6416 $vatratecleaned = $vatrate;
6417 $reg = array();
6418 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6419 $vatratecleaned = trim($reg[1]);
6420 $vatratecode = $reg[2];
6421 }
6422
6423 /*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
6424 {
6425 return 0;
6426 }*/
6427
6428 // Some test to guess with no need to make database access
6429 if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
6430 if ($local == 1) {
6431 if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
6432 return 0;
6433 }
6434 if ($thirdparty_seller->id == $mysoc->id) {
6435 if (!$thirdparty_buyer->localtax1_assuj) {
6436 return 0;
6437 }
6438 } else {
6439 if (!$thirdparty_seller->localtax1_assuj) {
6440 return 0;
6441 }
6442 }
6443 }
6444
6445 if ($local == 2) {
6446 //if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
6447 if (!$mysoc->localtax2_assuj) {
6448 return 0; // If main vat is 0, IRPF may be different than 0.
6449 }
6450 if ($thirdparty_seller->id == $mysoc->id) {
6451 if (!$thirdparty_buyer->localtax2_assuj) {
6452 return 0;
6453 }
6454 } else {
6455 if (!$thirdparty_seller->localtax2_assuj) {
6456 return 0;
6457 }
6458 }
6459 }
6460 } else {
6461 if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
6462 return 0;
6463 }
6464 if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
6465 return 0;
6466 }
6467 }
6468
6469 // For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
6470 if (in_array($mysoc->country_code, array('ES'))) {
6471 $conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
6472 }
6473
6474 // Search local taxes
6475 if (getDolGlobalString('MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY')) {
6476 if ($local == 1) {
6477 if ($thirdparty_seller != $mysoc) {
6478 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6479 return $thirdparty_seller->localtax1_value;
6480 }
6481 } else { // i am the seller
6482 if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
6483 return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
6484 }
6485 }
6486 }
6487 if ($local == 2) {
6488 if ($thirdparty_seller != $mysoc) {
6489 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6490 // TODO We should also return value defined on thirdparty only if defined
6491 return $thirdparty_seller->localtax2_value;
6492 }
6493 } else { // i am the seller
6494 if (in_array($mysoc->country_code, array('ES'))) {
6495 return $thirdparty_buyer->localtax2_value;
6496 } else {
6497 return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
6498 }
6499 }
6500 }
6501 }
6502
6503 // By default, search value of local tax on line of common tax
6504 $sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
6505 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6506 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
6507 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6508 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
6509 if (!empty($vatratecode)) {
6510 $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
6511 } else {
6512 $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
6513 }
6514
6515 $resql = $db->query($sql);
6516
6517 if ($resql) {
6518 $obj = $db->fetch_object($resql);
6519 if ($obj) {
6520 if ($local == 1) {
6521 return $obj->localtax1;
6522 } elseif ($local == 2) {
6523 return $obj->localtax2;
6524 }
6525 }
6526 }
6527
6528 return 0;
6529}
6530
6531
6540function isOnlyOneLocalTax($local)
6541{
6542 $tax = get_localtax_by_third($local);
6543
6544 $valors = explode(":", $tax);
6545
6546 if (count($valors) > 1) {
6547 return false;
6548 } else {
6549 return true;
6550 }
6551}
6552
6560{
6561 global $db, $mysoc;
6562
6563 $sql = " SELECT t.localtax".$local." as localtax";
6564 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_pays";
6565 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.active = 1 AND t.entity IN (".getEntity('c_tva').") AND t.taux = (";
6566 $sql .= "SELECT MAX(tt.taux) FROM ".MAIN_DB_PREFIX."c_tva as tt INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = tt.fk_pays";
6567 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.entity IN (".getEntity('c_tva').") AND tt.active = 1)";
6568 $sql .= " AND t.localtax".$local."_type <> '0'";
6569 $sql .= " ORDER BY t.rowid DESC";
6570
6571 $resql = $db->query($sql);
6572 if ($resql) {
6573 $o