dolibarr 18.0.6
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 if (!is_object($object) && empty($module)) {
127 return null;
128 }
129 if (empty($module) && !empty($object->element)) {
130 $module = $object->element;
131 }
132 return $conf->$module->multidir_output[(!empty($object->entity) ? $object->entity : $conf->entity)];
133}
134
142function getDolGlobalString($key, $default = '')
143{
144 global $conf;
145 // return $conf->global->$key ?? $default;
146 return (string) (isset($conf->global->$key) ? $conf->global->$key : $default);
147}
148
156function getDolGlobalInt($key, $default = 0)
157{
158 global $conf;
159 // return $conf->global->$key ?? $default;
160 return (int) (isset($conf->global->$key) ? $conf->global->$key : $default);
161}
162
171function getDolUserString($key, $default = '', $tmpuser = null)
172{
173 if (empty($tmpuser)) {
174 global $user;
175 $tmpuser = $user;
176 }
177
178 // return $conf->global->$key ?? $default;
179 return (string) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
180}
181
190function getDolUserInt($key, $default = 0, $tmpuser = null)
191{
192 if (empty($tmpuser)) {
193 global $user;
194 $tmpuser = $user;
195 }
196
197 // return $conf->global->$key ?? $default;
198 return (int) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
199}
200
207function isModEnabled($module)
208{
209 global $conf;
210
211 // Fix special cases
212 $arrayconv = array(
213 'bank' => 'banque',
214 'category' => 'categorie',
215 'contract' => 'contrat',
216 'project' => 'projet',
217 'delivery_note' => 'expedition'
218 );
219 if (empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) {
220 $arrayconv['supplier_order'] = 'fournisseur';
221 $arrayconv['supplier_invoice'] = 'fournisseur';
222 }
223 if (!empty($arrayconv[$module])) {
224 $module = $arrayconv[$module];
225 }
226
227 return !empty($conf->modules[$module]);
228 //return !empty($conf->$module->enabled);
229}
230
242function getDoliDBInstance($type, $host, $user, $pass, $name, $port)
243{
244 require_once DOL_DOCUMENT_ROOT."/core/db/".$type.'.class.php';
245
246 $class = 'DoliDB'.ucfirst($type);
247 $dolidb = new $class($type, $host, $user, $pass, $name, $port);
248 return $dolidb;
249}
250
268function getEntity($element, $shared = 1, $currentobject = null)
269{
270 global $conf, $mc, $hookmanager, $object, $action, $db;
271
272 if (!is_object($hookmanager)) {
273 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
274 $hookmanager = new HookManager($db);
275 }
276
277 // fix different element names (France to English)
278 switch ($element) {
279 case 'projet':
280 $element = 'project';
281 break;
282 case 'contrat':
283 $element = 'contract';
284 break; // "/contrat/class/contrat.class.php"
285 case 'order_supplier':
286 $element = 'supplier_order';
287 break; // "/fourn/class/fournisseur.commande.class.php"
288 case 'invoice_supplier':
289 $element = 'supplier_invoice';
290 break; // "/fourn/class/fournisseur.facture.class.php"
291 }
292
293 if (is_object($mc)) {
294 $out = $mc->getEntity($element, $shared, $currentobject);
295 } else {
296 $out = '';
297 $addzero = array('user', 'usergroup', 'cronjob', 'c_email_templates', 'email_template', 'default_values', 'overwrite_trans');
298 if (in_array($element, $addzero)) {
299 $out .= '0,';
300 }
301 $out .= ((int) $conf->entity);
302 }
303
304 // Manipulate entities to query on the fly
305 $parameters = array(
306 'element' => $element,
307 'shared' => $shared,
308 'object' => $object,
309 'currentobject' => $currentobject,
310 'out' => $out
311 );
312 $reshook = $hookmanager->executeHooks('hookGetEntity', $parameters, $currentobject, $action); // Note that $action and $object may have been modified by some hooks
313
314 if (is_numeric($reshook)) {
315 if ($reshook == 0 && !empty($hookmanager->resPrint)) {
316 $out .= ','.$hookmanager->resPrint; // add
317 } elseif ($reshook == 1) {
318 $out = $hookmanager->resPrint; // replace
319 }
320 }
321
322 return $out;
323}
324
331function setEntity($currentobject)
332{
333 global $conf, $mc;
334
335 if (is_object($mc) && method_exists($mc, 'setEntity')) {
336 return $mc->setEntity($currentobject);
337 } else {
338 return ((is_object($currentobject) && $currentobject->id > 0 && $currentobject->entity > 0) ? $currentobject->entity : $conf->entity);
339 }
340}
341
348function isASecretKey($keyname)
349{
350 return preg_match('/(_pass|password|_pw|_key|securekey|serverkey|secret\d?|p12key|exportkey|_PW_[a-z]+|token)$/i', $keyname);
351}
352
353
360function num2Alpha($n)
361{
362 for ($r = ""; $n >= 0; $n = intval($n / 26) - 1)
363 $r = chr($n % 26 + 0x41) . $r;
364 return $r;
365}
366
367
384function getBrowserInfo($user_agent)
385{
386 include_once DOL_DOCUMENT_ROOT.'/includes/mobiledetect/mobiledetectlib/Mobile_Detect.php';
387
388 $name = 'unknown';
389 $version = '';
390 $os = 'unknown';
391 $phone = '';
392
393 $user_agent = substr($user_agent, 0, 512); // Avoid to process too large user agent
394
395 $detectmobile = new Mobile_Detect(null, $user_agent);
396 $tablet = $detectmobile->isTablet();
397
398 if ($detectmobile->isMobile()) {
399 $phone = 'unknown';
400
401 // If phone/smartphone, we set phone os name.
402 if ($detectmobile->is('AndroidOS')) {
403 $os = $phone = 'android';
404 } elseif ($detectmobile->is('BlackBerryOS')) {
405 $os = $phone = 'blackberry';
406 } elseif ($detectmobile->is('iOS')) {
407 $os = 'ios';
408 $phone = 'iphone';
409 } elseif ($detectmobile->is('PalmOS')) {
410 $os = $phone = 'palm';
411 } elseif ($detectmobile->is('SymbianOS')) {
412 $os = 'symbian';
413 } elseif ($detectmobile->is('webOS')) {
414 $os = 'webos';
415 } elseif ($detectmobile->is('MaemoOS')) {
416 $os = 'maemo';
417 } elseif ($detectmobile->is('WindowsMobileOS') || $detectmobile->is('WindowsPhoneOS')) {
418 $os = 'windows';
419 }
420 }
421
422 // OS
423 if (preg_match('/linux/i', $user_agent)) {
424 $os = 'linux';
425 } elseif (preg_match('/macintosh/i', $user_agent)) {
426 $os = 'macintosh';
427 } elseif (preg_match('/windows/i', $user_agent)) {
428 $os = 'windows';
429 }
430
431 // Name
432 $reg = array();
433 if (preg_match('/firefox(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
434 $name = 'firefox';
435 $version = empty($reg[2]) ? '' : $reg[2];
436 } elseif (preg_match('/edge(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
437 $name = 'edge';
438 $version = empty($reg[2]) ? '' : $reg[2];
439 } elseif (preg_match('/chrome(\/|\s)([\d\.]+)/i', $user_agent, $reg)) {
440 $name = 'chrome';
441 $version = empty($reg[2]) ? '' : $reg[2];
442 } elseif (preg_match('/chrome/i', $user_agent, $reg)) {
443 // we can have 'chrome (Mozilla...) chrome x.y' in one string
444 $name = 'chrome';
445 } elseif (preg_match('/iceweasel/i', $user_agent)) {
446 $name = 'iceweasel';
447 } elseif (preg_match('/epiphany/i', $user_agent)) {
448 $name = 'epiphany';
449 } elseif (preg_match('/safari(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
450 $name = 'safari';
451 $version = empty($reg[2]) ? '' : $reg[2];
452 } elseif (preg_match('/opera(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
453 // Safari is often present in string for mobile but its not.
454 $name = 'opera';
455 $version = empty($reg[2]) ? '' : $reg[2];
456 } elseif (preg_match('/(MSIE\s([0-9]+\.[0-9]))|.*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
457 $name = 'ie';
458 $version = end($reg);
459 } elseif (preg_match('/(Windows NT\s([0-9]+\.[0-9])).*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
460 // MS products at end
461 $name = 'ie';
462 $version = end($reg);
463 } elseif (preg_match('/l[iy]n(x|ks)(\‍(|\/|\s)*([\d\.]+)/i', $user_agent, $reg)) {
464 // MS products at end
465 $name = 'lynxlinks';
466 $version = empty($reg[3]) ? '' : $reg[3];
467 }
468
469 if ($tablet) {
470 $layout = 'tablet';
471 } elseif ($phone) {
472 $layout = 'phone';
473 } else {
474 $layout = 'classic';
475 }
476
477 return array(
478 'browsername' => $name,
479 'browserversion' => $version,
480 'browseros' => $os,
481 'browserua' => $user_agent,
482 'layout' => $layout, // tablet, phone, classic
483 'phone' => $phone, // deprecated
484 'tablet' => $tablet // deprecated
485 );
486}
487
493function dol_shutdown()
494{
495 global $user, $langs, $db;
496 $disconnectdone = false;
497 $depth = 0;
498 if (is_object($db) && !empty($db->connected)) {
499 $depth = $db->transaction_opened;
500 $disconnectdone = $db->close();
501 }
502 dol_syslog("--- End access to ".$_SERVER["PHP_SELF"].(($disconnectdone && $depth) ? ' (Warn: db disconnection forced, transaction depth was '.$depth.')' : ''), (($disconnectdone && $depth) ? LOG_WARNING : LOG_INFO));
503}
504
514function GETPOSTISSET($paramname)
515{
516 $isset = false;
517
518 $relativepathstring = $_SERVER["PHP_SELF"];
519 // Clean $relativepathstring
520 if (constant('DOL_URL_ROOT')) {
521 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
522 }
523 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
524 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
525 //var_dump($relativepathstring);
526 //var_dump($user->default_values);
527
528 // Code for search criteria persistence.
529 // Retrieve values if restore_lastsearch_values
530 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
531 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
532 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
533 if (is_array($tmp)) {
534 foreach ($tmp as $key => $val) {
535 if ($key == $paramname) { // We are on the requested parameter
536 $isset = true;
537 break;
538 }
539 }
540 }
541 }
542 // If there is saved contextpage, limit, page or mode
543 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
544 $isset = true;
545 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
546 $isset = true;
547 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
548 $isset = true;
549 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
550 $isset = true;
551 }
552 } else {
553 $isset = (isset($_POST[$paramname]) || isset($_GET[$paramname])); // We must keep $_POST and $_GET here
554 }
555
556 return $isset;
557}
558
567function GETPOSTISARRAY($paramname, $method = 0)
568{
569 // for $method test need return the same $val as GETPOST
570 if (empty($method)) {
571 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
572 } elseif ($method == 1) {
573 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
574 } elseif ($method == 2) {
575 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
576 } elseif ($method == 3) {
577 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
578 } else {
579 $val = 'BadFirstParameterForGETPOST';
580 }
581
582 return is_array($val);
583}
584
614function GETPOST($paramname, $check = 'alphanohtml', $method = 0, $filter = null, $options = null, $noreplace = 0)
615{
616 global $mysoc, $user, $conf;
617
618 if (empty($paramname)) {
619 return 'BadFirstParameterForGETPOST';
620 }
621 if (empty($check)) {
622 dol_syslog("Deprecated use of GETPOST, called with 1st param = ".$paramname." and 2nd param is '', when calling page ".$_SERVER["PHP_SELF"], LOG_WARNING);
623 // Enable this line to know who call the GETPOST with '' $check parameter.
624 //var_dump(debug_backtrace()[0]);
625 }
626
627 if (empty($method)) {
628 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
629 } elseif ($method == 1) {
630 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
631 } elseif ($method == 2) {
632 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
633 } elseif ($method == 3) {
634 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
635 } else {
636 return 'BadThirdParameterForGETPOST';
637 }
638
639 if (empty($method) || $method == 3 || $method == 4) {
640 $relativepathstring = $_SERVER["PHP_SELF"];
641 // Clean $relativepathstring
642 if (constant('DOL_URL_ROOT')) {
643 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
644 }
645 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
646 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
647 //var_dump($relativepathstring);
648 //var_dump($user->default_values);
649
650 // Code for search criteria persistence.
651 // Retrieve values if restore_lastsearch_values
652 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
653 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
654 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
655 if (is_array($tmp)) {
656 foreach ($tmp as $key => $val) {
657 if ($key == $paramname) { // We are on the requested parameter
658 $out = $val;
659 break;
660 }
661 }
662 }
663 }
664 // If there is saved contextpage, page or limit
665 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
666 $out = $_SESSION['lastsearch_contextpage_'.$relativepathstring];
667 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
668 $out = $_SESSION['lastsearch_limit_'.$relativepathstring];
669 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
670 $out = $_SESSION['lastsearch_page_'.$relativepathstring];
671 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
672 $out = $_SESSION['lastsearch_mode_'.$relativepathstring];
673 }
674 } elseif (!isset($_GET['sortfield'])) {
675 // Else, retrieve default values if we are not doing a sort
676 // 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
677 if (!empty($_GET['action']) && $_GET['action'] == 'create' && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
678 // Search default value from $object->field
679 global $object;
680 if (is_object($object) && isset($object->fields[$paramname]['default'])) {
681 $out = $object->fields[$paramname]['default'];
682 }
683 }
684 if (!empty($conf->global->MAIN_ENABLE_DEFAULT_VALUES)) {
685 if (!empty($_GET['action']) && (preg_match('/^create/', $_GET['action']) || preg_match('/^presend/', $_GET['action'])) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
686 // Now search in setup to overwrite default values
687 if (!empty($user->default_values)) { // $user->default_values defined from menu 'Setup - Default values'
688 if (isset($user->default_values[$relativepathstring]['createform'])) {
689 foreach ($user->default_values[$relativepathstring]['createform'] as $defkey => $defval) {
690 $qualified = 0;
691 if ($defkey != '_noquery_') {
692 $tmpqueryarraytohave = explode('&', $defkey);
693 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
694 $foundintru = 0;
695 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
696 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
697 $foundintru = 1;
698 }
699 }
700 if (!$foundintru) {
701 $qualified = 1;
702 }
703 //var_dump($defkey.'-'.$qualified);
704 } else {
705 $qualified = 1;
706 }
707
708 if ($qualified) {
709 if (isset($user->default_values[$relativepathstring]['createform'][$defkey][$paramname])) {
710 $out = $user->default_values[$relativepathstring]['createform'][$defkey][$paramname];
711 break;
712 }
713 }
714 }
715 }
716 }
717 } elseif (!empty($paramname) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
718 // Management of default search_filters and sort order
719 if (!empty($user->default_values)) {
720 // $user->default_values defined from menu 'Setup - Default values'
721 //var_dump($user->default_values[$relativepathstring]);
722 if ($paramname == 'sortfield' || $paramname == 'sortorder') {
723 // Sorted on which fields ? ASC or DESC ?
724 if (isset($user->default_values[$relativepathstring]['sortorder'])) {
725 // Even if paramname is sortfield, data are stored into ['sortorder...']
726 foreach ($user->default_values[$relativepathstring]['sortorder'] as $defkey => $defval) {
727 $qualified = 0;
728 if ($defkey != '_noquery_') {
729 $tmpqueryarraytohave = explode('&', $defkey);
730 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
731 $foundintru = 0;
732 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
733 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
734 $foundintru = 1;
735 }
736 }
737 if (!$foundintru) {
738 $qualified = 1;
739 }
740 //var_dump($defkey.'-'.$qualified);
741 } else {
742 $qualified = 1;
743 }
744
745 if ($qualified) {
746 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
747 foreach ($user->default_values[$relativepathstring]['sortorder'][$defkey] as $key => $val) {
748 if ($out) {
749 $out .= ', ';
750 }
751 if ($paramname == 'sortfield') {
752 $out .= dol_string_nospecial($key, '', $forbidden_chars_to_replace);
753 }
754 if ($paramname == 'sortorder') {
755 $out .= dol_string_nospecial($val, '', $forbidden_chars_to_replace);
756 }
757 }
758 //break; // No break for sortfield and sortorder so we can cumulate fields (is it realy usefull ?)
759 }
760 }
761 }
762 } elseif (isset($user->default_values[$relativepathstring]['filters'])) {
763 foreach ($user->default_values[$relativepathstring]['filters'] as $defkey => $defval) { // $defkey is a querystring like 'a=b&c=d', $defval is key of user
764 if (!empty($_GET['disabledefaultvalues'])) { // If set of default values has been disabled by a request parameter
765 continue;
766 }
767 $qualified = 0;
768 if ($defkey != '_noquery_') {
769 $tmpqueryarraytohave = explode('&', $defkey);
770 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
771 $foundintru = 0;
772 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
773 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
774 $foundintru = 1;
775 }
776 }
777 if (!$foundintru) {
778 $qualified = 1;
779 }
780 //var_dump($defkey.'-'.$qualified);
781 } else {
782 $qualified = 1;
783 }
784
785 if ($qualified && isset($user->default_values[$relativepathstring]['filters'][$defkey][$paramname])) {
786 // We must keep $_POST and $_GET here
787 if (isset($_POST['sall']) || isset($_POST['search_all']) || isset($_GET['sall']) || isset($_GET['search_all'])) {
788 // We made a search from quick search menu, do we still use default filter ?
789 if (empty($conf->global->MAIN_DISABLE_DEFAULT_FILTER_FOR_QUICK_SEARCH)) {
790 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
791 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
792 }
793 } else {
794 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
795 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
796 }
797 break;
798 }
799 }
800 }
801 }
802 }
803 }
804 }
805 }
806
807 // Substitution variables for GETPOST (used to get final url with variable parameters or final default value with variable parameters)
808 // Example of variables: __DAY__, __MONTH__, __YEAR__, __MYCOMPANY_COUNTRY_ID__, __USER_ID__, ...
809 // 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.
810 if (!is_array($out) && empty($_POST[$paramname]) && empty($noreplace)) {
811 $reg = array();
812 $maxloop = 20;
813 $loopnb = 0; // Protection against infinite loop
814 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.
815 $loopnb++;
816 $newout = '';
817
818 if ($reg[1] == 'DAY') {
819 $tmp = dol_getdate(dol_now(), true);
820 $newout = $tmp['mday'];
821 } elseif ($reg[1] == 'MONTH') {
822 $tmp = dol_getdate(dol_now(), true);
823 $newout = $tmp['mon'];
824 } elseif ($reg[1] == 'YEAR') {
825 $tmp = dol_getdate(dol_now(), true);
826 $newout = $tmp['year'];
827 } elseif ($reg[1] == 'PREVIOUS_DAY') {
828 $tmp = dol_getdate(dol_now(), true);
829 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
830 $newout = $tmp2['day'];
831 } elseif ($reg[1] == 'PREVIOUS_MONTH') {
832 $tmp = dol_getdate(dol_now(), true);
833 $tmp2 = dol_get_prev_month($tmp['mon'], $tmp['year']);
834 $newout = $tmp2['month'];
835 } elseif ($reg[1] == 'PREVIOUS_YEAR') {
836 $tmp = dol_getdate(dol_now(), true);
837 $newout = ($tmp['year'] - 1);
838 } elseif ($reg[1] == 'NEXT_DAY') {
839 $tmp = dol_getdate(dol_now(), true);
840 $tmp2 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
841 $newout = $tmp2['day'];
842 } elseif ($reg[1] == 'NEXT_MONTH') {
843 $tmp = dol_getdate(dol_now(), true);
844 $tmp2 = dol_get_next_month($tmp['mon'], $tmp['year']);
845 $newout = $tmp2['month'];
846 } elseif ($reg[1] == 'NEXT_YEAR') {
847 $tmp = dol_getdate(dol_now(), true);
848 $newout = ($tmp['year'] + 1);
849 } elseif ($reg[1] == 'MYCOMPANY_COUNTRY_ID' || $reg[1] == 'MYCOUNTRY_ID' || $reg[1] == 'MYCOUNTRYID') {
850 $newout = $mysoc->country_id;
851 } elseif ($reg[1] == 'USER_ID' || $reg[1] == 'USERID') {
852 $newout = $user->id;
853 } elseif ($reg[1] == 'USER_SUPERVISOR_ID' || $reg[1] == 'SUPERVISOR_ID' || $reg[1] == 'SUPERVISORID') {
854 $newout = $user->fk_user;
855 } elseif ($reg[1] == 'ENTITY_ID' || $reg[1] == 'ENTITYID') {
856 $newout = $conf->entity;
857 } else {
858 $newout = ''; // Key not found, we replace with empty string
859 }
860 //var_dump('__'.$reg[1].'__ -> '.$newout);
861 $out = preg_replace('/__'.preg_quote($reg[1], '/').'__/', $newout, $out);
862 }
863 }
864
865 // Check rule
866 if (preg_match('/^array/', $check)) { // If 'array' or 'array:restricthtml' or 'array:aZ09' or 'array:intcomma'
867 if (!is_array($out) || empty($out)) {
868 $out = array();
869 } else {
870 $tmparray = explode(':', $check);
871 if (!empty($tmparray[1])) {
872 $tmpcheck = $tmparray[1];
873 } else {
874 $tmpcheck = 'alphanohtml';
875 }
876 foreach ($out as $outkey => $outval) {
877 $out[$outkey] = sanitizeVal($outval, $tmpcheck, $filter, $options);
878 }
879 }
880 } else {
881 // If field name is 'search_xxx' then we force the add of space after each < and > (when following char is numeric) because it means
882 // 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
883 if (strpos($paramname, 'search_') === 0) {
884 $out = preg_replace('/([<>])([-+]?\d)/', '\1 \2', $out);
885 }
886
887 $out = sanitizeVal($out, $check, $filter, $options);
888 }
889
890 // Sanitizing for special parameters.
891 // Note: There is no reason to allow the backtopage, backtolist or backtourl parameter to contains an external URL. Only relative URLs are allowed.
892 if ($paramname == 'backtopage' || $paramname == 'backtolist' || $paramname == 'backtourl') {
893 $out = str_replace('\\', '/', $out); // Can be before the loop because only 1 char is replaced. No risk to get it after other replacements.
894 $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.
895 do {
896 $oldstringtoclean = $out;
897 $out = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $out);
898 $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'
899 $out = preg_replace(array('/^[a-z]*\/\s*\/+/i'), '', $out); // We remove schema*// to remove external URL
900 } while ($oldstringtoclean != $out);
901 }
902
903 // Code for search criteria persistence.
904 // Save data into session if key start with 'search_' or is 'smonth', 'syear', 'month', 'year'
905 if (empty($method) || $method == 3 || $method == 4) {
906 if (preg_match('/^search_/', $paramname) || in_array($paramname, array('sortorder', 'sortfield'))) {
907 //var_dump($paramname.' - '.$out.' '.$user->default_values[$relativepathstring]['filters'][$paramname]);
908
909 // We save search key only if $out not empty that means:
910 // - posted value not empty, or
911 // - 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).
912
913 if ($out != '' && isset($user)) {// $out = '0' or 'abc', it is a search criteria to keep
914 $user->lastsearch_values_tmp[$relativepathstring][$paramname] = $out;
915 }
916 }
917 }
918
919 return $out;
920}
921
931function GETPOSTINT($paramname, $method = 0)
932{
933 return (int) GETPOST($paramname, 'int', $method, null, null, 0);
934}
935
936
947function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
948{
949 return sanitizeVal($out, $check, $filter, $options);
950}
951
961function sanitizeVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
962{
963 // TODO : use class "Validate" to perform tests (and add missing tests) if needed for factorize
964 // Check is done after replacement
965 switch ($check) {
966 case 'none':
967 break;
968 case 'int': // Check param is a numeric value (integer but also float or hexadecimal)
969 if (!is_numeric($out)) {
970 $out = '';
971 }
972 break;
973 case 'intcomma':
974 if (is_array($out)) {
975 $out = implode(',', $out);
976 }
977 if (preg_match('/[^0-9,-]+/i', $out)) {
978 $out = '';
979 }
980 break;
981 case 'san_alpha':
982 $out = filter_var($out, FILTER_SANITIZE_STRING);
983 break;
984 case 'email':
985 $out = filter_var($out, FILTER_SANITIZE_EMAIL);
986 break;
987 case 'aZ':
988 if (!is_array($out)) {
989 $out = trim($out);
990 if (preg_match('/[^a-z]+/i', $out)) {
991 $out = '';
992 }
993 }
994 break;
995 case 'aZ09':
996 if (!is_array($out)) {
997 $out = trim($out);
998 if (preg_match('/[^a-z0-9_\-\.]+/i', $out)) {
999 $out = '';
1000 }
1001 }
1002 break;
1003 case 'aZ09arobase': // great to sanitize $objecttype parameter
1004 if (!is_array($out)) {
1005 $out = trim($out);
1006 if (preg_match('/[^a-z0-9_\-\.@]+/i', $out)) {
1007 $out = '';
1008 }
1009 }
1010 break;
1011 case 'aZ09comma': // great to sanitize $sortfield or $sortorder params that can be 't.abc,t.def_gh'
1012 if (!is_array($out)) {
1013 $out = trim($out);
1014 if (preg_match('/[^a-z0-9_\-\.,]+/i', $out)) {
1015 $out = '';
1016 }
1017 }
1018 break;
1019 case 'alpha': // No html and no ../ and "
1020 case 'alphanohtml': // Recommended for most scalar parameters and search parameters
1021 if (!is_array($out)) {
1022 $out = trim($out);
1023 do {
1024 $oldstringtoclean = $out;
1025 // Remove html tags
1026 $out = dol_string_nohtmltag($out, 0);
1027 // Remove also other dangerous string sequences
1028 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1029 // '../' or '..\' is dangerous because it allows dir transversals
1030 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1031 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1032 } while ($oldstringtoclean != $out);
1033 // keep lines feed
1034 }
1035 break;
1036 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'
1037 if (!is_array($out)) {
1038 $out = trim($out);
1039 do {
1040 $oldstringtoclean = $out;
1041 // Remove html tags
1042 $out = dol_html_entity_decode($out, ENT_COMPAT | ENT_HTML5, 'UTF-8');
1043 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1044 // '../' or '..\' is dangerous because it allows dir transversals
1045 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1046 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1047 } while ($oldstringtoclean != $out);
1048 }
1049 break;
1050 case 'nohtml': // No html
1051 $out = dol_string_nohtmltag($out, 0);
1052 break;
1053 case 'restricthtmlnolink':
1054 case 'restricthtml': // Recommended for most html textarea
1055 case 'restricthtmlallowclass':
1056 case 'restricthtmlallowunvalid':
1057 $out = dol_htmlwithnojs($out, 1, $check);
1058 break;
1059 case 'custom':
1060 if (!empty($out)) {
1061 if (empty($filter)) {
1062 return 'BadParameterForGETPOST - Param 3 of sanitizeVal()';
1063 }
1064 /*if (empty($options)) {
1065 return 'BadParameterForGETPOST - Param 4 of sanitizeVal()';
1066 }*/
1067 $out = filter_var($out, $filter, $options);
1068 }
1069 break;
1070 }
1071
1072 return $out;
1073}
1074
1075
1076if (!function_exists('dol_getprefix')) {
1086 function dol_getprefix($mode = '')
1087 {
1088 // If prefix is for email (we need to have $conf already loaded for this case)
1089 if ($mode == 'email') {
1090 global $conf;
1091
1092 if (!empty($conf->global->MAIL_PREFIX_FOR_EMAIL_ID)) { // If MAIL_PREFIX_FOR_EMAIL_ID is set
1093 if ($conf->global->MAIL_PREFIX_FOR_EMAIL_ID != 'SERVER_NAME') {
1094 return $conf->global->MAIL_PREFIX_FOR_EMAIL_ID;
1095 } elseif (isset($_SERVER["SERVER_NAME"])) { // If MAIL_PREFIX_FOR_EMAIL_ID is set to 'SERVER_NAME'
1096 return $_SERVER["SERVER_NAME"];
1097 }
1098 }
1099
1100 // The recommended value if MAIL_PREFIX_FOR_EMAIL_ID is not defined (may be not defined for old versions)
1101 if (!empty($conf->file->instance_unique_id)) {
1102 return sha1('dolibarr'.$conf->file->instance_unique_id);
1103 }
1104
1105 // For backward compatibility when instance_unique_id is not set
1106 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1107 }
1108
1109 // If prefix is for session (no need to have $conf loaded)
1110 global $dolibarr_main_instance_unique_id, $dolibarr_main_cookie_cryptkey; // This is loaded by filefunc.inc.php
1111 $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
1112
1113 // The recommended value (may be not defined for old versions)
1114 if (!empty($tmp_instance_unique_id)) {
1115 return sha1('dolibarr'.$tmp_instance_unique_id);
1116 }
1117
1118 // For backward compatibility when instance_unique_id is not set
1119 if (isset($_SERVER["SERVER_NAME"]) && isset($_SERVER["DOCUMENT_ROOT"])) {
1120 return sha1($_SERVER["SERVER_NAME"].$_SERVER["DOCUMENT_ROOT"].DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1121 } else {
1122 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1123 }
1124 }
1125}
1126
1137function dol_include_once($relpath, $classname = '')
1138{
1139 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']
1140
1141 $fullpath = dol_buildpath($relpath);
1142
1143 if (!file_exists($fullpath)) {
1144 dol_syslog('functions::dol_include_once Tried to load unexisting file: '.$relpath, LOG_WARNING);
1145 return false;
1146 }
1147
1148 if (!empty($classname) && !class_exists($classname)) {
1149 return include $fullpath;
1150 } else {
1151 return include_once $fullpath;
1152 }
1153}
1154
1155
1166function dol_buildpath($path, $type = 0, $returnemptyifnotfound = 0)
1167{
1168 global $conf;
1169
1170 $path = preg_replace('/^\//', '', $path);
1171
1172 if (empty($type)) { // For a filesystem path
1173 $res = DOL_DOCUMENT_ROOT.'/'.$path; // Standard default path
1174 if (is_array($conf->file->dol_document_root)) {
1175 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array("main"=>"/home/main/htdocs", "alt0"=>"/home/dirmod/htdocs", ...)
1176 if ($key == 'main') {
1177 continue;
1178 }
1179 // if (@file_exists($dirroot.'/'.$path)) {
1180 if (@file_exists($dirroot.'/'.$path)) { // avoid [php:warn]
1181 $res = $dirroot.'/'.$path;
1182 return $res;
1183 }
1184 }
1185 }
1186 if ($returnemptyifnotfound) {
1187 // Not found into alternate dir
1188 if ($returnemptyifnotfound == 1 || !file_exists($res)) {
1189 return '';
1190 }
1191 }
1192 } else {
1193 // For an url path
1194 // We try to get local path of file on filesystem from url
1195 // Note that trying to know if a file on disk exist by forging path on disk from url
1196 // works only for some web server and some setup. This is bugged when
1197 // using proxy, rewriting, virtual path, etc...
1198 $res = '';
1199 if ($type == 1) {
1200 $res = DOL_URL_ROOT.'/'.$path; // Standard value
1201 }
1202 if ($type == 2) {
1203 $res = DOL_MAIN_URL_ROOT.'/'.$path; // Standard value
1204 }
1205 if ($type == 3) {
1206 $res = DOL_URL_ROOT.'/'.$path;
1207 }
1208
1209 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array(["main"]=>"/home/main/htdocs", ["alt0"]=>"/home/dirmod/htdocs", ...)
1210 if ($key == 'main') {
1211 if ($type == 3) {
1212 global $dolibarr_main_url_root;
1213
1214 // Define $urlwithroot
1215 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
1216 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1217 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1218
1219 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).'/'.$path; // Test on start with http is for old conf syntax
1220 }
1221 continue;
1222 }
1223 $regs = array();
1224 preg_match('/^([^\?]+(\.css\.php|\.css|\.js\.php|\.js|\.png|\.jpg|\.php)?)/i', $path, $regs); // Take part before '?'
1225 if (!empty($regs[1])) {
1226 //print $key.'-'.$dirroot.'/'.$path.'-'.$conf->file->dol_url_root[$type].'<br>'."\n";
1227 //if (file_exists($dirroot.'/'.$regs[1])) {
1228 if (@file_exists($dirroot.'/'.$regs[1])) { // avoid [php:warn]
1229 if ($type == 1) {
1230 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1231 }
1232 if ($type == 2) {
1233 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_MAIN_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1234 }
1235 if ($type == 3) {
1236 global $dolibarr_main_url_root;
1237
1238 // Define $urlwithroot
1239 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
1240 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1241 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1242
1243 $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
1244 }
1245 break;
1246 }
1247 }
1248 }
1249 }
1250
1251 return $res;
1252}
1253
1265function dol_clone($object, $native = 0)
1266{
1267 if ($native == 0) {
1268 // deprecated method, use the method with native = 2 instead
1269 $tmpsavdb = null;
1270 if (isset($object->db) && isset($object->db->db) && is_object($object->db->db) && get_class($object->db->db) == 'PgSql\Connection') {
1271 $tmpsavdb = $object->db;
1272 unset($object->db); // Such property can not be serialized with pgsl (when object->db->db = 'PgSql\Connection')
1273 }
1274
1275 $myclone = unserialize(serialize($object)); // serialize then unserialize is a hack to be sure to have a new object for all fields
1276
1277 if (!empty($tmpsavdb)) {
1278 $object->db = $tmpsavdb;
1279 }
1280 } elseif ($native == 2) {
1281 // recommended method to have a full isolated cloned object
1282 $myclone = new stdClass();
1283 $tmparray = get_object_vars($object); // return only public properties
1284
1285 if (is_array($tmparray)) {
1286 foreach ($tmparray as $propertykey => $propertyval) {
1287 if (is_scalar($propertyval) || is_array($propertyval)) {
1288 $myclone->$propertykey = $propertyval;
1289 }
1290 }
1291 }
1292 } else {
1293 $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)
1294 }
1295
1296 return $myclone;
1297}
1298
1308function dol_size($size, $type = '')
1309{
1310 global $conf;
1311 if (empty($conf->dol_optimize_smallscreen)) {
1312 return $size;
1313 }
1314 if ($type == 'width' && $size > 250) {
1315 return 250;
1316 } else {
1317 return 10;
1318 }
1319}
1320
1321
1333function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1)
1334{
1335 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1336 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1337 // Char '/' and '\' are file delimiters.
1338 // 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
1339 $filesystem_forbidden_chars = array('<', '>', '/', '\\', '?', '*', '|', '"', ':', '°', '$', ';', '`');
1340 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1341 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1342 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1343 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1344 $tmp = str_replace('..', '', $tmp);
1345 return $tmp;
1346}
1347
1359function dol_sanitizePathName($str, $newstr = '_', $unaccent = 1)
1360{
1361 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1362 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1363 // 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
1364 $filesystem_forbidden_chars = array('<', '>', '?', '*', '|', '"', '°', '$', ';', '`');
1365 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1366 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1367 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1368 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1369 $tmp = str_replace('..', '', $tmp);
1370 return $tmp;
1371}
1372
1380function dol_sanitizeUrl($stringtoclean, $type = 1)
1381{
1382 // 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)
1383 // We should use dol_string_nounprintableascii but function may not be yet loaded/available
1384 $stringtoclean = preg_replace('/[\x00-\x1F\x7F]/u', '', $stringtoclean); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1385 // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: on<!-- -->error=alert(1)
1386 $stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
1387
1388 $stringtoclean = str_replace('\\', '/', $stringtoclean);
1389 if ($type == 1) {
1390 // removing : should disable links to external url like http:aaa)
1391 // removing ';' should disable "named" html entities encode into an url (we should not have this into an url)
1392 $stringtoclean = str_replace(array(':', ';', '@'), '', $stringtoclean);
1393 }
1394
1395 do {
1396 $oldstringtoclean = $stringtoclean;
1397 // removing '&colon' should disable links to external url like http:aaa)
1398 // removing '&#' should disable "numeric" html entities encode into an url (we should not have this into an url)
1399 $stringtoclean = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $stringtoclean);
1400 } while ($oldstringtoclean != $stringtoclean);
1401
1402 if ($type == 1) {
1403 // removing '//' should disable links to external url like //aaa or http//)
1404 $stringtoclean = preg_replace(array('/^[a-z]*\/\/+/i'), '', $stringtoclean);
1405 }
1406
1407 return $stringtoclean;
1408}
1409
1416function dol_sanitizeEmail($stringtoclean)
1417{
1418 do {
1419 $oldstringtoclean = $stringtoclean;
1420 $stringtoclean = str_ireplace(array('"', ':', '[', ']',"\n", "\r", '\\', '\/'), '', $stringtoclean);
1421 } while ($oldstringtoclean != $stringtoclean);
1422
1423 return $stringtoclean;
1424}
1425
1435{
1436 global $conf;
1437
1438 if (is_null($str)) {
1439 return '';
1440 }
1441
1442 if (utf8_check($str)) {
1443 if (extension_loaded('intl') && !empty($conf->global->MAIN_UNACCENT_USE_TRANSLITERATOR)) {
1444 $transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: NFC;', Transliterator::FORWARD);
1445 return $transliterator->transliterate($str);
1446 }
1447 // See http://www.utf8-chartable.de/
1448 $string = rawurlencode($str);
1449 $replacements = array(
1450 '%C3%80' => 'A', '%C3%81' => 'A', '%C3%82' => 'A', '%C3%83' => 'A', '%C3%84' => 'A', '%C3%85' => 'A',
1451 '%C3%87' => 'C',
1452 '%C3%88' => 'E', '%C3%89' => 'E', '%C3%8A' => 'E', '%C3%8B' => 'E',
1453 '%C3%8C' => 'I', '%C3%8D' => 'I', '%C3%8E' => 'I', '%C3%8F' => 'I',
1454 '%C3%91' => 'N',
1455 '%C3%92' => 'O', '%C3%93' => 'O', '%C3%94' => 'O', '%C3%95' => 'O', '%C3%96' => 'O',
1456 '%C5%A0' => 'S',
1457 '%C3%99' => 'U', '%C3%9A' => 'U', '%C3%9B' => 'U', '%C3%9C' => 'U',
1458 '%C3%9D' => 'Y', '%C5%B8' => 'y',
1459 '%C3%A0' => 'a', '%C3%A1' => 'a', '%C3%A2' => 'a', '%C3%A3' => 'a', '%C3%A4' => 'a', '%C3%A5' => 'a',
1460 '%C3%A7' => 'c',
1461 '%C3%A8' => 'e', '%C3%A9' => 'e', '%C3%AA' => 'e', '%C3%AB' => 'e',
1462 '%C3%AC' => 'i', '%C3%AD' => 'i', '%C3%AE' => 'i', '%C3%AF' => 'i',
1463 '%C3%B1' => 'n',
1464 '%C3%B2' => 'o', '%C3%B3' => 'o', '%C3%B4' => 'o', '%C3%B5' => 'o', '%C3%B6' => 'o',
1465 '%C5%A1' => 's',
1466 '%C3%B9' => 'u', '%C3%BA' => 'u', '%C3%BB' => 'u', '%C3%BC' => 'u',
1467 '%C3%BD' => 'y', '%C3%BF' => 'y'
1468 );
1469 $string = strtr($string, $replacements);
1470 return rawurldecode($string);
1471 } else {
1472 // See http://www.ascii-code.com/
1473 $string = strtr(
1474 $str,
1475 "\xC0\xC1\xC2\xC3\xC4\xC5\xC7
1476 \xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1
1477 \xD2\xD3\xD4\xD5\xD8\xD9\xDA\xDB\xDD
1478 \xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB
1479 \xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF8
1480 \xF9\xFA\xFB\xFC\xFD\xFF",
1481 "AAAAAAC
1482 EEEEIIIIDN
1483 OOOOOUUUY
1484 aaaaaaceeee
1485 iiiidnooooo
1486 uuuuyy"
1487 );
1488 $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"));
1489 return $string;
1490 }
1491}
1492
1506function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '', $badcharstoremove = '', $keepspaces = 0)
1507{
1508 $forbidden_chars_to_replace = array("'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=", '°', '$', ';'); // more complete than dol_sanitizeFileName
1509 if (empty($keepspaces)) {
1510 $forbidden_chars_to_replace[] = " ";
1511 }
1512 $forbidden_chars_to_remove = array();
1513 //$forbidden_chars_to_remove=array("(",")");
1514
1515 if (is_array($badcharstoreplace)) {
1516 $forbidden_chars_to_replace = $badcharstoreplace;
1517 }
1518 if (is_array($badcharstoremove)) {
1519 $forbidden_chars_to_remove = $badcharstoremove;
1520 }
1521
1522 return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str));
1523}
1524
1525
1539function dol_string_nounprintableascii($str, $removetabcrlf = 1)
1540{
1541 if ($removetabcrlf) {
1542 return preg_replace('/[\x00-\x1F\x7F]/u', '', $str); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1543 } else {
1544 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
1545 }
1546}
1547
1556function dol_escape_js($stringtoescape, $mode = 0, $noescapebackslashn = 0)
1557{
1558 if (is_null($stringtoescape)) {
1559 return '';
1560 }
1561
1562 // escape quotes and backslashes, newlines, etc.
1563 $substitjs = array("&#039;"=>"\\'", "\r"=>'\\r');
1564 //$substitjs['</']='<\/'; // We removed this. Should be useless.
1565 if (empty($noescapebackslashn)) {
1566 $substitjs["\n"] = '\\n';
1567 $substitjs['\\'] = '\\\\';
1568 }
1569 if (empty($mode)) {
1570 $substitjs["'"] = "\\'";
1571 $substitjs['"'] = "\\'";
1572 } elseif ($mode == 1) {
1573 $substitjs["'"] = "\\'";
1574 } elseif ($mode == 2) {
1575 $substitjs['"'] = '\\"';
1576 } elseif ($mode == 3) {
1577 $substitjs["'"] = "\\'";
1578 $substitjs['"'] = "\\\"";
1579 }
1580 return strtr($stringtoescape, $substitjs);
1581}
1582
1589function dol_escape_json($stringtoescape)
1590{
1591 return str_replace('"', '\"', $stringtoescape);
1592}
1593
1601function dolPrintLabel($s)
1602{
1604}
1605
1613function dolPrintHTML($s)
1614{
1615 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1)), 1, 1, 'common', 0, 1);
1616}
1617
1626{
1628}
1629
1630
1647function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapetags = '', $escapeonlyhtmltags = 0, $cleanalsojavascript = 0)
1648{
1649 if ($noescapetags == 'common') {
1650 $noescapetags = 'html,body,a,b,em,hr,i,u,ul,li,br,div,img,font,p,span,strong,table,tr,td,th,tbody';
1651 }
1652 if ($cleanalsojavascript) {
1653 $stringtoescape = dol_string_onlythesehtmltags($stringtoescape, 0, 0, $cleanalsojavascript, 0, array(), 0);
1654 }
1655
1656 // escape quotes and backslashes, newlines, etc.
1657 if ($escapeonlyhtmltags) {
1658 $tmp = htmlspecialchars_decode((string) $stringtoescape, ENT_COMPAT);
1659 } else {
1660 $tmp = html_entity_decode((string) $stringtoescape, ENT_COMPAT, 'UTF-8');
1661 }
1662 if (!$keepb) {
1663 $tmp = strtr($tmp, array("<b>"=>'', '</b>'=>'', '<strong>'=>'', '</strong>'=>''));
1664 }
1665 if (!$keepn) {
1666 $tmp = strtr($tmp, array("\r"=>'\\r', "\n"=>'\\n'));
1667 }
1668
1669 if ($escapeonlyhtmltags) {
1670 return htmlspecialchars($tmp, ENT_COMPAT, 'UTF-8');
1671 } else {
1672 // Escape tags to keep
1673 // TODO Does not works yet when there is attributes into tag
1674 $tmparrayoftags = array();
1675 if ($noescapetags) {
1676 $tmparrayoftags = explode(',', $noescapetags);
1677 }
1678 if (count($tmparrayoftags)) {
1679 foreach ($tmparrayoftags as $tagtoreplace) {
1680 $tmp = str_ireplace('<'.$tagtoreplace.'>', '__BEGINTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1681 $tmp = str_ireplace('</'.$tagtoreplace.'>', '__ENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1682 $tmp = str_ireplace('<'.$tagtoreplace.' />', '__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1683 }
1684 }
1685
1686 $result = htmlentities($tmp, ENT_COMPAT, 'UTF-8');
1687
1688 if (count($tmparrayoftags)) {
1689 foreach ($tmparrayoftags as $tagtoreplace) {
1690 $result = str_ireplace('__BEGINTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.'>', $result);
1691 $result = str_ireplace('__ENDTAGTOREPLACE'.$tagtoreplace.'__', '</'.$tagtoreplace.'>', $result);
1692 $result = str_ireplace('__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.' />', $result);
1693 }
1694 }
1695
1696 return $result;
1697 }
1698}
1699
1707function dol_strtolower($string, $encoding = "UTF-8")
1708{
1709 if (function_exists('mb_strtolower')) {
1710 return mb_strtolower($string, $encoding);
1711 } else {
1712 return strtolower($string);
1713 }
1714}
1715
1724function dol_strtoupper($string, $encoding = "UTF-8")
1725{
1726 if (function_exists('mb_strtoupper')) {
1727 return mb_strtoupper($string, $encoding);
1728 } else {
1729 return strtoupper($string);
1730 }
1731}
1732
1741function dol_ucfirst($string, $encoding = "UTF-8")
1742{
1743 if (function_exists('mb_substr')) {
1744 return mb_strtoupper(mb_substr($string, 0, 1, $encoding), $encoding).mb_substr($string, 1, null, $encoding);
1745 } else {
1746 return ucfirst($string);
1747 }
1748}
1749
1758function dol_ucwords($string, $encoding = "UTF-8")
1759{
1760 if (function_exists('mb_convert_case')) {
1761 return mb_convert_case($string, MB_CASE_TITLE, $encoding);
1762 } else {
1763 return ucwords($string);
1764 }
1765}
1766
1788function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = '', $restricttologhandler = '', $logcontext = null)
1789{
1790 global $conf, $user, $debugbar;
1791
1792 // If syslog module enabled
1793 if (!isModEnabled('syslog')) {
1794 return;
1795 }
1796
1797 // Check if we are into execution of code of a website
1798 if (defined('USEEXTERNALSERVER') && !defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) {
1799 global $website, $websitekey;
1800 if (is_object($website) && !empty($website->ref)) {
1801 $suffixinfilename .= '_website_'.$website->ref;
1802 } elseif (!empty($websitekey)) {
1803 $suffixinfilename .= '_website_'.$websitekey;
1804 }
1805 }
1806
1807 // Check if we have a forced suffix
1808 if (defined('USESUFFIXINLOG')) {
1809 $suffixinfilename .= constant('USESUFFIXINLOG');
1810 }
1811
1812 if ($ident < 0) {
1813 foreach ($conf->loghandlers as $loghandlerinstance) {
1814 $loghandlerinstance->setIdent($ident);
1815 }
1816 }
1817
1818 if (!empty($message)) {
1819 // Test log level
1820 $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');
1821 if (!array_key_exists($level, $logLevels)) {
1822 throw new Exception('Incorrect log level');
1823 }
1824 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
1825 return;
1826 }
1827
1828 if (empty($conf->global->MAIN_SHOW_PASSWORD_INTO_LOG)) {
1829 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
1830 }
1831
1832 // If adding log inside HTML page is required
1833 if ((!empty($_REQUEST['logtohtml']) && !empty($conf->global->MAIN_ENABLE_LOG_TO_HTML))
1834 || (!empty($user->rights->debugbar->read) && is_object($debugbar))) {
1835 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".$logLevels[$level]." ".$message;
1836 }
1837
1838 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
1839 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
1840 if (!empty($conf->global->MAIN_ENABLE_LOG_INLINE_HTML) && !empty($_GET["log"])) {
1841 print "\n\n<!-- Log start\n";
1842 print dol_escape_htmltag($message)."\n";
1843 print "Log end -->\n";
1844 }
1845
1846 $data = array(
1847 'message' => $message,
1848 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
1849 'level' => $level,
1850 'user' => ((is_object($user) && $user->id) ? $user->login : false),
1851 'ip' => false
1852 );
1853
1854 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
1855 if (!empty($remoteip)) {
1856 $data['ip'] = $remoteip;
1857 // This is when server run behind a reverse proxy
1858 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
1859 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
1860 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
1861 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
1862 }
1863 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
1864 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
1865 $data['ip'] = $_SERVER['SERVER_ADDR'];
1866 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
1867 // 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).
1868 $data['ip'] = $_SERVER['COMPUTERNAME'].(empty($_SERVER['USERNAME']) ? '' : '@'.$_SERVER['USERNAME']);
1869 } elseif (!empty($_SERVER['LOGNAME'])) {
1870 // 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).
1871 $data['ip'] = '???@'.$_SERVER['LOGNAME'];
1872 }
1873
1874 // Loop on each log handler and send output
1875 foreach ($conf->loghandlers as $loghandlerinstance) {
1876 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
1877 continue;
1878 }
1879 $loghandlerinstance->export($data, $suffixinfilename);
1880 }
1881 unset($data);
1882 }
1883
1884 if ($ident > 0) {
1885 foreach ($conf->loghandlers as $loghandlerinstance) {
1886 $loghandlerinstance->setIdent($ident);
1887 }
1888 }
1889}
1890
1907function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
1908{
1909 global $conf;
1910
1911 if (strpos($url, '?') > 0) {
1912 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1913 } else {
1914 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1915 }
1916
1917 $out = '';
1918
1919 $backtopagejsfieldsid = ''; $backtopagejsfieldslabel = '';
1920 if ($backtopagejsfields) {
1921 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
1922 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
1923 $backtopagejsfields = $name.":".$backtopagejsfields;
1924 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
1925 } else {
1926 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
1927 }
1928 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
1929 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
1930 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
1931 }
1932
1933 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
1934 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
1935 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
1936 if (empty($conf->use_javascript_ajax)) {
1937 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
1938 } elseif ($jsonopen) {
1939 $out .= ' href="#" onclick="'.$jsonopen.'"';
1940 } else {
1941 $out .= ' href="#"';
1942 }
1943 $out .= '>'.$buttonstring.'</a>';
1944
1945 if (!empty($conf->use_javascript_ajax)) {
1946 // Add code to open url using the popup. Add also hidden field to retreive the returned variables
1947 $out .= '<!-- code to open popup and variables to retreive returned variables -->';
1948 $out .= '<div id="idfordialog'.$name.'" class="hidden">div for dialog</div>';
1949 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">div for returned id</div>';
1950 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">div for returned label</div>';
1951 $out .= '<!-- Add js code to open dialog popup on dialog -->';
1952 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
1953 jQuery(document).ready(function () {
1954 jQuery(".button_'.$name.'").click(function () {
1955 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
1956 var $tmpdialog = $(\'#idfordialog'.$name.'\');
1957 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
1958 $tmpdialog.dialog({
1959 autoOpen: false,
1960 modal: true,
1961 height: (window.innerHeight - 150),
1962 width: \'80%\',
1963 title: \''.dol_escape_js($label).'\',
1964 open: function (event, ui) {
1965 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
1966 },
1967 close: function (event, ui) {
1968 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
1969 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
1970 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
1971 if (returnedid != "" && returnedid != "div for returned id") {
1972 jQuery("#'.(empty($backtopagejsfieldsid)?"none":$backtopagejsfieldsid).'").val(returnedid);
1973 }
1974 if (returnedlabel != "" && returnedlabel != "div for returned label") {
1975 jQuery("#'.(empty($backtopagejsfieldslabel)?"none":$backtopagejsfieldslabel).'").val(returnedlabel);
1976 }
1977 }
1978 });
1979
1980 $tmpdialog.dialog(\'open\');
1981 return false;
1982 });
1983 });
1984 </script>';
1985 }
1986 return $out;
1987}
1988
2005function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2006{
2007 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2008}
2009
2026function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2027{
2028 global $conf, $langs, $hookmanager;
2029
2030 // Show title
2031 $showtitle = 1;
2032 if (!empty($conf->dol_optimize_smallscreen)) {
2033 $showtitle = 0;
2034 }
2035
2036 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2037
2038 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2039 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2040 }
2041
2042 // Show right part
2043 if ($morehtmlright) {
2044 $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.
2045 }
2046
2047 // Show title
2048 if (!empty($title) && $showtitle && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2049 $limittitle = 30;
2050 $out .= '<a class="tabTitle">';
2051 if ($picto) {
2052 $noprefix = $pictoisfullpath;
2053 if (strpos($picto, 'fontawesome_') !== false) {
2054 $noprefix = 1;
2055 }
2056 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2057 }
2058 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2059 $out .= '</a>';
2060 }
2061
2062 // Show tabs
2063
2064 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2065 $maxkey = -1;
2066 if (is_array($links) && !empty($links)) {
2067 $keys = array_keys($links);
2068 if (count($keys)) {
2069 $maxkey = max($keys);
2070 }
2071 }
2072
2073 // Show tabs
2074 // if =0 we don't use the feature
2075 if (empty($limittoshow)) {
2076 $limittoshow = (empty($conf->global->MAIN_MAXTABS_IN_CARD) ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2077 }
2078 if (!empty($conf->dol_optimize_smallscreen)) {
2079 $limittoshow = 2;
2080 }
2081
2082 $displaytab = 0;
2083 $nbintab = 0;
2084 $popuptab = 0;
2085 $outmore = '';
2086 for ($i = 0; $i <= $maxkey; $i++) {
2087 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2088 // If active tab is already present
2089 if ($i >= $limittoshow) {
2090 $limittoshow--;
2091 }
2092 }
2093 }
2094
2095 for ($i = 0; $i <= $maxkey; $i++) {
2096 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2097 $isactive = true;
2098 } else {
2099 $isactive = false;
2100 }
2101
2102 if ($i < $limittoshow || $isactive) {
2103 // Output entry with a visible tab
2104 $out .= '<div class="inline-block tabsElem'.($isactive ? ' tabsElemActive' : '').((!$isactive && !empty($conf->global->MAIN_HIDE_INACTIVETAB_ON_PRINT)) ? ' hideonprint' : '').'"><!-- id tab = '.(empty($links[$i][2]) ? '' : dol_escape_htmltag($links[$i][2])).' -->';
2105
2106 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2107 if (!empty($links[$i][0])) {
2108 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2109 } else {
2110 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2111 }
2112 } elseif (!empty($links[$i][1])) {
2113 //print "x $i $active ".$links[$i][2]." z";
2114 $out .= '<div class="tab tab'.($isactive?'active':'unactive').'" style="margin: 0 !important">';
2115 if (!empty($links[$i][0])) {
2116 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2117 $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).'">';
2118 }
2119 $out .= $links[$i][1];
2120 if (!empty($links[$i][0])) {
2121 $out .= '</a>'."\n";
2122 }
2123 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2124 $out .= '</div>';
2125 }
2126
2127 $out .= '</div>';
2128 } else {
2129 // Add entry into the combo popup with the other tabs
2130 if (!$popuptab) {
2131 $popuptab = 1;
2132 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2133 }
2134 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2135 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2136 if (!empty($links[$i][0])) {
2137 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2138 } else {
2139 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2140 }
2141 } elseif (!empty($links[$i][1])) {
2142 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2143 $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.
2144 $outmore .= '</a>'."\n";
2145 }
2146 $outmore .= '</div>';
2147
2148 $nbintab++;
2149 }
2150 $displaytab = $i;
2151 }
2152 if ($popuptab) {
2153 $outmore .= '</div>';
2154 }
2155
2156 if ($popuptab) { // If there is some tabs not shown
2157 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2158 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2159 $widthofpopup = 200;
2160
2161 $tabsname = $moretabssuffix;
2162 if (empty($tabsname)) {
2163 $tabsname = str_replace("@", "", $picto);
2164 }
2165 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2166 $out .= '<div class="tab"><a href="#" class="tab moretab inline-block tabunactive"><span class="hideonsmartphone">'.$langs->trans("More").'</span>... ('.$nbintab.')</a></div>'; // Do not use "reposition" class in the "More".
2167 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2168 $out .= $outmore;
2169 $out .= '</div>';
2170 $out .= '<div></div>';
2171 $out .= "</div>\n";
2172
2173 $out .= '<script nonce="'.getNonce().'">';
2174 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2175 var x = this.offsetLeft, y = this.offsetTop;
2176 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2177 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2178 $('#moretabsList".$tabsname."').css('".$right."','8px');
2179 }
2180 $('#moretabsList".$tabsname."').css('".$left."','auto');
2181 });
2182 ";
2183 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2184 $out .= "</script>";
2185 }
2186
2187 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2188 $out .= "</div>\n";
2189 }
2190
2191 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2192 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom'))).'">'."\n";
2193 }
2194 if (!empty($dragdropfile)) {
2195 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2196 }
2197 $parameters = array('tabname' => $active, 'out' => $out);
2198 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2199 if ($reshook > 0) {
2200 $out = $hookmanager->resPrint;
2201 }
2202
2203 return $out;
2204}
2205
2213function dol_fiche_end($notab = 0)
2214{
2215 print dol_get_fiche_end($notab);
2216}
2217
2224function dol_get_fiche_end($notab = 0)
2225{
2226 if (!$notab || $notab == -1) {
2227 return "\n</div>\n";
2228 } else {
2229 return '';
2230 }
2231}
2232
2252function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2253{
2254 global $conf, $form, $user, $langs, $hookmanager, $action;
2255
2256 $error = 0;
2257
2258 $maxvisiblephotos = 1;
2259 $showimage = 1;
2260 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2261 $showbarcode = empty($conf->barcode->enabled) ? 0 : (empty($object->barcode) ? 0 : 1);
2262 if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) {
2263 $showbarcode = 0;
2264 }
2265 $modulepart = 'unknown';
2266
2267 if ($object->element == 'societe' || $object->element == 'contact' || $object->element == 'product' || $object->element == 'ticket') {
2268 $modulepart = $object->element;
2269 } elseif ($object->element == 'member') {
2270 $modulepart = 'memberphoto';
2271 } elseif ($object->element == 'user') {
2272 $modulepart = 'userphoto';
2273 }
2274
2275 if (class_exists("Imagick")) {
2276 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2277 $modulepart = $object->element;
2278 } elseif ($object->element == 'fichinter') {
2279 $modulepart = 'ficheinter';
2280 } elseif ($object->element == 'contrat') {
2281 $modulepart = 'contract';
2282 } elseif ($object->element == 'order_supplier') {
2283 $modulepart = 'supplier_order';
2284 } elseif ($object->element == 'invoice_supplier') {
2285 $modulepart = 'supplier_invoice';
2286 }
2287 }
2288
2289 if ($object->element == 'product') {
2290 $width = 80;
2291 $cssclass = 'photowithmargin photoref';
2292 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2293 $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : 5);
2294 if ($conf->browser->layout == 'phone') {
2295 $maxvisiblephotos = 1;
2296 }
2297 if ($showimage) {
2298 $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>';
2299 } else {
2300 if (!empty($conf->global->PRODUCT_NODISPLAYIFNOPHOTO)) {
2301 $nophoto = '';
2302 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2303 } else { // Show no photo link
2304 $nophoto = '/public/theme/common/nophoto.png';
2305 $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>';
2306 }
2307 }
2308 } elseif ($object->element == 'ticket') {
2309 $width = 80;
2310 $cssclass = 'photoref';
2311 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2312 $maxvisiblephotos = (isset($conf->global->TICKET_MAX_VISIBLE_PHOTO) ? $conf->global->TICKET_MAX_VISIBLE_PHOTO : 2);
2313 if ($conf->browser->layout == 'phone') {
2314 $maxvisiblephotos = 1;
2315 }
2316
2317 if ($showimage) {
2318 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2319 if ($object->nbphoto > 0) {
2320 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2321 } else {
2322 $showimage = 0;
2323 }
2324 }
2325 if (!$showimage) {
2326 if (!empty($conf->global->TICKET_NODISPLAYIFNOPHOTO)) {
2327 $nophoto = '';
2328 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2329 } else { // Show no photo link
2330 $nophoto = img_picto('No photo', 'object_ticket');
2331 $morehtmlleft .= '<!-- No photo to show -->';
2332 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2333 $morehtmlleft .= $nophoto;
2334 $morehtmlleft .= '</div></div>';
2335 }
2336 }
2337 } else {
2338 if ($showimage) {
2339 if ($modulepart != 'unknown') {
2340 $phototoshow = '';
2341 // Check if a preview file is available
2342 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2343 $objectref = dol_sanitizeFileName($object->ref);
2344 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2345 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2346 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2347 $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
2348 } else {
2349 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2350 }
2351 if (empty($subdir)) {
2352 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2353 }
2354
2355 $filepath = $dir_output.$subdir."/";
2356
2357 $filepdf = $filepath.$objectref.".pdf";
2358 $relativepath = $subdir.'/'.$objectref.'.pdf';
2359
2360 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2361 $fileimage = $filepdf.'_preview.png';
2362 $relativepathimage = $relativepath.'_preview.png';
2363
2364 $pdfexists = file_exists($filepdf);
2365
2366 // If PDF file exists
2367 if ($pdfexists) {
2368 // Conversion du PDF en image png si fichier png non existant
2369 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2370 if (empty($conf->global->MAIN_DISABLE_PDF_THUMBS)) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2371 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2372 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2373 if ($ret < 0) {
2374 $error++;
2375 }
2376 }
2377 }
2378 }
2379
2380 if ($pdfexists && !$error) {
2381 $heightforphotref = 80;
2382 if (!empty($conf->dol_optimize_smallscreen)) {
2383 $heightforphotref = 60;
2384 }
2385 // If the preview file is found
2386 if (file_exists($fileimage)) {
2387 $phototoshow = '<div class="photoref">';
2388 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2389 $phototoshow .= '</div>';
2390 }
2391 }
2392 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo'
2393 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2394 }
2395
2396 if ($phototoshow) {
2397 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2398 $morehtmlleft .= $phototoshow;
2399 $morehtmlleft .= '</div>';
2400 }
2401 }
2402
2403 if (empty($phototoshow)) { // Show No photo link (picto of object)
2404 if ($object->element == 'action') {
2405 $width = 80;
2406 $cssclass = 'photorefcenter';
2407 $nophoto = img_picto('No photo', 'title_agenda');
2408 } else {
2409 $width = 14;
2410 $cssclass = 'photorefcenter';
2411 $picto = $object->picto;
2412 $prefix = 'object_';
2413 if ($object->element == 'project' && !$object->public) {
2414 $picto = 'project'; // instead of projectpub
2415 }
2416 if (strpos($picto, 'fontawesome_') !== false) {
2417 $prefix = '';
2418 }
2419 $nophoto = img_picto('No photo', $prefix.$picto);
2420 }
2421 $morehtmlleft .= '<!-- No photo to show -->';
2422 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2423 $morehtmlleft .= $nophoto;
2424 $morehtmlleft .= '</div></div>';
2425 }
2426 }
2427 }
2428
2429 // Show barcode
2430 if ($showbarcode) {
2431 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2432 }
2433
2434 if ($object->element == 'societe') {
2435 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2436 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2437 } else {
2438 $morehtmlstatus .= $object->getLibStatut(6);
2439 }
2440 } elseif ($object->element == 'product') {
2441 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2442 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2443 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2444 } else {
2445 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2446 }
2447 $morehtmlstatus .= ' &nbsp; ';
2448 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2449 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2450 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2451 } else {
2452 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2453 }
2454 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier', 'chargesociales', 'loan', 'tva', 'salary'))) {
2455 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2456 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2457 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2458 }
2459 $morehtmlstatus .= $tmptxt;
2460 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2461 if ($object->statut == 0) {
2462 $morehtmlstatus .= $object->getLibStatut(5);
2463 } else {
2464 $morehtmlstatus .= $object->getLibStatut(4);
2465 }
2466 } elseif ($object->element == 'facturerec') {
2467 if ($object->frequency == 0) {
2468 $morehtmlstatus .= $object->getLibStatut(2);
2469 } else {
2470 $morehtmlstatus .= $object->getLibStatut(5);
2471 }
2472 } elseif ($object->element == 'project_task') {
2473 $object->fk_statut = 1;
2474 if ($object->progress > 0) {
2475 $object->fk_statut = 2;
2476 }
2477 if ($object->progress >= 100) {
2478 $object->fk_statut = 3;
2479 }
2480 $tmptxt = $object->getLibStatut(5);
2481 $morehtmlstatus .= $tmptxt; // No status on task
2482 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2483 $tmptxt = $object->getLibStatut(6);
2484 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2485 $tmptxt = $object->getLibStatut(5);
2486 }
2487 $morehtmlstatus .= $tmptxt;
2488 }
2489
2490 // Add if object was dispatched "into accountancy"
2491 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2492 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2493 if (method_exists($object, 'getVentilExportCompta')) {
2494 $accounted = $object->getVentilExportCompta();
2495 $langs->load("accountancy");
2496 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2497 }
2498 }
2499
2500 // Add alias for thirdparty
2501 if (!empty($object->name_alias)) {
2502 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
2503 }
2504
2505 // Add label
2506 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
2507 if (!empty($object->label)) {
2508 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
2509 }
2510 }
2511
2512 // Show address and email
2513 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
2514 $moreaddress = $object->getBannerAddress('refaddress', $object);
2515 if ($moreaddress) {
2516 $morehtmlref .= '<div class="refidno refaddress">';
2517 $morehtmlref .= $moreaddress;
2518 $morehtmlref .= '</div>';
2519 }
2520 }
2521 if (!empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && ($conf->global->MAIN_SHOW_TECHNICAL_ID == '1' || preg_match('/'.preg_quote($object->element, '/').'/i', $conf->global->MAIN_SHOW_TECHNICAL_ID)) && !empty($object->id)) {
2522 $morehtmlref .= '<div style="clear: both;"></div>';
2523 $morehtmlref .= '<div class="refidno opacitymedium">';
2524 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
2525 $morehtmlref .= '</div>';
2526 }
2527
2528 $parameters=array('morehtmlref'=>$morehtmlref);
2529 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
2530 if ($reshook < 0) {
2531 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2532 } elseif (empty($reshook)) {
2533 $morehtmlref .= $hookmanager->resPrint;
2534 } elseif ($reshook > 0) {
2535 $morehtmlref = $hookmanager->resPrint;
2536 }
2537
2538
2539 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
2540 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
2541 print '</div>';
2542 print '<div class="underrefbanner clearboth"></div>';
2543}
2544
2554function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
2555{
2556 global $langs;
2557 $ret = '';
2558 if ($fieldrequired) {
2559 $ret .= '<span class="fieldrequired">';
2560 }
2561 $ret .= '<label for="'.$fieldkey.'">';
2562 $ret .= $langs->trans($langkey);
2563 $ret .= '</label>';
2564 if ($fieldrequired) {
2565 $ret .= '</span>';
2566 }
2567 return $ret;
2568}
2569
2577function dol_bc($var, $moreclass = '')
2578{
2579 global $bc;
2580 $ret = ' '.$bc[$var];
2581 if ($moreclass) {
2582 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
2583 }
2584 return $ret;
2585}
2586
2600function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = '', $mode = 0, $extralangcode = '')
2601{
2602 global $conf, $langs, $hookmanager;
2603
2604 $ret = '';
2605 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
2606
2607 // See format of addresses on https://en.wikipedia.org/wiki/Address
2608 // Address
2609 if (empty($mode)) {
2610 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
2611 }
2612 // Zip/Town/State
2613 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || !empty($conf->global->MAIN_FORCE_STATE_INTO_ADDRESS)) {
2614 // US: title firstname name \n address lines \n town, state, zip \n country
2615 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2616 $ret .= (($ret && $town) ? $sep : '').$town;
2617
2618 if (!empty($object->state)) {
2619 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
2620 }
2621 if (!empty($object->zip)) {
2622 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
2623 }
2624 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
2625 // UK: title firstname name \n address lines \n town state \n zip \n country
2626 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2627 $ret .= ($ret ? $sep : '').$town;
2628 if (!empty($object->state)) {
2629 $ret .= ($ret ? ", " : '').$object->state;
2630 }
2631 if (!empty($object->zip)) {
2632 $ret .= ($ret ? $sep : '').$object->zip;
2633 }
2634 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
2635 // ES: title firstname name \n address lines \n zip town \n state \n country
2636 $ret .= ($ret ? $sep : '').$object->zip;
2637 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2638 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2639 if (!empty($object->state)) {
2640 $ret .= $sep.$object->state;
2641 }
2642 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
2643 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
2644 // See https://www.sljfaq.org/afaq/addresses.html
2645 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2646 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
2647 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
2648 // IT: title firstname name\n address lines \n zip town state_code \n country
2649 $ret .= ($ret ? $sep : '').$object->zip;
2650 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2651 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2652 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
2653 } else {
2654 // Other: title firstname name \n address lines \n zip town[, state] \n country
2655 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2656 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
2657 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
2658 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
2659 $ret .= ($ret ? ", " : '').$object->state;
2660 }
2661 }
2662
2663 if (!is_object($outputlangs)) {
2664 $outputlangs = $langs;
2665 }
2666 if ($withcountry) {
2667 $langs->load("dict");
2668 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
2669 }
2670 if ($hookmanager) {
2671 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
2672 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
2673 if ($reshook > 0) {
2674 $ret = '';
2675 }
2676 $ret .= $hookmanager->resPrint;
2677 }
2678
2679 return $ret;
2680}
2681
2682
2683
2692function dol_strftime($fmt, $ts = false, $is_gmt = false)
2693{
2694 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
2695 return ($is_gmt) ? @gmstrftime($fmt, $ts) : @strftime($fmt, $ts);
2696 } else {
2697 return 'Error date into a not supported range';
2698 }
2699}
2700
2722function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = '', $encodetooutput = false)
2723{
2724 global $conf, $langs;
2725
2726 // If date undefined or "", we return ""
2727 if (dol_strlen($time) == 0) {
2728 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
2729 }
2730
2731 if ($tzoutput === 'auto') {
2732 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
2733 }
2734
2735 // Clean parameters
2736 $to_gmt = false;
2737 $offsettz = $offsetdst = 0;
2738 if ($tzoutput) {
2739 $to_gmt = true; // For backward compatibility
2740 if (is_string($tzoutput)) {
2741 if ($tzoutput == 'tzserver') {
2742 $to_gmt = false;
2743 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
2744 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
2745 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
2746 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
2747 $to_gmt = true;
2748 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
2749
2750 if (class_exists('DateTimeZone')) {
2751 $user_date_tz = new DateTimeZone($offsettzstring);
2752 $user_dt = new DateTime();
2753 $user_dt->setTimezone($user_date_tz);
2754 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
2755 $offsettz = $user_dt->getOffset(); // should include dst ?
2756 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
2757 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
2758 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
2759 }
2760 }
2761 }
2762 }
2763 if (!is_object($outputlangs)) {
2764 $outputlangs = $langs;
2765 }
2766 if (!$format) {
2767 $format = 'daytextshort';
2768 }
2769
2770 // Do we have to reduce the length of date (year on 2 chars) to save space.
2771 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
2772 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour'))) ? 1 : 0; // Test on original $format param.
2773 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
2774 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
2775 if ($formatwithoutreduce != $format) {
2776 $format = $formatwithoutreduce;
2777 $reduceformat = 1;
2778 } // so format 'dayreduceformat' is processed like day
2779
2780 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
2781 // TODO Add format daysmallyear and dayhoursmallyear
2782 if ($format == 'day') {
2783 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
2784 } elseif ($format == 'hour') {
2785 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
2786 } elseif ($format == 'hourduration') {
2787 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
2788 } elseif ($format == 'daytext') {
2789 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
2790 } elseif ($format == 'daytextshort') {
2791 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
2792 } elseif ($format == 'dayhour') {
2793 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
2794 } elseif ($format == 'dayhoursec') {
2795 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
2796 } elseif ($format == 'dayhourtext') {
2797 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
2798 } elseif ($format == 'dayhourtextshort') {
2799 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
2800 } elseif ($format == 'dayhourlog') {
2801 // Format not sensitive to language
2802 $format = '%Y%m%d%H%M%S';
2803 } elseif ($format == 'dayhourlogsmall') {
2804 // Format not sensitive to language
2805 $format = '%y%m%d%H%M';
2806 } elseif ($format == 'dayhourldap') {
2807 $format = '%Y%m%d%H%M%SZ';
2808 } elseif ($format == 'dayhourxcard') {
2809 $format = '%Y%m%dT%H%M%SZ';
2810 } elseif ($format == 'dayxcard') {
2811 $format = '%Y%m%d';
2812 } elseif ($format == 'dayrfc') {
2813 $format = '%Y-%m-%d'; // DATE_RFC3339
2814 } elseif ($format == 'dayhourrfc') {
2815 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
2816 } elseif ($format == 'standard') {
2817 $format = '%Y-%m-%d %H:%M:%S';
2818 }
2819
2820 if ($reduceformat) {
2821 $format = str_replace('%Y', '%y', $format);
2822 $format = str_replace('yyyy', 'yy', $format);
2823 }
2824
2825 // Clean format
2826 if (preg_match('/%b/i', $format)) { // There is some text to translate
2827 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2828 $format = str_replace('%b', '__b__', $format);
2829 $format = str_replace('%B', '__B__', $format);
2830 }
2831 if (preg_match('/%a/i', $format)) { // There is some text to translate
2832 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2833 $format = str_replace('%a', '__a__', $format);
2834 $format = str_replace('%A', '__A__', $format);
2835 }
2836
2837 // Analyze date
2838 $reg = array();
2839 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
2840 dol_print_error('', "Functions.lib::dol_print_date function called with a bad value from page ".$_SERVER["PHP_SELF"]);
2841 return '';
2842 } 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
2843 // This part of code should not be used anymore.
2844 dol_syslog("Functions.lib::dol_print_date function called with a bad value from page ".$_SERVER["PHP_SELF"], LOG_WARNING);
2845 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
2846 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
2847 $syear = (!empty($reg[1]) ? $reg[1] : '');
2848 $smonth = (!empty($reg[2]) ? $reg[2] : '');
2849 $sday = (!empty($reg[3]) ? $reg[3] : '');
2850 $shour = (!empty($reg[4]) ? $reg[4] : '');
2851 $smin = (!empty($reg[5]) ? $reg[5] : '');
2852 $ssec = (!empty($reg[6]) ? $reg[6] : '');
2853
2854 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
2855
2856 if ($to_gmt) {
2857 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2858 } else {
2859 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2860 }
2861 $dtts = new DateTime();
2862 $dtts->setTimestamp($time);
2863 $dtts->setTimezone($tzo);
2864 $newformat = str_replace(
2865 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2866 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2867 $format);
2868 $ret = $dtts->format($newformat);
2869 $ret = str_replace(
2870 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2871 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2872 $ret
2873 );
2874 } else {
2875 // Date is a timestamps
2876 if ($time < 100000000000) { // Protection against bad date values
2877 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2878
2879 if ($to_gmt) {
2880 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2881 } else {
2882 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2883 }
2884 $dtts = new DateTime();
2885 $dtts->setTimestamp($timetouse);
2886 $dtts->setTimezone($tzo);
2887 $newformat = str_replace(
2888 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2889 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2890 $format);
2891 $ret = $dtts->format($newformat);
2892 $ret = str_replace(
2893 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2894 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2895 $ret
2896 );
2897 //var_dump($ret);exit;
2898 } else {
2899 $ret = 'Bad value '.$time.' for date';
2900 }
2901 }
2902
2903 if (preg_match('/__b__/i', $format)) {
2904 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2905
2906 if ($to_gmt) {
2907 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2908 } else {
2909 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2910 }
2911 $dtts = new DateTime();
2912 $dtts->setTimestamp($timetouse);
2913 $dtts->setTimezone($tzo);
2914 $month = $dtts->format("m");
2915 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
2916 if ($encodetooutput) {
2917 $monthtext = $outputlangs->transnoentities('Month'.$month);
2918 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
2919 } else {
2920 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
2921 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
2922 }
2923 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
2924 $ret = str_replace('__b__', $monthtextshort, $ret);
2925 $ret = str_replace('__B__', $monthtext, $ret);
2926 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
2927 //return $ret;
2928 }
2929 if (preg_match('/__a__/i', $format)) {
2930 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
2931 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
2932
2933 if ($to_gmt) {
2934 $tzo = new DateTimeZone('UTC');
2935 } else {
2936 $tzo = new DateTimeZone(date_default_timezone_get());
2937 }
2938 $dtts = new DateTime();
2939 $dtts->setTimestamp($timetouse);
2940 $dtts->setTimezone($tzo);
2941 $w = $dtts->format("w");
2942 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
2943
2944 $ret = str_replace('__A__', $dayweek, $ret);
2945 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
2946 }
2947
2948 return $ret;
2949}
2950
2951
2972function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
2973{
2974 $datetimeobj = new DateTime();
2975 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
2976 if ($forcetimezone) {
2977 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
2978 }
2979 $arrayinfo = array(
2980 'year'=>((int) date_format($datetimeobj, 'Y')),
2981 'mon'=>((int) date_format($datetimeobj, 'm')),
2982 'mday'=>((int) date_format($datetimeobj, 'd')),
2983 'wday'=>((int) date_format($datetimeobj, 'w')),
2984 'yday'=>((int) date_format($datetimeobj, 'z')),
2985 'hours'=>((int) date_format($datetimeobj, 'H')),
2986 'minutes'=>((int) date_format($datetimeobj, 'i')),
2987 'seconds'=>((int) date_format($datetimeobj, 's')),
2988 '0'=>$timestamp
2989 );
2990
2991 return $arrayinfo;
2992}
2993
3015function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3016{
3017 global $conf;
3018 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3019
3020 if ($gm === 'auto') {
3021 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3022 }
3023 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3024
3025 // Clean parameters
3026 if ($hour == -1 || empty($hour)) {
3027 $hour = 0;
3028 }
3029 if ($minute == -1 || empty($minute)) {
3030 $minute = 0;
3031 }
3032 if ($second == -1 || empty($second)) {
3033 $second = 0;
3034 }
3035
3036 // Check parameters
3037 if ($check) {
3038 if (!$month || !$day) {
3039 return '';
3040 }
3041 if ($day > 31) {
3042 return '';
3043 }
3044 if ($month > 12) {
3045 return '';
3046 }
3047 if ($hour < 0 || $hour > 24) {
3048 return '';
3049 }
3050 if ($minute < 0 || $minute > 60) {
3051 return '';
3052 }
3053 if ($second < 0 || $second > 60) {
3054 return '';
3055 }
3056 }
3057
3058 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3059 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3060 $localtz = new DateTimeZone($default_timezone);
3061 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3062 // We use dol_tz_string first because it is more reliable.
3063 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3064 try {
3065 $localtz = new DateTimeZone($default_timezone);
3066 } catch (Exception $e) {
3067 dol_syslog("Warning dol_tz_string contains an invalid value ".$_SESSION["dol_tz_string"], LOG_WARNING);
3068 $default_timezone = @date_default_timezone_get();
3069 }
3070 } elseif (strrpos($gm, "tz,") !== false) {
3071 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3072 try {
3073 $localtz = new DateTimeZone($timezone);
3074 } catch (Exception $e) {
3075 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3076 }
3077 }
3078
3079 if (empty($localtz)) {
3080 $localtz = new DateTimeZone('UTC');
3081 }
3082 //var_dump($localtz);
3083 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3084 $dt = new DateTime('now', $localtz);
3085 $dt->setDate((int) $year, (int) $month, (int) $day);
3086 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3087 $date = $dt->getTimestamp(); // should include daylight saving time
3088 //var_dump($date);
3089 return $date;
3090}
3091
3092
3103function dol_now($mode = 'auto')
3104{
3105 $ret = 0;
3106
3107 if ($mode === 'auto') {
3108 $mode = 'gmt';
3109 }
3110
3111 if ($mode == 'gmt') {
3112 $ret = time(); // Time for now at greenwich.
3113 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3114 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3115 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3116 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3117 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3118 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3119 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3120 // $ret=dol_now('gmt')+($tzsecond*3600);
3121 //}
3122 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3123 // Time for now with user timezone added
3124 //print 'time: '.time();
3125 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3126 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3127 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3128 }
3129
3130 return $ret;
3131}
3132
3133
3142function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3143{
3144 global $conf, $langs;
3145 $level = 1024;
3146
3147 if (!empty($conf->dol_optimize_smallscreen)) {
3148 $shortunit = 1;
3149 }
3150
3151 // Set value text
3152 if (empty($shortvalue) || $size < ($level * 10)) {
3153 $ret = $size;
3154 $textunitshort = $langs->trans("b");
3155 $textunitlong = $langs->trans("Bytes");
3156 } else {
3157 $ret = round($size / $level, 0);
3158 $textunitshort = $langs->trans("Kb");
3159 $textunitlong = $langs->trans("KiloBytes");
3160 }
3161 // Use long or short text unit
3162 if (empty($shortunit)) {
3163 $ret .= ' '.$textunitlong;
3164 } else {
3165 $ret .= ' '.$textunitshort;
3166 }
3167
3168 return $ret;
3169}
3170
3181function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = 'float')
3182{
3183 global $langs;
3184
3185 if (empty($url)) {
3186 return '';
3187 }
3188
3189 $link = '<a href="';
3190 if (!preg_match('/^http/i', $url)) {
3191 $link .= 'http://';
3192 }
3193 $link .= $url;
3194 $link .= '"';
3195 if ($target) {
3196 $link .= ' target="'.$target.'"';
3197 }
3198 $link .= '>';
3199 if (!preg_match('/^http/i', $url)) {
3200 $link .= 'http://';
3201 }
3202 $link .= dol_trunc($url, $max);
3203 $link .= '</a>';
3204
3205 if ($morecss == 'float') {
3206 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ?img_picto($langs->trans("Url"), 'globe').' ' : '').$link.'</div>';
3207 } else {
3208 return '<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ?img_picto($langs->trans("Url"), 'globe').' ' : '').$link.'</span>';
3209 }
3210}
3211
3224function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3225{
3226 global $conf, $user, $langs, $hookmanager;
3227
3228 $newemail = dol_escape_htmltag($email);
3229
3230 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && $withpicto) {
3231 $withpicto = 0;
3232 }
3233
3234 if (empty($email)) {
3235 return '&nbsp;';
3236 }
3237
3238 if (!empty($addlink)) {
3239 $newemail = '<a style="text-overflow: ellipsis;" href="';
3240 if (!preg_match('/^mailto:/i', $email)) {
3241 $newemail .= 'mailto:';
3242 }
3243 $newemail .= $email;
3244 $newemail .= '">';
3245 $newemail .= dol_trunc($email, $max);
3246 $newemail .= '</a>';
3247 if ($showinvalid && !isValidEmail($email)) {
3248 $langs->load("errors");
3249 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3250 }
3251
3252 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3253 $type = 'AC_EMAIL';
3254 $link = '';
3255 if (!empty($conf->global->AGENDA_ADDACTIONFOREMAIL)) {
3256 $link = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.$type.'&amp;contactid='.$cid.'&amp;socid='.$socid.'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3257 }
3258 if ($link) {
3259 $newemail = '<div>'.$newemail.' '.$link.'</div>';
3260 }
3261 }
3262 } else {
3263 if ($showinvalid && !isValidEmail($email)) {
3264 $langs->load("errors");
3265 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3266 }
3267 }
3268
3269 //$rep = '<div class="nospan" style="margin-right: 10px">';
3270 $rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto)).' ' : '').$newemail;
3271 //$rep .= '</div>';
3272 if ($hookmanager) {
3273 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3274
3275 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3276 if ($reshook > 0) {
3277 $rep = '';
3278 }
3279 $rep .= $hookmanager->resPrint;
3280 }
3281
3282 return $rep;
3283}
3284
3291{
3292 global $conf, $db;
3293
3294 $socialnetworks = array();
3295 // Enable caching of array
3296 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3297 $cachekey = 'socialnetworks_' . $conf->entity;
3298 $dataretrieved = dol_getcache($cachekey);
3299 if (!is_null($dataretrieved)) {
3300 $socialnetworks = $dataretrieved;
3301 } else {
3302 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3303 $sql .= " WHERE entity=".$conf->entity;
3304 $resql = $db->query($sql);
3305 if ($resql) {
3306 while ($obj = $db->fetch_object($resql)) {
3307 $socialnetworks[$obj->code] = array(
3308 'rowid' => $obj->rowid,
3309 'label' => $obj->label,
3310 'url' => $obj->url,
3311 'icon' => $obj->icon,
3312 'active' => $obj->active,
3313 );
3314 }
3315 }
3316 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3317 }
3318
3319 return $socialnetworks;
3320}
3321
3332function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3333{
3334 global $conf, $user, $langs;
3335
3336 $htmllink = $value;
3337
3338 if (empty($value)) {
3339 return '&nbsp;';
3340 }
3341
3342 if (!empty($type)) {
3343 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3344 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3345 $htmllink .= '<span class="fa pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3346 if ($type == 'skype') {
3347 $htmllink .= dol_escape_htmltag($value);
3348 $htmllink .= '&nbsp; <a href="skype:';
3349 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3350 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3351 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3352 $htmllink .= '</a><a href="skype:';
3353 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3354 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3355 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3356 $htmllink .= '</a>';
3357 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3358 $addlink = 'AC_SKYPE';
3359 $link = '';
3360 if (!empty($conf->global->AGENDA_ADDACTIONFORSKYPE)) {
3361 $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>';
3362 }
3363 $htmllink .= ($link ? ' '.$link : '');
3364 }
3365 } else {
3366 if (!empty($dictsocialnetworks[$type]['url'])) {
3367 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3368 if ($tmpvirginurl) {
3369 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3370 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3371
3372 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3373 if ($tmpvirginurl3) {
3374 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3375 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3376 }
3377
3378 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3379 if ($tmpvirginurl2) {
3380 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3381 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3382 }
3383 }
3384 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3385 if (preg_match('/^https?:\/\//i', $link)) {
3386 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3387 } else {
3388 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3389 }
3390 } else {
3391 $htmllink .= dol_escape_htmltag($value);
3392 }
3393 }
3394 $htmllink .= '</div>';
3395 } else {
3396 $langs->load("errors");
3397 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3398 }
3399 return $htmllink;
3400}
3401
3412function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1, $separ = '&nbsp;')
3413{
3414 global $mysoc;
3415
3416 if (empty($profID) || empty($profIDtype)) {
3417 return '';
3418 }
3419 if (empty($countrycode)) $countrycode = $mysoc->country_code;
3420 $newProfID = $profID;
3421 $id = substr($profIDtype, -1);
3422 $ret = '';
3423 if (strtoupper($countrycode) == 'FR') {
3424 // France
3425 if ($id == 1 && dol_strlen($newProfID) == 9) $newProfID = substr($newProfID, 0, 3).$separ.substr($newProfID, 3, 3).$separ.substr($newProfID, 6, 3);
3426 if ($id == 2 && dol_strlen($newProfID) == 14) $newProfID = substr($newProfID, 0, 3).$separ.substr($newProfID, 3, 3).$separ.substr($newProfID, 6, 3).$separ.substr($newProfID, 9, 5);
3427 if ($profIDtype === 'VAT' && dol_strlen($newProfID) == 13) $newProfID = substr($newProfID, 0, 4).$separ.substr($newProfID, 4, 3).$separ.substr($newProfID, 7, 3).$separ.substr($newProfID, 10, 3);
3428 }
3429 if (!empty($addcpButton)) $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3430 else $ret = $newProfID;
3431 return $ret;
3432}
3433
3448function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0)
3449{
3450 global $conf, $user, $langs, $mysoc, $hookmanager;
3451
3452 // Clean phone parameter
3453 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
3454 if (empty($phone)) {
3455 return '';
3456 }
3457 if (!empty($conf->global->MAIN_PHONE_SEPAR)) {
3458 $separ = $conf->global->MAIN_PHONE_SEPAR;
3459 }
3460 if (empty($countrycode) && is_object($mysoc)) {
3461 $countrycode = $mysoc->country_code;
3462 }
3463
3464 // Short format for small screens
3465 if ($conf->dol_optimize_smallscreen) {
3466 $separ = '';
3467 }
3468
3469 $newphone = $phone;
3470 if (strtoupper($countrycode) == "FR") {
3471 // France
3472 if (dol_strlen($phone) == 10) {
3473 $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);
3474 } elseif (dol_strlen($phone) == 7) {
3475 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
3476 } elseif (dol_strlen($phone) == 9) {
3477 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
3478 } elseif (dol_strlen($phone) == 11) {
3479 $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);
3480 } elseif (dol_strlen($phone) == 12) {
3481 $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);
3482 } elseif (dol_strlen($phone) == 13) {
3483 $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);
3484 }
3485 } elseif (strtoupper($countrycode) == "CA") {
3486 if (dol_strlen($phone) == 10) {
3487 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
3488 }
3489 } elseif (strtoupper($countrycode) == "PT") {//Portugal
3490 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
3491 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3492 }
3493 } elseif (strtoupper($countrycode) == "SR") {//Suriname
3494 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
3495 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
3496 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
3497 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
3498 }
3499 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
3500 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
3501 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
3502 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
3503 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
3504 }
3505 } elseif (strtoupper($countrycode) == "ES") {//Espagne
3506 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
3507 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3508 }
3509 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
3510 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
3511 $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);
3512 }
3513 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
3514 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
3515 $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);
3516 }
3517 } elseif (strtoupper($countrycode) == "TR") {//Turquie
3518 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
3519 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3520 }
3521 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
3522 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
3523 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3524 }
3525 } elseif (strtoupper($countrycode) == "MX") {//Mexique
3526 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
3527 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3528 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
3529 $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);
3530 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
3531 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3532 }
3533 } elseif (strtoupper($countrycode) == "ML") {//Mali
3534 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
3535 $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);
3536 }
3537 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
3538 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
3539 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3540 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
3541 $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);
3542 }
3543 } elseif (strtoupper($countrycode) == "MU") {
3544 //Maurice
3545 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
3546 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3547 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
3548 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3549 }
3550 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
3551 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
3552 $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);
3553 }
3554 } elseif (strtoupper($countrycode) == "SY") {//Syrie
3555 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
3556 $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);
3557 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
3558 $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);
3559 }
3560 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
3561 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
3562 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3563 } elseif (dol_strlen($phone) == 13) {//ex: +971_ABC_DEF_GHI
3564 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3565 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
3566 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
3567 }
3568 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
3569 if (dol_strlen($phone) == 13) {//ex: +213_ABC_DEF_GHI
3570 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3571 }
3572 } elseif (strtoupper($countrycode) == "BE") {//Belgique
3573 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
3574 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3575 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
3576 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3577 }
3578 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
3579 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
3580 $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);
3581 }
3582 } elseif (strtoupper($countrycode) == "CO") {//Colombie
3583 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
3584 $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);
3585 }
3586 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
3587 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
3588 $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);
3589 }
3590 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
3591 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
3592 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3593 }
3594 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
3595 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
3596 $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);
3597 }
3598 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
3599 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
3600 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3601 }
3602 } elseif (strtoupper($countrycode) == "CH") {//Suisse
3603 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
3604 $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);
3605 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
3606 $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);
3607 }
3608 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
3609 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
3610 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3611 }
3612 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
3613 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
3614 $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);
3615 }
3616 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
3617 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
3618 $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);
3619 }
3620 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
3621 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
3622 $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);
3623 }
3624 } elseif (strtoupper($countrycode) == "IT") {//Italie
3625 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
3626 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3627 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
3628 $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);
3629 }
3630 } elseif (strtoupper($countrycode) == "AU") {
3631 //Australie
3632 if (dol_strlen($phone) == 12) {
3633 //ex: +61_A_BCDE_FGHI
3634 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
3635 }
3636 } elseif (strtoupper($countrycode) == "LU") {
3637 // Luxembourg
3638 if (dol_strlen($phone) == 10) {// fixe 6 chiffres +352_AA_BB_CC
3639 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3640 } elseif (dol_strlen($phone) == 11) {// fixe 7 chiffres +352_AA_BB_CC_D
3641 $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);
3642 } elseif (dol_strlen($phone) == 12) {// fixe 8 chiffres +352_AA_BB_CC_DD
3643 $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);
3644 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
3645 $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);
3646 }
3647 }
3648 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
3649 if ($addlink == 'tel' || $conf->browser->layout == 'phone' || (isModEnabled('clicktodial') && !empty($conf->global->CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS))) { // If phone or option for, we use link of phone
3650 $newphoneform = $newphone;
3651 $newphone = '<a href="tel:'.$phone.'"';
3652 $newphone .= '>'.$newphoneform.'</a>';
3653 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
3654 if (empty($user->clicktodial_loaded)) {
3655 $user->fetch_clicktodial();
3656 }
3657
3658 // Define urlmask
3659 $urlmask = 'ErrorClickToDialModuleNotConfigured';
3660 if (!empty($conf->global->CLICKTODIAL_URL)) {
3661 $urlmask = $conf->global->CLICKTODIAL_URL;
3662 }
3663 if (!empty($user->clicktodial_url)) {
3664 $urlmask = $user->clicktodial_url;
3665 }
3666
3667 $clicktodial_poste = (!empty($user->clicktodial_poste) ?urlencode($user->clicktodial_poste) : '');
3668 $clicktodial_login = (!empty($user->clicktodial_login) ?urlencode($user->clicktodial_login) : '');
3669 $clicktodial_password = (!empty($user->clicktodial_password) ?urlencode($user->clicktodial_password) : '');
3670 // This line is for backward compatibility
3671 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
3672 // Thoose lines are for substitution
3673 $substitarray = array('__PHONEFROM__'=>$clicktodial_poste,
3674 '__PHONETO__'=>urlencode($phone),
3675 '__LOGIN__'=>$clicktodial_login,
3676 '__PASS__'=>$clicktodial_password);
3677 $url = make_substitutions($url, $substitarray);
3678 $newphonesav = $newphone;
3679 if (empty($conf->global->CLICKTODIAL_DO_NOT_USE_AJAX_CALL)) {
3680 // Default and recommended: New method using ajax without submiting a page making a javascript history.go(-1) back
3681 $newphone = '<a href="'.$url.'" class="cssforclicktodial"'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
3682 $newphone .= '>'.$newphonesav.'</a>';
3683 } else {
3684 // Old method
3685 $newphone = '<a href="'.$url.'"';
3686 if (!empty($conf->global->CLICKTODIAL_FORCENEWTARGET)) {
3687 $newphone .= ' target="_blank" rel="noopener noreferrer"';
3688 }
3689 $newphone .= '>'.$newphonesav.'</a>';
3690 }
3691 }
3692
3693 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
3694 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3695 $type = 'AC_TEL';
3696 $link = '';
3697 if ($addlink == 'AC_FAX') {
3698 $type = 'AC_FAX';
3699 }
3700 if (!empty($conf->global->AGENDA_ADDACTIONFORPHONE)) {
3701 $link = '<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>';
3702 }
3703 if ($link) {
3704 $newphone = '<div>'.$newphone.' '.$link.'</div>';
3705 }
3706 }
3707 }
3708
3709 if (empty($titlealt)) {
3710 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
3711 }
3712 $rep = '';
3713
3714 if ($hookmanager) {
3715 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
3716 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
3717 $rep .= $hookmanager->resPrint;
3718 }
3719 if (empty($reshook)) {
3720 $picto = '';
3721 if ($withpicto) {
3722 if ($withpicto == 'fax') {
3723 $picto = 'phoning_fax';
3724 } elseif ($withpicto == 'phone') {
3725 $picto = 'phoning';
3726 } elseif ($withpicto == 'mobile') {
3727 $picto = 'phoning_mobile';
3728 } else {
3729 $picto = '';
3730 }
3731 }
3732 if ($adddivfloat == 1) {
3733 $rep .= '<div class="nospan float" style="margin-right: 10px">';
3734 } elseif (empty($adddivfloat)) {
3735 $rep .= '<span style="margin-right: 10px;">';
3736 }
3737 $rep .= ($withpicto ?img_picto($titlealt, 'object_'.$picto.'.png').' ' : '').$newphone;
3738 if ($adddivfloat == 1) {
3739 $rep .= '</div>';
3740 } elseif (empty($adddivfloat)) {
3741 $rep .= '</span>';
3742 }
3743 }
3744
3745 return $rep;
3746}
3747
3755function dol_print_ip($ip, $mode = 0)
3756{
3757 global $conf, $langs;
3758
3759 $ret = '';
3760
3761 if (empty($mode)) {
3762 $ret .= $ip;
3763 }
3764
3765 if ($mode != 2) {
3766 $countrycode = dolGetCountryCodeFromIp($ip);
3767 if ($countrycode) { // If success, countrycode is us, fr, ...
3768 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
3769 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
3770 } else {
3771 $ret .= ' ('.$countrycode.')';
3772 }
3773 } else {
3774 // Nothing
3775 }
3776 }
3777
3778 return $ret;
3779}
3780
3790{
3791 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
3792 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
3793 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
3794 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
3795 } else {
3796 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
3797 }
3798 } else {
3799 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
3800 }
3801 } else {
3802 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
3803 }
3804 return $ip;
3805}
3806
3815function isHTTPS()
3816{
3817 $isSecure = false;
3818 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
3819 $isSecure = true;
3820 } 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') {
3821 $isSecure = true;
3822 }
3823 return $isSecure;
3824}
3825
3833{
3834 global $conf;
3835
3836 $countrycode = '';
3837
3838 if (!empty($conf->geoipmaxmind->enabled)) {
3839 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3840 //$ip='24.24.24.24';
3841 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
3842 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3843 $geoip = new DolGeoIP('country', $datafile);
3844 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
3845 $countrycode = $geoip->getCountryCodeFromIP($ip);
3846 }
3847
3848 return $countrycode;
3849}
3850
3851
3859{
3860 global $conf, $langs, $user;
3861
3862 //$ret=$user->xxx;
3863 $ret = '';
3864 if (!empty($conf->geoipmaxmind->enabled)) {
3865 $ip = getUserRemoteIP();
3866 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3867 //$ip='24.24.24.24';
3868 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
3869 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3870 $geoip = new DolGeoIP('country', $datafile);
3871 $countrycode = $geoip->getCountryCodeFromIP($ip);
3872 $ret = $countrycode;
3873 }
3874 return $ret;
3875}
3876
3889function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
3890{
3891 global $conf, $user, $langs, $hookmanager;
3892
3893 $out = '';
3894
3895 if ($address) {
3896 if ($hookmanager) {
3897 $parameters = array('element' => $element, 'id' => $id);
3898 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
3899 $out .= $hookmanager->resPrint;
3900 }
3901 if (empty($reshook)) {
3902 if (empty($charfornl)) {
3903 $out .= nl2br($address);
3904 } else {
3905 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
3906 }
3907
3908 // TODO Remove this block, we can add this using the hook now
3909 $showgmap = $showomap = 0;
3910 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS)) {
3911 $showgmap = 1;
3912 }
3913 if ($element == 'contact' && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS_CONTACTS)) {
3914 $showgmap = 1;
3915 }
3916 if ($element == 'member' && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS_MEMBERS)) {
3917 $showgmap = 1;
3918 }
3919 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS)) {
3920 $showomap = 1;
3921 }
3922 if ($element == 'contact' && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS_CONTACTS)) {
3923 $showomap = 1;
3924 }
3925 if ($element == 'member' && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS_MEMBERS)) {
3926 $showomap = 1;
3927 }
3928 if ($showgmap) {
3929 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
3930 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
3931 }
3932 if ($showomap) {
3933 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
3934 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
3935 }
3936 }
3937 }
3938 if ($noprint) {
3939 return $out;
3940 } else {
3941 print $out;
3942 }
3943}
3944
3945
3955function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
3956{
3957 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
3958 return true;
3959 }
3960 if ($acceptuserkey && $address == '__USER_EMAIL__') {
3961 return true;
3962 }
3963 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
3964 return true;
3965 }
3966
3967 return false;
3968}
3969
3978function isValidMXRecord($domain)
3979{
3980 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
3981 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
3982 return 0;
3983 }
3984 if (function_exists('getmxrr')) {
3985 $mxhosts = array();
3986 $weight = array();
3987 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
3988 if (count($mxhosts) > 1) {
3989 return 1;
3990 }
3991 if (count($mxhosts) == 1 && !empty($mxhosts[0])) {
3992 return 1;
3993 }
3994
3995 return 0;
3996 }
3997 }
3998
3999 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4000 return -1;
4001}
4002
4010function isValidPhone($phone)
4011{
4012 return true;
4013}
4014
4015
4025function dolGetFirstLetters($s, $nbofchar = 1)
4026{
4027 $ret = '';
4028 $tmparray = explode(' ', $s);
4029 foreach ($tmparray as $tmps) {
4030 $ret .= dol_substr($tmps, 0, $nbofchar);
4031 }
4032
4033 return $ret;
4034}
4035
4036
4044function dol_strlen($string, $stringencoding = 'UTF-8')
4045{
4046 if (is_null($string)) {
4047 return 0;
4048 }
4049
4050 if (function_exists('mb_strlen')) {
4051 return mb_strlen($string, $stringencoding);
4052 } else {
4053 return strlen($string);
4054 }
4055}
4056
4067function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4068{
4069 global $langs;
4070
4071 if (empty($stringencoding)) {
4072 $stringencoding = $langs->charset_output;
4073 }
4074
4075 $ret = '';
4076 if (empty($trunconbytes)) {
4077 if (function_exists('mb_substr')) {
4078 $ret = mb_substr($string, $start, $length, $stringencoding);
4079 } else {
4080 $ret = substr($string, $start, $length);
4081 }
4082 } else {
4083 if (function_exists('mb_strcut')) {
4084 $ret = mb_strcut($string, $start, $length, $stringencoding);
4085 } else {
4086 $ret = substr($string, $start, $length);
4087 }
4088 }
4089 return $ret;
4090}
4091
4092
4106function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4107{
4108 global $conf;
4109
4110 if (empty($size) || !empty($conf->global->MAIN_DISABLE_TRUNC)) {
4111 return $string;
4112 }
4113
4114 if (empty($stringencoding)) {
4115 $stringencoding = 'UTF-8';
4116 }
4117 // reduce for small screen
4118 if ($conf->dol_optimize_smallscreen == 1 && $display == 1) {
4119 $size = round($size / 3);
4120 }
4121
4122 // We go always here
4123 if ($trunc == 'right') {
4124 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4125 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4126 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4127 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4128 } else {
4129 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4130 return $string;
4131 }
4132 } elseif ($trunc == 'middle') {
4133 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4134 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4135 $size1 = round($size / 2);
4136 $size2 = round($size / 2);
4137 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4138 } else {
4139 return $string;
4140 }
4141 } elseif ($trunc == 'left') {
4142 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4143 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4144 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4145 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4146 } else {
4147 return $string;
4148 }
4149 } elseif ($trunc == 'wrap') {
4150 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4151 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4152 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4153 } else {
4154 return $string;
4155 }
4156 } else {
4157 return 'BadParam3CallingDolTrunc';
4158 }
4159}
4160
4182function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4183{
4184 global $conf, $langs;
4185
4186 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4187 $url = DOL_URL_ROOT;
4188 $theme = isset($conf->theme) ? $conf->theme : null;
4189 $path = 'theme/'.$theme;
4190 // Define fullpathpicto to use into src
4191 if ($pictoisfullpath) {
4192 // Clean parameters
4193 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4194 $picto .= '.png';
4195 }
4196 $fullpathpicto = $picto;
4197 $reg = array();
4198 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4199 $morecss .= ($morecss ? ' ' : '').$reg[1];
4200 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4201 }
4202 } else {
4203 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', $picto);
4204 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4205 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4206
4207 if (strpos($pictowithouttext, 'fontawesome_') !== false || preg_match('/^fa-/', $pictowithouttext)) {
4208 // This is a font awesome image 'fonwtawesome_xxx' or 'fa-xxx'
4209 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4210 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4211
4212 $pictowithouttextarray = explode('_', $pictowithouttext);
4213 $marginleftonlyshort = 0;
4214
4215 if (!empty($pictowithouttextarray[1])) {
4216 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4217 $fakey = 'fa-'.$pictowithouttextarray[0];
4218 $fa = empty($pictowithouttextarray[1]) ? 'fa' : $pictowithouttextarray[1];
4219 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4220 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4221 } else {
4222 $fakey = 'fa-'.$pictowithouttext;
4223 $fa = 'fa';
4224 $facolor = '';
4225 $fasize = '';
4226 }
4227
4228 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4229 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4230 $morestyle = '';
4231 $reg = array();
4232 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4233 $morecss .= ($morecss ? ' ' : '').$reg[1];
4234 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4235 }
4236 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4237 $morestyle = $reg[1];
4238 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4239 }
4240 $moreatt = trim($moreatt);
4241
4242 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4243 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4244 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4245 $enabledisablehtml .= $titlealt;
4246 }*/
4247 $enabledisablehtml .= '</span>';
4248
4249 return $enabledisablehtml;
4250 }
4251
4252 if (empty($srconly) && in_array($pictowithouttext, array(
4253 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4254 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'angle-double-down', 'angle-double-up', 'asset',
4255 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building',
4256 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4257 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4258 'currency', 'multicurrency',
4259 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4260 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4261 'filter', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus',
4262 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4263 'hands-helping', 'help', 'holiday',
4264 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4265 'knowledgemanagement',
4266 'label', 'language', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4267 'margin', 'map-marker-alt', 'member', 'meeting', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4268 'off', 'on', 'order',
4269 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4270 'stock', 'resize', 'service', 'stats', 'trip',
4271 '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',
4272 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4273 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies',
4274 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4275 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4276 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4277 'technic', 'ticket',
4278 'error', 'warning',
4279 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4280 'shapes', 'skill', 'square', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4281 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda',
4282 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4283 'conferenceorbooth', 'eventorganization',
4284 'stamp', 'signature'
4285 ))) {
4286 $fakey = $pictowithouttext;
4287 $facolor = '';
4288 $fasize = '';
4289 $fa = 'fas';
4290 if (in_array($pictowithouttext, array('card', 'bell', 'clock', 'establishment', 'generic', 'minus-square', 'object_generic', 'pdf', 'plus-square', 'timespent', 'note', 'off', 'on', 'object_bookmark', 'bookmark', 'vcard'))) {
4291 $fa = 'far';
4292 }
4293 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4294 $fa = 'fab';
4295 }
4296
4297 $arrayconvpictotofa = array(
4298 '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',
4299 'bank_account'=>'university',
4300 'bill'=>'file-invoice-dollar', 'billa'=>'file-excel', 'billr'=>'file-invoice-dollar', 'billd'=>'file-medical',
4301 'supplier_invoice'=>'file-invoice-dollar', 'supplier_invoicea'=>'file-excel', 'supplier_invoicer'=>'file-invoice-dollar', 'supplier_invoiced'=>'file-medical',
4302 'bom'=>'shapes',
4303 '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',
4304 'donation'=>'file-alt', 'dynamicprice'=>'hand-holding-usd',
4305 'setup'=>'cog', 'companies'=>'building', 'products'=>'cube', 'commercial'=>'suitcase', 'invoicing'=>'coins',
4306 'accounting'=>'search-dollar', 'category'=>'tag', 'dollyrevert'=>'dolly',
4307 'generate'=>'plus-square', 'hrm'=>'user-tie', 'incoterm'=>'truck-loading',
4308 'margin'=>'calculator', 'members'=>'user-friends', 'ticket'=>'ticket-alt', 'globe'=>'external-link-alt', 'lot'=>'barcode',
4309 'email'=>'at', 'establishment'=>'building', 'edit'=>'pencil-alt', 'entity'=>'globe',
4310 'graph'=>'chart-line', 'grip_title'=>'arrows-alt', 'grip'=>'arrows-alt', 'help'=>'question-circle',
4311 'generic'=>'file', 'holiday'=>'umbrella-beach',
4312 'info'=>'info-circle', 'inventory'=>'boxes', 'intracommreport'=>'globe-europe', 'jobprofile'=>'cogs',
4313 'knowledgemanagement'=>'ticket-alt', 'label'=>'layer-group', 'line'=>'bars', 'loan'=>'money-bill-alt',
4314 'member'=>'user-alt', 'meeting'=>'chalkboard-teacher', 'mrp'=>'cubes', 'next'=>'arrow-alt-circle-right',
4315 'trip'=>'wallet', 'expensereport'=>'wallet', 'group'=>'users', 'movement'=>'people-carry',
4316 'sign-out'=>'sign-out-alt',
4317 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_warning'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star',
4318 'bank'=>'university', 'close_title'=>'times', 'delete'=>'trash', 'filter'=>'filter',
4319 'list-alt'=>'list-alt', 'calendarlist'=>'bars', 'calendar'=>'calendar-alt', 'calendarmonth'=>'calendar-alt', 'calendarweek'=>'calendar-week', 'calendarday'=>'calendar-day', 'calendarperuser'=>'table',
4320 'intervention'=>'ambulance', 'invoice'=>'file-invoice-dollar', 'currency'=>'dollar-sign', 'multicurrency'=>'dollar-sign', 'order'=>'file-invoice',
4321 'error'=>'exclamation-triangle', 'warning'=>'exclamation-triangle',
4322 'other'=>'square',
4323 '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',
4324 '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',
4325 'recent' => 'check-square', 'reception'=>'dolly', 'recruitmentjobposition'=>'id-card-alt', 'recruitmentcandidature'=>'id-badge',
4326 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature',
4327 'refresh'=>'redo', 'region'=>'map-marked', 'replacement'=>'exchange-alt', 'resource'=>'laptop-house', 'recurring'=>'history',
4328 'service'=>'concierge-bell',
4329 'skill'=>'shapes', 'state'=>'map-marked-alt', 'security'=>'key', 'salary'=>'wallet', 'shipment'=>'dolly', 'stock'=>'box-open', 'stats' => 'chart-bar', 'split'=>'code-branch', 'stripe'=>'stripe-s',
4330 'supplier'=>'building', 'technic'=>'cogs',
4331 'timespent'=>'clock', 'title_setup'=>'tools', 'title_accountancy'=>'money-check-alt', 'title_bank'=>'university', 'title_hrm'=>'umbrella-beach',
4332 'title_agenda'=>'calendar-alt',
4333 'uncheck'=>'times', 'uparrow'=>'share', 'url'=>'external-link-alt', 'vat'=>'money-check-alt', 'vcard'=>'arrow-alt-circle-down',
4334 'jabber'=>'comment-o',
4335 'website'=>'globe-americas', 'workstation'=>'pallet', 'webhook'=>'bullseye', 'world'=>'globe', 'private'=>'user-lock',
4336 'conferenceorbooth'=>'chalkboard-teacher', 'eventorganization'=>'project-diagram'
4337 );
4338 if ($pictowithouttext == 'off') {
4339 $fakey = 'fa-square';
4340 $fasize = '1.3em';
4341 } elseif ($pictowithouttext == 'on') {
4342 $fakey = 'fa-check-square';
4343 $fasize = '1.3em';
4344 } elseif ($pictowithouttext == 'listlight') {
4345 $fakey = 'fa-download';
4346 $marginleftonlyshort = 1;
4347 } elseif ($pictowithouttext == 'printer') {
4348 $fakey = 'fa-print';
4349 $fasize = '1.2em';
4350 } elseif ($pictowithouttext == 'note') {
4351 $fakey = 'fa-sticky-note';
4352 $marginleftonlyshort = 1;
4353 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
4354 $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');
4355 $fakey = 'fa-'.$convertarray[$pictowithouttext];
4356 if (preg_match('/selected/', $pictowithouttext)) {
4357 $facolor = '#888';
4358 }
4359 $marginleftonlyshort = 1;
4360 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
4361 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
4362 } else {
4363 $fakey = 'fa-'.$pictowithouttext;
4364 }
4365
4366 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment'))) {
4367 $morecss .= ' em092';
4368 }
4369 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
4370 $morecss .= ' em088';
4371 }
4372 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
4373 $morecss .= ' em080';
4374 }
4375
4376 // Define $marginleftonlyshort
4377 $arrayconvpictotomarginleftonly = array(
4378 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
4379 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
4380 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
4381 );
4382 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
4383 $marginleftonlyshort = 0;
4384 }
4385
4386 // Add CSS
4387 $arrayconvpictotomorcess = array(
4388 'action'=>'infobox-action', 'account'=>'infobox-bank_account', 'accounting_account'=>'infobox-bank_account', 'accountline'=>'infobox-bank_account', 'accountancy'=>'infobox-bank_account', 'asset'=>'infobox-bank_account',
4389 'bank_account'=>'infobox-bank_account',
4390 'bill'=>'infobox-commande', 'billa'=>'infobox-commande', 'billr'=>'infobox-commande', 'billd'=>'infobox-commande',
4391 'margin'=>'infobox-bank_account', 'conferenceorbooth'=>'infobox-project',
4392 'cash-register'=>'infobox-bank_account', 'contract'=>'infobox-contrat', 'check'=>'font-status4', 'collab'=>'infobox-action', 'conversation'=>'infobox-contrat',
4393 'donation'=>'infobox-commande', 'dolly'=>'infobox-commande', 'dollyrevert'=>'flip infobox-order_supplier',
4394 'ecm'=>'infobox-action', 'eventorganization'=>'infobox-project',
4395 'hrm'=>'infobox-adherent', 'group'=>'infobox-adherent', 'intervention'=>'infobox-contrat',
4396 'incoterm'=>'infobox-supplier_proposal',
4397 'currency'=>'infobox-bank_account', 'multicurrency'=>'infobox-bank_account',
4398 'members'=>'infobox-adherent', 'member'=>'infobox-adherent', 'money-bill-alt'=>'infobox-bank_account',
4399 'order'=>'infobox-commande',
4400 'user'=>'infobox-adherent', 'users'=>'infobox-adherent',
4401 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_warning'=>'font-status4 warning', 'switch_on_red'=>'font-status8',
4402 'holiday'=>'infobox-holiday', 'info'=>'opacityhigh', 'invoice'=>'infobox-commande',
4403 'knowledgemanagement'=>'infobox-contrat rotate90', 'loan'=>'infobox-bank_account',
4404 'payment'=>'infobox-bank_account', 'payment_vat'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'pos'=>'infobox-bank_account', 'project'=>'infobox-project', 'projecttask'=>'infobox-project',
4405 'propal'=>'infobox-propal', 'proposal'=>'infobox-propal','private'=>'infobox-project',
4406 'reception'=>'flip', 'recruitmentjobposition'=>'infobox-adherent', 'recruitmentcandidature'=>'infobox-adherent',
4407 'resource'=>'infobox-action',
4408 'salary'=>'infobox-bank_account', 'shipment'=>'infobox-commande', 'supplier_invoice'=>'infobox-order_supplier', 'supplier_invoicea'=>'infobox-order_supplier', 'supplier_invoiced'=>'infobox-order_supplier',
4409 'supplier'=>'infobox-order_supplier', 'supplier_order'=>'infobox-order_supplier', 'supplier_proposal'=>'infobox-supplier_proposal',
4410 'ticket'=>'infobox-contrat', 'title_accountancy'=>'infobox-bank_account', 'title_hrm'=>'infobox-holiday', 'expensereport'=>'infobox-expensereport', 'trip'=>'infobox-expensereport', 'title_agenda'=>'infobox-action',
4411 'vat'=>'infobox-bank_account',
4412 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
4413 'list-alt'=>'imgforviewmode', 'calendar'=>'imgforviewmode', 'calendarweek'=>'imgforviewmode', 'calendarmonth'=>'imgforviewmode', 'calendarday'=>'imgforviewmode', 'calendarperuser'=>'imgforviewmode'
4414 );
4415 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4416 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
4417 }
4418
4419 // Define $color
4420 $arrayconvpictotocolor = array(
4421 'address'=>'#6c6aa8', 'building'=>'#6c6aa8', 'bom'=>'#a69944',
4422 'clone'=>'#999', 'cog'=>'#999', 'companies'=>'#6c6aa8', 'company'=>'#6c6aa8', 'contact'=>'#6c6aa8', 'cron'=>'#555',
4423 'dynamicprice'=>'#a69944',
4424 'edit'=>'#444', 'note'=>'#999', 'error'=>'', 'help'=>'#bbb', 'listlight'=>'#999', 'language'=>'#555',
4425 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
4426 'lock'=>'#ddd', 'lot'=>'#a69944',
4427 'map-marker-alt'=>'#aaa', 'mrp'=>'#a69944', 'product'=>'#a69944', 'service'=>'#a69944', 'inventory'=>'#a69944', 'stock'=>'#a69944', 'movement'=>'#a69944',
4428 'other'=>'#ddd', 'world'=>'#986c6a',
4429 'partnership'=>'#6c6aa8', 'playdisabled'=>'#ccc', 'printer'=>'#444', 'projectpub'=>'#986c6a', 'reception'=>'#a69944', 'resize'=>'#444', 'rss'=>'#cba',
4430 //'shipment'=>'#a69944',
4431 'security'=>'#999', 'square'=>'#888', 'stop-circle'=>'#888', 'stats'=>'#444', 'switch_off'=>'#999', 'technic'=>'#999', 'timespent'=>'#555',
4432 'uncheck'=>'#800', 'uparrow'=>'#555', 'user-cog'=>'#999', 'country'=>'#aaa', 'globe-americas'=>'#aaa', 'region'=>'#aaa', 'state'=>'#aaa',
4433 'website'=>'#304', 'workstation'=>'#a69944'
4434 );
4435 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4436 $facolor = $arrayconvpictotocolor[$pictowithouttext];
4437 }
4438
4439 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4440 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4441 $morestyle = '';
4442 $reg = array();
4443 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4444 $morecss .= ($morecss ? ' ' : '').$reg[1];
4445 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4446 }
4447 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4448 $morestyle = $reg[1];
4449 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4450 }
4451 $moreatt = trim($moreatt);
4452
4453 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4454 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4455 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4456 $enabledisablehtml .= $titlealt;
4457 }*/
4458 $enabledisablehtml .= '</span>';
4459
4460 return $enabledisablehtml;
4461 }
4462
4463 if (!empty($conf->global->MAIN_OVERWRITE_THEME_PATH)) {
4464 $path = $conf->global->MAIN_OVERWRITE_THEME_PATH.'/theme/'.$theme; // If the theme does not have the same name as the module
4465 } elseif (!empty($conf->global->MAIN_OVERWRITE_THEME_RES)) {
4466 $path = $conf->global->MAIN_OVERWRITE_THEME_RES.'/theme/'.$conf->global->MAIN_OVERWRITE_THEME_RES; // To allow an external module to overwrite image resources whatever is activated theme
4467 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
4468 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
4469 }
4470
4471 // If we ask an image into $url/$mymodule/img (instead of default path)
4472 $regs = array();
4473 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
4474 $picto = $regs[1];
4475 $path = $regs[2]; // $path is $mymodule
4476 }
4477
4478 // Clean parameters
4479 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4480 $picto .= '.png';
4481 }
4482 // If alt path are defined, define url where img file is, according to physical path
4483 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
4484 foreach ($conf->file->dol_document_root as $type => $dirroot) {
4485 if ($type == 'main') {
4486 continue;
4487 }
4488 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommanded
4489 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
4490 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
4491 break;
4492 }
4493 }
4494
4495 // $url is '' or '/custom', $path is current theme or
4496 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
4497 }
4498
4499 if ($srconly) {
4500 return $fullpathpicto;
4501 }
4502
4503 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
4504 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
4505}
4506
4520function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0)
4521{
4522 if (strpos($picto, '^') === 0) {
4523 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
4524 } else {
4525 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
4526 }
4527}
4528
4540function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
4541{
4542 global $conf;
4543
4544 if (is_numeric($picto)) {
4545 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
4546 //$picto = $leveltopicto[$picto];
4547 return '<i class="fa fa-weather-level'.$picto.'"></i>';
4548 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4549 $picto .= '.png';
4550 }
4551
4552 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
4553
4554 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
4555}
4556
4568function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
4569{
4570 global $conf;
4571
4572 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4573 $picto .= '.png';
4574 }
4575
4576 if ($pictoisfullpath) {
4577 $path = $picto;
4578 } else {
4579 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
4580
4581 if (!empty($conf->global->MAIN_MODULE_CAN_OVERWRITE_COMMONICONS)) {
4582 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
4583
4584 if (file_exists($themepath)) {
4585 $path = $themepath;
4586 }
4587 }
4588 }
4589
4590 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
4591}
4592
4606function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
4607{
4608 global $langs;
4609
4610 if (empty($titlealt) || $titlealt == 'default') {
4611 if ($numaction == '-1' || $numaction == 'ST_NO') {
4612 $numaction = -1;
4613 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
4614 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
4615 $numaction = 0;
4616 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
4617 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
4618 $numaction = 1;
4619 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
4620 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
4621 $numaction = 2;
4622 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
4623 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
4624 $numaction = 3;
4625 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
4626 } else {
4627 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
4628 $numaction = 0;
4629 }
4630 }
4631 if (!is_numeric($numaction)) {
4632 $numaction = 0;
4633 }
4634
4635 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
4636}
4637
4645function img_pdf($titlealt = 'default', $size = 3)
4646{
4647 global $langs;
4648
4649 if ($titlealt == 'default') {
4650 $titlealt = $langs->trans('Show');
4651 }
4652
4653 return img_picto($titlealt, 'pdf'.$size.'.png');
4654}
4655
4663function img_edit_add($titlealt = 'default', $other = '')
4664{
4665 global $langs;
4666
4667 if ($titlealt == 'default') {
4668 $titlealt = $langs->trans('Add');
4669 }
4670
4671 return img_picto($titlealt, 'edit_add.png', $other);
4672}
4680function img_edit_remove($titlealt = 'default', $other = '')
4681{
4682 global $langs;
4683
4684 if ($titlealt == 'default') {
4685 $titlealt = $langs->trans('Remove');
4686 }
4687
4688 return img_picto($titlealt, 'edit_remove.png', $other);
4689}
4690
4699function img_edit($titlealt = 'default', $float = 0, $other = '')
4700{
4701 global $langs;
4702
4703 if ($titlealt == 'default') {
4704 $titlealt = $langs->trans('Modify');
4705 }
4706
4707 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
4708}
4709
4718function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
4719{
4720 global $langs;
4721
4722 if ($titlealt == 'default') {
4723 $titlealt = $langs->trans('View');
4724 }
4725
4726 $moreatt = ($float ? 'style="float: right" ' : '').$other;
4727
4728 return img_picto($titlealt, 'eye', $moreatt);
4729}
4730
4739function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
4740{
4741 global $langs;
4742
4743 if ($titlealt == 'default') {
4744 $titlealt = $langs->trans('Delete');
4745 }
4746
4747 return img_picto($titlealt, 'delete.png', $other, false, 0, 0, '', $morecss);
4748}
4749
4757function img_printer($titlealt = "default", $other = '')
4758{
4759 global $langs;
4760 if ($titlealt == "default") {
4761 $titlealt = $langs->trans("Print");
4762 }
4763 return img_picto($titlealt, 'printer.png', $other);
4764}
4765
4773function img_split($titlealt = 'default', $other = 'class="pictosplit"')
4774{
4775 global $langs;
4776
4777 if ($titlealt == 'default') {
4778 $titlealt = $langs->trans('Split');
4779 }
4780
4781 return img_picto($titlealt, 'split.png', $other);
4782}
4783
4791function img_help($usehelpcursor = 1, $usealttitle = 1)
4792{
4793 global $langs;
4794
4795 if ($usealttitle) {
4796 if (is_string($usealttitle)) {
4797 $usealttitle = dol_escape_htmltag($usealttitle);
4798 } else {
4799 $usealttitle = $langs->trans('Info');
4800 }
4801 }
4802
4803 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
4804}
4805
4812function img_info($titlealt = 'default')
4813{
4814 global $langs;
4815
4816 if ($titlealt == 'default') {
4817 $titlealt = $langs->trans('Informations');
4818 }
4819
4820 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
4821}
4822
4831function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
4832{
4833 global $langs;
4834
4835 if ($titlealt == 'default') {
4836 $titlealt = $langs->trans('Warning');
4837 }
4838
4839 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
4840 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
4841}
4842
4849function img_error($titlealt = 'default')
4850{
4851 global $langs;
4852
4853 if ($titlealt == 'default') {
4854 $titlealt = $langs->trans('Error');
4855 }
4856
4857 return img_picto($titlealt, 'error.png');
4858}
4859
4867function img_next($titlealt = 'default', $moreatt = '')
4868{
4869 global $langs;
4870
4871 if ($titlealt == 'default') {
4872 $titlealt = $langs->trans('Next');
4873 }
4874
4875 //return img_picto($titlealt, 'next.png', $moreatt);
4876 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
4877}
4878
4886function img_previous($titlealt = 'default', $moreatt = '')
4887{
4888 global $langs;
4889
4890 if ($titlealt == 'default') {
4891 $titlealt = $langs->trans('Previous');
4892 }
4893
4894 //return img_picto($titlealt, 'previous.png', $moreatt);
4895 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
4896}
4897
4906function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
4907{
4908 global $langs;
4909
4910 if ($titlealt == 'default') {
4911 $titlealt = $langs->trans('Down');
4912 }
4913
4914 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
4915}
4916
4925function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
4926{
4927 global $langs;
4928
4929 if ($titlealt == 'default') {
4930 $titlealt = $langs->trans('Up');
4931 }
4932
4933 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
4934}
4935
4944function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
4945{
4946 global $langs;
4947
4948 if ($titlealt == 'default') {
4949 $titlealt = $langs->trans('Left');
4950 }
4951
4952 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
4953}
4954
4963function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
4964{
4965 global $langs;
4966
4967 if ($titlealt == 'default') {
4968 $titlealt = $langs->trans('Right');
4969 }
4970
4971 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
4972}
4973
4981function img_allow($allow, $titlealt = 'default')
4982{
4983 global $langs;
4984
4985 if ($titlealt == 'default') {
4986 $titlealt = $langs->trans('Active');
4987 }
4988
4989 if ($allow == 1) {
4990 return img_picto($titlealt, 'tick.png');
4991 }
4992
4993 return '-';
4994}
4995
5003function img_credit_card($brand, $morecss = null)
5004{
5005 if (is_null($morecss)) {
5006 $morecss = 'fa-2x';
5007 }
5008
5009 if ($brand == 'visa' || $brand == 'Visa') {
5010 $brand = 'cc-visa';
5011 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5012 $brand = 'cc-mastercard';
5013 } elseif ($brand == 'amex' || $brand == 'American Express') {
5014 $brand = 'cc-amex';
5015 } elseif ($brand == 'discover' || $brand == 'Discover') {
5016 $brand = 'cc-discover';
5017 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5018 $brand = 'cc-jcb';
5019 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5020 $brand = 'cc-diners-club';
5021 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5022 $brand = 'credit-card';
5023 }
5024
5025 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5026}
5027
5036function img_mime($file, $titlealt = '', $morecss = '')
5037{
5038 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5039
5040 $mimetype = dol_mimetype($file, '', 1);
5041 $mimeimg = dol_mimetype($file, '', 2);
5042 $mimefa = dol_mimetype($file, '', 4);
5043
5044 if (empty($titlealt)) {
5045 $titlealt = 'Mime type: '.$mimetype;
5046 }
5047
5048 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5049 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5050}
5051
5052
5060function img_search($titlealt = 'default', $other = '')
5061{
5062 global $conf, $langs;
5063
5064 if ($titlealt == 'default') {
5065 $titlealt = $langs->trans('Search');
5066 }
5067
5068 $img = img_picto($titlealt, 'search.png', $other, false, 1);
5069
5070 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5071 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5072
5073 return $input;
5074}
5075
5083function img_searchclear($titlealt = 'default', $other = '')
5084{
5085 global $conf, $langs;
5086
5087 if ($titlealt == 'default') {
5088 $titlealt = $langs->trans('Search');
5089 }
5090
5091 $img = img_picto($titlealt, 'searchclear.png', $other, false, 1);
5092
5093 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5094 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5095
5096 return $input;
5097}
5098
5110function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '')
5111{
5112 global $conf, $langs;
5113
5114 if ($infoonimgalt) {
5115 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5116 } else {
5117 if (empty($conf->use_javascript_ajax)) {
5118 $textfordropdown = '';
5119 }
5120
5121 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5122 $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>');
5123
5124 if ($textfordropdown) {
5125 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5126 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5127 jQuery(document).ready(function() {
5128 jQuery(".'.$class.'text").click(function() {
5129 console.log("toggle text");
5130 jQuery(".'.$class.'").toggle();
5131 });
5132 });
5133 </script>';
5134
5135 $result = $tmpresult.$result;
5136 }
5137 }
5138
5139 return $result;
5140}
5141
5142
5154function dol_print_error($db = '', $error = '', $errors = null)
5155{
5156 global $conf, $langs, $argv;
5157 global $dolibarr_main_prod;
5158
5159 $out = '';
5160 $syslog = '';
5161
5162 // If error occurs before the $lang object was loaded
5163 if (!$langs) {
5164 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5165 $langs = new Translate('', $conf);
5166 $langs->load("main");
5167 }
5168
5169 // Load translation files required by the error messages
5170 $langs->loadLangs(array('main', 'errors'));
5171
5172 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5173 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5174 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5175 $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";
5176 }
5177 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5178
5179 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5180 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5181 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5182 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5183 }
5184 if (function_exists("phpversion")) {
5185 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5186 }
5187 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5188 if (function_exists("php_uname")) {
5189 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5190 }
5191 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5192 $out .= "<br>\n";
5193 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5194 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5195 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5196 $out .= "<br>\n";
5197 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5198 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5199 } else { // Mode CLI
5200 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5201 $syslog .= "pid=".dol_getmypid();
5202 }
5203
5204 if (!empty($conf->modules)) {
5205 $out .= "<b>".$langs->trans("Modules").":</b> ".join(', ', $conf->modules)."<br>\n";
5206 }
5207
5208 if (is_object($db)) {
5209 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5210 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5211 $lastqueryerror = $db->lastqueryerror();
5212 if (!utf8_check($lastqueryerror)) {
5213 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5214 }
5215 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5216 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5217 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5218 $out .= "<br>\n";
5219 } else { // Mode CLI
5220 // No dol_escape_htmltag for output, we are in CLI mode
5221 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5222 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5223 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5224 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5225 }
5226 $syslog .= ", sql=".$db->lastquery();
5227 $syslog .= ", db_error=".$db->lasterror();
5228 }
5229
5230 if ($error || $errors) {
5231 $langs->load("errors");
5232
5233 // Merge all into $errors array
5234 if (is_array($error) && is_array($errors)) {
5235 $errors = array_merge($error, $errors);
5236 } elseif (is_array($error)) {
5237 $errors = $error;
5238 } elseif (is_array($errors)) {
5239 $errors = array_merge(array($error), $errors);
5240 } else {
5241 $errors = array_merge(array($error), array($errors));
5242 }
5243
5244 foreach ($errors as $msg) {
5245 if (empty($msg)) {
5246 continue;
5247 }
5248 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5249 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5250 } else // Mode CLI
5251 {
5252 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5253 }
5254 $syslog .= ", msg=".$msg;
5255 }
5256 }
5257 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5258 xdebug_print_function_stack();
5259 $out .= '<b>XDebug informations:</b>'."<br>\n";
5260 $out .= 'File: '.xdebug_call_file()."<br>\n";
5261 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5262 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5263 $out .= "<br>\n";
5264 }
5265
5266 // Return a http header with error code if possible
5267 if (!headers_sent()) {
5268 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5269 top_httphead();
5270 }
5271 //http_response_code(500); // If we use 500, message is not ouput with some command line tools
5272 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
5273 }
5274
5275 if (empty($dolibarr_main_prod)) {
5276 print $out;
5277 } else {
5278 if (empty($langs->defaultlang)) {
5279 $langs->setDefaultLang();
5280 }
5281 $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.
5282 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5283 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";
5284 print $langs->trans("DolibarrHasDetectedError").'. ';
5285 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5286 if (!defined("MAIN_CORE_ERROR")) {
5287 define("MAIN_CORE_ERROR", 1);
5288 }
5289 }
5290
5291 dol_syslog("Error ".$syslog, LOG_ERR);
5292}
5293
5304function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5305{
5306 global $langs, $conf;
5307
5308 if (empty($email)) {
5309 $email = $conf->global->MAIN_INFO_SOCIETE_MAIL;
5310 }
5311
5312 $langs->load("errors");
5313 $now = dol_now();
5314
5315 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5316 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5317 if ($errormessage) {
5318 print '<br><br>'.$errormessage;
5319 }
5320 if (is_array($errormessages) && count($errormessages)) {
5321 foreach ($errormessages as $mesgtoshow) {
5322 print '<br><br>'.$mesgtoshow;
5323 }
5324 }
5325 print '</div></div>';
5326}
5327
5344function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
5345{
5346 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
5347}
5348
5367function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
5368{
5369 global $conf, $langs, $form;
5370 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
5371
5372 if ($moreattrib == 'class="right"') {
5373 $prefix .= 'right '; // For backward compatibility
5374 }
5375
5376 $sortorder = strtoupper($sortorder);
5377 $out = '';
5378 $sortimg = '';
5379
5380 $tag = 'th';
5381 if ($thead == 2) {
5382 $tag = 'div';
5383 }
5384
5385 $tmpsortfield = explode(',', $sortfield);
5386 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
5387 $tmpfield = explode(',', $field);
5388 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
5389
5390 if (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && empty($forcenowrapcolumntitle)) {
5391 $prefix = 'wrapcolumntitle '.$prefix;
5392 }
5393
5394 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
5395 // If field is used as sort criteria we use a specific css class liste_titre_sel
5396 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
5397 $liste_titre = 'liste_titre';
5398 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
5399 $liste_titre = 'liste_titre_sel';
5400 }
5401
5402 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
5403 //$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)).'"' : '');
5404 $tagstart .= ($name && empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
5405 $tagstart .= '>';
5406
5407 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5408 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5409 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5410 $options = preg_replace('/&+/i', '&', $options);
5411 if (!preg_match('/^&/', $options)) {
5412 $options = '&'.$options;
5413 }
5414
5415 $sortordertouseinlink = '';
5416 if ($field1 != $sortfield1) { // We are on another field than current sorted field
5417 if (preg_match('/^DESC/i', $sortorder)) {
5418 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5419 } else { // We reverse the var $sortordertouseinlink
5420 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5421 }
5422 } else { // We are on field that is the first current sorting criteria
5423 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
5424 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5425 } else {
5426 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5427 }
5428 }
5429 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
5430 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
5431 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5432 $out .= '>';
5433 }
5434 if ($tooltip) {
5435 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
5436 if (preg_match('/:\w+$/', $tooltip)) {
5437 $tmptooltip = explode(':', $tooltip);
5438 } else {
5439 $tmptooltip = array($tooltip);
5440 }
5441 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
5442 } else {
5443 $out .= $langs->trans($name);
5444 }
5445
5446 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5447 $out .= '</a>';
5448 }
5449
5450 if (empty($thead) && $field) { // If this is a sort field
5451 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5452 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5453 $options = preg_replace('/&+/i', '&', $options);
5454 if (!preg_match('/^&/', $options)) {
5455 $options = '&'.$options;
5456 }
5457
5458 if (!$sortorder || ($field1 != $sortfield1)) {
5459 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5460 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5461 } else {
5462 if (preg_match('/^DESC/', $sortorder)) {
5463 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5464 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
5465 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
5466 }
5467 if (preg_match('/^ASC/', $sortorder)) {
5468 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
5469 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5470 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
5471 }
5472 }
5473 }
5474
5475 $tagend = '</'.$tag.'>';
5476
5477 $out = $tagstart.$sortimg.$out.$tagend;
5478
5479 return $out;
5480}
5481
5490function print_titre($title)
5491{
5492 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
5493
5494 print '<div class="titre">'.$title.'</div>';
5495}
5496
5508function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
5509{
5510 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
5511}
5512
5526function load_fiche_titre($titre, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
5527{
5528 global $conf;
5529
5530 $return = '';
5531
5532 if ($picto == 'setup') {
5533 $picto = 'generic';
5534 }
5535
5536 $return .= "\n";
5537 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
5538 $return .= '<tr class="titre">';
5539 if ($picto) {
5540 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
5541 }
5542 $return .= '<td class="nobordernopadding valignmiddle col-title">';
5543 $return .= '<div class="titre inline-block">'.$titre.'</div>';
5544 $return .= '</td>';
5545 if (dol_strlen($morehtmlcenter)) {
5546 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5547 }
5548 if (dol_strlen($morehtmlright)) {
5549 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
5550 }
5551 $return .= '</tr></table>'."\n";
5552
5553 return $return;
5554}
5555
5579function 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 = '')
5580{
5581 global $conf, $langs;
5582
5583 $savlimit = $limit;
5584 $savtotalnboflines = $totalnboflines;
5585 $totalnboflines = abs((int) $totalnboflines);
5586
5587 $page = (int) $page;
5588
5589 if ($picto == 'setup') {
5590 $picto = 'title_setup.png';
5591 }
5592 if (($conf->browser->name == 'ie') && $picto == 'generic') {
5593 $picto = 'title.gif';
5594 }
5595 if ($limit < 0) {
5596 $limit = $conf->liste_limit;
5597 }
5598
5599 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
5600 $nextpage = 1;
5601 } else {
5602 $nextpage = 0;
5603 }
5604 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
5605
5606 print "\n";
5607 print "<!-- Begin title -->\n";
5608 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
5609
5610 // Left
5611
5612 if ($picto && $titre) {
5613 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
5614 }
5615
5616 print '<td class="nobordernopadding valignmiddle col-title">';
5617 print '<div class="titre inline-block">'.$titre;
5618 if (!empty($titre) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
5619 print '<span class="opacitymedium colorblack paddingleft">('.$totalnboflines.')</span>';
5620 }
5621 print '</div></td>';
5622
5623 // Center
5624 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
5625 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5626 }
5627
5628 // Right
5629 print '<td class="nobordernopadding valignmiddle right col-right">';
5630 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
5631 if ($sortfield) {
5632 $options .= "&sortfield=".urlencode($sortfield);
5633 }
5634 if ($sortorder) {
5635 $options .= "&sortorder=".urlencode($sortorder);
5636 }
5637 // Show navigation bar
5638 $pagelist = '';
5639 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
5640 if ($totalnboflines) { // If we know total nb of lines
5641 // Define nb of extra page links before and after selected page + ... + first or last
5642 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
5643
5644 if ($limit > 0) {
5645 $nbpages = ceil($totalnboflines / $limit);
5646 } else {
5647 $nbpages = 1;
5648 }
5649 $cpt = ($page - $maxnbofpage);
5650 if ($cpt < 0) {
5651 $cpt = 0;
5652 }
5653
5654 if ($cpt >= 1) {
5655 if (empty($pagenavastextinput)) {
5656 $pagelist .= '<li class="pagination"><a href="'.$file.'?page=0'.$options.'">1</a></li>';
5657 if ($cpt > 2) {
5658 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5659 } elseif ($cpt == 2) {
5660 $pagelist .= '<li class="pagination"><a href="'.$file.'?page=1'.$options.'">2</a></li>';
5661 }
5662 }
5663 }
5664
5665 do {
5666 if ($pagenavastextinput) {
5667 if ($cpt == $page) {
5668 $pagelist .= '<li class="pagination"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
5669 $pagelist .= '/';
5670 }
5671 } else {
5672 if ($cpt == $page) {
5673 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
5674 } else {
5675 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
5676 }
5677 }
5678 $cpt++;
5679 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
5680
5681 if (empty($pagenavastextinput)) {
5682 if ($cpt < $nbpages) {
5683 if ($cpt < $nbpages - 2) {
5684 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5685 } elseif ($cpt == $nbpages - 2) {
5686 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
5687 }
5688 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5689 }
5690 } else {
5691 //var_dump($page.' '.$cpt.' '.$nbpages);
5692 $pagelist .= '<li class="pagination paginationlastpage"><a href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5693 }
5694 } else {
5695 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
5696 }
5697 }
5698
5699 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
5700 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
5701 }
5702
5703 // js to autoselect page field on focus
5704 if ($pagenavastextinput) {
5705 print ajax_autoselect('.pageplusone');
5706 }
5707
5708 print '</td>';
5709 print '</tr>';
5710
5711 print '</table>'."\n";
5712
5713 // Center
5714 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
5715 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
5716 }
5717
5718 print "<!-- End title -->\n\n";
5719}
5720
5737function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
5738{
5739 global $conf, $langs;
5740
5741 print '<div class="pagination"><ul>';
5742 if ($beforearrows) {
5743 print '<li class="paginationbeforearrows">';
5744 print $beforearrows;
5745 print '</li>';
5746 }
5747
5748 if (empty($hidenavigation)) {
5749 if ((int) $limit > 0 && empty($hideselectlimit)) {
5750 $pagesizechoices = '10:10,15:15,20:20,30:30,40:40,50:50,100:100,250:250,500:500,1000:1000';
5751 $pagesizechoices .= ',5000:5000,10000:10000,20000:20000';
5752 //$pagesizechoices.=',0:'.$langs->trans("All"); // Not yet supported
5753 //$pagesizechoices.=',2:2';
5754 if (!empty($conf->global->MAIN_PAGESIZE_CHOICES)) {
5755 $pagesizechoices = $conf->global->MAIN_PAGESIZE_CHOICES;
5756 }
5757
5758 print '<li class="pagination">';
5759 print '<select class="flat selectlimit" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
5760 $tmpchoice = explode(',', $pagesizechoices);
5761 $tmpkey = $limit.':'.$limit;
5762 if (!in_array($tmpkey, $tmpchoice)) {
5763 $tmpchoice[] = $tmpkey;
5764 }
5765 $tmpkey = $conf->liste_limit.':'.$conf->liste_limit;
5766 if (!in_array($tmpkey, $tmpchoice)) {
5767 $tmpchoice[] = $tmpkey;
5768 }
5769 asort($tmpchoice, SORT_NUMERIC);
5770 foreach ($tmpchoice as $val) {
5771 $selected = '';
5772 $tmp = explode(':', $val);
5773 $key = $tmp[0];
5774 $val = $tmp[1];
5775 if ($key != '' && $val != '') {
5776 if ((int) $key == (int) $limit) {
5777 $selected = ' selected="selected"';
5778 }
5779 print '<option name="'.$key.'"'.$selected.'>'.dol_escape_htmltag($val).'</option>'."\n";
5780 }
5781 }
5782 print '</select>';
5783 if ($conf->use_javascript_ajax) {
5784 print '<!-- JS CODE TO ENABLE select limit to launch submit of page -->
5785 <script>
5786 jQuery(document).ready(function () {
5787 jQuery(".selectlimit").change(function() {
5788 console.log("Change limit. Send submit");
5789 $(this).parents(\'form:first\').submit();
5790 });
5791 });
5792 </script>
5793 ';
5794 }
5795 print '</li>';
5796 }
5797 if ($page > 0) {
5798 print '<li class="pagination paginationpage paginationpageleft"><a class="paginationprevious" href="'.$file.'?page='.($page - 1).$options.'"><i class="fa fa-chevron-left" title="'.dol_escape_htmltag($langs->trans("Previous")).'"></i></a></li>';
5799 }
5800 if ($betweenarrows) {
5801 print '<!--<div class="betweenarrows nowraponall inline-block">-->';
5802 print $betweenarrows;
5803 print '<!--</div>-->';
5804 }
5805 if ($nextpage > 0) {
5806 print '<li class="pagination paginationpage paginationpageright"><a class="paginationnext" href="'.$file.'?page='.($page + 1).$options.'"><i class="fa fa-chevron-right" title="'.dol_escape_htmltag($langs->trans("Next")).'"></i></a></li>';
5807 }
5808 if ($afterarrows) {
5809 print '<li class="paginationafterarrows">';
5810 print $afterarrows;
5811 print '</li>';
5812 }
5813 }
5814 print '</ul></div>'."\n";
5815}
5816
5817
5829function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, $html = 0)
5830{
5831 $morelabel = '';
5832
5833 if (preg_match('/%/', $rate)) {
5834 $rate = str_replace('%', '', $rate);
5835 $addpercent = true;
5836 }
5837 $reg = array();
5838 if (preg_match('/\‍((.*)\‍)/', $rate, $reg)) {
5839 $morelabel = ' ('.$reg[1].')';
5840 $rate = preg_replace('/\s*'.preg_quote($morelabel, '/').'/', '', $rate);
5841 $morelabel = ' '.($html ? '<span class="opacitymedium">' : '').'('.$reg[1].')'.($html ? '</span>' : '');
5842 }
5843 if (preg_match('/\*/', $rate)) {
5844 $rate = str_replace('*', '', $rate);
5845 $info_bits |= 1;
5846 }
5847
5848 // If rate is '9/9/9' we don't change it. If rate is '9.000' we apply price()
5849 if (!preg_match('/\//', $rate)) {
5850 $ret = price($rate, 0, '', 0, 0).($addpercent ? '%' : '');
5851 } else {
5852 // TODO Split on / and output with a price2num to have clean numbers without ton of 000.
5853 $ret = $rate.($addpercent ? '%' : '');
5854 }
5855 if (($info_bits & 1) && $usestarfornpr >= 0) {
5856 $ret .= ' *';
5857 }
5858 $ret .= $morelabel;
5859 return $ret;
5860}
5861
5862
5878function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1, $currency_code = '')
5879{
5880 global $langs, $conf;
5881
5882 // Clean parameters
5883 if (empty($amount)) {
5884 $amount = 0; // To have a numeric value if amount not defined or = ''
5885 }
5886 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number)
5887 if ($rounding == -1) {
5888 $rounding = min($conf->global->MAIN_MAX_DECIMALS_UNIT, $conf->global->MAIN_MAX_DECIMALS_TOT);
5889 }
5890 $nbdecimal = $rounding;
5891
5892 if ($outlangs === 'none') {
5893 // Use international separators
5894 $dec = '.';
5895 $thousand = '';
5896 } else {
5897 // Output separators by default (french)
5898 $dec = ',';
5899 $thousand = ' ';
5900
5901 // If $outlangs not forced, we use use language
5902 if (!is_object($outlangs)) {
5903 $outlangs = $langs;
5904 }
5905
5906 if ($outlangs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
5907 $dec = $outlangs->transnoentitiesnoconv("SeparatorDecimal");
5908 }
5909 if ($outlangs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
5910 $thousand = $outlangs->transnoentitiesnoconv("SeparatorThousand");
5911 }
5912 if ($thousand == 'None') {
5913 $thousand = '';
5914 } elseif ($thousand == 'Space') {
5915 $thousand = ' ';
5916 }
5917 }
5918 //print "outlangs=".$outlangs->defaultlang." amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
5919
5920 //print "amount=".$amount."-";
5921 $amount = str_replace(',', '.', $amount); // should be useless
5922 //print $amount."-";
5923 $datas = explode('.', $amount);
5924 $decpart = isset($datas[1]) ? $datas[1] : '';
5925 $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
5926 //print "decpart=".$decpart."<br>";
5927 $end = '';
5928
5929 // We increase nbdecimal if there is more decimal than asked (to not loose information)
5930 if (dol_strlen($decpart) > $nbdecimal) {
5931 $nbdecimal = dol_strlen($decpart);
5932 }
5933 // Si on depasse max
5934 if ($trunc && $nbdecimal > $conf->global->MAIN_MAX_DECIMALS_SHOWN) {
5935 $nbdecimal = $conf->global->MAIN_MAX_DECIMALS_SHOWN;
5936 if (preg_match('/\.\.\./i', $conf->global->MAIN_MAX_DECIMALS_SHOWN)) {
5937 // Si un affichage est tronque, on montre des ...
5938 $end = '...';
5939 }
5940 }
5941
5942 // If force rounding
5943 if ((string) $forcerounding != '-1') {
5944 if ($forcerounding === 'MU') {
5945 $nbdecimal = $conf->global->MAIN_MAX_DECIMALS_UNIT;
5946 } elseif ($forcerounding === 'MT') {
5947 $nbdecimal = $conf->global->MAIN_MAX_DECIMALS_TOT;
5948 } elseif ($forcerounding >= 0) {
5949 $nbdecimal = $forcerounding;
5950 }
5951 }
5952
5953 // Format number
5954 $output = number_format($amount, $nbdecimal, $dec, $thousand);
5955 if ($form) {
5956 $output = preg_replace('/\s/', '&nbsp;', $output);
5957 $output = preg_replace('/\'/', '&#039;', $output);
5958 }
5959 // Add symbol of currency if requested
5960 $cursymbolbefore = $cursymbolafter = '';
5961 if ($currency_code && is_object($outlangs)) {
5962 if ($currency_code == 'auto') {
5963 $currency_code = $conf->currency;
5964 }
5965
5966 $listofcurrenciesbefore = array('AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD', 'CRC');
5967 $listoflanguagesbefore = array('nl_NL');
5968 if (in_array($currency_code, $listofcurrenciesbefore) || in_array($outlangs->defaultlang, $listoflanguagesbefore)) {
5969 $cursymbolbefore .= $outlangs->getCurrencySymbol($currency_code);
5970 } else {
5971 $tmpcur = $outlangs->getCurrencySymbol($currency_code);
5972 $cursymbolafter .= ($tmpcur == $currency_code ? ' '.$tmpcur : $tmpcur);
5973 }
5974 }
5975 $output = $cursymbolbefore.$output.$end.($cursymbolafter ? ' ' : '').$cursymbolafter;
5976
5977 return $output;
5978}
5979
6004function price2num($amount, $rounding = '', $option = 0)
6005{
6006 global $langs, $conf;
6007
6008 // Clean parameters
6009 if (is_null($amount)) {
6010 $amount = '';
6011 }
6012
6013 // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
6014 // Numbers must be '1234.56'
6015 // Decimal delimiter for PHP and database SQL requests must be '.'
6016 $dec = ',';
6017 $thousand = ' ';
6018 if (is_null($langs)) { // $langs is not defined, we use english values.
6019 $dec = '.';
6020 $thousand = ',';
6021 } else {
6022 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6023 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
6024 }
6025 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6026 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
6027 }
6028 }
6029 if ($thousand == 'None') {
6030 $thousand = '';
6031 } elseif ($thousand == 'Space') {
6032 $thousand = ' ';
6033 }
6034 //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6035
6036 // Convert value to universal number format (no thousand separator, '.' as decimal separator)
6037 if ($option != 1) { // If not a PHP number or unknown, we change or clean format
6038 //print "\n".'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'<br>';
6039 if (!is_numeric($amount)) {
6040 $amount = preg_replace('/[a-zA-Z\/\\\*\‍(\‍)<>\_]/', '', $amount);
6041 }
6042
6043 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
6044 $amount = str_replace($thousand, '', $amount);
6045 }
6046
6047 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6048 // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
6049 // So if number was already a good number, it is converted into local Dolibarr setup.
6050 if (is_numeric($amount)) {
6051 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6052 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6053 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6054 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6055 $amount = number_format($amount, $nbofdec, $dec, $thousand);
6056 }
6057 //print "QQ".$amount."<br>\n";
6058
6059 // Now make replace (the main goal of function)
6060 if ($thousand != ',' && $thousand != '.') {
6061 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6062 }
6063
6064 $amount = str_replace(' ', '', $amount); // To avoid spaces
6065 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6066 $amount = str_replace($dec, '.', $amount);
6067
6068 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6069 }
6070 //print ' XX'.$amount.' '.$rounding;
6071
6072 // Now, $amount is a real PHP float number. We make a rounding if required.
6073 if ($rounding) {
6074 $nbofdectoround = '';
6075 if ($rounding == 'MU') {
6076 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_UNIT;
6077 } elseif ($rounding == 'MT') {
6078 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_TOT;
6079 } elseif ($rounding == 'MS') {
6080 $nbofdectoround = isset($conf->global->MAIN_MAX_DECIMALS_STOCK) ? $conf->global->MAIN_MAX_DECIMALS_STOCK : 5;
6081 } elseif ($rounding == 'CU') {
6082 $nbofdectoround = max($conf->global->MAIN_MAX_DECIMALS_UNIT, 8); // TODO Use param of currency
6083 } elseif ($rounding == 'CT') {
6084 $nbofdectoround = max($conf->global->MAIN_MAX_DECIMALS_TOT, 8); // TODO Use param of currency
6085 } elseif (is_numeric($rounding)) {
6086 $nbofdectoround = (int) $rounding;
6087 }
6088
6089 //print " RR".$amount.' - '.$nbofdectoround.'<br>';
6090 if (dol_strlen($nbofdectoround)) {
6091 $amount = round(is_string($amount) ? (float) $amount : $amount, $nbofdectoround); // $nbofdectoround can be 0.
6092 } else {
6093 return 'ErrorBadParameterProvidedToFunction';
6094 }
6095 //print ' SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
6096
6097 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6098 // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
6099 if (is_numeric($amount)) {
6100 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6101 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6102 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6103 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6104 $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
6105 }
6106 //print "TT".$amount.'<br>';
6107
6108 // Always make replace because each math function (like round) replace
6109 // with local values and we want a number that has a SQL string format x.y
6110 if ($thousand != ',' && $thousand != '.') {
6111 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6112 }
6113
6114 $amount = str_replace(' ', '', $amount); // To avoid spaces
6115 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6116 $amount = str_replace($dec, '.', $amount);
6117
6118 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6119 }
6120
6121 return $amount;
6122}
6123
6136function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round = -1, $forceunitoutput = 'no', $use_short_label = 0)
6137{
6138 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
6139
6140 if (($forceunitoutput == 'no' && $dimension < 1 / 10000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -6)) {
6141 $dimension = $dimension * 1000000;
6142 $unit = $unit - 6;
6143 } elseif (($forceunitoutput == 'no' && $dimension < 1 / 10 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -3)) {
6144 $dimension = $dimension * 1000;
6145 $unit = $unit - 3;
6146 } elseif (($forceunitoutput == 'no' && $dimension > 100000000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 6)) {
6147 $dimension = $dimension / 1000000;
6148 $unit = $unit + 6;
6149 } elseif (($forceunitoutput == 'no' && $dimension > 100000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 3)) {
6150 $dimension = $dimension / 1000;
6151 $unit = $unit + 3;
6152 }
6153 // Special case when we want output unit into pound or ounce
6154 /* TODO
6155 if ($unit < 90 && $type == 'weight' && is_numeric($forceunitoutput) && (($forceunitoutput == 98) || ($forceunitoutput == 99))
6156 {
6157 $dimension = // convert dimension from standard unit into ounce or pound
6158 $unit = $forceunitoutput;
6159 }
6160 if ($unit > 90 && $type == 'weight' && is_numeric($forceunitoutput) && $forceunitoutput < 90)
6161 {
6162 $dimension = // convert dimension from standard unit into ounce or pound
6163 $unit = $forceunitoutput;
6164 }*/
6165
6166 $ret = price($dimension, 0, $outputlangs, 0, 0, $round);
6167 $ret .= ' '.measuringUnitString(0, $type, $unit, $use_short_label, $outputlangs);
6168
6169 return $ret;
6170}
6171
6172
6185function get_localtax($vatrate, $local, $thirdparty_buyer = "", $thirdparty_seller = "", $vatnpr = 0)
6186{
6187 global $db, $conf, $mysoc;
6188
6189 if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
6190 $thirdparty_seller = $mysoc;
6191 }
6192
6193 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);
6194
6195 $vatratecleaned = $vatrate;
6196 $reg = array();
6197 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6198 $vatratecleaned = trim($reg[1]);
6199 $vatratecode = $reg[2];
6200 }
6201
6202 /*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
6203 {
6204 return 0;
6205 }*/
6206
6207 // Some test to guess with no need to make database access
6208 if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
6209 if ($local == 1) {
6210 if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
6211 return 0;
6212 }
6213 if ($thirdparty_seller->id == $mysoc->id) {
6214 if (!$thirdparty_buyer->localtax1_assuj) {
6215 return 0;
6216 }
6217 } else {
6218 if (!$thirdparty_seller->localtax1_assuj) {
6219 return 0;
6220 }
6221 }
6222 }
6223
6224 if ($local == 2) {
6225 //if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
6226 if (!$mysoc->localtax2_assuj) {
6227 return 0; // If main vat is 0, IRPF may be different than 0.
6228 }
6229 if ($thirdparty_seller->id == $mysoc->id) {
6230 if (!$thirdparty_buyer->localtax2_assuj) {
6231 return 0;
6232 }
6233 } else {
6234 if (!$thirdparty_seller->localtax2_assuj) {
6235 return 0;
6236 }
6237 }
6238 }
6239 } else {
6240 if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
6241 return 0;
6242 }
6243 if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
6244 return 0;
6245 }
6246 }
6247
6248 // For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
6249 if (in_array($mysoc->country_code, array('ES'))) {
6250 $conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
6251 }
6252
6253 // Search local taxes
6254 if (!empty($conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY)) {
6255 if ($local == 1) {
6256 if ($thirdparty_seller != $mysoc) {
6257 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6258 return $thirdparty_seller->localtax1_value;
6259 }
6260 } else { // i am the seller
6261 if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
6262 return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
6263 }
6264 }
6265 }
6266 if ($local == 2) {
6267 if ($thirdparty_seller != $mysoc) {
6268 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6269 // TODO We should also return value defined on thirdparty only if defined
6270 return $thirdparty_seller->localtax2_value;
6271 }
6272 } else { // i am the seller
6273 if (in_array($mysoc->country_code, array('ES'))) {
6274 return $thirdparty_buyer->localtax2_value;
6275 } else {
6276 return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
6277 }
6278 }
6279 }
6280 }
6281
6282 // By default, search value of local tax on line of common tax
6283 $sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
6284 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6285 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
6286 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6287 if (!empty($vatratecode)) {
6288 $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
6289 } else {
6290 $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
6291 }
6292
6293 $resql = $db->query($sql);
6294
6295 if ($resql) {
6296 $obj = $db->fetch_object($resql);
6297 if ($obj) {
6298 if ($local == 1) {
6299 return $obj->localtax1;
6300 } elseif ($local == 2) {
6301 return $obj->localtax2;
6302 }
6303 }
6304 }
6305
6306 return 0;
6307}
6308
6309
6318function isOnlyOneLocalTax($local)
6319{
6320 $tax = get_localtax_by_third($local);
6321
6322 $valors = explode(":", $tax);
6323
6324 if (count($valors) > 1) {
6325 return false;
6326 } else {
6327 return true;
6328 }
6329}
6330
6338{
6339 global $db, $mysoc;
6340
6341 $sql = " SELECT t.localtax".$local." as localtax";
6342 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_pays";
6343 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.active = 1 AND t.taux = (";
6344 $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";
6345 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND tt.active = 1)";
6346 $sql .= " AND t.localtax".$local."_type <> '0'";
6347 $sql .= " ORDER BY t.rowid DESC";
6348
6349 $resql = $db->query($sql);
6350 if ($resql) {
6351 $obj = $db->fetch_object($resql);
6352 if ($obj) {
6353 return $obj->localtax;
6354 } else {
6355 return '0';
6356 }
6357 }
6358
6359 return 'Error';
6360}
6361
6362
6374function getTaxesFromId($vatrate, $buyer = null, $seller = null, $firstparamisid = 1)
6375{
6376 global $db, $mysoc;
6377
6378 dol_syslog("getTaxesFromId vat id or rate = ".$vatrate);
6379
6380 // Search local taxes
6381 $sql = "SELECT t.rowid, t.code, t.taux as rate, t.recuperableonly as npr, t.accountancy_code_sell, t.accountancy_code_buy,";
6382 $sql .= " t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type";
6383 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6384 if ($firstparamisid) {
6385 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6386 } else {
6387 $vatratecleaned = $vatrate;
6388 $vatratecode = '';
6389 $reg = array();
6390 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6391 $vatratecleaned = $reg[1];
6392 $vatratecode = $reg[2];
6393 }
6394
6395 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6396 /*if ($mysoc->country_code == 'ES') $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($buyer->country_code)."'"; // vat in spain use the buyer country ??
6397 else $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";*/
6398 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";
6399 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6400 if ($vatratecode) {
6401 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6402 }
6403 }
6404
6405 $resql = $db->query($sql);
6406 if ($resql) {
6407 $obj = $db->fetch_object($resql);
6408 if ($obj) {
6409 return array(
6410 'rowid'=>$obj->rowid,
6411 'code'=>$obj->code,
6412 'rate'=>$obj->rate,
6413 'localtax1'=>$obj->localtax1,
6414 'localtax1_type'=>$obj->localtax1_type,
6415 'localtax2'=>$obj->localtax2,
6416 'localtax2_type'=>$obj->localtax2_type,
6417 'npr'=>$obj->npr,
6418 'accountancy_code_sell'=>$obj->accountancy_code_sell,
6419 'accountancy_code_buy'=>$obj->accountancy_code_buy
6420 );
6421 } else {
6422 return array();
6423 }
6424 } else {
6425 dol_print_error($db);
6426 }
6427
6428 return array();
6429}
6430
6447function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid = 0)
6448{
6449 global $db, $mysoc;
6450
6451 dol_syslog("getLocalTaxesFromRate vatrate=".$vatrate." local=".$local);
6452
6453 // Search local taxes
6454 $sql = "SELECT t.taux as rate, t.code, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.accountancy_code_sell, t.accountancy_code_buy";
6455 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6456 if ($firstparamisid) {
6457 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6458 } else {
6459 $vatratecleaned = $vatrate;
6460 $vatratecode = '';
6461 $reg = array();
6462 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "x.x (yy)"
6463 $vatratecleaned = $reg[1];
6464 $vatratecode = $reg[2];
6465 }
6466
6467 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6468 if (!empty($mysoc) && $mysoc->country_code == 'ES') {
6469 $countrycodetouse = ((empty($buyer) || empty($buyer->country_code)) ? $mysoc->country_code : $buyer->country_code);
6470 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'"; // local tax in spain use the buyer country ??
6471 } else {
6472 $countrycodetouse = ((empty($seller) || empty($seller->country_code)) ? $mysoc->country_code : $seller->country_code);
6473 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'";
6474 }
6475 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6476 if ($vatratecode) {
6477 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6478 }
6479 }
6480
6481 $resql = $db->query($sql);
6482 if ($resql) {
6483 $obj = $db->fetch_object($resql);
6484
6485 if ($obj) {
6486 $vateratestring = $obj->rate.($obj->code ? ' ('.$obj->code.')' : '');
6487
6488 if ($local == 1) {
6489 return array($obj->localtax1_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6490 } elseif ($local == 2) {
6491 return array($obj->localtax2_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6492 } else {
6493 return array($obj->localtax1_type, get_localtax($vateratestring, 1, $buyer, $seller), $obj->localtax2_type, get_localtax($vateratestring, 2, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6494 }
6495 }
6496 }
6497
6498 return array();
6499}
6500
6511function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice = 0)
6512{
6513 global $db, $conf, $mysoc;
6514
6515 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6516
6517 $ret = 0;
6518 $found = 0;
6519
6520 if ($idprod > 0) {
6521 // Load product
6522 $product = new Product($db);
6523 $product->fetch($idprod);
6524
6525 if ($mysoc->country_code == $thirdpartytouse->country_code) {
6526 // If country to consider is ours
6527 if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object
6528 $result = $product->get_buyprice($idprodfournprice, 0, 0, 0);
6529 if ($result > 0) {
6530 $ret = $product->vatrate_supplier;
6531 if ($product->default_vat_code_supplier) {
6532 $ret .= ' ('.$product->default_vat_code_supplier.')';
6533 }
6534 $found = 1;
6535 }
6536 }
6537 if (!$found) {
6538 $ret = $product->tva_tx; // Default sales vat of product
6539 if ($product->default_vat_code) {
6540 $ret .= ' ('.$product->default_vat_code.')';
6541 }
6542 $found = 1;
6543 }
6544 } else {
6545 // TODO Read default product vat according to product and another countrycode.
6546 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6547 }
6548 }
6549
6550 if (!$found) {
6551 if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) {
6552 // If vat of product for the country not found or not defined, we return the first rate found (sorting on use_default, then on higher vat of country).
6553 $sql = "SELECT t.taux as vat_rate, t.code as default_vat_code";
6554 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6555 $sql .= " WHERE t.active = 1 AND t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdpartytouse->country_code)."'";
6556 $sql .= " ORDER BY t.use_default DESC, t.taux DESC, t.code ASC, t.recuperableonly ASC";
6557 $sql .= $db->plimit(1);
6558
6559 $resql = $db->query($sql);
6560 if ($resql) {
6561 $obj = $db->fetch_object($resql);
6562 if ($obj) {
6563 $ret = $obj->vat_rate;
6564 if ($obj->default_vat_code) {
6565 $ret .= ' ('.$obj->default_vat_code.')';
6566 }
6567 }
6568 $db->free($resql);
6569 } else {
6570 dol_print_error($db);
6571 }
6572 } else {
6573 // Forced value if autodetect fails. MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS can be
6574 // '1.23'
6575 // or '1.23 (CODE)'
6576 $defaulttx = '';
6577 if ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS != 'none') {
6578 $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6579 }
6580 /*if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6581 $defaultcode = $reg[1];
6582 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6583 }*/
6584
6585 $ret = $defaulttx;
6586 }
6587 }
6588
6589 dol_syslog("get_product_vat_for_country: ret=".$ret);
6590 return $ret;
6591}
6592
6602function get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
6603{
6604 global $db, $mysoc;
6605
6606 if (!class_exists('Product')) {
6607 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6608 }
6609
6610 $ret = 0;
6611 $found = 0;
6612
6613 if ($idprod > 0) {
6614 // Load product
6615 $product = new Product($db);
6616 $result = $product->fetch($idprod);
6617
6618 if ($mysoc->country_code == $thirdpartytouse->country_code) { // If selling country is ours
6619 /* Not defined yet, so we don't use this
6620 if ($local==1) $ret=$product->localtax1_tx;
6621 elseif ($local==2) $ret=$product->localtax2_tx;
6622 $found=1;
6623 */
6624 } else {
6625 // TODO Read default product vat according to product and another countrycode.
6626 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6627 }
6628 }
6629
6630 if (!$found) {
6631 // If vat of product for the country not found or not defined, we return higher vat of country.
6632 $sql = "SELECT taux as vat_rate, localtax1, localtax2";
6633 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6634 $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code='".$db->escape($thirdpartytouse->country_code)."'";
6635 $sql .= " ORDER BY t.taux DESC, t.recuperableonly ASC";
6636 $sql .= $db->plimit(1);
6637
6638 $resql = $db->query($sql);
6639 if ($resql) {
6640 $obj = $db->fetch_object($resql);
6641 if ($obj) {
6642 if ($local == 1) {
6643 $ret = $obj->localtax1;
6644 } elseif ($local == 2) {
6645 $ret = $obj->localtax2;
6646 }
6647 }
6648 } else {
6649 dol_print_error($db);
6650 }
6651 }
6652
6653 dol_syslog("get_product_localtax_for_country: ret=".$ret);
6654 return $ret;
6655}
6656
6673function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6674{
6675 global $conf;
6676
6677 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6678
6679 // Note: possible values for tva_assuj are 0/1 or franchise/reel
6680 $seller_use_vat = ((is_numeric($thirdparty_seller->tva_assuj) && !$thirdparty_seller->tva_assuj) || (!is_numeric($thirdparty_seller->tva_assuj) && $thirdparty_seller->tva_assuj == 'franchise')) ? 0 : 1;
6681
6682 $seller_country_code = $thirdparty_seller->country_code;
6683 $seller_in_cee = isInEEC($thirdparty_seller);
6684
6685 $buyer_country_code = $thirdparty_buyer->country_code;
6686 $buyer_in_cee = isInEEC($thirdparty_buyer);
6687