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
6688 dol_syslog("get_default_tva: seller use vat=".$seller_use_vat.", seller country=".$seller_country_code.", seller in cee=".$seller_in_cee.", buyer vat number=".$thirdparty_buyer->tva_intra." buyer country=".$buyer_country_code.", buyer in cee=".$buyer_in_cee.", idprod=".$idprod.", idprodfournprice=".$idprodfournprice.", SERVICE_ARE_ECOMMERCE_200238EC=".(!empty($conf->global->SERVICES_ARE_ECOMMERCE_200238EC) ? $conf->global->SERVICES_ARE_ECOMMERCE_200238EC : ''));
6689
6690 // If services are eServices according to EU Council Directive 2002/38/EC (http://ec.europa.eu/taxation_customs/taxation/vat/traders/e-commerce/article_1610_en.htm)
6691 // we use the buyer VAT.
6692 if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) {
6693 if ($seller_in_cee && $buyer_in_cee) {
6694 $isacompany = $thirdparty_buyer->isACompany();
6695 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6696 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6697 if (!isValidVATID($thirdparty_buyer)) {
6698 $isacompany = 0;
6699 }
6700 }
6701
6702 if (!$isacompany) {
6703 //print 'VATRULE 0';
6704 return get_product_vat_for_country($idprod, $thirdparty_buyer, $idprodfournprice);
6705 }
6706 }
6707 }
6708
6709 // If seller does not use VAT, default VAT is 0. End of rule.
6710 if (!$seller_use_vat) {
6711 //print 'VATRULE 1';
6712 return 0;
6713 }
6714
6715 // If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule.
6716 if (($seller_country_code == $buyer_country_code)
6717 || (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC')))) { // Warning ->country_code not always defined
6718 //print 'VATRULE 2';
6719 $tmpvat = get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6720
6721 if ($seller_country_code == 'IN' && getDolGlobalString('MAIN_SALETAX_AUTOSWITCH_I_CS_FOR_INDIA')) {
6722 // Special case for india.
6723 //print 'VATRULE 2b';
6724 $reg = array();
6725 if (preg_match('/C+S-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id != $thirdparty_buyer->state_id) {
6726 // we must revert the C+S into I
6727 $tmpvat = str_replace("C+S", "I", $tmpvat);
6728 } elseif (preg_match('/I-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id == $thirdparty_buyer->state_id) {
6729 // we must revert the I into C+S
6730 $tmpvat = str_replace("I", "C+S", $tmpvat);
6731 }
6732 }
6733
6734 return $tmpvat;
6735 }
6736
6737 // If (seller and buyer in the European Community) and (property sold = new means of transport such as car, boat, plane) then VAT by default = 0 (VAT must be paid by the buyer to the tax center of his country and not to the seller). End of rule.
6738 // 'VATRULE 3' - Not supported
6739
6740 // If (seller and buyer in the European Community) and (buyer = individual) then VAT by default = VAT of the product sold. End of rule
6741 // If (seller and buyer in European Community) and (buyer = company) then VAT by default=0. End of rule
6742 if (($seller_in_cee && $buyer_in_cee)) {
6743 $isacompany = $thirdparty_buyer->isACompany();
6744 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6745 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6746 if (!isValidVATID($thirdparty_buyer)) {
6747 $isacompany = 0;
6748 }
6749 }
6750
6751 if (!$isacompany) {
6752 //print 'VATRULE 4';
6753 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6754 } else {
6755 //print 'VATRULE 5';
6756 return 0;
6757 }
6758 }
6759
6760 // If (seller in the European Community and buyer outside the European Community and private buyer) then VAT by default = VAT of the product sold. End of rule
6761 // I don't see any use case that need this rule.
6762 if (!empty($conf->global->MAIN_USE_VAT_OF_PRODUCT_FOR_INDIVIDUAL_CUSTOMER_OUT_OF_EEC) && empty($buyer_in_cee)) {
6763 $isacompany = $thirdparty_buyer->isACompany();
6764 if (!$isacompany) {
6765 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6766 //print 'VATRULE extra';
6767 }
6768 }
6769
6770 // Otherwise the VAT proposed by default=0. End of rule.
6771 // Rem: This means that at least one of the 2 is outside the European Community and the country differs
6772 //print 'VATRULE 6';
6773 return 0;
6774}
6775
6776
6787function get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6788{
6789 global $db;
6790
6791 if ($idprodfournprice > 0) {
6792 if (!class_exists('ProductFournisseur')) {
6793 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
6794 }
6795 $prodprice = new ProductFournisseur($db);
6796 $prodprice->fetch_product_fournisseur_price($idprodfournprice);
6797 return $prodprice->fourn_tva_npr;
6798 } elseif ($idprod > 0) {
6799 if (!class_exists('Product')) {
6800 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6801 }
6802 $prod = new Product($db);
6803 $prod->fetch($idprod);
6804 return $prod->tva_npr;
6805 }
6806
6807 return 0;
6808}
6809
6823function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod = 0)
6824{
6825 global $mysoc;
6826
6827 if (!is_object($thirdparty_seller)) {
6828 return -1;
6829 }
6830 if (!is_object($thirdparty_buyer)) {
6831 return -1;
6832 }
6833
6834 if ($local == 1) { // Localtax 1
6835 if ($mysoc->country_code == 'ES') {
6836 if (is_numeric($thirdparty_buyer->localtax1_assuj) && !$thirdparty_buyer->localtax1_assuj) {
6837 return 0;
6838 }
6839 } else {
6840 // Si vendeur non assujeti a Localtax1, localtax1 par default=0
6841 if (is_numeric($thirdparty_seller->localtax1_assuj) && !$thirdparty_seller->localtax1_assuj) {
6842 return 0;
6843 }
6844 if (!is_numeric($thirdparty_seller->localtax1_assuj) && $thirdparty_seller->localtax1_assuj == 'localtax1off') {
6845 return 0;
6846 }
6847 }
6848 } elseif ($local == 2) { //I Localtax 2
6849 // Si vendeur non assujeti a Localtax2, localtax2 par default=0
6850 if (is_numeric($thirdparty_seller->localtax2_assuj) && !$thirdparty_seller->localtax2_assuj) {
6851 return 0;
6852 }
6853 if (!is_numeric($thirdparty_seller->localtax2_assuj) && $thirdparty_seller->localtax2_assuj == 'localtax2off') {
6854 return 0;
6855 }
6856 }
6857
6858 if ($thirdparty_seller->country_code == $thirdparty_buyer->country_code) {
6859 return get_product_localtax_for_country($idprod, $local, $thirdparty_seller);
6860 }
6861
6862 return 0;
6863}
6864
6873function yn($yesno, $case = 1, $color = 0)
6874{
6875 global $langs;
6876
6877 $result = 'unknown';
6878 $classname = '';
6879 if ($yesno == 1 || (isset($yesno) && (strtolower($yesno) == 'yes' || strtolower($yesno) == 'true'))) { // A mettre avant test sur no a cause du == 0
6880 $result = $langs->trans('yes');
6881 if ($case == 1 || $case == 3) {
6882 $result = $langs->trans("Yes");
6883 }
6884 if ($case == 2) {
6885 $result = '<input type="checkbox" value="1" checked disabled>';
6886 }
6887 if ($case == 3) {
6888 $result = '<input type="checkbox" value="1" checked disabled> '.$result;
6889 }
6890
6891 $classname = 'ok';
6892 } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') {
6893 $result = $langs->trans("no");
6894 if ($case == 1 || $case == 3) {
6895 $result = $langs->trans("No");
6896 }
6897 if ($case == 2) {
6898 $result = '<input type="checkbox" value="0" disabled>';
6899 }
6900 if ($case == 3) {
6901 $result = '<input type="checkbox" value="0" disabled> '.$result;
6902 }
6903
6904 if ($color == 2) {
6905 $classname = 'ok';
6906 } else {
6907 $classname = 'error';
6908 }
6909 }
6910 if ($color) {
6911 return '<span class="'.$classname.'">'.$result.'</span>';
6912 }
6913 return $result;
6914}
6915
6931function get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart = '')
6932{
6933 global $conf;
6934
6935 if (empty($modulepart) && !empty($object->module)) {
6936 $modulepart = $object->module;
6937 }
6938
6939 $path = '';
6940
6941 $arrayforoldpath = array('cheque', 'category', 'holiday', 'supplier_invoice', 'invoice_supplier', 'mailing', 'supplier_payment');
6942 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
6943 $arrayforoldpath[] = 'product';
6944 }
6945 if (!empty($level) && in_array($modulepart, $arrayforoldpath)) {
6946 // This part should be removed once all code is using "get_exdir" to forge path, with parameter $object and $modulepart provided.
6947 if (empty($alpha)) {
6948 $num = preg_replace('/([^0-9])/i', '', $num);
6949 } else {
6950 $num = preg_replace('/^.*\-/i', '', $num);
6951 }
6952 $num = substr("000".$num, -$level);
6953 if ($level == 1) {
6954 $path = substr($num, 0, 1);
6955 }
6956 if ($level == 2) {
6957 $path = substr($num, 1, 1).'/'.substr($num, 0, 1);
6958 }
6959 if ($level == 3) {
6960 $path = substr($num, 2, 1).'/'.substr($num, 1, 1).'/'.substr($num, 0, 1);
6961 }
6962 } else {
6963 // We will enhance here a common way of forging path for document storage.
6964 // In a future, we may distribute directories on several levels depending on setup and object.
6965 // Here, $object->id, $object->ref and $modulepart are required.
6966 //var_dump($modulepart);
6967 $path = dol_sanitizeFileName(empty($object->ref) ? (string) $object->id : $object->ref);
6968 }
6969
6970 if (empty($withoutslash) && !empty($path)) {
6971 $path .= '/';
6972 }
6973
6974 return $path;
6975}
6976
6985function dol_mkdir($dir, $dataroot = '', $newmask = '')
6986{
6987 global $conf;
6988
6989 dol_syslog("functions.lib::dol_mkdir: dir=".$dir, LOG_INFO);
6990
6991 $dir_osencoded = dol_osencode($dir);
6992 if (@is_dir($dir_osencoded)) {
6993 return 0;
6994 }
6995
6996 $nberr = 0;
6997 $nbcreated = 0;
6998
6999 $ccdir = '';
7000 if (!empty($dataroot)) {
7001 // Remove data root from loop
7002 $dir = str_replace($dataroot.'/', '', $dir);
7003 $ccdir = $dataroot.'/';
7004 }
7005
7006 $cdir = explode("/", $dir);
7007 $num = count($cdir);
7008 for ($i = 0; $i < $num; $i++) {
7009 if ($i > 0) {
7010 $ccdir .= '/'.$cdir[$i];
7011 } else {
7012 $ccdir .= $cdir[$i];
7013 }
7014 $regs = array();
7015 if (preg_match("/^.:$/", $ccdir, $regs)) {
7016 continue; // Si chemin Windows incomplet, on poursuit par rep suivant
7017 }
7018
7019 // Attention, le is_dir() peut echouer bien que le rep existe.
7020 // (ex selon config de open_basedir)
7021 if ($ccdir) {
7022 $ccdir_osencoded = dol_osencode($ccdir);
7023 if (!@is_dir($ccdir_osencoded)) {
7024 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.", LOG_DEBUG);
7025
7026 umask(0);
7027 $dirmaskdec = octdec((string) $newmask);
7028 if (empty($newmask)) {
7029 $dirmaskdec = empty($conf->global->MAIN_UMASK) ? octdec('0755') : octdec($conf->global->MAIN_UMASK);
7030 }
7031 $dirmaskdec |= octdec('0111'); // Set x bit required for directories
7032 if (!@mkdir($ccdir_osencoded, $dirmaskdec)) {
7033 // Si le is_dir a renvoye une fausse info, alors on passe ici.
7034 dol_syslog("functions.lib::dol_mkdir: Fails to create directory '".$ccdir."' or directory already exists.", LOG_WARNING);
7035 $nberr++;
7036 } else {
7037 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' created", LOG_DEBUG);
7038 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignore
7039 $nbcreated++;
7040 }
7041 } else {
7042 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignores
7043 }
7044 }
7045 }
7046 return ($nberr ? -$nberr : $nbcreated);
7047}
7048
7049
7057function dolChmod($filepath, $newmask = '')
7058{
7059 global $conf;
7060
7061 if (!empty($newmask)) {
7062 @chmod($filepath, octdec($newmask));
7063 } elseif (!empty($conf->global->MAIN_UMASK)) {
7064 @chmod($filepath, octdec($conf->global->MAIN_UMASK));
7065 }
7066}
7067
7068
7075{
7076 return '<span class="fieldrequired">*</span>';
7077}
7078
7079
7096function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = 'UTF-8', $strip_tags = 0, $removedoublespaces = 1)
7097{
7098 if (is_null($stringtoclean)) {
7099 return '';
7100 }
7101
7102 if ($removelinefeed == 2) {
7103 $stringtoclean = preg_replace('/<br[^>]*>(\n|\r)+/ims', '<br>', $stringtoclean);
7104 }
7105 $temp = preg_replace('/<br[^>]*>/i', "\n", $stringtoclean);
7106
7107 // We remove entities BEFORE stripping (in case of an open separator char that is entity encoded and not the closing other, the strip will fails)
7108 $temp = dol_html_entity_decode($temp, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7109
7110 $temp = str_replace('< ', '__ltspace__', $temp);
7111
7112 if ($strip_tags) {
7113 $temp = strip_tags($temp);
7114 } else {
7115 // Remove '<' into remainging, so remove non closing html tags like '<abc' or '<<abc'. Note: '<123abc' is not a html tag (can be kept), but '<abc123' is (must be removed).
7116 $pattern = "/<[^<>]+>/";
7117 // Example of $temp: <a href="/myurl" title="<u>A title</u>">0000-021</a>
7118 // pass 1 - $temp after pass 1: <a href="/myurl" title="A title">0000-021
7119 // pass 2 - $temp after pass 2: 0000-021
7120 $tempbis = $temp;
7121 do {
7122 $temp = $tempbis;
7123 $tempbis = str_replace('<>', '', $temp); // No reason to have this into a text, except if value is to try bypass the next html cleaning
7124 $tempbis = preg_replace($pattern, '', $tempbis);
7125 //$idowhile++; print $temp.'-'.$tempbis."\n"; if ($idowhile > 100) break;
7126 } while ($tempbis != $temp);
7127
7128 $temp = $tempbis;
7129
7130 // Remove '<' into remaining, so remove non closing html tags like '<abc' or '<<abc'. Note: '<123abc' is not a html tag (can be kept), but '<abc123' is (must be removed).
7131 $temp = preg_replace('/<+([a-z]+)/i', '\1', $temp);
7132 }
7133
7134 $temp = dol_html_entity_decode($temp, ENT_COMPAT, $pagecodeto);
7135
7136 // Remove also carriage returns
7137 if ($removelinefeed == 1) {
7138 $temp = str_replace(array("\r\n", "\r", "\n"), " ", $temp);
7139 }
7140
7141 // And double quotes
7142 if ($removedoublespaces) {
7143 while (strpos($temp, " ")) {
7144 $temp = str_replace(" ", " ", $temp);
7145 }
7146 }
7147
7148 $temp = str_replace('__ltspace__', '< ', $temp);
7149
7150 return trim($temp);
7151}
7152
7168function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1, $cleanalsojavascript = 0, $allowiframe = 0, $allowed_tags = array(), $allowlink = 0)
7169{
7170 if (empty($allowed_tags)) {
7171 $allowed_tags = array(
7172 "html", "head", "meta", "body", "article", "a", "abbr", "b", "blockquote", "br", "cite", "div", "dl", "dd", "dt", "em", "font", "img", "ins", "hr", "i", "li",
7173 "ol", "p", "q", "s", "section", "span", "strike", "strong", "title", "table", "tr", "th", "td", "u", "ul", "sup", "sub", "blockquote", "pre", "h1", "h2", "h3", "h4", "h5", "h6"
7174 );
7175 }
7176 $allowed_tags[] = "comment"; // this tags is added to manage comment <!--...--> that are replaced into <comment>...</comment>
7177 if ($allowiframe) {
7178 if (!in_array('iframe', $allowed_tags)) {
7179 $allowed_tags[] = "iframe";
7180 }
7181 }
7182 if ($allowlink) {
7183 if (!in_array('link', $allowed_tags)) {
7184 $allowed_tags[] = "link";
7185 }
7186 }
7187
7188 $allowed_tags_string = join("><", $allowed_tags);
7189 $allowed_tags_string = '<'.$allowed_tags_string.'>';
7190
7191 $stringtoclean = str_replace('<!DOCTYPE html>', '__!DOCTYPE_HTML__', $stringtoclean); // Replace DOCTYPE to avoid to have it removed by the strip_tags
7192
7193 $stringtoclean = dol_string_nounprintableascii($stringtoclean, 0);
7194
7195 //$stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
7196 $stringtoclean = preg_replace('/<!--([^>]*)-->/', '<comment>\1</comment>', $stringtoclean);
7197
7198 $stringtoclean = preg_replace('/&colon;/i', ':', $stringtoclean);
7199 $stringtoclean = preg_replace('/&#58;|&#0+58|&#x3A/i', '', $stringtoclean); // refused string ':' encoded (no reason to have a : encoded like this) to disable 'javascript:...'
7200
7201 $temp = strip_tags($stringtoclean, $allowed_tags_string); // Warning: This remove also undesired </>, so may changes string obfuscated with </> that pass the injection detection into a harmfull string
7202
7203 if ($cleanalsosomestyles) { // Clean for remaining html tags
7204 $temp = preg_replace('/position\s*:\s*(absolute|fixed)\s*!\s*important/i', '', $temp); // Note: If hacker try to introduce css comment into string to bypass this regex, the string must also be encoded by the dol_htmlentitiesbr during output so it become harmless
7205 }
7206 if ($removeclassattribute) { // Clean for remaining html tags
7207 $temp = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $temp);
7208 }
7209
7210 // Remove 'javascript:' that we should not find into a text with
7211 // Warning: This is not reliable to fight against obfuscated javascript, there is a lot of other solution to include js into a common html tag (only filtered by a GETPOST(.., powerfullfilter)).
7212 if ($cleanalsojavascript) {
7213 $temp = preg_replace('/j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*:/i', '', $temp);
7214 }
7215
7216 $temp = str_replace('__!DOCTYPE_HTML__', '<!DOCTYPE html>', $temp); // Restore the DOCTYPE
7217
7218 $temp = preg_replace('/<comment>([^>]*)<\/comment>/', '<!--\1-->', $temp); // Restore html comments
7219
7220
7221 return $temp;
7222}
7223
7224
7236function dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes = array("allow", "allowfullscreen", "alt", "class", "contenteditable", "data-html", "frameborder", "height", "href", "id", "name", "src", "style", "target", "title", "width"))
7237{
7238 if (class_exists('DOMDocument') && !empty($stringtoclean)) {
7239 $stringtoclean = '<?xml encoding="UTF-8"><html><body>'.$stringtoclean.'</body></html>';
7240
7241 $dom = new DOMDocument(null, 'UTF-8');
7242 $dom->loadHTML($stringtoclean, LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7243
7244 if (is_object($dom)) {
7245 for ($els = $dom->getElementsByTagname('*'), $i = $els->length - 1; $i >= 0; $i--) {
7246 for ($attrs = $els->item($i)->attributes, $ii = $attrs->length - 1; $ii >= 0; $ii--) {
7247 //var_dump($attrs->item($ii));
7248 if (!empty($attrs->item($ii)->name)) {
7249 if (! in_array($attrs->item($ii)->name, $allowed_attributes)) {
7250 // Delete attribute if not into allowed_attributes
7251 $els->item($i)->removeAttribute($attrs->item($ii)->name);
7252 } elseif (in_array($attrs->item($ii)->name, array('style'))) {
7253 // If attribute is 'style'
7254 $valuetoclean = $attrs->item($ii)->value;
7255
7256 if (isset($valuetoclean)) {
7257 do {
7258 $oldvaluetoclean = $valuetoclean;
7259 $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments
7260 $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean);
7261 if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags.
7262 $valuetoclean = preg_replace('/display\s*:/mi', '', $valuetoclean);
7263 $valuetoclean = preg_replace('/z-index\s*:/mi', '', $valuetoclean);
7264 $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*:/mi', '', $valuetoclean);
7265 }
7266
7267 // We do not allow logout|passwordforgotten.php and action= into the content of a "style" tag
7268 $valuetoclean = preg_replace('/(logout|passwordforgotten)\.php/mi', '', $valuetoclean);
7269 $valuetoclean = preg_replace('/action=/mi', '', $valuetoclean);
7270 } while ($oldvaluetoclean != $valuetoclean);
7271 }
7272
7273 $attrs->item($ii)->value = $valuetoclean;
7274 }
7275 }
7276 }
7277 }
7278 }
7279
7280 $return = $dom->saveHTML(); // This may add a LF at end of lines, so we will trim later
7281 //$return = '<html><body>aaaa</p>bb<p>ssdd</p>'."\n<p>aaa</p>aa<p>bb</p>";
7282
7283 $return = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $return);
7284 $return = preg_replace('/^'.preg_quote('<html><body>', '/').'/', '', $return);
7285 $return = preg_replace('/'.preg_quote('</body></html>', '/').'$/', '', $return);
7286 return trim($return);
7287 } else {
7288 return $stringtoclean;
7289 }
7290}
7291
7303function dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags = array('textarea'), $cleanalsosomestyles = 0)
7304{
7305 $temp = $stringtoclean;
7306 foreach ($disallowed_tags as $tagtoremove) {
7307 $temp = preg_replace('/<\/?'.$tagtoremove.'>/', '', $temp);
7308 $temp = preg_replace('/<\/?'.$tagtoremove.'\s+[^>]*>/', '', $temp);
7309 }
7310
7311 if ($cleanalsosomestyles) {
7312 $temp = preg_replace('/position\s*:\s*(absolute|fixed)\s*!\s*important/', '', $temp); // Note: If hacker try to introduce css comment into string to avoid this, string should be encoded by the dol_htmlentitiesbr so be harmless
7313 }
7314
7315 return $temp;
7316}
7317
7318
7328function dolGetFirstLineOfText($text, $nboflines = 1, $charset = 'UTF-8')
7329{
7330 if ($nboflines == 1) {
7331 if (dol_textishtml($text)) {
7332 $firstline = preg_replace('/<br[^>]*>.*$/s', '', $text); // The s pattern modifier means the . can match newline characters
7333 $firstline = preg_replace('/<div[^>]*>.*$/s', '', $firstline); // The s pattern modifier means the . can match newline characters
7334 } else {
7335 if (isset($text)) {
7336 $firstline = preg_replace('/[\n\r].*/', '', $text);
7337 } else {
7338 $firstline = '';
7339 }
7340 }
7341 return $firstline.(isset($firstline) && isset($text) && (strlen($firstline) != strlen($text)) ? '...' : '');
7342 } else {
7343 $ishtml = 0;
7344 if (dol_textishtml($text)) {
7345 $text = preg_replace('/\n/', '', $text);
7346 $ishtml = 1;
7347 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7348 } else {
7349 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7350 }
7351
7352 $text = strtr($text, $repTable);
7353 if ($charset == 'UTF-8') {
7354 $pattern = '/(<br[^>]*>)/Uu';
7355 } else {
7356 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7357 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7358 }
7359 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7360
7361 $firstline = '';
7362 $i = 0;
7363 $nba = count($a); // 2x nb of lines in $a because $a contains also a line for each new line separator
7364 while (($i < $nba) && ($i < ($nboflines * 2))) {
7365 if ($i % 2 == 0) {
7366 $firstline .= $a[$i];
7367 } elseif (($i < (($nboflines * 2) - 1)) && ($i < ($nba - 1))) {
7368 $firstline .= ($ishtml ? "<br>\n" : "\n");
7369 }
7370 $i++;
7371 }
7372 unset($a);
7373 return $firstline.(($i < $nba) ? '...' : '');
7374 }
7375}
7376
7377
7389function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false)
7390{
7391 if (is_null($stringtoencode)) {
7392 return '';
7393 }
7394
7395 if (!$nl2brmode) {
7396 return nl2br($stringtoencode, $forxml);
7397 } else {
7398 $ret = preg_replace('/(\r\n|\r|\n)/i', ($forxml ? '<br />' : '<br>'), $stringtoencode);
7399 return $ret;
7400 }
7401}
7402
7411function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = 'restricthtml')
7412{
7413 global $conf;
7414
7415 if (empty($nouseofiframesandbox) && !empty($conf->global->MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS)) {
7416 // TODO using sandbox on inline html content is not possible yet with current browsers
7417 //$s = '<iframe class="iframewithsandbox" sandbox><html><body>';
7418 //$s .= $stringtoencode;
7419 //$s .= '</body></html></iframe>';
7420 return $stringtoencode;
7421 } else {
7422 $out = $stringtoencode;
7423
7424 do {
7425 $oldstringtoclean = $out;
7426
7427 if (!empty($out) && !empty($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML) && $check != 'restricthtmlallowunvalid') {
7428 try {
7429 libxml_use_internal_errors(false); // Avoid to fill memory with xml errors
7430
7431 $dom = new DOMDocument;
7432 // Add a trick to solve pb with text without parent tag
7433 // like '<h1>Foo</h1><p>bar</p>' that wrongly ends up, without the trick, with '<h1>Foo<p>bar</p></h1>'
7434 // like 'abc' that wrongly ends up, without the trick, with '<p>abc</p>'
7435 $out = '<div class="tricktoremove">'.$out.'</div>';
7436 $dom->loadHTML($out, LIBXML_HTML_NODEFDTD|LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7437 $out = trim($dom->saveHTML());
7438
7439 // Remove the trick added to solve pb with text without parent tag
7440 $out = preg_replace('/^<div class="tricktoremove">/', '', $out);
7441 $out = preg_replace('/<\/div>$/', '', $out);
7442 } catch (Exception $e) {
7443 // If error, invalid HTML string with no way to clean it
7444 //print $e->getMessage();
7445 $out = 'InvalidHTMLStringCantBeCleaned';
7446 }
7447 }
7448
7449 // Clean some html entities that are useless so text is cleaner
7450 $out = preg_replace('/&(tab|newline);/i', ' ', $out);
7451
7452 // Ckeditor use the numeric entitic for apostrophe so we force it to text entity (all other special chars are
7453 // encoded using text entities) so we can then exclude all numeric entities.
7454 $out = preg_replace('/&#39;/i', '&apos;', $out);
7455
7456 // We replace chars from a/A to z/Z encoded with numeric HTML entities with the real char so we won't loose the chars at the next step (preg_replace).
7457 // No need to use a loop here, this step is not to sanitize (this is done at next step, this is to try to save chars, even if they are
7458 // using a non coventionnel way to be encoded, to not have them sanitized just after)
7459 $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) {
7460 return realCharForNumericEntities($m); }, $out);
7461
7462
7463 // Now we remove all remaining HTML entities starting with a number. We don't want such entities.
7464 $out = preg_replace('/&#x?[0-9]+/i', '', $out); // For example if we have j&#x61vascript with an entities without the ; to hide the 'a' of 'javascript'.
7465
7466 // Keep only some html tags and remove also some 'javascript:' strings
7467 $out = dol_string_onlythesehtmltags($out, 0, ($check == 'restricthtmlallowclass' ? 0 : 1), 1);
7468
7469 // Keep only some html attributes and exclude non expected HTML attributes and clean content of some attributes (keep only alt=, title=...).
7470 if (!empty($conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES)) {
7472 }
7473
7474 // Restore entity &apos; into &#39; (restricthtml is for html content so we can use html entity)
7475 $out = preg_replace('/&apos;/i', "&#39;", $out);
7476 } while ($oldstringtoclean != $out);
7477
7478 // Check the limit of external links that are automatically executed in a Rich text content. We count:
7479 // '<img' to avoid <img src="http...">
7480 // 'url(' to avoid inline style like background: url(http...
7481 // '<link' to avoid <link href="http...">
7482 $reg = array();
7483 preg_match_all('/(<img|url\‍(|<link)/i', $out, $reg);
7484 $nbextlink = count($reg[0]);
7485 if ($nbextlink > getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) {
7486 $out = 'TooManyLinksIntoHTMLString';
7487 }
7488 //
7489 if (!empty($conf->global->MAIN_DISALLOW_EXT_URL_INTO_DESCRIPTIONS) || $check == 'restricthtmlnolink') {
7490 if ($nbextlink > 0) {
7491 $out = 'ExternalLinksNotAllowed';
7492 }
7493 }
7494
7495 return $out;
7496 }
7497}
7498
7520function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UTF-8', $removelasteolbr = 1)
7521{
7522 if (is_null($stringtoencode)) {
7523 return '';
7524 }
7525
7526 $newstring = $stringtoencode;
7527 if (dol_textishtml($stringtoencode)) { // Check if text is already HTML or not
7528 $newstring = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', '<br>', $newstring); // Replace "<br type="_moz" />" by "<br>". It's same and avoid pb with FPDF.
7529 if ($removelasteolbr) {
7530 $newstring = preg_replace('/<br>$/i', '', $newstring); // Remove last <br> (remove only last one)
7531 }
7532 $newstring = strtr($newstring, array('&'=>'__and__', '<'=>'__lt__', '>'=>'__gt__', '"'=>'__dquot__'));
7533 $newstring = dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom); // Make entity encoding
7534 $newstring = strtr($newstring, array('__and__'=>'&', '__lt__'=>'<', '__gt__'=>'>', '__dquot__'=>'"'));
7535 } else {
7536 if ($removelasteolbr) {
7537 $newstring = preg_replace('/(\r\n|\r|\n)$/i', '', $newstring); // Remove last \n (may remove several)
7538 }
7539 $newstring = dol_nl2br(dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom), $nl2brmode);
7540 }
7541 // Other substitutions that htmlentities does not do
7542 //$newstring=str_replace(chr(128),'&euro;',$newstring); // 128 = 0x80. Not in html entity table. // Seems useles with TCPDF. Make bug with UTF8 languages
7543 return $newstring;
7544}
7545
7553function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8')
7554{
7555 $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7556 $ret = preg_replace('/'."\r\n".'<br(\s[\sa-zA-Z_="]*)?\/?>/i', "<br>", $ret);
7557 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\r\n".'/i', "\r\n", $ret);
7558 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\n".'/i', "\n", $ret);
7559 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', "\n", $ret);
7560 return $ret;
7561}
7562
7569function dol_htmlcleanlastbr($stringtodecode)
7570{
7571 $ret = preg_replace('/&nbsp;$/i', "", $stringtodecode); // Because wysiwyg editor may add a &nbsp; at end of last line
7572 $ret = preg_replace('/(<br>|<br(\s[\sa-zA-Z_="]*)?\/?>|'."\n".'|'."\r".')+$/i', "", $ret);
7573 return $ret;
7574}
7575
7585function dol_html_entity_decode($a, $b, $c = 'UTF-8', $keepsomeentities = 0)
7586{
7587 $newstring = $a;
7588 if ($keepsomeentities) {
7589 $newstring = strtr($newstring, array('&amp;'=>'__andamp__', '&lt;'=>'__andlt__', '&gt;'=>'__andgt__', '"'=>'__dquot__'));
7590 }
7591 $newstring = html_entity_decode((string) $newstring, (int) $b, (string) $c);
7592 if ($keepsomeentities) {
7593 $newstring = strtr($newstring, array('__andamp__'=>'&amp;', '__andlt__'=>'&lt;', '__andgt__'=>'&gt;', '__dquot__'=>'"'));
7594 }
7595 return $newstring;
7596}
7597
7608function dol_htmlentities($string, $flags = ENT_QUOTES|ENT_SUBSTITUTE, $encoding = 'UTF-8', $double_encode = false)
7609{
7610 return htmlentities($string, $flags, $encoding, $double_encode);
7611}
7612
7624function dol_string_is_good_iso($s, $clean = 0)
7625{
7626 $len = dol_strlen($s);
7627 $out = '';
7628 $ok = 1;
7629 for ($scursor = 0; $scursor < $len; $scursor++) {
7630 $ordchar = ord($s[$scursor]);
7631 //print $scursor.'-'.$ordchar.'<br>';
7632 if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) {
7633 $ok = 0;
7634 break;
7635 } elseif ($ordchar > 126 && $ordchar < 160) {
7636 $ok = 0;
7637 break;
7638 } elseif ($clean) {
7639 $out .= $s[$scursor];
7640 }
7641 }
7642 if ($clean) {
7643 return $out;
7644 }
7645 return $ok;
7646}
7647
7656function dol_nboflines($s, $maxchar = 0)
7657{
7658 if ($s == '') {
7659 return 0;
7660 }
7661 $arraystring = explode("\n", $s);
7662 $nb = count($arraystring);
7663
7664 return $nb;
7665}
7666
7667
7677function dol_nboflines_bis($text, $maxlinesize = 0, $charset = 'UTF-8')
7678{
7679 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7680 if (dol_textishtml($text)) {
7681 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7682 }
7683
7684 $text = strtr($text, $repTable);
7685 if ($charset == 'UTF-8') {
7686 $pattern = '/(<br[^>]*>)/Uu';
7687 } else {
7688 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7689 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7690 }
7691 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7692
7693 $nblines = (int) floor((count($a) + 1) / 2);
7694 // count possible auto line breaks
7695 if ($maxlinesize) {
7696 foreach ($a as $line) {
7697 if (dol_strlen($line) > $maxlinesize) {
7698 //$line_dec = html_entity_decode(strip_tags($line));
7699 $line_dec = html_entity_decode($line);
7700 if (dol_strlen($line_dec) > $maxlinesize) {
7701 $line_dec = wordwrap($line_dec, $maxlinesize, '\n', true);
7702 $nblines += substr_count($line_dec, '\n');
7703 }
7704 }
7705 }
7706 }
7707
7708 unset($a);
7709 return $nblines;
7710}
7711
7720function dol_textishtml($msg, $option = 0)
7721{
7722 if (is_null($msg)) {
7723 return false;
7724 }
7725
7726 if ($option == 1) {
7727 if (preg_match('/<html/i', $msg)) {
7728 return true;
7729 } elseif (preg_match('/<body/i', $msg)) {
7730 return true;
7731 } elseif (preg_match('/<\/textarea/i', $msg)) {
7732 return true;
7733 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
7734 return true;
7735 } elseif (preg_match('/<br/i', $msg)) {
7736 return true;
7737 }
7738 return false;
7739 } else {
7740 // Remove all urls because 'http://aa?param1=abc&amp;param2=def' must not be used inside detection
7741 $msg = preg_replace('/https?:\/\/[^"\'\s]+/i', '', $msg);
7742 if (preg_match('/<html/i', $msg)) {
7743 return true;
7744 } elseif (preg_match('/<body/i', $msg)) {
7745 return true;
7746 } elseif (preg_match('/<\/textarea/i', $msg)) {
7747 return true;
7748 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
7749 return true;
7750 } elseif (preg_match('/<(br|hr)\/>/i', $msg)) {
7751 return true;
7752 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)>/i', $msg)) {
7753 return true;
7754 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)\s+[^<>\/]*\/?>/i', $msg)) {
7755 return true;
7756 } elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i', $msg)) {
7757 return true; // must accept <img src="http://example.com/aaa.png" />
7758 } elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i', $msg)) {
7759 return true; // must accept <a href="http://example.com/aaa.png" />
7760 } elseif (preg_match('/<h[0-9]>/i', $msg)) {
7761 return true;
7762 } elseif (preg_match('/&[A-Z0-9]{1,6};/i', $msg)) {
7763 // TODO If content is 'A link https://aaa?param=abc&amp;param2=def', it return true but must be false
7764 return true; // Html entities names (http://www.w3schools.com/tags/ref_entities.asp)
7765 } elseif (preg_match('/&#[0-9]{2,3};/i', $msg)) {
7766 return true; // Html entities numbers (http://www.w3schools.com/tags/ref_entities.asp)
7767 }
7768
7769 return false;
7770 }
7771}
7772
7787function dol_concatdesc($text1, $text2, $forxml = false, $invert = false)
7788{
7789 if (!empty($invert)) {
7790 $tmp = $text1;
7791 $text1 = $text2;
7792 $text2 = $tmp;
7793 }
7794
7795 $ret = '';
7796 $ret .= (!dol_textishtml($text1) && dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text1, 0, 1, '', 1), 0, $forxml) : $text1;
7797 $ret .= (!empty($text1) && !empty($text2)) ? ((dol_textishtml($text1) || dol_textishtml($text2)) ? ($forxml ? "<br >\n" : "<br>\n") : "\n") : "";
7798 $ret .= (dol_textishtml($text1) && !dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text2, 0, 1, '', 1), 0, $forxml) : $text2;
7799 return $ret;
7800}
7801
7802
7803
7815function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null)
7816{
7817 global $db, $conf, $mysoc, $user, $extrafields;
7818
7819 $substitutionarray = array();
7820
7821 if ((empty($exclude) || !in_array('user', $exclude)) && (empty($include) || in_array('user', $include))) {
7822 // Add SIGNATURE into substitutionarray first, so, when we will make the substitution,
7823 // this will include signature content first and then replace var found into content of signature
7824 //var_dump($onlykey);
7825 $emailsendersignature = $user->signature; // dy default, we use the signature of current user. We must complete substitution with signature in c_email_senderprofile of array after calling getCommonSubstitutionArray()
7826 $usersignature = $user->signature;
7827 $substitutionarray = array_merge($substitutionarray, array(
7828 '__SENDEREMAIL_SIGNATURE__' => (string) ((empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN)) ? ($onlykey == 2 ? dol_trunc('SignatureFromTheSelectedSenderProfile', 30) : $emailsendersignature) : ''),
7829 '__USER_SIGNATURE__' => (string) (($usersignature && empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN)) ? ($onlykey == 2 ? dol_trunc(dol_string_nohtmltag($usersignature), 30) : $usersignature) : '')
7830 ));
7831
7832 if (is_object($user)) {
7833 $substitutionarray = array_merge($substitutionarray, array(
7834 '__USER_ID__' => (string) $user->id,
7835 '__USER_LOGIN__' => (string) $user->login,
7836 '__USER_EMAIL__' => (string) $user->email,
7837 '__USER_PHONE__' => (string) dol_print_phone($user->office_phone, '', 0, 0, '', " ", '', '', -1),
7838 '__USER_PHONEPRO__' => (string) dol_print_phone($user->user_mobile, '', 0, 0, '', " ", '', '', -1),
7839 '__USER_PHONEMOBILE__' => (string) dol_print_phone($user->personal_mobile, '', 0, 0, '', " ", '', '', -1),
7840 '__USER_FAX__' => (string) $user->office_fax,
7841 '__USER_LASTNAME__' => (string) $user->lastname,
7842 '__USER_FIRSTNAME__' => (string) $user->firstname,
7843 '__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
7844 '__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
7845 '__USER_JOB__' => (string) $user->job,
7846 '__USER_REMOTE_IP__' => (string) getUserRemoteIP(),
7847 '__USER_VCARD_URL__' => (string) $user->getOnlineVirtualCardUrl('', 'external')
7848 ));
7849 }
7850 }
7851 if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc) && (empty($include) || in_array('mycompany', $include))) {
7852 $substitutionarray = array_merge($substitutionarray, array(
7853 '__MYCOMPANY_NAME__' => $mysoc->name,
7854 '__MYCOMPANY_EMAIL__' => $mysoc->email,
7855 '__MYCOMPANY_PHONE__' => dol_print_phone($mysoc->phone, '', 0, 0, '', " ", '', '', -1),
7856 '__MYCOMPANY_FAX__' => dol_print_phone($mysoc->fax, '', 0, 0, '', " ", '', '', -1),
7857 '__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
7858 '__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
7859 '__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
7860 '__MYCOMPANY_PROFID4__' => $mysoc->idprof4,
7861 '__MYCOMPANY_PROFID5__' => $mysoc->idprof5,
7862 '__MYCOMPANY_PROFID6__' => $mysoc->idprof6,
7863 '__MYCOMPANY_CAPITAL__' => $mysoc->capital,
7864 '__MYCOMPANY_FULLADDRESS__' => (method_exists($mysoc, 'getFullAddress') ? $mysoc->getFullAddress(1, ', ') : ''), // $mysoc may be stdClass
7865 '__MYCOMPANY_ADDRESS__' => $mysoc->address,
7866 '__MYCOMPANY_ZIP__' => $mysoc->zip,
7867 '__MYCOMPANY_TOWN__' => $mysoc->town,
7868 '__MYCOMPANY_COUNTRY__' => $mysoc->country,
7869 '__MYCOMPANY_COUNTRY_ID__' => $mysoc->country_id,
7870 '__MYCOMPANY_COUNTRY_CODE__' => $mysoc->country_code,
7871 '__MYCOMPANY_CURRENCY_CODE__' => $conf->currency
7872 ));
7873 }
7874
7875 if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude)) && (empty($include) || in_array('object', $include))) {
7876 if ($onlykey) {
7877 $substitutionarray['__ID__'] = '__ID__';
7878 $substitutionarray['__REF__'] = '__REF__';
7879 $substitutionarray['__NEWREF__'] = '__NEWREF__';
7880 $substitutionarray['__LABEL__'] = '__LABEL__';
7881 $substitutionarray['__REF_CLIENT__'] = '__REF_CLIENT__';
7882 $substitutionarray['__REF_SUPPLIER__'] = '__REF_SUPPLIER__';
7883 $substitutionarray['__NOTE_PUBLIC__'] = '__NOTE_PUBLIC__';
7884 $substitutionarray['__NOTE_PRIVATE__'] = '__NOTE_PRIVATE__';
7885 $substitutionarray['__EXTRAFIELD_XXX__'] = '__EXTRAFIELD_XXX__';
7886
7887 if (isModEnabled("societe")) { // Most objects are concerned
7888 $substitutionarray['__THIRDPARTY_ID__'] = '__THIRDPARTY_ID__';
7889 $substitutionarray['__THIRDPARTY_NAME__'] = '__THIRDPARTY_NAME__';
7890 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = '__THIRDPARTY_NAME_ALIAS__';
7891 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = '__THIRDPARTY_CODE_CLIENT__';
7892 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = '__THIRDPARTY_CODE_FOURNISSEUR__';
7893 $substitutionarray['__THIRDPARTY_EMAIL__'] = '__THIRDPARTY_EMAIL__';
7894 $substitutionarray['__THIRDPARTY_PHONE__'] = '__THIRDPARTY_PHONE__';
7895 $substitutionarray['__THIRDPARTY_FAX__'] = '__THIRDPARTY_FAX__';
7896 $substitutionarray['__THIRDPARTY_ADDRESS__'] = '__THIRDPARTY_ADDRESS__';
7897 $substitutionarray['__THIRDPARTY_ZIP__'] = '__THIRDPARTY_ZIP__';
7898 $substitutionarray['__THIRDPARTY_TOWN__'] = '__THIRDPARTY_TOWN__';
7899 $substitutionarray['__THIRDPARTY_IDPROF1__'] = '__THIRDPARTY_IDPROF1__';
7900 $substitutionarray['__THIRDPARTY_IDPROF2__'] = '__THIRDPARTY_IDPROF2__';
7901 $substitutionarray['__THIRDPARTY_IDPROF3__'] = '__THIRDPARTY_IDPROF3__';
7902 $substitutionarray['__THIRDPARTY_IDPROF4__'] = '__THIRDPARTY_IDPROF4__';
7903 $substitutionarray['__THIRDPARTY_IDPROF5__'] = '__THIRDPARTY_IDPROF5__';
7904 $substitutionarray['__THIRDPARTY_IDPROF6__'] = '__THIRDPARTY_IDPROF6__';
7905 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = '__THIRDPARTY_TVAINTRA__';
7906 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = '__THIRDPARTY_NOTE_PUBLIC__';
7907 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = '__THIRDPARTY_NOTE_PRIVATE__';
7908 }
7909 if (isModEnabled('adherent') && (!is_object($object) || $object->element == 'adherent') && (empty($exclude) || !in_array('member', $exclude)) && (empty($include) || in_array('member', $include))) {
7910 $substitutionarray['__MEMBER_ID__'] = '__MEMBER_ID__';
7911 $substitutionarray['__MEMBER_CIVILITY__'] = '__MEMBER_CIVILITY__';
7912 $substitutionarray['__MEMBER_FIRSTNAME__'] = '__MEMBER_FIRSTNAME__';
7913 $substitutionarray['__MEMBER_LASTNAME__'] = '__MEMBER_LASTNAME__';
7914 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = 'Login and pass of the external user account';
7915 /*$substitutionarray['__MEMBER_NOTE_PUBLIC__'] = '__MEMBER_NOTE_PUBLIC__';
7916 $substitutionarray['__MEMBER_NOTE_PRIVATE__'] = '__MEMBER_NOTE_PRIVATE__';*/
7917 }
7918 // add variables subtitutions ticket
7919 if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket') && (empty($exclude) || !in_array('ticket', $exclude)) && (empty($include) || in_array('ticket', $include))) {
7920 $substitutionarray['__TICKET_TRACKID__'] = '__TICKET_TRACKID__';
7921 $substitutionarray['__TICKET_SUBJECT__'] = '__TICKET_SUBJECT__';
7922 $substitutionarray['__TICKET_TYPE__'] = '__TICKET_TYPE__';
7923 $substitutionarray['__TICKET_SEVERITY__'] = '__TICKET_SEVERITY__';
7924 $substitutionarray['__TICKET_CATEGORY__'] = '__TICKET_CATEGORY__';
7925 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = '__TICKET_ANALYTIC_CODE__';
7926 $substitutionarray['__TICKET_MESSAGE__'] = '__TICKET_MESSAGE__';
7927 $substitutionarray['__TICKET_PROGRESSION__'] = '__TICKET_PROGRESSION__';
7928 $substitutionarray['__TICKET_USER_ASSIGN__'] = '__TICKET_USER_ASSIGN__';
7929 }
7930
7931 if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature') && (empty($exclude) || !in_array('recruitment', $exclude)) && (empty($include) || in_array('recruitment', $include))) {
7932 $substitutionarray['__CANDIDATE_FULLNAME__'] = '__CANDIDATE_FULLNAME__';
7933 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = '__CANDIDATE_FIRSTNAME__';
7934 $substitutionarray['__CANDIDATE_LASTNAME__'] = '__CANDIDATE_LASTNAME__';
7935 }
7936 if (isModEnabled('project') && (empty($exclude) || !in_array('project', $exclude)) && (empty($include) || in_array('project', $include))) { // Most objects
7937 $substitutionarray['__PROJECT_ID__'] = '__PROJECT_ID__';
7938 $substitutionarray['__PROJECT_REF__'] = '__PROJECT_REF__';
7939 $substitutionarray['__PROJECT_NAME__'] = '__PROJECT_NAME__';
7940 /*$substitutionarray['__PROJECT_NOTE_PUBLIC__'] = '__PROJECT_NOTE_PUBLIC__';
7941 $substitutionarray['__PROJECT_NOTE_PRIVATE__'] = '__PROJECT_NOTE_PRIVATE__';*/
7942 }
7943 if (isModEnabled('contrat') && (!is_object($object) || $object->element == 'contract') && (empty($exclude) || !in_array('contract', $exclude)) && (empty($include) || in_array('contract', $include))) {
7944 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = 'Highest date planned for a service start';
7945 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = 'Highest date and hour planned for service start';
7946 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = 'Lowest data for planned expiration of service';
7947 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = 'Lowest date and hour for planned expiration of service';
7948 }
7949 if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal') && (empty($exclude) || !in_array('propal', $exclude)) && (empty($include) || in_array('propal', $include))) {
7950 $substitutionarray['__ONLINE_SIGN_URL__'] = 'ToOfferALinkForOnlineSignature';
7951 }
7952 if (isModEnabled("ficheinter") && (!is_object($object) || $object->element == 'fichinter') && (empty($exclude) || !in_array('intervention', $exclude)) && (empty($include) || in_array('intervention', $include))) {
7953 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = 'ToOfferALinkForOnlineSignature';
7954 }
7955 $substitutionarray['__ONLINE_PAYMENT_URL__'] = 'UrlToPayOnlineIfApplicable';
7956 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = 'TextAndUrlToPayOnlineIfApplicable';
7957 $substitutionarray['__SECUREKEYPAYMENT__'] = 'Security key (if key is not unique per record)';
7958 $substitutionarray['__SECUREKEYPAYMENT_MEMBER__'] = 'Security key for payment on a member subscription (one key per member)';
7959 $substitutionarray['__SECUREKEYPAYMENT_ORDER__'] = 'Security key for payment on an order';
7960 $substitutionarray['__SECUREKEYPAYMENT_INVOICE__'] = 'Security key for payment on an invoice';
7961 $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'Security key for payment on a service of a contract';
7962
7963 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = 'Direct download url of a proposal';
7964 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = 'Direct download url of an order';
7965 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = 'Direct download url of an invoice';
7966 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = 'Direct download url of a contract';
7967 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = 'Direct download url of a supplier proposal';
7968
7969 if (isModEnabled("expedition") && (!is_object($object) || $object->element == 'shipping')) {
7970 $substitutionarray['__SHIPPINGTRACKNUM__'] = 'Shipping tracking number';
7971 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = 'Shipping tracking url';
7972 }
7973 if (isModEnabled("reception") && (!is_object($object) || $object->element == 'reception')) {
7974 $substitutionarray['__RECEPTIONTRACKNUM__'] = 'Shippin tracking number of shipment';
7975 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = 'Shipping tracking url';
7976 }
7977 } else {
7978 $substitutionarray['__ID__'] = $object->id;
7979 $substitutionarray['__REF__'] = $object->ref;
7980 $substitutionarray['__NEWREF__'] = $object->newref;
7981 $substitutionarray['__LABEL__'] = (isset($object->label) ? $object->label : (isset($object->title) ? $object->title : null));
7982 $substitutionarray['__REF_CLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
7983 $substitutionarray['__REF_SUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
7984 $substitutionarray['__NOTE_PUBLIC__'] = (isset($object->note_public) ? $object->note_public : null);
7985 $substitutionarray['__NOTE_PRIVATE__'] = (isset($object->note_private) ? $object->note_private : null);
7986 if ($object->element == "shipping") {
7987 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, 'day', 0, $outputlangs) : '');
7988 } else {
7989 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, 'day', 0, $outputlangs) : '');
7990 }
7991 $substitutionarray['__DATE_DELIVERY_DAY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%d") : '');
7992 $substitutionarray['__DATE_DELIVERY_DAY_TEXT__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%A") : '');
7993 $substitutionarray['__DATE_DELIVERY_MON__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%m") : '');
7994 $substitutionarray['__DATE_DELIVERY_MON_TEXT__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%b") : '');
7995 $substitutionarray['__DATE_DELIVERY_YEAR__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%Y") : '');
7996 $substitutionarray['__DATE_DELIVERY_HH__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%H") : '');
7997 $substitutionarray['__DATE_DELIVERY_MM__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%M") : '');
7998 $substitutionarray['__DATE_DELIVERY_SS__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%S") : '');
7999
8000 // For backward compatibility (deprecated)
8001 $substitutionarray['__REFCLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8002 $substitutionarray['__REFSUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8003 $substitutionarray['__SUPPLIER_ORDER_DATE_DELIVERY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, 'day', 0, $outputlangs) : '');
8004 $substitutionarray['__SUPPLIER_ORDER_DELAY_DELIVERY__'] = (isset($object->availability_code) ? ($outputlangs->transnoentities("AvailabilityType".$object->availability_code) != ('AvailabilityType'.$object->availability_code) ? $outputlangs->transnoentities("AvailabilityType".$object->availability_code) : $outputlangs->convToOutputCharset(isset($object->availability) ? $object->availability : '')) : '');
8005
8006 if (is_object($object) && ($object->element == 'adherent' || $object->element == 'member') && $object->id > 0) {
8007 $birthday = (empty($object->birth) ? '' : dol_print_date($object->birth, 'day'));
8008
8009 $substitutionarray['__MEMBER_ID__'] = (isset($object->id) ? $object->id : '');
8010 if (method_exists($object, 'getCivilityLabel')) {
8011 $substitutionarray['__MEMBER_CIVILITY__'] = $object->getCivilityLabel();
8012 }
8013 $substitutionarray['__MEMBER_FIRSTNAME__'] = (isset($object->firstname) ? $object->firstname : '');
8014 $substitutionarray['__MEMBER_LASTNAME__'] = (isset($object->lastname) ? $object->lastname : '');
8015 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = '';
8016 if (method_exists($object, 'getFullName')) {
8017 $substitutionarray['__MEMBER_FULLNAME__'] = $object->getFullName($outputlangs);
8018 }
8019 $substitutionarray['__MEMBER_COMPANY__'] = (isset($object->societe) ? $object->societe : '');
8020 $substitutionarray['__MEMBER_ADDRESS__'] = (isset($object->address) ? $object->address : '');
8021 $substitutionarray['__MEMBER_ZIP__'] = (isset($object->zip) ? $object->zip : '');
8022 $substitutionarray['__MEMBER_TOWN__'] = (isset($object->town) ? $object->town : '');
8023 $substitutionarray['__MEMBER_COUNTRY__'] = (isset($object->country) ? $object->country : '');
8024 $substitutionarray['__MEMBER_EMAIL__'] = (isset($object->email) ? $object->email : '');
8025 $substitutionarray['__MEMBER_BIRTH__'] = (isset($birthday) ? $birthday : '');
8026 $substitutionarray['__MEMBER_PHOTO__'] = (isset($object->photo) ? $object->photo : '');
8027 $substitutionarray['__MEMBER_LOGIN__'] = (isset($object->login) ? $object->login : '');
8028 $substitutionarray['__MEMBER_PASSWORD__'] = (isset($object->pass) ? $object->pass : '');
8029 $substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? dol_print_phone($object->phone) : '');
8030 $substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? dol_print_phone($object->phone_perso) : '');
8031 $substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? dol_print_phone($object->phone_mobile) : '');
8032 $substitutionarray['__MEMBER_TYPE__'] = (isset($object->type) ? $object->type : '');
8033 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__'] = dol_print_date($object->first_subscription_date, 'day');
8034 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = (isset($object->first_subscription_date_start) ? dol_print_date($object->first_subscription_date_start, 'day') : '');
8035 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END__'] = (isset($object->first_subscription_date_end) ? dol_print_date($object->first_subscription_date_end, 'day') : '');
8036 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE__'] = dol_print_date($object->last_subscription_date, 'day');
8037 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->last_subscription_date_start, 'day');
8038 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END__'] = dol_print_date($object->last_subscription_date_end, 'day');
8039 }
8040
8041 if (is_object($object) && $object->element == 'societe') {
8042 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object) ? $object->id : '');
8043 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object) ? $object->name : '');
8044 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object) ? $object->name_alias : '');
8045 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object) ? $object->code_client : '');
8046 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object) ? $object->code_fournisseur : '');
8047 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object) ? $object->email : '');
8048 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? dol_print_phone($object->phone) : '');
8049 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? dol_print_phone($object->fax) : '');
8050 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object) ? $object->address : '');
8051 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object) ? $object->zip : '');
8052 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object) ? $object->town : '');
8053 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object) ? $object->country_id : '');
8054 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object) ? $object->country_code : '');
8055 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object) ? $object->idprof1 : '');
8056 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object) ? $object->idprof2 : '');
8057 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object) ? $object->idprof3 : '');
8058 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object) ? $object->idprof4 : '');
8059 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object) ? $object->idprof5 : '');
8060 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object) ? $object->idprof6 : '');
8061 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object) ? $object->tva_intra : '');
8062 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_public) : '');
8063 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_private) : '');
8064 } elseif (is_object($object->thirdparty)) {
8065 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->id : '');
8066 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object->thirdparty) ? $object->thirdparty->name : '');
8067 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object->thirdparty) ? $object->thirdparty->name_alias : '');
8068 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_client : '');
8069 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_fournisseur : '');
8070 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object->thirdparty) ? $object->thirdparty->email : '');
8071 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->phone) : '');
8072 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->fax) : '');
8073 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object->thirdparty) ? $object->thirdparty->address : '');
8074 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object->thirdparty) ? $object->thirdparty->zip : '');
8075 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object->thirdparty) ? $object->thirdparty->town : '');
8076 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_id : '');
8077 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_code : '');
8078 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof1 : '');
8079 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof2 : '');
8080 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof3 : '');
8081 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof4 : '');
8082 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof5 : '');
8083 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof6 : '');
8084 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object->thirdparty) ? $object->thirdparty->tva_intra : '');
8085 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_public) : '');
8086 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_private) : '');
8087 }
8088
8089 if (is_object($object) && $object->element == 'recruitmentcandidature') {
8090 $substitutionarray['__CANDIDATE_FULLNAME__'] = $object->getFullName($outputlangs);
8091 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8092 $substitutionarray['__CANDIDATE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8093 }
8094 if (is_object($object) && $object->element == 'conferenceorboothattendee') {
8095 $substitutionarray['__ATTENDEE_FULLNAME__'] = $object->getFullName($outputlangs);
8096 $substitutionarray['__ATTENDEE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8097 $substitutionarray['__ATTENDEE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8098 }
8099
8100 $project = null;
8101 if (is_object($object->project)) {
8102 $project = $object->project;
8103 } elseif (is_object($object->projet)) { // Deprecated, for backward compatibility
8104 $project = $object->projet;
8105 }
8106 if ($project) {
8107 $substitutionarray['__PROJECT_ID__'] = $project->id;
8108 $substitutionarray['__PROJECT_REF__'] = $project->ref;
8109 $substitutionarray['__PROJECT_NAME__'] = $project->title;
8110 }
8111 if (is_object($object) && $object->element == 'project') {
8112 $substitutionarray['__PROJECT_NAME__'] = $object->title;
8113 }
8114
8115 if (is_object($object) && $object->element == 'shipping') {
8116 $substitutionarray['__SHIPPINGTRACKNUM__'] = $object->tracking_number;
8117 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = $object->tracking_url;
8118 }
8119 if (is_object($object) && $object->element == 'reception') {
8120 $substitutionarray['__RECEPTIONTRACKNUM__'] = $object->tracking_number;
8121 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = $object->tracking_url;
8122 }
8123
8124 if (is_object($object) && $object->element == 'contrat' && $object->id > 0 && is_array($object->lines)) {
8125 $dateplannedstart = '';
8126 $datenextexpiration = '';
8127 foreach ($object->lines as $line) {
8128 if ($line->date_start > $dateplannedstart) {
8129 $dateplannedstart = $line->date_start;
8130 }
8131 if ($line->statut == 4 && $line->date_end && (!$datenextexpiration || $line->date_end < $datenextexpiration)) {
8132 $datenextexpiration = $line->date_end;
8133 }
8134 }
8135 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = dol_print_date($dateplannedstart, 'day');
8136 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = dol_print_date($dateplannedstart, 'standard');
8137 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = dol_print_date($datenextexpiration, 'day');
8138 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = dol_print_date($datenextexpiration, 'standard');
8139 }
8140 // add substition variable for ticket
8141 if (is_object($object) && $object->element == 'ticket') {
8142 $substitutionarray['__TICKET_TRACKID__'] = $object->track_id;
8143 $substitutionarray['__REF__'] = $object->ref;
8144 $substitutionarray['__TICKET_SUBJECT__'] = $object->subject;
8145 $substitutionarray['__TICKET_TYPE__'] = $object->type_code;
8146 $substitutionarray['__TICKET_SEVERITY__'] = $object->severity_code;
8147 $substitutionarray['__TICKET_CATEGORY__'] = $object->category_code; // For backward compatibility
8148 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = $object->category_code;
8149 $substitutionarray['__TICKET_MESSAGE__'] = $object->message;
8150 $substitutionarray['__TICKET_PROGRESSION__'] = $object->progress;
8151 $userstat = new User($db);
8152 if ($object->fk_user_assign > 0) {
8153 $userstat->fetch($object->fk_user_assign);
8154 $substitutionarray['__TICKET_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8155 }
8156
8157 if ($object->fk_user_create > 0) {
8158 $userstat->fetch($object->fk_user_create);
8159 $substitutionarray['__USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8160 }
8161 }
8162
8163 // Create dynamic tags for __EXTRAFIELD_FIELD__
8164 if ($object->table_element && $object->id > 0) {
8165 if (!is_object($extrafields)) {
8166 $extrafields = new ExtraFields($db);
8167 }
8168 $extrafields->fetch_name_optionals_label($object->table_element, true);
8169
8170 if ($object->fetch_optionals() > 0) {
8171 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) {
8172 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
8173 if ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
8174 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_date($object->array_options['options_'.$key], 'day');
8175 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = dol_print_date($object->array_options['options_'.$key], 'day', 'tzserver', $outputlangs);
8176 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = dol_print_date($object->array_options['options_'.$key], 'dayrfc');
8177 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'datetime') {
8178 $datetime = $object->array_options['options_'.$key];
8179 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour') : '');
8180 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : '');
8181 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_DAY_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'day', 'tzserver', $outputlangs) : '');
8182 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : '');
8183 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'phone') {
8184 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_phone($object->array_options['options_'.$key]);
8185 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
8186 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = $object->array_options['options_'.$key];
8187 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATED__'] = price($object->array_options['options_'.$key]);
8188 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] != 'separator') {
8189 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = !empty($object->array_options['options_'.$key]) ? $object->array_options['options_'.$key] :'';
8190 }
8191 }
8192 }
8193 }
8194 }
8195
8196 // Complete substitution array with the url to make online payment
8197 $paymenturl = '';
8198 if (empty($substitutionarray['__REF__'])) {
8199 $paymenturl = '';
8200 } else {
8201 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
8202 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
8203 $outputlangs->loadLangs(array('paypal', 'other'));
8204
8205 $amounttouse = 0;
8206 $typeforonlinepayment = 'free';
8207 if (is_object($object) && $object->element == 'commande') {
8208 $typeforonlinepayment = 'order';
8209 }
8210 if (is_object($object) && $object->element == 'facture') {
8211 $typeforonlinepayment = 'invoice';
8212 }
8213 if (is_object($object) && $object->element == 'member') {
8214 $typeforonlinepayment = 'member';
8215 if (!empty($object->last_subscription_amount)) {
8216 $amounttouse = $object->last_subscription_amount;
8217 }
8218 }
8219 if (is_object($object) && $object->element == 'contrat') {
8220 $typeforonlinepayment = 'contract';
8221 }
8222 if (is_object($object) && $object->element == 'fichinter') {
8223 $typeforonlinepayment = 'ficheinter';
8224 }
8225
8226 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__'], $amounttouse);
8227 $paymenturl = $url;
8228 }
8229
8230 if ($object->id > 0) {
8231 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ?str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : '');
8232 $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl;
8233
8234 if (!empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'propal') {
8235 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8236 } else {
8237 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = '';
8238 }
8239 if (!empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'commande') {
8240 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = $object->getLastMainDocLink($object->element);
8241 } else {
8242 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = '';
8243 }
8244 if (!empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'facture') {
8245 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = $object->getLastMainDocLink($object->element);
8246 } else {
8247 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = '';
8248 }
8249 if (!empty($conf->global->CONTRACT_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'contrat') {
8250 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = $object->getLastMainDocLink($object->element);
8251 } else {
8252 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = '';
8253 }
8254 if (!empty($conf->global->FICHINTER_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'fichinter') {
8255 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = $object->getLastMainDocLink($object->element);
8256 } else {
8257 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = '';
8258 }
8259 if (!empty($conf->global->SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'supplier_proposal') {
8260 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8261 } else {
8262 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = '';
8263 }
8264
8265 if (is_object($object) && $object->element == 'propal') {
8266 $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id;
8267 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8268 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref);
8269 }
8270 if (is_object($object) && $object->element == 'commande') {
8271 $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id;
8272 }
8273 if (is_object($object) && $object->element == 'facture') {
8274 $substitutionarray['__URL_INVOICE__'] = DOL_MAIN_URL_ROOT."/compta/facture/card.php?id=".$object->id;
8275 }
8276 if (is_object($object) && $object->element == 'contrat') {
8277 $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id;
8278 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8279 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref);
8280 }
8281 if (is_object($object) && $object->element == 'fichinter') {
8282 $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id;
8283 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8284 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref);
8285 }
8286 if (is_object($object) && $object->element == 'supplier_proposal') {
8287 $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id;
8288 }
8289 if (is_object($object) && $object->element == 'shipping') {
8290 $substitutionarray['__URL_SHIPMENT__'] = DOL_MAIN_URL_ROOT."/expedition/card.php?id=".$object->id;
8291 }
8292 }
8293
8294 if (is_object($object) && $object->element == 'action') {
8295 $substitutionarray['__EVENT_LABEL__'] = $object->label;
8296 $substitutionarray['__EVENT_DATE__'] = dol_print_date($object->datep, '%A %d %b %Y');
8297 $substitutionarray['__EVENT_TIME__'] = dol_print_date($object->datep, '%H:%M:%S');
8298 }
8299 }
8300 }
8301 if ((empty($exclude) || !in_array('objectamount', $exclude)) && (empty($include) || in_array('objectamount', $include))) {
8302 include_once DOL_DOCUMENT_ROOT.'/core/lib/functionsnumtoword.lib.php';
8303
8304 $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : '';
8305 $substitutionarray['__DATE_DUE_YMD__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs) : null) : '';
8306
8307 $already_payed_all = 0;
8308 if (is_object($object) && ($object instanceof Facture)) {
8309 $already_payed_all = $object->sumpayed + $object->sumdeposit + $object->sumcreditnote;
8310 }
8311
8312 $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : '';
8313
8314 $substitutionarray['__AMOUNT__'] = is_object($object) ? $object->total_ttc : '';
8315 $substitutionarray['__AMOUNT_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, '', true) : '';
8316 $substitutionarray['__AMOUNT_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, $conf->currency, true) : '';
8317
8318 $substitutionarray['__AMOUNT_REMAIN__'] = is_object($object) ? price2num($object->total_ttc - $already_payed_all, 'MT') : '';
8319
8320 $substitutionarray['__AMOUNT_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8321 $substitutionarray['__AMOUNT_VAT_TEXT__'] = is_object($object) ? (isset($object->total_vat) ? dol_convertToWord($object->total_vat, $outputlangs, '', true) : dol_convertToWord($object->total_tva, $outputlangs, '', true)) : '';
8322 $substitutionarray['__AMOUNT_VAT_TEXTCURRENCY__'] = is_object($object) ? (isset($object->total_vat) ? dol_convertToWord($object->total_vat, $outputlangs, $conf->currency, true) : dol_convertToWord($object->total_tva, $outputlangs, $conf->currency, true)) : '';
8323
8324 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8325 $substitutionarray['__AMOUNT_TAX2__'] = is_object($object) ? $object->total_localtax1 : '';
8326 }
8327 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8328 $substitutionarray['__AMOUNT_TAX3__'] = is_object($object) ? $object->total_localtax2 : '';
8329 }
8330
8331 // Amount keys formated in a currency
8332 $substitutionarray['__AMOUNT_EXCL_TAX_FORMATED__'] = is_object($object) ? ($object->total_ht ? price($object->total_ht, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8333 $substitutionarray['__AMOUNT_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8334 $substitutionarray['__AMOUNT_REMAIN_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc - $already_payed_all, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8335 $substitutionarray['__AMOUNT_VAT_FORMATED__'] = is_object($object) ? (isset($object->total_vat) ? price($object->total_vat, 0, $outputlangs, 0, -1, -1, $conf->currency) : ($object->total_tva ? price($object->total_tva, 0, $outputlangs, 0, -1, -1, $conf->currency) : null)) : '';
8336 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8337 $substitutionarray['__AMOUNT_TAX2_FORMATED__'] = is_object($object) ? ($object->total_localtax1 ? price($object->total_localtax1, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8338 }
8339 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8340 $substitutionarray['__AMOUNT_TAX3_FORMATED__'] = is_object($object) ? ($object->total_localtax2 ? price($object->total_localtax2, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8341 }
8342
8343 $substitutionarray['__AMOUNT_MULTICURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? $object->multicurrency_total_ttc : '';
8344 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXT__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, '', true) : '';
8345 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXTCURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, $object->multicurrency_code, true) : '';
8346 // TODO Add other keys for foreign multicurrency
8347
8348 // For backward compatibility
8349 if ($onlykey != 2) {
8350 $substitutionarray['__TOTAL_TTC__'] = is_object($object) ? $object->total_ttc : '';
8351 $substitutionarray['__TOTAL_HT__'] = is_object($object) ? $object->total_ht : '';
8352 $substitutionarray['__TOTAL_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8353 }
8354 }
8355
8356 //var_dump($substitutionarray['__AMOUNT_FORMATED__']);
8357 if ((empty($exclude) || !in_array('date', $exclude)) && (empty($include) || in_array('date', $include))) {
8358 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
8359
8360 $now = dol_now();
8361
8362 $tmp = dol_getdate($now, true);
8363 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8364 $tmp3 = dol_get_prev_month($tmp['mon'], $tmp['year']);
8365 $tmp4 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8366 $tmp5 = dol_get_next_month($tmp['mon'], $tmp['year']);
8367
8368 $daytext = $outputlangs->trans('Day'.$tmp['wday']);
8369
8370 $substitutionarray = array_merge($substitutionarray, array(
8371 '__NOW_TMS__' => (int) $now,
8372 '__NOW_TMS_YMD__' => dol_print_date($now, 'day', 0, $outputlangs),
8373 '__DAY__' => (string) $tmp['mday'],
8374 '__DAY_TEXT__' => $daytext, // Monday
8375 '__DAY_TEXT_SHORT__' => dol_trunc($daytext, 3, 'right', 'UTF-8', 1), // Mon
8376 '__DAY_TEXT_MIN__' => dol_trunc($daytext, 1, 'right', 'UTF-8', 1), // M
8377 '__MONTH__' => (string) $tmp['mon'],
8378 '__MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp['mon'])),
8379 '__MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp['mon'])),
8380 '__MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp['mon'])),
8381 '__YEAR__' => (string) $tmp['year'],
8382 '__PREVIOUS_DAY__' => (string) $tmp2['day'],
8383 '__PREVIOUS_MONTH__' => (string) $tmp3['month'],
8384 '__PREVIOUS_YEAR__' => (string) ($tmp['year'] - 1),
8385 '__NEXT_DAY__' => (string) $tmp4['day'],
8386 '__NEXT_MONTH__' => (string) $tmp5['month'],
8387 '__NEXT_YEAR__' => (string) ($tmp['year'] + 1),
8388 ));
8389 }
8390
8391 if (isModEnabled('multicompany')) {
8392 $substitutionarray = array_merge($substitutionarray, array('__ENTITY_ID__' => $conf->entity));
8393 }
8394 if ((empty($exclude) || !in_array('system', $exclude)) && (empty($include) || in_array('user', $include))) {
8395 $substitutionarray['__DOL_MAIN_URL_ROOT__'] = DOL_MAIN_URL_ROOT;
8396 $substitutionarray['__(AnyTranslationKey)__'] = $outputlangs->trans('TranslationOfKey');
8397 $substitutionarray['__(AnyTranslationKey|langfile)__'] = $outputlangs->trans('TranslationOfKey').' (load also language file before)';
8398 $substitutionarray['__[AnyConstantKey]__'] = $outputlangs->trans('ValueOfConstantKey');
8399 }
8400
8401 return $substitutionarray;
8402}
8403
8420function make_substitutions($text, $substitutionarray, $outputlangs = null, $converttextinhtmlifnecessary = 0)
8421{
8422 global $conf, $langs;
8423
8424 if (!is_array($substitutionarray)) {
8425 return 'ErrorBadParameterSubstitutionArrayWhenCalling_make_substitutions';
8426 }
8427
8428 if (empty($outputlangs)) {
8429 $outputlangs = $langs;
8430 }
8431
8432 // Is initial text HTML or simple text ?
8433 $msgishtml = 0;
8434 if (dol_textishtml($text, 1)) {
8435 $msgishtml = 1;
8436 }
8437
8438 // Make substitution for language keys: __(AnyTranslationKey)__ or __(AnyTranslationKey|langfile)__
8439 if (is_object($outputlangs)) {
8440 $reg = array();
8441 while (preg_match('/__\‍(([^\‍)]+)\‍)__/', $text, $reg)) {
8442 // If key is __(TranslationKey|langfile)__, then force load of langfile.lang
8443 $tmp = explode('|', $reg[1]);
8444 if (!empty($tmp[1])) {
8445 $outputlangs->load($tmp[1]);
8446 }
8447
8448 $value = $outputlangs->transnoentitiesnoconv($reg[1]);
8449
8450 if (empty($converttextinhtmlifnecessary)) {
8451 // convert $newval into HTML is necessary
8452 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8453 } else {
8454 if (! $msgishtml) {
8455 $valueishtml = dol_textishtml($value, 1);
8456 //var_dump("valueishtml=".$valueishtml);
8457
8458 if ($valueishtml) {
8459 $text = dol_htmlentitiesbr($text);
8460 $msgishtml = 1;
8461 }
8462 } else {
8463 $value = dol_nl2br("$value");
8464 }
8465
8466 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $value, $text);
8467 }
8468 }
8469 }
8470
8471 // Make substitution for constant keys.
8472 // Must be after the substitution of translation, so if the text of translation contains a string __[xxx]__, it is also converted.
8473 $reg = array();
8474 while (preg_match('/__\[([^\]]+)\]__/', $text, $reg)) {
8475 $keyfound = $reg[1];
8476 if (isASecretKey($keyfound)) {
8477 $value = '*****forbidden*****';
8478 } else {
8479 $value = empty($conf->global->$keyfound) ? '' : $conf->global->$keyfound;
8480 }
8481
8482 if (empty($converttextinhtmlifnecessary)) {
8483 // convert $newval into HTML is necessary
8484 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8485 } else {
8486 if (! $msgishtml) {
8487 $valueishtml = dol_textishtml($value, 1);
8488
8489 if ($valueishtml) {
8490 $text = dol_htmlentitiesbr($text);
8491 $msgishtml = 1;
8492 }
8493 } else {
8494 $value = dol_nl2br("$value");
8495 }
8496
8497 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $value, $text);
8498 }
8499 }
8500
8501 // Make substitution for array $substitutionarray
8502 foreach ($substitutionarray as $key => $value) {
8503 if (!isset($value)) {
8504 continue; // If value is null, it same than not having substitution key at all into array, we do not replace.
8505 }
8506
8507 if (($key == '__USER_SIGNATURE__' || $key == '__SENDEREMAIL_SIGNATURE__') && (!empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN))) {
8508 $value = ''; // Protection
8509 }
8510
8511 if (empty($converttextinhtmlifnecessary)) {
8512 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8513 } else {
8514 if (! $msgishtml) {
8515 $valueishtml = dol_textishtml($value, 1);
8516
8517 if ($valueishtml) {
8518 $text = dol_htmlentitiesbr($text);
8519 $msgishtml = 1;
8520 }
8521 } else {
8522 $value = dol_nl2br("$value");
8523 }
8524 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8525 }
8526 }
8527
8528 return $text;
8529}
8530
8543function complete_substitutions_array(&$substitutionarray, $outputlangs, $object = null, $parameters = null, $callfunc = "completesubstitutionarray")
8544{
8545 global $conf, $user;
8546
8547 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
8548
8549 // Note: substitution key for each extrafields, using key __EXTRA_XXX__ is already available into the getCommonSubstitutionArray used to build the substitution array.
8550
8551 // Check if there is external substitution to do, requested by plugins
8552 $dirsubstitutions = array_merge(array(), (array) $conf->modules_parts['substitutions']);
8553
8554 foreach ($dirsubstitutions as $reldir) {
8555 $dir = dol_buildpath($reldir, 0);
8556
8557 // Check if directory exists
8558 if (!dol_is_dir($dir)) {
8559 continue;
8560 }
8561
8562 $substitfiles = dol_dir_list($dir, 'files', 0, 'functions_');
8563 foreach ($substitfiles as $substitfile) {
8564 $reg = array();
8565 if (preg_match('/functions_(.*)\.lib\.php/i', $substitfile['name'], $reg)) {
8566 $module = $reg[1];
8567
8568 dol_syslog("Library ".$substitfile['name']." found into ".$dir);
8569 // Include the user's functions file
8570 require_once $dir.$substitfile['name'];
8571 // Call the user's function, and only if it is defined
8572 $function_name = $module."_".$callfunc;
8573 if (function_exists($function_name)) {
8574 $function_name($substitutionarray, $outputlangs, $object, $parameters);
8575 }
8576 }
8577 }
8578 }
8579 if (!empty($conf->global->ODT_ENABLE_ALL_TAGS_IN_SUBSTITUTIONS)) {
8580 // to list all tags in odt template
8581 $tags = '';
8582 foreach ($substitutionarray as $key => $value) {
8583 $tags .= '{'.$key.'} => '.$value."\n";
8584 }
8585 $substitutionarray = array_merge($substitutionarray, array('__ALL_TAGS__' => $tags));
8586 }
8587}
8588
8598function print_date_range($date_start, $date_end, $format = '', $outputlangs = '')
8599{
8600 print get_date_range($date_start, $date_end, $format, $outputlangs);
8601}
8602
8613function get_date_range($date_start, $date_end, $format = '', $outputlangs = '', $withparenthesis = 1)
8614{
8615 global $langs;
8616
8617 $out = '';
8618
8619 if (!is_object($outputlangs)) {
8620 $outputlangs = $langs;
8621 }
8622
8623 if ($date_start && $date_end) {
8624 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFromTo', dol_print_date($date_start, $format, false, $outputlangs), dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8625 }
8626 if ($date_start && !$date_end) {
8627 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($date_start, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8628 }
8629 if (!$date_start && $date_end) {
8630 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8631 }
8632
8633 return $out;
8634}
8635
8644function dolGetFirstLastname($firstname, $lastname, $nameorder = -1)
8645{
8646 global $conf;
8647
8648 $ret = '';
8649 // If order not defined, we use the setup
8650 if ($nameorder < 0) {
8651 $nameorder = (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION) ? 1 : 0);
8652 }
8653 if ($nameorder == 1) {
8654 $ret .= $firstname;
8655 if ($firstname && $lastname) {
8656 $ret .= ' ';
8657 }
8658 $ret .= $lastname;
8659 } elseif ($nameorder == 2 || $nameorder == 3) {
8660 $ret .= $firstname;
8661 if (empty($ret) && $nameorder == 3) {
8662 $ret .= $lastname;
8663 }
8664 } else { // 0, 4 or 5
8665 $ret .= $lastname;
8666 if (empty($ret) && $nameorder == 5) {
8667 $ret .= $firstname;
8668 }
8669 if ($nameorder == 0) {
8670 if ($firstname && $lastname) {
8671 $ret .= ' ';
8672 }
8673 $ret .= $firstname;
8674 }
8675 }
8676 return $ret;
8677}
8678
8679
8691function setEventMessage($mesgs, $style = 'mesgs', $noduplicate = 0)
8692{
8693 //dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING); This is not deprecated, it is used by setEventMessages function
8694 if (!is_array($mesgs)) {
8695 // If mesgs is a string
8696 if ($mesgs) {
8697 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesgs, $_SESSION['dol_events'][$style])) {
8698 return;
8699 }
8700 $_SESSION['dol_events'][$style][] = $mesgs;
8701 }
8702 } else {
8703 // If mesgs is an array
8704 foreach ($mesgs as $mesg) {
8705 if ($mesg) {
8706 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesg, $_SESSION['dol_events'][$style])) {
8707 return;
8708 }
8709 $_SESSION['dol_events'][$style][] = $mesg;
8710 }
8711 }
8712 }
8713}
8714
8727function setEventMessages($mesg, $mesgs, $style = 'mesgs', $messagekey = '', $noduplicate = 0)
8728{
8729 if (empty($mesg) && empty($mesgs)) {
8730 dol_syslog("Try to add a message in stack, but value to add is empty message", LOG_WARNING);
8731 } else {
8732 if ($messagekey) {
8733 // Complete message with a js link to set a cookie "DOLHIDEMESSAGE".$messagekey;
8734 // TODO
8735 $mesg .= '';
8736 }
8737 if (empty($messagekey) || empty($_COOKIE["DOLHIDEMESSAGE".$messagekey])) {
8738 if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
8739 dol_print_error('', 'Bad parameter style='.$style.' for setEventMessages');
8740 }
8741 if (empty($mesgs)) {
8742 setEventMessage($mesg, $style, $noduplicate);
8743 } else {
8744 if (!empty($mesg) && !in_array($mesg, $mesgs)) {
8745 setEventMessage($mesg, $style, $noduplicate); // Add message string if not already into array
8746 }
8747 setEventMessage($mesgs, $style, $noduplicate);
8748 }
8749 }
8750 }
8751}
8752
8762function dol_htmloutput_events($disabledoutputofmessages = 0)
8763{
8764 // Show mesgs
8765 if (isset($_SESSION['dol_events']['mesgs'])) {
8766 if (empty($disabledoutputofmessages)) {
8767 dol_htmloutput_mesg('', $_SESSION['dol_events']['mesgs']);
8768 }
8769 unset($_SESSION['dol_events']['mesgs']);
8770 }
8771 // Show errors
8772 if (isset($_SESSION['dol_events']['errors'])) {
8773 if (empty($disabledoutputofmessages)) {
8774 dol_htmloutput_mesg('', $_SESSION['dol_events']['errors'], 'error');
8775 }
8776 unset($_SESSION['dol_events']['errors']);
8777 }
8778
8779 // Show warnings
8780 if (isset($_SESSION['dol_events']['warnings'])) {
8781 if (empty($disabledoutputofmessages)) {
8782 dol_htmloutput_mesg('', $_SESSION['dol_events']['warnings'], 'warning');
8783 }
8784 unset($_SESSION['dol_events']['warnings']);
8785 }
8786}
8787
8802function get_htmloutput_mesg($mesgstring = '', $mesgarray = '', $style = 'ok', $keepembedded = 0)
8803{
8804 global $conf, $langs;
8805
8806 $ret = 0;
8807 $return = '';
8808 $out = '';
8809 $divstart = $divend = '';
8810
8811 // If inline message with no format, we add it.
8812 if ((empty($conf->use_javascript_ajax) || !empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) || $keepembedded) && !preg_match('/<div class=".*">/i', $out)) {
8813 $divstart = '<div class="'.$style.' clearboth">';
8814 $divend = '</div>';
8815 }
8816
8817 if ((is_array($mesgarray) && count($mesgarray)) || $mesgstring) {
8818 $langs->load("errors");
8819 $out .= $divstart;
8820 if (is_array($mesgarray) && count($mesgarray)) {
8821 foreach ($mesgarray as $message) {
8822 $ret++;
8823 $out .= $langs->trans($message);
8824 if ($ret < count($mesgarray)) {
8825 $out .= "<br>\n";
8826 }
8827 }
8828 }
8829 if ($mesgstring) {
8830 $ret++;
8831 $out .= $langs->trans($mesgstring);
8832 }
8833 $out .= $divend;
8834 }
8835
8836 if ($out) {
8837 if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) && empty($keepembedded)) {
8838 $return = '<script nonce="'.getNonce().'">
8839 $(document).ready(function() {
8840 var block = '.(!empty($conf->global->MAIN_USE_JQUERY_BLOCKUI) ? "true" : "false").'
8841 if (block) {
8842 $.dolEventValid("","'.dol_escape_js($out).'");
8843 } else {
8844 /* jnotify(message, preset of message type, keepmessage) */
8845 $.jnotify("'.dol_escape_js($out).'",
8846 "'.($style == "ok" ? 3000 : $style).'",
8847 '.($style == "ok" ? "false" : "true").',
8848 { remove: function (){} } );
8849 }
8850 });
8851 </script>';
8852 } else {
8853 $return = $out;
8854 }
8855 }
8856
8857 return $return;
8858}
8859
8871function get_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
8872{
8873 return get_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
8874}
8875
8889function dol_htmloutput_mesg($mesgstring = '', $mesgarray = array(), $style = 'ok', $keepembedded = 0)
8890{
8891 if (empty($mesgstring) && (!is_array($mesgarray) || count($mesgarray) == 0)) {
8892 return;
8893 }
8894
8895 $iserror = 0;
8896 $iswarning = 0;
8897 if (is_array($mesgarray)) {
8898 foreach ($mesgarray as $val) {
8899 if ($val && preg_match('/class="error"/i', $val)) {
8900 $iserror++;
8901 break;
8902 }
8903 if ($val && preg_match('/class="warning"/i', $val)) {
8904 $iswarning++;
8905 break;
8906 }
8907 }
8908 } elseif ($mesgstring && preg_match('/class="error"/i', $mesgstring)) {
8909 $iserror++;
8910 } elseif ($mesgstring && preg_match('/class="warning"/i', $mesgstring)) {
8911 $iswarning++;
8912 }
8913 if ($style == 'error') {
8914 $iserror++;
8915 }
8916 if ($style == 'warning') {
8917 $iswarning++;
8918 }
8919
8920 if ($iserror || $iswarning) {
8921 // Remove div from texts
8922 $mesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $mesgstring);
8923 $mesgstring = preg_replace('/<div class="(error|warning)">/', '', $mesgstring);
8924 $mesgstring = preg_replace('/<\/div>/', '', $mesgstring);
8925 // Remove div from texts array
8926 if (is_array($mesgarray)) {
8927 $newmesgarray = array();
8928 foreach ($mesgarray as $val) {
8929 if (is_string($val)) {
8930 $tmpmesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $val);
8931 $tmpmesgstring = preg_replace('/<div class="(error|warning)">/', '', $tmpmesgstring);
8932 $tmpmesgstring = preg_replace('/<\/div>/', '', $tmpmesgstring);
8933 $newmesgarray[] = $tmpmesgstring;
8934 } else {
8935 dol_syslog("Error call of dol_htmloutput_mesg with an array with a value that is not a string", LOG_WARNING);
8936 }
8937 }
8938 $mesgarray = $newmesgarray;
8939 }
8940 print get_htmloutput_mesg($mesgstring, $mesgarray, ($iserror ? 'error' : 'warning'), $keepembedded);
8941 } else {
8942 print get_htmloutput_mesg($mesgstring, $mesgarray, 'ok', $keepembedded);
8943 }
8944}
8945
8957function dol_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
8958{
8959 dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
8960}
8961
8976function dol_sort_array(&$array, $index, $order = 'asc', $natsort = 0, $case_sensitive = 0, $keepindex = 0)
8977{
8978 // Clean parameters
8979 $order = strtolower($order);
8980
8981 if (is_array($array)) {
8982 $sizearray = count($array);
8983 if ($sizearray > 0) {
8984 $temp = array();
8985 foreach (array_keys($array) as $key) {
8986 if (is_object($array[$key])) {
8987 $temp[$key] = empty($array[$key]->$index) ? 0 : $array[$key]->$index;
8988 } else {
8989 $temp[$key] = empty($array[$key][$index]) ? 0 : $array[$key][$index];
8990 }
8991 if ($natsort == -1) {
8992 $temp[$key] = '___'.$temp[$key]; // We add a string at begin of value to force an alpha order when using asort.
8993 }
8994 }
8995
8996 if (empty($natsort) || $natsort == -1) {
8997 if ($order == 'asc') {
8998 asort($temp);
8999 } else {
9000 arsort($temp);
9001 }
9002 } else {
9003 if ($case_sensitive) {
9004 natsort($temp);
9005 } else {
9006 natcasesort($temp); // natecasesort is not sensible to case
9007 }
9008 if ($order != 'asc') {
9009 $temp = array_reverse($temp, true);
9010 }
9011 }
9012
9013 $sorted = array();
9014
9015 foreach (array_keys($temp) as $key) {
9016 (is_numeric($key) && empty($keepindex)) ? $sorted[] = $array[$key] : $sorted[$key] = $array[$key];
9017 }
9018
9019 return $sorted;
9020 }
9021 }
9022 return $array;
9023}
9024
9025
9032function utf8_check($str)
9033{
9034 $str = (string) $str; // Sometimes string is an int.
9035
9036 // We must use here a binary strlen function (so not dol_strlen)
9037 $strLength = dol_strlen($str);
9038 for ($i = 0; $i < $strLength; $i++) {
9039 if (ord($str[$i]) < 0x80) {
9040 continue; // 0bbbbbbb
9041 } elseif ((ord($str[$i]) & 0xE0) == 0xC0) {
9042 $n = 1; // 110bbbbb
9043 } elseif ((ord($str[$i]) & 0xF0) == 0xE0) {
9044 $n = 2; // 1110bbbb
9045 } elseif ((ord($str[$i]) & 0xF8) == 0xF0) {
9046 $n = 3; // 11110bbb
9047 } elseif ((ord($str[$i]) & 0xFC) == 0xF8) {
9048 $n = 4; // 111110bb
9049 } elseif ((ord($str[$i]) & 0xFE) == 0xFC) {
9050 $n = 5; // 1111110b
9051 } else {
9052 return false; // Does not match any model
9053 }
9054 for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
9055 if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80)) {
9056 return false;
9057 }
9058 }
9059 }
9060 return true;
9061}
9062
9069function utf8_valid($str)
9070{
9071 /* 2 other methods to test if string is utf8
9072 $validUTF8 = mb_check_encoding($messagetext, 'UTF-8');
9073 $validUTF8b = ! (false === mb_detect_encoding($messagetext, 'UTF-8', true));
9074 */
9075 return preg_match('//u', $str) ? true : false;
9076}
9077
9078
9085function ascii_check($str)
9086{
9087 if (function_exists('mb_check_encoding')) {
9088 //if (mb_detect_encoding($str, 'ASCII', true) return false;
9089 if (!mb_check_encoding($str, 'ASCII')) {
9090 return false;
9091 }
9092 } else {
9093 if (preg_match('/[^\x00-\x7f]/', $str)) {
9094 return false; // Contains a byte > 7f
9095 }
9096 }
9097
9098 return true;
9099}
9100
9101
9109function dol_osencode($str)
9110{
9111 global $conf;
9112
9113 $tmp = ini_get("unicode.filesystem_encoding"); // Disponible avec PHP 6.0
9114 if (empty($tmp) && !empty($_SERVER["WINDIR"])) {
9115 $tmp = 'iso-8859-1'; // By default for windows
9116 }
9117 if (empty($tmp)) {
9118 $tmp = 'utf-8'; // By default for other
9119 }
9120 if (!empty($conf->global->MAIN_FILESYSTEM_ENCODING)) {
9121 $tmp = $conf->global->MAIN_FILESYSTEM_ENCODING;
9122 }
9123
9124 if ($tmp == 'iso-8859-1') {
9125 return mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8');
9126 }
9127 return $str;
9128}
9129
9130
9145function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '')
9146{
9147 global $cache_codes;
9148
9149 // If key empty
9150 if ($key == '') {
9151 return '';
9152 }
9153
9154 // Check in cache
9155 if (isset($cache_codes[$tablename][$key][$fieldid])) { // Can be defined to 0 or ''
9156 return $cache_codes[$tablename][$key][$fieldid]; // Found in cache
9157 }
9158
9159 dol_syslog('dol_getIdFromCode (value for field '.$fieldid.' from key '.$key.' not found into cache)', LOG_DEBUG);
9160
9161 $sql = "SELECT ".$fieldid." as valuetoget";
9162 $sql .= " FROM ".MAIN_DB_PREFIX.$tablename;
9163 $sql .= " WHERE ".$fieldkey." = '".$db->escape($key)."'";
9164 if (!empty($entityfilter)) {
9165 $sql .= " AND entity IN (".getEntity($tablename).")";
9166 }
9167 if ($filters) {
9168 $sql .= $filters;
9169 }
9170
9171 $resql = $db->query($sql);
9172 if ($resql) {
9173 $obj = $db->fetch_object($resql);
9174 if ($obj) {
9175 $cache_codes[$tablename][$key][$fieldid] = $obj->valuetoget;
9176 } else {
9177 $cache_codes[$tablename][$key][$fieldid] = '';
9178 }
9179 $db->free($resql);
9180 return $cache_codes[$tablename][$key][$fieldid];
9181 } else {
9182 return -1;
9183 }
9184}
9185
9192function verifCond($strToEvaluate)
9193{
9194 global $user, $conf, $langs;
9195 global $leftmenu;
9196 global $rights; // To export to dol_eval function
9197
9198 //print $strToEvaluate."<br>\n";
9199 $rights = true;
9200 if (isset($strToEvaluate) && $strToEvaluate !== '') {
9201 //var_dump($strToEvaluate);
9202 //$rep = dol_eval($strToEvaluate, 1, 0, '1'); // to show the error
9203 $rep = dol_eval($strToEvaluate, 1, 1, '1'); // The dol_eval() must contains all the "global $xxx;" for all variables $xxx found into the string condition
9204 $rights = $rep && (!is_string($rep) || strpos($rep, 'Bad string syntax to evaluate') === false);
9205 //var_dump($rights);
9206 }
9207 return $rights;
9208}
9209
9220function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1')
9221{
9222 // Only global variables can be changed by eval function and returned to caller
9223 global $db, $langs, $user, $conf, $website, $websitepage;
9224 global $action, $mainmenu, $leftmenu;
9225 global $mysoc;
9226 global $objectoffield;
9227
9228 // Old variables used
9229 global $rights;
9230 global $object;
9231 global $obj; // To get $obj used into list when dol_eval is used for computed fields and $obj is not yet $object
9232 global $soc; // For backward compatibility
9233
9234 try {
9235 // Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing
9236 if ($onlysimplestring == '1') {
9237 // We must accept: '1 && getDolGlobalInt("doesnotexist1") && $conf->global->MAIN_FEATURES_LEVEL'
9238 // We must accept: '$conf->barcode->enabled || preg_match(\'/^AAA/\',$leftmenu)'
9239 // We must accept: '$user->rights->cabinetmed->read && !$object->canvas=="patient@cabinetmed"'
9240 if (preg_match('/[^a-z0-9\s'.preg_quote('^$_+-.*>&|=!?():"\',/@', '/').']/i', $s)) {
9241 if ($returnvalue) {
9242 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9243 } else {
9244 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9245 return '';
9246 }
9247 // TODO
9248 // We can exclude all parenthesis ( that are not '($db' and 'getDolGlobalInt(' and 'getDolGlobalString(' and 'preg_match(' and 'isModEnabled('
9249 // ...
9250 }
9251 } elseif ($onlysimplestring == '2') {
9252 // We must accept: (($reloadedobj = new Task($db)) && ($reloadedobj->fetchNoCompute($object->id) > 0) && ($secondloadedobj = new Project($db)) && ($secondloadedobj->fetchNoCompute($reloadedobj->fk_project) > 0)) ? $secondloadedobj->ref : "Parent project not found"
9253 if (preg_match('/[^a-z0-9\s'.preg_quote('^$_+-.*>&|=!?():"\',/@[]', '/').']/i', $s)) {
9254 if ($returnvalue) {
9255 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9256 } else {
9257 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9258 return '';
9259 }
9260 // TODO
9261 // We can exclude all parenthesis ( that are not '($db' and 'getDolGlobalInt(' and 'getDolGlobalString(' and 'preg_match(' and 'isModEnabled('
9262 // ...
9263 }
9264 }
9265 if (is_array($s) || $s === 'Array') {
9266 return 'Bad string syntax to evaluate (value is Array) '.var_export($s, true);
9267 }
9268 if (strpos($s, '::') !== false) {
9269 if ($returnvalue) {
9270 return 'Bad string syntax to evaluate (double : char is forbidden): '.$s;
9271 } else {
9272 dol_syslog('Bad string syntax to evaluate (double : char is forbidden): '.$s);
9273 return '';
9274 }
9275 }
9276 if (strpos($s, '`') !== false) {
9277 if ($returnvalue) {
9278 return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
9279 } else {
9280 dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s);
9281 return '';
9282 }
9283 }
9284 if (preg_match('/[^0-9]+\.[^0-9]+/', $s)) { // We refuse . if not between 2 numbers
9285 if ($returnvalue) {
9286 return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
9287 } else {
9288 dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s);
9289 return '';
9290 }
9291 }
9292
9293 // We block use of php exec or php file functions
9294 $forbiddenphpstrings = array('$$');
9295 $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
9296
9297 $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen");
9298 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
9299 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64_decode", "rawurldecode", "urldecode", "str_rot13", "hex2bin")); // decode string functions used to obfuscated function name
9300 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
9301 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
9302 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));
9303 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
9304 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
9305
9306 $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
9307
9308 $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
9309
9310 $forbiddenphpmethodsregex = '->('.implode('|', $forbiddenphpmethods).')';
9311
9312 do {
9313 $oldstringtoclean = $s;
9314 $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);
9315 $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);
9316 $s = preg_replace('/'.$forbiddenphpmethodsregex.'/i', '__forbiddenstring__', $s);
9317 //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\‍(/i', '', $s); // Remove $function( call and $mycall->mymethod(
9318 } while ($oldstringtoclean != $s);
9319
9320 if (strpos($s, '__forbiddenstring__') !== false) {
9321 dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
9322 if ($returnvalue) {
9323 return 'Bad string syntax to evaluate: '.$s;
9324 } else {
9325 dol_syslog('Bad string syntax to evaluate: '.$s);
9326 return '';
9327 }
9328 }
9329
9330 //print $s."<br>\n";
9331 if ($returnvalue) {
9332 if ($hideerrors) {
9333 return @eval('return '.$s.';');
9334 } else {
9335 return eval('return '.$s.';');
9336 }
9337 } else {
9338 if ($hideerrors) {
9339 @eval($s);
9340 } else {
9341 eval($s);
9342 }
9343 }
9344 } catch (Error $e) {
9345 $error = 'dol_eval try/catch error : ';
9346 $error .= $e->getMessage();
9347 dol_syslog($error);
9348 }
9349}
9350
9357function dol_validElement($element)
9358{
9359 return (trim($element) != '');
9360}
9361
9370function picto_from_langcode($codelang, $moreatt = '', $notitlealt = 0)
9371{
9372 if (empty($codelang)) {
9373 return '';
9374 }
9375
9376 if ($codelang == 'auto') {
9377 return '<span class="fa fa-language"></span>';
9378 }
9379
9380 $langtocountryflag = array(
9381 'ar_AR' => '',
9382 'ca_ES' => 'catalonia',
9383 'da_DA' => 'dk',
9384 'fr_CA' => 'mq',
9385 'sv_SV' => 'se',
9386 'sw_SW' => 'unknown',
9387 'AQ' => 'unknown',
9388 'CW' => 'unknown',
9389 'IM' => 'unknown',
9390 'JE' => 'unknown',
9391 'MF' => 'unknown',
9392 'BL' => 'unknown',
9393 'SX' => 'unknown'
9394 );
9395
9396 if (isset($langtocountryflag[$codelang])) {
9397 $flagImage = $langtocountryflag[$codelang];
9398 } else {
9399 $tmparray = explode('_', $codelang);
9400 $flagImage = empty($tmparray[1]) ? $tmparray[0] : $tmparray[1];
9401 }
9402
9403 return img_picto_common($codelang, 'flags/'.strtolower($flagImage).'.png', $moreatt, 0, $notitlealt);
9404}
9405
9414{
9415 global $mysoc;
9416
9417 if (empty($countrycode)) {
9418 return null;
9419 }
9420
9421 if (strtoupper($countrycode) == 'MQ') {
9422 return 'fr_CA';
9423 }
9424 if (strtoupper($countrycode) == 'SE') {
9425 return 'sv_SE'; // se_SE is Sami/Sweden, and we want in priority sv_SE for SE country
9426 }
9427 if (strtoupper($countrycode) == 'CH') {
9428 if ($mysoc->country_code == 'FR') {
9429 return 'fr_CH';
9430 }
9431 if ($mysoc->country_code == 'DE') {
9432 return 'de_CH';
9433 }
9434 if ($mysoc->country_code == 'IT') {
9435 return 'it_CH';
9436 }
9437 }
9438
9439 // Locale list taken from:
9440 // http://stackoverflow.com/questions/3191664/
9441 // list-of-all-locales-and-their-short-codes
9442 $locales = array(
9443 'af-ZA',
9444 'am-ET',
9445 'ar-AE',
9446 'ar-BH',
9447 'ar-DZ',
9448 'ar-EG',
9449 'ar-IQ',
9450 'ar-JO',
9451 'ar-KW',
9452 'ar-LB',
9453 'ar-LY',
9454 'ar-MA',
9455 'ar-OM',
9456 'ar-QA',
9457 'ar-SA',
9458 'ar-SY',
9459 'ar-TN',
9460 'ar-YE',
9461 //'as-IN', // Moved after en-IN
9462 'ba-RU',
9463 'be-BY',
9464 'bg-BG',
9465 'bn-BD',
9466 //'bn-IN', // Moved after en-IN
9467 'bo-CN',
9468 'br-FR',
9469 'ca-ES',
9470 'co-FR',
9471 'cs-CZ',
9472 'cy-GB',
9473 'da-DK',
9474 'de-AT',
9475 'de-CH',
9476 'de-DE',
9477 'de-LI',
9478 'de-LU',
9479 'dv-MV',
9480 'el-GR',
9481 'en-AU',
9482 'en-BZ',
9483 'en-CA',
9484 'en-GB',
9485 'en-IE',
9486 'en-IN',
9487 'as-IN', // as-IN must be after en-IN (en in priority if country is IN)
9488 'bn-IN', // bn-IN must be after en-IN (en in priority if country is IN)
9489 'en-JM',
9490 'en-MY',
9491 'en-NZ',
9492 'en-PH',
9493 'en-SG',
9494 'en-TT',
9495 'en-US',
9496 'en-ZA',
9497 'en-ZW',
9498 'es-AR',
9499 'es-BO',
9500 'es-CL',
9501 'es-CO',
9502 'es-CR',
9503 'es-DO',
9504 'es-EC',
9505 'es-ES',
9506 'es-GT',
9507 'es-HN',
9508 'es-MX',
9509 'es-NI',
9510 'es-PA',
9511 'es-PE',
9512 'es-PR',
9513 'es-PY',
9514 'es-SV',
9515 'es-US',
9516 'es-UY',
9517 'es-VE',
9518 'et-EE',
9519 'eu-ES',
9520 'fa-IR',
9521 'fi-FI',
9522 'fo-FO',
9523 'fr-BE',
9524 'fr-CA',
9525 'fr-CH',
9526 'fr-FR',
9527 'fr-LU',
9528 'fr-MC',
9529 'fy-NL',
9530 'ga-IE',
9531 'gd-GB',
9532 'gl-ES',
9533 'gu-IN',
9534 'he-IL',
9535 'hi-IN',
9536 'hr-BA',
9537 'hr-HR',
9538 'hu-HU',
9539 'hy-AM',
9540 'id-ID',
9541 'ig-NG',
9542 'ii-CN',
9543 'is-IS',
9544 'it-CH',
9545 'it-IT',
9546 'ja-JP',
9547 'ka-GE',
9548 'kk-KZ',
9549 'kl-GL',
9550 'km-KH',
9551 'kn-IN',
9552 'ko-KR',
9553 'ky-KG',
9554 'lb-LU',
9555 'lo-LA',
9556 'lt-LT',
9557 'lv-LV',
9558 'mi-NZ',
9559 'mk-MK',
9560 'ml-IN',
9561 'mn-MN',
9562 'mr-IN',
9563 'ms-BN',
9564 'ms-MY',
9565 'mt-MT',
9566 'nb-NO',
9567 'ne-NP',
9568 'nl-BE',
9569 'nl-NL',
9570 'nn-NO',
9571 'oc-FR',
9572 'or-IN',
9573 'pa-IN',
9574 'pl-PL',
9575 'ps-AF',
9576 'pt-BR',
9577 'pt-PT',
9578 'rm-CH',
9579 'ro-MD',
9580 'ro-RO',
9581 'ru-RU',
9582 'rw-RW',
9583 'sa-IN',
9584 'se-FI',
9585 'se-NO',
9586 'se-SE',
9587 'si-LK',
9588 'sk-SK',
9589 'sl-SI',
9590 'sq-AL',
9591 'sv-FI',
9592 'sv-SE',
9593 'sw-KE',
9594 'ta-IN',
9595 'te-IN',
9596 'th-TH',
9597 'tk-TM',
9598 'tn-ZA',
9599 'tr-TR',
9600 'tt-RU',
9601 'ug-CN',
9602 'uk-UA',
9603 'ur-PK',
9604 'vi-VN',
9605 'wo-SN',
9606 'xh-ZA',
9607 'yo-NG',
9608 'zh-CN',
9609 'zh-HK',
9610 'zh-MO',
9611 'zh-SG',
9612 'zh-TW',
9613 'zu-ZA',
9614 );
9615
9616 $buildprimarykeytotest = strtolower($countrycode).'-'.strtoupper($countrycode);
9617 if (in_array($buildprimarykeytotest, $locales)) {
9618 return strtolower($countrycode).'_'.strtoupper($countrycode);
9619 }
9620
9621 if (function_exists('locale_get_primary_language') && function_exists('locale_get_region')) { // Need extension php-intl
9622 foreach ($locales as $locale) {
9623 $locale_language = locale_get_primary_language($locale);
9624 $locale_region = locale_get_region($locale);
9625 if (strtoupper($countrycode) == $locale_region) {
9626 //var_dump($locale.' - '.$locale_language.' - '.$locale_region);
9627 return strtolower($locale_language).'_'.strtoupper($locale_region);
9628 }
9629 }
9630 } else {
9631 dol_syslog("Warning Exention php-intl is not available", LOG_WARNING);
9632 }
9633
9634 return null;
9635}
9636
9667function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode = 'add', $filterorigmodule = '')
9668{
9669 global $hookmanager, $db;
9670
9671 if (isset($conf->modules_parts['tabs'][$type]) && is_array($conf->modules_parts['tabs'][$type])) {
9672 foreach ($conf->modules_parts['tabs'][$type] as $value) {
9673 $values = explode(':', $value);
9674
9675 $reg = array();
9676 if ($mode == 'add' && !preg_match('/^\-/', $values[1])) {
9677 if (count($values) == 6) {
9678 // new declaration with permissions:
9679 // $value='objecttype:+tabname1:Title1:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
9680 // $value='objecttype:+tabname1:Title1,class,pathfile,method:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
9681 if ($values[0] != $type) {
9682 continue;
9683 }
9684
9685 if (verifCond($values[4])) {
9686 if ($values[3]) {
9687 if ($filterorigmodule) { // If a filter of module origin has been requested
9688 if (strpos($values[3], '@')) { // This is an external module
9689 if ($filterorigmodule != 'external') {
9690 continue;
9691 }
9692 } else { // This looks a core module
9693 if ($filterorigmodule != 'core') {
9694 continue;
9695 }
9696 }
9697 }
9698 $langs->load($values[3]);
9699 }
9700 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
9701 // If label is "SUBSTITUION_..."
9702 $substitutionarray = array();
9703 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
9704 $label = make_substitutions($reg[1], $substitutionarray);
9705 } else {
9706 // If label is "Label,Class,File,Method", we call the method to show content inside the badge
9707 $labeltemp = explode(',', $values[2]);
9708 $label = $langs->trans($labeltemp[0]);
9709
9710 if (!empty($labeltemp[1]) && is_object($object) && !empty($object->id)) {
9711 dol_include_once($labeltemp[2]);
9712 $classtoload = $labeltemp[1];
9713 if (class_exists($classtoload)) {
9714 $obj = new $classtoload($db);
9715 $function = $labeltemp[3];
9716 if ($obj && $function && method_exists($obj, $function)) {
9717 $nbrec = $obj->$function($object->id, $obj);
9718 if (!empty($nbrec)) {
9719 $label .= '<span class="badge marginleftonlyshort">'.$nbrec.'</span>';
9720 }
9721 }
9722 }
9723 }
9724 }
9725
9726 $head[$h][0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[5]), 1);
9727 $head[$h][1] = $label;
9728 $head[$h][2] = str_replace('+', '', $values[1]);
9729 $h++;
9730 }
9731 } elseif (count($values) == 5) { // case deprecated
9732 dol_syslog('Passing 5 values in tabs module_parts is deprecated. Please update to 6 with permissions.', LOG_WARNING);
9733
9734 if ($values[0] != $type) {
9735 continue;
9736 }
9737 if ($values[3]) {
9738 if ($filterorigmodule) { // If a filter of module origin has been requested
9739 if (strpos($values[3], '@')) { // This is an external module
9740 if ($filterorigmodule != 'external') {
9741 continue;
9742 }
9743 } else { // This looks a core module
9744 if ($filterorigmodule != 'core') {
9745 continue;
9746 }
9747 }
9748 }
9749 $langs->load($values[3]);
9750 }
9751 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
9752 $substitutionarray = array();
9753 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
9754 $label = make_substitutions($reg[1], $substitutionarray);
9755 } else {
9756 $label = $langs->trans($values[2]);
9757 }
9758
9759 $head[$h][0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[4]), 1);
9760 $head[$h][1] = $label;
9761 $head[$h][2] = str_replace('+', '', $values[1]);
9762 $h++;
9763 }
9764 } elseif ($mode == 'remove' && preg_match('/^\-/', $values[1])) {
9765 if ($values[0] != $type) {
9766 continue;
9767 }
9768 $tabname = str_replace('-', '', $values[1]);
9769 foreach ($head as $key => $val) {
9770 $condition = (!empty($values[3]) ? verifCond($values[3]) : 1);
9771 //var_dump($key.' - '.$tabname.' - '.$head[$key][2].' - '.$values[3].' - '.$condition);
9772 if ($head[$key][2] == $tabname && $condition) {
9773 unset($head[$key]);
9774 break;
9775 }
9776 }
9777 }
9778 }
9779 }
9780
9781 // No need to make a return $head. Var is modified as a reference
9782 if (!empty($hookmanager)) {
9783 $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule);
9784 $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters);
9785 if ($reshook > 0) { // Hook ask to replace completely the array
9786 $head = $hookmanager->resArray;
9787 } else { // Hook
9788 $head = array_merge($head, $hookmanager->resArray);
9789 }
9790 $h = count($head);
9791 }
9792}
9793
9805function printCommonFooter($zone = 'private')
9806{
9807 global $conf, $hookmanager, $user, $debugbar;
9808 global $action;
9809 global $micro_start_time;
9810
9811 if ($zone == 'private') {
9812 print "\n".'<!-- Common footer for private page -->'."\n";
9813 } else {
9814 print "\n".'<!-- Common footer for public page -->'."\n";
9815 }
9816
9817 // A div to store page_y POST parameter so we can read it using javascript
9818 print "\n<!-- A div to store page_y POST parameter -->\n";
9819 print '<div id="page_y" style="display: none;">'.(GETPOST('page_y') ? GETPOST('page_y') : '').'</div>'."\n";
9820
9821 $parameters = array();
9822 $reshook = $hookmanager->executeHooks('printCommonFooter', $parameters); // Note that $action and $object may have been modified by some hooks
9823 if (empty($reshook)) {
9824 if (!empty($conf->global->MAIN_HTML_FOOTER)) {
9825 print $conf->global->MAIN_HTML_FOOTER."\n";
9826 }
9827
9828 print "\n";
9829 if (!empty($conf->use_javascript_ajax)) {
9830 print "\n<!-- A script section to add menuhider handler on backoffice, manage focus and madatory fields, tuning info, ... -->\n";
9831 print '<script>'."\n";
9832 print 'jQuery(document).ready(function() {'."\n";
9833
9834 if ($zone == 'private' && empty($conf->dol_use_jmobile)) {
9835 print "\n";
9836 print '/* JS CODE TO ENABLE to manage handler to switch left menu page (menuhider) */'."\n";
9837 print 'jQuery("li.menuhider").click(function(event) {';
9838 print ' if (!$( "body" ).hasClass( "sidebar-collapse" )){ event.preventDefault(); }'."\n";
9839 print ' console.log("We click on .menuhider");'."\n";
9840 print ' $("body").toggleClass("sidebar-collapse")'."\n";
9841 print '});'."\n";
9842 }
9843
9844 // Management of focus and mandatory for fields
9845 if ($action == 'create' || $action == 'edit' || (empty($action) && (preg_match('/new\.php/', $_SERVER["PHP_SELF"]))) || ((empty($action) || $action == 'addline') && (preg_match('/card\.php/', $_SERVER["PHP_SELF"])))) {
9846 print '/* JS CODE TO ENABLE to manage focus and mandatory form fields */'."\n";
9847 $relativepathstring = $_SERVER["PHP_SELF"];
9848 // Clean $relativepathstring
9849 if (constant('DOL_URL_ROOT')) {
9850 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
9851 }
9852 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
9853 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
9854 //$tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
9855 if (!empty($user->default_values[$relativepathstring]['focus'])) {
9856 foreach ($user->default_values[$relativepathstring]['focus'] as $defkey => $defval) {
9857 $qualified = 0;
9858 if ($defkey != '_noquery_') {
9859 $tmpqueryarraytohave = explode('&', $defkey);
9860 $foundintru = 0;
9861 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
9862 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
9863 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
9864 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
9865 $foundintru = 1;
9866 }
9867 }
9868 if (!$foundintru) {
9869 $qualified = 1;
9870 }
9871 //var_dump($defkey.'-'.$qualified);
9872 } else {
9873 $qualified = 1;
9874 }
9875
9876 if ($qualified) {
9877 foreach ($defval as $paramkey => $paramval) {
9878 // Set focus on field
9879 print 'jQuery("input[name=\''.$paramkey.'\']").focus();'."\n";
9880 print 'jQuery("textarea[name=\''.$paramkey.'\']").focus();'."\n";
9881 print 'jQuery("select[name=\''.$paramkey.'\']").focus();'."\n"; // Not really usefull, but we keep it in case of.
9882 }
9883 }
9884 }
9885 }
9886 if (!empty($user->default_values[$relativepathstring]['mandatory'])) {
9887 foreach ($user->default_values[$relativepathstring]['mandatory'] as $defkey => $defval) {
9888 $qualified = 0;
9889 if ($defkey != '_noquery_') {
9890 $tmpqueryarraytohave = explode('&', $defkey);
9891 $foundintru = 0;
9892 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
9893 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
9894 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
9895 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
9896 $foundintru = 1;
9897 }
9898 }
9899 if (!$foundintru) {
9900 $qualified = 1;
9901 }
9902 //var_dump($defkey.'-'.$qualified);
9903 } else {
9904 $qualified = 1;
9905 }
9906
9907 if ($qualified) {
9908 foreach ($defval as $paramkey => $paramval) {
9909 // Add property 'required' on input
9910 print 'jQuery("input[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
9911 print 'jQuery("textarea[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
9912 print '// required on a select works only if key is "", so we add the required attributes but also we reset the key -1 or 0 to an empty string'."\n";
9913 print 'jQuery("select[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
9914 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'-1\']").prop(\'value\', \'\');'."\n";
9915 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'0\']").prop(\'value\', \'\');'."\n";
9916
9917 // Add 'field required' class on closest td for all input elements : input, textarea and select
9918 print 'jQuery(":input[name=\'' . $paramkey . '\']").closest("tr").find("td:first").addClass("fieldrequired");' . "\n";
9919 }
9920 }
9921 }
9922 }
9923 }
9924
9925 print '});'."\n";
9926
9927 // End of tuning
9928 if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO']) || !empty($conf->global->MAIN_SHOW_TUNING_INFO)) {
9929 print "\n";
9930 print "/* JS CODE TO ENABLE to add memory info */\n";
9931 print 'window.console && console.log("';
9932 if (!empty($conf->global->MEMCACHED_SERVER)) {
9933 print 'MEMCACHED_SERVER='.$conf->global->MEMCACHED_SERVER.' - ';
9934 }
9935 print 'MAIN_OPTIMIZE_SPEED='.(isset($conf->global->MAIN_OPTIMIZE_SPEED) ? $conf->global->MAIN_OPTIMIZE_SPEED : 'off');
9936 if (!empty($micro_start_time)) { // Works only if MAIN_SHOW_TUNING_INFO is defined at $_SERVER level. Not in global variable.
9937 $micro_end_time = microtime(true);
9938 print ' - Build time: '.ceil(1000 * ($micro_end_time - $micro_start_time)).' ms';
9939 }
9940
9941 if (function_exists("memory_get_usage")) {
9942 print ' - Mem: '.memory_get_usage(); // Do not use true here, it seems it takes the peak amount
9943 }
9944 if (function_exists("memory_get_peak_usage")) {
9945 print ' - Real mem peak: '.memory_get_peak_usage(true);
9946 }
9947 if (function_exists("zend_loader_file_encoded")) {
9948 print ' - Zend encoded file: '.(zend_loader_file_encoded() ? 'yes' : 'no');
9949 }
9950 print '");'."\n";
9951 }
9952
9953 print "\n".'</script>'."\n";
9954
9955 // Google Analytics
9956 // TODO Add a hook here
9957 if (isModEnabled('google') && !empty($conf->global->MAIN_GOOGLE_AN_ID)) {
9958 $tmptagarray = explode(',', $conf->global->MAIN_GOOGLE_AN_ID);
9959 foreach ($tmptagarray as $tmptag) {
9960 print "\n";
9961 print "<!-- JS CODE TO ENABLE for google analtics tag -->\n";
9962 print '
9963 <!-- Global site tag (gtag.js) - Google Analytics -->
9964 <script nonce="'.getNonce().'" async src="https://www.googletagmanager.com/gtag/js?id='.trim($tmptag).'"></script>
9965 <script>
9966 window.dataLayer = window.dataLayer || [];
9967 function gtag(){dataLayer.push(arguments);}
9968 gtag(\'js\', new Date());
9969
9970 gtag(\'config\', \''.trim($tmptag).'\');
9971 </script>';
9972 print "\n";
9973 }
9974 }
9975 }
9976
9977 // Add Xdebug coverage of code
9978 if (defined('XDEBUGCOVERAGE')) {
9979 print_r(xdebug_get_code_coverage());
9980 }
9981
9982 // Add DebugBar data
9983 if (!empty($user->rights->debugbar->read) && is_object($debugbar)) {
9984 $debugbar['time']->stopMeasure('pageaftermaster');
9985 print '<!-- Output debugbar data -->'."\n";
9986 $renderer = $debugbar->getRenderer();
9987 print $debugbar->getRenderer()->render();
9988 } elseif (count($conf->logbuffer)) { // If there is some logs in buffer to show
9989 print "\n";
9990 print "<!-- Start of log output\n";
9991 //print '<div class="hidden">'."\n";
9992 foreach ($conf->logbuffer as $logline) {
9993 print $logline."<br>\n";
9994 }
9995 //print '</div>'."\n";
9996 print "End of log output -->\n";
9997 }
9998 }
9999}
10000
10010function dolExplodeIntoArray($string, $delimiter = ';', $kv = '=')
10011{
10012 if (is_null($string)) {
10013 return array();
10014 }
10015
10016 if (preg_match('/^\[.*\]$/sm', $delimiter) || preg_match('/^\‍(.*\‍)$/sm', $delimiter)) {
10017 // This is a regex string
10018 $newdelimiter = $delimiter;
10019 } else {
10020 // This is a simple string
10021 $newdelimiter = preg_quote($delimiter, '/');
10022 }
10023
10024 if ($a = preg_split('/'.$newdelimiter.'/', $string)) {
10025 $ka = array();
10026 foreach ($a as $s) { // each part
10027 if ($s) {
10028 if ($pos = strpos($s, $kv)) { // key/value delimiter
10029 $ka[trim(substr($s, 0, $pos))] = trim(substr($s, $pos + strlen($kv)));
10030 } else { // key delimiter not found
10031 $ka[] = trim($s);
10032 }
10033 }
10034 }
10035 return $ka;
10036 }
10037
10038 return array();
10039}
10040
10041
10048function dol_set_focus($selector)
10049{
10050 print "\n".'<!-- Set focus onto a specific field -->'."\n";
10051 print '<script nonce="'.getNonce().'">jQuery(document).ready(function() { jQuery("'.dol_escape_js($selector).'").focus(); });</script>'."\n";
10052}
10053
10054
10062function dol_getmypid()
10063{
10064 if (!function_exists('getmypid')) {
10065 return mt_rand(99900000, 99965535);
10066 } else {
10067 return getmypid(); // May be a number on 64 bits (depending on OS)
10068 }
10069}
10070
10071
10089function natural_search($fields, $value, $mode = 0, $nofirstand = 0)
10090{
10091 global $db, $langs;
10092
10093 $value = trim($value);
10094
10095 if ($mode == 0) {
10096 $value = preg_replace('/\*/', '%', $value); // Replace * with %
10097 }
10098 if ($mode == 1) {
10099 $value = preg_replace('/([!<>=]+)\s+([0-9'.preg_quote($langs->trans("DecimalSeparator"), '/').'\-])/', '\1\2', $value); // Clean string '< 10' into '<10' so we can then explode on space to get all tests to do
10100 }
10101
10102 $value = preg_replace('/\s*\|\s*/', '|', $value);
10103
10104 $crits = explode(' ', $value);
10105 $res = '';
10106 if (!is_array($fields)) {
10107 $fields = array($fields);
10108 }
10109
10110 $i1 = 0; // count the nb of and criteria added (all fields / criterias)
10111 foreach ($crits as $crit) { // Loop on each AND criteria
10112 $crit = trim($crit);
10113 $i2 = 0; // count the nb of valid criteria added for this this first criteria
10114 $newres = '';
10115 foreach ($fields as $field) {
10116 if ($mode == 1) {
10117 $tmpcrits = explode('|', $crit);
10118 $i3 = 0; // count the nb of valid criteria added for this current field
10119 foreach ($tmpcrits as $tmpcrit) {
10120 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10121 continue;
10122 }
10123 $tmpcrit = trim($tmpcrit);
10124
10125 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10126
10127 $operator = '=';
10128 $newcrit = preg_replace('/([!<>=]+)/', '', $tmpcrit);
10129
10130 $reg = array();
10131 preg_match('/([!<>=]+)/', $tmpcrit, $reg);
10132 if (!empty($reg[1])) {
10133 $operator = $reg[1];
10134 }
10135 if ($newcrit != '') {
10136 $numnewcrit = price2num($newcrit);
10137 if (is_numeric($numnewcrit)) {
10138 $newres .= $field.' '.$operator.' '.((float) $numnewcrit); // should be a numeric
10139 } else {
10140 $newres .= '1 = 2'; // force false, we received a corrupted data
10141 }
10142 $i3++; // a criteria was added to string
10143 }
10144 }
10145 $i2++; // a criteria for 1 more field was added to string
10146 } elseif ($mode == 2 || $mode == -2) {
10147 $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer
10148 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -2 ? 'NOT ' : '');
10149 $newres .= $crit ? "IN (".$db->sanitize($db->escape($crit)).")" : "IN (0)";
10150 if ($mode == -2) {
10151 $newres .= ' OR '.$field.' IS NULL';
10152 }
10153 $i2++; // a criteria for 1 more field was added to string
10154 } elseif ($mode == 3 || $mode == -3) {
10155 $tmparray = explode(',', $crit);
10156 if (count($tmparray)) {
10157 $listofcodes = '';
10158 foreach ($tmparray as $val) {
10159 $val = trim($val);
10160 if ($val) {
10161 $listofcodes .= ($listofcodes ? ',' : '');
10162 $listofcodes .= "'".$db->escape($val)."'";
10163 }
10164 }
10165 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -3 ? 'NOT ' : '')."IN (".$db->sanitize($listofcodes, 1).")";
10166 $i2++; // a criteria for 1 more field was added to string
10167 }
10168 if ($mode == -3) {
10169 $newres .= ' OR '.$field.' IS NULL';
10170 }
10171 } elseif ($mode == 4) {
10172 $tmparray = explode(',', $crit);
10173 if (count($tmparray)) {
10174 $listofcodes = '';
10175 foreach ($tmparray as $val) {
10176 $val = trim($val);
10177 if ($val) {
10178 $newres .= ($i2 > 0 ? " OR (" : "(").$field." LIKE '".$db->escape($val).",%'";
10179 $newres .= ' OR '.$field." = '".$db->escape($val)."'";
10180 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val)."'";
10181 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val).",%'";
10182 $newres .= ')';
10183 $i2++; // a criteria for 1 more field was added to string (we can add several citeria for the same field as it is a multiselect search criteria)
10184 }
10185 }
10186 }
10187 } else { // $mode=0
10188 $tmpcrits = explode('|', $crit);
10189 $i3 = 0; // count the nb of valid criteria added for the current couple criteria/field
10190 foreach ($tmpcrits as $tmpcrit) { // loop on each OR criteria
10191 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10192 continue;
10193 }
10194 $tmpcrit = trim($tmpcrit);
10195
10196 if ($tmpcrit == '^$' || strpos($crit, '!') === 0) { // If we search empty, we must combined different OR fields with AND
10197 $newres .= (($i2 > 0 || $i3 > 0) ? ' AND ' : '');
10198 } else {
10199 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10200 }
10201
10202 if (preg_match('/\.(id|rowid)$/', $field)) { // Special case for rowid that is sometimes a ref so used as a search field
10203 $newres .= $field." = ".(is_numeric($tmpcrit) ? ((float) $tmpcrit) : '0');
10204 } else {
10205 $tmpcrit2 = $tmpcrit;
10206 $tmpbefore = '%';
10207 $tmpafter = '%';
10208 $tmps = '';
10209
10210 if (preg_match('/^!/', $tmpcrit)) {
10211 $tmps .= $field." NOT LIKE "; // ! as exclude character
10212 $tmpcrit2 = preg_replace('/^!/', '', $tmpcrit2);
10213 } else {
10214 $tmps .= $field." LIKE ";
10215 }
10216 $tmps .= "'";
10217
10218 if (preg_match('/^[\^\$]/', $tmpcrit)) {
10219 $tmpbefore = '';
10220 $tmpcrit2 = preg_replace('/^[\^\$]/', '', $tmpcrit2);
10221 }
10222 if (preg_match('/[\^\$]$/', $tmpcrit)) {
10223 $tmpafter = '';
10224 $tmpcrit2 = preg_replace('/[\^\$]$/', '', $tmpcrit2);
10225 }
10226
10227 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10228 $tmps = "(".$tmps;
10229 }
10230 $newres .= $tmps;
10231 $newres .= $tmpbefore;
10232 $newres .= $db->escape($tmpcrit2);
10233 $newres .= $tmpafter;
10234 $newres .= "'";
10235 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10236 $newres .= " OR ".$field." IS NULL)";
10237 }
10238 }
10239
10240 $i3++;
10241 }
10242
10243 $i2++; // a criteria for 1 more field was added to string
10244 }
10245 }
10246
10247 if ($newres) {
10248 $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : '');
10249 }
10250 $i1++;
10251 }
10252 $res = ($nofirstand ? "" : " AND ")."(".$res.")";
10253
10254 return $res;
10255}
10256
10263function showDirectDownloadLink($object)
10264{
10265 global $conf, $langs;
10266
10267 $out = '';
10268 $url = $object->getLastMainDocLink($object->element);
10269
10270 $out .= img_picto($langs->trans("PublicDownloadLinkDesc"), 'globe').' <span class="opacitymedium">'.$langs->trans("DirectDownloadLink").'</span><br>';
10271 if ($url) {
10272 $out .= '<div class="urllink"><input type="text" id="directdownloadlink" class="quatrevingtpercent" value="'.$url.'"></div>';
10273 $out .= ajax_autoselect("directdownloadlink", 0);
10274 } else {
10275 $out .= '<div class="urllink">'.$langs->trans("FileNotShared").'</div>';
10276 }
10277
10278 return $out;
10279}
10280
10289function getImageFileNameForSize($file, $extName, $extImgTarget = '')
10290{
10291 $dirName = dirname($file);
10292 if ($dirName == '.') {
10293 $dirName = '';
10294 }
10295
10296 $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.webp)$/i', '', $file); // We remove extension, whatever is its case
10297 $fileName = basename($fileName);
10298
10299 if (empty($extImgTarget)) {
10300 $extImgTarget = (preg_match('/\.jpg$/i', $file) ? '.jpg' : '');
10301 }
10302 if (empty($extImgTarget)) {
10303 $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '');
10304 }
10305 if (empty($extImgTarget)) {
10306 $extImgTarget = (preg_match('/\.gif$/i', $file) ? '.gif' : '');
10307 }
10308 if (empty($extImgTarget)) {
10309 $extImgTarget = (preg_match('/\.png$/i', $file) ? '.png' : '');
10310 }
10311 if (empty($extImgTarget)) {
10312 $extImgTarget = (preg_match('/\.bmp$/i', $file) ? '.bmp' : '');
10313 }
10314 if (empty($extImgTarget)) {
10315 $extImgTarget = (preg_match('/\.webp$/i', $file) ? '.webp' : '');
10316 }
10317
10318 if (!$extImgTarget) {
10319 return $file;
10320 }
10321
10322 $subdir = '';
10323 if ($extName) {
10324 $subdir = 'thumbs/';
10325 }
10326
10327 return ($dirName ? $dirName.'/' : '').$subdir.$fileName.$extName.$extImgTarget; // New filename for thumb
10328}
10329
10330
10340function getAdvancedPreviewUrl($modulepart, $relativepath, $alldata = 0, $param = '')
10341{
10342 global $conf, $langs;
10343
10344 if (empty($conf->use_javascript_ajax)) {
10345 return '';
10346 }
10347
10348 $isAllowedForPreview = dolIsAllowedForPreview($relativepath);
10349
10350 if ($alldata == 1) {
10351 if ($isAllowedForPreview) {
10352 return array('target'=>'_blank', 'css'=>'documentpreview', 'url'=>DOL_URL_ROOT.'/document.php?modulepart='.$modulepart.'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : ''), 'mime'=>dol_mimetype($relativepath));
10353 } else {
10354 return array();
10355 }
10356 }
10357
10358 // old behavior, return a string
10359 if ($isAllowedForPreview) {
10360 return 'javascript:document_preview(\''.dol_escape_js(DOL_URL_ROOT.'/document.php?modulepart='.$modulepart.'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : '')).'\', \''.dol_mimetype($relativepath).'\', \''.dol_escape_js($langs->trans('Preview')).'\')';
10361 } else {
10362 return '';
10363 }
10364}
10365
10366
10375function ajax_autoselect($htmlname, $addlink = '', $textonlink = 'Link')
10376{
10377 global $langs;
10378 $out = '<script nonce="'.getNonce().'">
10379 jQuery(document).ready(function () {
10380 jQuery("'.((strpos($htmlname, '.') === 0 ? '' : '#').$htmlname).'").click(function() { jQuery(this).select(); } );
10381 });
10382 </script>';
10383 if ($addlink) {
10384 if ($textonlink === 'image') {
10385 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.img_picto('', 'globe').'</a>';
10386 } else {
10387 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.$langs->trans("Link").'</a>';
10388 }
10389 }
10390 return $out;
10391}
10392
10401{
10402 global $conf;
10403
10404 // Check .noexe extension in filename
10405 if (preg_match('/\.noexe$/i', $file)) {
10406 return 0;
10407 }
10408
10409 // Check mime types
10410 $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'webp');
10411 if (!empty($conf->global->MAIN_ALLOW_SVG_FILES_AS_IMAGES)) {
10412 $mime_preview[] = 'svg+xml';
10413 }
10414 //$mime_preview[]='vnd.oasis.opendocument.presentation';
10415 //$mime_preview[]='archive';
10416 $num_mime = array_search(dol_mimetype($file, '', 1), $mime_preview);
10417 if ($num_mime !== false) {
10418 return 1;
10419 }
10420
10421 // By default, not allowed for preview
10422 return 0;
10423}
10424
10425
10435function dol_mimetype($file, $default = 'application/octet-stream', $mode = 0)
10436{
10437 $mime = $default;
10438 $imgmime = 'other.png';
10439 $famime = 'file-o';
10440 $srclang = '';
10441
10442 $tmpfile = preg_replace('/\.noexe$/', '', $file);
10443
10444 // Plain text files
10445 if (preg_match('/\.txt$/i', $tmpfile)) {
10446 $mime = 'text/plain';
10447 $imgmime = 'text.png';
10448 $famime = 'file-text-o';
10449 }
10450 if (preg_match('/\.rtx$/i', $tmpfile)) {
10451 $mime = 'text/richtext';
10452 $imgmime = 'text.png';
10453 $famime = 'file-text-o';
10454 }
10455 if (preg_match('/\.csv$/i', $tmpfile)) {
10456 $mime = 'text/csv';
10457 $imgmime = 'text.png';
10458 $famime = 'file-text-o';
10459 }
10460 if (preg_match('/\.tsv$/i', $tmpfile)) {
10461 $mime = 'text/tab-separated-values';
10462 $imgmime = 'text.png';
10463 $famime = 'file-text-o';
10464 }
10465 if (preg_match('/\.(cf|conf|log)$/i', $tmpfile)) {
10466 $mime = 'text/plain';
10467 $imgmime = 'text.png';
10468 $famime = 'file-text-o';
10469 }
10470 if (preg_match('/\.ini$/i', $tmpfile)) {
10471 $mime = 'text/plain';
10472 $imgmime = 'text.png';
10473 $srclang = 'ini';
10474 $famime = 'file-text-o';
10475 }
10476 if (preg_match('/\.md$/i', $tmpfile)) {
10477 $mime = 'text/plain';
10478 $imgmime = 'text.png';
10479 $srclang = 'md';
10480 $famime = 'file-text-o';
10481 }
10482 if (preg_match('/\.css$/i', $tmpfile)) {
10483 $mime = 'text/css';
10484 $imgmime = 'css.png';
10485 $srclang = 'css';
10486 $famime = 'file-text-o';
10487 }
10488 if (preg_match('/\.lang$/i', $tmpfile)) {
10489 $mime = 'text/plain';
10490 $imgmime = 'text.png';
10491 $srclang = 'lang';
10492 $famime = 'file-text-o';
10493 }
10494 // Certificate files
10495 if (preg_match('/\.(crt|cer|key|pub)$/i', $tmpfile)) {
10496 $mime = 'text/plain';
10497 $imgmime = 'text.png';
10498 $famime = 'file-text-o';
10499 }
10500 // XML based (HTML/XML/XAML)
10501 if (preg_match('/\.(html|htm|shtml)$/i', $tmpfile)) {
10502 $mime = 'text/html';
10503 $imgmime = 'html.png';
10504 $srclang = 'html';
10505 $famime = 'file-text-o';
10506 }
10507 if (preg_match('/\.(xml|xhtml)$/i', $tmpfile)) {
10508 $mime = 'text/xml';
10509 $imgmime = 'other.png';
10510 $srclang = 'xml';
10511 $famime = 'file-text-o';
10512 }
10513 if (preg_match('/\.xaml$/i', $tmpfile)) {
10514 $mime = 'text/xml';
10515 $imgmime = 'other.png';
10516 $srclang = 'xaml';
10517 $famime = 'file-text-o';
10518 }
10519 // Languages
10520 if (preg_match('/\.bas$/i', $tmpfile)) {
10521 $mime = 'text/plain';
10522 $imgmime = 'text.png';
10523 $srclang = 'bas';
10524 $famime = 'file-code-o';
10525 }
10526 if (preg_match('/\.(c)$/i', $tmpfile)) {
10527 $mime = 'text/plain';
10528 $imgmime = 'text.png';
10529 $srclang = 'c';
10530 $famime = 'file-code-o';
10531 }
10532 if (preg_match('/\.(cpp)$/i', $tmpfile)) {
10533 $mime = 'text/plain';
10534 $imgmime = 'text.png';
10535 $srclang = 'cpp';
10536 $famime = 'file-code-o';
10537 }
10538 if (preg_match('/\.cs$/i', $tmpfile)) {
10539 $mime = 'text/plain';
10540 $imgmime = 'text.png';
10541 $srclang = 'cs';
10542 $famime = 'file-code-o';
10543 }
10544 if (preg_match('/\.(h)$/i', $tmpfile)) {
10545 $mime = 'text/plain';
10546 $imgmime = 'text.png';
10547 $srclang = 'h';
10548 $famime = 'file-code-o';
10549 }
10550 if (preg_match('/\.(java|jsp)$/i', $tmpfile)) {
10551 $mime = 'text/plain';
10552 $imgmime = 'text.png';
10553 $srclang = 'java';
10554 $famime = 'file-code-o';
10555 }
10556 if (preg_match('/\.php([0-9]{1})?$/i', $tmpfile)) {
10557 $mime = 'text/plain';
10558 $imgmime = 'php.png';
10559 $srclang = 'php';
10560 $famime = 'file-code-o';
10561 }
10562 if (preg_match('/\.phtml$/i', $tmpfile)) {
10563 $mime = 'text/plain';
10564 $imgmime = 'php.png';
10565 $srclang = 'php';
10566 $famime = 'file-code-o';
10567 }
10568 if (preg_match('/\.(pl|pm)$/i', $tmpfile)) {
10569 $mime = 'text/plain';
10570 $imgmime = 'pl.png';
10571 $srclang = 'perl';
10572 $famime = 'file-code-o';
10573 }
10574 if (preg_match('/\.sql$/i', $tmpfile)) {
10575 $mime = 'text/plain';
10576 $imgmime = 'text.png';
10577 $srclang = 'sql';
10578 $famime = 'file-code-o';
10579 }
10580 if (preg_match('/\.js$/i', $tmpfile)) {
10581 $mime = 'text/x-javascript';
10582 $imgmime = 'jscript.png';
10583 $srclang = 'js';
10584 $famime = 'file-code-o';
10585 }
10586 // Open office
10587 if (preg_match('/\.odp$/i', $tmpfile)) {
10588 $mime = 'application/vnd.oasis.opendocument.presentation';
10589 $imgmime = 'ooffice.png';
10590 $famime = 'file-powerpoint-o';
10591 }
10592 if (preg_match('/\.ods$/i', $tmpfile)) {
10593 $mime = 'application/vnd.oasis.opendocument.spreadsheet';
10594 $imgmime = 'ooffice.png';
10595 $famime = 'file-excel-o';
10596 }
10597 if (preg_match('/\.odt$/i', $tmpfile)) {
10598 $mime = 'application/vnd.oasis.opendocument.text';
10599 $imgmime = 'ooffice.png';
10600 $famime = 'file-word-o';
10601 }
10602 // MS Office
10603 if (preg_match('/\.mdb$/i', $tmpfile)) {
10604 $mime = 'application/msaccess';
10605 $imgmime = 'mdb.png';
10606 $famime = 'file-o';
10607 }
10608 if (preg_match('/\.doc[xm]?$/i', $tmpfile)) {
10609 $mime = 'application/msword';
10610 $imgmime = 'doc.png';
10611 $famime = 'file-word-o';
10612 }
10613 if (preg_match('/\.dot[xm]?$/i', $tmpfile)) {
10614 $mime = 'application/msword';
10615 $imgmime = 'doc.png';
10616 $famime = 'file-word-o';
10617 }
10618 if (preg_match('/\.xlt(x)?$/i', $tmpfile)) {
10619 $mime = 'application/vnd.ms-excel';
10620 $imgmime = 'xls.png';
10621 $famime = 'file-excel-o';
10622 }
10623 if (preg_match('/\.xla(m)?$/i', $tmpfile)) {
10624 $mime = 'application/vnd.ms-excel';
10625 $imgmime = 'xls.png';
10626 $famime = 'file-excel-o';
10627 }
10628 if (preg_match('/\.xls$/i', $tmpfile)) {
10629 $mime = 'application/vnd.ms-excel';
10630 $imgmime = 'xls.png';
10631 $famime = 'file-excel-o';
10632 }
10633 if (preg_match('/\.xls[bmx]$/i', $tmpfile)) {
10634 $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
10635 $imgmime = 'xls.png';
10636 $famime = 'file-excel-o';
10637 }
10638 if (preg_match('/\.pps[mx]?$/i', $tmpfile)) {
10639 $mime = 'application/vnd.ms-powerpoint';
10640 $imgmime = 'ppt.png';
10641 $famime = 'file-powerpoint-o';
10642 }
10643 if (preg_match('/\.ppt[mx]?$/i', $tmpfile)) {
10644 $mime = 'application/x-mspowerpoint';
10645 $imgmime = 'ppt.png';
10646 $famime = 'file-powerpoint-o';
10647 }
10648 // Other
10649 if (preg_match('/\.pdf$/i', $tmpfile)) {
10650 $mime = 'application/pdf';
10651 $imgmime = 'pdf.png';
10652 $famime = 'file-pdf-o';
10653 }
10654 // Scripts
10655 if (preg_match('/\.bat$/i', $tmpfile)) {
10656 $mime = 'text/x-bat';
10657 $imgmime = 'script.png';
10658 $srclang = 'dos';
10659 $famime = 'file-code-o';
10660 }
10661 if (preg_match('/\.sh$/i', $tmpfile)) {
10662 $mime = 'text/x-sh';
10663 $imgmime = 'script.png';
10664 $srclang = 'bash';
10665 $famime = 'file-code-o';
10666 }
10667 if (preg_match('/\.ksh$/i', $tmpfile)) {
10668 $mime = 'text/x-ksh';
10669 $imgmime = 'script.png';
10670 $srclang = 'bash';
10671 $famime = 'file-code-o';
10672 }
10673 if (preg_match('/\.bash$/i', $tmpfile)) {
10674 $mime = 'text/x-bash';
10675 $imgmime = 'script.png';
10676 $srclang = 'bash';
10677 $famime = 'file-code-o';
10678 }
10679 // Images
10680 if (preg_match('/\.ico$/i', $tmpfile)) {
10681 $mime = 'image/x-icon';
10682 $imgmime = 'image.png';
10683 $famime = 'file-image-o';
10684 }
10685 if (preg_match('/\.(jpg|jpeg)$/i', $tmpfile)) {
10686 $mime = 'image/jpeg';
10687 $imgmime = 'image.png';
10688 $famime = 'file-image-o';
10689 }
10690 if (preg_match('/\.png$/i', $tmpfile)) {
10691 $mime = 'image/png';
10692 $imgmime = 'image.png';
10693 $famime = 'file-image-o';
10694 }
10695 if (preg_match('/\.gif$/i', $tmpfile)) {
10696 $mime = 'image/gif';
10697 $imgmime = 'image.png';
10698 $famime = 'file-image-o';
10699 }
10700 if (preg_match('/\.bmp$/i', $tmpfile)) {
10701 $mime = 'image/bmp';
10702 $imgmime = 'image.png';
10703 $famime = 'file-image-o';
10704 }
10705 if (preg_match('/\.(tif|tiff)$/i', $tmpfile)) {
10706 $mime = 'image/tiff';
10707 $imgmime = 'image.png';
10708 $famime = 'file-image-o';
10709 }
10710 if (preg_match('/\.svg$/i', $tmpfile)) {
10711 $mime = 'image/svg+xml';
10712 $imgmime = 'image.png';
10713 $famime = 'file-image-o';
10714 }
10715 if (preg_match('/\.webp$/i', $tmpfile)) {
10716 $mime = 'image/webp';
10717 $imgmime = 'image.png';
10718 $famime = 'file-image-o';
10719 }
10720 // Calendar
10721 if (preg_match('/\.vcs$/i', $tmpfile)) {
10722 $mime = 'text/calendar';
10723 $imgmime = 'other.png';
10724 $famime = 'file-text-o';
10725 }
10726 if (preg_match('/\.ics$/i', $tmpfile)) {
10727 $mime = 'text/calendar';
10728 $imgmime = 'other.png';
10729 $famime = 'file-text-o';
10730 }
10731 // Other
10732 if (preg_match('/\.torrent$/i', $tmpfile)) {
10733 $mime = 'application/x-bittorrent';
10734 $imgmime = 'other.png';
10735 $famime = 'file-o';
10736 }
10737 // Audio
10738 if (preg_match('/\.(mp3|ogg|au|wav|wma|mid)$/i', $tmpfile)) {
10739 $mime = 'audio';
10740 $imgmime = 'audio.png';
10741 $famime = 'file-audio-o';
10742 }
10743 // Video
10744 if (preg_match('/\.mp4$/i', $tmpfile)) {
10745 $mime = 'video/mp4';
10746 $imgmime = 'video.png';
10747 $famime = 'file-video-o';
10748 }
10749 if (preg_match('/\.ogv$/i', $tmpfile)) {
10750 $mime = 'video/ogg';
10751 $imgmime = 'video.png';
10752 $famime = 'file-video-o';
10753 }
10754 if (preg_match('/\.webm$/i', $tmpfile)) {
10755 $mime = 'video/webm';
10756 $imgmime = 'video.png';
10757 $famime = 'file-video-o';
10758 }
10759 if (preg_match('/\.avi$/i', $tmpfile)) {
10760 $mime = 'video/x-msvideo';
10761 $imgmime = 'video.png';
10762 $famime = 'file-video-o';
10763 }
10764 if (preg_match('/\.divx$/i', $tmpfile)) {
10765 $mime = 'video/divx';
10766 $imgmime = 'video.png';
10767 $famime = 'file-video-o';
10768 }
10769 if (preg_match('/\.xvid$/i', $tmpfile)) {
10770 $mime = 'video/xvid';
10771 $imgmime = 'video.png';
10772 $famime = 'file-video-o';
10773 }
10774 if (preg_match('/\.(wmv|mpg|mpeg)$/i', $tmpfile)) {
10775 $mime = 'video';
10776 $imgmime = 'video.png';
10777 $famime = 'file-video-o';
10778 }
10779 // Archive
10780 if (preg_match('/\.(zip|rar|gz|tgz|z|cab|bz2|7z|tar|lzh|zst)$/i', $tmpfile)) {
10781 $mime = 'archive';
10782 $imgmime = 'archive.png';
10783 $famime = 'file-archive-o';
10784 } // application/xxx where zzz is zip, ...
10785 // Exe
10786 if (preg_match('/\.(exe|com)$/i', $tmpfile)) {
10787 $mime = 'application/octet-stream';
10788 $imgmime = 'other.png';
10789 $famime = 'file-o';
10790 }
10791 // Lib
10792 if (preg_match('/\.(dll|lib|o|so|a)$/i', $tmpfile)) {
10793 $mime = 'library';
10794 $imgmime = 'library.png';
10795 $famime = 'file-o';
10796 }
10797 // Err
10798 if (preg_match('/\.err$/i', $tmpfile)) {
10799 $mime = 'error';
10800 $imgmime = 'error.png';
10801 $famime = 'file-text-o';
10802 }
10803
10804 // Return string
10805 if ($mode == 1) {
10806 $tmp = explode('/', $mime);
10807 return (!empty($tmp[1]) ? $tmp[1] : $tmp[0]);
10808 }
10809 if ($mode == 2) {
10810 return $imgmime;
10811 }
10812 if ($mode == 3) {
10813 return $srclang;
10814 }
10815 if ($mode == 4) {
10816 return $famime;
10817 }
10818 return $mime;
10819}
10820
10832function getDictionaryValue($tablename, $field, $id, $checkentity = false, $rowidfield = 'rowid')
10833{
10834 global $conf, $db;
10835
10836 $tablename = preg_replace('/^'.preg_quote(MAIN_DB_PREFIX, '/').'/', '', $tablename); // Clean name of table for backward compatibility.
10837
10838 $dictvalues = (isset($conf->cache['dictvalues_'.$tablename]) ? $conf->cache['dictvalues_'.$tablename] : null);
10839
10840 if (is_null($dictvalues)) {
10841 $dictvalues = array();
10842
10843 $sql = "SELECT * FROM ".MAIN_DB_PREFIX.$tablename." WHERE 1 = 1"; // Here select * is allowed as it is generic code and we don't have list of fields
10844 if ($checkentity) {
10845 $sql .= ' AND entity IN (0,'.getEntity($tablename).')';
10846 }
10847
10848 $resql = $db->query($sql);
10849 if ($resql) {
10850 while ($obj = $db->fetch_object($resql)) {
10851 $dictvalues[$obj->{$rowidfield}] = $obj; // $obj is stdClass
10852 }
10853 } else {
10854 dol_print_error($db);
10855 }
10856
10857 $conf->cache['dictvalues_'.$tablename] = $dictvalues;
10858 }
10859
10860 if (!empty($dictvalues[$id])) {
10861 // Found
10862 $tmp = $dictvalues[$id];
10863 return (property_exists($tmp, $field) ? $tmp->$field : '');
10864 } else {
10865 // Not found
10866 return '';
10867 }
10868}
10869
10876function colorIsLight($stringcolor)
10877{
10878 $stringcolor = str_replace('#', '', $stringcolor);
10879 $res = -1;
10880 if (!empty($stringcolor)) {
10881 $res = 0;
10882 $tmp = explode(',', $stringcolor);
10883 if (count($tmp) > 1) { // This is a comma RGB ('255','255','255')
10884 $r = $tmp[0];
10885 $g = $tmp[1];
10886 $b = $tmp[2];
10887 } else {
10888 $hexr = $stringcolor[0].$stringcolor[1];
10889 $hexg = $stringcolor[2].$stringcolor[3];
10890 $hexb = $stringcolor[4].$stringcolor[5];
10891 $r = hexdec($hexr);
10892 $g = hexdec($hexg);
10893 $b = hexdec($hexb);
10894 }
10895 $bright = (max($r, $g, $b) + min($r, $g, $b)) / 510.0; // HSL algorithm
10896 if ($bright > 0.6) {
10897 $res = 1;
10898 }
10899 }
10900 return $res;
10901}
10902
10911function isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
10912{
10913 global $conf;
10914
10915 //print 'type_user='.$type_user.' module='.$menuentry['module'].' enabled='.$menuentry['enabled'].' perms='.$menuentry['perms'];
10916 //print 'ok='.in_array($menuentry['module'], $listofmodulesforexternal);
10917 if (empty($menuentry['enabled'])) {
10918 return 0; // Entry disabled by condition
10919 }
10920 if ($type_user && $menuentry['module']) {
10921 $tmploops = explode('|', $menuentry['module']);
10922 $found = 0;
10923 foreach ($tmploops as $tmploop) {
10924 if (in_array($tmploop, $listofmodulesforexternal)) {
10925 $found++;
10926 break;
10927 }
10928 }
10929 if (!$found) {
10930 return 0; // Entry is for menus all excluded to external users
10931 }
10932 }
10933 if (!$menuentry['perms'] && $type_user) {
10934 return 0; // No permissions and user is external
10935 }
10936 if (!$menuentry['perms'] && !empty($conf->global->MAIN_MENU_HIDE_UNAUTHORIZED)) {
10937 return 0; // No permissions and option to hide when not allowed, even for internal user, is on
10938 }
10939 if (!$menuentry['perms']) {
10940 return 2; // No permissions and user is external
10941 }
10942 return 1;
10943}
10944
10952function roundUpToNextMultiple($n, $x = 5)
10953{
10954 return (ceil($n) % $x === 0) ? ceil($n) : round(($n + $x / 2) / $x) * $x;
10955}
10956
10968function dolGetBadge($label, $html = '', $type = 'primary', $mode = '', $url = '', $params = array())
10969{
10970 $attr = array(
10971 'class'=>'badge '.(!empty($mode) ? ' badge-'.$mode : '').(!empty($type) ? ' badge-'.$type : '').(empty($params['css']) ? '' : ' '.$params['css'])
10972 );
10973
10974 if (empty($html)) {
10975 $html = $label;
10976 }
10977
10978 if (!empty($url)) {
10979 $attr['href'] = $url;
10980 }
10981
10982 if ($mode === 'dot') {
10983 $attr['class'] .= ' classfortooltip';
10984 $attr['title'] = $html;
10985 $attr['aria-label'] = $label;
10986 $html = '';
10987 }
10988
10989 // Override attr
10990 if (!empty($params['attr']) && is_array($params['attr'])) {
10991 foreach ($params['attr'] as $key => $value) {
10992 if ($key == 'class') {
10993 $attr['class'] .= ' '.$value;
10994 } elseif ($key == 'classOverride') {
10995 $attr['class'] = $value;
10996 } else {
10997 $attr[$key] = $value;
10998 }
10999 }
11000 }
11001
11002 // TODO: add hook
11003
11004 // escape all attribute
11005 $attr = array_map('dol_escape_htmltag', $attr);
11006
11007 $TCompiledAttr = array();
11008 foreach ($attr as $key => $value) {
11009 $TCompiledAttr[] = $key.'="'.$value.'"';
11010 }
11011
11012 $compiledAttributes = !empty($TCompiledAttr) ?implode(' ', $TCompiledAttr) : '';
11013
11014 $tag = !empty($url) ? 'a' : 'span';
11015
11016 return '<'.$tag.' '.$compiledAttributes.'>'.$html.'</'.$tag.'>';
11017}
11018
11019
11032function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $statusType = 'status0', $displayMode = 0, $url = '', $params = array())
11033{
11034 global $conf;
11035
11036 $return = '';
11037 $dolGetBadgeParams = array();
11038
11039 if (!empty($params['badgeParams'])) {
11040 $dolGetBadgeParams = $params['badgeParams'];
11041 }
11042
11043 // TODO : add a hook
11044 if ($displayMode == 0) {
11045 $return = !empty($html) ? $html : (empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort));
11046 } elseif ($displayMode == 1) {
11047 $return = !empty($html) ? $html : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11048 } elseif (!empty($conf->global->MAIN_STATUS_USES_IMAGES)) {
11049 // Use status with images (for backward compatibility)
11050 $return = '';
11051 $htmlLabel = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : $statusLabel).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
11052 $htmlLabelShort = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : (!empty($statusLabelShort) ? $statusLabelShort : $statusLabel)).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
11053
11054 // For small screen, we always use the short label instead of long label.
11055 if (!empty($conf->dol_optimize_smallscreen)) {
11056 if ($displayMode == 0) {
11057 $displayMode = 1;
11058 } elseif ($displayMode == 4) {
11059 $displayMode = 2;
11060 } elseif ($displayMode == 6) {
11061 $displayMode = 5;
11062 }
11063 }
11064
11065 // For backward compatibility. Image's filename are still in French, so we use this array to convert
11066 $statusImg = array(
11067 'status0' => 'statut0',
11068 'status1' => 'statut1',
11069 'status2' => 'statut2',
11070 'status3' => 'statut3',
11071 'status4' => 'statut4',
11072 'status5' => 'statut5',
11073 'status6' => 'statut6',
11074 'status7' => 'statut7',
11075 'status8' => 'statut8',
11076 'status9' => 'statut9'
11077 );
11078
11079 if (!empty($statusImg[$statusType])) {
11080 $htmlImg = img_picto($statusLabel, $statusImg[$statusType]);
11081 } else {
11082 $htmlImg = img_picto($statusLabel, $statusType);
11083 }
11084
11085 if ($displayMode === 2) {
11086 $return = $htmlImg.' '.$htmlLabelShort;
11087 } elseif ($displayMode === 3) {
11088 $return = $htmlImg;
11089 } elseif ($displayMode === 4) {
11090 $return = $htmlImg.' '.$htmlLabel;
11091 } elseif ($displayMode === 5) {
11092 $return = $htmlLabelShort.' '.$htmlImg;
11093 } else { // $displayMode >= 6
11094 $return = $htmlLabel.' '.$htmlImg;
11095 }
11096 } elseif (empty($conf->global->MAIN_STATUS_USES_IMAGES) && !empty($displayMode)) {
11097 // Use new badge
11098 $statusLabelShort = (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11099
11100 $dolGetBadgeParams['attr']['class'] = 'badge-status';
11101 $dolGetBadgeParams['attr']['title'] = empty($params['tooltip']) ? $statusLabel : ($params['tooltip'] != 'no' ? $params['tooltip'] : '');
11102
11103 if ($displayMode == 3) {
11104 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), '', $statusType, 'dot', $url, $dolGetBadgeParams);
11105 } elseif ($displayMode === 5) {
11106 $return = dolGetBadge($statusLabelShort, $html, $statusType, '', $url, $dolGetBadgeParams);
11107 } else {
11108 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), $html, $statusType, '', $url, $dolGetBadgeParams);
11109 }
11110 }
11111
11112 return $return;
11113}
11114
11115
11150function dolGetButtonAction($label, $text = '', $actionType = 'default', $url = '', $id = '', $userRight = 1, $params = array())
11151{
11152 global $hookmanager, $action, $object, $langs;
11153
11154 // If $url is an array, we must build a dropdown button
11155 if (is_array($url)) {
11156 $out = '<div class="dropdown inline-block dropdown-holder">';
11157 $out .= '<a style="margin-right: auto;" class="dropdown-toggle butAction" data-toggle="dropdown">'.$label.'</a>';
11158 $out .= '<div class="dropdown-content">';
11159 foreach ($url as $subbutton) {
11160 if ($subbutton['enabled'] && $subbutton['perm']) {
11161 if (!empty($subbutton['lang'])) {
11162 $langs->load($subbutton['lang']);
11163 }
11164 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage'])), '', 1, array('isDropDown' => true));
11165 }
11166 }
11167 $out .= "</div>";
11168 $out .= "</div>";
11169
11170 return $out;
11171 }
11172
11173 // If $url is a simple link
11174 if (!empty($params['isDropdown']))
11175 $class = "dropdown-item";
11176 else {
11177 $class = 'butAction';
11178 if ($actionType == 'danger' || $actionType == 'delete') {
11179 $class = 'butActionDelete';
11180 if (!empty($url) && strpos($url, 'token=') === false) $url .= '&token='.newToken();
11181 }
11182 }
11183 $attr = array(
11184 'class' => $class,
11185 'href' => empty($url) ? '' : $url,
11186 'title' => $label
11187 );
11188
11189 if (empty($text)) {
11190 $text = $label;
11191 $attr['title'] = ''; // if html not set, leave label on title is redundant
11192 } else {
11193 $attr['title'] = $label;
11194 $attr['aria-label'] = $label;
11195 }
11196
11197 if (empty($userRight)) {
11198 $attr['class'] = 'butActionRefused';
11199 $attr['href'] = '';
11200 $attr['title'] = (($label && $text && $label != $text) ? $label : $langs->trans('NotEnoughPermissions'));
11201 }
11202
11203 if (!empty($id)) {
11204 $attr['id'] = $id;
11205 }
11206
11207 // Override attr
11208 if (!empty($params['attr']) && is_array($params['attr'])) {
11209 foreach ($params['attr'] as $key => $value) {
11210 if ($key == 'class') {
11211 $attr['class'] .= ' '.$value;
11212 } elseif ($key == 'classOverride') {
11213 $attr['class'] = $value;
11214 } else {
11215 $attr[$key] = $value;
11216 }
11217 }
11218 }
11219
11220 // automatic add tooltip when title is detected
11221 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
11222 $attr['class'].= ' classfortooltip';
11223 }
11224
11225 // Js Confirm button
11226 if ($userRight && !empty($params['confirm'])) {
11227 if (!is_array($params['confirm'])) {
11228 $params['confirm'] = array();
11229 }
11230
11231 if (empty($params['confirm']['url'])) {
11232 $params['confirm']['url'] = $url . (strpos($url, '?') > 0 ? '&' : '?') . 'confirm=yes';
11233 }
11234
11235 // for js desabled compatibility set $url as call to confirm action and $params['confirm']['url'] to confirmed action
11236 $attr['data-confirm-url'] = $params['confirm']['url'];
11237 $attr['data-confirm-title'] = !empty($params['confirm']['title']) ? $params['confirm']['title'] : $langs->trans('ConfirmBtnCommonTitle', $label);
11238 $attr['data-confirm-content'] = !empty($params['confirm']['content']) ? $params['confirm']['content'] : $langs->trans('ConfirmBtnCommonContent', $label);
11239 $attr['data-confirm-content'] = preg_replace("/\r|\n/", "", $attr['data-confirm-content']);
11240 $attr['data-confirm-action-btn-label'] = !empty($params['confirm']['action-btn-label']) ? $params['confirm']['action-btn-label'] : $langs->trans('Confirm');
11241 $attr['data-confirm-cancel-btn-label'] = !empty($params['confirm']['cancel-btn-label']) ? $params['confirm']['cancel-btn-label'] : $langs->trans('CloseDialog');
11242 $attr['data-confirm-modal'] = !empty($params['confirm']['modal']) ? $params['confirm']['modal'] : true;
11243
11244 $attr['class'].= ' butActionConfirm';
11245 }
11246
11247 if (isset($attr['href']) && empty($attr['href'])) {
11248 unset($attr['href']);
11249 }
11250
11251 // escape all attribute
11252 $attr = array_map('dol_escape_htmltag', $attr);
11253
11254 $TCompiledAttr = array();
11255 foreach ($attr as $key => $value) {
11256 $TCompiledAttr[] = $key.'= "'.$value.'"';
11257 }
11258
11259 $compiledAttributes = empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr);
11260
11261 $tag = !empty($attr['href']) ? 'a' : 'span';
11262
11263
11264 $parameters = array(
11265 'TCompiledAttr' => $TCompiledAttr, // array
11266 'compiledAttributes' => $compiledAttributes, // string
11267 'attr' => $attr,
11268 'tag' => $tag,
11269 'label' => $label,
11270 'html' => $text,
11271 'actionType' => $actionType,
11272 'url' => $url,
11273 'id' => $id,
11274 'userRight' => $userRight,
11275 'params' => $params
11276 );
11277
11278 $reshook = $hookmanager->executeHooks('dolGetButtonAction', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
11279 if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
11280
11281 if (empty($reshook)) {
11282 if (dol_textishtml($text)) { // If content already HTML encoded
11283 return '<' . $tag . ' ' . $compiledAttributes . '>' . $text . '</' . $tag . '>';
11284 } else {
11285 return '<' . $tag . ' ' . $compiledAttributes . '>' . dol_escape_htmltag($text) . '</' . $tag . '>';
11286 }
11287 } else {
11288 return $hookmanager->resPrint;
11289 }
11290}
11291
11298function dolGetButtonTitleSeparator($moreClass = "")
11299{
11300 return '<span class="button-title-separator '.$moreClass.'" ></span>';
11301}
11302
11309function getFieldErrorIcon($fieldValidationErrorMsg)
11310{
11311 $out = '';
11312 if (!empty($fieldValidationErrorMsg)) {
11313 $out.= '<span class="field-error-icon classfortooltip" title="'.dol_escape_htmltag($fieldValidationErrorMsg, 1).'" role="alert" >'; // role alert is used for accessibility
11314 $out.= '<span class="fa fa-exclamation-circle" aria-hidden="true" ></span>'; // For accessibility icon is separated and aria-hidden
11315 $out.= '</span>';
11316 }
11317
11318 return $out;
11319}
11320
11333function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $url = '', $id = '', $status = 1, $params = array())
11334{
11335 global $langs, $conf, $user;
11336
11337 // Actually this conf is used in css too for external module compatibility and smooth transition to this function
11338 if (!empty($conf->global->MAIN_BUTTON_HIDE_UNAUTHORIZED) && (!$user->admin) && $status <= 0) {
11339 return '';
11340 }
11341
11342 $class = 'btnTitle';
11343 if (in_array($iconClass, array('fa fa-plus-circle', 'fa fa-plus-circle size15x', 'fa fa-comment-dots', 'fa fa-paper-plane'))) {
11344 $class .= ' btnTitlePlus';
11345 }
11346 $useclassfortooltip = 1;
11347
11348 if (!empty($params['morecss'])) {
11349 $class .= ' '.$params['morecss'];
11350 }
11351
11352 $attr = array(
11353 'class' => $class,
11354 'href' => empty($url) ? '' : $url
11355 );
11356
11357 if (!empty($helpText)) {
11358 $attr['title'] = dol_escape_htmltag($helpText);
11359 } elseif (empty($attr['title']) && $label) {
11360 $attr['title'] = $label;
11361 $useclassfortooltip = 0;
11362 }
11363
11364 if ($status == 2) {
11365 $attr['class'] .= ' btnTitleSelected';
11366 } elseif ($status <= 0) {
11367 $attr['class'] .= ' refused';
11368
11369 $attr['href'] = '';
11370
11371 if ($status == -1) { // disable
11372 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("FeatureDisabled"));
11373 } elseif ($status == 0) { // Not enough permissions
11374 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions"));
11375 }
11376 }
11377
11378 if (!empty($attr['title']) && $useclassfortooltip) {
11379 $attr['class'] .= ' classfortooltip';
11380 }
11381
11382 if (!empty($id)) {
11383 $attr['id'] = $id;
11384 }
11385
11386 // Override attr
11387 if (!empty($params['attr']) && is_array($params['attr'])) {
11388 foreach ($params['attr'] as $key => $value) {
11389 if ($key == 'class') {
11390 $attr['class'] .= ' '.$value;
11391 } elseif ($key == 'classOverride') {
11392 $attr['class'] = $value;
11393 } else {
11394 $attr[$key] = $value;
11395 }
11396 }
11397 }
11398
11399 if (isset($attr['href']) && empty($attr['href'])) {
11400 unset($attr['href']);
11401 }
11402
11403 // TODO : add a hook
11404
11405 // escape all attribute
11406 $attr = array_map('dol_escape_htmltag', $attr);
11407
11408 $TCompiledAttr = array();
11409 foreach ($attr as $key => $value) {
11410 $TCompiledAttr[] = $key.'="'.$value.'"';
11411 }
11412
11413 $compiledAttributes = (empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr));
11414
11415 $tag = (empty($attr['href']) ? 'span' : 'a');
11416
11417 $button = '<'.$tag.' '.$compiledAttributes.'>';
11418 $button .= '<span class="'.$iconClass.' valignmiddle btnTitle-icon"></span>';
11419 if (!empty($params['forcenohideoftext'])) {
11420 $button .= '<span class="valignmiddle text-plus-circle btnTitle-label'.(empty($params['forcenohideoftext']) ? ' hideonsmartphone' : '').'">'.$label.'</span>';
11421 }
11422 $button .= '</'.$tag.'>';
11423
11424 return $button;
11425}
11426
11437function getElementProperties($element_type)
11438{
11439 global $conf;
11440
11441 $regs = array();
11442
11443 $classfile = $classname = $classpath = $subdir = $dir_output = '';
11444
11445 // Parse element/subelement
11446 $module = $element_type;
11447 $element = $element_type;
11448 $subelement = $element_type;
11449
11450 // If we ask a resource form external module (instead of default path)
11451 if (preg_match('/^([^@]+)@([^@]+)$/i', $element_type, $regs)) { // 'myobject@mymodule'
11452 $element = $subelement = $regs[1];
11453 $module = $regs[2];
11454 }
11455
11456 // If we ask a resource for a string with an element and a subelement
11457 // Example 'project_task'
11458 if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { // 'myobject_mysubobject' with myobject=mymodule
11459 $module = $element = $regs[1];
11460 $subelement = $regs[2];
11461 }
11462
11463 // For compat and To work with non standard path
11464 if ($element_type == "action") {
11465 $classpath = 'comm/action/class';
11466 $subelement = 'Actioncomm';
11467 $module = 'agenda';
11468 } elseif ($element_type == 'cronjob') {
11469 $classpath = 'cron/class';
11470 $module = 'cron';
11471 } elseif ($element_type == 'adherent_type') {
11472 $classpath = 'adherents/class';
11473 $classfile = 'adherent_type';
11474 $module = 'adherent';
11475 $subelement = 'adherent_type';
11476 $classname = 'AdherentType';
11477 } elseif ($element_type == 'bank_account') {
11478 $classpath = 'compta/bank/class';
11479 $module = 'bank'; // We need $conf->bank->dir_output and not $conf->banque->dir_output
11480 $classfile = 'account';
11481 $classname = 'Account';
11482 } elseif ($element_type == 'category') {
11483 $classpath = 'categories/class';
11484 $module = 'categorie';
11485 $subelement = 'categorie';
11486 } elseif ($element_type == 'contact') {
11487 $classpath = 'contact/class';
11488 $classfile = 'contact';
11489 $module = 'societe';
11490 $subelement = 'contact';
11491 } elseif ($element_type == 'stock') {
11492 $classpath = 'product/stock/class';
11493 $classfile = 'entrepot';
11494 $classname = 'Entrepot';
11495 } elseif ($element_type == 'project') {
11496 $classpath = 'projet/class';
11497 $module = 'projet';
11498 } elseif ($element_type == 'project_task') {
11499 $classpath = 'projet/class';
11500 $module = 'projet';
11501 $subelement = 'task';
11502 } elseif ($element_type == 'facture' || $element_type == 'invoice') {
11503 $classpath = 'compta/facture/class';
11504 $module = 'facture';
11505 $subelement = 'facture';
11506 } elseif ($element_type == 'commande' || $element_type == 'order') {
11507 $classpath = 'commande/class';
11508 $module = 'commande';
11509 $subelement = 'commande';
11510 } elseif ($element_type == 'propal') {
11511 $classpath = 'comm/propal/class';
11512 } elseif ($element_type == 'shipping') {
11513 $classpath = 'expedition/class';
11514 $classfile = 'expedition';
11515 $classname = 'Expedition';
11516 $module = 'expedition';
11517 } elseif ($element_type == 'supplier_proposal') {
11518 $classpath = 'supplier_proposal/class';
11519 $module = 'supplier_proposal';
11520 $element = 'supplierproposal';
11521 $classfile = 'supplier_proposal';
11522 $subelement = 'supplierproposal';
11523 } elseif ($element_type == 'shipping') {
11524 $classpath = 'expedition/class';
11525 $subelement = 'expedition';
11526 $module = 'expedition_bon';
11527 } elseif ($element_type == 'delivery') {
11528 $classpath = 'delivery/class';
11529 $subelement = 'delivery';
11530 $module = 'delivery_note';
11531 } elseif ($element_type == 'contract') {
11532 $classpath = 'contrat/class';
11533 $module = 'contrat';
11534 $subelement = 'contrat';
11535 } elseif ($element_type == 'mailing') {
11536 $classpath = 'comm/mailing/class';
11537 $module = 'mailing';
11538 $classfile = 'mailing';
11539 $classname = 'Mailing';
11540 $subelement = '';
11541 } elseif ($element_type == 'member') {
11542 $classpath = 'adherents/class';
11543 $module = 'adherent';
11544 $subelement = 'adherent';
11545 } elseif ($element_type == 'usergroup') {
11546 $classpath = 'user/class';
11547 $module = 'user';
11548 } elseif ($element_type == 'mo') {
11549 $classpath = 'mrp/class';
11550 $classfile = 'mo';
11551 $classname = 'Mo';
11552 $module = 'mrp';
11553 $subelement = '';
11554 } elseif ($element_type == 'cabinetmed_cons') {
11555 $classpath = 'cabinetmed/class';
11556 $module = 'cabinetmed';
11557 $subelement = 'cabinetmedcons';
11558 } elseif ($element_type == 'fichinter') {
11559 $classpath = 'fichinter/class';
11560 $module = 'ficheinter';
11561 $subelement = 'fichinter';
11562 } elseif ($element_type == 'dolresource' || $element_type == 'resource') {
11563 $classpath = 'resource/class';
11564 $module = 'resource';
11565 $subelement = 'dolresource';
11566 } elseif ($element_type == 'propaldet') {
11567 $classpath = 'comm/propal/class';
11568 $module = 'propal';
11569 $subelement = 'propaleligne';
11570 } elseif ($element_type == 'opensurvey_sondage') {
11571 $classpath = 'opensurvey/class';
11572 $module = 'opensurvey';
11573 $subelement = 'opensurveysondage';
11574 } elseif ($element_type == 'order_supplier') {
11575 $classpath = 'fourn/class';
11576 $module = 'fournisseur';
11577 $classfile = 'fournisseur.commande';
11578 $element = 'order_supplier';
11579 $subelement = '';
11580 $classname = 'CommandeFournisseur';
11581 } elseif ($element_type == 'invoice_supplier') {
11582 $classpath = 'fourn/class';
11583 $module = 'fournisseur';
11584 $classfile = 'fournisseur.facture';
11585 $element = 'invoice_supplier';
11586 $subelement = '';
11587 $classname = 'FactureFournisseur';
11588 } elseif ($element_type == "service") {
11589 $classpath = 'product/class';
11590 $subelement = 'product';
11591 } elseif ($element_type == 'salary') {
11592 $classpath = 'salaries/class';
11593 $module = 'salaries';
11594 } elseif ($element_type == 'productlot') {
11595 $module = 'productbatch';
11596 $classpath = 'product/stock/class';
11597 $classfile = 'productlot';
11598 $classname = 'Productlot';
11599 $element = 'productlot';
11600 $subelement = '';
11601 } elseif ($element_type == 'websitepage') {
11602 $classpath = 'website/class';
11603 $classfile = 'websitepage';
11604 $classname = 'Websitepage';
11605 $module = 'website';
11606 $subelement = 'websitepage';
11607 } elseif ($element_type == 'fiscalyear') {
11608 $classpath = 'core/class';
11609 $module = 'accounting';
11610 $subelement = 'fiscalyear';
11611 } elseif ($element_type == 'chargesociales') {
11612 $classpath = 'compta/sociales/class';
11613 $module = 'tax';
11614 } elseif ($element_type == 'tva') {
11615 $classpath = 'compta/tva/class';
11616 $module = 'tax';
11617 $subdir = '/vat';
11618 }
11619
11620 if (empty($classfile)) {
11621 $classfile = strtolower($subelement);
11622 }
11623 if (empty($classname)) {
11624 $classname = ucfirst($subelement);
11625 }
11626 if (empty($classpath)) {
11627 $classpath = $module.'/class';
11628 }
11629
11630 //print 'getElementProperties subdir='.$subdir;
11631
11632 // Set dir_output
11633 if ($module && isset($conf->$module)) { // The generic case
11634 if (!empty($conf->$module->multidir_output[$conf->entity])) {
11635 $dir_output = $conf->$module->multidir_output[$conf->entity];
11636 } elseif (!empty($conf->$module->output[$conf->entity])) {
11637 $dir_output = $conf->$module->output[$conf->entity];
11638 } elseif (!empty($conf->$module->dir_output)) {
11639 $dir_output = $conf->$module->dir_output;
11640 }
11641 }
11642
11643 // Overwrite value for special cases
11644 if ($element == 'order_supplier') {
11645 $dir_output = $conf->fournisseur->commande->dir_output;
11646 } elseif ($element == 'invoice_supplier') {
11647 $dir_output = $conf->fournisseur->facture->dir_output;
11648 }
11649 $dir_output .= $subdir;
11650
11651 $element_properties = array(
11652 'module' => $module,
11653 'element' => $element,
11654 'subelement' => $subelement,
11655 'classpath' => $classpath,
11656 'classfile' => $classfile,
11657 'classname' => $classname,
11658 'dir_output' => $dir_output
11659 );
11660 return $element_properties;
11661}
11662
11672function fetchObjectByElement($element_id, $element_type, $element_ref = '')
11673{
11674 global $db;
11675
11676 $ret = 0;
11677
11678 $element_prop = getElementProperties($element_type);
11679
11680 if (is_array($element_prop) && isModEnabled($element_prop['module'])) {
11681 dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php');
11682
11683 if (class_exists($element_prop['classname'])) {
11684 $classname = $element_prop['classname'];
11685 $objecttmp = new $classname($db);
11686 $ret = $objecttmp->fetch($element_id, $element_ref);
11687 if ($ret >= 0) {
11688 if (empty($objecttmp->module)) {
11689 $objecttmp->module = $element_prop['module'];
11690 }
11691
11692 return $objecttmp;
11693 }
11694 } else {
11695 return -1;
11696 }
11697 }
11698
11699 return $ret;
11700}
11701
11709{
11710 if (preg_match('/\.(htm|html|js|phar|php|php\d+|phtml|pht|pl|py|cgi|ksh|sh|shtml|bash|bat|cmd|wpk|exe|dmg)$/i', $filename)) {
11711 return true;
11712 }
11713
11714 return false;
11715}
11716
11724function newToken()
11725{
11726 return empty($_SESSION['newtoken']) ? '' : $_SESSION['newtoken'];
11727}
11728
11737{
11738 return isset($_SESSION['token']) ? $_SESSION['token'] : '';
11739}
11740
11746function getNonce()
11747{
11748 global $conf;
11749
11750 if (empty($conf->cache['nonce'])) {
11751 $conf->cache['nonce'] = dolGetRandomBytes(8);
11752 }
11753
11754 return $conf->cache['nonce'];
11755}
11756
11757
11770function startSimpleTable($header, $link = "", $arguments = "", $emptyRows = 0, $number = -1)
11771{
11772 global $langs;
11773
11774 print '<div class="div-table-responsive-no-min">';
11775 print '<table class="noborder centpercent">';
11776 print '<tr class="liste_titre">';
11777
11778 print $emptyRows < 1 ? '<th>' : '<th colspan="'.($emptyRows + 1).'">';
11779
11780 print $langs->trans($header);
11781
11782 // extra space between the first header and the number
11783 if ($number > -1) {
11784 print ' ';
11785 }
11786
11787 if (!empty($link)) {
11788 if (!empty($arguments)) {
11789 print '<a href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
11790 } else {
11791 print '<a href="'.DOL_URL_ROOT.'/'.$link.'">';
11792 }
11793 }
11794
11795 if ($number > -1) {
11796 print '<span class="badge">'.$number.'</span>';
11797 }
11798
11799 if (!empty($link)) {
11800 print '</a>';
11801 }
11802
11803 print '</th>';
11804
11805 if ($number < 0 && !empty($link)) {
11806 print '<th class="right">';
11807
11808 if (!empty($arguments)) {
11809 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
11810 } else {
11811 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'">';
11812 }
11813
11814 print $langs->trans("FullList");
11815 print '</a>';
11816 print '</th>';
11817 }
11818
11819 print '</tr>';
11820}
11821
11830function finishSimpleTable($addLineBreak = false)
11831{
11832 print '</table>';
11833 print '</div>';
11834
11835 if ($addLineBreak) {
11836 print '<br>';
11837 }
11838}
11839
11851function addSummaryTableLine($tableColumnCount, $num, $nbofloop = 0, $total = 0, $noneWord = "None", $extraRightColumn = false)
11852{
11853 global $langs;
11854
11855 if ($num === 0) {
11856 print '<tr class="oddeven">';
11857 print '<td colspan="'.$tableColumnCount.'" class="opacitymedium">'.$langs->trans($noneWord).'</td>';
11858 print '</tr>';
11859 return;
11860 }
11861
11862 if ($nbofloop === 0) {
11863 // don't show a summary line
11864 return;
11865 }
11866
11867 if ($num === 0) {
11868 $colspan = $tableColumnCount;
11869 } elseif ($num > $nbofloop) {
11870 $colspan = $tableColumnCount;
11871 } else {
11872 $colspan = $tableColumnCount - 1;
11873 }
11874
11875 if ($extraRightColumn) {
11876 $colspan--;
11877 }
11878
11879 print '<tr class="liste_total">';
11880
11881 if ($nbofloop > 0 && $num > $nbofloop) {
11882 print '<td colspan="'.$colspan.'" class="right">'.$langs->trans("XMoreLines", ($num - $nbofloop)).'</td>';
11883 } else {
11884 print '<td colspan="'.$colspan.'" class="right"> '.$langs->trans("Total").'</td>';
11885 print '<td class="right" width="100">'.price($total).'</td>';
11886 }
11887
11888 if ($extraRightColumn) {
11889 print '<td></td>';
11890 }
11891
11892 print '</tr>';
11893}
11894
11903function readfileLowMemory($fullpath_original_file_osencoded, $method = -1)
11904{
11905 global $conf;
11906
11907 if ($method == -1) {
11908 $method = 0;
11909 if (!empty($conf->global->MAIN_FORCE_READFILE_WITH_FREAD)) {
11910 $method = 1;
11911 }
11912 if (!empty($conf->global->MAIN_FORCE_READFILE_WITH_STREAM_COPY)) {
11913 $method = 2;
11914 }
11915 }
11916
11917 // Be sure we don't have output buffering enabled to have readfile working correctly
11918 while (ob_get_level()) {
11919 ob_end_flush();
11920 }
11921
11922 // Solution 0
11923 if ($method == 0) {
11924 readfile($fullpath_original_file_osencoded);
11925 } elseif ($method == 1) {
11926 // Solution 1
11927 $handle = fopen($fullpath_original_file_osencoded, "rb");
11928 while (!feof($handle)) {
11929 print fread($handle, 8192);
11930 }
11931 fclose($handle);
11932 } elseif ($method == 2) {
11933 // Solution 2
11934 $handle1 = fopen($fullpath_original_file_osencoded, "rb");
11935 $handle2 = fopen("php://output", "wb");
11936 stream_copy_to_stream($handle1, $handle2);
11937 fclose($handle1);
11938 fclose($handle2);
11939 }
11940}
11941
11951function showValueWithClipboardCPButton($valuetocopy, $showonlyonhover = 1, $texttoshow = '')
11952{
11953 /*
11954 global $conf;
11955
11956 if (!empty($conf->dol_no_mouse_hover)) {
11957 $showonlyonhover = 0;
11958 }*/
11959
11960 $tag = 'span'; // Using div (like any style of type 'block') does not work when using the js copy code.
11961 if ($texttoshow === 'none') {
11962 $result = '<span class="clipboardCP'.($showonlyonhover ? ' clipboardCPShowOnHover' : '').'"><'.$tag.' class="clipboardCPValue hidewithsize">'.dol_escape_htmltag($valuetocopy, 1, 1).'</'.$tag.'><span class="clipboardCPValueToPrint"></span><span class="clipboardCPButton far fa-clipboard opacitymedium paddingleft paddingright"></span><span class="clipboardCPText"></span></span>';
11963 } elseif ($texttoshow) {
11964 $result = '<span class="clipboardCP'.($showonlyonhover ? ' clipboardCPShowOnHover' : '').'"><'.$tag.' class="clipboardCPValue hidewithsize">'.dol_escape_htmltag($valuetocopy, 1, 1).'</'.$tag.'><span class="clipboardCPValueToPrint">'.dol_escape_htmltag($texttoshow, 1, 1).'</span><span class="clipboardCPButton far fa-clipboard opacitymedium paddingleft paddingright"></span><span class="clipboardCPText"></span></span>';
11965 } else {
11966 $result = '<span class="clipboardCP'.($showonlyonhover ? ' clipboardCPShowOnHover' : '').'"><'.$tag.' class="clipboardCPValue">'.dol_escape_htmltag($valuetocopy, 1, 1).'</'.$tag.'><span class="clipboardCPButton far fa-clipboard opacitymedium paddingleft paddingright"></span><span class="clipboardCPText"></span></span>';
11967 }
11968
11969 return $result;
11970}
11971
11972
11979function jsonOrUnserialize($stringtodecode)
11980{
11981 $result = json_decode($stringtodecode);
11982 if ($result === null) {
11983 $result = unserialize($stringtodecode);
11984 }
11985
11986 return $result;
11987}
11988
11989
12003function forgeSQLFromUniversalSearchCriteria($filter, &$errorstr = '', $noand = 0, $nopar = 0, $noerror = 0)
12004{
12005 if (!preg_match('/^\‍(.*\‍)$/', $filter)) { // If $filter does not start and end with ()
12006 $filter = '(' . $filter . ')';
12007 }
12008
12009 $regexstring = '\‍(([a-zA-Z0-9_\.]+:[<>!=insotlke]+:[^\‍(\‍)]+)\‍)'; // Must be (aaa:bbb:...) with aaa is a field name (with alias or not) and bbb is one of this operator '=', '<', '>', '<=', '>=', '!=', 'in', 'notin', 'like', 'notlike', 'is', 'isnot'
12010
12011 if (!dolCheckFilters($filter, $errorstr)) {
12012 if ($noerror) {
12013 return '1 = 2';
12014 } else {
12015 return 'Filter syntax error - '.$errorstr; // Bad balance of parenthesis, we return an error message or force a SQL not found
12016 }
12017 }
12018
12019 // Test the filter syntax
12020 $t = preg_replace_callback('/'.$regexstring.'/i', 'dolForgeDummyCriteriaCallback', $filter);
12021 $t = str_replace(array('and','or','AND','OR',' '), '', $t); // Remove the only strings allowed between each () criteria
12022 // If the string result contains something else than '()', the syntax was wrong
12023 if (preg_match('/[^\‍(\‍)]/', $t)) {
12024 $errorstr = 'Bad syntax of the search string';
12025 if ($noerror) {
12026 return '1 = 2';
12027 } else {
12028 return 'Filter syntax error - '.$errorstr; // Bad syntax of the search string, we return an error message or force a SQL not found
12029 }
12030 }
12031
12032 return ($noand ? "" : " AND ").($nopar ? "" : '(').preg_replace_callback('/'.$regexstring.'/i', 'dolForgeCriteriaCallback', $filter).($nopar ? "" : ')');
12033}
12034
12042function dolCheckFilters($sqlfilters, &$error = '')
12043{
12044 //$regexstring='\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^:\‍(\‍)]+)\‍)';
12045 //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
12046 $tmp = $sqlfilters;
12047 $i = 0; $nb = strlen($tmp);
12048 $counter = 0;
12049 while ($i < $nb) {
12050 if ($tmp[$i] == '(') {
12051 $counter++;
12052 }
12053 if ($tmp[$i] == ')') {
12054 $counter--;
12055 }
12056 if ($counter < 0) {
12057 $error = "Wrond balance of parenthesis in sqlfilters=".$sqlfilters;
12058 dol_syslog($error, LOG_WARNING);
12059 return false;
12060 }
12061 $i++;
12062 }
12063 return true;
12064}
12065
12074{
12075 //dol_syslog("Convert matches ".$matches[1]);
12076 if (empty($matches[1])) {
12077 return '';
12078 }
12079 $tmp = explode(':', $matches[1]);
12080 if (count($tmp) < 3) {
12081 return '';
12082 }
12083
12084 return '()'; // An empty criteria
12085}
12086
12096{
12097 global $db;
12098
12099 //dol_syslog("Convert matches ".$matches[1]);
12100 if (empty($matches[1])) {
12101 return '';
12102 }
12103 $tmp = explode(':', $matches[1]);
12104 if (count($tmp) < 3) {
12105 return '';
12106 }
12107
12108 $operand = preg_replace('/[^a-z0-9\._]/i', '', trim($tmp[0]));
12109
12110 $operator = strtoupper(preg_replace('/[^a-z<>!=]/i', '', trim($tmp[1])));
12111
12112 if ($operator == 'NOTLIKE') {
12113 $operator = 'NOT LIKE';
12114 }
12115 if ($operator == 'ISNOT') {
12116 $operator = 'IS NOT';
12117 }
12118 if ($operator == '!=') {
12119 $operator = '<>';
12120 }
12121
12122 $tmpescaped = $tmp[2];
12123 $regbis = array();
12124
12125 if ($operator == 'IN') { // IN is allowed for list of ID or code only
12126 //if (!preg_match('/^\‍(.*\‍)$/', $tmpescaped)) {
12127 $tmpescaped = '('.$db->escape($db->sanitize($tmpescaped, 1, 0)).')';
12128 //} else {
12129 // $tmpescaped = $db->escape($db->sanitize($tmpescaped, 1));
12130 //}
12131 } elseif ($operator == 'LIKE' || $operator == 'NOT LIKE') {
12132 if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12133 $tmpescaped = $regbis[1];
12134 }
12135 //$tmpescaped = "'".$db->escapeforlike($db->escape($regbis[1]))."'";
12136 $tmpescaped = "'".$db->escape($tmpescaped)."'"; // We do not escape the _ and % so the like will works
12137 } elseif (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12138 $tmpescaped = "'".$db->escape($regbis[1])."'";
12139 } else {
12140 if (strtoupper($tmpescaped) == 'NULL') {
12141 $tmpescaped = 'NULL';
12142 } elseif (is_int($tmpescaped)) {
12143 $tmpescaped = (int) $tmpescaped;
12144 } else {
12145 $tmpescaped = (float) $tmpescaped;
12146 }
12147 }
12148
12149 return '('.$db->escape($operand).' '.strtoupper($operator).' '.$tmpescaped.')';
12150}
12151
12152
12161function getTimelineIcon($actionstatic, &$histo, $key)
12162{
12163 global $conf, $langs;
12164 $out = '<!-- timeline icon -->'."\n";
12165 $iconClass = 'fa fa-comments';
12166 $img_picto = '';
12167 $colorClass = '';
12168 $pictoTitle = '';
12169
12170 if ($histo[$key]['percent'] == -1) {
12171 $colorClass = 'timeline-icon-not-applicble';
12172 $pictoTitle = $langs->trans('StatusNotApplicable');
12173 } elseif ($histo[$key]['percent'] == 0) {
12174 $colorClass = 'timeline-icon-todo';
12175 $pictoTitle = $langs->trans('StatusActionToDo').' (0%)';
12176 } elseif ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100) {
12177 $colorClass = 'timeline-icon-in-progress';
12178 $pictoTitle = $langs->trans('StatusActionInProcess').' ('.$histo[$key]['percent'].'%)';
12179 } elseif ($histo[$key]['percent'] >= 100) {
12180 $colorClass = 'timeline-icon-done';
12181 $pictoTitle = $langs->trans('StatusActionDone').' (100%)';
12182 }
12183
12184 if ($actionstatic->code == 'AC_TICKET_CREATE') {
12185 $iconClass = 'fa fa-ticket';
12186 } elseif ($actionstatic->code == 'AC_TICKET_MODIFY') {
12187 $iconClass = 'fa fa-pencilxxx';
12188 } elseif (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12189 $iconClass = 'fa fa-comments';
12190 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12191 $iconClass = 'fa fa-mask';
12192 } elseif (!empty($conf->global->AGENDA_USE_EVENT_TYPE)) {
12193 if ($actionstatic->type_picto) {
12194 $img_picto = img_picto('', $actionstatic->type_picto);
12195 } else {
12196 if ($actionstatic->type_code == 'AC_RDV') {
12197 $iconClass = 'fa fa-handshake';
12198 } elseif ($actionstatic->type_code == 'AC_TEL') {
12199 $iconClass = 'fa fa-phone';
12200 } elseif ($actionstatic->type_code == 'AC_FAX') {
12201 $iconClass = 'fa fa-fax';
12202 } elseif ($actionstatic->type_code == 'AC_EMAIL') {
12203 $iconClass = 'fa fa-envelope';
12204 } elseif ($actionstatic->type_code == 'AC_INT') {
12205 $iconClass = 'fa fa-shipping-fast';
12206 } elseif ($actionstatic->type_code == 'AC_OTH_AUTO') {
12207 $iconClass = 'fa fa-robot';
12208 } elseif (!preg_match('/_AUTO/', $actionstatic->type_code)) {
12209 $iconClass = 'fa fa-robot';
12210 }
12211 }
12212 }
12213
12214 $out .= '<i class="'.$iconClass.' '.$colorClass.'" title="'.$pictoTitle.'">'.$img_picto.'</i>'."\n";
12215 return $out;
12216}
12217
12224function getActionCommEcmList($object)
12225{
12226 global $conf, $db;
12227
12228 $documents = array();
12229
12230 $sql = 'SELECT ecm.rowid as id, ecm.src_object_type, ecm.src_object_id, ecm.filepath, ecm.filename';
12231 $sql .= ' FROM '.MAIN_DB_PREFIX.'ecm_files ecm';
12232 $sql .= " WHERE ecm.filepath = 'agenda/".((int) $object->id)."'";
12233 //$sql.= " ecm.src_object_type = '".$db->escape($object->element)."' AND ecm.src_object_id = ".((int) $object->id); // Old version didn't add object_type during upload
12234 $sql .= ' ORDER BY ecm.position ASC';
12235
12236 $resql = $db->query($sql);
12237 if ($resql) {
12238 if ($db->num_rows($resql)) {
12239 while ($obj = $db->fetch_object($resql)) {
12240 $documents[$obj->id] = $obj;
12241 }
12242 }
12243 }
12244
12245 return $documents;
12246}
12247
12248
12249
12267function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
12268{
12269 global $user, $conf;
12270 global $form;
12271
12272 global $param, $massactionbutton;
12273
12274 dol_include_once('/comm/action/class/actioncomm.class.php');
12275
12276 // Check parameters
12277 if (!is_object($filterobj) && !is_object($objcon)) {
12278 dol_print_error('', 'BadParameter');
12279 }
12280
12281 $histo = array();
12282 $numaction = 0;
12283 $now = dol_now();
12284
12285 $sortfield_list = explode(',', $sortfield);
12286 $sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent');
12287 $sortfield_new_list = array();
12288 foreach ($sortfield_list as $sortfield_value) {
12289 $sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)];
12290 }
12291 $sortfield_new = implode(',', $sortfield_new_list);
12292
12293 if (isModEnabled('agenda')) {
12294 // Search histo on actioncomm
12295 if (is_object($objcon) && $objcon->id > 0) {
12296 $sql = "SELECT DISTINCT a.id, a.label as label,";
12297 } else {
12298 $sql = "SELECT a.id, a.label as label,";
12299 }
12300 $sql .= " a.datep as dp,";
12301 $sql .= " a.note as message,";
12302 $sql .= " a.datep2 as dp2,";
12303 $sql .= " a.percent as percent, 'action' as type,";
12304 $sql .= " a.fk_element, a.elementtype,";
12305 $sql .= " a.fk_contact,";
12306 $sql .= " a.email_from as msg_from,";
12307 $sql .= " c.code as acode, c.libelle as alabel, c.picto as apicto,";
12308 $sql .= " u.rowid as user_id, u.login as user_login, u.photo as user_photo, u.firstname as user_firstname, u.lastname as user_lastname";
12309 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12310 $sql .= ", sp.lastname, sp.firstname";
12311 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12312 $sql .= ", m.lastname, m.firstname";
12313 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12314 $sql .= ", o.ref";
12315 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12316 $sql .= ", o.ref";
12317 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12318 $sql .= ", o.ref";
12319 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12320 $sql .= ", o.ref";
12321 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12322 $sql .= ", o.ref";
12323 }
12324 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
12325 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
12326 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
12327
12328 $force_filter_contact = false;
12329 if (is_object($objcon) && $objcon->id > 0) {
12330 $force_filter_contact = true;
12331 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
12332 $sql .= " AND r.element_type = '".$db->escape($objcon->table_element)."' AND r.fk_element = ".((int) $objcon->id);
12333 }
12334
12335 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12336 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
12337 } elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
12338 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er";
12339 $sql .= " ON er.resource_type = 'dolresource'";
12340 $sql .= " AND er.element_id = a.id";
12341 $sql .= " AND er.resource_id = ".((int) $filterobj->id);
12342 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12343 $sql .= ", ".MAIN_DB_PREFIX."adherent as m";
12344 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12345 $sql .= ", ".MAIN_DB_PREFIX."commande_fournisseur as o";
12346 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12347 $sql .= ", ".MAIN_DB_PREFIX."product as o";
12348 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12349 $sql .= ", ".MAIN_DB_PREFIX."ticket as o";
12350 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12351 $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o";
12352 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12353 $sql .= ", ".MAIN_DB_PREFIX."contrat as o";
12354 }
12355
12356 $sql .= " WHERE a.entity IN (".getEntity('agenda').")";
12357 if ($force_filter_contact === false) {
12358 if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) {
12359 $sql .= " AND a.fk_soc = ".((int) $filterobj->id);
12360 } elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) {
12361 $sql .= " AND a.fk_project = ".((int) $filterobj->id);
12362 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12363 $sql .= " AND a.fk_element = m.rowid AND a.elementtype = 'member'";
12364 if ($filterobj->id) {
12365 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12366 }
12367 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12368 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'order_supplier'";
12369 if ($filterobj->id) {
12370 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12371 }
12372 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12373 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
12374 if ($filterobj->id) {
12375 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12376 }
12377 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12378 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'ticket'";
12379 if ($filterobj->id) {
12380 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12381 }
12382 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12383 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'bom'";
12384 if ($filterobj->id) {
12385 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12386 }
12387 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12388 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'contract'";
12389 if ($filterobj->id) {
12390 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12391 }
12392 }
12393 }
12394
12395 // Condition on actioncode
12396 if (!empty($actioncode)) {
12397 if (empty($conf->global->AGENDA_USE_EVENT_TYPE)) {
12398 if ($actioncode == 'AC_NON_AUTO') {
12399 $sql .= " AND c.type != 'systemauto'";
12400 } elseif ($actioncode == 'AC_ALL_AUTO') {
12401 $sql .= " AND c.type = 'systemauto'";
12402 } else {
12403 if ($actioncode == 'AC_OTH') {
12404 $sql .= " AND c.type != 'systemauto'";
12405 } elseif ($actioncode == 'AC_OTH_AUTO') {
12406 $sql .= " AND c.type = 'systemauto'";
12407 }
12408 }
12409 } else {
12410 if ($actioncode == 'AC_NON_AUTO') {
12411 $sql .= " AND c.type != 'systemauto'";
12412 } elseif ($actioncode == 'AC_ALL_AUTO') {
12413 $sql .= " AND c.type = 'systemauto'";
12414 } else {
12415 $sql .= " AND c.code = '".$db->escape($actioncode)."'";
12416 }
12417 }
12418 }
12419 if ($donetodo == 'todo') {
12420 $sql .= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
12421 } elseif ($donetodo == 'done') {
12422 $sql .= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
12423 }
12424 if (is_array($filters) && $filters['search_agenda_label']) {
12425 $sql .= natural_search('a.label', $filters['search_agenda_label']);
12426 }
12427 }
12428
12429 // Add also event from emailings. TODO This should be replaced by an automatic event ? May be it's too much for very large emailing.
12430 if (isModEnabled('mailing') && !empty($objcon->email)
12431 && (empty($actioncode) || $actioncode == 'AC_OTH_AUTO' || $actioncode == 'AC_EMAILING')) {
12432 $langs->load("mails");
12433
12434 $sql2 = "SELECT m.rowid as id, m.titre as label, mc.date_envoi as dp, mc.date_envoi as dp2, '100' as percent, 'mailing' as type";
12435 $sql2 .= ", null as fk_element, '' as elementtype, null as contact_id";
12436 $sql2 .= ", 'AC_EMAILING' as acode, '' as alabel, '' as apicto";
12437 $sql2 .= ", u.rowid as user_id, u.login as user_login, u.photo as user_photo, u.firstname as user_firstname, u.lastname as user_lastname"; // User that valid action
12438 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12439 $sql2 .= ", '' as lastname, '' as firstname";
12440 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12441 $sql2 .= ", '' as lastname, '' as firstname";
12442 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12443 $sql2 .= ", '' as ref";
12444 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12445 $sql2 .= ", '' as ref";
12446 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12447 $sql2 .= ", '' as ref";
12448 }
12449 $sql2 .= " FROM ".MAIN_DB_PREFIX."mailing as m, ".MAIN_DB_PREFIX."mailing_cibles as mc, ".MAIN_DB_PREFIX."user as u";
12450 $sql2 .= " WHERE mc.email = '".$db->escape($objcon->email)."'"; // Search is done on email.
12451 $sql2 .= " AND mc.statut = 1";
12452 $sql2 .= " AND u.rowid = m.fk_user_valid";
12453 $sql2 .= " AND mc.fk_mailing=m.rowid";
12454 }
12455
12456 if (!empty($sql) && !empty($sql2)) {
12457 $sql = $sql." UNION ".$sql2;
12458 } elseif (empty($sql) && !empty($sql2)) {
12459 $sql = $sql2;
12460 }
12461
12462 // TODO Add limit in nb of results
12463 if ($sql) { // May not be defined if module Agenda is not enabled and mailing module disabled too
12464 $sql .= $db->order($sortfield_new, $sortorder);
12465
12466 dol_syslog("function.lib::show_actions_messaging", LOG_DEBUG);
12467 $resql = $db->query($sql);
12468 if ($resql) {
12469 $i = 0;
12470 $num = $db->num_rows($resql);
12471
12472 while ($i < $num) {
12473 $obj = $db->fetch_object($resql);
12474
12475 if ($obj->type == 'action') {
12476 $contactaction = new ActionComm($db);
12477 $contactaction->id = $obj->id;
12478 $result = $contactaction->fetchResources();
12479 if ($result < 0) {
12480 dol_print_error($db);
12481 setEventMessage("actions.lib::show_actions_messaging Error fetch ressource", 'errors');
12482 }
12483
12484 //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
12485 //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
12486 $tododone = '';
12487 if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && $obj->dp > $now)) {
12488 $tododone = 'todo';
12489 }
12490
12491 $histo[$numaction] = array(
12492 'type'=>$obj->type,
12493 'tododone'=>$tododone,
12494 'id'=>$obj->id,
12495 'datestart'=>$db->jdate($obj->dp),
12496 'dateend'=>$db->jdate($obj->dp2),
12497 'note'=>$obj->label,
12498 'message'=>$obj->message,
12499 'percent'=>$obj->percent,
12500
12501 'userid'=>$obj->user_id,
12502 'login'=>$obj->user_login,
12503 'userfirstname'=>$obj->user_firstname,
12504 'userlastname'=>$obj->user_lastname,
12505 'userphoto'=>$obj->user_photo,
12506 'msg_from'=>$obj->msg_from,
12507
12508 'contact_id'=>$obj->fk_contact,
12509 'socpeopleassigned' => $contactaction->socpeopleassigned,
12510 'lastname' => (empty($obj->lastname) ? '' : $obj->lastname),
12511 'firstname' => (empty($obj->firstname) ? '' : $obj->firstname),
12512 'fk_element'=>$obj->fk_element,
12513 'elementtype'=>$obj->elementtype,
12514 // Type of event
12515 'acode'=>$obj->acode,
12516 'alabel'=>$obj->alabel,
12517 'libelle'=>$obj->alabel, // deprecated
12518 'apicto'=>$obj->apicto
12519 );
12520 } else {
12521 $histo[$numaction] = array(
12522 'type'=>$obj->type,
12523 'tododone'=>'done',
12524 'id'=>$obj->id,
12525 'datestart'=>$db->jdate($obj->dp),
12526 'dateend'=>$db->jdate($obj->dp2),
12527 'note'=>$obj->label,
12528 'message'=>$obj->message,
12529 'percent'=>$obj->percent,
12530 'acode'=>$obj->acode,
12531
12532 'userid'=>$obj->user_id,
12533 'login'=>$obj->user_login,
12534 'userfirstname'=>$obj->user_firstname,
12535 'userlastname'=>$obj->user_lastname,
12536 'userphoto'=>$obj->user_photo
12537 );
12538 }
12539
12540 $numaction++;
12541 $i++;
12542 }
12543 } else {
12544 dol_print_error($db);
12545 }
12546 }
12547
12548 // Set $out to show events
12549 $out = '';
12550
12551 if (!isModEnabled('agenda')) {
12552 $langs->loadLangs(array("admin", "errors"));
12553 $out = info_admin($langs->trans("WarningModuleXDisabledSoYouMayMissEventHere", $langs->transnoentitiesnoconv("Module2400Name")), 0, 0, 'warning');
12554 }
12555
12556 if (isModEnabled('agenda') || (isModEnabled('mailing') && !empty($objcon->email))) {
12557 $delay_warning = $conf->global->MAIN_DELAY_ACTIONS_TODO * 24 * 60 * 60;
12558
12559 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
12560 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
12561 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
12562 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
12563
12564 $formactions = new FormActions($db);
12565
12566 $actionstatic = new ActionComm($db);
12567 $userstatic = new User($db);
12568 $contactstatic = new Contact($db);
12569 $userGetNomUrlCache = array();
12570 $contactGetNomUrlCache = array();
12571
12572 $out .= '<div class="filters-container" >';
12573 $out .= '<form name="listactionsfilter" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
12574 $out .= '<input type="hidden" name="token" value="'.newToken().'">';
12575
12576 if ($objcon && get_class($objcon) == 'Contact' &&
12577 (is_null($filterobj) || get_class($filterobj) == 'Societe')) {
12578 $out .= '<input type="hidden" name="id" value="'.$objcon->id.'" />';
12579 } else {
12580 $out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
12581 }
12582 if ($filterobj && get_class($filterobj) == 'Societe') {
12583 $out .= '<input type="hidden" name="socid" value="'.$filterobj->id.'" />';
12584 }
12585
12586 $out .= "\n";
12587
12588 $out .= '<div class="div-table-responsive-no-min">';
12589 $out .= '<table class="noborder borderbottom centpercent">';
12590
12591 $out .= '<tr class="liste_titre">';
12592
12593 // Action column
12594 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
12595 $out .= '<th class="liste_titre width50 middle">';
12596 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
12597 $out .= $searchpicto;
12598 $out .= '</th>';
12599 }
12600
12601 $out .= getTitleFieldOfList('Date', 0, $_SERVER["PHP_SELF"], 'a.datep', '', $param, '', $sortfield, $sortorder, '')."\n";
12602
12603 $out .= '<th class="liste_titre"><strong class="hideonsmartphone">'.$langs->trans("Search").' : </strong></th>';
12604 if ($donetodo) {
12605 $out .= '<th class="liste_titre"></th>';
12606 }
12607 $out .= '<th class="liste_titre">';
12608 $out .= '<span class="fas fa-square inline-block fawidth30" style=" color: #ddd;" title="'.$langs->trans("ActionType").'"></span>';
12609 //$out .= img_picto($langs->trans("Type"), 'type');
12610 $out .= $formactions->select_type_actions($actioncode, "actioncode", '', empty($conf->global->AGENDA_USE_EVENT_TYPE) ? 1 : -1, 0, 0, 1, 'minwidth200imp');
12611 $out .= '</th>';
12612 $out .= '<th class="liste_titre maxwidth100onsmartphone">';
12613 $out .= '<input type="text" class="maxwidth100onsmartphone" name="search_agenda_label" value="'.$filters['search_agenda_label'].'" placeholder="'.$langs->trans("Label").'">';
12614 $out .= '</th>';
12615
12616 // Action column
12617 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
12618 $out .= '<th class="liste_titre width50 middle">';
12619 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
12620 $out .= $searchpicto;
12621 $out .= '</th>';
12622 }
12623
12624 $out .= '</tr>';
12625
12626
12627 $out .= '</table>';
12628
12629 $out .= '</form>';
12630 $out .= '</div>';
12631
12632 $out .= "\n";
12633
12634 $out .= '<ul class="timeline">';
12635
12636 if ($donetodo) {
12637 $tmp = '';
12638 if (get_class($filterobj) == 'Societe') {
12639 $tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&socid='.$filterobj->id.'&status=done">';
12640 }
12641 $tmp .= ($donetodo != 'done' ? $langs->trans("ActionsToDoShort") : '');
12642 $tmp .= ($donetodo != 'done' && $donetodo != 'todo' ? ' / ' : '');
12643 $tmp .= ($donetodo != 'todo' ? $langs->trans("ActionsDoneShort") : '');
12644 //$out.=$langs->trans("ActionsToDoShort").' / '.$langs->trans("ActionsDoneShort");
12645 if (get_class($filterobj) == 'Societe') {
12646 $tmp .= '</a>';
12647 }
12648 $out .= getTitleFieldOfList($tmp);
12649 }
12650
12651
12652 //require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
12653 //$caction=new CActionComm($db);
12654 //$arraylist=$caction->liste_array(1, 'code', '', (empty($conf->global->AGENDA_USE_EVENT_TYPE)?1:0), '', 1);
12655
12656 $actualCycleDate = false;
12657
12658 // Loop on each event to show it
12659 foreach ($histo as $key => $value) {
12660 $actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo
12661
12662 $actionstatic->type_picto = $histo[$key]['apicto'];
12663 $actionstatic->type_code = $histo[$key]['acode'];
12664
12665 $url = DOL_URL_ROOT.'/comm/action/card.php?id='.$histo[$key]['id'];
12666
12667 $tmpa = dol_getdate($histo[$key]['datestart'], false);
12668 if ($actualCycleDate !== $tmpa['year'].'-'.$tmpa['yday']) {
12669 $actualCycleDate = $tmpa['year'].'-'.$tmpa['yday'];
12670 $out .= '<!-- timeline time label -->';
12671 $out .= '<li class="time-label">';
12672 $out .= '<span class="timeline-badge-date">';
12673 $out .= dol_print_date($histo[$key]['datestart'], 'daytext', 'tzuserrel', $langs);
12674 $out .= '</span>';
12675 $out .= '</li>';
12676 $out .= '<!-- /.timeline-label -->';
12677 }
12678
12679
12680 $out .= '<!-- timeline item -->'."\n";
12681 $out .= '<li class="timeline-code-'.strtolower($actionstatic->code).'">';
12682
12683 $out .= getTimelineIcon($actionstatic, $histo, $key);
12684
12685 $out .= '<div class="timeline-item">'."\n";
12686
12687 $out .= '<span class="timeline-header-action">';
12688
12689 if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
12690 $out .= '<a class="timeline-btn" href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
12691 $out .= $histo[$key]['id'];
12692 $out .= '</a> ';
12693 } else {
12694 $out .= $actionstatic->getNomUrl(1, -1, 'valignmiddle').' ';
12695 }
12696
12697 if ($user->hasRight('agenda', 'allactions', 'create') ||
12698 (($actionstatic->authorid == $user->id || $actionstatic->userownerid == $user->id) && $user->hasRight('agenda', 'myactions', 'create'))) {
12699 $out .= '<a class="timeline-btn" href="'.DOL_MAIN_URL_ROOT.'/comm/action/card.php?action=edit&token='.newToken().'&id='.$actionstatic->id.'&backtopage='.urlencode($_SERVER["PHP_SELF"].'?'.$param).'"><i class="fa fa-pencil" title="'.$langs->trans("Modify").'" ></i></a>';
12700 }
12701
12702 $out .= '</span>';
12703 // Date
12704 $out .= '<span class="time"><i class="fa fa-clock-o valignmiddle"></i> <span class="valignmiddle">';
12705 $out .= dol_print_date($histo[$key]['datestart'], 'dayhour', 'tzuserrel');
12706 if ($histo[$key]['dateend'] && $histo[$key]['dateend'] != $histo[$key]['datestart']) {
12707 $tmpa = dol_getdate($histo[$key]['datestart'], true);
12708 $tmpb = dol_getdate($histo[$key]['dateend'], true);
12709 if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
12710 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'hour', 'tzuserrel');
12711 } else {
12712 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'dayhour', 'tzuserrel');
12713 }
12714 }
12715 $late = 0;
12716 if ($histo[$key]['percent'] == 0 && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12717 $late = 1;
12718 }
12719 if ($histo[$key]['percent'] == 0 && !$histo[$key]['datestart'] && $histo[$key]['dateend'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12720 $late = 1;
12721 }
12722 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && $histo[$key]['dateend'] && $histo[$key]['dateend'] < ($now - $delay_warning)) {
12723 $late = 1;
12724 }
12725 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && !$histo[$key]['dateend'] && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12726 $late = 1;
12727 }
12728 if ($late) {
12729 $out .= img_warning($langs->trans("Late")).' ';
12730 }
12731 $out .= "</span></span>\n";
12732
12733 // Ref
12734 $out .= '<h3 class="timeline-header">';
12735
12736 // Author of event
12737 $out .= '<div class="messaging-author inline-block tdoverflowmax150 valignmiddle marginrightonly">';
12738 if ($histo[$key]['userid'] > 0) {
12739 if (!isset($userGetNomUrlCache[$histo[$key]['userid']])) { // is in cache ?
12740 $userstatic->fetch($histo[$key]['userid']);
12741 $userGetNomUrlCache[$histo[$key]['userid']] = $userstatic->getNomUrl(-1, '', 0, 0, 16, 0, 'firstelselast', '');
12742 }
12743 $out .= $userGetNomUrlCache[$histo[$key]['userid']];
12744 } elseif (!empty($histo[$key]['msg_from']) && $actionstatic->code == 'TICKET_MSG') {
12745 if (!isset($contactGetNomUrlCache[$histo[$key]['msg_from']])) {
12746 if ($contactstatic->fetch(0, null, '', $histo[$key]['msg_from']) > 0) {
12747 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $contactstatic->getNomUrl(-1, '', 16);
12748 } else {
12749 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $histo[$key]['msg_from'];
12750 }
12751 }
12752 $out .= $contactGetNomUrlCache[$histo[$key]['msg_from']];
12753 }
12754 $out .= '</div>';
12755
12756 // Title
12757 $libelle = '';
12758 $out .= ' <div class="messaging-title inline-block">';
12759
12760 if (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12761 $out .= $langs->trans('TicketNewMessage');
12762 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12763 $out .= $langs->trans('TicketNewMessage').' <em>('.$langs->trans('Private').')</em>';
12764 } elseif (isset($histo[$key]['type'])) {
12765 if ($histo[$key]['type'] == 'action') {
12766 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
12767 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : $histo[$key]['alabel']);
12768 $libelle = $histo[$key]['note'];
12769 $actionstatic->id = $histo[$key]['id'];
12770 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12771 } elseif ($histo[$key]['type'] == 'mailing') {
12772 $out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
12773 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
12774 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : 'Send mass mailing');
12775 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12776 } else {
12777 $libelle .= $histo[$key]['note'];
12778 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12779 }
12780 }
12781
12782 $out .= '</div>';
12783
12784 $out .= '</h3>';
12785
12786 if (!empty($histo[$key]['message'] && $histo[$key]['message'] != $libelle)
12787 && $actionstatic->code != 'AC_TICKET_CREATE'
12788 && $actionstatic->code != 'AC_TICKET_MODIFY'
12789 ) {
12790 $out .= '<div class="timeline-body">';
12791 $out .= $histo[$key]['message'];
12792 $out .= '</div>';
12793 }
12794
12795 // Timeline footer
12796 $footer = '';
12797
12798 // Contact for this action
12799 if (isset($histo[$key]['socpeopleassigned']) && is_array($histo[$key]['socpeopleassigned']) && count($histo[$key]['socpeopleassigned']) > 0) {
12800 $contactList = '';
12801 foreach ($histo[$key]['socpeopleassigned'] as $cid => $Tab) {
12802 $contact = new Contact($db);
12803 $result = $contact->fetch($cid);
12804
12805 if ($result < 0) {
12806 dol_print_error($db, $contact->error);
12807 }
12808
12809 if ($result > 0) {
12810 $contactList .= !empty($contactList) ? ', ' : '';
12811 $contactList .= $contact->getNomUrl(1);
12812 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
12813 if (!empty($contact->phone_pro)) {
12814 $contactList .= '('.dol_print_phone($contact->phone_pro).')';
12815 }
12816 }
12817 }
12818 }
12819
12820 $footer .= $langs->trans('ActionOnContact').' : '.$contactList;
12821 } elseif (empty($objcon->id) && isset($histo[$key]['contact_id']) && $histo[$key]['contact_id'] > 0) {
12822 $contact = new Contact($db);
12823 $result = $contact->fetch($histo[$key]['contact_id']);
12824
12825 if ($result < 0) {
12826 dol_print_error($db, $contact->error);
12827 }
12828
12829 if ($result > 0) {
12830 $footer .= $contact->getNomUrl(1);
12831 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
12832 if (!empty($contact->phone_pro)) {
12833 $footer .= '('.dol_print_phone($contact->phone_pro).')';
12834 }
12835 }
12836 }
12837 }
12838
12839 $documents = getActionCommEcmList($actionstatic);
12840 if (!empty($documents)) {
12841 $footer .= '<div class="timeline-documents-container">';
12842 foreach ($documents as $doc) {
12843 $footer .= '<span id="document_'.$doc->id.'" class="timeline-documents" ';
12844 $footer .= ' data-id="'.$doc->id.'" ';
12845 $footer .= ' data-path="'.$doc->filepath.'"';
12846 $footer .= ' data-filename="'.dol_escape_htmltag($doc->filename).'" ';
12847 $footer .= '>';
12848
12849 $filePath = DOL_DATA_ROOT.'/'.$doc->filepath.'/'.$doc->filename;
12850 $mime = dol_mimetype($filePath);
12851 $file = $actionstatic->id.'/'.$doc->filename;
12852 $thumb = $actionstatic->id.'/thumbs/'.substr($doc->filename, 0, strrpos($doc->filename, '.')).'_mini'.substr($doc->filename, strrpos($doc->filename, '.'));
12853 $doclink = dol_buildpath('document.php', 1).'?modulepart=actions&attachment=0&file='.urlencode($file).'&entity='.$conf->entity;
12854 $viewlink = dol_buildpath('viewimage.php', 1).'?modulepart=actions&file='.urlencode($thumb).'&entity='.$conf->entity;
12855
12856 $mimeAttr = ' mime="'.$mime.'" ';
12857 $class = '';
12858 if (in_array($mime, array('image/png', 'image/jpeg', 'application/pdf'))) {
12859 $class .= ' documentpreview';
12860 }
12861
12862 $footer .= '<a href="'.$doclink.'" class="btn-link '.$class.'" target="_blank" rel="noopener noreferrer" '.$mimeAttr.' >';
12863 $footer .= img_mime($filePath).' '.$doc->filename;
12864 $footer .= '</a>';
12865
12866 $footer .= '</span>';
12867 }
12868 $footer .= '</div>';
12869 }
12870
12871 if (!empty($footer)) {
12872 $out .= '<div class="timeline-footer">'.$footer.'</div>';
12873 }
12874
12875 $out .= '</div>'."\n"; // end timeline-item
12876
12877 $out .= '</li>';
12878 $out .= '<!-- END timeline item -->';
12879
12880 $i++;
12881 }
12882
12883 $out .= "</ul>\n";
12884
12885 if (empty($histo)) {
12886 $out .= '<span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span>';
12887 }
12888 }
12889
12890 if ($noprint) {
12891 return $out;
12892 } else {
12893 print $out;
12894 }
12895}
12896
12907function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto')
12908{
12909 if ($hourTime === 'getpost') {
12910 $hour = GETPOSTINT($prefix . 'hour');
12911 $minute = GETPOSTINT($prefix . 'minute');
12912 $second = GETPOSTINT($prefix . 'second');
12913 } elseif (preg_match('/^(\d\d):(\d\d):(\d\d)$/', $hourTime, $m)) {
12914 $hour = intval($m[1]);
12915 $minute = intval($m[2]);
12916 $second = intval($m[3]);
12917 } else {
12918 $hour = $minute = $second = 0;
12919 }
12920 // normalize out of range values
12921 $hour = min($hour, 23);
12922 $minute = min($minute, 59);
12923 $second = min($second, 59);
12924 return dol_mktime($hour, $minute, $second, GETPOSTINT($prefix . 'month'), GETPOSTINT($prefix . 'day'), GETPOSTINT($prefix . 'year'), $gm);
12925}
12926
12938function buildParamDate($prefix, $timestamp = null, $hourTime = '', $gm = 'auto')
12939{
12940 if ($timestamp === null) $timestamp = GETPOSTDATE($prefix, $hourTime, $gm);
12941 $TParam = array(
12942 $prefix . 'day' => intval(dol_print_date($timestamp, '%d')),
12943 $prefix . 'month' => intval(dol_print_date($timestamp, '%m')),
12944 $prefix . 'year' => intval(dol_print_date($timestamp, '%Y')),
12945 );
12946 if ($hourTime === 'getpost' || ($timestamp !== null && dol_print_date($timestamp, '%H:%M:%S') !== '00:00:00')) {
12947 $TParam = array_merge($TParam, array(
12948 $prefix . 'hour' => intval(dol_print_date($timestamp, '%H')),
12949 $prefix . 'minute' => intval(dol_print_date($timestamp, '%M')),
12950 $prefix . 'second' => intval(dol_print_date($timestamp, '%S'))
12951 ));
12952 }
12953
12954 return '&' . http_build_query($TParam);
12955}
if(preg_match('/set_([a-z0-9_\-]+)/i', $action, $reg)) if(preg_match('/del_([a-z0-9_\-]+)/i', $action, $reg)) if($action=='set') elseif( $action=='specimen') elseif($action=='setmodel') elseif( $action=='del') elseif($action=='setdoc') $formactions
View.
ajax_object_onoff($object, $code, $field, $text_on, $text_off, $input=array(), $morecss='', $htmlname='', $forcenojs=0)
On/off button to change a property status of an object This uses the ajax service objectonoff....
Definition ajax.lib.php:711
Class to manage agenda events (actions)
Class to manage contact/addresses.
Class to manage GeoIP conversion Usage: $geoip=new GeoIP('country',$datfile); $geoip->getCountryCodeF...
Class to manage standard extra fields.
Class to manage invoices.
Class to manage building of HTML components.
Class to manage hooks.
Class to manage predefined suppliers products.
Class to manage products or services.
Class to manage third parties objects (customers, suppliers, prospects...)
isACompany()
Return if third party is a company (Business) or an end user (Consumer)
Class to manage translations.
Class to manage Dolibarr users.
isInEEC($object)
Return if a country of an object is inside the EEC (European Economic Community)
dol_get_prev_month($month, $year)
Return previous month.
Definition date.lib.php:496
dol_get_next_day($day, $month, $year)
Return next day.
Definition date.lib.php:481
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:83
dol_get_prev_day($day, $month, $year)
Return previous day.
Definition date.lib.php:465
dol_get_next_month($month, $year)
Return next month.
Definition date.lib.php:515
dol_convert_file($fileinput, $ext='png', $fileoutput='', $page='')
Convert an image file or a PDF into another image format.
dragAndDropFileUpload($htmlname)
Function to manage the drag and drop of a file.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:62
dol_is_dir($folder)
Test if filename is a directory.
isValidVATID($company)
Check if VAT numero is valid (check done on syntax only, no database or remote access)
dol_html_entity_decode($a, $b, $c='UTF-8', $keepsomeentities=0)
Replace html_entity_decode functions to manage errors.
dol_fiche_end($notab=0)
Show tab footer of a card.
dolCheckFilters($sqlfilters, &$error='')
Return if a $sqlfilters parameter has a valid balance of parenthesis.
dol_print_size($size, $shortvalue=0, $shortunit=0)
Return string with formated size.
dol_banner_tab($object, $paramid, $morehtml='', $shownav=1, $fieldid='rowid', $fieldref='ref', $morehtmlref='', $moreparam='', $nodbprefix=0, $morehtmlleft='', $morehtmlstatus='', $onlybanner=0, $morehtmlright='')
Show tab footer of a card.
isOnlyOneLocalTax($local)
Return true if LocalTax (1 or 2) is unique.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod=0)
Function that return localtax of a product line (according to seller, buyer and product vat rate) Si ...
img_weather($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $morecss='')
Show weather picto.
finishSimpleTable($addLineBreak=false)
Add the correct HTML close tags for "startSimpleTable(...)" (use after the last table line)
startSimpleTable($header, $link="", $arguments="", $emptyRows=0, $number=-1)
Start a table with headers and a optinal clickable number (don't forget to use "finishSimpleTable()" ...
getLanguageCodeFromCountryCode($countrycode)
Return default language from country code.
setEntity($currentobject)
Set entity id to use when to create an object.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks=array())
Show social network link.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
dol_ucfirst($string, $encoding="UTF-8")
Convert first character of the first word of a string to upper.
img_right($titlealt='default', $selected=0, $moreatt='')
Show right arrow logo.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
dol_strtolower($string, $encoding="UTF-8")
Convert a string to lower.
showValueWithClipboardCPButton($valuetocopy, $showonlyonhover=1, $texttoshow='')
Create a button to copy $valuetocopy in the clipboard (for copy and paste feature).
dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto='UTF-8')
This function is called to decode a HTML string (it decodes entities and br tags)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_left($titlealt='default', $selected=0, $moreatt='')
Show left arrow logo.
dol_print_ip($ip, $mode=0)
Return an IP formated to be shown on screen.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
GETPOSTINT($paramname, $method=0)
Return value of a param into GET or POST supervariable.
isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
Function to test if an entry is enabled or not.
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
getDolUserInt($key, $default=0, $tmpuser=null)
Return Dolibarr user constant int value.
yn($yesno, $case=1, $color=0)
Return yes or no in current language.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
isASecretKey($keyname)
Return if string has a name dedicated to store a secret.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
print_fleche_navigation($page, $file, $options='', $nextpage=0, $betweenarrows='', $afterarrows='', $limit=-1, $totalnboflines=0, $hideselectlimit=0, $beforearrows='', $hidenavigation=0)
Function to show navigation arrows into lists.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
get_date_range($date_start, $date_end, $format='', $outputlangs='', $withparenthesis=1)
Format output for start and end date.
get_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Get formated error messages to output (Used to show messages on html output).
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
roundUpToNextMultiple($n, $x=5)
Round to next multiple.
dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled='', $morecss='classlink button bordertransp', $jsonopen='', $backtopagejsfields='', $accesskey='')
Return HTML code to output a button to open a dialog popup box.
dol_user_country()
Return country code for current user.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_format_address($object, $withcountry=0, $sep="\n", $outputlangs='', $mode=0, $extralangcode='')
Return a formated address (part address/zip/town/state) according to country rules.
isHTTPS()
Return if we are using a HTTPS connexion Check HTTPS (no way to be modified by user but may be empty ...
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
picto_required()
Return picto saying a field is required.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
img_action($titlealt, $numaction, $picto='', $moreatt='')
Show logo action.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0)
Set event message in dol_events session object.
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
GETPOSTDATE($prefix, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
printCommonFooter($zone='private')
Print common footer : conf->global->MAIN_HTML_FOOTER js for switch of menu hider js for conf->global-...
checkVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
img_down($titlealt='default', $selected=0, $moreclass='')
Show down arrow logo.
getTaxesFromId($vatrate, $buyer=null, $seller=null, $firstparamisid=1)
Get tax (VAT) main information from Id.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
utf8_valid($str)
Check if a string is in UTF8.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
getDolUserString($key, $default='', $tmpuser=null)
Return Dolibarr user constant string value.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
img_allow($allow, $titlealt='default')
Show tick logo if allowed.
isValidMXRecord($domain)
Return if the domain name has a valid MX record.
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
get_htmloutput_mesg($mesgstring='', $mesgarray='', $style='ok', $keepembedded=0)
Get formated messages to output (Used to show messages on html output).
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0)
Format phone numbers according to country.
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
dol_fiche_head($links=array(), $active='0', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tab header of a card.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
get_localtax_by_third($local)
Get values of localtaxes (1 or 2) for company country for the common vat with the highest value.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0)
Clean a string to keep only desirable HTML tags.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
ajax_autoselect($htmlname, $addlink='', $textonlink='Link')
Make content of an input box selected when we click into input field.
img_view($titlealt='default', $float=0, $other='class="valignmiddle"')
Show logo view card.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_eval($s, $returnvalue=0, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_strftime($fmt, $ts=false, $is_gmt=false)
Format a string.
img_picto_common($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $notitle=0)
Show picto (generic function)
img_search($titlealt='default', $other='')
Show search logo.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
isValidPhone($phone)
Return true if phone number syntax is ok TODO Decide what to do with this.
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
img_previous($titlealt='default', $moreatt='')
Show previous logo.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
dol_print_profids($profID, $profIDtype, $countrycode='', $addcpButton=1, $separ='&nbsp;')
Format profIDs according to country.
fieldLabel($langkey, $fieldkey, $fieldrequired=0)
Show a string with the label tag dedicated to the HTML edit field.
getBrowserInfo($user_agent)
Return information about user browser.
dolGetFirstLetters($s, $nbofchar=1)
Return first letters of a strings.
dol_strtoupper($string, $encoding="UTF-8")
Convert a string to upper.
dol_sanitizeUrl($stringtoclean, $type=1)
Clean a string to use it as an URL (into a href or src attribute)
img_printer($titlealt="default", $other='')
Show printer logo.
dol_htmloutput_events($disabledoutputofmessages=0)
Print formated messages to output (Used to show messages on html output).
getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $disablesortlink=0, $tooltip='', $forcenowrapcolumntitle=0)
Get title line of an array.
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
ascii_check($str)
Check if a string is in ASCII.
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
getArrayOfSocialNetworks()
Get array of social network dictionary.
dolGetButtonTitleSeparator($moreClass="")
Add space between dolGetButtonTitle.
dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes=array("allow", "allowfullscreen", "alt", "class", "contenteditable", "data-html", "frameborder", "height", "href", "id", "name", "src", "style", "target", "title", "width"))
Clean a string from some undesirable HTML tags.
num2Alpha($n)
Return a numeric value into an Excel like column number.
dol_size($size, $type='')
Optimize a size for some browsers (phone, smarphone, ...)
img_split($titlealt='default', $other='class="pictosplit"')
Show split logo.
img_pdf($titlealt='default', $size=3)
Show pdf logo.
dolGetCountryCodeFromIp($ip)
Return a country code from IP.
dol_textishtml($msg, $option=0)
Return if a text is a html content.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
colorIsLight($stringcolor)
Return true if the color is light.
readfileLowMemory($fullpath_original_file_osencoded, $method=-1)
Return a file on output using a low memory.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
dol_shutdown()
Function called at end of web php process.
dol_print_address($address, $htmlid, $element, $id, $noprint=0, $charfornl='')
Format address string.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_print_error_email($prefixcode, $errormessage='', $errormessages=array(), $morecss='error', $email='')
Show a public email and error code to contact if technical error.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='float')
Show Url link.
print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
dol_bc($var, $moreclass='')
Return string to add class property on html element with pair/impair.
print_titre($title)
Show a title.
getElementProperties($element_type)
Get an array with properties of an element.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_string_nounprintableascii($str, $removetabcrlf=1)
Clean a string from all non printable ASCII chars (0x00-0x1F and 0x7F).
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
img_error($titlealt='default')
Show error logo.
getTimelineIcon($actionstatic, &$histo, $key)
Get timeline icon.
dol_htmloutput_mesg($mesgstring='', $mesgarray=array(), $style='ok', $keepembedded=0)
Print formated messages to output (Used to show messages on html output).
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
buildParamDate($prefix, $timestamp=null, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
img_next($titlealt='default', $moreatt='')
Show next logo.
print_date_range($date_start, $date_end, $format='', $outputlangs='')
Format output for start and end date.
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_string_is_good_iso($s, $clean=0)
Check if a string is a correct iso string If not, it will not be considered as HTML encoded even if i...
getNonce()
Return a random string to be used as a nonce value for js.
complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode='add', $filterorigmodule='')
Complete or removed entries into a head array (used to build tabs).
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
Return localtax vat rate of a product in a particular country or default country vat if product is un...
getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $object=null, $include=null)
Return array of possible common substitutions.
dol_nboflines($s, $maxchar=0)
Return nb of lines of a clear text.
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js and dangerous content.
jsonOrUnserialize($stringtodecode)
Decode an encode string.
addSummaryTableLine($tableColumnCount, $num, $nbofloop=0, $total=0, $noneWord="None", $extraRightColumn=false)
Add a summary line to the current open table ("None", "XMoreLines" or "Total xxx")
isValidEmail($address, $acceptsupervisorkey=0, $acceptuserkey=0)
Return true if email syntax is ok.
getActionCommEcmList($object)
getActionCommEcmList
dol_ucwords($string, $encoding="UTF-8")
Convert first character of all the words of a string to upper.
img_edit_add($titlealt='default', $other='')
Show logo +.
verifCond($strToEvaluate)
Verify if condition in string is ok or not.
if(!function_exists( 'utf8_encode')) if(!function_exists('utf8_decode')) if(!function_exists( 'str_starts_with')) if(!function_exists('str_ends_with')) if(!function_exists( 'str_contains')) getMultidirOutput($object, $module='')
Return the full path of the directory where a module (or an object of a module) stores its files.
print_fiche_titre($title, $mesg='', $picto='generic', $pictoisfullpath=0, $id='')
Show a title with picto.
get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice=0)
Return vat rate of a product in a particular country, or default country vat if product is unknown.
dolForgeDummyCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
dol_escape_json($stringtoescape)
Returns text escaped for inclusion into javascript code.
dolForgeCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
getUserRemoteIP()
Return the IP of remote user.
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_validElement($element)
Return if var element is ok.
img_credit_card($brand, $morecss=null)
Return image of a credit card according to its brand name.
dolPrintHTML($s)
Return a string ready to be output on HTML page To use text inside an attribute, use can use only dol...
img_searchclear($titlealt='default', $other='')
Show search logo.
dolPrintLabel($s)
Return a string label ready to be output on HTML content To use text inside an attribute,...
fetchObjectByElement($element_id, $element_type, $element_ref='')
Fetch an object from its id and element_type Inclusion of classes is automatic.
utf8_check($str)
Check if a string is in UTF8.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
show_actions_messaging($conf, $langs, $db, $filterobj, $objcon='', $noprint=0, $actioncode='', $donetodo='done', $filters=array(), $sortfield='a.datep, a.id', $sortorder='DESC')
Show html area with actions in messaging format.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
getDictionaryValue($tablename, $field, $id, $checkentity=false, $rowidfield='rowid')
Return the value of a filed into a dictionary for the record $id.
img_up($titlealt='default', $selected=0, $moreclass='')
Show top arrow logo.
dol_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Print formated error messages to output (Used to show messages on html output).
getFieldErrorIcon($fieldValidationErrorMsg)
get field error icon
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
img_edit_remove($titlealt='default', $other='')
Show logo -.
img_info($titlealt='default')
Show info logo.
getDoliDBInstance($type, $host, $user, $pass, $name, $port)
Return a DoliDB instance (database handler).
dol_sanitizeEmail($stringtoclean)
Clean a string to use it as an Email.
dol_nboflines_bis($text, $maxlinesize=0, $charset='UTF-8')
Return nb of lines of a formated text with and (WARNING: string must not have mixed and br sepa...
dolPrintHTMLForTextArea($s)
Return a string ready to be output on input textarea To use text inside an attribute,...
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
dol_convertToWord($num, $langs, $currency='', $centimes=false)
Function to return a number into a text.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1632
document_preview(file, type, title)
Function show document preview.
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
if(!empty( $_SERVER[ 'MAIN_SHOW_TUNING_INFO'])) realCharForNumericEntities($matches)
Return the real char for a numeric entities.
Definition main.inc.php:63
dol_setcache($memoryid, $data, $expire=0)
Save data into a memory area shared by all users, all sessions on server.
dol_getcache($memoryid)
Read a memory area shared by all users, all sessions on server.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:120
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:123
dolGetRandomBytes($length)
Return a string of random bytes (hexa string) with length = $length fro cryptographic purposes.