dolibarr 18.0.8
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
1822 if (!array_key_exists($level, $logLevels)) {
1823 dol_syslog('Error Bad Log Level '.$level, LOG_ERR);
1824 $level = $logLevels[LOG_ERR];
1825 }
1826 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
1827 return;
1828 }
1829
1830 if (empty($conf->global->MAIN_SHOW_PASSWORD_INTO_LOG)) {
1831 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
1832 }
1833
1834 // If adding log inside HTML page is required
1835 if ((!empty($_REQUEST['logtohtml']) && !empty($conf->global->MAIN_ENABLE_LOG_TO_HTML))
1836 || (!empty($user->rights->debugbar->read) && is_object($debugbar))) {
1837 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".$logLevels[$level]." ".$message;
1838 }
1839
1840 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
1841 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
1842 if (!empty($conf->global->MAIN_ENABLE_LOG_INLINE_HTML) && !empty($_GET["log"])) {
1843 print "\n\n<!-- Log start\n";
1844 print dol_escape_htmltag($message)."\n";
1845 print "Log end -->\n";
1846 }
1847
1848 $data = array(
1849 'message' => $message,
1850 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
1851 'level' => $level,
1852 'user' => ((is_object($user) && $user->id) ? $user->login : false),
1853 'ip' => false
1854 );
1855
1856 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
1857 if (!empty($remoteip)) {
1858 $data['ip'] = $remoteip;
1859 // This is when server run behind a reverse proxy
1860 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
1861 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
1862 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
1863 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
1864 }
1865 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
1866 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
1867 $data['ip'] = $_SERVER['SERVER_ADDR'];
1868 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
1869 // 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).
1870 $data['ip'] = $_SERVER['COMPUTERNAME'].(empty($_SERVER['USERNAME']) ? '' : '@'.$_SERVER['USERNAME']);
1871 } elseif (!empty($_SERVER['LOGNAME'])) {
1872 // 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).
1873 $data['ip'] = '???@'.$_SERVER['LOGNAME'];
1874 }
1875
1876 // Loop on each log handler and send output
1877 foreach ($conf->loghandlers as $loghandlerinstance) {
1878 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
1879 continue;
1880 }
1881 $loghandlerinstance->export($data, $suffixinfilename);
1882 }
1883 unset($data);
1884 }
1885
1886 if ($ident > 0) {
1887 foreach ($conf->loghandlers as $loghandlerinstance) {
1888 $loghandlerinstance->setIdent($ident);
1889 }
1890 }
1891}
1892
1909function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
1910{
1911 global $conf;
1912
1913 if (strpos($url, '?') > 0) {
1914 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1915 } else {
1916 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1917 }
1918
1919 $out = '';
1920
1921 $backtopagejsfieldsid = ''; $backtopagejsfieldslabel = '';
1922 if ($backtopagejsfields) {
1923 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
1924 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
1925 $backtopagejsfields = $name.":".$backtopagejsfields;
1926 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
1927 } else {
1928 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
1929 }
1930 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
1931 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
1932 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
1933 }
1934
1935 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
1936 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
1937 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
1938 if (empty($conf->use_javascript_ajax)) {
1939 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
1940 } elseif ($jsonopen) {
1941 $out .= ' href="#" onclick="'.$jsonopen.'"';
1942 } else {
1943 $out .= ' href="#"';
1944 }
1945 $out .= '>'.$buttonstring.'</a>';
1946
1947 if (!empty($conf->use_javascript_ajax)) {
1948 // Add code to open url using the popup. Add also hidden field to retreive the returned variables
1949 $out .= '<!-- code to open popup and variables to retreive returned variables -->';
1950 $out .= '<div id="idfordialog'.$name.'" class="hidden">div for dialog</div>';
1951 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">div for returned id</div>';
1952 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">div for returned label</div>';
1953 $out .= '<!-- Add js code to open dialog popup on dialog -->';
1954 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
1955 jQuery(document).ready(function () {
1956 jQuery(".button_'.$name.'").click(function () {
1957 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
1958 var $tmpdialog = $(\'#idfordialog'.$name.'\');
1959 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
1960 $tmpdialog.dialog({
1961 autoOpen: false,
1962 modal: true,
1963 height: (window.innerHeight - 150),
1964 width: \'80%\',
1965 title: \''.dol_escape_js($label).'\',
1966 open: function (event, ui) {
1967 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
1968 },
1969 close: function (event, ui) {
1970 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
1971 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
1972 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
1973 if (returnedid != "" && returnedid != "div for returned id") {
1974 jQuery("#'.(empty($backtopagejsfieldsid)?"none":$backtopagejsfieldsid).'").val(returnedid);
1975 }
1976 if (returnedlabel != "" && returnedlabel != "div for returned label") {
1977 jQuery("#'.(empty($backtopagejsfieldslabel)?"none":$backtopagejsfieldslabel).'").val(returnedlabel);
1978 }
1979 }
1980 });
1981
1982 $tmpdialog.dialog(\'open\');
1983 return false;
1984 });
1985 });
1986 </script>';
1987 }
1988 return $out;
1989}
1990
2007function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2008{
2009 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2010}
2011
2028function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2029{
2030 global $conf, $langs, $hookmanager;
2031
2032 // Show title
2033 $showtitle = 1;
2034 if (!empty($conf->dol_optimize_smallscreen)) {
2035 $showtitle = 0;
2036 }
2037
2038 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2039
2040 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2041 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2042 }
2043
2044 // Show right part
2045 if ($morehtmlright) {
2046 $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.
2047 }
2048
2049 // Show title
2050 if (!empty($title) && $showtitle && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2051 $limittitle = 30;
2052 $out .= '<a class="tabTitle">';
2053 if ($picto) {
2054 $noprefix = $pictoisfullpath;
2055 if (strpos($picto, 'fontawesome_') !== false) {
2056 $noprefix = 1;
2057 }
2058 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2059 }
2060 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2061 $out .= '</a>';
2062 }
2063
2064 // Show tabs
2065
2066 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2067 $maxkey = -1;
2068 if (is_array($links) && !empty($links)) {
2069 $keys = array_keys($links);
2070 if (count($keys)) {
2071 $maxkey = max($keys);
2072 }
2073 }
2074
2075 // Show tabs
2076 // if =0 we don't use the feature
2077 if (empty($limittoshow)) {
2078 $limittoshow = (empty($conf->global->MAIN_MAXTABS_IN_CARD) ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2079 }
2080 if (!empty($conf->dol_optimize_smallscreen)) {
2081 $limittoshow = 2;
2082 }
2083
2084 $displaytab = 0;
2085 $nbintab = 0;
2086 $popuptab = 0;
2087 $outmore = '';
2088 for ($i = 0; $i <= $maxkey; $i++) {
2089 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2090 // If active tab is already present
2091 if ($i >= $limittoshow) {
2092 $limittoshow--;
2093 }
2094 }
2095 }
2096
2097 for ($i = 0; $i <= $maxkey; $i++) {
2098 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2099 $isactive = true;
2100 } else {
2101 $isactive = false;
2102 }
2103
2104 if ($i < $limittoshow || $isactive) {
2105 // Output entry with a visible tab
2106 $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])).' -->';
2107
2108 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2109 if (!empty($links[$i][0])) {
2110 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2111 } else {
2112 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2113 }
2114 } elseif (!empty($links[$i][1])) {
2115 //print "x $i $active ".$links[$i][2]." z";
2116 $out .= '<div class="tab tab'.($isactive?'active':'unactive').'" style="margin: 0 !important">';
2117 if (!empty($links[$i][0])) {
2118 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2119 $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).'">';
2120 }
2121 $out .= $links[$i][1];
2122 if (!empty($links[$i][0])) {
2123 $out .= '</a>'."\n";
2124 }
2125 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2126 $out .= '</div>';
2127 }
2128
2129 $out .= '</div>';
2130 } else {
2131 // Add entry into the combo popup with the other tabs
2132 if (!$popuptab) {
2133 $popuptab = 1;
2134 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2135 }
2136 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2137 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2138 if (!empty($links[$i][0])) {
2139 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2140 } else {
2141 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2142 }
2143 } elseif (!empty($links[$i][1])) {
2144 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2145 $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.
2146 $outmore .= '</a>'."\n";
2147 }
2148 $outmore .= '</div>';
2149
2150 $nbintab++;
2151 }
2152 $displaytab = $i;
2153 }
2154 if ($popuptab) {
2155 $outmore .= '</div>';
2156 }
2157
2158 if ($popuptab) { // If there is some tabs not shown
2159 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2160 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2161 $widthofpopup = 200;
2162
2163 $tabsname = $moretabssuffix;
2164 if (empty($tabsname)) {
2165 $tabsname = str_replace("@", "", $picto);
2166 }
2167 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2168 $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".
2169 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2170 $out .= $outmore;
2171 $out .= '</div>';
2172 $out .= '<div></div>';
2173 $out .= "</div>\n";
2174
2175 $out .= '<script nonce="'.getNonce().'">';
2176 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2177 var x = this.offsetLeft, y = this.offsetTop;
2178 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2179 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2180 $('#moretabsList".$tabsname."').css('".$right."','8px');
2181 }
2182 $('#moretabsList".$tabsname."').css('".$left."','auto');
2183 });
2184 ";
2185 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2186 $out .= "</script>";
2187 }
2188
2189 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2190 $out .= "</div>\n";
2191 }
2192
2193 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2194 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom'))).'">'."\n";
2195 }
2196 if (!empty($dragdropfile)) {
2197 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2198 }
2199 $parameters = array('tabname' => $active, 'out' => $out);
2200 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2201 if ($reshook > 0) {
2202 $out = $hookmanager->resPrint;
2203 }
2204
2205 return $out;
2206}
2207
2215function dol_fiche_end($notab = 0)
2216{
2217 print dol_get_fiche_end($notab);
2218}
2219
2226function dol_get_fiche_end($notab = 0)
2227{
2228 if (!$notab || $notab == -1) {
2229 return "\n</div>\n";
2230 } else {
2231 return '';
2232 }
2233}
2234
2254function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2255{
2256 global $conf, $form, $user, $langs, $hookmanager, $action;
2257
2258 $error = 0;
2259
2260 $maxvisiblephotos = 1;
2261 $showimage = 1;
2262 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2263 $showbarcode = empty($conf->barcode->enabled) ? 0 : (empty($object->barcode) ? 0 : 1);
2264 if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) {
2265 $showbarcode = 0;
2266 }
2267 $modulepart = 'unknown';
2268
2269 if ($object->element == 'societe' || $object->element == 'contact' || $object->element == 'product' || $object->element == 'ticket') {
2270 $modulepart = $object->element;
2271 } elseif ($object->element == 'member') {
2272 $modulepart = 'memberphoto';
2273 } elseif ($object->element == 'user') {
2274 $modulepart = 'userphoto';
2275 }
2276
2277 if (class_exists("Imagick")) {
2278 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2279 $modulepart = $object->element;
2280 } elseif ($object->element == 'fichinter') {
2281 $modulepart = 'ficheinter';
2282 } elseif ($object->element == 'contrat') {
2283 $modulepart = 'contract';
2284 } elseif ($object->element == 'order_supplier') {
2285 $modulepart = 'supplier_order';
2286 } elseif ($object->element == 'invoice_supplier') {
2287 $modulepart = 'supplier_invoice';
2288 }
2289 }
2290
2291 if ($object->element == 'product') {
2292 $width = 80;
2293 $cssclass = 'photowithmargin photoref';
2294 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2295 $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : 5);
2296 if ($conf->browser->layout == 'phone') {
2297 $maxvisiblephotos = 1;
2298 }
2299 if ($showimage) {
2300 $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>';
2301 } else {
2302 if (!empty($conf->global->PRODUCT_NODISPLAYIFNOPHOTO)) {
2303 $nophoto = '';
2304 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2305 } else { // Show no photo link
2306 $nophoto = '/public/theme/common/nophoto.png';
2307 $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>';
2308 }
2309 }
2310 } elseif ($object->element == 'ticket') {
2311 $width = 80;
2312 $cssclass = 'photoref';
2313 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2314 $maxvisiblephotos = (isset($conf->global->TICKET_MAX_VISIBLE_PHOTO) ? $conf->global->TICKET_MAX_VISIBLE_PHOTO : 2);
2315 if ($conf->browser->layout == 'phone') {
2316 $maxvisiblephotos = 1;
2317 }
2318
2319 if ($showimage) {
2320 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2321 if ($object->nbphoto > 0) {
2322 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2323 } else {
2324 $showimage = 0;
2325 }
2326 }
2327 if (!$showimage) {
2328 if (!empty($conf->global->TICKET_NODISPLAYIFNOPHOTO)) {
2329 $nophoto = '';
2330 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2331 } else { // Show no photo link
2332 $nophoto = img_picto('No photo', 'object_ticket');
2333 $morehtmlleft .= '<!-- No photo to show -->';
2334 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2335 $morehtmlleft .= $nophoto;
2336 $morehtmlleft .= '</div></div>';
2337 }
2338 }
2339 } else {
2340 if ($showimage) {
2341 if ($modulepart != 'unknown') {
2342 $phototoshow = '';
2343 // Check if a preview file is available
2344 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2345 $objectref = dol_sanitizeFileName($object->ref);
2346 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2347 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2348 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2349 $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
2350 } else {
2351 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2352 }
2353 if (empty($subdir)) {
2354 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2355 }
2356
2357 $filepath = $dir_output.$subdir."/";
2358
2359 $filepdf = $filepath.$objectref.".pdf";
2360 $relativepath = $subdir.'/'.$objectref.'.pdf';
2361
2362 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2363 $fileimage = $filepdf.'_preview.png';
2364 $relativepathimage = $relativepath.'_preview.png';
2365
2366 $pdfexists = file_exists($filepdf);
2367
2368 // If PDF file exists
2369 if ($pdfexists) {
2370 // Conversion du PDF en image png si fichier png non existant
2371 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2372 if (empty($conf->global->MAIN_DISABLE_PDF_THUMBS)) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2373 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2374 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2375 if ($ret < 0) {
2376 $error++;
2377 }
2378 }
2379 }
2380 }
2381
2382 if ($pdfexists && !$error) {
2383 $heightforphotref = 80;
2384 if (!empty($conf->dol_optimize_smallscreen)) {
2385 $heightforphotref = 60;
2386 }
2387 // If the preview file is found
2388 if (file_exists($fileimage)) {
2389 $phototoshow = '<div class="photoref">';
2390 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2391 $phototoshow .= '</div>';
2392 }
2393 }
2394 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo'
2395 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2396 }
2397
2398 if ($phototoshow) {
2399 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2400 $morehtmlleft .= $phototoshow;
2401 $morehtmlleft .= '</div>';
2402 }
2403 }
2404
2405 if (empty($phototoshow)) { // Show No photo link (picto of object)
2406 if ($object->element == 'action') {
2407 $width = 80;
2408 $cssclass = 'photorefcenter';
2409 $nophoto = img_picto('No photo', 'title_agenda');
2410 } else {
2411 $width = 14;
2412 $cssclass = 'photorefcenter';
2413 $picto = $object->picto;
2414 $prefix = 'object_';
2415 if ($object->element == 'project' && !$object->public) {
2416 $picto = 'project'; // instead of projectpub
2417 }
2418 if (strpos($picto, 'fontawesome_') !== false) {
2419 $prefix = '';
2420 }
2421 $nophoto = img_picto('No photo', $prefix.$picto);
2422 }
2423 $morehtmlleft .= '<!-- No photo to show -->';
2424 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2425 $morehtmlleft .= $nophoto;
2426 $morehtmlleft .= '</div></div>';
2427 }
2428 }
2429 }
2430
2431 // Show barcode
2432 if ($showbarcode) {
2433 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2434 }
2435
2436 if ($object->element == 'societe') {
2437 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2438 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2439 } else {
2440 $morehtmlstatus .= $object->getLibStatut(6);
2441 }
2442 } elseif ($object->element == 'product') {
2443 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2444 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2445 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2446 } else {
2447 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2448 }
2449 $morehtmlstatus .= ' &nbsp; ';
2450 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2451 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2452 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2453 } else {
2454 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2455 }
2456 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier'))) {
2457 $totalallpayments = $object->getSommePaiement(0);
2458 $totalallpayments += $object->getSumCreditNotesUsed(0);
2459 $totalallpayments += $object->getSumDepositsUsed(0);
2460 $tmptxt = $object->getLibStatut(6, $totalallpayments);
2461 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2462 $tmptxt = $object->getLibStatut(5, $totalallpayments);
2463 }
2464 $morehtmlstatus .= $tmptxt;
2465 } elseif (in_array($object->element, array('chargesociales', 'loan', 'tva'))) {
2466 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2467 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2468 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2469 }
2470 $morehtmlstatus .= $tmptxt;
2471 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2472 if ($object->statut == 0) {
2473 $morehtmlstatus .= $object->getLibStatut(5);
2474 } else {
2475 $morehtmlstatus .= $object->getLibStatut(4);
2476 }
2477 } elseif ($object->element == 'facturerec') {
2478 if ($object->frequency == 0) {
2479 $morehtmlstatus .= $object->getLibStatut(2);
2480 } else {
2481 $morehtmlstatus .= $object->getLibStatut(5);
2482 }
2483 } elseif ($object->element == 'project_task') {
2484 $object->fk_statut = 1;
2485 if ($object->progress > 0) {
2486 $object->fk_statut = 2;
2487 }
2488 if ($object->progress >= 100) {
2489 $object->fk_statut = 3;
2490 }
2491 $tmptxt = $object->getLibStatut(5);
2492 $morehtmlstatus .= $tmptxt; // No status on task
2493 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2494 $tmptxt = $object->getLibStatut(6);
2495 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2496 $tmptxt = $object->getLibStatut(5);
2497 }
2498 $morehtmlstatus .= $tmptxt;
2499 }
2500
2501 // Add if object was dispatched "into accountancy"
2502 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2503 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2504 if (method_exists($object, 'getVentilExportCompta')) {
2505 $accounted = $object->getVentilExportCompta();
2506 $langs->load("accountancy");
2507 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2508 }
2509 }
2510
2511 // Add alias for thirdparty
2512 if (!empty($object->name_alias)) {
2513 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
2514 }
2515
2516 // Add label
2517 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
2518 if (!empty($object->label)) {
2519 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
2520 }
2521 }
2522
2523 // Show address and email
2524 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
2525 $moreaddress = $object->getBannerAddress('refaddress', $object);
2526 if ($moreaddress) {
2527 $morehtmlref .= '<div class="refidno refaddress">';
2528 $morehtmlref .= $moreaddress;
2529 $morehtmlref .= '</div>';
2530 }
2531 }
2532 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)) {
2533 $morehtmlref .= '<div style="clear: both;"></div>';
2534 $morehtmlref .= '<div class="refidno opacitymedium">';
2535 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
2536 $morehtmlref .= '</div>';
2537 }
2538
2539 $parameters=array('morehtmlref'=>$morehtmlref);
2540 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
2541 if ($reshook < 0) {
2542 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2543 } elseif (empty($reshook)) {
2544 $morehtmlref .= $hookmanager->resPrint;
2545 } elseif ($reshook > 0) {
2546 $morehtmlref = $hookmanager->resPrint;
2547 }
2548
2549
2550 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
2551 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
2552 print '</div>';
2553 print '<div class="underrefbanner clearboth"></div>';
2554}
2555
2565function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
2566{
2567 global $langs;
2568 $ret = '';
2569 if ($fieldrequired) {
2570 $ret .= '<span class="fieldrequired">';
2571 }
2572 $ret .= '<label for="'.$fieldkey.'">';
2573 $ret .= $langs->trans($langkey);
2574 $ret .= '</label>';
2575 if ($fieldrequired) {
2576 $ret .= '</span>';
2577 }
2578 return $ret;
2579}
2580
2588function dol_bc($var, $moreclass = '')
2589{
2590 global $bc;
2591 $ret = ' '.$bc[$var];
2592 if ($moreclass) {
2593 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
2594 }
2595 return $ret;
2596}
2597
2611function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = '', $mode = 0, $extralangcode = '')
2612{
2613 global $conf, $langs, $hookmanager;
2614
2615 $ret = '';
2616 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
2617
2618 // See format of addresses on https://en.wikipedia.org/wiki/Address
2619 // Address
2620 if (empty($mode)) {
2621 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
2622 }
2623 // Zip/Town/State
2624 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || !empty($conf->global->MAIN_FORCE_STATE_INTO_ADDRESS)) {
2625 // US: title firstname name \n address lines \n town, state, zip \n country
2626 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2627 $ret .= (($ret && $town) ? $sep : '').$town;
2628
2629 if (!empty($object->state)) {
2630 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
2631 }
2632 if (!empty($object->zip)) {
2633 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
2634 }
2635 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
2636 // UK: title firstname name \n address lines \n town state \n zip \n country
2637 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2638 $ret .= ($ret ? $sep : '').$town;
2639 if (!empty($object->state)) {
2640 $ret .= ($ret ? ", " : '').$object->state;
2641 }
2642 if (!empty($object->zip)) {
2643 $ret .= ($ret ? $sep : '').$object->zip;
2644 }
2645 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
2646 // ES: title firstname name \n address lines \n zip town \n state \n country
2647 $ret .= ($ret ? $sep : '').$object->zip;
2648 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2649 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2650 if (!empty($object->state)) {
2651 $ret .= $sep.$object->state;
2652 }
2653 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
2654 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
2655 // See https://www.sljfaq.org/afaq/addresses.html
2656 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2657 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
2658 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
2659 // IT: title firstname name\n address lines \n zip town state_code \n country
2660 $ret .= ($ret ? $sep : '').$object->zip;
2661 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2662 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2663 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
2664 } else {
2665 // Other: title firstname name \n address lines \n zip town[, state] \n country
2666 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2667 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
2668 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
2669 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
2670 $ret .= ($ret ? ", " : '').$object->state;
2671 }
2672 }
2673
2674 if (!is_object($outputlangs)) {
2675 $outputlangs = $langs;
2676 }
2677 if ($withcountry) {
2678 $langs->load("dict");
2679 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
2680 }
2681 if ($hookmanager) {
2682 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
2683 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
2684 if ($reshook > 0) {
2685 $ret = '';
2686 }
2687 $ret .= $hookmanager->resPrint;
2688 }
2689
2690 return $ret;
2691}
2692
2693
2694
2703function dol_strftime($fmt, $ts = false, $is_gmt = false)
2704{
2705 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
2706 return ($is_gmt) ? @gmstrftime($fmt, $ts) : @strftime($fmt, $ts);
2707 } else {
2708 return 'Error date into a not supported range';
2709 }
2710}
2711
2733function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = '', $encodetooutput = false)
2734{
2735 global $conf, $langs;
2736
2737 // If date undefined or "", we return ""
2738 if (dol_strlen($time) == 0) {
2739 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
2740 }
2741
2742 if ($tzoutput === 'auto') {
2743 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
2744 }
2745
2746 // Clean parameters
2747 $to_gmt = false;
2748 $offsettz = $offsetdst = 0;
2749 if ($tzoutput) {
2750 $to_gmt = true; // For backward compatibility
2751 if (is_string($tzoutput)) {
2752 if ($tzoutput == 'tzserver') {
2753 $to_gmt = false;
2754 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
2755 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
2756 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
2757 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
2758 $to_gmt = true;
2759 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
2760
2761 if (class_exists('DateTimeZone')) {
2762 $user_date_tz = new DateTimeZone($offsettzstring);
2763 $user_dt = new DateTime();
2764 $user_dt->setTimezone($user_date_tz);
2765 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
2766 $offsettz = $user_dt->getOffset(); // should include dst ?
2767 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
2768 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
2769 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
2770 }
2771 }
2772 }
2773 }
2774 if (!is_object($outputlangs)) {
2775 $outputlangs = $langs;
2776 }
2777 if (!$format) {
2778 $format = 'daytextshort';
2779 }
2780
2781 // Do we have to reduce the length of date (year on 2 chars) to save space.
2782 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
2783 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour'))) ? 1 : 0; // Test on original $format param.
2784 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
2785 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
2786 if ($formatwithoutreduce != $format) {
2787 $format = $formatwithoutreduce;
2788 $reduceformat = 1;
2789 } // so format 'dayreduceformat' is processed like day
2790
2791 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
2792 // TODO Add format daysmallyear and dayhoursmallyear
2793 if ($format == 'day') {
2794 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
2795 } elseif ($format == 'hour') {
2796 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
2797 } elseif ($format == 'hourduration') {
2798 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
2799 } elseif ($format == 'daytext') {
2800 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
2801 } elseif ($format == 'daytextshort') {
2802 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
2803 } elseif ($format == 'dayhour') {
2804 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
2805 } elseif ($format == 'dayhoursec') {
2806 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
2807 } elseif ($format == 'dayhourtext') {
2808 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
2809 } elseif ($format == 'dayhourtextshort') {
2810 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
2811 } elseif ($format == 'dayhourlog') {
2812 // Format not sensitive to language
2813 $format = '%Y%m%d%H%M%S';
2814 } elseif ($format == 'dayhourlogsmall') {
2815 // Format not sensitive to language
2816 $format = '%y%m%d%H%M';
2817 } elseif ($format == 'dayhourldap') {
2818 $format = '%Y%m%d%H%M%SZ';
2819 } elseif ($format == 'dayhourxcard') {
2820 $format = '%Y%m%dT%H%M%SZ';
2821 } elseif ($format == 'dayxcard') {
2822 $format = '%Y%m%d';
2823 } elseif ($format == 'dayrfc') {
2824 $format = '%Y-%m-%d'; // DATE_RFC3339
2825 } elseif ($format == 'dayhourrfc') {
2826 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
2827 } elseif ($format == 'standard') {
2828 $format = '%Y-%m-%d %H:%M:%S';
2829 }
2830
2831 if ($reduceformat) {
2832 $format = str_replace('%Y', '%y', $format);
2833 $format = str_replace('yyyy', 'yy', $format);
2834 }
2835
2836 // Clean format
2837 if (preg_match('/%b/i', $format)) { // There is some text to translate
2838 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2839 $format = str_replace('%b', '__b__', $format);
2840 $format = str_replace('%B', '__B__', $format);
2841 }
2842 if (preg_match('/%a/i', $format)) { // There is some text to translate
2843 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2844 $format = str_replace('%a', '__a__', $format);
2845 $format = str_replace('%A', '__A__', $format);
2846 }
2847
2848 // Analyze date
2849 $reg = array();
2850 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
2851 dol_print_error('', "Functions.lib::dol_print_date function called with a bad value from page ".$_SERVER["PHP_SELF"]);
2852 return '';
2853 } 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
2854 // This part of code should not be used anymore.
2855 dol_syslog("Functions.lib::dol_print_date function called with a bad value from page ".$_SERVER["PHP_SELF"], LOG_WARNING);
2856 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
2857 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
2858 $syear = (!empty($reg[1]) ? $reg[1] : '');
2859 $smonth = (!empty($reg[2]) ? $reg[2] : '');
2860 $sday = (!empty($reg[3]) ? $reg[3] : '');
2861 $shour = (!empty($reg[4]) ? $reg[4] : '');
2862 $smin = (!empty($reg[5]) ? $reg[5] : '');
2863 $ssec = (!empty($reg[6]) ? $reg[6] : '');
2864
2865 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
2866
2867 if ($to_gmt) {
2868 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2869 } else {
2870 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2871 }
2872 $dtts = new DateTime();
2873 $dtts->setTimestamp($time);
2874 $dtts->setTimezone($tzo);
2875 $newformat = str_replace(
2876 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2877 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2878 $format);
2879 $ret = $dtts->format($newformat);
2880 $ret = str_replace(
2881 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2882 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2883 $ret
2884 );
2885 } else {
2886 // Date is a timestamps
2887 if ($time < 100000000000) { // Protection against bad date values
2888 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2889
2890 if ($to_gmt) {
2891 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2892 } else {
2893 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2894 }
2895 $dtts = new DateTime();
2896 $dtts->setTimestamp($timetouse);
2897 $dtts->setTimezone($tzo);
2898 $newformat = str_replace(
2899 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2900 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2901 $format);
2902 $ret = $dtts->format($newformat);
2903 $ret = str_replace(
2904 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2905 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2906 $ret
2907 );
2908 //var_dump($ret);exit;
2909 } else {
2910 $ret = 'Bad value '.$time.' for date';
2911 }
2912 }
2913
2914 if (preg_match('/__b__/i', $format)) {
2915 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2916
2917 if ($to_gmt) {
2918 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2919 } else {
2920 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2921 }
2922 $dtts = new DateTime();
2923 $dtts->setTimestamp($timetouse);
2924 $dtts->setTimezone($tzo);
2925 $month = $dtts->format("m");
2926 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
2927 if ($encodetooutput) {
2928 $monthtext = $outputlangs->transnoentities('Month'.$month);
2929 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
2930 } else {
2931 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
2932 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
2933 }
2934 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
2935 $ret = str_replace('__b__', $monthtextshort, $ret);
2936 $ret = str_replace('__B__', $monthtext, $ret);
2937 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
2938 //return $ret;
2939 }
2940 if (preg_match('/__a__/i', $format)) {
2941 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
2942 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
2943
2944 if ($to_gmt) {
2945 $tzo = new DateTimeZone('UTC');
2946 } else {
2947 $tzo = new DateTimeZone(date_default_timezone_get());
2948 }
2949 $dtts = new DateTime();
2950 $dtts->setTimestamp($timetouse);
2951 $dtts->setTimezone($tzo);
2952 $w = $dtts->format("w");
2953 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
2954
2955 $ret = str_replace('__A__', $dayweek, $ret);
2956 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
2957 }
2958
2959 return $ret;
2960}
2961
2962
2983function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
2984{
2985 if ($timestamp === '') {
2986 return array();
2987 }
2988
2989 $datetimeobj = new DateTime();
2990 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
2991 if ($forcetimezone) {
2992 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
2993 }
2994 $arrayinfo = array(
2995 'year'=>((int) date_format($datetimeobj, 'Y')),
2996 'mon'=>((int) date_format($datetimeobj, 'm')),
2997 'mday'=>((int) date_format($datetimeobj, 'd')),
2998 'wday'=>((int) date_format($datetimeobj, 'w')),
2999 'yday'=>((int) date_format($datetimeobj, 'z')),
3000 'hours'=>((int) date_format($datetimeobj, 'H')),
3001 'minutes'=>((int) date_format($datetimeobj, 'i')),
3002 'seconds'=>((int) date_format($datetimeobj, 's')),
3003 '0'=>$timestamp
3004 );
3005
3006 return $arrayinfo;
3007}
3008
3030function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3031{
3032 global $conf;
3033 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3034
3035 if ($gm === 'auto') {
3036 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3037 }
3038 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3039
3040 // Clean parameters
3041 if ($hour == -1 || empty($hour)) {
3042 $hour = 0;
3043 }
3044 if ($minute == -1 || empty($minute)) {
3045 $minute = 0;
3046 }
3047 if ($second == -1 || empty($second)) {
3048 $second = 0;
3049 }
3050
3051 // Check parameters
3052 if ($check) {
3053 if (!$month || !$day) {
3054 return '';
3055 }
3056 if ($day > 31) {
3057 return '';
3058 }
3059 if ($month > 12) {
3060 return '';
3061 }
3062 if ($hour < 0 || $hour > 24) {
3063 return '';
3064 }
3065 if ($minute < 0 || $minute > 60) {
3066 return '';
3067 }
3068 if ($second < 0 || $second > 60) {
3069 return '';
3070 }
3071 }
3072
3073 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3074 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3075 $localtz = new DateTimeZone($default_timezone);
3076 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3077 // We use dol_tz_string first because it is more reliable.
3078 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3079 try {
3080 $localtz = new DateTimeZone($default_timezone);
3081 } catch (Exception $e) {
3082 dol_syslog("Warning dol_tz_string contains an invalid value ".$_SESSION["dol_tz_string"], LOG_WARNING);
3083 $default_timezone = @date_default_timezone_get();
3084 }
3085 } elseif (strrpos($gm, "tz,") !== false) {
3086 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3087 try {
3088 $localtz = new DateTimeZone($timezone);
3089 } catch (Exception $e) {
3090 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3091 }
3092 }
3093
3094 if (empty($localtz)) {
3095 $localtz = new DateTimeZone('UTC');
3096 }
3097 //var_dump($localtz);
3098 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3099 $dt = new DateTime('now', $localtz);
3100 $dt->setDate((int) $year, (int) $month, (int) $day);
3101 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3102 $date = $dt->getTimestamp(); // should include daylight saving time
3103 //var_dump($date);
3104 return $date;
3105}
3106
3107
3118function dol_now($mode = 'auto')
3119{
3120 $ret = 0;
3121
3122 if ($mode === 'auto') {
3123 $mode = 'gmt';
3124 }
3125
3126 if ($mode == 'gmt') {
3127 $ret = time(); // Time for now at greenwich.
3128 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3129 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3130 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3131 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3132 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3133 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3134 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3135 // $ret=dol_now('gmt')+($tzsecond*3600);
3136 //}
3137 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3138 // Time for now with user timezone added
3139 //print 'time: '.time();
3140 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3141 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3142 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3143 }
3144
3145 return $ret;
3146}
3147
3148
3157function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3158{
3159 global $conf, $langs;
3160 $level = 1024;
3161
3162 if (!empty($conf->dol_optimize_smallscreen)) {
3163 $shortunit = 1;
3164 }
3165
3166 // Set value text
3167 if (empty($shortvalue) || $size < ($level * 10)) {
3168 $ret = $size;
3169 $textunitshort = $langs->trans("b");
3170 $textunitlong = $langs->trans("Bytes");
3171 } else {
3172 $ret = round($size / $level, 0);
3173 $textunitshort = $langs->trans("Kb");
3174 $textunitlong = $langs->trans("KiloBytes");
3175 }
3176 // Use long or short text unit
3177 if (empty($shortunit)) {
3178 $ret .= ' '.$textunitlong;
3179 } else {
3180 $ret .= ' '.$textunitshort;
3181 }
3182
3183 return $ret;
3184}
3185
3196function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = 'float')
3197{
3198 global $langs;
3199
3200 if (empty($url)) {
3201 return '';
3202 }
3203
3204 $link = '<a href="';
3205 if (!preg_match('/^http/i', $url)) {
3206 $link .= 'http://';
3207 }
3208 $link .= $url;
3209 $link .= '"';
3210 if ($target) {
3211 $link .= ' target="'.$target.'"';
3212 }
3213 $link .= '>';
3214 if (!preg_match('/^http/i', $url)) {
3215 $link .= 'http://';
3216 }
3217 $link .= dol_trunc($url, $max);
3218 $link .= '</a>';
3219
3220 if ($morecss == 'float') {
3221 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ?img_picto($langs->trans("Url"), 'globe').' ' : '').$link.'</div>';
3222 } else {
3223 return '<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ?img_picto($langs->trans("Url"), 'globe').' ' : '').$link.'</span>';
3224 }
3225}
3226
3239function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3240{
3241 global $conf, $user, $langs, $hookmanager;
3242
3243 $newemail = dol_escape_htmltag($email);
3244
3245 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && $withpicto) {
3246 $withpicto = 0;
3247 }
3248
3249 if (empty($email)) {
3250 return '&nbsp;';
3251 }
3252
3253 if (!empty($addlink)) {
3254 $newemail = '<a style="text-overflow: ellipsis;" href="';
3255 if (!preg_match('/^mailto:/i', $email)) {
3256 $newemail .= 'mailto:';
3257 }
3258 $newemail .= $email;
3259 $newemail .= '">';
3260 $newemail .= dol_trunc($email, $max);
3261 $newemail .= '</a>';
3262 if ($showinvalid && !isValidEmail($email)) {
3263 $langs->load("errors");
3264 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3265 }
3266
3267 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3268 $type = 'AC_EMAIL';
3269 $link = '';
3270 if (!empty($conf->global->AGENDA_ADDACTIONFOREMAIL)) {
3271 $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>';
3272 }
3273 if ($link) {
3274 $newemail = '<div>'.$newemail.' '.$link.'</div>';
3275 }
3276 }
3277 } else {
3278 if ($showinvalid && !isValidEmail($email)) {
3279 $langs->load("errors");
3280 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3281 }
3282 }
3283
3284 //$rep = '<div class="nospan" style="margin-right: 10px">';
3285 $rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto)).' ' : '').$newemail;
3286 //$rep .= '</div>';
3287 if ($hookmanager) {
3288 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3289
3290 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3291 if ($reshook > 0) {
3292 $rep = '';
3293 }
3294 $rep .= $hookmanager->resPrint;
3295 }
3296
3297 return $rep;
3298}
3299
3306{
3307 global $conf, $db;
3308
3309 $socialnetworks = array();
3310 // Enable caching of array
3311 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3312 $cachekey = 'socialnetworks_' . $conf->entity;
3313 $dataretrieved = dol_getcache($cachekey);
3314 if (!is_null($dataretrieved)) {
3315 $socialnetworks = $dataretrieved;
3316 } else {
3317 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3318 $sql .= " WHERE entity=".$conf->entity;
3319 $resql = $db->query($sql);
3320 if ($resql) {
3321 while ($obj = $db->fetch_object($resql)) {
3322 $socialnetworks[$obj->code] = array(
3323 'rowid' => $obj->rowid,
3324 'label' => $obj->label,
3325 'url' => $obj->url,
3326 'icon' => $obj->icon,
3327 'active' => $obj->active,
3328 );
3329 }
3330 }
3331 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3332 }
3333
3334 return $socialnetworks;
3335}
3336
3347function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3348{
3349 global $conf, $user, $langs;
3350
3351 $htmllink = $value;
3352
3353 if (empty($value)) {
3354 return '&nbsp;';
3355 }
3356
3357 if (!empty($type)) {
3358 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3359 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3360 $htmllink .= '<span class="fa pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3361 if ($type == 'skype') {
3362 $htmllink .= dol_escape_htmltag($value);
3363 $htmllink .= '&nbsp; <a href="skype:';
3364 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3365 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3366 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3367 $htmllink .= '</a><a href="skype:';
3368 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3369 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3370 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3371 $htmllink .= '</a>';
3372 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3373 $addlink = 'AC_SKYPE';
3374 $link = '';
3375 if (!empty($conf->global->AGENDA_ADDACTIONFORSKYPE)) {
3376 $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>';
3377 }
3378 $htmllink .= ($link ? ' '.$link : '');
3379 }
3380 } else {
3381 if (!empty($dictsocialnetworks[$type]['url'])) {
3382 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3383 if ($tmpvirginurl) {
3384 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3385 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3386
3387 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3388 if ($tmpvirginurl3) {
3389 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3390 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3391 }
3392
3393 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3394 if ($tmpvirginurl2) {
3395 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3396 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3397 }
3398 }
3399 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3400 if (preg_match('/^https?:\/\//i', $link)) {
3401 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3402 } else {
3403 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3404 }
3405 } else {
3406 $htmllink .= dol_escape_htmltag($value);
3407 }
3408 }
3409 $htmllink .= '</div>';
3410 } else {
3411 $langs->load("errors");
3412 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3413 }
3414 return $htmllink;
3415}
3416
3427function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1, $separ = '&nbsp;')
3428{
3429 global $mysoc;
3430
3431 if (empty($profID) || empty($profIDtype)) {
3432 return '';
3433 }
3434 if (empty($countrycode)) $countrycode = $mysoc->country_code;
3435 $newProfID = $profID;
3436 $id = substr($profIDtype, -1);
3437 $ret = '';
3438 if (strtoupper($countrycode) == 'FR') {
3439 // France
3440 if ($id == 1 && dol_strlen($newProfID) == 9) $newProfID = substr($newProfID, 0, 3).$separ.substr($newProfID, 3, 3).$separ.substr($newProfID, 6, 3);
3441 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);
3442 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);
3443 }
3444 if (!empty($addcpButton)) $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3445 else $ret = $newProfID;
3446 return $ret;
3447}
3448
3463function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0)
3464{
3465 global $conf, $user, $langs, $mysoc, $hookmanager;
3466
3467 // Clean phone parameter
3468 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
3469 if (empty($phone)) {
3470 return '';
3471 }
3472 if (!empty($conf->global->MAIN_PHONE_SEPAR)) {
3473 $separ = $conf->global->MAIN_PHONE_SEPAR;
3474 }
3475 if (empty($countrycode) && is_object($mysoc)) {
3476 $countrycode = $mysoc->country_code;
3477 }
3478
3479 // Short format for small screens
3480 if ($conf->dol_optimize_smallscreen) {
3481 $separ = '';
3482 }
3483
3484 $newphone = $phone;
3485 if (strtoupper($countrycode) == "FR") {
3486 // France
3487 if (dol_strlen($phone) == 10) {
3488 $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);
3489 } elseif (dol_strlen($phone) == 7) {
3490 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
3491 } elseif (dol_strlen($phone) == 9) {
3492 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
3493 } elseif (dol_strlen($phone) == 11) {
3494 $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);
3495 } elseif (dol_strlen($phone) == 12) {
3496 $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);
3497 } elseif (dol_strlen($phone) == 13) {
3498 $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);
3499 }
3500 } elseif (strtoupper($countrycode) == "CA") {
3501 if (dol_strlen($phone) == 10) {
3502 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
3503 }
3504 } elseif (strtoupper($countrycode) == "PT") {//Portugal
3505 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
3506 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3507 }
3508 } elseif (strtoupper($countrycode) == "SR") {//Suriname
3509 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
3510 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
3511 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
3512 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
3513 }
3514 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
3515 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
3516 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
3517 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
3518 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
3519 }
3520 } elseif (strtoupper($countrycode) == "ES") {//Espagne
3521 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
3522 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3523 }
3524 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
3525 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
3526 $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);
3527 }
3528 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
3529 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
3530 $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);
3531 }
3532 } elseif (strtoupper($countrycode) == "TR") {//Turquie
3533 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
3534 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3535 }
3536 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
3537 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
3538 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3539 }
3540 } elseif (strtoupper($countrycode) == "MX") {//Mexique
3541 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
3542 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3543 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
3544 $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);
3545 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
3546 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3547 }
3548 } elseif (strtoupper($countrycode) == "ML") {//Mali
3549 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
3550 $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);
3551 }
3552 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
3553 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
3554 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3555 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
3556 $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);
3557 }
3558 } elseif (strtoupper($countrycode) == "MU") {
3559 //Maurice
3560 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
3561 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3562 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
3563 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3564 }
3565 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
3566 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
3567 $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);
3568 }
3569 } elseif (strtoupper($countrycode) == "SY") {//Syrie
3570 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
3571 $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);
3572 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
3573 $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);
3574 }
3575 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
3576 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
3577 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3578 } elseif (dol_strlen($phone) == 13) {//ex: +971_ABC_DEF_GHI
3579 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3580 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
3581 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
3582 }
3583 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
3584 if (dol_strlen($phone) == 13) {//ex: +213_ABC_DEF_GHI
3585 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3586 }
3587 } elseif (strtoupper($countrycode) == "BE") {//Belgique
3588 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
3589 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3590 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
3591 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3592 }
3593 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
3594 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
3595 $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);
3596 }
3597 } elseif (strtoupper($countrycode) == "CO") {//Colombie
3598 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
3599 $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);
3600 }
3601 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
3602 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
3603 $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);
3604 }
3605 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
3606 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
3607 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3608 }
3609 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
3610 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
3611 $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);
3612 }
3613 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
3614 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
3615 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3616 }
3617 } elseif (strtoupper($countrycode) == "CH") {//Suisse
3618 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
3619 $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);
3620 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
3621 $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);
3622 }
3623 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
3624 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
3625 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3626 }
3627 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
3628 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
3629 $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);
3630 }
3631 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
3632 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
3633 $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);
3634 }
3635 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
3636 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
3637 $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);
3638 }
3639 } elseif (strtoupper($countrycode) == "IT") {//Italie
3640 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
3641 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3642 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
3643 $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);
3644 }
3645 } elseif (strtoupper($countrycode) == "AU") {
3646 //Australie
3647 if (dol_strlen($phone) == 12) {
3648 //ex: +61_A_BCDE_FGHI
3649 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
3650 }
3651 } elseif (strtoupper($countrycode) == "LU") {
3652 // Luxembourg
3653 if (dol_strlen($phone) == 10) {// fixe 6 chiffres +352_AA_BB_CC
3654 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3655 } elseif (dol_strlen($phone) == 11) {// fixe 7 chiffres +352_AA_BB_CC_D
3656 $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);
3657 } elseif (dol_strlen($phone) == 12) {// fixe 8 chiffres +352_AA_BB_CC_DD
3658 $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);
3659 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
3660 $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);
3661 }
3662 }
3663 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
3664 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
3665 $newphoneform = $newphone;
3666 $newphone = '<a href="tel:'.$phone.'"';
3667 $newphone .= '>'.$newphoneform.'</a>';
3668 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
3669 if (empty($user->clicktodial_loaded)) {
3670 $user->fetch_clicktodial();
3671 }
3672
3673 // Define urlmask
3674 $urlmask = 'ErrorClickToDialModuleNotConfigured';
3675 if (!empty($conf->global->CLICKTODIAL_URL)) {
3676 $urlmask = $conf->global->CLICKTODIAL_URL;
3677 }
3678 if (!empty($user->clicktodial_url)) {
3679 $urlmask = $user->clicktodial_url;
3680 }
3681
3682 $clicktodial_poste = (!empty($user->clicktodial_poste) ?urlencode($user->clicktodial_poste) : '');
3683 $clicktodial_login = (!empty($user->clicktodial_login) ?urlencode($user->clicktodial_login) : '');
3684 $clicktodial_password = (!empty($user->clicktodial_password) ?urlencode($user->clicktodial_password) : '');
3685 // This line is for backward compatibility
3686 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
3687 // Thoose lines are for substitution
3688 $substitarray = array('__PHONEFROM__'=>$clicktodial_poste,
3689 '__PHONETO__'=>urlencode($phone),
3690 '__LOGIN__'=>$clicktodial_login,
3691 '__PASS__'=>$clicktodial_password);
3692 $url = make_substitutions($url, $substitarray);
3693 $newphonesav = $newphone;
3694 if (empty($conf->global->CLICKTODIAL_DO_NOT_USE_AJAX_CALL)) {
3695 // Default and recommended: New method using ajax without submiting a page making a javascript history.go(-1) back
3696 $newphone = '<a href="'.$url.'" class="cssforclicktodial"'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
3697 $newphone .= '>'.$newphonesav.'</a>';
3698 } else {
3699 // Old method
3700 $newphone = '<a href="'.$url.'"';
3701 if (!empty($conf->global->CLICKTODIAL_FORCENEWTARGET)) {
3702 $newphone .= ' target="_blank" rel="noopener noreferrer"';
3703 }
3704 $newphone .= '>'.$newphonesav.'</a>';
3705 }
3706 }
3707
3708 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
3709 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3710 $type = 'AC_TEL';
3711 $link = '';
3712 if ($addlink == 'AC_FAX') {
3713 $type = 'AC_FAX';
3714 }
3715 if (!empty($conf->global->AGENDA_ADDACTIONFORPHONE)) {
3716 $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>';
3717 }
3718 if ($link) {
3719 $newphone = '<div>'.$newphone.' '.$link.'</div>';
3720 }
3721 }
3722 }
3723
3724 if (empty($titlealt)) {
3725 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
3726 }
3727 $rep = '';
3728
3729 if ($hookmanager) {
3730 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
3731 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
3732 $rep .= $hookmanager->resPrint;
3733 }
3734 if (empty($reshook)) {
3735 $picto = '';
3736 if ($withpicto) {
3737 if ($withpicto == 'fax') {
3738 $picto = 'phoning_fax';
3739 } elseif ($withpicto == 'phone') {
3740 $picto = 'phoning';
3741 } elseif ($withpicto == 'mobile') {
3742 $picto = 'phoning_mobile';
3743 } else {
3744 $picto = '';
3745 }
3746 }
3747 if ($adddivfloat == 1) {
3748 $rep .= '<div class="nospan float" style="margin-right: 10px">';
3749 } elseif (empty($adddivfloat)) {
3750 $rep .= '<span style="margin-right: 10px;">';
3751 }
3752 $rep .= ($withpicto ?img_picto($titlealt, 'object_'.$picto.'.png').' ' : '').$newphone;
3753 if ($adddivfloat == 1) {
3754 $rep .= '</div>';
3755 } elseif (empty($adddivfloat)) {
3756 $rep .= '</span>';
3757 }
3758 }
3759
3760 return $rep;
3761}
3762
3770function dol_print_ip($ip, $mode = 0)
3771{
3772 global $conf, $langs;
3773
3774 $ret = '';
3775
3776 if (empty($mode)) {
3777 $ret .= $ip;
3778 }
3779
3780 if ($mode != 2) {
3781 $countrycode = dolGetCountryCodeFromIp($ip);
3782 if ($countrycode) { // If success, countrycode is us, fr, ...
3783 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
3784 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
3785 } else {
3786 $ret .= ' ('.$countrycode.')';
3787 }
3788 } else {
3789 // Nothing
3790 }
3791 }
3792
3793 return $ret;
3794}
3795
3805{
3806 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
3807 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
3808 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
3809 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
3810 } else {
3811 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
3812 }
3813 } else {
3814 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
3815 }
3816 } else {
3817 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
3818 }
3819 return $ip;
3820}
3821
3830function isHTTPS()
3831{
3832 $isSecure = false;
3833 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
3834 $isSecure = true;
3835 } 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') {
3836 $isSecure = true;
3837 }
3838 return $isSecure;
3839}
3840
3848{
3849 global $conf;
3850
3851 $countrycode = '';
3852
3853 if (!empty($conf->geoipmaxmind->enabled)) {
3854 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3855 //$ip='24.24.24.24';
3856 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
3857 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3858 $geoip = new DolGeoIP('country', $datafile);
3859 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
3860 $countrycode = $geoip->getCountryCodeFromIP($ip);
3861 }
3862
3863 return $countrycode;
3864}
3865
3866
3874{
3875 global $conf, $langs, $user;
3876
3877 //$ret=$user->xxx;
3878 $ret = '';
3879 if (!empty($conf->geoipmaxmind->enabled)) {
3880 $ip = getUserRemoteIP();
3881 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3882 //$ip='24.24.24.24';
3883 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
3884 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3885 $geoip = new DolGeoIP('country', $datafile);
3886 $countrycode = $geoip->getCountryCodeFromIP($ip);
3887 $ret = $countrycode;
3888 }
3889 return $ret;
3890}
3891
3904function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
3905{
3906 global $conf, $user, $langs, $hookmanager;
3907
3908 $out = '';
3909
3910 if ($address) {
3911 if ($hookmanager) {
3912 $parameters = array('element' => $element, 'id' => $id);
3913 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
3914 $out .= $hookmanager->resPrint;
3915 }
3916 if (empty($reshook)) {
3917 if (empty($charfornl)) {
3918 $out .= nl2br($address);
3919 } else {
3920 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
3921 }
3922
3923 // TODO Remove this block, we can add this using the hook now
3924 $showgmap = $showomap = 0;
3925 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS)) {
3926 $showgmap = 1;
3927 }
3928 if ($element == 'contact' && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS_CONTACTS)) {
3929 $showgmap = 1;
3930 }
3931 if ($element == 'member' && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS_MEMBERS)) {
3932 $showgmap = 1;
3933 }
3934 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS)) {
3935 $showomap = 1;
3936 }
3937 if ($element == 'contact' && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS_CONTACTS)) {
3938 $showomap = 1;
3939 }
3940 if ($element == 'member' && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS_MEMBERS)) {
3941 $showomap = 1;
3942 }
3943 if ($showgmap) {
3944 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
3945 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
3946 }
3947 if ($showomap) {
3948 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
3949 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
3950 }
3951 }
3952 }
3953 if ($noprint) {
3954 return $out;
3955 } else {
3956 print $out;
3957 }
3958}
3959
3960
3970function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
3971{
3972 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
3973 return true;
3974 }
3975 if ($acceptuserkey && $address == '__USER_EMAIL__') {
3976 return true;
3977 }
3978 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
3979 return true;
3980 }
3981
3982 return false;
3983}
3984
3993function isValidMXRecord($domain)
3994{
3995 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
3996 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
3997 return 0;
3998 }
3999 if (function_exists('getmxrr')) {
4000 $mxhosts = array();
4001 $weight = array();
4002 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
4003 if (count($mxhosts) > 1) {
4004 return 1;
4005 }
4006 if (count($mxhosts) == 1 && !empty($mxhosts[0])) {
4007 return 1;
4008 }
4009
4010 return 0;
4011 }
4012 }
4013
4014 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4015 return -1;
4016}
4017
4025function isValidPhone($phone)
4026{
4027 return true;
4028}
4029
4030
4040function dolGetFirstLetters($s, $nbofchar = 1)
4041{
4042 $ret = '';
4043 $tmparray = explode(' ', $s);
4044 foreach ($tmparray as $tmps) {
4045 $ret .= dol_substr($tmps, 0, $nbofchar);
4046 }
4047
4048 return $ret;
4049}
4050
4051
4059function dol_strlen($string, $stringencoding = 'UTF-8')
4060{
4061 if (is_null($string)) {
4062 return 0;
4063 }
4064
4065 if (function_exists('mb_strlen')) {
4066 return mb_strlen($string, $stringencoding);
4067 } else {
4068 return strlen($string);
4069 }
4070}
4071
4082function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4083{
4084 global $langs;
4085
4086 if (empty($stringencoding)) {
4087 $stringencoding = $langs->charset_output;
4088 }
4089
4090 $ret = '';
4091 if (empty($trunconbytes)) {
4092 if (function_exists('mb_substr')) {
4093 $ret = mb_substr($string, $start, $length, $stringencoding);
4094 } else {
4095 $ret = substr($string, $start, $length);
4096 }
4097 } else {
4098 if (function_exists('mb_strcut')) {
4099 $ret = mb_strcut($string, $start, $length, $stringencoding);
4100 } else {
4101 $ret = substr($string, $start, $length);
4102 }
4103 }
4104 return $ret;
4105}
4106
4107
4121function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4122{
4123 global $conf;
4124
4125 if (empty($size) || !empty($conf->global->MAIN_DISABLE_TRUNC)) {
4126 return $string;
4127 }
4128
4129 if (empty($stringencoding)) {
4130 $stringencoding = 'UTF-8';
4131 }
4132 // reduce for small screen
4133 if ($conf->dol_optimize_smallscreen == 1 && $display == 1) {
4134 $size = round($size / 3);
4135 }
4136
4137 // We go always here
4138 if ($trunc == 'right') {
4139 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4140 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4141 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4142 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4143 } else {
4144 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4145 return $string;
4146 }
4147 } elseif ($trunc == 'middle') {
4148 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4149 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4150 $size1 = round($size / 2);
4151 $size2 = round($size / 2);
4152 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4153 } else {
4154 return $string;
4155 }
4156 } elseif ($trunc == 'left') {
4157 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4158 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4159 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4160 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4161 } else {
4162 return $string;
4163 }
4164 } elseif ($trunc == 'wrap') {
4165 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4166 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4167 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4168 } else {
4169 return $string;
4170 }
4171 } else {
4172 return 'BadParam3CallingDolTrunc';
4173 }
4174}
4175
4197function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4198{
4199 global $conf, $langs;
4200
4201 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4202 $url = DOL_URL_ROOT;
4203 $theme = isset($conf->theme) ? $conf->theme : null;
4204 $path = 'theme/'.$theme;
4205 // Define fullpathpicto to use into src
4206 if ($pictoisfullpath) {
4207 // Clean parameters
4208 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4209 $picto .= '.png';
4210 }
4211 $fullpathpicto = $picto;
4212 $reg = array();
4213 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4214 $morecss .= ($morecss ? ' ' : '').$reg[1];
4215 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4216 }
4217 } else {
4218 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', $picto);
4219 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4220 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4221
4222 if (strpos($pictowithouttext, 'fontawesome_') !== false || preg_match('/^fa-/', $pictowithouttext)) {
4223 // This is a font awesome image 'fonwtawesome_xxx' or 'fa-xxx'
4224 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4225 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4226
4227 $pictowithouttextarray = explode('_', $pictowithouttext);
4228 $marginleftonlyshort = 0;
4229
4230 if (!empty($pictowithouttextarray[1])) {
4231 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4232 $fakey = 'fa-'.$pictowithouttextarray[0];
4233 $fa = empty($pictowithouttextarray[1]) ? 'fa' : $pictowithouttextarray[1];
4234 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4235 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4236 } else {
4237 $fakey = 'fa-'.$pictowithouttext;
4238 $fa = 'fa';
4239 $facolor = '';
4240 $fasize = '';
4241 }
4242
4243 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4244 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4245 $morestyle = '';
4246 $reg = array();
4247 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4248 $morecss .= ($morecss ? ' ' : '').$reg[1];
4249 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4250 }
4251 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4252 $morestyle = $reg[1];
4253 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4254 }
4255 $moreatt = trim($moreatt);
4256
4257 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4258 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4259 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4260 $enabledisablehtml .= $titlealt;
4261 }*/
4262 $enabledisablehtml .= '</span>';
4263
4264 return $enabledisablehtml;
4265 }
4266
4267 if (empty($srconly) && in_array($pictowithouttext, array(
4268 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4269 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'angle-double-down', 'angle-double-up', 'asset',
4270 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building',
4271 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4272 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4273 'currency', 'multicurrency',
4274 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4275 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4276 'filter', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus',
4277 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4278 'hands-helping', 'help', 'holiday',
4279 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4280 'knowledgemanagement',
4281 'label', 'language', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4282 'margin', 'map-marker-alt', 'member', 'meeting', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4283 'off', 'on', 'order',
4284 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4285 'stock', 'resize', 'service', 'stats', 'trip',
4286 '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',
4287 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4288 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies',
4289 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4290 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4291 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4292 'technic', 'ticket',
4293 'error', 'warning',
4294 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4295 'shapes', 'skill', 'square', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4296 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda',
4297 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4298 'conferenceorbooth', 'eventorganization',
4299 'stamp', 'signature'
4300 ))) {
4301 $fakey = $pictowithouttext;
4302 $facolor = '';
4303 $fasize = '';
4304 $fa = 'fas';
4305 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'))) {
4306 $fa = 'far';
4307 }
4308 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4309 $fa = 'fab';
4310 }
4311
4312 $arrayconvpictotofa = array(
4313 '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',
4314 'bank_account'=>'university',
4315 'bill'=>'file-invoice-dollar', 'billa'=>'file-excel', 'billr'=>'file-invoice-dollar', 'billd'=>'file-medical',
4316 'supplier_invoice'=>'file-invoice-dollar', 'supplier_invoicea'=>'file-excel', 'supplier_invoicer'=>'file-invoice-dollar', 'supplier_invoiced'=>'file-medical',
4317 'bom'=>'shapes',
4318 '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',
4319 'donation'=>'file-alt', 'dynamicprice'=>'hand-holding-usd',
4320 'setup'=>'cog', 'companies'=>'building', 'products'=>'cube', 'commercial'=>'suitcase', 'invoicing'=>'coins',
4321 'accounting'=>'search-dollar', 'category'=>'tag', 'dollyrevert'=>'dolly',
4322 'generate'=>'plus-square', 'hrm'=>'user-tie', 'incoterm'=>'truck-loading',
4323 'margin'=>'calculator', 'members'=>'user-friends', 'ticket'=>'ticket-alt', 'globe'=>'external-link-alt', 'lot'=>'barcode',
4324 'email'=>'at', 'establishment'=>'building', 'edit'=>'pencil-alt', 'entity'=>'globe',
4325 'graph'=>'chart-line', 'grip_title'=>'arrows-alt', 'grip'=>'arrows-alt', 'help'=>'question-circle',
4326 'generic'=>'file', 'holiday'=>'umbrella-beach',
4327 'info'=>'info-circle', 'inventory'=>'boxes', 'intracommreport'=>'globe-europe', 'jobprofile'=>'cogs',
4328 'knowledgemanagement'=>'ticket-alt', 'label'=>'layer-group', 'line'=>'bars', 'loan'=>'money-bill-alt',
4329 'member'=>'user-alt', 'meeting'=>'chalkboard-teacher', 'mrp'=>'cubes', 'next'=>'arrow-alt-circle-right',
4330 'trip'=>'wallet', 'expensereport'=>'wallet', 'group'=>'users', 'movement'=>'people-carry',
4331 'sign-out'=>'sign-out-alt',
4332 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_warning'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star',
4333 'bank'=>'university', 'close_title'=>'times', 'delete'=>'trash', 'filter'=>'filter',
4334 'list-alt'=>'list-alt', 'calendarlist'=>'bars', 'calendar'=>'calendar-alt', 'calendarmonth'=>'calendar-alt', 'calendarweek'=>'calendar-week', 'calendarday'=>'calendar-day', 'calendarperuser'=>'table',
4335 'intervention'=>'ambulance', 'invoice'=>'file-invoice-dollar', 'currency'=>'dollar-sign', 'multicurrency'=>'dollar-sign', 'order'=>'file-invoice',
4336 'error'=>'exclamation-triangle', 'warning'=>'exclamation-triangle',
4337 'other'=>'square',
4338 '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',
4339 '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',
4340 'recent' => 'check-square', 'reception'=>'dolly', 'recruitmentjobposition'=>'id-card-alt', 'recruitmentcandidature'=>'id-badge',
4341 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature',
4342 'refresh'=>'redo', 'region'=>'map-marked', 'replacement'=>'exchange-alt', 'resource'=>'laptop-house', 'recurring'=>'history',
4343 'service'=>'concierge-bell',
4344 'skill'=>'shapes', 'state'=>'map-marked-alt', 'security'=>'key', 'salary'=>'wallet', 'shipment'=>'dolly', 'stock'=>'box-open', 'stats' => 'chart-bar', 'split'=>'code-branch', 'stripe'=>'stripe-s',
4345 'supplier'=>'building', 'technic'=>'cogs',
4346 'timespent'=>'clock', 'title_setup'=>'tools', 'title_accountancy'=>'money-check-alt', 'title_bank'=>'university', 'title_hrm'=>'umbrella-beach',
4347 'title_agenda'=>'calendar-alt',
4348 'uncheck'=>'times', 'uparrow'=>'share', 'url'=>'external-link-alt', 'vat'=>'money-check-alt', 'vcard'=>'arrow-alt-circle-down',
4349 'jabber'=>'comment-o',
4350 'website'=>'globe-americas', 'workstation'=>'pallet', 'webhook'=>'bullseye', 'world'=>'globe', 'private'=>'user-lock',
4351 'conferenceorbooth'=>'chalkboard-teacher', 'eventorganization'=>'project-diagram'
4352 );
4353 if ($pictowithouttext == 'off') {
4354 $fakey = 'fa-square';
4355 $fasize = '1.3em';
4356 } elseif ($pictowithouttext == 'on') {
4357 $fakey = 'fa-check-square';
4358 $fasize = '1.3em';
4359 } elseif ($pictowithouttext == 'listlight') {
4360 $fakey = 'fa-download';
4361 $marginleftonlyshort = 1;
4362 } elseif ($pictowithouttext == 'printer') {
4363 $fakey = 'fa-print';
4364 $fasize = '1.2em';
4365 } elseif ($pictowithouttext == 'note') {
4366 $fakey = 'fa-sticky-note';
4367 $marginleftonlyshort = 1;
4368 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
4369 $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');
4370 $fakey = 'fa-'.$convertarray[$pictowithouttext];
4371 if (preg_match('/selected/', $pictowithouttext)) {
4372 $facolor = '#888';
4373 }
4374 $marginleftonlyshort = 1;
4375 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
4376 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
4377 } else {
4378 $fakey = 'fa-'.$pictowithouttext;
4379 }
4380
4381 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment'))) {
4382 $morecss .= ' em092';
4383 }
4384 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
4385 $morecss .= ' em088';
4386 }
4387 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
4388 $morecss .= ' em080';
4389 }
4390
4391 // Define $marginleftonlyshort
4392 $arrayconvpictotomarginleftonly = array(
4393 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
4394 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
4395 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
4396 );
4397 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
4398 $marginleftonlyshort = 0;
4399 }
4400
4401 // Add CSS
4402 $arrayconvpictotomorcess = array(
4403 'action'=>'infobox-action', 'account'=>'infobox-bank_account', 'accounting_account'=>'infobox-bank_account', 'accountline'=>'infobox-bank_account', 'accountancy'=>'infobox-bank_account', 'asset'=>'infobox-bank_account',
4404 'bank_account'=>'infobox-bank_account',
4405 'bill'=>'infobox-commande', 'billa'=>'infobox-commande', 'billr'=>'infobox-commande', 'billd'=>'infobox-commande',
4406 'margin'=>'infobox-bank_account', 'conferenceorbooth'=>'infobox-project',
4407 'cash-register'=>'infobox-bank_account', 'contract'=>'infobox-contrat', 'check'=>'font-status4', 'collab'=>'infobox-action', 'conversation'=>'infobox-contrat',
4408 'donation'=>'infobox-commande', 'dolly'=>'infobox-commande', 'dollyrevert'=>'flip infobox-order_supplier',
4409 'ecm'=>'infobox-action', 'eventorganization'=>'infobox-project',
4410 'hrm'=>'infobox-adherent', 'group'=>'infobox-adherent', 'intervention'=>'infobox-contrat',
4411 'incoterm'=>'infobox-supplier_proposal',
4412 'currency'=>'infobox-bank_account', 'multicurrency'=>'infobox-bank_account',
4413 'members'=>'infobox-adherent', 'member'=>'infobox-adherent', 'money-bill-alt'=>'infobox-bank_account',
4414 'order'=>'infobox-commande',
4415 'user'=>'infobox-adherent', 'users'=>'infobox-adherent',
4416 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_warning'=>'font-status4 warning', 'switch_on_red'=>'font-status8',
4417 'holiday'=>'infobox-holiday', 'info'=>'opacityhigh', 'invoice'=>'infobox-commande',
4418 'knowledgemanagement'=>'infobox-contrat rotate90', 'loan'=>'infobox-bank_account',
4419 'payment'=>'infobox-bank_account', 'payment_vat'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'pos'=>'infobox-bank_account', 'project'=>'infobox-project', 'projecttask'=>'infobox-project',
4420 'propal'=>'infobox-propal', 'proposal'=>'infobox-propal','private'=>'infobox-project',
4421 'reception'=>'flip', 'recruitmentjobposition'=>'infobox-adherent', 'recruitmentcandidature'=>'infobox-adherent',
4422 'resource'=>'infobox-action',
4423 'salary'=>'infobox-bank_account', 'shipment'=>'infobox-commande', 'supplier_invoice'=>'infobox-order_supplier', 'supplier_invoicea'=>'infobox-order_supplier', 'supplier_invoiced'=>'infobox-order_supplier',
4424 'supplier'=>'infobox-order_supplier', 'supplier_order'=>'infobox-order_supplier', 'supplier_proposal'=>'infobox-supplier_proposal',
4425 'ticket'=>'infobox-contrat', 'title_accountancy'=>'infobox-bank_account', 'title_hrm'=>'infobox-holiday', 'expensereport'=>'infobox-expensereport', 'trip'=>'infobox-expensereport', 'title_agenda'=>'infobox-action',
4426 'vat'=>'infobox-bank_account',
4427 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
4428 'list-alt'=>'imgforviewmode', 'calendar'=>'imgforviewmode', 'calendarweek'=>'imgforviewmode', 'calendarmonth'=>'imgforviewmode', 'calendarday'=>'imgforviewmode', 'calendarperuser'=>'imgforviewmode'
4429 );
4430 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4431 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
4432 }
4433
4434 // Define $color
4435 $arrayconvpictotocolor = array(
4436 'address'=>'#6c6aa8', 'building'=>'#6c6aa8', 'bom'=>'#a69944',
4437 'clone'=>'#999', 'cog'=>'#999', 'companies'=>'#6c6aa8', 'company'=>'#6c6aa8', 'contact'=>'#6c6aa8', 'cron'=>'#555',
4438 'dynamicprice'=>'#a69944',
4439 'edit'=>'#444', 'note'=>'#999', 'error'=>'', 'help'=>'#bbb', 'listlight'=>'#999', 'language'=>'#555',
4440 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
4441 'lock'=>'#ddd', 'lot'=>'#a69944',
4442 'map-marker-alt'=>'#aaa', 'mrp'=>'#a69944', 'product'=>'#a69944', 'service'=>'#a69944', 'inventory'=>'#a69944', 'stock'=>'#a69944', 'movement'=>'#a69944',
4443 'other'=>'#ddd', 'world'=>'#986c6a',
4444 'partnership'=>'#6c6aa8', 'playdisabled'=>'#ccc', 'printer'=>'#444', 'projectpub'=>'#986c6a', 'reception'=>'#a69944', 'resize'=>'#444', 'rss'=>'#cba',
4445 //'shipment'=>'#a69944',
4446 'security'=>'#999', 'square'=>'#888', 'stop-circle'=>'#888', 'stats'=>'#444', 'switch_off'=>'#999', 'technic'=>'#999', 'timespent'=>'#555',
4447 'uncheck'=>'#800', 'uparrow'=>'#555', 'user-cog'=>'#999', 'country'=>'#aaa', 'globe-americas'=>'#aaa', 'region'=>'#aaa', 'state'=>'#aaa',
4448 'website'=>'#304', 'workstation'=>'#a69944'
4449 );
4450 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4451 $facolor = $arrayconvpictotocolor[$pictowithouttext];
4452 }
4453
4454 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4455 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4456 $morestyle = '';
4457 $reg = array();
4458 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4459 $morecss .= ($morecss ? ' ' : '').$reg[1];
4460 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4461 }
4462 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4463 $morestyle = $reg[1];
4464 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4465 }
4466 $moreatt = trim($moreatt);
4467
4468 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4469 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4470 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4471 $enabledisablehtml .= $titlealt;
4472 }*/
4473 $enabledisablehtml .= '</span>';
4474
4475 return $enabledisablehtml;
4476 }
4477
4478 if (!empty($conf->global->MAIN_OVERWRITE_THEME_PATH)) {
4479 $path = $conf->global->MAIN_OVERWRITE_THEME_PATH.'/theme/'.$theme; // If the theme does not have the same name as the module
4480 } elseif (!empty($conf->global->MAIN_OVERWRITE_THEME_RES)) {
4481 $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
4482 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
4483 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
4484 }
4485
4486 // If we ask an image into $url/$mymodule/img (instead of default path)
4487 $regs = array();
4488 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
4489 $picto = $regs[1];
4490 $path = $regs[2]; // $path is $mymodule
4491 }
4492
4493 // Clean parameters
4494 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4495 $picto .= '.png';
4496 }
4497 // If alt path are defined, define url where img file is, according to physical path
4498 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
4499 foreach ($conf->file->dol_document_root as $type => $dirroot) {
4500 if ($type == 'main') {
4501 continue;
4502 }
4503 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommanded
4504 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
4505 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
4506 break;
4507 }
4508 }
4509
4510 // $url is '' or '/custom', $path is current theme or
4511 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
4512 }
4513
4514 if ($srconly) {
4515 return $fullpathpicto;
4516 }
4517
4518 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
4519 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
4520}
4521
4535function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0)
4536{
4537 if (strpos($picto, '^') === 0) {
4538 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
4539 } else {
4540 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
4541 }
4542}
4543
4555function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
4556{
4557 global $conf;
4558
4559 if (is_numeric($picto)) {
4560 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
4561 //$picto = $leveltopicto[$picto];
4562 return '<i class="fa fa-weather-level'.$picto.'"></i>';
4563 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4564 $picto .= '.png';
4565 }
4566
4567 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
4568
4569 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
4570}
4571
4583function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
4584{
4585 global $conf;
4586
4587 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4588 $picto .= '.png';
4589 }
4590
4591 if ($pictoisfullpath) {
4592 $path = $picto;
4593 } else {
4594 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
4595
4596 if (!empty($conf->global->MAIN_MODULE_CAN_OVERWRITE_COMMONICONS)) {
4597 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
4598
4599 if (file_exists($themepath)) {
4600 $path = $themepath;
4601 }
4602 }
4603 }
4604
4605 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
4606}
4607
4621function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
4622{
4623 global $langs;
4624
4625 if (empty($titlealt) || $titlealt == 'default') {
4626 if ($numaction == '-1' || $numaction == 'ST_NO') {
4627 $numaction = -1;
4628 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
4629 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
4630 $numaction = 0;
4631 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
4632 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
4633 $numaction = 1;
4634 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
4635 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
4636 $numaction = 2;
4637 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
4638 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
4639 $numaction = 3;
4640 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
4641 } else {
4642 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
4643 $numaction = 0;
4644 }
4645 }
4646 if (!is_numeric($numaction)) {
4647 $numaction = 0;
4648 }
4649
4650 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
4651}
4652
4660function img_pdf($titlealt = 'default', $size = 3)
4661{
4662 global $langs;
4663
4664 if ($titlealt == 'default') {
4665 $titlealt = $langs->trans('Show');
4666 }
4667
4668 return img_picto($titlealt, 'pdf'.$size.'.png');
4669}
4670
4678function img_edit_add($titlealt = 'default', $other = '')
4679{
4680 global $langs;
4681
4682 if ($titlealt == 'default') {
4683 $titlealt = $langs->trans('Add');
4684 }
4685
4686 return img_picto($titlealt, 'edit_add.png', $other);
4687}
4695function img_edit_remove($titlealt = 'default', $other = '')
4696{
4697 global $langs;
4698
4699 if ($titlealt == 'default') {
4700 $titlealt = $langs->trans('Remove');
4701 }
4702
4703 return img_picto($titlealt, 'edit_remove.png', $other);
4704}
4705
4714function img_edit($titlealt = 'default', $float = 0, $other = '')
4715{
4716 global $langs;
4717
4718 if ($titlealt == 'default') {
4719 $titlealt = $langs->trans('Modify');
4720 }
4721
4722 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
4723}
4724
4733function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
4734{
4735 global $langs;
4736
4737 if ($titlealt == 'default') {
4738 $titlealt = $langs->trans('View');
4739 }
4740
4741 $moreatt = ($float ? 'style="float: right" ' : '').$other;
4742
4743 return img_picto($titlealt, 'eye', $moreatt);
4744}
4745
4754function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
4755{
4756 global $langs;
4757
4758 if ($titlealt == 'default') {
4759 $titlealt = $langs->trans('Delete');
4760 }
4761
4762 return img_picto($titlealt, 'delete.png', $other, false, 0, 0, '', $morecss);
4763}
4764
4772function img_printer($titlealt = "default", $other = '')
4773{
4774 global $langs;
4775 if ($titlealt == "default") {
4776 $titlealt = $langs->trans("Print");
4777 }
4778 return img_picto($titlealt, 'printer.png', $other);
4779}
4780
4788function img_split($titlealt = 'default', $other = 'class="pictosplit"')
4789{
4790 global $langs;
4791
4792 if ($titlealt == 'default') {
4793 $titlealt = $langs->trans('Split');
4794 }
4795
4796 return img_picto($titlealt, 'split.png', $other);
4797}
4798
4806function img_help($usehelpcursor = 1, $usealttitle = 1)
4807{
4808 global $langs;
4809
4810 if ($usealttitle) {
4811 if (is_string($usealttitle)) {
4812 $usealttitle = dol_escape_htmltag($usealttitle);
4813 } else {
4814 $usealttitle = $langs->trans('Info');
4815 }
4816 }
4817
4818 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
4819}
4820
4827function img_info($titlealt = 'default')
4828{
4829 global $langs;
4830
4831 if ($titlealt == 'default') {
4832 $titlealt = $langs->trans('Informations');
4833 }
4834
4835 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
4836}
4837
4846function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
4847{
4848 global $langs;
4849
4850 if ($titlealt == 'default') {
4851 $titlealt = $langs->trans('Warning');
4852 }
4853
4854 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
4855 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
4856}
4857
4864function img_error($titlealt = 'default')
4865{
4866 global $langs;
4867
4868 if ($titlealt == 'default') {
4869 $titlealt = $langs->trans('Error');
4870 }
4871
4872 return img_picto($titlealt, 'error.png');
4873}
4874
4882function img_next($titlealt = 'default', $moreatt = '')
4883{
4884 global $langs;
4885
4886 if ($titlealt == 'default') {
4887 $titlealt = $langs->trans('Next');
4888 }
4889
4890 //return img_picto($titlealt, 'next.png', $moreatt);
4891 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
4892}
4893
4901function img_previous($titlealt = 'default', $moreatt = '')
4902{
4903 global $langs;
4904
4905 if ($titlealt == 'default') {
4906 $titlealt = $langs->trans('Previous');
4907 }
4908
4909 //return img_picto($titlealt, 'previous.png', $moreatt);
4910 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
4911}
4912
4921function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
4922{
4923 global $langs;
4924
4925 if ($titlealt == 'default') {
4926 $titlealt = $langs->trans('Down');
4927 }
4928
4929 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
4930}
4931
4940function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
4941{
4942 global $langs;
4943
4944 if ($titlealt == 'default') {
4945 $titlealt = $langs->trans('Up');
4946 }
4947
4948 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
4949}
4950
4959function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
4960{
4961 global $langs;
4962
4963 if ($titlealt == 'default') {
4964 $titlealt = $langs->trans('Left');
4965 }
4966
4967 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
4968}
4969
4978function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
4979{
4980 global $langs;
4981
4982 if ($titlealt == 'default') {
4983 $titlealt = $langs->trans('Right');
4984 }
4985
4986 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
4987}
4988
4996function img_allow($allow, $titlealt = 'default')
4997{
4998 global $langs;
4999
5000 if ($titlealt == 'default') {
5001 $titlealt = $langs->trans('Active');
5002 }
5003
5004 if ($allow == 1) {
5005 return img_picto($titlealt, 'tick.png');
5006 }
5007
5008 return '-';
5009}
5010
5018function img_credit_card($brand, $morecss = null)
5019{
5020 if (is_null($morecss)) {
5021 $morecss = 'fa-2x';
5022 }
5023
5024 if ($brand == 'visa' || $brand == 'Visa') {
5025 $brand = 'cc-visa';
5026 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5027 $brand = 'cc-mastercard';
5028 } elseif ($brand == 'amex' || $brand == 'American Express') {
5029 $brand = 'cc-amex';
5030 } elseif ($brand == 'discover' || $brand == 'Discover') {
5031 $brand = 'cc-discover';
5032 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5033 $brand = 'cc-jcb';
5034 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5035 $brand = 'cc-diners-club';
5036 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5037 $brand = 'credit-card';
5038 }
5039
5040 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5041}
5042
5051function img_mime($file, $titlealt = '', $morecss = '')
5052{
5053 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5054
5055 $mimetype = dol_mimetype($file, '', 1);
5056 $mimeimg = dol_mimetype($file, '', 2);
5057 $mimefa = dol_mimetype($file, '', 4);
5058
5059 if (empty($titlealt)) {
5060 $titlealt = 'Mime type: '.$mimetype;
5061 }
5062
5063 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5064 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5065}
5066
5067
5075function img_search($titlealt = 'default', $other = '')
5076{
5077 global $conf, $langs;
5078
5079 if ($titlealt == 'default') {
5080 $titlealt = $langs->trans('Search');
5081 }
5082
5083 $img = img_picto($titlealt, 'search.png', $other, false, 1);
5084
5085 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5086 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5087
5088 return $input;
5089}
5090
5098function img_searchclear($titlealt = 'default', $other = '')
5099{
5100 global $conf, $langs;
5101
5102 if ($titlealt == 'default') {
5103 $titlealt = $langs->trans('Search');
5104 }
5105
5106 $img = img_picto($titlealt, 'searchclear.png', $other, false, 1);
5107
5108 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5109 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5110
5111 return $input;
5112}
5113
5125function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '')
5126{
5127 global $conf, $langs;
5128
5129 if ($infoonimgalt) {
5130 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5131 } else {
5132 if (empty($conf->use_javascript_ajax)) {
5133 $textfordropdown = '';
5134 }
5135
5136 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5137 $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>');
5138
5139 if ($textfordropdown) {
5140 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5141 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5142 jQuery(document).ready(function() {
5143 jQuery(".'.$class.'text").click(function() {
5144 console.log("toggle text");
5145 jQuery(".'.$class.'").toggle();
5146 });
5147 });
5148 </script>';
5149
5150 $result = $tmpresult.$result;
5151 }
5152 }
5153
5154 return $result;
5155}
5156
5157
5169function dol_print_error($db = '', $error = '', $errors = null)
5170{
5171 global $conf, $langs, $argv;
5172 global $dolibarr_main_prod;
5173
5174 $out = '';
5175 $syslog = '';
5176
5177 // If error occurs before the $lang object was loaded
5178 if (!$langs) {
5179 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5180 $langs = new Translate('', $conf);
5181 $langs->load("main");
5182 }
5183
5184 // Load translation files required by the error messages
5185 $langs->loadLangs(array('main', 'errors'));
5186
5187 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5188 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5189 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5190 $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";
5191 }
5192 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5193
5194 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5195 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5196 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5197 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5198 }
5199 if (function_exists("phpversion")) {
5200 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5201 }
5202 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5203 if (function_exists("php_uname")) {
5204 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5205 }
5206 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5207 $out .= "<br>\n";
5208 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5209 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5210 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5211 $out .= "<br>\n";
5212 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5213 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5214 } else { // Mode CLI
5215 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5216 $syslog .= "pid=".dol_getmypid();
5217 }
5218
5219 if (!empty($conf->modules)) {
5220 $out .= "<b>".$langs->trans("Modules").":</b> ".join(', ', $conf->modules)."<br>\n";
5221 }
5222
5223 if (is_object($db)) {
5224 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5225 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5226 $lastqueryerror = $db->lastqueryerror();
5227 if (!utf8_check($lastqueryerror)) {
5228 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5229 }
5230 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5231 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5232 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5233 $out .= "<br>\n";
5234 } else { // Mode CLI
5235 // No dol_escape_htmltag for output, we are in CLI mode
5236 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5237 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5238 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5239 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5240 }
5241 $syslog .= ", sql=".$db->lastquery();
5242 $syslog .= ", db_error=".$db->lasterror();
5243 }
5244
5245 if ($error || $errors) {
5246 $langs->load("errors");
5247
5248 // Merge all into $errors array
5249 if (is_array($error) && is_array($errors)) {
5250 $errors = array_merge($error, $errors);
5251 } elseif (is_array($error)) {
5252 $errors = $error;
5253 } elseif (is_array($errors)) {
5254 $errors = array_merge(array($error), $errors);
5255 } else {
5256 $errors = array_merge(array($error), array($errors));
5257 }
5258
5259 foreach ($errors as $msg) {
5260 if (empty($msg)) {
5261 continue;
5262 }
5263 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5264 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5265 } else // Mode CLI
5266 {
5267 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5268 }
5269 $syslog .= ", msg=".$msg;
5270 }
5271 }
5272 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5273 xdebug_print_function_stack();
5274 $out .= '<b>XDebug informations:</b>'."<br>\n";
5275 $out .= 'File: '.xdebug_call_file()."<br>\n";
5276 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5277 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5278 $out .= "<br>\n";
5279 }
5280
5281 // Return a http header with error code if possible
5282 if (!headers_sent()) {
5283 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5284 top_httphead();
5285 }
5286 //http_response_code(500); // If we use 500, message is not ouput with some command line tools
5287 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
5288 }
5289
5290 if (empty($dolibarr_main_prod)) {
5291 print $out;
5292 } else {
5293 if (empty($langs->defaultlang)) {
5294 $langs->setDefaultLang();
5295 }
5296 $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.
5297 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5298 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";
5299 print $langs->trans("DolibarrHasDetectedError").'. ';
5300 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5301 if (!defined("MAIN_CORE_ERROR")) {
5302 define("MAIN_CORE_ERROR", 1);
5303 }
5304 }
5305
5306 dol_syslog("Error ".$syslog, LOG_ERR);
5307}
5308
5319function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5320{
5321 global $langs, $conf;
5322
5323 if (empty($email)) {
5324 $email = $conf->global->MAIN_INFO_SOCIETE_MAIL;
5325 }
5326
5327 $langs->load("errors");
5328 $now = dol_now();
5329
5330 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5331 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5332 if ($errormessage) {
5333 print '<br><br>'.$errormessage;
5334 }
5335 if (is_array($errormessages) && count($errormessages)) {
5336 foreach ($errormessages as $mesgtoshow) {
5337 print '<br><br>'.$mesgtoshow;
5338 }
5339 }
5340 print '</div></div>';
5341}
5342
5359function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
5360{
5361 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
5362}
5363
5382function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
5383{
5384 global $conf, $langs, $form;
5385 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
5386
5387 if ($moreattrib == 'class="right"') {
5388 $prefix .= 'right '; // For backward compatibility
5389 }
5390
5391 $sortorder = strtoupper($sortorder);
5392 $out = '';
5393 $sortimg = '';
5394
5395 $tag = 'th';
5396 if ($thead == 2) {
5397 $tag = 'div';
5398 }
5399
5400 $tmpsortfield = explode(',', $sortfield);
5401 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
5402 $tmpfield = explode(',', $field);
5403 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
5404
5405 if (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && empty($forcenowrapcolumntitle)) {
5406 $prefix = 'wrapcolumntitle '.$prefix;
5407 }
5408
5409 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
5410 // If field is used as sort criteria we use a specific css class liste_titre_sel
5411 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
5412 $liste_titre = 'liste_titre';
5413 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
5414 $liste_titre = 'liste_titre_sel';
5415 }
5416
5417 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
5418 //$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)).'"' : '');
5419 $tagstart .= ($name && empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
5420 $tagstart .= '>';
5421
5422 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5423 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5424 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5425 $options = preg_replace('/&+/i', '&', $options);
5426 if (!preg_match('/^&/', $options)) {
5427 $options = '&'.$options;
5428 }
5429
5430 $sortordertouseinlink = '';
5431 if ($field1 != $sortfield1) { // We are on another field than current sorted field
5432 if (preg_match('/^DESC/i', $sortorder)) {
5433 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5434 } else { // We reverse the var $sortordertouseinlink
5435 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5436 }
5437 } else { // We are on field that is the first current sorting criteria
5438 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
5439 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5440 } else {
5441 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5442 }
5443 }
5444 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
5445 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
5446 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5447 $out .= '>';
5448 }
5449 if ($tooltip) {
5450 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
5451 if (preg_match('/:\w+$/', $tooltip)) {
5452 $tmptooltip = explode(':', $tooltip);
5453 } else {
5454 $tmptooltip = array($tooltip);
5455 }
5456 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
5457 } else {
5458 $out .= $langs->trans($name);
5459 }
5460
5461 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5462 $out .= '</a>';
5463 }
5464
5465 if (empty($thead) && $field) { // If this is a sort field
5466 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5467 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5468 $options = preg_replace('/&+/i', '&', $options);
5469 if (!preg_match('/^&/', $options)) {
5470 $options = '&'.$options;
5471 }
5472
5473 if (!$sortorder || ($field1 != $sortfield1)) {
5474 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5475 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5476 } else {
5477 if (preg_match('/^DESC/', $sortorder)) {
5478 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5479 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
5480 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
5481 }
5482 if (preg_match('/^ASC/', $sortorder)) {
5483 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
5484 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5485 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
5486 }
5487 }
5488 }
5489
5490 $tagend = '</'.$tag.'>';
5491
5492 $out = $tagstart.$sortimg.$out.$tagend;
5493
5494 return $out;
5495}
5496
5505function print_titre($title)
5506{
5507 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
5508
5509 print '<div class="titre">'.$title.'</div>';
5510}
5511
5523function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
5524{
5525 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
5526}
5527
5541function load_fiche_titre($titre, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
5542{
5543 global $conf;
5544
5545 $return = '';
5546
5547 if ($picto == 'setup') {
5548 $picto = 'generic';
5549 }
5550
5551 $return .= "\n";
5552 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
5553 $return .= '<tr class="titre">';
5554 if ($picto) {
5555 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
5556 }
5557 $return .= '<td class="nobordernopadding valignmiddle col-title">';
5558 $return .= '<div class="titre inline-block">'.$titre.'</div>';
5559 $return .= '</td>';
5560 if (dol_strlen($morehtmlcenter)) {
5561 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5562 }
5563 if (dol_strlen($morehtmlright)) {
5564 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
5565 }
5566 $return .= '</tr></table>'."\n";
5567
5568 return $return;
5569}
5570
5594function 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 = '')
5595{
5596 global $conf, $langs;
5597
5598 $savlimit = $limit;
5599 $savtotalnboflines = $totalnboflines;
5600 $totalnboflines = abs((int) $totalnboflines);
5601
5602 $page = (int) $page;
5603
5604 if ($picto == 'setup') {
5605 $picto = 'title_setup.png';
5606 }
5607 if (($conf->browser->name == 'ie') && $picto == 'generic') {
5608 $picto = 'title.gif';
5609 }
5610 if ($limit < 0) {
5611 $limit = $conf->liste_limit;
5612 }
5613
5614 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
5615 $nextpage = 1;
5616 } else {
5617 $nextpage = 0;
5618 }
5619 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
5620
5621 print "\n";
5622 print "<!-- Begin title -->\n";
5623 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
5624
5625 // Left
5626
5627 if ($picto && $titre) {
5628 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
5629 }
5630
5631 print '<td class="nobordernopadding valignmiddle col-title">';
5632 print '<div class="titre inline-block">'.$titre;
5633 if (!empty($titre) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
5634 print '<span class="opacitymedium colorblack paddingleft">('.$totalnboflines.')</span>';
5635 }
5636 print '</div></td>';
5637
5638 // Center
5639 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
5640 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5641 }
5642
5643 // Right
5644 print '<td class="nobordernopadding valignmiddle right col-right">';
5645 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
5646 if ($sortfield) {
5647 $options .= "&sortfield=".urlencode($sortfield);
5648 }
5649 if ($sortorder) {
5650 $options .= "&sortorder=".urlencode($sortorder);
5651 }
5652 // Show navigation bar
5653 $pagelist = '';
5654 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
5655 if ($totalnboflines) { // If we know total nb of lines
5656 // Define nb of extra page links before and after selected page + ... + first or last
5657 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
5658
5659 if ($limit > 0) {
5660 $nbpages = ceil($totalnboflines / $limit);
5661 } else {
5662 $nbpages = 1;
5663 }
5664 $cpt = ($page - $maxnbofpage);
5665 if ($cpt < 0) {
5666 $cpt = 0;
5667 }
5668
5669 if ($cpt >= 1) {
5670 if (empty($pagenavastextinput)) {
5671 $pagelist .= '<li class="pagination"><a href="'.$file.'?page=0'.$options.'">1</a></li>';
5672 if ($cpt > 2) {
5673 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5674 } elseif ($cpt == 2) {
5675 $pagelist .= '<li class="pagination"><a href="'.$file.'?page=1'.$options.'">2</a></li>';
5676 }
5677 }
5678 }
5679
5680 do {
5681 if ($pagenavastextinput) {
5682 if ($cpt == $page) {
5683 $pagelist .= '<li class="pagination"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
5684 $pagelist .= '/';
5685 }
5686 } else {
5687 if ($cpt == $page) {
5688 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
5689 } else {
5690 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
5691 }
5692 }
5693 $cpt++;
5694 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
5695
5696 if (empty($pagenavastextinput)) {
5697 if ($cpt < $nbpages) {
5698 if ($cpt < $nbpages - 2) {
5699 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5700 } elseif ($cpt == $nbpages - 2) {
5701 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
5702 }
5703 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5704 }
5705 } else {
5706 //var_dump($page.' '.$cpt.' '.$nbpages);
5707 $pagelist .= '<li class="pagination paginationlastpage"><a href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5708 }
5709 } else {
5710 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
5711 }
5712 }
5713
5714 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
5715 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
5716 }
5717
5718 // js to autoselect page field on focus
5719 if ($pagenavastextinput) {
5720 print ajax_autoselect('.pageplusone');
5721 }
5722
5723 print '</td>';
5724 print '</tr>';
5725
5726 print '</table>'."\n";
5727
5728 // Center
5729 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
5730 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
5731 }
5732
5733 print "<!-- End title -->\n\n";
5734}
5735
5752function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
5753{
5754 global $conf, $langs;
5755
5756 print '<div class="pagination"><ul>';
5757 if ($beforearrows) {
5758 print '<li class="paginationbeforearrows">';
5759 print $beforearrows;
5760 print '</li>';
5761 }
5762
5763 if (empty($hidenavigation)) {
5764 if ((int) $limit > 0 && empty($hideselectlimit)) {
5765 $pagesizechoices = '10:10,15:15,20:20,30:30,40:40,50:50,100:100,250:250,500:500,1000:1000';
5766 $pagesizechoices .= ',5000:5000,10000:10000,20000:20000';
5767 //$pagesizechoices.=',0:'.$langs->trans("All"); // Not yet supported
5768 //$pagesizechoices.=',2:2';
5769 if (!empty($conf->global->MAIN_PAGESIZE_CHOICES)) {
5770 $pagesizechoices = $conf->global->MAIN_PAGESIZE_CHOICES;
5771 }
5772
5773 print '<li class="pagination">';
5774 print '<select class="flat selectlimit" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
5775 $tmpchoice = explode(',', $pagesizechoices);
5776 $tmpkey = $limit.':'.$limit;
5777 if (!in_array($tmpkey, $tmpchoice)) {
5778 $tmpchoice[] = $tmpkey;
5779 }
5780 $tmpkey = $conf->liste_limit.':'.$conf->liste_limit;
5781 if (!in_array($tmpkey, $tmpchoice)) {
5782 $tmpchoice[] = $tmpkey;
5783 }
5784 asort($tmpchoice, SORT_NUMERIC);
5785 foreach ($tmpchoice as $val) {
5786 $selected = '';
5787 $tmp = explode(':', $val);
5788 $key = $tmp[0];
5789 $val = $tmp[1];
5790 if ($key != '' && $val != '') {
5791 if ((int) $key == (int) $limit) {
5792 $selected = ' selected="selected"';
5793 }
5794 print '<option name="'.$key.'"'.$selected.'>'.dol_escape_htmltag($val).'</option>'."\n";
5795 }
5796 }
5797 print '</select>';
5798 if ($conf->use_javascript_ajax) {
5799 print '<!-- JS CODE TO ENABLE select limit to launch submit of page -->
5800 <script>
5801 jQuery(document).ready(function () {
5802 jQuery(".selectlimit").change(function() {
5803 console.log("Change limit. Send submit");
5804 $(this).parents(\'form:first\').submit();
5805 });
5806 });
5807 </script>
5808 ';
5809 }
5810 print '</li>';
5811 }
5812 if ($page > 0) {
5813 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>';
5814 }
5815 if ($betweenarrows) {
5816 print '<!--<div class="betweenarrows nowraponall inline-block">-->';
5817 print $betweenarrows;
5818 print '<!--</div>-->';
5819 }
5820 if ($nextpage > 0) {
5821 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>';
5822 }
5823 if ($afterarrows) {
5824 print '<li class="paginationafterarrows">';
5825 print $afterarrows;
5826 print '</li>';
5827 }
5828 }
5829 print '</ul></div>'."\n";
5830}
5831
5832
5844function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, $html = 0)
5845{
5846 $morelabel = '';
5847
5848 if (preg_match('/%/', $rate)) {
5849 $rate = str_replace('%', '', $rate);
5850 $addpercent = true;
5851 }
5852 $reg = array();
5853 if (preg_match('/\‍((.*)\‍)/', $rate, $reg)) {
5854 $morelabel = ' ('.$reg[1].')';
5855 $rate = preg_replace('/\s*'.preg_quote($morelabel, '/').'/', '', $rate);
5856 $morelabel = ' '.($html ? '<span class="opacitymedium">' : '').'('.$reg[1].')'.($html ? '</span>' : '');
5857 }
5858 if (preg_match('/\*/', $rate)) {
5859 $rate = str_replace('*', '', $rate);
5860 $info_bits |= 1;
5861 }
5862
5863 // If rate is '9/9/9' we don't change it. If rate is '9.000' we apply price()
5864 if (!preg_match('/\//', $rate)) {
5865 $ret = price($rate, 0, '', 0, 0).($addpercent ? '%' : '');
5866 } else {
5867 // TODO Split on / and output with a price2num to have clean numbers without ton of 000.
5868 $ret = $rate.($addpercent ? '%' : '');
5869 }
5870 if (($info_bits & 1) && $usestarfornpr >= 0) {
5871 $ret .= ' *';
5872 }
5873 $ret .= $morelabel;
5874 return $ret;
5875}
5876
5877
5893function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1, $currency_code = '')
5894{
5895 global $langs, $conf;
5896
5897 // Clean parameters
5898 if (empty($amount)) {
5899 $amount = 0; // To have a numeric value if amount not defined or = ''
5900 }
5901 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number)
5902 if ($rounding == -1) {
5903 $rounding = min($conf->global->MAIN_MAX_DECIMALS_UNIT, $conf->global->MAIN_MAX_DECIMALS_TOT);
5904 }
5905 $nbdecimal = $rounding;
5906
5907 if ($outlangs === 'none') {
5908 // Use international separators
5909 $dec = '.';
5910 $thousand = '';
5911 } else {
5912 // Output separators by default (french)
5913 $dec = ',';
5914 $thousand = ' ';
5915
5916 // If $outlangs not forced, we use use language
5917 if (!is_object($outlangs)) {
5918 $outlangs = $langs;
5919 }
5920
5921 if ($outlangs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
5922 $dec = $outlangs->transnoentitiesnoconv("SeparatorDecimal");
5923 }
5924 if ($outlangs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
5925 $thousand = $outlangs->transnoentitiesnoconv("SeparatorThousand");
5926 }
5927 if ($thousand == 'None') {
5928 $thousand = '';
5929 } elseif ($thousand == 'Space') {
5930 $thousand = ' ';
5931 }
5932 }
5933 //print "outlangs=".$outlangs->defaultlang." amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
5934
5935 //print "amount=".$amount."-";
5936 $amount = str_replace(',', '.', $amount); // should be useless
5937 //print $amount."-";
5938 $datas = explode('.', $amount);
5939 $decpart = isset($datas[1]) ? $datas[1] : '';
5940 $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
5941 //print "decpart=".$decpart."<br>";
5942 $end = '';
5943
5944 // We increase nbdecimal if there is more decimal than asked (to not loose information)
5945 if (dol_strlen($decpart) > $nbdecimal) {
5946 $nbdecimal = dol_strlen($decpart);
5947 }
5948 // Si on depasse max
5949 $max_nbdecimal = (int) str_replace('...', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'));
5950 if ($trunc && $nbdecimal > $max_nbdecimal) {
5951 $nbdecimal = $max_nbdecimal;
5952 if (preg_match('/\.\.\./i', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'))) {
5953 // Si un affichage est tronque, on montre des ...
5954 $end = '...';
5955 }
5956 }
5957
5958 // If force rounding
5959 if ((string) $forcerounding != '-1') {
5960 if ($forcerounding === 'MU') {
5961 $nbdecimal = $conf->global->MAIN_MAX_DECIMALS_UNIT;
5962 } elseif ($forcerounding === 'MT') {
5963 $nbdecimal = $conf->global->MAIN_MAX_DECIMALS_TOT;
5964 } elseif ($forcerounding >= 0) {
5965 $nbdecimal = $forcerounding;
5966 }
5967 }
5968
5969 // Format number
5970 $output = number_format($amount, $nbdecimal, $dec, $thousand);
5971 if ($form) {
5972 $output = preg_replace('/\s/', '&nbsp;', $output);
5973 $output = preg_replace('/\'/', '&#039;', $output);
5974 }
5975 // Add symbol of currency if requested
5976 $cursymbolbefore = $cursymbolafter = '';
5977 if ($currency_code && is_object($outlangs)) {
5978 if ($currency_code == 'auto') {
5979 $currency_code = $conf->currency;
5980 }
5981
5982 $listofcurrenciesbefore = array('AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD', 'CRC');
5983 $listoflanguagesbefore = array('nl_NL');
5984 if (in_array($currency_code, $listofcurrenciesbefore) || in_array($outlangs->defaultlang, $listoflanguagesbefore)) {
5985 $cursymbolbefore .= $outlangs->getCurrencySymbol($currency_code);
5986 } else {
5987 $tmpcur = $outlangs->getCurrencySymbol($currency_code);
5988 $cursymbolafter .= ($tmpcur == $currency_code ? ' '.$tmpcur : $tmpcur);
5989 }
5990 }
5991 $output = $cursymbolbefore.$output.$end.($cursymbolafter ? ' ' : '').$cursymbolafter;
5992
5993 return $output;
5994}
5995
6020function price2num($amount, $rounding = '', $option = 0)
6021{
6022 global $langs, $conf;
6023
6024 // Clean parameters
6025 if (is_null($amount)) {
6026 $amount = '';
6027 }
6028
6029 // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
6030 // Numbers must be '1234.56'
6031 // Decimal delimiter for PHP and database SQL requests must be '.'
6032 $dec = ',';
6033 $thousand = ' ';
6034 if (is_null($langs)) { // $langs is not defined, we use english values.
6035 $dec = '.';
6036 $thousand = ',';
6037 } else {
6038 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6039 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
6040 }
6041 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6042 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
6043 }
6044 }
6045 if ($thousand == 'None') {
6046 $thousand = '';
6047 } elseif ($thousand == 'Space') {
6048 $thousand = ' ';
6049 }
6050 //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6051
6052 // Convert value to universal number format (no thousand separator, '.' as decimal separator)
6053 if ($option != 1) { // If not a PHP number or unknown, we change or clean format
6054 //print "\n".'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'<br>';
6055 if (!is_numeric($amount)) {
6056 $amount = preg_replace('/[a-zA-Z\/\\\*\‍(\‍)<>\_]/', '', $amount);
6057 }
6058
6059 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
6060 $amount = str_replace($thousand, '', $amount);
6061 }
6062
6063 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6064 // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
6065 // So if number was already a good number, it is converted into local Dolibarr setup.
6066 if (is_numeric($amount)) {
6067 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6068 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6069 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6070 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6071 $amount = number_format($amount, $nbofdec, $dec, $thousand);
6072 }
6073 //print "QQ".$amount."<br>\n";
6074
6075 // Now make replace (the main goal of function)
6076 if ($thousand != ',' && $thousand != '.') {
6077 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6078 }
6079
6080 $amount = str_replace(' ', '', $amount); // To avoid spaces
6081 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6082 $amount = str_replace($dec, '.', $amount);
6083
6084 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6085 }
6086 //print ' XX'.$amount.' '.$rounding;
6087
6088 // Now, $amount is a real PHP float number. We make a rounding if required.
6089 if ($rounding) {
6090 $nbofdectoround = '';
6091 if ($rounding == 'MU') {
6092 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_UNIT;
6093 } elseif ($rounding == 'MT') {
6094 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_TOT;
6095 } elseif ($rounding == 'MS') {
6096 $nbofdectoround = isset($conf->global->MAIN_MAX_DECIMALS_STOCK) ? $conf->global->MAIN_MAX_DECIMALS_STOCK : 5;
6097 } elseif ($rounding == 'CU') {
6098 $nbofdectoround = max($conf->global->MAIN_MAX_DECIMALS_UNIT, 8); // TODO Use param of currency
6099 } elseif ($rounding == 'CT') {
6100 $nbofdectoround = max($conf->global->MAIN_MAX_DECIMALS_TOT, 8); // TODO Use param of currency
6101 } elseif (is_numeric($rounding)) {
6102 $nbofdectoround = (int) $rounding;
6103 }
6104
6105 //print " RR".$amount.' - '.$nbofdectoround.'<br>';
6106 if (dol_strlen($nbofdectoround)) {
6107 $amount = round(is_string($amount) ? (float) $amount : $amount, $nbofdectoround); // $nbofdectoround can be 0.
6108 } else {
6109 return 'ErrorBadParameterProvidedToFunction';
6110 }
6111 //print ' SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
6112
6113 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6114 // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
6115 if (is_numeric($amount)) {
6116 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6117 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6118 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6119 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6120 $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
6121 }
6122 //print "TT".$amount.'<br>';
6123
6124 // Always make replace because each math function (like round) replace
6125 // with local values and we want a number that has a SQL string format x.y
6126 if ($thousand != ',' && $thousand != '.') {
6127 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6128 }
6129
6130 $amount = str_replace(' ', '', $amount); // To avoid spaces
6131 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6132 $amount = str_replace($dec, '.', $amount);
6133
6134 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6135 }
6136
6137 return $amount;
6138}
6139
6152function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round = -1, $forceunitoutput = 'no', $use_short_label = 0)
6153{
6154 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
6155
6156 if (($forceunitoutput == 'no' && $dimension < 1 / 10000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -6)) {
6157 $dimension = $dimension * 1000000;
6158 $unit = $unit - 6;
6159 } elseif (($forceunitoutput == 'no' && $dimension < 1 / 10 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -3)) {
6160 $dimension = $dimension * 1000;
6161 $unit = $unit - 3;
6162 } elseif (($forceunitoutput == 'no' && $dimension > 100000000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 6)) {
6163 $dimension = $dimension / 1000000;
6164 $unit = $unit + 6;
6165 } elseif (($forceunitoutput == 'no' && $dimension > 100000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 3)) {
6166 $dimension = $dimension / 1000;
6167 $unit = $unit + 3;
6168 }
6169 // Special case when we want output unit into pound or ounce
6170 /* TODO
6171 if ($unit < 90 && $type == 'weight' && is_numeric($forceunitoutput) && (($forceunitoutput == 98) || ($forceunitoutput == 99))
6172 {
6173 $dimension = // convert dimension from standard unit into ounce or pound
6174 $unit = $forceunitoutput;
6175 }
6176 if ($unit > 90 && $type == 'weight' && is_numeric($forceunitoutput) && $forceunitoutput < 90)
6177 {
6178 $dimension = // convert dimension from standard unit into ounce or pound
6179 $unit = $forceunitoutput;
6180 }*/
6181
6182 $ret = price($dimension, 0, $outputlangs, 0, 0, $round);
6183 $ret .= ' '.measuringUnitString(0, $type, $unit, $use_short_label, $outputlangs);
6184
6185 return $ret;
6186}
6187
6188
6201function get_localtax($vatrate, $local, $thirdparty_buyer = "", $thirdparty_seller = "", $vatnpr = 0)
6202{
6203 global $db, $conf, $mysoc;
6204
6205 if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
6206 $thirdparty_seller = $mysoc;
6207 }
6208
6209 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);
6210
6211 $vatratecleaned = $vatrate;
6212 $reg = array();
6213 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6214 $vatratecleaned = trim($reg[1]);
6215 $vatratecode = $reg[2];
6216 }
6217
6218 /*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
6219 {
6220 return 0;
6221 }*/
6222
6223 // Some test to guess with no need to make database access
6224 if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
6225 if ($local == 1) {
6226 if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
6227 return 0;
6228 }
6229 if ($thirdparty_seller->id == $mysoc->id) {
6230 if (!$thirdparty_buyer->localtax1_assuj) {
6231 return 0;
6232 }
6233 } else {
6234 if (!$thirdparty_seller->localtax1_assuj) {
6235 return 0;
6236 }
6237 }
6238 }
6239
6240 if ($local == 2) {
6241 //if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
6242 if (!$mysoc->localtax2_assuj) {
6243 return 0; // If main vat is 0, IRPF may be different than 0.
6244 }
6245 if ($thirdparty_seller->id == $mysoc->id) {
6246 if (!$thirdparty_buyer->localtax2_assuj) {
6247 return 0;
6248 }
6249 } else {
6250 if (!$thirdparty_seller->localtax2_assuj) {
6251 return 0;
6252 }
6253 }
6254 }
6255 } else {
6256 if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
6257 return 0;
6258 }
6259 if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
6260 return 0;
6261 }
6262 }
6263
6264 // For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
6265 if (in_array($mysoc->country_code, array('ES'))) {
6266 $conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
6267 }
6268
6269 // Search local taxes
6270 if (!empty($conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY)) {
6271 if ($local == 1) {
6272 if ($thirdparty_seller != $mysoc) {
6273 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6274 return $thirdparty_seller->localtax1_value;
6275 }
6276 } else { // i am the seller
6277 if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
6278 return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
6279 }
6280 }
6281 }
6282 if ($local == 2) {
6283 if ($thirdparty_seller != $mysoc) {
6284 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6285 // TODO We should also return value defined on thirdparty only if defined
6286 return $thirdparty_seller->localtax2_value;
6287 }
6288 } else { // i am the seller
6289 if (in_array($mysoc->country_code, array('ES'))) {
6290 return $thirdparty_buyer->localtax2_value;
6291 } else {
6292 return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
6293 }
6294 }
6295 }
6296 }
6297
6298 // By default, search value of local tax on line of common tax
6299 $sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
6300 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6301 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
6302 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6303 if (!empty($vatratecode)) {
6304 $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
6305 } else {
6306 $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
6307 }
6308
6309 $resql = $db->query($sql);
6310
6311 if ($resql) {
6312 $obj = $db->fetch_object($resql);
6313 if ($obj) {
6314 if ($local == 1) {
6315 return $obj->localtax1;
6316 } elseif ($local == 2) {
6317 return $obj->localtax2;
6318 }
6319 }
6320 }
6321
6322 return 0;
6323}
6324
6325
6334function isOnlyOneLocalTax($local)
6335{
6336 $tax = get_localtax_by_third($local);
6337
6338 $valors = explode(":", $tax);
6339
6340 if (count($valors) > 1) {
6341 return false;
6342 } else {
6343 return true;
6344 }
6345}
6346
6354{
6355 global $db, $mysoc;
6356
6357 $sql = " SELECT t.localtax".$local." as localtax";
6358 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_pays";
6359 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.active = 1 AND t.taux = (";
6360 $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";
6361 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND tt.active = 1)";
6362 $sql .= " AND t.localtax".$local."_type <> '0'";
6363 $sql .= " ORDER BY t.rowid DESC";
6364
6365 $resql = $db->query($sql);
6366 if ($resql) {
6367 $obj = $db->fetch_object($resql);
6368 if ($obj) {
6369 return $obj->localtax;
6370 } else {
6371 return '0';
6372 }
6373 }
6374
6375 return 'Error';
6376}
6377
6378
6390function getTaxesFromId($vatrate, $buyer = null, $seller = null, $firstparamisid = 1)
6391{
6392 global $db, $mysoc;
6393
6394 dol_syslog("getTaxesFromId vat id or rate = ".$vatrate);
6395
6396 // Search local taxes
6397 $sql = "SELECT t.rowid, t.code, t.taux as rate, t.recuperableonly as npr, t.accountancy_code_sell, t.accountancy_code_buy,";
6398 $sql .= " t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type";
6399 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6400 if ($firstparamisid) {
6401 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6402 } else {
6403 $vatratecleaned = $vatrate;
6404 $vatratecode = '';
6405 $reg = array();
6406 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6407 $vatratecleaned = $reg[1];
6408 $vatratecode = $reg[2];
6409 }
6410
6411 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6412 /*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 ??
6413 else $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";*/
6414 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";
6415 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6416 if ($vatratecode) {
6417 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6418 }
6419 }
6420
6421 $resql = $db->query($sql);
6422 if ($resql) {
6423 $obj = $db->fetch_object($resql);
6424 if ($obj) {
6425 return array(
6426 'rowid'=>$obj->rowid,
6427 'code'=>$obj->code,
6428 'rate'=>$obj->rate,
6429 'localtax1'=>$obj->localtax1,
6430 'localtax1_type'=>$obj->localtax1_type,
6431 'localtax2'=>$obj->localtax2,
6432 'localtax2_type'=>$obj->localtax2_type,
6433 'npr'=>$obj->npr,
6434 'accountancy_code_sell'=>$obj->accountancy_code_sell,
6435 'accountancy_code_buy'=>$obj->accountancy_code_buy
6436 );
6437 } else {
6438 return array();
6439 }
6440 } else {
6441 dol_print_error($db);
6442 }
6443
6444 return array();
6445}
6446
6463function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid = 0)
6464{
6465 global $db, $mysoc;
6466
6467 dol_syslog("getLocalTaxesFromRate vatrate=".$vatrate." local=".$local);
6468
6469 // Search local taxes
6470 $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";
6471 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6472 if ($firstparamisid) {
6473 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6474 } else {
6475 $vatratecleaned = $vatrate;
6476 $vatratecode = '';
6477 $reg = array();
6478 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "x.x (yy)"
6479 $vatratecleaned = $reg[1];
6480 $vatratecode = $reg[2];
6481 }
6482
6483 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6484 if (!empty($mysoc) && $mysoc->country_code == 'ES') {
6485 $countrycodetouse = ((empty($buyer) || empty($buyer->country_code)) ? $mysoc->country_code : $buyer->country_code);
6486 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'"; // local tax in spain use the buyer country ??
6487 } else {
6488 $countrycodetouse = ((empty($seller) || empty($seller->country_code)) ? $mysoc->country_code : $seller->country_code);
6489 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'";
6490 }
6491 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6492 if ($vatratecode) {
6493 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6494 }
6495 }
6496
6497 $resql = $db->query($sql);
6498 if ($resql) {
6499 $obj = $db->fetch_object($resql);
6500
6501 if ($obj) {
6502 $vateratestring = $obj->rate.($obj->code ? ' ('.$obj->code.')' : '');
6503
6504 if ($local == 1) {
6505 return array($obj->localtax1_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6506 } elseif ($local == 2) {
6507 return array($obj->localtax2_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6508 } else {
6509 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);
6510 }
6511 }
6512 }
6513
6514 return array();
6515}
6516
6527function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice = 0)
6528{
6529 global $db, $conf, $mysoc;
6530
6531 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6532
6533 $ret = 0;
6534 $found = 0;
6535
6536 if ($idprod > 0) {
6537 // Load product
6538 $product = new Product($db);
6539 $product->fetch($idprod);
6540
6541 if ($mysoc->country_code == $thirdpartytouse->country_code) {
6542 // If country to consider is ours
6543 if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object
6544 $result = $product->get_buyprice($idprodfournprice, 0, 0, 0);
6545 if ($result > 0) {
6546 $ret = $product->vatrate_supplier;
6547 if ($product->default_vat_code_supplier) {
6548 $ret .= ' ('.$product->default_vat_code_supplier.')';
6549 }
6550 $found = 1;
6551 }
6552 }
6553 if (!$found) {
6554 $ret = $product->tva_tx; // Default sales vat of product
6555 if ($product->default_vat_code) {
6556 $ret .= ' ('.$product->default_vat_code.')';
6557 }
6558 $found = 1;
6559 }
6560 } else {
6561 // TODO Read default product vat according to product and another countrycode.
6562 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6563 }
6564 }
6565
6566 if (!$found) {
6567 if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) {
6568 // 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).
6569 $sql = "SELECT t.taux as vat_rate, t.code as default_vat_code";
6570 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6571 $sql .= " WHERE t.active = 1 AND t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdpartytouse->country_code)."'";
6572 $sql .= " ORDER BY t.use_default DESC, t.taux DESC, t.code ASC, t.recuperableonly ASC";
6573 $sql .= $db->plimit(1);
6574
6575 $resql = $db->query($sql);
6576 if ($resql) {
6577 $obj = $db->fetch_object($resql);
6578 if ($obj) {
6579 $ret = $obj->vat_rate;
6580 if ($obj->default_vat_code) {
6581 $ret .= ' ('.$obj->default_vat_code.')';
6582 }
6583 }
6584 $db->free($resql);
6585 } else {
6586 dol_print_error($db);
6587 }
6588 } else {
6589 // Forced value if autodetect fails. MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS can be
6590 // '1.23'
6591 // or '1.23 (CODE)'
6592 $defaulttx = '';
6593 if ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS != 'none') {
6594 $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6595 }
6596 /*if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6597 $defaultcode = $reg[1];
6598 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6599 }*/
6600
6601 $ret = $defaulttx;
6602 }
6603 }
6604
6605 dol_syslog("get_product_vat_for_country: ret=".$ret);
6606 return $ret;
6607}
6608
6618function get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
6619{
6620 global $db, $mysoc;
6621
6622 if (!class_exists('Product')) {
6623 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6624 }
6625
6626 $ret = 0;
6627 $found = 0;
6628
6629 if ($idprod > 0) {
6630 // Load product
6631 $product = new Product($db);
6632 $result = $product->fetch($idprod);
6633
6634 if ($mysoc->country_code == $thirdpartytouse->country_code) { // If selling country is ours
6635 /* Not defined yet, so we don't use this
6636 if ($local==1) $ret=$product->localtax1_tx;
6637 elseif ($local==2) $ret=$product->localtax2_tx;
6638 $found=1;
6639 */
6640 } else {
6641 // TODO Read default product vat according to product and another countrycode.
6642 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6643 }
6644 }
6645
6646 if (!$found) {
6647 // If vat of product for the country not found or not defined, we return higher vat of country.
6648 $sql = "SELECT taux as vat_rate, localtax1, localtax2";
6649 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6650 $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code='".$db->escape($thirdpartytouse->country_code)."'";
6651 $sql .= " ORDER BY t.taux DESC, t.recuperableonly ASC";
6652 $sql .= $db->plimit(1);
6653
6654 $resql = $db->query($sql);
6655 if ($resql) {
6656 $obj = $db->fetch_object($resql);
6657 if ($obj) {
6658 if ($local == 1) {
6659 $ret = $obj->localtax1;
6660 } elseif ($local == 2) {
6661 $ret = $obj->localtax2;
6662 }
6663 }
6664 } else {
6665 dol_print_error($db);
6666 }
6667 }
6668
6669 dol_syslog("get_product_localtax_for_country: ret=".$ret);
6670 return $ret;
6671}
6672
6689function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6690{
6691 global $conf;
6692
6693 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6694
6695 // Note: possible values for tva_assuj are 0/1 or franchise/reel
6696 $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;
6697
6698 $seller_country_code = $thirdparty_seller->country_code;
6699 $seller_in_cee = isInEEC($thirdparty_seller);
6700
6701 $buyer_country_code = $thirdparty_buyer->country_code;
6702 $buyer_in_cee = isInEEC($thirdparty_buyer);
6703
6704 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 : ''));
6705
6706 // 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)
6707 // we use the buyer VAT.
6708 if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) {
6709 if ($seller_in_cee && $buyer_in_cee) {
6710 $isacompany = $thirdparty_buyer->isACompany();
6711 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6712 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6713 if (!isValidVATID($thirdparty_buyer)) {
6714 $isacompany = 0;
6715 }
6716 }
6717
6718 if (!$isacompany) {
6719 //print 'VATRULE 0';
6720 return get_product_vat_for_country($idprod, $thirdparty_buyer, $idprodfournprice);
6721 }
6722 }
6723 }
6724
6725 // If seller does not use VAT, default VAT is 0. End of rule.
6726 if (!$seller_use_vat) {
6727 //print 'VATRULE 1';
6728 return 0;
6729 }
6730
6731 // If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule.
6732 if (($seller_country_code == $buyer_country_code)
6733 || (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC')))) { // Warning ->country_code not always defined
6734 //print 'VATRULE 2';
6735 $tmpvat = get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6736
6737 if ($seller_country_code == 'IN' && getDolGlobalString('MAIN_SALETAX_AUTOSWITCH_I_CS_FOR_INDIA')) {
6738 // Special case for india.
6739 //print 'VATRULE 2b';
6740 $reg = array();
6741 if (preg_match('/C+S-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id != $thirdparty_buyer->state_id) {
6742 // we must revert the C+S into I
6743 $tmpvat = str_replace("C+S", "I", $tmpvat);
6744 } elseif (preg_match('/I-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id == $thirdparty_buyer->state_id) {
6745 // we must revert the I into C+S
6746 $tmpvat = str_replace("I", "C+S", $tmpvat);
6747 }
6748 }
6749
6750 return $tmpvat;
6751 }
6752
6753 // 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.
6754 // 'VATRULE 3' - Not supported
6755
6756 // If (seller and buyer in the European Community) and (buyer = individual) then VAT by default = VAT of the product sold. End of rule
6757 // If (seller and buyer in European Community) and (buyer = company) then VAT by default=0. End of rule
6758 if (($seller_in_cee && $buyer_in_cee)) {
6759 $isacompany = $thirdparty_buyer->isACompany();
6760 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6761 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6762 if (!isValidVATID($thirdparty_buyer)) {
6763 $isacompany = 0;
6764 }
6765 }
6766
6767 if (!$isacompany) {
6768 //print 'VATRULE 4';
6769 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6770 } else {
6771 //print 'VATRULE 5';
6772 return 0;
6773 }
6774 }
6775
6776 // 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
6777 // I don't see any use case that need this rule.
6778 if (!empty($conf->global->MAIN_USE_VAT_OF_PRODUCT_FOR_INDIVIDUAL_CUSTOMER_OUT_OF_EEC) && empty($buyer_in_cee)) {
6779 $isacompany = $thirdparty_buyer->isACompany();
6780 if (!$isacompany) {
6781 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6782 //print 'VATRULE extra';
6783 }
6784 }
6785
6786 // Otherwise the VAT proposed by default=0. End of rule.
6787 // Rem: This means that at least one of the 2 is outside the European Community and the country differs
6788 //print 'VATRULE 6';
6789 return 0;
6790}
6791
6792
6803function get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6804{
6805 global $db;
6806
6807 if ($idprodfournprice > 0) {
6808 if (!class_exists('ProductFournisseur')) {
6809 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
6810 }
6811 $prodprice = new ProductFournisseur($db);
6812 $prodprice->fetch_product_fournisseur_price($idprodfournprice);
6813 return $prodprice->fourn_tva_npr;
6814 } elseif ($idprod > 0) {
6815 if (!class_exists('Product')) {
6816 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6817 }
6818 $prod = new Product($db);
6819 $prod->fetch($idprod);
6820 return $prod->tva_npr;
6821 }
6822
6823 return 0;
6824}
6825
6839function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod = 0)
6840{
6841 global $mysoc;
6842
6843 if (!is_object($thirdparty_seller)) {
6844 return -1;
6845 }
6846 if (!is_object($thirdparty_buyer)) {
6847 return -1;
6848 }
6849
6850 if ($local == 1) { // Localtax 1
6851 if ($mysoc->country_code == 'ES') {
6852 if (is_numeric($thirdparty_buyer->localtax1_assuj) && !$thirdparty_buyer->localtax1_assuj) {
6853 return 0;
6854 }
6855 } else {
6856 // Si vendeur non assujeti a Localtax1, localtax1 par default=0
6857 if (is_numeric($thirdparty_seller->localtax1_assuj) && !$thirdparty_seller->localtax1_assuj) {
6858 return 0;
6859 }
6860 if (!is_numeric($thirdparty_seller->localtax1_assuj) && $thirdparty_seller->localtax1_assuj == 'localtax1off') {
6861 return 0;
6862 }
6863 }
6864 } elseif ($local == 2) { //I Localtax 2
6865 // Si vendeur non assujeti a Localtax2, localtax2 par default=0
6866 if (is_numeric($thirdparty_seller->localtax2_assuj) && !$thirdparty_seller->localtax2_assuj) {
6867 return 0;
6868 }
6869 if (!is_numeric($thirdparty_seller->localtax2_assuj) && $thirdparty_seller->localtax2_assuj == 'localtax2off') {
6870 return 0;
6871 }
6872 }
6873
6874 if ($thirdparty_seller->country_code == $thirdparty_buyer->country_code) {
6875 return get_product_localtax_for_country($idprod, $local, $thirdparty_seller);
6876 }
6877
6878 return 0;
6879}
6880
6889function yn($yesno, $case = 1, $color = 0)
6890{
6891 global $langs;
6892
6893 $result = 'unknown';
6894 $classname = '';
6895 if ($yesno == 1 || (isset($yesno) && (strtolower($yesno) == 'yes' || strtolower($yesno) == 'true'))) { // A mettre avant test sur no a cause du == 0
6896 $result = $langs->trans('yes');
6897 if ($case == 1 || $case == 3) {
6898 $result = $langs->trans("Yes");
6899 }
6900 if ($case == 2) {
6901 $result = '<input type="checkbox" value="1" checked disabled>';
6902 }
6903 if ($case == 3) {
6904 $result = '<input type="checkbox" value="1" checked disabled> '.$result;
6905 }
6906
6907 $classname = 'ok';
6908 } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') {
6909 $result = $langs->trans("no");
6910 if ($case == 1 || $case == 3) {
6911 $result = $langs->trans("No");
6912 }
6913 if ($case == 2) {
6914 $result = '<input type="checkbox" value="0" disabled>';
6915 }
6916 if ($case == 3) {
6917 $result = '<input type="checkbox" value="0" disabled> '.$result;
6918 }
6919
6920 if ($color == 2) {
6921 $classname = 'ok';
6922 } else {
6923 $classname = 'error';
6924 }
6925 }
6926 if ($color) {
6927 return '<span class="'.$classname.'">'.$result.'</span>';
6928 }
6929 return $result;
6930}
6931
6947function get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart = '')
6948{
6949 global $conf;
6950
6951 if (empty($modulepart) && !empty($object->module)) {
6952 $modulepart = $object->module;
6953 }
6954
6955 $path = '';
6956
6957 $arrayforoldpath = array('cheque', 'category', 'holiday', 'supplier_invoice', 'invoice_supplier', 'mailing', 'supplier_payment');
6958 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
6959 $arrayforoldpath[] = 'product';
6960 }
6961 if (!empty($level) && in_array($modulepart, $arrayforoldpath)) {
6962 // This part should be removed once all code is using "get_exdir" to forge path, with parameter $object and $modulepart provided.
6963 if (empty($alpha)) {
6964 $num = preg_replace('/([^0-9])/i', '', $num);
6965 } else {
6966 $num = preg_replace('/^.*\-/i', '', $num);
6967 }
6968 $num = substr("000".$num, -$level);
6969 if ($level == 1) {
6970 $path = substr($num, 0, 1);
6971 }
6972 if ($level == 2) {
6973 $path = substr($num, 1, 1).'/'.substr($num, 0, 1);
6974 }
6975 if ($level == 3) {
6976 $path = substr($num, 2, 1).'/'.substr($num, 1, 1).'/'.substr($num, 0, 1);
6977 }
6978 } else {
6979 // We will enhance here a common way of forging path for document storage.
6980 // In a future, we may distribute directories on several levels depending on setup and object.
6981 // Here, $object->id, $object->ref and $modulepart are required.
6982 //var_dump($modulepart);
6983 $path = dol_sanitizeFileName(empty($object->ref) ? (string) $object->id : $object->ref);
6984 }
6985
6986 if (empty($withoutslash) && !empty($path)) {
6987 $path .= '/';
6988 }
6989
6990 return $path;
6991}
6992
7001function dol_mkdir($dir, $dataroot = '', $newmask = '')
7002{
7003 global $conf;
7004
7005 dol_syslog("functions.lib::dol_mkdir: dir=".$dir, LOG_INFO);
7006
7007 $dir_osencoded = dol_osencode($dir);
7008 if (@is_dir($dir_osencoded)) {
7009 return 0;
7010 }
7011
7012 $nberr = 0;
7013 $nbcreated = 0;
7014
7015 $ccdir = '';
7016 if (!empty($dataroot)) {
7017 // Remove data root from loop
7018 $dir = str_replace($dataroot.'/', '', $dir);
7019 $ccdir = $dataroot.'/';
7020 }
7021
7022 $cdir = explode("/", $dir);
7023 $num = count($cdir);
7024 for ($i = 0; $i < $num; $i++) {
7025 if ($i > 0) {
7026 $ccdir .= '/'.$cdir[$i];
7027 } else {
7028 $ccdir .= $cdir[$i];
7029 }
7030 $regs = array();
7031 if (preg_match("/^.:$/", $ccdir, $regs)) {
7032 continue; // Si chemin Windows incomplet, on poursuit par rep suivant
7033 }
7034
7035 // Attention, le is_dir() peut echouer bien que le rep existe.
7036 // (ex selon config de open_basedir)
7037 if ($ccdir) {
7038 $ccdir_osencoded = dol_osencode($ccdir);
7039 if (!@is_dir($ccdir_osencoded)) {
7040 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.", LOG_DEBUG);
7041
7042 umask(0);
7043 $dirmaskdec = octdec((string) $newmask);
7044 if (empty($newmask)) {
7045 $dirmaskdec = empty($conf->global->MAIN_UMASK) ? octdec('0755') : octdec($conf->global->MAIN_UMASK);
7046 }
7047 $dirmaskdec |= octdec('0111'); // Set x bit required for directories
7048 if (!@mkdir($ccdir_osencoded, $dirmaskdec)) {
7049 // Si le is_dir a renvoye une fausse info, alors on passe ici.
7050 dol_syslog("functions.lib::dol_mkdir: Fails to create directory '".$ccdir."' or directory already exists.", LOG_WARNING);
7051 $nberr++;
7052 } else {
7053 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' created", LOG_DEBUG);
7054 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignore
7055 $nbcreated++;
7056 }
7057 } else {
7058 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignores
7059 }
7060 }
7061 }
7062 return ($nberr ? -$nberr : $nbcreated);
7063}
7064
7065
7073function dolChmod($filepath, $newmask = '')
7074{
7075 global $conf;
7076
7077 if (!empty($newmask)) {
7078 @chmod($filepath, octdec($newmask));
7079 } elseif (!empty($conf->global->MAIN_UMASK)) {
7080 @chmod($filepath, octdec($conf->global->MAIN_UMASK));
7081 }
7082}
7083
7084
7091{
7092 return '<span class="fieldrequired">*</span>';
7093}
7094
7095
7112function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = 'UTF-8', $strip_tags = 0, $removedoublespaces = 1)
7113{
7114 if (is_null($stringtoclean)) {
7115 return '';
7116 }
7117
7118 if ($removelinefeed == 2) {
7119 $stringtoclean = preg_replace('/<br[^>]*>(\n|\r)+/ims', '<br>', $stringtoclean);
7120 }
7121 $temp = preg_replace('/<br[^>]*>/i', "\n", $stringtoclean);
7122
7123 // 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)
7124 $temp = dol_html_entity_decode($temp, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7125
7126 $temp = str_replace('< ', '__ltspace__', $temp);
7127
7128 if ($strip_tags) {
7129 $temp = strip_tags($temp);
7130 } else {
7131 // 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).
7132 $pattern = "/<[^<>]+>/";
7133 // Example of $temp: <a href="/myurl" title="<u>A title</u>">0000-021</a>
7134 // pass 1 - $temp after pass 1: <a href="/myurl" title="A title">0000-021
7135 // pass 2 - $temp after pass 2: 0000-021
7136 $tempbis = $temp;
7137 do {
7138 $temp = $tempbis;
7139 $tempbis = str_replace('<>', '', $temp); // No reason to have this into a text, except if value is to try bypass the next html cleaning
7140 $tempbis = preg_replace($pattern, '', $tempbis);
7141 //$idowhile++; print $temp.'-'.$tempbis."\n"; if ($idowhile > 100) break;
7142 } while ($tempbis != $temp);
7143
7144 $temp = $tempbis;
7145
7146 // 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).
7147 $temp = preg_replace('/<+([a-z]+)/i', '\1', $temp);
7148 }
7149
7150 $temp = dol_html_entity_decode($temp, ENT_COMPAT, $pagecodeto);
7151
7152 // Remove also carriage returns
7153 if ($removelinefeed == 1) {
7154 $temp = str_replace(array("\r\n", "\r", "\n"), " ", $temp);
7155 }
7156
7157 // And double quotes
7158 if ($removedoublespaces) {
7159 while (strpos($temp, " ")) {
7160 $temp = str_replace(" ", " ", $temp);
7161 }
7162 }
7163
7164 $temp = str_replace('__ltspace__', '< ', $temp);
7165
7166 return trim($temp);
7167}
7168
7184function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1, $cleanalsojavascript = 0, $allowiframe = 0, $allowed_tags = array(), $allowlink = 0)
7185{
7186 if (empty($allowed_tags)) {
7187 $allowed_tags = array(
7188 "html", "head", "meta", "body", "article", "a", "abbr", "b", "blockquote", "br", "cite", "div", "dl", "dd", "dt", "em", "font", "img", "ins", "hr", "i", "li",
7189 "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"
7190 );
7191 }
7192 $allowed_tags[] = "comment"; // this tags is added to manage comment <!--...--> that are replaced into <comment>...</comment>
7193 if ($allowiframe) {
7194 if (!in_array('iframe', $allowed_tags)) {
7195 $allowed_tags[] = "iframe";
7196 }
7197 }
7198 if ($allowlink) {
7199 if (!in_array('link', $allowed_tags)) {
7200 $allowed_tags[] = "link";
7201 }
7202 }
7203
7204 $allowed_tags_string = join("><", $allowed_tags);
7205 $allowed_tags_string = '<'.$allowed_tags_string.'>';
7206
7207 $stringtoclean = str_replace('<!DOCTYPE html>', '__!DOCTYPE_HTML__', $stringtoclean); // Replace DOCTYPE to avoid to have it removed by the strip_tags
7208
7209 $stringtoclean = dol_string_nounprintableascii($stringtoclean, 0);
7210
7211 //$stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
7212 $stringtoclean = preg_replace('/<!--([^>]*)-->/', '<comment>\1</comment>', $stringtoclean);
7213
7214 $stringtoclean = preg_replace('/&colon;/i', ':', $stringtoclean);
7215 $stringtoclean = preg_replace('/&#58;|&#0+58|&#x3A/i', '', $stringtoclean); // refused string ':' encoded (no reason to have a : encoded like this) to disable 'javascript:...'
7216
7217 $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
7218
7219 if ($cleanalsosomestyles) { // Clean for remaining html tags
7220 $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
7221 }
7222 if ($removeclassattribute) { // Clean for remaining html tags
7223 $temp = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $temp);
7224 }
7225
7226 // Remove 'javascript:' that we should not find into a text with
7227 // 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)).
7228 if ($cleanalsojavascript) {
7229 $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);
7230 }
7231
7232 $temp = str_replace('__!DOCTYPE_HTML__', '<!DOCTYPE html>', $temp); // Restore the DOCTYPE
7233
7234 $temp = preg_replace('/<comment>([^>]*)<\/comment>/', '<!--\1-->', $temp); // Restore html comments
7235
7236
7237 return $temp;
7238}
7239
7240
7252function dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes = array("allow", "allowfullscreen", "alt", "class", "contenteditable", "data-html", "frameborder", "height", "href", "id", "name", "src", "style", "target", "title", "width"))
7253{
7254 if (is_null($allowed_attributes)) {
7255 $allowed_attributes = array(
7256 "allow", "allowfullscreen", "alt", "async", "class", "contenteditable", "crossorigin", "data-html", "frameborder", "height", "href", "id", "name", "property", "rel", "src", "style", "target", "title", "type", "width",
7257 // HTML5
7258 "header", "footer", "nav", "section", "menu", "menuitem"
7259 );
7260 }
7261 // Always add content and http-equiv for meta tags, required to force encoding and keep html content in utf8 by load/saveHTML functions.
7262 if (!in_array("content", $allowed_attributes)) {
7263 $allowed_attributes[] = "content";
7264 }
7265 if (!in_array("http-equiv", $allowed_attributes)) {
7266 $allowed_attributes[] = "http-equiv";
7267 }
7268
7269 if (class_exists('DOMDocument') && !empty($stringtoclean)) {
7270 $stringtoclean = '<?xml encoding="UTF-8"><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body>'.$stringtoclean.'</body></html>';
7271
7272 $dom = new DOMDocument(null, 'UTF-8');
7273 $dom->loadHTML($stringtoclean, LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7274
7275 if (is_object($dom)) {
7276 for ($els = $dom->getElementsByTagname('*'), $i = $els->length - 1; $i >= 0; $i--) {
7277 for ($attrs = $els->item($i)->attributes, $ii = $attrs->length - 1; $ii >= 0; $ii--) {
7278 //var_dump($attrs->item($ii));
7279 if (!empty($attrs->item($ii)->name)) {
7280 if (! in_array($attrs->item($ii)->name, $allowed_attributes)) {
7281 // Delete attribute if not into allowed_attributes
7282 $els->item($i)->removeAttribute($attrs->item($ii)->name);
7283 } elseif (in_array($attrs->item($ii)->name, array('style'))) {
7284 // If attribute is 'style'
7285 $valuetoclean = $attrs->item($ii)->value;
7286
7287 if (isset($valuetoclean)) {
7288 do {
7289 $oldvaluetoclean = $valuetoclean;
7290 $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments
7291 $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean);
7292 if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags.
7293 $valuetoclean = preg_replace('/display\s*:/mi', '', $valuetoclean);
7294 $valuetoclean = preg_replace('/z-index\s*:/mi', '', $valuetoclean);
7295 $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*:/mi', '', $valuetoclean);
7296 }
7297
7298 // We do not allow logout|passwordforgotten.php and action= into the content of a "style" tag
7299 $valuetoclean = preg_replace('/(logout|passwordforgotten)\.php/mi', '', $valuetoclean);
7300 $valuetoclean = preg_replace('/action=/mi', '', $valuetoclean);
7301 } while ($oldvaluetoclean != $valuetoclean);
7302 }
7303
7304 $attrs->item($ii)->value = $valuetoclean;
7305 }
7306 }
7307 }
7308 }
7309 }
7310
7311 $dom->encoding = 'UTF-8';
7312
7313 $return = $dom->saveHTML(); // This may add a LF at end of lines, so we will trim later
7314 //$return = '<html><body>aaaa</p>bb<p>ssdd</p>'."\n<p>aaa</p>aa<p>bb</p>";
7315
7316 $return = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $return);
7317 $return = preg_replace('/^'.preg_quote('<html><head><', '/').'[^<>]*'.preg_quote('></head><body>', '/').'/', '', $return);
7318 $return = preg_replace('/'.preg_quote('</body></html>', '/').'$/', '', trim($return));
7319
7320 return trim($return);
7321 } else {
7322 return $stringtoclean;
7323 }
7324}
7325
7337function dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags = array('textarea'), $cleanalsosomestyles = 0)
7338{
7339 $temp = $stringtoclean;
7340 foreach ($disallowed_tags as $tagtoremove) {
7341 $temp = preg_replace('/<\/?'.$tagtoremove.'>/', '', $temp);
7342 $temp = preg_replace('/<\/?'.$tagtoremove.'\s+[^>]*>/', '', $temp);
7343 }
7344
7345 if ($cleanalsosomestyles) {
7346 $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
7347 }
7348
7349 return $temp;
7350}
7351
7352
7362function dolGetFirstLineOfText($text, $nboflines = 1, $charset = 'UTF-8')
7363{
7364 if ($nboflines == 1) {
7365 if (dol_textishtml($text)) {
7366 $firstline = preg_replace('/<br[^>]*>.*$/s', '', $text); // The s pattern modifier means the . can match newline characters
7367 $firstline = preg_replace('/<div[^>]*>.*$/s', '', $firstline); // The s pattern modifier means the . can match newline characters
7368 } else {
7369 if (isset($text)) {
7370 $firstline = preg_replace('/[\n\r].*/', '', $text);
7371 } else {
7372 $firstline = '';
7373 }
7374 }
7375 return $firstline.(isset($firstline) && isset($text) && (strlen($firstline) != strlen($text)) ? '...' : '');
7376 } else {
7377 $ishtml = 0;
7378 if (dol_textishtml($text)) {
7379 $text = preg_replace('/\n/', '', $text);
7380 $ishtml = 1;
7381 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7382 } else {
7383 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7384 }
7385
7386 $text = strtr($text, $repTable);
7387 if ($charset == 'UTF-8') {
7388 $pattern = '/(<br[^>]*>)/Uu';
7389 } else {
7390 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7391 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7392 }
7393 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7394
7395 $firstline = '';
7396 $i = 0;
7397 $nba = count($a); // 2x nb of lines in $a because $a contains also a line for each new line separator
7398 while (($i < $nba) && ($i < ($nboflines * 2))) {
7399 if ($i % 2 == 0) {
7400 $firstline .= $a[$i];
7401 } elseif (($i < (($nboflines * 2) - 1)) && ($i < ($nba - 1))) {
7402 $firstline .= ($ishtml ? "<br>\n" : "\n");
7403 }
7404 $i++;
7405 }
7406 unset($a);
7407 return $firstline.(($i < $nba) ? '...' : '');
7408 }
7409}
7410
7411
7423function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false)
7424{
7425 if (is_null($stringtoencode)) {
7426 return '';
7427 }
7428
7429 if (!$nl2brmode) {
7430 return nl2br($stringtoencode, $forxml);
7431 } else {
7432 $ret = preg_replace('/(\r\n|\r|\n)/i', ($forxml ? '<br />' : '<br>'), $stringtoencode);
7433 return $ret;
7434 }
7435}
7436
7445function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = 'restricthtml')
7446{
7447 global $conf;
7448
7449 if (empty($nouseofiframesandbox) && !empty($conf->global->MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS)) {
7450 // TODO using sandbox on inline html content is not possible yet with current browsers
7451 //$s = '<iframe class="iframewithsandbox" sandbox><html><body>';
7452 //$s .= $stringtoencode;
7453 //$s .= '</body></html></iframe>';
7454 return $stringtoencode;
7455 } else {
7456 $out = $stringtoencode;
7457
7458 do {
7459 $oldstringtoclean = $out;
7460
7461 if (!empty($out) && !empty($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML) && $check != 'restricthtmlallowunvalid') {
7462 try {
7463 libxml_use_internal_errors(false); // Avoid to fill memory with xml errors
7464
7465 $dom = new DOMDocument;
7466 // Add a trick to solve pb with text without parent tag
7467 // like '<h1>Foo</h1><p>bar</p>' that wrongly ends up, without the trick, with '<h1>Foo<p>bar</p></h1>'
7468 // like 'abc' that wrongly ends up, without the trick, with '<p>abc</p>'
7469
7470 if (dol_textishtml($out)) {
7471 $out = '<?xml encoding="UTF-8"><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body><div class="tricktoremove">'.$out.'</div></body></html>';
7472 } else {
7473 $out = '<?xml encoding="UTF-8"><html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body><div class="tricktoremove">'.dol_nl2br($out).'</div></body></html>';
7474 }
7475
7476 $dom->loadHTML($out, LIBXML_HTML_NODEFDTD | LIBXML_ERR_NONE | LIBXML_HTML_NOIMPLIED | LIBXML_NONET | LIBXML_NOWARNING | LIBXML_NOERROR | LIBXML_NOXMLDECL);
7477
7478 $dom->encoding = 'UTF-8';
7479
7480 $out = trim($dom->saveHTML());
7481
7482 // Remove the trick added to solve pb with text in utf8 and text without parent tag
7483 $out = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $out);
7484 $out = preg_replace('/^'.preg_quote('<html><head><', '/').'[^<>]+'.preg_quote('></head><body><div class="tricktoremove">', '/').'/', '', $out);
7485 $out = preg_replace('/'.preg_quote('</div></body></html>', '/').'$/', '', trim($out));
7486 // $out = preg_replace('/^<\?xml encoding="UTF-8"><div class="tricktoremove">/', '', $out);
7487 // $out = preg_replace('/<\/div>$/', '', $out);
7488 // var_dump('rrrrrrrrrrrrrrrrrrrrrrrrrrrrr'.$out);
7489 } catch (Exception $e) {
7490 // If error, invalid HTML string with no way to clean it
7491 //print $e->getMessage();
7492 $out = 'InvalidHTMLStringCantBeCleaned';
7493 }
7494 }
7495
7496 // Clean some html entities that are useless so text is cleaner
7497 $out = preg_replace('/&(tab|newline);/i', ' ', $out);
7498
7499 // Ckeditor use the numeric entitic for apostrophe so we force it to text entity (all other special chars are
7500 // encoded using text entities) so we can then exclude all numeric entities.
7501 $out = preg_replace('/&#39;/i', '&apos;', $out);
7502
7503 // 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).
7504 // 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
7505 // using a non coventionnel way to be encoded, to not have them sanitized just after)
7506 $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) {
7507 return realCharForNumericEntities($m); }, $out);
7508
7509
7510 // Now we remove all remaining HTML entities starting with a number. We don't want such entities.
7511 $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'.
7512
7513 // Keep only some html tags and remove also some 'javascript:' strings
7514 $out = dol_string_onlythesehtmltags($out, 0, ($check == 'restricthtmlallowclass' ? 0 : 1), 1);
7515
7516 // Keep only some html attributes and exclude non expected HTML attributes and clean content of some attributes (keep only alt=, title=...).
7517 if (!empty($conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES)) {
7519 }
7520
7521 // Restore entity &apos; into &#39; (restricthtml is for html content so we can use html entity)
7522 $out = preg_replace('/&apos;/i', "&#39;", $out);
7523 } while ($oldstringtoclean != $out);
7524
7525 // Check the limit of external links that are automatically executed in a Rich text content. We count:
7526 // '<img' to avoid <img src="http...">, we can only accept "<img src="data:..."
7527 // 'url(' to avoid inline style like background: url(http...
7528 // '<link' to avoid <link href="http...">
7529 $reg = array();
7530 preg_match_all('/(<img|url\‍(|<link)/i', $out, $reg);
7531 $nbextlink = count($reg[0]);
7532 if ($nbextlink > getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) {
7533 $out = 'TooManyLinksIntoHTMLString';
7534 }
7535 //
7536 if (!empty($conf->global->MAIN_DISALLOW_EXT_URL_INTO_DESCRIPTIONS) || $check == 'restricthtmlnolink') {
7537 if ($nbextlink > 0) {
7538 $out = 'ExternalLinksNotAllowed';
7539 }
7540 }
7541
7542 return $out;
7543 }
7544}
7545
7567function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UTF-8', $removelasteolbr = 1)
7568{
7569 if (is_null($stringtoencode)) {
7570 return '';
7571 }
7572
7573 $newstring = $stringtoencode;
7574 if (dol_textishtml($stringtoencode)) { // Check if text is already HTML or not
7575 $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.
7576 if ($removelasteolbr) {
7577 $newstring = preg_replace('/<br>$/i', '', $newstring); // Remove last <br> (remove only last one)
7578 }
7579 $newstring = strtr($newstring, array('&'=>'__and__', '<'=>'__lt__', '>'=>'__gt__', '"'=>'__dquot__'));
7580 $newstring = dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom); // Make entity encoding
7581 $newstring = strtr($newstring, array('__and__'=>'&', '__lt__'=>'<', '__gt__'=>'>', '__dquot__'=>'"'));
7582 } else {
7583 if ($removelasteolbr) {
7584 $newstring = preg_replace('/(\r\n|\r|\n)$/i', '', $newstring); // Remove last \n (may remove several)
7585 }
7586 $newstring = dol_nl2br(dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom), $nl2brmode);
7587 }
7588 // Other substitutions that htmlentities does not do
7589 //$newstring=str_replace(chr(128),'&euro;',$newstring); // 128 = 0x80. Not in html entity table. // Seems useles with TCPDF. Make bug with UTF8 languages
7590 return $newstring;
7591}
7592
7600function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8')
7601{
7602 $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7603 $ret = preg_replace('/'."\r\n".'<br(\s[\sa-zA-Z_="]*)?\/?>/i', "<br>", $ret);
7604 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\r\n".'/i', "\r\n", $ret);
7605 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\n".'/i', "\n", $ret);
7606 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', "\n", $ret);
7607 return $ret;
7608}
7609
7616function dol_htmlcleanlastbr($stringtodecode)
7617{
7618 $ret = preg_replace('/&nbsp;$/i', "", $stringtodecode); // Because wysiwyg editor may add a &nbsp; at end of last line
7619 $ret = preg_replace('/(<br>|<br(\s[\sa-zA-Z_="]*)?\/?>|'."\n".'|'."\r".')+$/i', "", $ret);
7620 return $ret;
7621}
7622
7632function dol_html_entity_decode($a, $b, $c = 'UTF-8', $keepsomeentities = 0)
7633{
7634 $newstring = $a;
7635 if ($keepsomeentities) {
7636 $newstring = strtr($newstring, array('&amp;'=>'__andamp__', '&lt;'=>'__andlt__', '&gt;'=>'__andgt__', '"'=>'__dquot__'));
7637 }
7638 $newstring = html_entity_decode((string) $newstring, (int) $b, (string) $c);
7639 if ($keepsomeentities) {
7640 $newstring = strtr($newstring, array('__andamp__'=>'&amp;', '__andlt__'=>'&lt;', '__andgt__'=>'&gt;', '__dquot__'=>'"'));
7641 }
7642 return $newstring;
7643}
7644
7655function dol_htmlentities($string, $flags = ENT_QUOTES|ENT_SUBSTITUTE, $encoding = 'UTF-8', $double_encode = false)
7656{
7657 return htmlentities($string, $flags, $encoding, $double_encode);
7658}
7659
7671function dol_string_is_good_iso($s, $clean = 0)
7672{
7673 $len = dol_strlen($s);
7674 $out = '';
7675 $ok = 1;
7676 for ($scursor = 0; $scursor < $len; $scursor++) {
7677 $ordchar = ord($s[$scursor]);
7678 //print $scursor.'-'.$ordchar.'<br>';
7679 if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) {
7680 $ok = 0;
7681 break;
7682 } elseif ($ordchar > 126 && $ordchar < 160) {
7683 $ok = 0;
7684 break;
7685 } elseif ($clean) {
7686 $out .= $s[$scursor];
7687 }
7688 }
7689 if ($clean) {
7690 return $out;
7691 }
7692 return $ok;
7693}
7694
7703function dol_nboflines($s, $maxchar = 0)
7704{
7705 if ($s == '') {
7706 return 0;
7707 }
7708 $arraystring = explode("\n", $s);
7709 $nb = count($arraystring);
7710
7711 return $nb;
7712}
7713
7714
7724function dol_nboflines_bis($text, $maxlinesize = 0, $charset = 'UTF-8')
7725{
7726 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7727 if (dol_textishtml($text)) {
7728 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7729 }
7730
7731 $text = strtr($text, $repTable);
7732 if ($charset == 'UTF-8') {
7733 $pattern = '/(<br[^>]*>)/Uu';
7734 } else {
7735 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7736 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7737 }
7738 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7739
7740 $nblines = (int) floor((count($a) + 1) / 2);
7741 // count possible auto line breaks
7742 if ($maxlinesize) {
7743 foreach ($a as $line) {
7744 if (dol_strlen($line) > $maxlinesize) {
7745 //$line_dec = html_entity_decode(strip_tags($line));
7746 $line_dec = html_entity_decode($line);
7747 if (dol_strlen($line_dec) > $maxlinesize) {
7748 $line_dec = wordwrap($line_dec, $maxlinesize, '\n', true);
7749 $nblines += substr_count($line_dec, '\n');
7750 }
7751 }
7752 }
7753 }
7754
7755 unset($a);
7756 return $nblines;
7757}
7758
7767function dol_textishtml($msg, $option = 0)
7768{
7769 if (is_null($msg)) {
7770 return false;
7771 }
7772
7773 if ($option == 1) {
7774 if (preg_match('/<html/i', $msg)) {
7775 return true;
7776 } elseif (preg_match('/<body/i', $msg)) {
7777 return true;
7778 } elseif (preg_match('/<\/textarea/i', $msg)) {
7779 return true;
7780 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
7781 return true;
7782 } elseif (preg_match('/<br/i', $msg)) {
7783 return true;
7784 }
7785 return false;
7786 } else {
7787 // Remove all urls because 'http://aa?param1=abc&amp;param2=def' must not be used inside detection
7788 $msg = preg_replace('/https?:\/\/[^"\'\s]+/i', '', $msg);
7789 if (preg_match('/<html/i', $msg)) {
7790 return true;
7791 } elseif (preg_match('/<body/i', $msg)) {
7792 return true;
7793 } elseif (preg_match('/<\/textarea/i', $msg)) {
7794 return true;
7795 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
7796 return true;
7797 } elseif (preg_match('/<(br|hr)\/>/i', $msg)) {
7798 return true;
7799 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)>/i', $msg)) {
7800 return true;
7801 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)\s+[^<>\/]*\/?>/i', $msg)) {
7802 return true;
7803 } elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i', $msg)) {
7804 return true; // must accept <img src="http://example.com/aaa.png" />
7805 } elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i', $msg)) {
7806 return true; // must accept <a href="http://example.com/aaa.png" />
7807 } elseif (preg_match('/<h[0-9]>/i', $msg)) {
7808 return true;
7809 } elseif (preg_match('/&[A-Z0-9]{1,6};/i', $msg)) {
7810 // TODO If content is 'A link https://aaa?param=abc&amp;param2=def', it return true but must be false
7811 return true; // Html entities names (http://www.w3schools.com/tags/ref_entities.asp)
7812 } elseif (preg_match('/&#[0-9]{2,3};/i', $msg)) {
7813 return true; // Html entities numbers (http://www.w3schools.com/tags/ref_entities.asp)
7814 }
7815
7816 return false;
7817 }
7818}
7819
7834function dol_concatdesc($text1, $text2, $forxml = false, $invert = false)
7835{
7836 if (!empty($invert)) {
7837 $tmp = $text1;
7838 $text1 = $text2;
7839 $text2 = $tmp;
7840 }
7841
7842 $ret = '';
7843 $ret .= (!dol_textishtml($text1) && dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text1, 0, 1, '', 1), 0, $forxml) : $text1;
7844 $ret .= (!empty($text1) && !empty($text2)) ? ((dol_textishtml($text1) || dol_textishtml($text2)) ? ($forxml ? "<br >\n" : "<br>\n") : "\n") : "";
7845 $ret .= (dol_textishtml($text1) && !dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text2, 0, 1, '', 1), 0, $forxml) : $text2;
7846 return $ret;
7847}
7848
7849
7850
7862function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null)
7863{
7864 global $db, $conf, $mysoc, $user, $extrafields;
7865
7866 $substitutionarray = array();
7867
7868 if ((empty($exclude) || !in_array('user', $exclude)) && (empty($include) || in_array('user', $include))) {
7869 // Add SIGNATURE into substitutionarray first, so, when we will make the substitution,
7870 // this will include signature content first and then replace var found into content of signature
7871 //var_dump($onlykey);
7872 $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()
7873 $usersignature = $user->signature;
7874 $substitutionarray = array_merge($substitutionarray, array(
7875 '__SENDEREMAIL_SIGNATURE__' => (string) ((empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN)) ? ($onlykey == 2 ? dol_trunc('SignatureFromTheSelectedSenderProfile', 30) : $emailsendersignature) : ''),
7876 '__USER_SIGNATURE__' => (string) (($usersignature && empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN)) ? ($onlykey == 2 ? dol_trunc(dol_string_nohtmltag($usersignature), 30) : $usersignature) : '')
7877 ));
7878
7879 if (is_object($user)) {
7880 $substitutionarray = array_merge($substitutionarray, array(
7881 '__USER_ID__' => (string) $user->id,
7882 '__USER_LOGIN__' => (string) $user->login,
7883 '__USER_EMAIL__' => (string) $user->email,
7884 '__USER_PHONE__' => (string) dol_print_phone($user->office_phone, '', 0, 0, '', " ", '', '', -1),
7885 '__USER_PHONEPRO__' => (string) dol_print_phone($user->user_mobile, '', 0, 0, '', " ", '', '', -1),
7886 '__USER_PHONEMOBILE__' => (string) dol_print_phone($user->personal_mobile, '', 0, 0, '', " ", '', '', -1),
7887 '__USER_FAX__' => (string) $user->office_fax,
7888 '__USER_LASTNAME__' => (string) $user->lastname,
7889 '__USER_FIRSTNAME__' => (string) $user->firstname,
7890 '__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
7891 '__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
7892 '__USER_JOB__' => (string) $user->job,
7893 '__USER_REMOTE_IP__' => (string) getUserRemoteIP(),
7894 '__USER_VCARD_URL__' => (string) $user->getOnlineVirtualCardUrl('', 'external')
7895 ));
7896 }
7897 }
7898 if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc) && (empty($include) || in_array('mycompany', $include))) {
7899 $substitutionarray = array_merge($substitutionarray, array(
7900 '__MYCOMPANY_NAME__' => $mysoc->name,
7901 '__MYCOMPANY_EMAIL__' => $mysoc->email,
7902 '__MYCOMPANY_PHONE__' => dol_print_phone($mysoc->phone, '', 0, 0, '', " ", '', '', -1),
7903 '__MYCOMPANY_FAX__' => dol_print_phone($mysoc->fax, '', 0, 0, '', " ", '', '', -1),
7904 '__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
7905 '__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
7906 '__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
7907 '__MYCOMPANY_PROFID4__' => $mysoc->idprof4,
7908 '__MYCOMPANY_PROFID5__' => $mysoc->idprof5,
7909 '__MYCOMPANY_PROFID6__' => $mysoc->idprof6,
7910 '__MYCOMPANY_CAPITAL__' => $mysoc->capital,
7911 '__MYCOMPANY_FULLADDRESS__' => (method_exists($mysoc, 'getFullAddress') ? $mysoc->getFullAddress(1, ', ') : ''), // $mysoc may be stdClass
7912 '__MYCOMPANY_ADDRESS__' => $mysoc->address,
7913 '__MYCOMPANY_ZIP__' => $mysoc->zip,
7914 '__MYCOMPANY_TOWN__' => $mysoc->town,
7915 '__MYCOMPANY_COUNTRY__' => $mysoc->country,
7916 '__MYCOMPANY_COUNTRY_ID__' => $mysoc->country_id,
7917 '__MYCOMPANY_COUNTRY_CODE__' => $mysoc->country_code,
7918 '__MYCOMPANY_CURRENCY_CODE__' => $conf->currency
7919 ));
7920 }
7921
7922 if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude)) && (empty($include) || in_array('object', $include))) {
7923 if ($onlykey) {
7924 $substitutionarray['__ID__'] = '__ID__';
7925 $substitutionarray['__REF__'] = '__REF__';
7926 $substitutionarray['__NEWREF__'] = '__NEWREF__';
7927 $substitutionarray['__LABEL__'] = '__LABEL__';
7928 $substitutionarray['__REF_CLIENT__'] = '__REF_CLIENT__';
7929 $substitutionarray['__REF_SUPPLIER__'] = '__REF_SUPPLIER__';
7930 $substitutionarray['__NOTE_PUBLIC__'] = '__NOTE_PUBLIC__';
7931 $substitutionarray['__NOTE_PRIVATE__'] = '__NOTE_PRIVATE__';
7932 $substitutionarray['__EXTRAFIELD_XXX__'] = '__EXTRAFIELD_XXX__';
7933
7934 if (isModEnabled("societe")) { // Most objects are concerned
7935 $substitutionarray['__THIRDPARTY_ID__'] = '__THIRDPARTY_ID__';
7936 $substitutionarray['__THIRDPARTY_NAME__'] = '__THIRDPARTY_NAME__';
7937 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = '__THIRDPARTY_NAME_ALIAS__';
7938 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = '__THIRDPARTY_CODE_CLIENT__';
7939 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = '__THIRDPARTY_CODE_FOURNISSEUR__';
7940 $substitutionarray['__THIRDPARTY_EMAIL__'] = '__THIRDPARTY_EMAIL__';
7941 $substitutionarray['__THIRDPARTY_PHONE__'] = '__THIRDPARTY_PHONE__';
7942 $substitutionarray['__THIRDPARTY_FAX__'] = '__THIRDPARTY_FAX__';
7943 $substitutionarray['__THIRDPARTY_ADDRESS__'] = '__THIRDPARTY_ADDRESS__';
7944 $substitutionarray['__THIRDPARTY_ZIP__'] = '__THIRDPARTY_ZIP__';
7945 $substitutionarray['__THIRDPARTY_TOWN__'] = '__THIRDPARTY_TOWN__';
7946 $substitutionarray['__THIRDPARTY_IDPROF1__'] = '__THIRDPARTY_IDPROF1__';
7947 $substitutionarray['__THIRDPARTY_IDPROF2__'] = '__THIRDPARTY_IDPROF2__';
7948 $substitutionarray['__THIRDPARTY_IDPROF3__'] = '__THIRDPARTY_IDPROF3__';
7949 $substitutionarray['__THIRDPARTY_IDPROF4__'] = '__THIRDPARTY_IDPROF4__';
7950 $substitutionarray['__THIRDPARTY_IDPROF5__'] = '__THIRDPARTY_IDPROF5__';
7951 $substitutionarray['__THIRDPARTY_IDPROF6__'] = '__THIRDPARTY_IDPROF6__';
7952 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = '__THIRDPARTY_TVAINTRA__';
7953 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = '__THIRDPARTY_NOTE_PUBLIC__';
7954 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = '__THIRDPARTY_NOTE_PRIVATE__';
7955 }
7956 if (isModEnabled('adherent') && (!is_object($object) || $object->element == 'adherent') && (empty($exclude) || !in_array('member', $exclude)) && (empty($include) || in_array('member', $include))) {
7957 $substitutionarray['__MEMBER_ID__'] = '__MEMBER_ID__';
7958 $substitutionarray['__MEMBER_CIVILITY__'] = '__MEMBER_CIVILITY__';
7959 $substitutionarray['__MEMBER_FIRSTNAME__'] = '__MEMBER_FIRSTNAME__';
7960 $substitutionarray['__MEMBER_LASTNAME__'] = '__MEMBER_LASTNAME__';
7961 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = 'Login and pass of the external user account';
7962 /*$substitutionarray['__MEMBER_NOTE_PUBLIC__'] = '__MEMBER_NOTE_PUBLIC__';
7963 $substitutionarray['__MEMBER_NOTE_PRIVATE__'] = '__MEMBER_NOTE_PRIVATE__';*/
7964 }
7965 // add variables subtitutions ticket
7966 if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket') && (empty($exclude) || !in_array('ticket', $exclude)) && (empty($include) || in_array('ticket', $include))) {
7967 $substitutionarray['__TICKET_TRACKID__'] = '__TICKET_TRACKID__';
7968 $substitutionarray['__TICKET_SUBJECT__'] = '__TICKET_SUBJECT__';
7969 $substitutionarray['__TICKET_TYPE__'] = '__TICKET_TYPE__';
7970 $substitutionarray['__TICKET_SEVERITY__'] = '__TICKET_SEVERITY__';
7971 $substitutionarray['__TICKET_CATEGORY__'] = '__TICKET_CATEGORY__';
7972 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = '__TICKET_ANALYTIC_CODE__';
7973 $substitutionarray['__TICKET_MESSAGE__'] = '__TICKET_MESSAGE__';
7974 $substitutionarray['__TICKET_PROGRESSION__'] = '__TICKET_PROGRESSION__';
7975 $substitutionarray['__TICKET_USER_ASSIGN__'] = '__TICKET_USER_ASSIGN__';
7976 }
7977
7978 if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature') && (empty($exclude) || !in_array('recruitment', $exclude)) && (empty($include) || in_array('recruitment', $include))) {
7979 $substitutionarray['__CANDIDATE_FULLNAME__'] = '__CANDIDATE_FULLNAME__';
7980 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = '__CANDIDATE_FIRSTNAME__';
7981 $substitutionarray['__CANDIDATE_LASTNAME__'] = '__CANDIDATE_LASTNAME__';
7982 }
7983 if (isModEnabled('project') && (empty($exclude) || !in_array('project', $exclude)) && (empty($include) || in_array('project', $include))) { // Most objects
7984 $substitutionarray['__PROJECT_ID__'] = '__PROJECT_ID__';
7985 $substitutionarray['__PROJECT_REF__'] = '__PROJECT_REF__';
7986 $substitutionarray['__PROJECT_NAME__'] = '__PROJECT_NAME__';
7987 /*$substitutionarray['__PROJECT_NOTE_PUBLIC__'] = '__PROJECT_NOTE_PUBLIC__';
7988 $substitutionarray['__PROJECT_NOTE_PRIVATE__'] = '__PROJECT_NOTE_PRIVATE__';*/
7989 }
7990 if (isModEnabled('contrat') && (!is_object($object) || $object->element == 'contract') && (empty($exclude) || !in_array('contract', $exclude)) && (empty($include) || in_array('contract', $include))) {
7991 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = 'Highest date planned for a service start';
7992 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = 'Highest date and hour planned for service start';
7993 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = 'Lowest data for planned expiration of service';
7994 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = 'Lowest date and hour for planned expiration of service';
7995 }
7996 if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal') && (empty($exclude) || !in_array('propal', $exclude)) && (empty($include) || in_array('propal', $include))) {
7997 $substitutionarray['__ONLINE_SIGN_URL__'] = 'ToOfferALinkForOnlineSignature';
7998 }
7999 if (isModEnabled("ficheinter") && (!is_object($object) || $object->element == 'fichinter') && (empty($exclude) || !in_array('intervention', $exclude)) && (empty($include) || in_array('intervention', $include))) {
8000 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = 'ToOfferALinkForOnlineSignature';
8001 }
8002 $substitutionarray['__ONLINE_PAYMENT_URL__'] = 'UrlToPayOnlineIfApplicable';
8003 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = 'TextAndUrlToPayOnlineIfApplicable';
8004 $substitutionarray['__SECUREKEYPAYMENT__'] = 'Security key (if key is not unique per record)';
8005 $substitutionarray['__SECUREKEYPAYMENT_MEMBER__'] = 'Security key for payment on a member subscription (one key per member)';
8006 $substitutionarray['__SECUREKEYPAYMENT_ORDER__'] = 'Security key for payment on an order';
8007 $substitutionarray['__SECUREKEYPAYMENT_INVOICE__'] = 'Security key for payment on an invoice';
8008 $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'Security key for payment on a service of a contract';
8009
8010 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = 'Direct download url of a proposal';
8011 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = 'Direct download url of an order';
8012 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = 'Direct download url of an invoice';
8013 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = 'Direct download url of a contract';
8014 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = 'Direct download url of a supplier proposal';
8015
8016 if (isModEnabled("expedition") && (!is_object($object) || $object->element == 'shipping')) {
8017 $substitutionarray['__SHIPPINGTRACKNUM__'] = 'Shipping tracking number';
8018 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = 'Shipping tracking url';
8019 }
8020 if (isModEnabled("reception") && (!is_object($object) || $object->element == 'reception')) {
8021 $substitutionarray['__RECEPTIONTRACKNUM__'] = 'Shippin tracking number of shipment';
8022 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = 'Shipping tracking url';
8023 }
8024 } else {
8025 $substitutionarray['__ID__'] = $object->id;
8026 $substitutionarray['__REF__'] = $object->ref;
8027 $substitutionarray['__NEWREF__'] = $object->newref;
8028 $substitutionarray['__LABEL__'] = (isset($object->label) ? $object->label : (isset($object->title) ? $object->title : null));
8029 $substitutionarray['__REF_CLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8030 $substitutionarray['__REF_SUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8031 $substitutionarray['__NOTE_PUBLIC__'] = (isset($object->note_public) ? $object->note_public : null);
8032 $substitutionarray['__NOTE_PRIVATE__'] = (isset($object->note_private) ? $object->note_private : null);
8033 if ($object->element == "shipping") {
8034 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, 'day', 0, $outputlangs) : '');
8035 } else {
8036 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, 'day', 0, $outputlangs) : '');
8037 }
8038 $substitutionarray['__DATE_DELIVERY_DAY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%d") : '');
8039 $substitutionarray['__DATE_DELIVERY_DAY_TEXT__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%A") : '');
8040 $substitutionarray['__DATE_DELIVERY_MON__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%m") : '');
8041 $substitutionarray['__DATE_DELIVERY_MON_TEXT__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%b") : '');
8042 $substitutionarray['__DATE_DELIVERY_YEAR__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%Y") : '');
8043 $substitutionarray['__DATE_DELIVERY_HH__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%H") : '');
8044 $substitutionarray['__DATE_DELIVERY_MM__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%M") : '');
8045 $substitutionarray['__DATE_DELIVERY_SS__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%S") : '');
8046
8047 // For backward compatibility (deprecated)
8048 $substitutionarray['__REFCLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8049 $substitutionarray['__REFSUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8050 $substitutionarray['__SUPPLIER_ORDER_DATE_DELIVERY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, 'day', 0, $outputlangs) : '');
8051 $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 : '')) : '');
8052
8053 if (is_object($object) && ($object->element == 'adherent' || $object->element == 'member') && $object->id > 0) {
8054 $birthday = (empty($object->birth) ? '' : dol_print_date($object->birth, 'day'));
8055
8056 $substitutionarray['__MEMBER_ID__'] = (isset($object->id) ? $object->id : '');
8057 if (method_exists($object, 'getCivilityLabel')) {
8058 $substitutionarray['__MEMBER_CIVILITY__'] = $object->getCivilityLabel();
8059 }
8060 $substitutionarray['__MEMBER_FIRSTNAME__'] = (isset($object->firstname) ? $object->firstname : '');
8061 $substitutionarray['__MEMBER_LASTNAME__'] = (isset($object->lastname) ? $object->lastname : '');
8062 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = '';
8063 if (method_exists($object, 'getFullName')) {
8064 $substitutionarray['__MEMBER_FULLNAME__'] = $object->getFullName($outputlangs);
8065 }
8066 $substitutionarray['__MEMBER_COMPANY__'] = (isset($object->societe) ? $object->societe : '');
8067 $substitutionarray['__MEMBER_ADDRESS__'] = (isset($object->address) ? $object->address : '');
8068 $substitutionarray['__MEMBER_ZIP__'] = (isset($object->zip) ? $object->zip : '');
8069 $substitutionarray['__MEMBER_TOWN__'] = (isset($object->town) ? $object->town : '');
8070 $substitutionarray['__MEMBER_COUNTRY__'] = (isset($object->country) ? $object->country : '');
8071 $substitutionarray['__MEMBER_EMAIL__'] = (isset($object->email) ? $object->email : '');
8072 $substitutionarray['__MEMBER_BIRTH__'] = (isset($birthday) ? $birthday : '');
8073 $substitutionarray['__MEMBER_PHOTO__'] = (isset($object->photo) ? $object->photo : '');
8074 $substitutionarray['__MEMBER_LOGIN__'] = (isset($object->login) ? $object->login : '');
8075 $substitutionarray['__MEMBER_PASSWORD__'] = (isset($object->pass) ? $object->pass : '');
8076 $substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? dol_print_phone($object->phone) : '');
8077 $substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? dol_print_phone($object->phone_perso) : '');
8078 $substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? dol_print_phone($object->phone_mobile) : '');
8079 $substitutionarray['__MEMBER_TYPE__'] = (isset($object->type) ? $object->type : '');
8080 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__'] = dol_print_date($object->first_subscription_date, 'day');
8081 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = (isset($object->first_subscription_date_start) ? dol_print_date($object->first_subscription_date_start, 'day') : '');
8082 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END__'] = (isset($object->first_subscription_date_end) ? dol_print_date($object->first_subscription_date_end, 'day') : '');
8083 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE__'] = dol_print_date($object->last_subscription_date, 'day');
8084 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->last_subscription_date_start, 'day');
8085 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END__'] = dol_print_date($object->last_subscription_date_end, 'day');
8086 }
8087
8088 if (is_object($object) && $object->element == 'societe') {
8089 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object) ? $object->id : '');
8090 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object) ? $object->name : '');
8091 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object) ? $object->name_alias : '');
8092 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object) ? $object->code_client : '');
8093 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object) ? $object->code_fournisseur : '');
8094 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object) ? $object->email : '');
8095 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? dol_print_phone($object->phone) : '');
8096 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? dol_print_phone($object->fax) : '');
8097 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object) ? $object->address : '');
8098 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object) ? $object->zip : '');
8099 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object) ? $object->town : '');
8100 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object) ? $object->country_id : '');
8101 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object) ? $object->country_code : '');
8102 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object) ? $object->idprof1 : '');
8103 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object) ? $object->idprof2 : '');
8104 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object) ? $object->idprof3 : '');
8105 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object) ? $object->idprof4 : '');
8106 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object) ? $object->idprof5 : '');
8107 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object) ? $object->idprof6 : '');
8108 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object) ? $object->tva_intra : '');
8109 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_public) : '');
8110 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_private) : '');
8111 } elseif (is_object($object->thirdparty)) {
8112 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->id : '');
8113 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object->thirdparty) ? $object->thirdparty->name : '');
8114 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object->thirdparty) ? $object->thirdparty->name_alias : '');
8115 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_client : '');
8116 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_fournisseur : '');
8117 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object->thirdparty) ? $object->thirdparty->email : '');
8118 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->phone) : '');
8119 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->fax) : '');
8120 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object->thirdparty) ? $object->thirdparty->address : '');
8121 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object->thirdparty) ? $object->thirdparty->zip : '');
8122 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object->thirdparty) ? $object->thirdparty->town : '');
8123 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_id : '');
8124 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_code : '');
8125 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof1 : '');
8126 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof2 : '');
8127 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof3 : '');
8128 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof4 : '');
8129 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof5 : '');
8130 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof6 : '');
8131 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object->thirdparty) ? $object->thirdparty->tva_intra : '');
8132 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_public) : '');
8133 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_private) : '');
8134 }
8135
8136 if (is_object($object) && $object->element == 'recruitmentcandidature') {
8137 $substitutionarray['__CANDIDATE_FULLNAME__'] = $object->getFullName($outputlangs);
8138 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8139 $substitutionarray['__CANDIDATE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8140 }
8141 if (is_object($object) && $object->element == 'conferenceorboothattendee') {
8142 $substitutionarray['__ATTENDEE_FULLNAME__'] = $object->getFullName($outputlangs);
8143 $substitutionarray['__ATTENDEE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8144 $substitutionarray['__ATTENDEE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8145 }
8146
8147 $project = null;
8148 if (is_object($object->project)) {
8149 $project = $object->project;
8150 } elseif (is_object($object->projet)) { // Deprecated, for backward compatibility
8151 $project = $object->projet;
8152 }
8153 if ($project) {
8154 $substitutionarray['__PROJECT_ID__'] = $project->id;
8155 $substitutionarray['__PROJECT_REF__'] = $project->ref;
8156 $substitutionarray['__PROJECT_NAME__'] = $project->title;
8157 }
8158 if (is_object($object) && $object->element == 'project') {
8159 $substitutionarray['__PROJECT_NAME__'] = $object->title;
8160 }
8161
8162 if (is_object($object) && $object->element == 'shipping') {
8163 $substitutionarray['__SHIPPINGTRACKNUM__'] = $object->tracking_number;
8164 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = $object->tracking_url;
8165 }
8166 if (is_object($object) && $object->element == 'reception') {
8167 $substitutionarray['__RECEPTIONTRACKNUM__'] = $object->tracking_number;
8168 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = $object->tracking_url;
8169 }
8170
8171 if (is_object($object) && $object->element == 'contrat' && $object->id > 0 && is_array($object->lines)) {
8172 $dateplannedstart = '';
8173 $datenextexpiration = '';
8174 foreach ($object->lines as $line) {
8175 if ($line->date_start > $dateplannedstart) {
8176 $dateplannedstart = $line->date_start;
8177 }
8178 if ($line->statut == 4 && $line->date_end && (!$datenextexpiration || $line->date_end < $datenextexpiration)) {
8179 $datenextexpiration = $line->date_end;
8180 }
8181 }
8182 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = dol_print_date($dateplannedstart, 'day');
8183 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = dol_print_date($dateplannedstart, 'standard');
8184 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = dol_print_date($datenextexpiration, 'day');
8185 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = dol_print_date($datenextexpiration, 'standard');
8186 }
8187 // add substition variable for ticket
8188 if (is_object($object) && $object->element == 'ticket') {
8189 $substitutionarray['__TICKET_TRACKID__'] = $object->track_id;
8190 $substitutionarray['__REF__'] = $object->ref;
8191 $substitutionarray['__TICKET_SUBJECT__'] = $object->subject;
8192 $substitutionarray['__TICKET_TYPE__'] = $object->type_code;
8193 $substitutionarray['__TICKET_SEVERITY__'] = $object->severity_code;
8194 $substitutionarray['__TICKET_CATEGORY__'] = $object->category_code; // For backward compatibility
8195 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = $object->category_code;
8196 $substitutionarray['__TICKET_MESSAGE__'] = $object->message;
8197 $substitutionarray['__TICKET_PROGRESSION__'] = $object->progress;
8198 $userstat = new User($db);
8199 if ($object->fk_user_assign > 0) {
8200 $userstat->fetch($object->fk_user_assign);
8201 $substitutionarray['__TICKET_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8202 }
8203
8204 if ($object->fk_user_create > 0) {
8205 $userstat->fetch($object->fk_user_create);
8206 $substitutionarray['__USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8207 }
8208 }
8209
8210 // Create dynamic tags for __EXTRAFIELD_FIELD__
8211 if ($object->table_element && $object->id > 0) {
8212 if (!is_object($extrafields)) {
8213 $extrafields = new ExtraFields($db);
8214 }
8215 $extrafields->fetch_name_optionals_label($object->table_element, true);
8216
8217 if ($object->fetch_optionals() > 0) {
8218 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) {
8219 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
8220 if ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
8221 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_date($object->array_options['options_'.$key], 'day');
8222 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = dol_print_date($object->array_options['options_'.$key], 'day', 'tzserver', $outputlangs);
8223 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = dol_print_date($object->array_options['options_'.$key], 'dayrfc');
8224 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'datetime') {
8225 $datetime = $object->array_options['options_'.$key];
8226 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour') : '');
8227 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : '');
8228 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_DAY_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'day', 'tzserver', $outputlangs) : '');
8229 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : '');
8230 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'phone') {
8231 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_phone($object->array_options['options_'.$key]);
8232 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
8233 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = $object->array_options['options_'.$key];
8234 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATED__'] = price($object->array_options['options_'.$key]);
8235 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] != 'separator') {
8236 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = !empty($object->array_options['options_'.$key]) ? $object->array_options['options_'.$key] :'';
8237 }
8238 }
8239 }
8240 }
8241 }
8242
8243 // Complete substitution array with the url to make online payment
8244 $paymenturl = '';
8245 if (empty($substitutionarray['__REF__'])) {
8246 $paymenturl = '';
8247 } else {
8248 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
8249 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
8250 $outputlangs->loadLangs(array('paypal', 'other'));
8251
8252 $amounttouse = 0;
8253 $typeforonlinepayment = 'free';
8254 if (is_object($object) && $object->element == 'commande') {
8255 $typeforonlinepayment = 'order';
8256 }
8257 if (is_object($object) && $object->element == 'facture') {
8258 $typeforonlinepayment = 'invoice';
8259 }
8260 if (is_object($object) && $object->element == 'member') {
8261 $typeforonlinepayment = 'member';
8262 if (!empty($object->last_subscription_amount)) {
8263 $amounttouse = $object->last_subscription_amount;
8264 }
8265 }
8266 if (is_object($object) && $object->element == 'contrat') {
8267 $typeforonlinepayment = 'contract';
8268 }
8269 if (is_object($object) && $object->element == 'fichinter') {
8270 $typeforonlinepayment = 'ficheinter';
8271 }
8272
8273 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__'], $amounttouse);
8274 $paymenturl = $url;
8275 }
8276
8277 if ($object->id > 0) {
8278 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ?str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : '');
8279 $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl;
8280
8281 if (!empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'propal') {
8282 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8283 } else {
8284 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = '';
8285 }
8286 if (!empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'commande') {
8287 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = $object->getLastMainDocLink($object->element);
8288 } else {
8289 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = '';
8290 }
8291 if (!empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'facture') {
8292 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = $object->getLastMainDocLink($object->element);
8293 } else {
8294 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = '';
8295 }
8296 if (!empty($conf->global->CONTRACT_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'contrat') {
8297 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = $object->getLastMainDocLink($object->element);
8298 } else {
8299 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = '';
8300 }
8301 if (!empty($conf->global->FICHINTER_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'fichinter') {
8302 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = $object->getLastMainDocLink($object->element);
8303 } else {
8304 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = '';
8305 }
8306 if (!empty($conf->global->SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'supplier_proposal') {
8307 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8308 } else {
8309 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = '';
8310 }
8311
8312 if (is_object($object) && $object->element == 'propal') {
8313 $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id;
8314 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8315 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref, 1, $object);
8316 }
8317 if (is_object($object) && $object->element == 'commande') {
8318 $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id;
8319 }
8320 if (is_object($object) && $object->element == 'facture') {
8321 $substitutionarray['__URL_INVOICE__'] = DOL_MAIN_URL_ROOT."/compta/facture/card.php?id=".$object->id;
8322 }
8323 if (is_object($object) && $object->element == 'contrat') {
8324 $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id;
8325 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8326 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref, 1, $object);
8327 }
8328 if (is_object($object) && $object->element == 'fichinter') {
8329 $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id;
8330 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8331 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref, 1, $object);
8332 }
8333 if (is_object($object) && $object->element == 'supplier_proposal') {
8334 $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id;
8335 }
8336 if (is_object($object) && $object->element == 'shipping') {
8337 $substitutionarray['__URL_SHIPMENT__'] = DOL_MAIN_URL_ROOT."/expedition/card.php?id=".$object->id;
8338 }
8339 }
8340
8341 if (is_object($object) && $object->element == 'action') {
8342 $substitutionarray['__EVENT_LABEL__'] = $object->label;
8343 $substitutionarray['__EVENT_DATE__'] = dol_print_date($object->datep, '%A %d %b %Y');
8344 $substitutionarray['__EVENT_TIME__'] = dol_print_date($object->datep, '%H:%M:%S');
8345 }
8346 }
8347 }
8348 if ((empty($exclude) || !in_array('objectamount', $exclude)) && (empty($include) || in_array('objectamount', $include))) {
8349 include_once DOL_DOCUMENT_ROOT.'/core/lib/functionsnumtoword.lib.php';
8350
8351 $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : '';
8352 $substitutionarray['__DATE_DUE_YMD__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs) : null) : '';
8353
8354 $already_payed_all = 0;
8355 if (is_object($object) && ($object instanceof Facture)) {
8356 $already_payed_all = $object->sumpayed + $object->sumdeposit + $object->sumcreditnote;
8357 }
8358
8359 $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : '';
8360
8361 $substitutionarray['__AMOUNT__'] = is_object($object) ? $object->total_ttc : '';
8362 $substitutionarray['__AMOUNT_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, '', true) : '';
8363 $substitutionarray['__AMOUNT_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, $conf->currency, true) : '';
8364
8365 $substitutionarray['__AMOUNT_REMAIN__'] = is_object($object) ? price2num($object->total_ttc - $already_payed_all, 'MT') : '';
8366
8367 $substitutionarray['__AMOUNT_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8368 $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)) : '';
8369 $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)) : '';
8370
8371 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8372 $substitutionarray['__AMOUNT_TAX2__'] = is_object($object) ? $object->total_localtax1 : '';
8373 }
8374 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8375 $substitutionarray['__AMOUNT_TAX3__'] = is_object($object) ? $object->total_localtax2 : '';
8376 }
8377
8378 // Amount keys formated in a currency
8379 $substitutionarray['__AMOUNT_EXCL_TAX_FORMATED__'] = is_object($object) ? ($object->total_ht ? price($object->total_ht, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8380 $substitutionarray['__AMOUNT_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8381 $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) : '';
8382 $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)) : '';
8383 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8384 $substitutionarray['__AMOUNT_TAX2_FORMATED__'] = is_object($object) ? ($object->total_localtax1 ? price($object->total_localtax1, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8385 }
8386 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8387 $substitutionarray['__AMOUNT_TAX3_FORMATED__'] = is_object($object) ? ($object->total_localtax2 ? price($object->total_localtax2, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8388 }
8389
8390 $substitutionarray['__AMOUNT_MULTICURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? $object->multicurrency_total_ttc : '';
8391 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXT__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, '', true) : '';
8392 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXTCURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, $object->multicurrency_code, true) : '';
8393 // TODO Add other keys for foreign multicurrency
8394
8395 // For backward compatibility
8396 if ($onlykey != 2) {
8397 $substitutionarray['__TOTAL_TTC__'] = is_object($object) ? $object->total_ttc : '';
8398 $substitutionarray['__TOTAL_HT__'] = is_object($object) ? $object->total_ht : '';
8399 $substitutionarray['__TOTAL_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8400 }
8401 }
8402
8403 //var_dump($substitutionarray['__AMOUNT_FORMATED__']);
8404 if ((empty($exclude) || !in_array('date', $exclude)) && (empty($include) || in_array('date', $include))) {
8405 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
8406
8407 $now = dol_now();
8408
8409 $tmp = dol_getdate($now, true);
8410 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8411 $tmp3 = dol_get_prev_month($tmp['mon'], $tmp['year']);
8412 $tmp4 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8413 $tmp5 = dol_get_next_month($tmp['mon'], $tmp['year']);
8414
8415 $daytext = $outputlangs->trans('Day'.$tmp['wday']);
8416
8417 $substitutionarray = array_merge($substitutionarray, array(
8418 '__NOW_TMS__' => (int) $now,
8419 '__NOW_TMS_YMD__' => dol_print_date($now, 'day', 0, $outputlangs),
8420 '__DAY__' => (string) $tmp['mday'],
8421 '__DAY_TEXT__' => $daytext, // Monday
8422 '__DAY_TEXT_SHORT__' => dol_trunc($daytext, 3, 'right', 'UTF-8', 1), // Mon
8423 '__DAY_TEXT_MIN__' => dol_trunc($daytext, 1, 'right', 'UTF-8', 1), // M
8424 '__MONTH__' => (string) $tmp['mon'],
8425 '__MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp['mon'])),
8426 '__MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp['mon'])),
8427 '__MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp['mon'])),
8428 '__YEAR__' => (string) $tmp['year'],
8429 '__PREVIOUS_DAY__' => (string) $tmp2['day'],
8430 '__PREVIOUS_MONTH__' => (string) $tmp3['month'],
8431 '__PREVIOUS_YEAR__' => (string) ($tmp['year'] - 1),
8432 '__NEXT_DAY__' => (string) $tmp4['day'],
8433 '__NEXT_MONTH__' => (string) $tmp5['month'],
8434 '__NEXT_YEAR__' => (string) ($tmp['year'] + 1),
8435 ));
8436 }
8437
8438 if (isModEnabled('multicompany')) {
8439 $substitutionarray = array_merge($substitutionarray, array('__ENTITY_ID__' => $conf->entity));
8440 }
8441 if ((empty($exclude) || !in_array('system', $exclude)) && (empty($include) || in_array('user', $include))) {
8442 $substitutionarray['__DOL_MAIN_URL_ROOT__'] = DOL_MAIN_URL_ROOT;
8443 $substitutionarray['__(AnyTranslationKey)__'] = $outputlangs->trans('TranslationOfKey');
8444 $substitutionarray['__(AnyTranslationKey|langfile)__'] = $outputlangs->trans('TranslationOfKey').' (load also language file before)';
8445 $substitutionarray['__[AnyConstantKey]__'] = $outputlangs->trans('ValueOfConstantKey');
8446 }
8447
8448 return $substitutionarray;
8449}
8450
8467function make_substitutions($text, $substitutionarray, $outputlangs = null, $converttextinhtmlifnecessary = 0)
8468{
8469 global $conf, $langs;
8470
8471 if (!is_array($substitutionarray)) {
8472 return 'ErrorBadParameterSubstitutionArrayWhenCalling_make_substitutions';
8473 }
8474
8475 if (empty($outputlangs)) {
8476 $outputlangs = $langs;
8477 }
8478
8479 // Is initial text HTML or simple text ?
8480 $msgishtml = 0;
8481 if (dol_textishtml($text, 1)) {
8482 $msgishtml = 1;
8483 }
8484
8485 // Make substitution for language keys: __(AnyTranslationKey)__ or __(AnyTranslationKey|langfile)__
8486 if (is_object($outputlangs)) {
8487 $reg = array();
8488 while (preg_match('/__\‍(([^\‍)]+)\‍)__/', $text, $reg)) {
8489 // If key is __(TranslationKey|langfile)__, then force load of langfile.lang
8490 $tmp = explode('|', $reg[1]);
8491 if (!empty($tmp[1])) {
8492 $outputlangs->load($tmp[1]);
8493 }
8494
8495 $value = $outputlangs->transnoentitiesnoconv($reg[1]);
8496
8497 if (empty($converttextinhtmlifnecessary)) {
8498 // convert $newval into HTML is necessary
8499 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8500 } else {
8501 if (! $msgishtml) {
8502 $valueishtml = dol_textishtml($value, 1);
8503 //var_dump("valueishtml=".$valueishtml);
8504
8505 if ($valueishtml) {
8506 $text = dol_htmlentitiesbr($text);
8507 $msgishtml = 1;
8508 }
8509 } else {
8510 $value = dol_nl2br("$value");
8511 }
8512
8513 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $value, $text);
8514 }
8515 }
8516 }
8517
8518 // Make substitution for constant keys.
8519 // Must be after the substitution of translation, so if the text of translation contains a string __[xxx]__, it is also converted.
8520 $reg = array();
8521 while (preg_match('/__\[([^\]]+)\]__/', $text, $reg)) {
8522 $keyfound = $reg[1];
8523 if (isASecretKey($keyfound)) {
8524 $value = '*****forbidden*****';
8525 } else {
8526 $value = empty($conf->global->$keyfound) ? '' : $conf->global->$keyfound;
8527 }
8528
8529 if (empty($converttextinhtmlifnecessary)) {
8530 // convert $newval into HTML is necessary
8531 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8532 } else {
8533 if (! $msgishtml) {
8534 $valueishtml = dol_textishtml($value, 1);
8535
8536 if ($valueishtml) {
8537 $text = dol_htmlentitiesbr($text);
8538 $msgishtml = 1;
8539 }
8540 } else {
8541 $value = dol_nl2br("$value");
8542 }
8543
8544 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $value, $text);
8545 }
8546 }
8547
8548 // Make substitution for array $substitutionarray
8549 foreach ($substitutionarray as $key => $value) {
8550 if (!isset($value)) {
8551 continue; // If value is null, it same than not having substitution key at all into array, we do not replace.
8552 }
8553
8554 if (($key == '__USER_SIGNATURE__' || $key == '__SENDEREMAIL_SIGNATURE__') && (!empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN))) {
8555 $value = ''; // Protection
8556 }
8557
8558 if (empty($converttextinhtmlifnecessary)) {
8559 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8560 } else {
8561 if (! $msgishtml) {
8562 $valueishtml = dol_textishtml($value, 1);
8563
8564 if ($valueishtml) {
8565 $text = dol_htmlentitiesbr($text);
8566 $msgishtml = 1;
8567 }
8568 } else {
8569 $value = dol_nl2br("$value");
8570 }
8571 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8572 }
8573 }
8574
8575 return $text;
8576}
8577
8590function complete_substitutions_array(&$substitutionarray, $outputlangs, $object = null, $parameters = null, $callfunc = "completesubstitutionarray")
8591{
8592 global $conf, $user;
8593
8594 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
8595
8596 // Note: substitution key for each extrafields, using key __EXTRA_XXX__ is already available into the getCommonSubstitutionArray used to build the substitution array.
8597
8598 // Check if there is external substitution to do, requested by plugins
8599 $dirsubstitutions = array_merge(array(), (array) $conf->modules_parts['substitutions']);
8600
8601 foreach ($dirsubstitutions as $reldir) {
8602 $dir = dol_buildpath($reldir, 0);
8603
8604 // Check if directory exists
8605 if (!dol_is_dir($dir)) {
8606 continue;
8607 }
8608
8609 $substitfiles = dol_dir_list($dir, 'files', 0, 'functions_');
8610 foreach ($substitfiles as $substitfile) {
8611 $reg = array();
8612 if (preg_match('/functions_(.*)\.lib\.php/i', $substitfile['name'], $reg)) {
8613 $module = $reg[1];
8614
8615 dol_syslog("Library ".$substitfile['name']." found into ".$dir);
8616 // Include the user's functions file
8617 require_once $dir.$substitfile['name'];
8618 // Call the user's function, and only if it is defined
8619 $function_name = $module."_".$callfunc;
8620 if (function_exists($function_name)) {
8621 $function_name($substitutionarray, $outputlangs, $object, $parameters);
8622 }
8623 }
8624 }
8625 }
8626 if (!empty($conf->global->ODT_ENABLE_ALL_TAGS_IN_SUBSTITUTIONS)) {
8627 // to list all tags in odt template
8628 $tags = '';
8629 foreach ($substitutionarray as $key => $value) {
8630 $tags .= '{'.$key.'} => '.$value."\n";
8631 }
8632 $substitutionarray = array_merge($substitutionarray, array('__ALL_TAGS__' => $tags));
8633 }
8634}
8635
8645function print_date_range($date_start, $date_end, $format = '', $outputlangs = '')
8646{
8647 print get_date_range($date_start, $date_end, $format, $outputlangs);
8648}
8649
8660function get_date_range($date_start, $date_end, $format = '', $outputlangs = '', $withparenthesis = 1)
8661{
8662 global $langs;
8663
8664 $out = '';
8665
8666 if (!is_object($outputlangs)) {
8667 $outputlangs = $langs;
8668 }
8669
8670 if ($date_start && $date_end) {
8671 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFromTo', dol_print_date($date_start, $format, false, $outputlangs), dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8672 }
8673 if ($date_start && !$date_end) {
8674 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($date_start, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8675 }
8676 if (!$date_start && $date_end) {
8677 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8678 }
8679
8680 return $out;
8681}
8682
8691function dolGetFirstLastname($firstname, $lastname, $nameorder = -1)
8692{
8693 global $conf;
8694
8695 $ret = '';
8696 // If order not defined, we use the setup
8697 if ($nameorder < 0) {
8698 $nameorder = (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION) ? 1 : 0);
8699 }
8700 if ($nameorder == 1) {
8701 $ret .= $firstname;
8702 if ($firstname && $lastname) {
8703 $ret .= ' ';
8704 }
8705 $ret .= $lastname;
8706 } elseif ($nameorder == 2 || $nameorder == 3) {
8707 $ret .= $firstname;
8708 if (empty($ret) && $nameorder == 3) {
8709 $ret .= $lastname;
8710 }
8711 } else { // 0, 4 or 5
8712 $ret .= $lastname;
8713 if (empty($ret) && $nameorder == 5) {
8714 $ret .= $firstname;
8715 }
8716 if ($nameorder == 0) {
8717 if ($firstname && $lastname) {
8718 $ret .= ' ';
8719 }
8720 $ret .= $firstname;
8721 }
8722 }
8723 return $ret;
8724}
8725
8726
8738function setEventMessage($mesgs, $style = 'mesgs', $noduplicate = 0)
8739{
8740 //dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING); This is not deprecated, it is used by setEventMessages function
8741 if (!is_array($mesgs)) {
8742 // If mesgs is a string
8743 if ($mesgs) {
8744 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesgs, $_SESSION['dol_events'][$style])) {
8745 return;
8746 }
8747 $_SESSION['dol_events'][$style][] = $mesgs;
8748 }
8749 } else {
8750 // If mesgs is an array
8751 foreach ($mesgs as $mesg) {
8752 if ($mesg) {
8753 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesg, $_SESSION['dol_events'][$style])) {
8754 return;
8755 }
8756 $_SESSION['dol_events'][$style][] = $mesg;
8757 }
8758 }
8759 }
8760}
8761
8774function setEventMessages($mesg, $mesgs, $style = 'mesgs', $messagekey = '', $noduplicate = 0)
8775{
8776 if (empty($mesg) && empty($mesgs)) {
8777 dol_syslog("Try to add a message in stack, but value to add is empty message", LOG_WARNING);
8778 } else {
8779 if ($messagekey) {
8780 // Complete message with a js link to set a cookie "DOLHIDEMESSAGE".$messagekey;
8781 // TODO
8782 $mesg .= '';
8783 }
8784 if (empty($messagekey) || empty($_COOKIE["DOLHIDEMESSAGE".$messagekey])) {
8785 if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
8786 dol_print_error('', 'Bad parameter style='.$style.' for setEventMessages');
8787 }
8788 if (empty($mesgs)) {
8789 setEventMessage($mesg, $style, $noduplicate);
8790 } else {
8791 if (!empty($mesg) && !in_array($mesg, $mesgs)) {
8792 setEventMessage($mesg, $style, $noduplicate); // Add message string if not already into array
8793 }
8794 setEventMessage($mesgs, $style, $noduplicate);
8795 }
8796 }
8797 }
8798}
8799
8809function dol_htmloutput_events($disabledoutputofmessages = 0)
8810{
8811 // Show mesgs
8812 if (isset($_SESSION['dol_events']['mesgs'])) {
8813 if (empty($disabledoutputofmessages)) {
8814 dol_htmloutput_mesg('', $_SESSION['dol_events']['mesgs']);
8815 }
8816 unset($_SESSION['dol_events']['mesgs']);
8817 }
8818 // Show errors
8819 if (isset($_SESSION['dol_events']['errors'])) {
8820 if (empty($disabledoutputofmessages)) {
8821 dol_htmloutput_mesg('', $_SESSION['dol_events']['errors'], 'error');
8822 }
8823 unset($_SESSION['dol_events']['errors']);
8824 }
8825
8826 // Show warnings
8827 if (isset($_SESSION['dol_events']['warnings'])) {
8828 if (empty($disabledoutputofmessages)) {
8829 dol_htmloutput_mesg('', $_SESSION['dol_events']['warnings'], 'warning');
8830 }
8831 unset($_SESSION['dol_events']['warnings']);
8832 }
8833}
8834
8849function get_htmloutput_mesg($mesgstring = '', $mesgarray = '', $style = 'ok', $keepembedded = 0)
8850{
8851 global $conf, $langs;
8852
8853 $ret = 0;
8854 $return = '';
8855 $out = '';
8856 $divstart = $divend = '';
8857
8858 // If inline message with no format, we add it.
8859 if ((empty($conf->use_javascript_ajax) || !empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) || $keepembedded) && !preg_match('/<div class=".*">/i', $out)) {
8860 $divstart = '<div class="'.$style.' clearboth">';
8861 $divend = '</div>';
8862 }
8863
8864 if ((is_array($mesgarray) && count($mesgarray)) || $mesgstring) {
8865 $langs->load("errors");
8866 $out .= $divstart;
8867 if (is_array($mesgarray) && count($mesgarray)) {
8868 foreach ($mesgarray as $message) {
8869 $ret++;
8870 $out .= $langs->trans($message);
8871 if ($ret < count($mesgarray)) {
8872 $out .= "<br>\n";
8873 }
8874 }
8875 }
8876 if ($mesgstring) {
8877 $ret++;
8878 $out .= $langs->trans($mesgstring);
8879 }
8880 $out .= $divend;
8881 }
8882
8883 if ($out) {
8884 if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) && empty($keepembedded)) {
8885 $return = '<script nonce="'.getNonce().'">
8886 $(document).ready(function() {
8887 var block = '.(!empty($conf->global->MAIN_USE_JQUERY_BLOCKUI) ? "true" : "false").'
8888 if (block) {
8889 $.dolEventValid("","'.dol_escape_js($out).'");
8890 } else {
8891 /* jnotify(message, preset of message type, keepmessage) */
8892 $.jnotify("'.dol_escape_js($out).'",
8893 "'.($style == "ok" ? 3000 : $style).'",
8894 '.($style == "ok" ? "false" : "true").',
8895 { remove: function (){} } );
8896 }
8897 });
8898 </script>';
8899 } else {
8900 $return = $out;
8901 }
8902 }
8903
8904 return $return;
8905}
8906
8918function get_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
8919{
8920 return get_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
8921}
8922
8936function dol_htmloutput_mesg($mesgstring = '', $mesgarray = array(), $style = 'ok', $keepembedded = 0)
8937{
8938 if (empty($mesgstring) && (!is_array($mesgarray) || count($mesgarray) == 0)) {
8939 return;
8940 }
8941
8942 $iserror = 0;
8943 $iswarning = 0;
8944 if (is_array($mesgarray)) {
8945 foreach ($mesgarray as $val) {
8946 if ($val && preg_match('/class="error"/i', $val)) {
8947 $iserror++;
8948 break;
8949 }
8950 if ($val && preg_match('/class="warning"/i', $val)) {
8951 $iswarning++;
8952 break;
8953 }
8954 }
8955 } elseif ($mesgstring && preg_match('/class="error"/i', $mesgstring)) {
8956 $iserror++;
8957 } elseif ($mesgstring && preg_match('/class="warning"/i', $mesgstring)) {
8958 $iswarning++;
8959 }
8960 if ($style == 'error') {
8961 $iserror++;
8962 }
8963 if ($style == 'warning') {
8964 $iswarning++;
8965 }
8966
8967 if ($iserror || $iswarning) {
8968 // Remove div from texts
8969 $mesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $mesgstring);
8970 $mesgstring = preg_replace('/<div class="(error|warning)">/', '', $mesgstring);
8971 $mesgstring = preg_replace('/<\/div>/', '', $mesgstring);
8972 // Remove div from texts array
8973 if (is_array($mesgarray)) {
8974 $newmesgarray = array();
8975 foreach ($mesgarray as $val) {
8976 if (is_string($val)) {
8977 $tmpmesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $val);
8978 $tmpmesgstring = preg_replace('/<div class="(error|warning)">/', '', $tmpmesgstring);
8979 $tmpmesgstring = preg_replace('/<\/div>/', '', $tmpmesgstring);
8980 $newmesgarray[] = $tmpmesgstring;
8981 } else {
8982 dol_syslog("Error call of dol_htmloutput_mesg with an array with a value that is not a string", LOG_WARNING);
8983 }
8984 }
8985 $mesgarray = $newmesgarray;
8986 }
8987 print get_htmloutput_mesg($mesgstring, $mesgarray, ($iserror ? 'error' : 'warning'), $keepembedded);
8988 } else {
8989 print get_htmloutput_mesg($mesgstring, $mesgarray, 'ok', $keepembedded);
8990 }
8991}
8992
9004function dol_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
9005{
9006 dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
9007}
9008
9023function dol_sort_array(&$array, $index, $order = 'asc', $natsort = 0, $case_sensitive = 0, $keepindex = 0)
9024{
9025 // Clean parameters
9026 $order = strtolower($order);
9027
9028 if (is_array($array)) {
9029 $sizearray = count($array);
9030 if ($sizearray > 0) {
9031 $temp = array();
9032 foreach (array_keys($array) as $key) {
9033 if (is_object($array[$key])) {
9034 $temp[$key] = empty($array[$key]->$index) ? 0 : $array[$key]->$index;
9035 } else {
9036 $temp[$key] = empty($array[$key][$index]) ? 0 : $array[$key][$index];
9037 }
9038 if ($natsort == -1) {
9039 $temp[$key] = '___'.$temp[$key]; // We add a string at begin of value to force an alpha order when using asort.
9040 }
9041 }
9042
9043 if (empty($natsort) || $natsort == -1) {
9044 if ($order == 'asc') {
9045 asort($temp);
9046 } else {
9047 arsort($temp);
9048 }
9049 } else {
9050 if ($case_sensitive) {
9051 natsort($temp);
9052 } else {
9053 natcasesort($temp); // natecasesort is not sensible to case
9054 }
9055 if ($order != 'asc') {
9056 $temp = array_reverse($temp, true);
9057 }
9058 }
9059
9060 $sorted = array();
9061
9062 foreach (array_keys($temp) as $key) {
9063 (is_numeric($key) && empty($keepindex)) ? $sorted[] = $array[$key] : $sorted[$key] = $array[$key];
9064 }
9065
9066 return $sorted;
9067 }
9068 }
9069 return $array;
9070}
9071
9072
9079function utf8_check($str)
9080{
9081 $str = (string) $str; // Sometimes string is an int.
9082
9083 // We must use here a binary strlen function (so not dol_strlen)
9084 $strLength = dol_strlen($str);
9085 for ($i = 0; $i < $strLength; $i++) {
9086 if (ord($str[$i]) < 0x80) {
9087 continue; // 0bbbbbbb
9088 } elseif ((ord($str[$i]) & 0xE0) == 0xC0) {
9089 $n = 1; // 110bbbbb
9090 } elseif ((ord($str[$i]) & 0xF0) == 0xE0) {
9091 $n = 2; // 1110bbbb
9092 } elseif ((ord($str[$i]) & 0xF8) == 0xF0) {
9093 $n = 3; // 11110bbb
9094 } elseif ((ord($str[$i]) & 0xFC) == 0xF8) {
9095 $n = 4; // 111110bb
9096 } elseif ((ord($str[$i]) & 0xFE) == 0xFC) {
9097 $n = 5; // 1111110b
9098 } else {
9099 return false; // Does not match any model
9100 }
9101 for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
9102 if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80)) {
9103 return false;
9104 }
9105 }
9106 }
9107 return true;
9108}
9109
9116function utf8_valid($str)
9117{
9118 /* 2 other methods to test if string is utf8
9119 $validUTF8 = mb_check_encoding($messagetext, 'UTF-8');
9120 $validUTF8b = ! (false === mb_detect_encoding($messagetext, 'UTF-8', true));
9121 */
9122 return preg_match('//u', $str) ? true : false;
9123}
9124
9125
9132function ascii_check($str)
9133{
9134 if (function_exists('mb_check_encoding')) {
9135 //if (mb_detect_encoding($str, 'ASCII', true) return false;
9136 if (!mb_check_encoding($str, 'ASCII')) {
9137 return false;
9138 }
9139 } else {
9140 if (preg_match('/[^\x00-\x7f]/', $str)) {
9141 return false; // Contains a byte > 7f
9142 }
9143 }
9144
9145 return true;
9146}
9147
9148
9156function dol_osencode($str)
9157{
9158 global $conf;
9159
9160 $tmp = ini_get("unicode.filesystem_encoding"); // Disponible avec PHP 6.0
9161 if (empty($tmp) && !empty($_SERVER["WINDIR"])) {
9162 $tmp = 'iso-8859-1'; // By default for windows
9163 }
9164 if (empty($tmp)) {
9165 $tmp = 'utf-8'; // By default for other
9166 }
9167 if (!empty($conf->global->MAIN_FILESYSTEM_ENCODING)) {
9168 $tmp = $conf->global->MAIN_FILESYSTEM_ENCODING;
9169 }
9170
9171 if ($tmp == 'iso-8859-1') {
9172 return mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8');
9173 }
9174 return $str;
9175}
9176
9177
9193function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '', $useCache = true)
9194{
9195 global $cache_codes;
9196
9197 // If key empty
9198 if ($key == '') {
9199 return '';
9200 }
9201
9202 // Check in cache
9203 if ($useCache && isset($cache_codes[$tablename][$fieldkey][$fieldid][$entityfilter][$filters][$key])) { // Can be defined to 0 or ''
9204 return $cache_codes[$tablename][$fieldkey][$fieldid][$entityfilter][$filters][$key]; // Found in cache
9205 }
9206
9207 dol_syslog('dol_getIdFromCode (value for field '.$fieldid.' from key '.$key.' not found into cache)', LOG_DEBUG);
9208
9209 $sql = "SELECT ".$fieldid." as valuetoget";
9210 $sql .= " FROM ".MAIN_DB_PREFIX.$tablename;
9211 $sql .= " WHERE ".$fieldkey." = '".$db->escape($key)."'";
9212 if (!empty($entityfilter)) {
9213 $sql .= " AND entity IN (".getEntity($tablename).")";
9214 }
9215 if ($filters) {
9216 $sql .= $filters;
9217 }
9218
9219 $resql = $db->query($sql);
9220 if ($resql) {
9221 $obj = $db->fetch_object($resql);
9222 $valuetoget = '';
9223 if ($obj) {
9224 $valuetoget = $obj->valuetoget;
9225 }
9226 $db->free($resql);
9227 if ($useCache) {
9228 $cache_codes[$tablename][$fieldkey][$fieldid][$entityfilter][$filters][$key] = $valuetoget;
9229 }
9230 return $valuetoget;
9231 } else {
9232 return -1;
9233 }
9234}
9235
9242function verifCond($strToEvaluate)
9243{
9244 global $user, $conf, $langs;
9245 global $leftmenu;
9246 global $rights; // To export to dol_eval function
9247
9248 //print $strToEvaluate."<br>\n";
9249 $rights = true;
9250 if (isset($strToEvaluate) && $strToEvaluate !== '') {
9251 //var_dump($strToEvaluate);
9252 //$rep = dol_eval($strToEvaluate, 1, 0, '1'); // to show the error
9253 $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
9254 $rights = $rep && (!is_string($rep) || strpos($rep, 'Bad string syntax to evaluate') === false);
9255 //var_dump($rights);
9256 }
9257 return $rights;
9258}
9259
9270function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1')
9271{
9272 // Only global variables can be changed by eval function and returned to caller
9273 global $db, $langs, $user, $conf, $website, $websitepage;
9274 global $action, $mainmenu, $leftmenu;
9275 global $mysoc;
9276 global $objectoffield;
9277
9278 // Old variables used
9279 global $rights;
9280 global $object;
9281 global $obj; // To get $obj used into list when dol_eval is used for computed fields and $obj is not yet $object
9282 global $soc; // For backward compatibility
9283
9284 try {
9285 // Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing
9286 if ($onlysimplestring == '1') {
9287 // We must accept: '1 && getDolGlobalInt("doesnotexist1") && $conf->global->MAIN_FEATURES_LEVEL'
9288 // We must accept: '$conf->barcode->enabled || preg_match(\'/^AAA/\',$leftmenu)'
9289 // We must accept: '$user->rights->cabinetmed->read && !$object->canvas=="patient@cabinetmed"'
9290 if (preg_match('/[^a-z0-9\s'.preg_quote('^$_+-.*>&|=!?():"\',/@', '/').']/i', $s)) {
9291 if ($returnvalue) {
9292 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9293 } else {
9294 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9295 return '';
9296 }
9297 // TODO
9298 // We can exclude all parenthesis ( that are not '($db' and 'getDolGlobalInt(' and 'getDolGlobalString(' and 'preg_match(' and 'isModEnabled('
9299 // ...
9300 }
9301 } elseif ($onlysimplestring == '2') {
9302 // 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"
9303 if (preg_match('/[^a-z0-9\s'.preg_quote('^$_+-.*>&|=!?():"\',/@[]', '/').']/i', $s)) {
9304 if ($returnvalue) {
9305 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9306 } else {
9307 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9308 return '';
9309 }
9310 // TODO
9311 // We can exclude all parenthesis ( that are not '($db' and 'getDolGlobalInt(' and 'getDolGlobalString(' and 'preg_match(' and 'isModEnabled('
9312 // ...
9313 }
9314 }
9315 if (is_array($s) || $s === 'Array') {
9316 return 'Bad string syntax to evaluate (value is Array) '.var_export($s, true);
9317 }
9318
9319 if (!getDolGlobalString('MAIN_ALLOW_DOUBLE_COLON_IN_DOL_EVAL') && strpos($s, '::') !== false) {
9320 if ($returnvalue) {
9321 return 'Bad string syntax to evaluate (double : char is forbidden without setting MAIN_ALLOW_DOUBLE_COLON_IN_DOL_EVAL): '.$s;
9322 } else {
9323 dol_syslog('Bad string syntax to evaluate (double : char is forbidden without setting MAIN_ALLOW_DOUBLE_COLON_IN_DOL_EVAL): '.$s, LOG_WARNING);
9324 return '';
9325 }
9326 }
9327
9328 if (strpos($s, '`') !== false) {
9329 if ($returnvalue) {
9330 return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
9331 } else {
9332 dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s);
9333 return '';
9334 }
9335 }
9336
9337 // Disallow also concat
9338 if (getDolGlobalString('MAIN_DISALLOW_STRING_OBFUSCATION_IN_DOL_EVAL')) {
9339 if (preg_match('/[^0-9]+\.[^0-9]+/', $s)) { // We refuse . if not between 2 numbers
9340 if ($returnvalue) {
9341 return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
9342 } else {
9343 dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s);
9344 return '';
9345 }
9346 }
9347 }
9348
9349 // We block use of php exec or php file functions
9350 $forbiddenphpstrings = array('$$');
9351 $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
9352
9353 // We list all forbidden function as keywords we don't want to see (we don't mind it if is "kewyord(" or just "keyword", we don't want "keyword" at all)
9354 // We must exclude all functions that allow to execute another function. This includes all function that has a parameter with type "callable" to avoid things
9355 // like we can do with array_map and its callable parameter: dol_eval('json_encode(array_map(implode("",["ex","ec"]), ["id"]))', 1, 1, '0')
9356 $forbiddenphpfunctions = array();
9357 // @phpcs:ignore
9358 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64"."_"."decode", "rawurl"."decode", "url"."decode", "str"."_rot13", "hex"."2bin")); // name of forbidden functions are split to avoid false positive
9359 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("override_function", "session_id", "session_create_id", "session_regenerate_id"));
9360 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
9361 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func", "call_user_func_array"));
9362
9363 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("array_all", "array_any", "array_diff_ukey", "array_filter", "array_find", "array_find_key", "array_map", "array_reduce", "array_intersect_uassoc", "array_intersect_ukey", "array_walk", "array_walk_recursive"));
9364 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("usort", "uasort", "uksort", "preg_replace_callback", "preg_replace_callback_array", "header_register_callback"));
9365 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("set_error_handler", "set_exception_handler", "libxml_set_external_entity_loader", "register_shutdown_function", "register_tick_function", "unregister_tick_function"));
9366 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("spl_autoload_register", "spl_autoload_unregister", "iterator_apply", "session_set_save_handler"));
9367 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("forward_static_call", "forward_static_call_array", "register_postsend_function"));
9368
9369 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("ob_start"));
9370
9371 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
9372 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("exec", "passthru", "shell_exec", "system", "proc_open", "popen"));
9373 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
9374 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace", "mb_ereg_replace_callback")); // function with eval capabilities
9375 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("readline_completion_function", "readline_callback_handler_install"));
9376 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_compress_dir", "dol_decode", "dol_delete_file", "dol_delete_dir", "dol_delete_dir_recursive", "dol_copy", "archiveOrBackupFile")); // more dolibarr functions
9377 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
9378 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include"));
9379
9380 $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
9381
9382 $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
9383
9384 $forbiddenphpmethodsregex = '->('.implode('|', $forbiddenphpmethods).')';
9385
9386 do {
9387 $oldstringtoclean = $s;
9388 $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);
9389 $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);
9390 $s = preg_replace('/'.$forbiddenphpmethodsregex.'/i', '__forbiddenstring__', $s);
9391 //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\‍(/i', '', $s); // Remove $function( call and $mycall->mymethod(
9392 } while ($oldstringtoclean != $s);
9393
9394 if (strpos($s, '__forbiddenstring__') !== false) {
9395 dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
9396 if ($returnvalue) {
9397 return 'Bad string syntax to evaluate: '.$s;
9398 } else {
9399 dol_syslog('Bad string syntax to evaluate: '.$s);
9400 return '';
9401 }
9402 }
9403
9404 //print $s."<br>\n";
9405 if ($returnvalue) {
9406 if ($hideerrors) {
9407 return @eval('return '.$s.';');
9408 } else {
9409 return eval('return '.$s.';');
9410 }
9411 } else {
9412 if ($hideerrors) {
9413 @eval($s);
9414 } else {
9415 eval($s);
9416 }
9417 }
9418 } catch (Error $e) {
9419 $error = 'dol_eval try/catch error : ';
9420 $error .= $e->getMessage();
9421 dol_syslog($error);
9422 }
9423}
9424
9431function dol_validElement($element)
9432{
9433 return (trim($element) != '');
9434}
9435
9444function picto_from_langcode($codelang, $moreatt = '', $notitlealt = 0)
9445{
9446 if (empty($codelang)) {
9447 return '';
9448 }
9449
9450 if ($codelang == 'auto') {
9451 return '<span class="fa fa-language"></span>';
9452 }
9453
9454 $langtocountryflag = array(
9455 'ar_AR' => '',
9456 'ca_ES' => 'catalonia',
9457 'da_DA' => 'dk',
9458 'fr_CA' => 'mq',
9459 'sv_SV' => 'se',
9460 'sw_SW' => 'unknown',
9461 'AQ' => 'unknown',
9462 'CW' => 'unknown',
9463 'IM' => 'unknown',
9464 'JE' => 'unknown',
9465 'MF' => 'unknown',
9466 'BL' => 'unknown',
9467 'SX' => 'unknown'
9468 );
9469
9470 if (isset($langtocountryflag[$codelang])) {
9471 $flagImage = $langtocountryflag[$codelang];
9472 } else {
9473 $tmparray = explode('_', $codelang);
9474 $flagImage = empty($tmparray[1]) ? $tmparray[0] : $tmparray[1];
9475 }
9476
9477 return img_picto_common($codelang, 'flags/'.strtolower($flagImage).'.png', $moreatt, 0, $notitlealt);
9478}
9479
9488{
9489 global $mysoc;
9490
9491 if (empty($countrycode)) {
9492 return null;
9493 }
9494
9495 if (strtoupper($countrycode) == 'MQ') {
9496 return 'fr_CA';
9497 }
9498 if (strtoupper($countrycode) == 'SE') {
9499 return 'sv_SE'; // se_SE is Sami/Sweden, and we want in priority sv_SE for SE country
9500 }
9501 if (strtoupper($countrycode) == 'CH') {
9502 if ($mysoc->country_code == 'FR') {
9503 return 'fr_CH';
9504 }
9505 if ($mysoc->country_code == 'DE') {
9506 return 'de_CH';
9507 }
9508 if ($mysoc->country_code == 'IT') {
9509 return 'it_CH';
9510 }
9511 }
9512
9513 // Locale list taken from:
9514 // http://stackoverflow.com/questions/3191664/
9515 // list-of-all-locales-and-their-short-codes
9516 $locales = array(
9517 'af-ZA',
9518 'am-ET',
9519 'ar-AE',
9520 'ar-BH',
9521 'ar-DZ',
9522 'ar-EG',
9523 'ar-IQ',
9524 'ar-JO',
9525 'ar-KW',
9526 'ar-LB',
9527 'ar-LY',
9528 'ar-MA',
9529 'ar-OM',
9530 'ar-QA',
9531 'ar-SA',
9532 'ar-SY',
9533 'ar-TN',
9534 'ar-YE',
9535 //'as-IN', // Moved after en-IN
9536 'ba-RU',
9537 'be-BY',
9538 'bg-BG',
9539 'bn-BD',
9540 //'bn-IN', // Moved after en-IN
9541 'bo-CN',
9542 'br-FR',
9543 'ca-ES',
9544 'co-FR',
9545 'cs-CZ',
9546 'cy-GB',
9547 'da-DK',
9548 'de-AT',
9549 'de-CH',
9550 'de-DE',
9551 'de-LI',
9552 'de-LU',
9553 'dv-MV',
9554 'el-GR',
9555 'en-AU',
9556 'en-BZ',
9557 'en-CA',
9558 'en-GB',
9559 'en-IE',
9560 'en-IN',
9561 'as-IN', // as-IN must be after en-IN (en in priority if country is IN)
9562 'bn-IN', // bn-IN must be after en-IN (en in priority if country is IN)
9563 'en-JM',
9564 'en-MY',
9565 'en-NZ',
9566 'en-PH',
9567 'en-SG',
9568 'en-TT',
9569 'en-US',
9570 'en-ZA',
9571 'en-ZW',
9572 'es-AR',
9573 'es-BO',
9574 'es-CL',
9575 'es-CO',
9576 'es-CR',
9577 'es-DO',
9578 'es-EC',
9579 'es-ES',
9580 'es-GT',
9581 'es-HN',
9582 'es-MX',
9583 'es-NI',
9584 'es-PA',
9585 'es-PE',
9586 'es-PR',
9587 'es-PY',
9588 'es-SV',
9589 'es-US',
9590 'es-UY',
9591 'es-VE',
9592 'et-EE',
9593 'eu-ES',
9594 'fa-IR',
9595 'fi-FI',
9596 'fo-FO',
9597 'fr-BE',
9598 'fr-CA',
9599 'fr-CH',
9600 'fr-FR',
9601 'fr-LU',
9602 'fr-MC',
9603 'fy-NL',
9604 'ga-IE',
9605 'gd-GB',
9606 'gl-ES',
9607 'gu-IN',
9608 'he-IL',
9609 'hi-IN',
9610 'hr-BA',
9611 'hr-HR',
9612 'hu-HU',
9613 'hy-AM',
9614 'id-ID',
9615 'ig-NG',
9616 'ii-CN',
9617 'is-IS',
9618 'it-CH',
9619 'it-IT',
9620 'ja-JP',
9621 'ka-GE',
9622 'kk-KZ',
9623 'kl-GL',
9624 'km-KH',
9625 'kn-IN',
9626 'ko-KR',
9627 'ky-KG',
9628 'lb-LU',
9629 'lo-LA',
9630 'lt-LT',
9631 'lv-LV',
9632 'mi-NZ',
9633 'mk-MK',
9634 'ml-IN',
9635 'mn-MN',
9636 'mr-IN',
9637 'ms-BN',
9638 'ms-MY',
9639 'mt-MT',
9640 'nb-NO',
9641 'ne-NP',
9642 'nl-BE',
9643 'nl-NL',
9644 'nn-NO',
9645 'oc-FR',
9646 'or-IN',
9647 'pa-IN',
9648 'pl-PL',
9649 'ps-AF',
9650 'pt-BR',
9651 'pt-PT',
9652 'rm-CH',
9653 'ro-MD',
9654 'ro-RO',
9655 'ru-RU',
9656 'rw-RW',
9657 'sa-IN',
9658 'se-FI',
9659 'se-NO',
9660 'se-SE',
9661 'si-LK',
9662 'sk-SK',
9663 'sl-SI',
9664 'sq-AL',
9665 'sv-FI',
9666 'sv-SE',
9667 'sw-KE',
9668 'ta-IN',
9669 'te-IN',
9670 'th-TH',
9671 'tk-TM',
9672 'tn-ZA',
9673 'tr-TR',
9674 'tt-RU',
9675 'ug-CN',
9676 'uk-UA',
9677 'ur-PK',
9678 'vi-VN',
9679 'wo-SN',
9680 'xh-ZA',
9681 'yo-NG',
9682 'zh-CN',
9683 'zh-HK',
9684 'zh-MO',
9685 'zh-SG',
9686 'zh-TW',
9687 'zu-ZA',
9688 );
9689
9690 $buildprimarykeytotest = strtolower($countrycode).'-'.strtoupper($countrycode);
9691 if (in_array($buildprimarykeytotest, $locales)) {
9692 return strtolower($countrycode).'_'.strtoupper($countrycode);
9693 }
9694
9695 if (function_exists('locale_get_primary_language') && function_exists('locale_get_region')) { // Need extension php-intl
9696 foreach ($locales as $locale) {
9697 $locale_language = locale_get_primary_language($locale);
9698 $locale_region = locale_get_region($locale);
9699 if (strtoupper($countrycode) == $locale_region) {
9700 //var_dump($locale.' - '.$locale_language.' - '.$locale_region);
9701 return strtolower($locale_language).'_'.strtoupper($locale_region);
9702 }
9703 }
9704 } else {
9705 dol_syslog("Warning Exention php-intl is not available", LOG_WARNING);
9706 }
9707
9708 return null;
9709}
9710
9741function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode = 'add', $filterorigmodule = '')
9742{
9743 global $hookmanager, $db;
9744
9745 if (isset($conf->modules_parts['tabs'][$type]) && is_array($conf->modules_parts['tabs'][$type])) {
9746 foreach ($conf->modules_parts['tabs'][$type] as $value) {
9747 $values = explode(':', $value);
9748
9749 $reg = array();
9750 if ($mode == 'add' && !preg_match('/^\-/', $values[1])) {
9751 if (count($values) == 6) {
9752 // new declaration with permissions:
9753 // $value='objecttype:+tabname1:Title1:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
9754 // $value='objecttype:+tabname1:Title1,class,pathfile,method:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
9755 if ($values[0] != $type) {
9756 continue;
9757 }
9758
9759 if (verifCond($values[4])) {
9760 if ($values[3]) {
9761 if ($filterorigmodule) { // If a filter of module origin has been requested
9762 if (strpos($values[3], '@')) { // This is an external module
9763 if ($filterorigmodule != 'external') {
9764 continue;
9765 }
9766 } else { // This looks a core module
9767 if ($filterorigmodule != 'core') {
9768 continue;
9769 }
9770 }
9771 }
9772 $langs->load($values[3]);
9773 }
9774 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
9775 // If label is "SUBSTITUION_..."
9776 $substitutionarray = array();
9777 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
9778 $label = make_substitutions($reg[1], $substitutionarray);
9779 } else {
9780 // If label is "Label,Class,File,Method", we call the method to show content inside the badge
9781 $labeltemp = explode(',', $values[2]);
9782 $label = $langs->trans($labeltemp[0]);
9783
9784 if (!empty($labeltemp[1]) && is_object($object) && !empty($object->id)) {
9785 dol_include_once($labeltemp[2]);
9786 $classtoload = $labeltemp[1];
9787 if (class_exists($classtoload)) {
9788 $obj = new $classtoload($db);
9789 $function = $labeltemp[3];
9790 if ($obj && $function && method_exists($obj, $function)) {
9791 $nbrec = $obj->$function($object->id, $obj);
9792 if (!empty($nbrec)) {
9793 $label .= '<span class="badge marginleftonlyshort">'.$nbrec.'</span>';
9794 }
9795 }
9796 }
9797 }
9798 }
9799
9800 $head[$h][0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[5]), 1);
9801 $head[$h][1] = $label;
9802 $head[$h][2] = str_replace('+', '', $values[1]);
9803 $h++;
9804 }
9805 } elseif (count($values) == 5) { // case deprecated
9806 dol_syslog('Passing 5 values in tabs module_parts is deprecated. Please update to 6 with permissions.', LOG_WARNING);
9807
9808 if ($values[0] != $type) {
9809 continue;
9810 }
9811 if ($values[3]) {
9812 if ($filterorigmodule) { // If a filter of module origin has been requested
9813 if (strpos($values[3], '@')) { // This is an external module
9814 if ($filterorigmodule != 'external') {
9815 continue;
9816 }
9817 } else { // This looks a core module
9818 if ($filterorigmodule != 'core') {
9819 continue;
9820 }
9821 }
9822 }
9823 $langs->load($values[3]);
9824 }
9825 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
9826 $substitutionarray = array();
9827 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
9828 $label = make_substitutions($reg[1], $substitutionarray);
9829 } else {
9830 $label = $langs->trans($values[2]);
9831 }
9832
9833 $head[$h][0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[4]), 1);
9834 $head[$h][1] = $label;
9835 $head[$h][2] = str_replace('+', '', $values[1]);
9836 $h++;
9837 }
9838 } elseif ($mode == 'remove' && preg_match('/^\-/', $values[1])) {
9839 if ($values[0] != $type) {
9840 continue;
9841 }
9842 $tabname = str_replace('-', '', $values[1]);
9843 foreach ($head as $key => $val) {
9844 $condition = (!empty($values[3]) ? verifCond($values[3]) : 1);
9845 //var_dump($key.' - '.$tabname.' - '.$head[$key][2].' - '.$values[3].' - '.$condition);
9846 if ($head[$key][2] == $tabname && $condition) {
9847 unset($head[$key]);
9848 break;
9849 }
9850 }
9851 }
9852 }
9853 }
9854
9855 // No need to make a return $head. Var is modified as a reference
9856 if (!empty($hookmanager)) {
9857 $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule);
9858 $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters);
9859 if ($reshook > 0) { // Hook ask to replace completely the array
9860 $head = $hookmanager->resArray;
9861 } else { // Hook
9862 $head = array_merge($head, $hookmanager->resArray);
9863 }
9864 $h = count($head);
9865 }
9866}
9867
9879function printCommonFooter($zone = 'private')
9880{
9881 global $conf, $hookmanager, $user, $debugbar;
9882 global $action;
9883 global $micro_start_time;
9884
9885 if ($zone == 'private') {
9886 print "\n".'<!-- Common footer for private page -->'."\n";
9887 } else {
9888 print "\n".'<!-- Common footer for public page -->'."\n";
9889 }
9890
9891 // A div to store page_y POST parameter so we can read it using javascript
9892 print "\n<!-- A div to store page_y POST parameter -->\n";
9893 print '<div id="page_y" style="display: none;">'.(GETPOST('page_y') ? GETPOST('page_y') : '').'</div>'."\n";
9894
9895 $parameters = array();
9896 $reshook = $hookmanager->executeHooks('printCommonFooter', $parameters); // Note that $action and $object may have been modified by some hooks
9897 if (empty($reshook)) {
9898 if (!empty($conf->global->MAIN_HTML_FOOTER)) {
9899 print $conf->global->MAIN_HTML_FOOTER."\n";
9900 }
9901
9902 print "\n";
9903 if (!empty($conf->use_javascript_ajax)) {
9904 print "\n<!-- A script section to add menuhider handler on backoffice, manage focus and madatory fields, tuning info, ... -->\n";
9905 print '<script>'."\n";
9906 print 'jQuery(document).ready(function() {'."\n";
9907
9908 if ($zone == 'private' && empty($conf->dol_use_jmobile)) {
9909 print "\n";
9910 print '/* JS CODE TO ENABLE to manage handler to switch left menu page (menuhider) */'."\n";
9911 print 'jQuery("li.menuhider").click(function(event) {';
9912 print ' if (!$( "body" ).hasClass( "sidebar-collapse" )){ event.preventDefault(); }'."\n";
9913 print ' console.log("We click on .menuhider");'."\n";
9914 print ' $("body").toggleClass("sidebar-collapse")'."\n";
9915 print '});'."\n";
9916 }
9917
9918 // Management of focus and mandatory for fields
9919 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"])))) {
9920 print '/* JS CODE TO ENABLE to manage focus and mandatory form fields */'."\n";
9921 $relativepathstring = $_SERVER["PHP_SELF"];
9922 // Clean $relativepathstring
9923 if (constant('DOL_URL_ROOT')) {
9924 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
9925 }
9926 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
9927 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
9928 //$tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
9929 if (!empty($user->default_values[$relativepathstring]['focus'])) {
9930 foreach ($user->default_values[$relativepathstring]['focus'] as $defkey => $defval) {
9931 $qualified = 0;
9932 if ($defkey != '_noquery_') {
9933 $tmpqueryarraytohave = explode('&', $defkey);
9934 $foundintru = 0;
9935 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
9936 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
9937 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
9938 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
9939 $foundintru = 1;
9940 }
9941 }
9942 if (!$foundintru) {
9943 $qualified = 1;
9944 }
9945 //var_dump($defkey.'-'.$qualified);
9946 } else {
9947 $qualified = 1;
9948 }
9949
9950 if ($qualified) {
9951 foreach ($defval as $paramkey => $paramval) {
9952 // Set focus on field
9953 print 'jQuery("input[name=\''.$paramkey.'\']").focus();'."\n";
9954 print 'jQuery("textarea[name=\''.$paramkey.'\']").focus();'."\n";
9955 print 'jQuery("select[name=\''.$paramkey.'\']").focus();'."\n"; // Not really usefull, but we keep it in case of.
9956 }
9957 }
9958 }
9959 }
9960 if (!empty($user->default_values[$relativepathstring]['mandatory'])) {
9961 foreach ($user->default_values[$relativepathstring]['mandatory'] as $defkey => $defval) {
9962 $qualified = 0;
9963 if ($defkey != '_noquery_') {
9964 $tmpqueryarraytohave = explode('&', $defkey);
9965 $foundintru = 0;
9966 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
9967 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
9968 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
9969 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
9970 $foundintru = 1;
9971 }
9972 }
9973 if (!$foundintru) {
9974 $qualified = 1;
9975 }
9976 //var_dump($defkey.'-'.$qualified);
9977 } else {
9978 $qualified = 1;
9979 }
9980
9981 if ($qualified) {
9982 foreach ($defval as $paramkey => $paramval) {
9983 // Add property 'required' on input
9984 print 'jQuery("input[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
9985 print 'jQuery("textarea[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
9986 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";
9987 print 'if (jQuery("select[name=\''.$paramkey.'\']").is(\':visible\')===true) {'."\n";
9988 print 'jQuery("select[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n"; // can set focus only if this element is visible
9989 print '}'."\n";
9990 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'-1\']").prop(\'value\', \'\');'."\n";
9991 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'0\']").prop(\'value\', \'\');'."\n";
9992
9993 // Add 'field required' class on closest td for all input elements : input, textarea and select
9994 print 'jQuery(":input[name=\'' . $paramkey . '\']").closest("tr").find("td:first").addClass("fieldrequired");' . "\n";
9995 }
9996 }
9997 }
9998 }
9999 }
10000
10001 print '});'."\n";
10002
10003 // End of tuning
10004 if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO']) || !empty($conf->global->MAIN_SHOW_TUNING_INFO)) {
10005 print "\n";
10006 print "/* JS CODE TO ENABLE to add memory info */\n";
10007 print 'window.console && console.log("';
10008 if (!empty($conf->global->MEMCACHED_SERVER)) {
10009 print 'MEMCACHED_SERVER='.$conf->global->MEMCACHED_SERVER.' - ';
10010 }
10011 print 'MAIN_OPTIMIZE_SPEED='.(isset($conf->global->MAIN_OPTIMIZE_SPEED) ? $conf->global->MAIN_OPTIMIZE_SPEED : 'off');
10012 if (!empty($micro_start_time)) { // Works only if MAIN_SHOW_TUNING_INFO is defined at $_SERVER level. Not in global variable.
10013 $micro_end_time = microtime(true);
10014 print ' - Build time: '.ceil(1000 * ($micro_end_time - $micro_start_time)).' ms';
10015 }
10016
10017 if (function_exists("memory_get_usage")) {
10018 print ' - Mem: '.memory_get_usage(); // Do not use true here, it seems it takes the peak amount
10019 }
10020 if (function_exists("memory_get_peak_usage")) {
10021 print ' - Real mem peak: '.memory_get_peak_usage(true);
10022 }
10023 if (function_exists("zend_loader_file_encoded")) {
10024 print ' - Zend encoded file: '.(zend_loader_file_encoded() ? 'yes' : 'no');
10025 }
10026 print '");'."\n";
10027 }
10028
10029 print "\n".'</script>'."\n";
10030
10031 // Google Analytics
10032 // TODO Add a hook here
10033 if (isModEnabled('google') && !empty($conf->global->MAIN_GOOGLE_AN_ID)) {
10034 $tmptagarray = explode(',', $conf->global->MAIN_GOOGLE_AN_ID);
10035 foreach ($tmptagarray as $tmptag) {
10036 print "\n";
10037 print "<!-- JS CODE TO ENABLE for google analtics tag -->\n";
10038 print '
10039 <!-- Global site tag (gtag.js) - Google Analytics -->
10040 <script nonce="'.getNonce().'" async src="https://www.googletagmanager.com/gtag/js?id='.trim($tmptag).'"></script>
10041 <script>
10042 window.dataLayer = window.dataLayer || [];
10043 function gtag(){dataLayer.push(arguments);}
10044 gtag(\'js\', new Date());
10045
10046 gtag(\'config\', \''.trim($tmptag).'\');
10047 </script>';
10048 print "\n";
10049 }
10050 }
10051 }
10052
10053 // Add Xdebug coverage of code
10054 if (defined('XDEBUGCOVERAGE')) {
10055 print_r(xdebug_get_code_coverage());
10056 }
10057
10058 // Add DebugBar data
10059 if (!empty($user->rights->debugbar->read) && is_object($debugbar)) {
10060 $debugbar['time']->stopMeasure('pageaftermaster');
10061 print '<!-- Output debugbar data -->'."\n";
10062 $renderer = $debugbar->getRenderer();
10063 print $debugbar->getRenderer()->render();
10064 } elseif (count($conf->logbuffer)) { // If there is some logs in buffer to show
10065 print "\n";
10066 print "<!-- Start of log output\n";
10067 //print '<div class="hidden">'."\n";
10068 foreach ($conf->logbuffer as $logline) {
10069 print $logline."<br>\n";
10070 }
10071 //print '</div>'."\n";
10072 print "End of log output -->\n";
10073 }
10074 }
10075}
10076
10086function dolExplodeIntoArray($string, $delimiter = ';', $kv = '=')
10087{
10088 if (is_null($string)) {
10089 return array();
10090 }
10091
10092 if (preg_match('/^\[.*\]$/sm', $delimiter) || preg_match('/^\‍(.*\‍)$/sm', $delimiter)) {
10093 // This is a regex string
10094 $newdelimiter = $delimiter;
10095 } else {
10096 // This is a simple string
10097 $newdelimiter = preg_quote($delimiter, '/');
10098 }
10099
10100 if ($a = preg_split('/'.$newdelimiter.'/', $string)) {
10101 $ka = array();
10102 foreach ($a as $s) { // each part
10103 if ($s) {
10104 if ($pos = strpos($s, $kv)) { // key/value delimiter
10105 $ka[trim(substr($s, 0, $pos))] = trim(substr($s, $pos + strlen($kv)));
10106 } else { // key delimiter not found
10107 $ka[] = trim($s);
10108 }
10109 }
10110 }
10111 return $ka;
10112 }
10113
10114 return array();
10115}
10116
10117
10124function dol_set_focus($selector)
10125{
10126 print "\n".'<!-- Set focus onto a specific field -->'."\n";
10127 print '<script nonce="'.getNonce().'">jQuery(document).ready(function() { jQuery("'.dol_escape_js($selector).'").focus(); });</script>'."\n";
10128}
10129
10130
10138function dol_getmypid()
10139{
10140 if (!function_exists('getmypid')) {
10141 return mt_rand(99900000, 99965535);
10142 } else {
10143 return getmypid(); // May be a number on 64 bits (depending on OS)
10144 }
10145}
10146
10147
10165function natural_search($fields, $value, $mode = 0, $nofirstand = 0)
10166{
10167 global $db, $langs;
10168
10169 $value = trim($value);
10170
10171 if ($mode == 0) {
10172 $value = preg_replace('/\*/', '%', $value); // Replace * with %
10173 }
10174 if ($mode == 1) {
10175 $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
10176 }
10177
10178 $value = preg_replace('/\s*\|\s*/', '|', $value);
10179
10180 //natural mode search type 3 allow spaces into search ...
10181 if ($mode == 3 || $mode == -3) {
10182 $crits = explode(',', $value);
10183 } else {
10184 $crits = explode(' ', $value);
10185 }
10186 $res = '';
10187 if (!is_array($fields)) {
10188 $fields = array($fields);
10189 }
10190
10191 $i1 = 0; // count the nb of and criteria added (all fields / criterias)
10192 foreach ($crits as $crit) { // Loop on each AND criteria
10193 $crit = trim($crit);
10194 $i2 = 0; // count the nb of valid criteria added for this this first criteria
10195 $newres = '';
10196 foreach ($fields as $field) {
10197 if ($mode == 1) {
10198 $tmpcrits = explode('|', $crit);
10199 $i3 = 0; // count the nb of valid criteria added for this current field
10200 foreach ($tmpcrits as $tmpcrit) {
10201 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10202 continue;
10203 }
10204 $tmpcrit = trim($tmpcrit);
10205
10206 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10207
10208 $operator = '=';
10209 $newcrit = preg_replace('/([!<>=]+)/', '', $tmpcrit);
10210
10211 $reg = array();
10212 preg_match('/([!<>=]+)/', $tmpcrit, $reg);
10213 if (!empty($reg[1])) {
10214 $operator = $reg[1];
10215 }
10216 if ($newcrit != '') {
10217 $numnewcrit = price2num($newcrit);
10218 if (is_numeric($numnewcrit)) {
10219 $newres .= $field.' '.$operator.' '.((float) $numnewcrit); // should be a numeric
10220 } else {
10221 $newres .= '1 = 2'; // force false, we received a corrupted data
10222 }
10223 $i3++; // a criteria was added to string
10224 }
10225 }
10226 $i2++; // a criteria for 1 more field was added to string
10227 } elseif ($mode == 2 || $mode == -2) {
10228 $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer
10229 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -2 ? 'NOT ' : '');
10230 $newres .= $crit ? "IN (".$db->sanitize($db->escape($crit)).")" : "IN (0)";
10231 if ($mode == -2) {
10232 $newres .= ' OR '.$field.' IS NULL';
10233 }
10234 $i2++; // a criteria for 1 more field was added to string
10235 } elseif ($mode == 3 || $mode == -3) {
10236 $tmparray = explode(',', $crit);
10237 if (count($tmparray)) {
10238 $listofcodes = '';
10239 foreach ($tmparray as $val) {
10240 $val = trim($val);
10241 if ($val) {
10242 $listofcodes .= ($listofcodes ? ',' : '');
10243 $listofcodes .= "'".$db->escape($val)."'";
10244 }
10245 }
10246 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -3 ? 'NOT ' : '')."IN (".$db->sanitize($listofcodes, 1, 0, 1).")";
10247 $i2++; // a criteria for 1 more field was added to string
10248 }
10249 if ($mode == -3) {
10250 $newres .= ' OR '.$field.' IS NULL';
10251 }
10252 } elseif ($mode == 4) {
10253 $tmparray = explode(',', $crit);
10254 if (count($tmparray)) {
10255 $listofcodes = '';
10256 foreach ($tmparray as $val) {
10257 $val = trim($val);
10258 if ($val) {
10259 $newres .= ($i2 > 0 ? " OR (" : "(").$field." LIKE '".$db->escape($val).",%'";
10260 $newres .= ' OR '.$field." = '".$db->escape($val)."'";
10261 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val)."'";
10262 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val).",%'";
10263 $newres .= ')';
10264 $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)
10265 }
10266 }
10267 }
10268 } else { // $mode=0
10269 $tmpcrits = explode('|', $crit);
10270 $i3 = 0; // count the nb of valid criteria added for the current couple criteria/field
10271 foreach ($tmpcrits as $tmpcrit) { // loop on each OR criteria
10272 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10273 continue;
10274 }
10275 $tmpcrit = trim($tmpcrit);
10276
10277 if ($tmpcrit == '^$' || strpos($crit, '!') === 0) { // If we search empty, we must combined different OR fields with AND
10278 $newres .= (($i2 > 0 || $i3 > 0) ? ' AND ' : '');
10279 } else {
10280 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10281 }
10282
10283 if (preg_match('/\.(id|rowid)$/', $field)) { // Special case for rowid that is sometimes a ref so used as a search field
10284 $newres .= $field." = ".(is_numeric($tmpcrit) ? ((float) $tmpcrit) : '0');
10285 } else {
10286 $tmpcrit2 = $tmpcrit;
10287 $tmpbefore = '%';
10288 $tmpafter = '%';
10289 $tmps = '';
10290
10291 if (preg_match('/^!/', $tmpcrit)) {
10292 $tmps .= $field." NOT LIKE "; // ! as exclude character
10293 $tmpcrit2 = preg_replace('/^!/', '', $tmpcrit2);
10294 } else {
10295 $tmps .= $field." LIKE ";
10296 }
10297 $tmps .= "'";
10298
10299 if (preg_match('/^[\^\$]/', $tmpcrit)) {
10300 $tmpbefore = '';
10301 $tmpcrit2 = preg_replace('/^[\^\$]/', '', $tmpcrit2);
10302 }
10303 if (preg_match('/[\^\$]$/', $tmpcrit)) {
10304 $tmpafter = '';
10305 $tmpcrit2 = preg_replace('/[\^\$]$/', '', $tmpcrit2);
10306 }
10307
10308 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10309 $tmps = "(".$tmps;
10310 }
10311 $newres .= $tmps;
10312 $newres .= $tmpbefore;
10313 $newres .= $db->escape($tmpcrit2);
10314 $newres .= $tmpafter;
10315 $newres .= "'";
10316 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10317 $newres .= " OR ".$field." IS NULL)";
10318 }
10319 }
10320
10321 $i3++;
10322 }
10323
10324 $i2++; // a criteria for 1 more field was added to string
10325 }
10326 }
10327
10328 if ($newres) {
10329 $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : '');
10330 }
10331 $i1++;
10332 }
10333 $res = ($nofirstand ? "" : " AND ")."(".$res.")";
10334
10335 return $res;
10336}
10337
10344function showDirectDownloadLink($object)
10345{
10346 global $conf, $langs;
10347
10348 $out = '';
10349 $url = $object->getLastMainDocLink($object->element);
10350
10351 $out .= img_picto($langs->trans("PublicDownloadLinkDesc"), 'globe').' <span class="opacitymedium">'.$langs->trans("DirectDownloadLink").'</span><br>';
10352 if ($url) {
10353 $out .= '<div class="urllink"><input type="text" id="directdownloadlink" class="quatrevingtpercent" value="'.$url.'"></div>';
10354 $out .= ajax_autoselect("directdownloadlink", 0);
10355 } else {
10356 $out .= '<div class="urllink">'.$langs->trans("FileNotShared").'</div>';
10357 }
10358
10359 return $out;
10360}
10361
10370function getImageFileNameForSize($file, $extName, $extImgTarget = '')
10371{
10372 $dirName = dirname($file);
10373 if ($dirName == '.') {
10374 $dirName = '';
10375 }
10376
10377 $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.webp)$/i', '', $file); // We remove extension, whatever is its case
10378 $fileName = basename($fileName);
10379
10380 if (empty($extImgTarget)) {
10381 $extImgTarget = (preg_match('/\.jpg$/i', $file) ? '.jpg' : '');
10382 }
10383 if (empty($extImgTarget)) {
10384 $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '');
10385 }
10386 if (empty($extImgTarget)) {
10387 $extImgTarget = (preg_match('/\.gif$/i', $file) ? '.gif' : '');
10388 }
10389 if (empty($extImgTarget)) {
10390 $extImgTarget = (preg_match('/\.png$/i', $file) ? '.png' : '');
10391 }
10392 if (empty($extImgTarget)) {
10393 $extImgTarget = (preg_match('/\.bmp$/i', $file) ? '.bmp' : '');
10394 }
10395 if (empty($extImgTarget)) {
10396 $extImgTarget = (preg_match('/\.webp$/i', $file) ? '.webp' : '');
10397 }
10398
10399 if (!$extImgTarget) {
10400 return $file;
10401 }
10402
10403 $subdir = '';
10404 if ($extName) {
10405 $subdir = 'thumbs/';
10406 }
10407
10408 return ($dirName ? $dirName.'/' : '').$subdir.$fileName.$extName.$extImgTarget; // New filename for thumb
10409}
10410
10411
10421function getAdvancedPreviewUrl($modulepart, $relativepath, $alldata = 0, $param = '')
10422{
10423 global $conf, $langs;
10424
10425 if (empty($conf->use_javascript_ajax)) {
10426 return '';
10427 }
10428
10429 $isAllowedForPreview = dolIsAllowedForPreview($relativepath);
10430
10431 if ($alldata == 1) {
10432 if ($isAllowedForPreview) {
10433 return array('target'=>'_blank', 'css'=>'documentpreview', 'url'=>DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : ''), 'mime'=>dol_mimetype($relativepath));
10434 } else {
10435 return array();
10436 }
10437 }
10438
10439 // old behavior, return a string
10440 if ($isAllowedForPreview) {
10441 $tmpurl = DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : '');
10442 $title = $langs->transnoentities("Preview");
10443 //$title = '%27-alert(document.domain)-%27';
10444 //$tmpurl = 'file='.urlencode("'-alert(document.domain)-'_small.jpg");
10445
10446 // We need to urlencode the parameter after the dol_escape_js($tmpurl) because $tmpurl may contain n url with param file=abc%27def if file has a ' inside.
10447 // and when we click on href with this javascript string, a urlcode is done by browser, converted the %27 of file param
10448 return 'javascript:document_preview(\''.urlencode(dol_escape_js($tmpurl)).'\', \''.urlencode(dol_mimetype($relativepath)).'\', \''.rawurlencode(dol_escape_js($title)).'\')';
10449 } else {
10450 return '';
10451 }
10452}
10453
10454
10463function ajax_autoselect($htmlname, $addlink = '', $textonlink = 'Link')
10464{
10465 global $langs;
10466 $out = '<script nonce="'.getNonce().'">
10467 jQuery(document).ready(function () {
10468 jQuery("'.((strpos($htmlname, '.') === 0 ? '' : '#').$htmlname).'").click(function() { jQuery(this).select(); } );
10469 });
10470 </script>';
10471 if ($addlink) {
10472 if ($textonlink === 'image') {
10473 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.img_picto('', 'globe').'</a>';
10474 } else {
10475 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.$langs->trans("Link").'</a>';
10476 }
10477 }
10478 return $out;
10479}
10480
10488function dolIsAllowedForPreview($file)
10489{
10490 global $conf;
10491
10492 // Check .noexe extension in filename
10493 if (preg_match('/\.noexe$/i', $file)) {
10494 return 0;
10495 }
10496
10497 // Check mime types
10498 $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'webp');
10499 if (!empty($conf->global->MAIN_ALLOW_SVG_FILES_AS_IMAGES)) {
10500 $mime_preview[] = 'svg+xml';
10501 }
10502 //$mime_preview[]='vnd.oasis.opendocument.presentation';
10503 //$mime_preview[]='archive';
10504 $num_mime = array_search(dol_mimetype($file, '', 1), $mime_preview);
10505 if ($num_mime !== false) {
10506 return 1;
10507 }
10508
10509 // By default, not allowed for preview
10510 return 0;
10511}
10512
10513
10523function dol_mimetype($file, $default = 'application/octet-stream', $mode = 0)
10524{
10525 $mime = $default;
10526 $imgmime = 'other.png';
10527 $famime = 'file-o';
10528 $srclang = '';
10529
10530 $tmpfile = preg_replace('/\.noexe$/', '', $file);
10531
10532 // Plain text files
10533 if (preg_match('/\.txt$/i', $tmpfile)) {
10534 $mime = 'text/plain';
10535 $imgmime = 'text.png';
10536 $famime = 'file-text-o';
10537 }
10538 if (preg_match('/\.rtx$/i', $tmpfile)) {
10539 $mime = 'text/richtext';
10540 $imgmime = 'text.png';
10541 $famime = 'file-text-o';
10542 }
10543 if (preg_match('/\.csv$/i', $tmpfile)) {
10544 $mime = 'text/csv';
10545 $imgmime = 'text.png';
10546 $famime = 'file-text-o';
10547 }
10548 if (preg_match('/\.tsv$/i', $tmpfile)) {
10549 $mime = 'text/tab-separated-values';
10550 $imgmime = 'text.png';
10551 $famime = 'file-text-o';
10552 }
10553 if (preg_match('/\.(cf|conf|log)$/i', $tmpfile)) {
10554 $mime = 'text/plain';
10555 $imgmime = 'text.png';
10556 $famime = 'file-text-o';
10557 }
10558 if (preg_match('/\.ini$/i', $tmpfile)) {
10559 $mime = 'text/plain';
10560 $imgmime = 'text.png';
10561 $srclang = 'ini';
10562 $famime = 'file-text-o';
10563 }
10564 if (preg_match('/\.md$/i', $tmpfile)) {
10565 $mime = 'text/plain';
10566 $imgmime = 'text.png';
10567 $srclang = 'md';
10568 $famime = 'file-text-o';
10569 }
10570 if (preg_match('/\.css$/i', $tmpfile)) {
10571 $mime = 'text/css';
10572 $imgmime = 'css.png';
10573 $srclang = 'css';
10574 $famime = 'file-text-o';
10575 }
10576 if (preg_match('/\.lang$/i', $tmpfile)) {
10577 $mime = 'text/plain';
10578 $imgmime = 'text.png';
10579 $srclang = 'lang';
10580 $famime = 'file-text-o';
10581 }
10582 // Certificate files
10583 if (preg_match('/\.(crt|cer|key|pub)$/i', $tmpfile)) {
10584 $mime = 'text/plain';
10585 $imgmime = 'text.png';
10586 $famime = 'file-text-o';
10587 }
10588 // XML based (HTML/XML/XAML)
10589 if (preg_match('/\.(html|htm|shtml)$/i', $tmpfile)) {
10590 $mime = 'text/html';
10591 $imgmime = 'html.png';
10592 $srclang = 'html';
10593 $famime = 'file-text-o';
10594 }
10595 if (preg_match('/\.(xml|xhtml)$/i', $tmpfile)) {
10596 $mime = 'text/xml';
10597 $imgmime = 'other.png';
10598 $srclang = 'xml';
10599 $famime = 'file-text-o';
10600 }
10601 if (preg_match('/\.xaml$/i', $tmpfile)) {
10602 $mime = 'text/xml';
10603 $imgmime = 'other.png';
10604 $srclang = 'xaml';
10605 $famime = 'file-text-o';
10606 }
10607 // Languages
10608 if (preg_match('/\.bas$/i', $tmpfile)) {
10609 $mime = 'text/plain';
10610 $imgmime = 'text.png';
10611 $srclang = 'bas';
10612 $famime = 'file-code-o';
10613 }
10614 if (preg_match('/\.(c)$/i', $tmpfile)) {
10615 $mime = 'text/plain';
10616 $imgmime = 'text.png';
10617 $srclang = 'c';
10618 $famime = 'file-code-o';
10619 }
10620 if (preg_match('/\.(cpp)$/i', $tmpfile)) {
10621 $mime = 'text/plain';
10622 $imgmime = 'text.png';
10623 $srclang = 'cpp';
10624 $famime = 'file-code-o';
10625 }
10626 if (preg_match('/\.cs$/i', $tmpfile)) {
10627 $mime = 'text/plain';
10628 $imgmime = 'text.png';
10629 $srclang = 'cs';
10630 $famime = 'file-code-o';
10631 }
10632 if (preg_match('/\.(h)$/i', $tmpfile)) {
10633 $mime = 'text/plain';
10634 $imgmime = 'text.png';
10635 $srclang = 'h';
10636 $famime = 'file-code-o';
10637 }
10638 if (preg_match('/\.(java|jsp)$/i', $tmpfile)) {
10639 $mime = 'text/plain';
10640 $imgmime = 'text.png';
10641 $srclang = 'java';
10642 $famime = 'file-code-o';
10643 }
10644 if (preg_match('/\.php([0-9]{1})?$/i', $tmpfile)) {
10645 $mime = 'text/plain';
10646 $imgmime = 'php.png';
10647 $srclang = 'php';
10648 $famime = 'file-code-o';
10649 }
10650 if (preg_match('/\.phtml$/i', $tmpfile)) {
10651 $mime = 'text/plain';
10652 $imgmime = 'php.png';
10653 $srclang = 'php';
10654 $famime = 'file-code-o';
10655 }
10656 if (preg_match('/\.(pl|pm)$/i', $tmpfile)) {
10657 $mime = 'text/plain';
10658 $imgmime = 'pl.png';
10659 $srclang = 'perl';
10660 $famime = 'file-code-o';
10661 }
10662 if (preg_match('/\.sql$/i', $tmpfile)) {
10663 $mime = 'text/plain';
10664 $imgmime = 'text.png';
10665 $srclang = 'sql';
10666 $famime = 'file-code-o';
10667 }
10668 if (preg_match('/\.js$/i', $tmpfile)) {
10669 $mime = 'text/x-javascript';
10670 $imgmime = 'jscript.png';
10671 $srclang = 'js';
10672 $famime = 'file-code-o';
10673 }
10674 // Open office
10675 if (preg_match('/\.odp$/i', $tmpfile)) {
10676 $mime = 'application/vnd.oasis.opendocument.presentation';
10677 $imgmime = 'ooffice.png';
10678 $famime = 'file-powerpoint-o';
10679 }
10680 if (preg_match('/\.ods$/i', $tmpfile)) {
10681 $mime = 'application/vnd.oasis.opendocument.spreadsheet';
10682 $imgmime = 'ooffice.png';
10683 $famime = 'file-excel-o';
10684 }
10685 if (preg_match('/\.odt$/i', $tmpfile)) {
10686 $mime = 'application/vnd.oasis.opendocument.text';
10687 $imgmime = 'ooffice.png';
10688 $famime = 'file-word-o';
10689 }
10690 // MS Office
10691 if (preg_match('/\.mdb$/i', $tmpfile)) {
10692 $mime = 'application/msaccess';
10693 $imgmime = 'mdb.png';
10694 $famime = 'file-o';
10695 }
10696 if (preg_match('/\.doc[xm]?$/i', $tmpfile)) {
10697 $mime = 'application/msword';
10698 $imgmime = 'doc.png';
10699 $famime = 'file-word-o';
10700 }
10701 if (preg_match('/\.dot[xm]?$/i', $tmpfile)) {
10702 $mime = 'application/msword';
10703 $imgmime = 'doc.png';
10704 $famime = 'file-word-o';
10705 }
10706 if (preg_match('/\.xlt(x)?$/i', $tmpfile)) {
10707 $mime = 'application/vnd.ms-excel';
10708 $imgmime = 'xls.png';
10709 $famime = 'file-excel-o';
10710 }
10711 if (preg_match('/\.xla(m)?$/i', $tmpfile)) {
10712 $mime = 'application/vnd.ms-excel';
10713 $imgmime = 'xls.png';
10714 $famime = 'file-excel-o';
10715 }
10716 if (preg_match('/\.xls$/i', $tmpfile)) {
10717 $mime = 'application/vnd.ms-excel';
10718 $imgmime = 'xls.png';
10719 $famime = 'file-excel-o';
10720 }
10721 if (preg_match('/\.xls[bmx]$/i', $tmpfile)) {
10722 $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
10723 $imgmime = 'xls.png';
10724 $famime = 'file-excel-o';
10725 }
10726 if (preg_match('/\.pps[mx]?$/i', $tmpfile)) {
10727 $mime = 'application/vnd.ms-powerpoint';
10728 $imgmime = 'ppt.png';
10729 $famime = 'file-powerpoint-o';
10730 }
10731 if (preg_match('/\.ppt[mx]?$/i', $tmpfile)) {
10732 $mime = 'application/x-mspowerpoint';
10733 $imgmime = 'ppt.png';
10734 $famime = 'file-powerpoint-o';
10735 }
10736 // Other
10737 if (preg_match('/\.pdf$/i', $tmpfile)) {
10738 $mime = 'application/pdf';
10739 $imgmime = 'pdf.png';
10740 $famime = 'file-pdf-o';
10741 }
10742 // Scripts
10743 if (preg_match('/\.bat$/i', $tmpfile)) {
10744 $mime = 'text/x-bat';
10745 $imgmime = 'script.png';
10746 $srclang = 'dos';
10747 $famime = 'file-code-o';
10748 }
10749 if (preg_match('/\.sh$/i', $tmpfile)) {
10750 $mime = 'text/x-sh';
10751 $imgmime = 'script.png';
10752 $srclang = 'bash';
10753 $famime = 'file-code-o';
10754 }
10755 if (preg_match('/\.ksh$/i', $tmpfile)) {
10756 $mime = 'text/x-ksh';
10757 $imgmime = 'script.png';
10758 $srclang = 'bash';
10759 $famime = 'file-code-o';
10760 }
10761 if (preg_match('/\.bash$/i', $tmpfile)) {
10762 $mime = 'text/x-bash';
10763 $imgmime = 'script.png';
10764 $srclang = 'bash';
10765 $famime = 'file-code-o';
10766 }
10767 // Images
10768 if (preg_match('/\.ico$/i', $tmpfile)) {
10769 $mime = 'image/x-icon';
10770 $imgmime = 'image.png';
10771 $famime = 'file-image-o';
10772 }
10773 if (preg_match('/\.(jpg|jpeg)$/i', $tmpfile)) {
10774 $mime = 'image/jpeg';
10775 $imgmime = 'image.png';
10776 $famime = 'file-image-o';
10777 }
10778 if (preg_match('/\.png$/i', $tmpfile)) {
10779 $mime = 'image/png';
10780 $imgmime = 'image.png';
10781 $famime = 'file-image-o';
10782 }
10783 if (preg_match('/\.gif$/i', $tmpfile)) {
10784 $mime = 'image/gif';
10785 $imgmime = 'image.png';
10786 $famime = 'file-image-o';
10787 }
10788 if (preg_match('/\.bmp$/i', $tmpfile)) {
10789 $mime = 'image/bmp';
10790 $imgmime = 'image.png';
10791 $famime = 'file-image-o';
10792 }
10793 if (preg_match('/\.(tif|tiff)$/i', $tmpfile)) {
10794 $mime = 'image/tiff';
10795 $imgmime = 'image.png';
10796 $famime = 'file-image-o';
10797 }
10798 if (preg_match('/\.svg$/i', $tmpfile)) {
10799 $mime = 'image/svg+xml';
10800 $imgmime = 'image.png';
10801 $famime = 'file-image-o';
10802 }
10803 if (preg_match('/\.webp$/i', $tmpfile)) {
10804 $mime = 'image/webp';
10805 $imgmime = 'image.png';
10806 $famime = 'file-image-o';
10807 }
10808 // Calendar
10809 if (preg_match('/\.vcs$/i', $tmpfile)) {
10810 $mime = 'text/calendar';
10811 $imgmime = 'other.png';
10812 $famime = 'file-text-o';
10813 }
10814 if (preg_match('/\.ics$/i', $tmpfile)) {
10815 $mime = 'text/calendar';
10816 $imgmime = 'other.png';
10817 $famime = 'file-text-o';
10818 }
10819 // Other
10820 if (preg_match('/\.torrent$/i', $tmpfile)) {
10821 $mime = 'application/x-bittorrent';
10822 $imgmime = 'other.png';
10823 $famime = 'file-o';
10824 }
10825 // Audio
10826 if (preg_match('/\.(mp3|ogg|au|wav|wma|mid)$/i', $tmpfile)) {
10827 $mime = 'audio';
10828 $imgmime = 'audio.png';
10829 $famime = 'file-audio-o';
10830 }
10831 // Video
10832 if (preg_match('/\.mp4$/i', $tmpfile)) {
10833 $mime = 'video/mp4';
10834 $imgmime = 'video.png';
10835 $famime = 'file-video-o';
10836 }
10837 if (preg_match('/\.ogv$/i', $tmpfile)) {
10838 $mime = 'video/ogg';
10839 $imgmime = 'video.png';
10840 $famime = 'file-video-o';
10841 }
10842 if (preg_match('/\.webm$/i', $tmpfile)) {
10843 $mime = 'video/webm';
10844 $imgmime = 'video.png';
10845 $famime = 'file-video-o';
10846 }
10847 if (preg_match('/\.avi$/i', $tmpfile)) {
10848 $mime = 'video/x-msvideo';
10849 $imgmime = 'video.png';
10850 $famime = 'file-video-o';
10851 }
10852 if (preg_match('/\.divx$/i', $tmpfile)) {
10853 $mime = 'video/divx';
10854 $imgmime = 'video.png';
10855 $famime = 'file-video-o';
10856 }
10857 if (preg_match('/\.xvid$/i', $tmpfile)) {
10858 $mime = 'video/xvid';
10859 $imgmime = 'video.png';
10860 $famime = 'file-video-o';
10861 }
10862 if (preg_match('/\.(wmv|mpg|mpeg)$/i', $tmpfile)) {
10863 $mime = 'video';
10864 $imgmime = 'video.png';
10865 $famime = 'file-video-o';
10866 }
10867 // Archive
10868 if (preg_match('/\.(zip|rar|gz|tgz|z|cab|bz2|7z|tar|lzh|zst)$/i', $tmpfile)) {
10869 $mime = 'archive';
10870 $imgmime = 'archive.png';
10871 $famime = 'file-archive-o';
10872 } // application/xxx where zzz is zip, ...
10873 // Exe
10874 if (preg_match('/\.(exe|com)$/i', $tmpfile)) {
10875 $mime = 'application/octet-stream';
10876 $imgmime = 'other.png';
10877 $famime = 'file-o';
10878 }
10879 // Lib
10880 if (preg_match('/\.(dll|lib|o|so|a)$/i', $tmpfile)) {
10881 $mime = 'library';
10882 $imgmime = 'library.png';
10883 $famime = 'file-o';
10884 }
10885 // Err
10886 if (preg_match('/\.err$/i', $tmpfile)) {
10887 $mime = 'error';
10888 $imgmime = 'error.png';
10889 $famime = 'file-text-o';
10890 }
10891
10892 // Return string
10893 if ($mode == 1) {
10894 $tmp = explode('/', $mime);
10895 return (!empty($tmp[1]) ? $tmp[1] : $tmp[0]);
10896 }
10897 if ($mode == 2) {
10898 return $imgmime;
10899 }
10900 if ($mode == 3) {
10901 return $srclang;
10902 }
10903 if ($mode == 4) {
10904 return $famime;
10905 }
10906 return $mime;
10907}
10908
10920function getDictionaryValue($tablename, $field, $id, $checkentity = false, $rowidfield = 'rowid')
10921{
10922 global $conf, $db;
10923
10924 $tablename = preg_replace('/^'.preg_quote(MAIN_DB_PREFIX, '/').'/', '', $tablename); // Clean name of table for backward compatibility.
10925
10926 $dictvalues = (isset($conf->cache['dictvalues_'.$tablename]) ? $conf->cache['dictvalues_'.$tablename] : null);
10927
10928 if (is_null($dictvalues)) {
10929 $dictvalues = array();
10930
10931 $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
10932 if ($checkentity) {
10933 $sql .= ' AND entity IN (0,'.getEntity($tablename).')';
10934 }
10935
10936 $resql = $db->query($sql);
10937 if ($resql) {
10938 while ($obj = $db->fetch_object($resql)) {
10939 $dictvalues[$obj->{$rowidfield}] = $obj; // $obj is stdClass
10940 }
10941 } else {
10942 dol_print_error($db);
10943 }
10944
10945 $conf->cache['dictvalues_'.$tablename] = $dictvalues;
10946 }
10947
10948 if (!empty($dictvalues[$id])) {
10949 // Found
10950 $tmp = $dictvalues[$id];
10951 return (property_exists($tmp, $field) ? $tmp->$field : '');
10952 } else {
10953 // Not found
10954 return '';
10955 }
10956}
10957
10964function colorIsLight($stringcolor)
10965{
10966 $stringcolor = str_replace('#', '', $stringcolor);
10967 $res = -1;
10968 if (!empty($stringcolor)) {
10969 $res = 0;
10970 $tmp = explode(',', $stringcolor);
10971 if (count($tmp) > 1) { // This is a comma RGB ('255','255','255')
10972 $r = $tmp[0];
10973 $g = $tmp[1];
10974 $b = $tmp[2];
10975 } else {
10976 $hexr = $stringcolor[0].$stringcolor[1];
10977 $hexg = $stringcolor[2].$stringcolor[3];
10978 $hexb = $stringcolor[4].$stringcolor[5];
10979 $r = hexdec($hexr);
10980 $g = hexdec($hexg);
10981 $b = hexdec($hexb);
10982 }
10983 $bright = (max($r, $g, $b) + min($r, $g, $b)) / 510.0; // HSL algorithm
10984 if ($bright > 0.6) {
10985 $res = 1;
10986 }
10987 }
10988 return $res;
10989}
10990
10999function isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
11000{
11001 global $conf;
11002
11003 //print 'type_user='.$type_user.' module='.$menuentry['module'].' enabled='.$menuentry['enabled'].' perms='.$menuentry['perms'];
11004 //print 'ok='.in_array($menuentry['module'], $listofmodulesforexternal);
11005 if (empty($menuentry['enabled'])) {
11006 return 0; // Entry disabled by condition
11007 }
11008 if ($type_user && $menuentry['module']) {
11009 $tmploops = explode('|', $menuentry['module']);
11010 $found = 0;
11011 foreach ($tmploops as $tmploop) {
11012 if (in_array($tmploop, $listofmodulesforexternal)) {
11013 $found++;
11014 break;
11015 }
11016 }
11017 if (!$found) {
11018 return 0; // Entry is for menus all excluded to external users
11019 }
11020 }
11021 if (!$menuentry['perms'] && $type_user) {
11022 return 0; // No permissions and user is external
11023 }
11024 if (!$menuentry['perms'] && !empty($conf->global->MAIN_MENU_HIDE_UNAUTHORIZED)) {
11025 return 0; // No permissions and option to hide when not allowed, even for internal user, is on
11026 }
11027 if (!$menuentry['perms']) {
11028 return 2; // No permissions and user is external
11029 }
11030 return 1;
11031}
11032
11040function roundUpToNextMultiple($n, $x = 5)
11041{
11042 return (ceil($n) % $x === 0) ? ceil($n) : round(($n + $x / 2) / $x) * $x;
11043}
11044
11056function dolGetBadge($label, $html = '', $type = 'primary', $mode = '', $url = '', $params = array())
11057{
11058 $attr = array(
11059 'class'=>'badge '.(!empty($mode) ? ' badge-'.$mode : '').(!empty($type) ? ' badge-'.$type : '').(empty($params['css']) ? '' : ' '.$params['css'])
11060 );
11061
11062 if (empty($html)) {
11063 $html = $label;
11064 }
11065
11066 if (!empty($url)) {
11067 $attr['href'] = $url;
11068 }
11069
11070 if ($mode === 'dot') {
11071 $attr['class'] .= ' classfortooltip';
11072 $attr['title'] = $html;
11073 $attr['aria-label'] = $label;
11074 $html = '';
11075 }
11076
11077 // Override attr
11078 if (!empty($params['attr']) && is_array($params['attr'])) {
11079 foreach ($params['attr'] as $key => $value) {
11080 if ($key == 'class') {
11081 $attr['class'] .= ' '.$value;
11082 } elseif ($key == 'classOverride') {
11083 $attr['class'] = $value;
11084 } else {
11085 $attr[$key] = $value;
11086 }
11087 }
11088 }
11089
11090 // TODO: add hook
11091
11092 // escape all attribute
11093 $attr = array_map('dol_escape_htmltag', $attr);
11094
11095 $TCompiledAttr = array();
11096 foreach ($attr as $key => $value) {
11097 $TCompiledAttr[] = $key.'="'.$value.'"';
11098 }
11099
11100 $compiledAttributes = !empty($TCompiledAttr) ?implode(' ', $TCompiledAttr) : '';
11101
11102 $tag = !empty($url) ? 'a' : 'span';
11103
11104 return '<'.$tag.' '.$compiledAttributes.'>'.$html.'</'.$tag.'>';
11105}
11106
11107
11120function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $statusType = 'status0', $displayMode = 0, $url = '', $params = array())
11121{
11122 global $conf;
11123
11124 $return = '';
11125 $dolGetBadgeParams = array();
11126
11127 if (!empty($params['badgeParams'])) {
11128 $dolGetBadgeParams = $params['badgeParams'];
11129 }
11130
11131 // TODO : add a hook
11132 if ($displayMode == 0) {
11133 $return = !empty($html) ? $html : (empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort));
11134 } elseif ($displayMode == 1) {
11135 $return = !empty($html) ? $html : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11136 } elseif (!empty($conf->global->MAIN_STATUS_USES_IMAGES)) {
11137 // Use status with images (for backward compatibility)
11138 $return = '';
11139 $htmlLabel = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : $statusLabel).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
11140 $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>' : '');
11141
11142 // For small screen, we always use the short label instead of long label.
11143 if (!empty($conf->dol_optimize_smallscreen)) {
11144 if ($displayMode == 0) {
11145 $displayMode = 1;
11146 } elseif ($displayMode == 4) {
11147 $displayMode = 2;
11148 } elseif ($displayMode == 6) {
11149 $displayMode = 5;
11150 }
11151 }
11152
11153 // For backward compatibility. Image's filename are still in French, so we use this array to convert
11154 $statusImg = array(
11155 'status0' => 'statut0',
11156 'status1' => 'statut1',
11157 'status2' => 'statut2',
11158 'status3' => 'statut3',
11159 'status4' => 'statut4',
11160 'status5' => 'statut5',
11161 'status6' => 'statut6',
11162 'status7' => 'statut7',
11163 'status8' => 'statut8',
11164 'status9' => 'statut9'
11165 );
11166
11167 if (!empty($statusImg[$statusType])) {
11168 $htmlImg = img_picto($statusLabel, $statusImg[$statusType]);
11169 } else {
11170 $htmlImg = img_picto($statusLabel, $statusType);
11171 }
11172
11173 if ($displayMode === 2) {
11174 $return = $htmlImg.' '.$htmlLabelShort;
11175 } elseif ($displayMode === 3) {
11176 $return = $htmlImg;
11177 } elseif ($displayMode === 4) {
11178 $return = $htmlImg.' '.$htmlLabel;
11179 } elseif ($displayMode === 5) {
11180 $return = $htmlLabelShort.' '.$htmlImg;
11181 } else { // $displayMode >= 6
11182 $return = $htmlLabel.' '.$htmlImg;
11183 }
11184 } elseif (empty($conf->global->MAIN_STATUS_USES_IMAGES) && !empty($displayMode)) {
11185 // Use new badge
11186 $statusLabelShort = (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11187
11188 $dolGetBadgeParams['attr']['class'] = 'badge-status';
11189 $dolGetBadgeParams['attr']['title'] = empty($params['tooltip']) ? $statusLabel : ($params['tooltip'] != 'no' ? $params['tooltip'] : '');
11190
11191 if ($displayMode == 3) {
11192 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), '', $statusType, 'dot', $url, $dolGetBadgeParams);
11193 } elseif ($displayMode === 5) {
11194 $return = dolGetBadge($statusLabelShort, $html, $statusType, '', $url, $dolGetBadgeParams);
11195 } else {
11196 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), $html, $statusType, '', $url, $dolGetBadgeParams);
11197 }
11198 }
11199
11200 return $return;
11201}
11202
11203
11238function dolGetButtonAction($label, $text = '', $actionType = 'default', $url = '', $id = '', $userRight = 1, $params = array())
11239{
11240 global $hookmanager, $action, $object, $langs;
11241
11242 // If $url is an array, we must build a dropdown button
11243 if (is_array($url)) {
11244 $out = '<div class="dropdown inline-block dropdown-holder">';
11245 $out .= '<a style="margin-right: auto;" class="dropdown-toggle butAction" data-toggle="dropdown">'.$label.'</a>';
11246 $out .= '<div class="dropdown-content">';
11247 foreach ($url as $subbutton) {
11248 if ($subbutton['enabled'] && $subbutton['perm']) {
11249 if (!empty($subbutton['lang'])) {
11250 $langs->load($subbutton['lang']);
11251 }
11252 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage'])), '', 1, array('isDropDown' => true));
11253 }
11254 }
11255 $out .= "</div>";
11256 $out .= "</div>";
11257
11258 return $out;
11259 }
11260
11261 // If $url is a simple link
11262 if (!empty($params['isDropdown']))
11263 $class = "dropdown-item";
11264 else {
11265 $class = 'butAction';
11266 if ($actionType == 'danger' || $actionType == 'delete') {
11267 $class = 'butActionDelete';
11268 if (!empty($url) && strpos($url, 'token=') === false) $url .= '&token='.newToken();
11269 }
11270 }
11271 $attr = array(
11272 'class' => $class,
11273 'href' => empty($url) ? '' : $url,
11274 'title' => $label
11275 );
11276
11277 if (empty($text)) {
11278 $text = $label;
11279 $attr['title'] = ''; // if html not set, leave label on title is redundant
11280 } else {
11281 $attr['title'] = $label;
11282 $attr['aria-label'] = $label;
11283 }
11284
11285 if (empty($userRight)) {
11286 $attr['class'] = 'butActionRefused';
11287 $attr['href'] = '';
11288 $attr['title'] = (($label && $text && $label != $text) ? $label : $langs->trans('NotEnoughPermissions'));
11289 }
11290
11291 if (!empty($id)) {
11292 $attr['id'] = $id;
11293 }
11294
11295 // Override attr
11296 if (!empty($params['attr']) && is_array($params['attr'])) {
11297 foreach ($params['attr'] as $key => $value) {
11298 if ($key == 'class') {
11299 $attr['class'] .= ' '.$value;
11300 } elseif ($key == 'classOverride') {
11301 $attr['class'] = $value;
11302 } else {
11303 $attr[$key] = $value;
11304 }
11305 }
11306 }
11307
11308 // automatic add tooltip when title is detected
11309 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
11310 $attr['class'].= ' classfortooltip';
11311 }
11312
11313 // Js Confirm button
11314 if ($userRight && !empty($params['confirm'])) {
11315 if (!is_array($params['confirm'])) {
11316 $params['confirm'] = array();
11317 }
11318
11319 if (empty($params['confirm']['url'])) {
11320 $params['confirm']['url'] = $url . (strpos($url, '?') > 0 ? '&' : '?') . 'confirm=yes';
11321 }
11322
11323 // for js desabled compatibility set $url as call to confirm action and $params['confirm']['url'] to confirmed action
11324 $attr['data-confirm-url'] = $params['confirm']['url'];
11325 $attr['data-confirm-title'] = !empty($params['confirm']['title']) ? $params['confirm']['title'] : $langs->trans('ConfirmBtnCommonTitle', $label);
11326 $attr['data-confirm-content'] = !empty($params['confirm']['content']) ? $params['confirm']['content'] : $langs->trans('ConfirmBtnCommonContent', $label);
11327 $attr['data-confirm-content'] = preg_replace("/\r|\n/", "", $attr['data-confirm-content']);
11328 $attr['data-confirm-action-btn-label'] = !empty($params['confirm']['action-btn-label']) ? $params['confirm']['action-btn-label'] : $langs->trans('Confirm');
11329 $attr['data-confirm-cancel-btn-label'] = !empty($params['confirm']['cancel-btn-label']) ? $params['confirm']['cancel-btn-label'] : $langs->trans('CloseDialog');
11330 $attr['data-confirm-modal'] = !empty($params['confirm']['modal']) ? $params['confirm']['modal'] : true;
11331
11332 $attr['class'].= ' butActionConfirm';
11333 }
11334
11335 if (isset($attr['href']) && empty($attr['href'])) {
11336 unset($attr['href']);
11337 }
11338
11339 // escape all attribute
11340 $attr = array_map('dol_escape_htmltag', $attr);
11341
11342 $TCompiledAttr = array();
11343 foreach ($attr as $key => $value) {
11344 $TCompiledAttr[] = $key.'= "'.$value.'"';
11345 }
11346
11347 $compiledAttributes = empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr);
11348
11349 $tag = !empty($attr['href']) ? 'a' : 'span';
11350
11351
11352 $parameters = array(
11353 'TCompiledAttr' => $TCompiledAttr, // array
11354 'compiledAttributes' => $compiledAttributes, // string
11355 'attr' => $attr,
11356 'tag' => $tag,
11357 'label' => $label,
11358 'html' => $text,
11359 'actionType' => $actionType,
11360 'url' => $url,
11361 'id' => $id,
11362 'userRight' => $userRight,
11363 'params' => $params
11364 );
11365
11366 $reshook = $hookmanager->executeHooks('dolGetButtonAction', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
11367 if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
11368
11369 if (empty($reshook)) {
11370 if (dol_textishtml($text)) { // If content already HTML encoded
11371 return '<' . $tag . ' ' . $compiledAttributes . '>' . $text . '</' . $tag . '>';
11372 } else {
11373 return '<' . $tag . ' ' . $compiledAttributes . '>' . dol_escape_htmltag($text) . '</' . $tag . '>';
11374 }
11375 } else {
11376 return $hookmanager->resPrint;
11377 }
11378}
11379
11386function dolGetButtonTitleSeparator($moreClass = "")
11387{
11388 return '<span class="button-title-separator '.$moreClass.'" ></span>';
11389}
11390
11397function getFieldErrorIcon($fieldValidationErrorMsg)
11398{
11399 $out = '';
11400 if (!empty($fieldValidationErrorMsg)) {
11401 $out.= '<span class="field-error-icon classfortooltip" title="'.dol_escape_htmltag($fieldValidationErrorMsg, 1).'" role="alert" >'; // role alert is used for accessibility
11402 $out.= '<span class="fa fa-exclamation-circle" aria-hidden="true" ></span>'; // For accessibility icon is separated and aria-hidden
11403 $out.= '</span>';
11404 }
11405
11406 return $out;
11407}
11408
11421function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $url = '', $id = '', $status = 1, $params = array())
11422{
11423 global $langs, $conf, $user;
11424
11425 // Actually this conf is used in css too for external module compatibility and smooth transition to this function
11426 if (!empty($conf->global->MAIN_BUTTON_HIDE_UNAUTHORIZED) && (!$user->admin) && $status <= 0) {
11427 return '';
11428 }
11429
11430 $class = 'btnTitle';
11431 if (in_array($iconClass, array('fa fa-plus-circle', 'fa fa-plus-circle size15x', 'fa fa-comment-dots', 'fa fa-paper-plane'))) {
11432 $class .= ' btnTitlePlus';
11433 }
11434 $useclassfortooltip = 1;
11435
11436 if (!empty($params['morecss'])) {
11437 $class .= ' '.$params['morecss'];
11438 }
11439
11440 $attr = array(
11441 'class' => $class,
11442 'href' => empty($url) ? '' : $url
11443 );
11444
11445 if (!empty($helpText)) {
11446 $attr['title'] = dol_escape_htmltag($helpText);
11447 } elseif (empty($attr['title']) && $label) {
11448 $attr['title'] = $label;
11449 $useclassfortooltip = 0;
11450 }
11451
11452 if ($status == 2) {
11453 $attr['class'] .= ' btnTitleSelected';
11454 } elseif ($status <= 0) {
11455 $attr['class'] .= ' refused';
11456
11457 $attr['href'] = '';
11458
11459 if ($status == -1) { // disable
11460 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("FeatureDisabled"));
11461 } elseif ($status == 0) { // Not enough permissions
11462 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions"));
11463 }
11464 }
11465
11466 if (!empty($attr['title']) && $useclassfortooltip) {
11467 $attr['class'] .= ' classfortooltip';
11468 }
11469
11470 if (!empty($id)) {
11471 $attr['id'] = $id;
11472 }
11473
11474 // Override attr
11475 if (!empty($params['attr']) && is_array($params['attr'])) {
11476 foreach ($params['attr'] as $key => $value) {
11477 if ($key == 'class') {
11478 $attr['class'] .= ' '.$value;
11479 } elseif ($key == 'classOverride') {
11480 $attr['class'] = $value;
11481 } else {
11482 $attr[$key] = $value;
11483 }
11484 }
11485 }
11486
11487 if (isset($attr['href']) && empty($attr['href'])) {
11488 unset($attr['href']);
11489 }
11490
11491 // TODO : add a hook
11492
11493 // escape all attribute
11494 $attr = array_map('dol_escape_htmltag', $attr);
11495
11496 $TCompiledAttr = array();
11497 foreach ($attr as $key => $value) {
11498 $TCompiledAttr[] = $key.'="'.$value.'"';
11499 }
11500
11501 $compiledAttributes = (empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr));
11502
11503 $tag = (empty($attr['href']) ? 'span' : 'a');
11504
11505 $button = '<'.$tag.' '.$compiledAttributes.'>';
11506 $button .= '<span class="'.$iconClass.' valignmiddle btnTitle-icon"></span>';
11507 if (!empty($params['forcenohideoftext'])) {
11508 $button .= '<span class="valignmiddle text-plus-circle btnTitle-label'.(empty($params['forcenohideoftext']) ? ' hideonsmartphone' : '').'">'.$label.'</span>';
11509 }
11510 $button .= '</'.$tag.'>';
11511
11512 return $button;
11513}
11514
11525function getElementProperties($element_type)
11526{
11527 global $conf;
11528
11529 $regs = array();
11530
11531 $classfile = $classname = $classpath = $subdir = $dir_output = '';
11532
11533 // Parse element/subelement
11534 $module = $element_type;
11535 $element = $element_type;
11536 $subelement = $element_type;
11537
11538 // If we ask a resource form external module (instead of default path)
11539 if (preg_match('/^([^@]+)@([^@]+)$/i', $element_type, $regs)) { // 'myobject@mymodule'
11540 $element = $subelement = $regs[1];
11541 $module = $regs[2];
11542 }
11543
11544 // If we ask a resource for a string with an element and a subelement
11545 // Example 'project_task'
11546 if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { // 'myobject_mysubobject' with myobject=mymodule
11547 $module = $element = $regs[1];
11548 $subelement = $regs[2];
11549 }
11550
11551 // For compat and To work with non standard path
11552 if ($element_type == "action") {
11553 $classpath = 'comm/action/class';
11554 $subelement = 'Actioncomm';
11555 $module = 'agenda';
11556 } elseif ($element_type == 'cronjob') {
11557 $classpath = 'cron/class';
11558 $module = 'cron';
11559 } elseif ($element_type == 'adherent_type') {
11560 $classpath = 'adherents/class';
11561 $classfile = 'adherent_type';
11562 $module = 'adherent';
11563 $subelement = 'adherent_type';
11564 $classname = 'AdherentType';
11565 } elseif ($element_type == 'bank_account') {
11566 $classpath = 'compta/bank/class';
11567 $module = 'bank'; // We need $conf->bank->dir_output and not $conf->banque->dir_output
11568 $classfile = 'account';
11569 $classname = 'Account';
11570 } elseif ($element_type == 'category') {
11571 $classpath = 'categories/class';
11572 $module = 'categorie';
11573 $subelement = 'categorie';
11574 } elseif ($element_type == 'contact') {
11575 $classpath = 'contact/class';
11576 $classfile = 'contact';
11577 $module = 'societe';
11578 $subelement = 'contact';
11579 } elseif ($element_type == 'stock') {
11580 $classpath = 'product/stock/class';
11581 $classfile = 'entrepot';
11582 $classname = 'Entrepot';
11583 } elseif ($element_type == 'project') {
11584 $classpath = 'projet/class';
11585 $module = 'projet';
11586 } elseif ($element_type == 'project_task') {
11587 $classpath = 'projet/class';
11588 $module = 'projet';
11589 $subelement = 'task';
11590 } elseif ($element_type == 'facture' || $element_type == 'invoice') {
11591 $classpath = 'compta/facture/class';
11592 $module = 'facture';
11593 $subelement = 'facture';
11594 } elseif ($element_type == 'commande' || $element_type == 'order') {
11595 $classpath = 'commande/class';
11596 $module = 'commande';
11597 $subelement = 'commande';
11598 } elseif ($element_type == 'propal') {
11599 $classpath = 'comm/propal/class';
11600 } elseif ($element_type == 'shipping') {
11601 $classpath = 'expedition/class';
11602 $classfile = 'expedition';
11603 $classname = 'Expedition';
11604 $module = 'expedition';
11605 } elseif ($element_type == 'supplier_proposal') {
11606 $classpath = 'supplier_proposal/class';
11607 $module = 'supplier_proposal';
11608 $element = 'supplierproposal';
11609 $classfile = 'supplier_proposal';
11610 $subelement = 'supplierproposal';
11611 } elseif ($element_type == 'shipping') {
11612 $classpath = 'expedition/class';
11613 $subelement = 'expedition';
11614 $module = 'expedition_bon';
11615 } elseif ($element_type == 'delivery') {
11616 $classpath = 'delivery/class';
11617 $subelement = 'delivery';
11618 $module = 'delivery_note';
11619 } elseif ($element_type == 'contract') {
11620 $classpath = 'contrat/class';
11621 $module = 'contrat';
11622 $subelement = 'contrat';
11623 } elseif ($element_type == 'mailing') {
11624 $classpath = 'comm/mailing/class';
11625 $module = 'mailing';
11626 $classfile = 'mailing';
11627 $classname = 'Mailing';
11628 $subelement = '';
11629 } elseif ($element_type == 'member') {
11630 $classpath = 'adherents/class';
11631 $module = 'adherent';
11632 $subelement = 'adherent';
11633 } elseif ($element_type == 'usergroup') {
11634 $classpath = 'user/class';
11635 $module = 'user';
11636 } elseif ($element_type == 'mo') {
11637 $classpath = 'mrp/class';
11638 $classfile = 'mo';
11639 $classname = 'Mo';
11640 $module = 'mrp';
11641 $subelement = '';
11642 } elseif ($element_type == 'cabinetmed_cons') {
11643 $classpath = 'cabinetmed/class';
11644 $module = 'cabinetmed';
11645 $subelement = 'cabinetmedcons';
11646 } elseif ($element_type == 'fichinter') {
11647 $classpath = 'fichinter/class';
11648 $module = 'ficheinter';
11649 $subelement = 'fichinter';
11650 } elseif ($element_type == 'dolresource' || $element_type == 'resource') {
11651 $classpath = 'resource/class';
11652 $module = 'resource';
11653 $subelement = 'dolresource';
11654 } elseif ($element_type == 'propaldet') {
11655 $classpath = 'comm/propal/class';
11656 $module = 'propal';
11657 $subelement = 'propaleligne';
11658 } elseif ($element_type == 'opensurvey_sondage') {
11659 $classpath = 'opensurvey/class';
11660 $module = 'opensurvey';
11661 $subelement = 'opensurveysondage';
11662 } elseif ($element_type == 'order_supplier') {
11663 $classpath = 'fourn/class';
11664 $module = 'fournisseur';
11665 $classfile = 'fournisseur.commande';
11666 $element = 'order_supplier';
11667 $subelement = '';
11668 $classname = 'CommandeFournisseur';
11669 } elseif ($element_type == 'invoice_supplier') {
11670 $classpath = 'fourn/class';
11671 $module = 'fournisseur';
11672 $classfile = 'fournisseur.facture';
11673 $element = 'invoice_supplier';
11674 $subelement = '';
11675 $classname = 'FactureFournisseur';
11676 } elseif ($element_type == "service") {
11677 $classpath = 'product/class';
11678 $subelement = 'product';
11679 } elseif ($element_type == 'salary') {
11680 $classpath = 'salaries/class';
11681 $module = 'salaries';
11682 } elseif ($element_type == 'productlot') {
11683 $module = 'productbatch';
11684 $classpath = 'product/stock/class';
11685 $classfile = 'productlot';
11686 $classname = 'Productlot';
11687 $element = 'productlot';
11688 $subelement = '';
11689 } elseif ($element_type == 'websitepage') {
11690 $classpath = 'website/class';
11691 $classfile = 'websitepage';
11692 $classname = 'Websitepage';
11693 $module = 'website';
11694 $subelement = 'websitepage';
11695 } elseif ($element_type == 'fiscalyear') {
11696 $classpath = 'core/class';
11697 $module = 'accounting';
11698 $subelement = 'fiscalyear';
11699 } elseif ($element_type == 'chargesociales') {
11700 $classpath = 'compta/sociales/class';
11701 $module = 'tax';
11702 } elseif ($element_type == 'tva') {
11703 $classpath = 'compta/tva/class';
11704 $module = 'tax';
11705 $subdir = '/vat';
11706 }
11707
11708 if (empty($classfile)) {
11709 $classfile = strtolower($subelement);
11710 }
11711 if (empty($classname)) {
11712 $classname = ucfirst($subelement);
11713 }
11714 if (empty($classpath)) {
11715 $classpath = $module.'/class';
11716 }
11717
11718 //print 'getElementProperties subdir='.$subdir;
11719
11720 // Set dir_output
11721 if ($module && isset($conf->$module)) { // The generic case
11722 if (!empty($conf->$module->multidir_output[$conf->entity])) {
11723 $dir_output = $conf->$module->multidir_output[$conf->entity];
11724 } elseif (!empty($conf->$module->output[$conf->entity])) {
11725 $dir_output = $conf->$module->output[$conf->entity];
11726 } elseif (!empty($conf->$module->dir_output)) {
11727 $dir_output = $conf->$module->dir_output;
11728 }
11729 }
11730
11731 // Overwrite value for special cases
11732 if ($element == 'order_supplier') {
11733 $dir_output = $conf->fournisseur->commande->dir_output;
11734 } elseif ($element == 'invoice_supplier') {
11735 $dir_output = $conf->fournisseur->facture->dir_output;
11736 }
11737 $dir_output .= $subdir;
11738
11739 $element_properties = array(
11740 'module' => $module,
11741 'element' => $element,
11742 'subelement' => $subelement,
11743 'classpath' => $classpath,
11744 'classfile' => $classfile,
11745 'classname' => $classname,
11746 'dir_output' => $dir_output
11747 );
11748 return $element_properties;
11749}
11750
11760function fetchObjectByElement($element_id, $element_type, $element_ref = '')
11761{
11762 global $db;
11763
11764 $ret = 0;
11765
11766 $element_prop = getElementProperties($element_type);
11767
11768 if (is_array($element_prop) && isModEnabled($element_prop['module'])) {
11769 dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php');
11770
11771 if (class_exists($element_prop['classname'])) {
11772 $classname = $element_prop['classname'];
11773 $objecttmp = new $classname($db);
11774 $ret = $objecttmp->fetch($element_id, $element_ref);
11775 if ($ret >= 0) {
11776 if (empty($objecttmp->module)) {
11777 $objecttmp->module = $element_prop['module'];
11778 }
11779
11780 return $objecttmp;
11781 }
11782 } else {
11783 return -1;
11784 }
11785 }
11786
11787 return $ret;
11788}
11789
11797{
11798 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)) {
11799 return true;
11800 }
11801
11802 return false;
11803}
11804
11812function newToken()
11813{
11814 return empty($_SESSION['newtoken']) ? '' : $_SESSION['newtoken'];
11815}
11816
11825{
11826 return isset($_SESSION['token']) ? $_SESSION['token'] : '';
11827}
11828
11834function getNonce()
11835{
11836 global $conf;
11837
11838 if (empty($conf->cache['nonce'])) {
11839 $conf->cache['nonce'] = dolGetRandomBytes(8);
11840 }
11841
11842 return $conf->cache['nonce'];
11843}
11844
11845
11858function startSimpleTable($header, $link = "", $arguments = "", $emptyRows = 0, $number = -1)
11859{
11860 global $langs;
11861
11862 print '<div class="div-table-responsive-no-min">';
11863 print '<table class="noborder centpercent">';
11864 print '<tr class="liste_titre">';
11865
11866 print $emptyRows < 1 ? '<th>' : '<th colspan="'.($emptyRows + 1).'">';
11867
11868 print $langs->trans($header);
11869
11870 // extra space between the first header and the number
11871 if ($number > -1) {
11872 print ' ';
11873 }
11874
11875 if (!empty($link)) {
11876 if (!empty($arguments)) {
11877 print '<a href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
11878 } else {
11879 print '<a href="'.DOL_URL_ROOT.'/'.$link.'">';
11880 }
11881 }
11882
11883 if ($number > -1) {
11884 print '<span class="badge">'.$number.'</span>';
11885 }
11886
11887 if (!empty($link)) {
11888 print '</a>';
11889 }
11890
11891 print '</th>';
11892
11893 if ($number < 0 && !empty($link)) {
11894 print '<th class="right">';
11895
11896 if (!empty($arguments)) {
11897 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
11898 } else {
11899 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'">';
11900 }
11901
11902 print $langs->trans("FullList");
11903 print '</a>';
11904 print '</th>';
11905 }
11906
11907 print '</tr>';
11908}
11909
11918function finishSimpleTable($addLineBreak = false)
11919{
11920 print '</table>';
11921 print '</div>';
11922
11923 if ($addLineBreak) {
11924 print '<br>';
11925 }
11926}
11927
11939function addSummaryTableLine($tableColumnCount, $num, $nbofloop = 0, $total = 0, $noneWord = "None", $extraRightColumn = false)
11940{
11941 global $langs;
11942
11943 if ($num === 0) {
11944 print '<tr class="oddeven">';
11945 print '<td colspan="'.$tableColumnCount.'" class="opacitymedium">'.$langs->trans($noneWord).'</td>';
11946 print '</tr>';
11947 return;
11948 }
11949
11950 if ($nbofloop === 0) {
11951 // don't show a summary line
11952 return;
11953 }
11954
11955 if ($num === 0) {
11956 $colspan = $tableColumnCount;
11957 } elseif ($num > $nbofloop) {
11958 $colspan = $tableColumnCount;
11959 } else {
11960 $colspan = $tableColumnCount - 1;
11961 }
11962
11963 if ($extraRightColumn) {
11964 $colspan--;
11965 }
11966
11967 print '<tr class="liste_total">';
11968
11969 if ($nbofloop > 0 && $num > $nbofloop) {
11970 print '<td colspan="'.$colspan.'" class="right">'.$langs->trans("XMoreLines", ($num - $nbofloop)).'</td>';
11971 } else {
11972 print '<td colspan="'.$colspan.'" class="right"> '.$langs->trans("Total").'</td>';
11973 print '<td class="right" width="100">'.price($total).'</td>';
11974 }
11975
11976 if ($extraRightColumn) {
11977 print '<td></td>';
11978 }
11979
11980 print '</tr>';
11981}
11982
11991function readfileLowMemory($fullpath_original_file_osencoded, $method = -1)
11992{
11993 global $conf;
11994
11995 if ($method == -1) {
11996 $method = 0;
11997 if (!empty($conf->global->MAIN_FORCE_READFILE_WITH_FREAD)) {
11998 $method = 1;
11999 }
12000 if (!empty($conf->global->MAIN_FORCE_READFILE_WITH_STREAM_COPY)) {
12001 $method = 2;
12002 }
12003 }
12004
12005 // Be sure we don't have output buffering enabled to have readfile working correctly
12006 while (ob_get_level()) {
12007 ob_end_flush();
12008 }
12009
12010 // Solution 0
12011 if ($method == 0) {
12012 readfile($fullpath_original_file_osencoded);
12013 } elseif ($method == 1) {
12014 // Solution 1
12015 $handle = fopen($fullpath_original_file_osencoded, "rb");
12016 while (!feof($handle)) {
12017 print fread($handle, 8192);
12018 }
12019 fclose($handle);
12020 } elseif ($method == 2) {
12021 // Solution 2
12022 $handle1 = fopen($fullpath_original_file_osencoded, "rb");
12023 $handle2 = fopen("php://output", "wb");
12024 stream_copy_to_stream($handle1, $handle2);
12025 fclose($handle1);
12026 fclose($handle2);
12027 }
12028}
12029
12039function showValueWithClipboardCPButton($valuetocopy, $showonlyonhover = 1, $texttoshow = '')
12040{
12041 /*
12042 global $conf;
12043
12044 if (!empty($conf->dol_no_mouse_hover)) {
12045 $showonlyonhover = 0;
12046 }*/
12047
12048 $tag = 'span'; // Using div (like any style of type 'block') does not work when using the js copy code.
12049 if ($texttoshow === 'none') {
12050 $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>';
12051 } elseif ($texttoshow) {
12052 $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>';
12053 } else {
12054 $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>';
12055 }
12056
12057 return $result;
12058}
12059
12060
12067function jsonOrUnserialize($stringtodecode)
12068{
12069 $result = json_decode($stringtodecode);
12070 if ($result === null) {
12071 $result = unserialize($stringtodecode);
12072 }
12073
12074 return $result;
12075}
12076
12077
12091function forgeSQLFromUniversalSearchCriteria($filter, &$errorstr = '', $noand = 0, $nopar = 0, $noerror = 0)
12092{
12093 if (!preg_match('/^\‍(.*\‍)$/', $filter)) { // If $filter does not start and end with ()
12094 $filter = '(' . $filter . ')';
12095 }
12096
12097 $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'
12098
12099 if (!dolCheckFilters($filter, $errorstr)) {
12100 if ($noerror) {
12101 return '1 = 2';
12102 } else {
12103 return 'Filter syntax error - '.$errorstr; // Bad balance of parenthesis, we return an error message or force a SQL not found
12104 }
12105 }
12106
12107 // Test the filter syntax
12108 $t = preg_replace_callback('/'.$regexstring.'/i', 'dolForgeDummyCriteriaCallback', $filter);
12109 $t = str_replace(array('and','or','AND','OR',' '), '', $t); // Remove the only strings allowed between each () criteria
12110 // If the string result contains something else than '()', the syntax was wrong
12111 if (preg_match('/[^\‍(\‍)]/', $t)) {
12112 $errorstr = 'Bad syntax of the search string';
12113 if ($noerror) {
12114 return '1 = 2';
12115 } else {
12116 return 'Filter syntax error - '.$errorstr; // Bad syntax of the search string, we return an error message or force a SQL not found
12117 }
12118 }
12119
12120 return ($noand ? "" : " AND ").($nopar ? "" : '(').preg_replace_callback('/'.$regexstring.'/i', 'dolForgeCriteriaCallback', $filter).($nopar ? "" : ')');
12121}
12122
12130function dolCheckFilters($sqlfilters, &$error = '')
12131{
12132 //$regexstring='\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^:\‍(\‍)]+)\‍)';
12133 //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
12134 $tmp = $sqlfilters;
12135 $i = 0; $nb = strlen($tmp);
12136 $counter = 0;
12137 while ($i < $nb) {
12138 if ($tmp[$i] == '(') {
12139 $counter++;
12140 }
12141 if ($tmp[$i] == ')') {
12142 $counter--;
12143 }
12144 if ($counter < 0) {
12145 $error = "Wrond balance of parenthesis in sqlfilters=".$sqlfilters;
12146 dol_syslog($error, LOG_WARNING);
12147 return false;
12148 }
12149 $i++;
12150 }
12151 return true;
12152}
12153
12162{
12163 //dol_syslog("Convert matches ".$matches[1]);
12164 if (empty($matches[1])) {
12165 return '';
12166 }
12167 $tmp = explode(':', $matches[1]);
12168 if (count($tmp) < 3) {
12169 return '';
12170 }
12171
12172 return '()'; // An empty criteria
12173}
12174
12184{
12185 global $db;
12186
12187 //dol_syslog("Convert matches ".$matches[1]);
12188 if (empty($matches[1])) {
12189 return '';
12190 }
12191 $tmp = explode(':', $matches[1]);
12192 if (count($tmp) < 3) {
12193 return '';
12194 }
12195
12196 $operand = preg_replace('/[^a-z0-9\._]/i', '', trim($tmp[0]));
12197
12198 $operator = strtoupper(preg_replace('/[^a-z<>!=]/i', '', trim($tmp[1])));
12199
12200 if ($operator == 'NOTLIKE') {
12201 $operator = 'NOT LIKE';
12202 }
12203 if ($operator == 'ISNOT') {
12204 $operator = 'IS NOT';
12205 }
12206 if ($operator == '!=') {
12207 $operator = '<>';
12208 }
12209
12210 $tmpescaped = $tmp[2];
12211 $regbis = array();
12212
12213 if ($operator == 'IN') { // IN is allowed for list of ID or code only
12214 //if (!preg_match('/^\‍(.*\‍)$/', $tmpescaped)) {
12215 $tmpescaped = '('.$db->escape($db->sanitize($tmpescaped, 1, 0)).')';
12216 //} else {
12217 // $tmpescaped = $db->escape($db->sanitize($tmpescaped, 1));
12218 //}
12219 } elseif ($operator == 'LIKE' || $operator == 'NOT LIKE') {
12220 if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12221 $tmpescaped = $regbis[1];
12222 }
12223 //$tmpescaped = "'".$db->escapeforlike($db->escape($regbis[1]))."'";
12224 $tmpescaped = "'".$db->escape($tmpescaped)."'"; // We do not escape the _ and % so the like will works
12225 } elseif (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12226 $tmpescaped = "'".$db->escape($regbis[1])."'";
12227 } else {
12228 if (strtoupper($tmpescaped) == 'NULL') {
12229 $tmpescaped = 'NULL';
12230 } elseif (is_int($tmpescaped)) {
12231 $tmpescaped = (int) $tmpescaped;
12232 } else {
12233 $tmpescaped = (float) $tmpescaped;
12234 }
12235 }
12236
12237 return '('.$db->escape($operand).' '.strtoupper($operator).' '.$tmpescaped.')';
12238}
12239
12240
12249function getTimelineIcon($actionstatic, &$histo, $key)
12250{
12251 global $conf, $langs;
12252 $out = '<!-- timeline icon -->'."\n";
12253 $iconClass = 'fa fa-comments';
12254 $img_picto = '';
12255 $colorClass = '';
12256 $pictoTitle = '';
12257
12258 if ($histo[$key]['percent'] == -1) {
12259 $colorClass = 'timeline-icon-not-applicble';
12260 $pictoTitle = $langs->trans('StatusNotApplicable');
12261 } elseif ($histo[$key]['percent'] == 0) {
12262 $colorClass = 'timeline-icon-todo';
12263 $pictoTitle = $langs->trans('StatusActionToDo').' (0%)';
12264 } elseif ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100) {
12265 $colorClass = 'timeline-icon-in-progress';
12266 $pictoTitle = $langs->trans('StatusActionInProcess').' ('.$histo[$key]['percent'].'%)';
12267 } elseif ($histo[$key]['percent'] >= 100) {
12268 $colorClass = 'timeline-icon-done';
12269 $pictoTitle = $langs->trans('StatusActionDone').' (100%)';
12270 }
12271
12272 if ($actionstatic->code == 'AC_TICKET_CREATE') {
12273 $iconClass = 'fa fa-ticket';
12274 } elseif ($actionstatic->code == 'AC_TICKET_MODIFY') {
12275 $iconClass = 'fa fa-pencilxxx';
12276 } elseif (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12277 $iconClass = 'fa fa-comments';
12278 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12279 $iconClass = 'fa fa-mask';
12280 } elseif (!empty($conf->global->AGENDA_USE_EVENT_TYPE)) {
12281 if ($actionstatic->type_picto) {
12282 $img_picto = img_picto('', $actionstatic->type_picto);
12283 } else {
12284 if ($actionstatic->type_code == 'AC_RDV') {
12285 $iconClass = 'fa fa-handshake';
12286 } elseif ($actionstatic->type_code == 'AC_TEL') {
12287 $iconClass = 'fa fa-phone';
12288 } elseif ($actionstatic->type_code == 'AC_FAX') {
12289 $iconClass = 'fa fa-fax';
12290 } elseif ($actionstatic->type_code == 'AC_EMAIL') {
12291 $iconClass = 'fa fa-envelope';
12292 } elseif ($actionstatic->type_code == 'AC_INT') {
12293 $iconClass = 'fa fa-shipping-fast';
12294 } elseif ($actionstatic->type_code == 'AC_OTH_AUTO') {
12295 $iconClass = 'fa fa-robot';
12296 } elseif (!preg_match('/_AUTO/', $actionstatic->type_code)) {
12297 $iconClass = 'fa fa-robot';
12298 }
12299 }
12300 }
12301
12302 $out .= '<i class="'.$iconClass.' '.$colorClass.'" title="'.$pictoTitle.'">'.$img_picto.'</i>'."\n";
12303 return $out;
12304}
12305
12312function getActionCommEcmList($object)
12313{
12314 global $conf, $db;
12315
12316 $documents = array();
12317
12318 $sql = 'SELECT ecm.rowid as id, ecm.src_object_type, ecm.src_object_id, ecm.filepath, ecm.filename';
12319 $sql .= ' FROM '.MAIN_DB_PREFIX.'ecm_files ecm';
12320 $sql .= " WHERE ecm.filepath = 'agenda/".((int) $object->id)."'";
12321 //$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
12322 $sql .= ' ORDER BY ecm.position ASC';
12323
12324 $resql = $db->query($sql);
12325 if ($resql) {
12326 if ($db->num_rows($resql)) {
12327 while ($obj = $db->fetch_object($resql)) {
12328 $documents[$obj->id] = $obj;
12329 }
12330 }
12331 }
12332
12333 return $documents;
12334}
12335
12336
12337
12355function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
12356{
12357 global $user, $conf;
12358 global $form;
12359
12360 global $param, $massactionbutton;
12361
12362 dol_include_once('/comm/action/class/actioncomm.class.php');
12363
12364 // Check parameters
12365 if (!is_object($filterobj) && !is_object($objcon)) {
12366 dol_print_error('', 'BadParameter');
12367 }
12368
12369 $histo = array();
12370 $numaction = 0;
12371 $now = dol_now();
12372
12373 $sortfield_list = explode(',', $sortfield);
12374 $sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent');
12375 $sortfield_new_list = array();
12376 foreach ($sortfield_list as $sortfield_value) {
12377 $sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)];
12378 }
12379 $sortfield_new = implode(',', $sortfield_new_list);
12380
12381 if (isModEnabled('agenda')) {
12382 // Search histo on actioncomm
12383 if (is_object($objcon) && $objcon->id > 0) {
12384 $sql = "SELECT DISTINCT a.id, a.label as label,";
12385 } else {
12386 $sql = "SELECT a.id, a.label as label,";
12387 }
12388 $sql .= " a.datep as dp,";
12389 $sql .= " a.note as message,";
12390 $sql .= " a.datep2 as dp2,";
12391 $sql .= " a.percent as percent, 'action' as type,";
12392 $sql .= " a.fk_element, a.elementtype,";
12393 $sql .= " a.fk_contact,";
12394 $sql .= " a.email_from as msg_from,";
12395 $sql .= " c.code as acode, c.libelle as alabel, c.picto as apicto,";
12396 $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";
12397 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12398 $sql .= ", sp.lastname, sp.firstname";
12399 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12400 $sql .= ", m.lastname, m.firstname";
12401 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12402 $sql .= ", o.ref";
12403 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12404 $sql .= ", o.ref";
12405 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12406 $sql .= ", o.ref";
12407 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12408 $sql .= ", o.ref";
12409 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12410 $sql .= ", o.ref";
12411 }
12412 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
12413 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
12414 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
12415
12416 $force_filter_contact = false;
12417 if (is_object($objcon) && $objcon->id > 0) {
12418 $force_filter_contact = true;
12419 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
12420 $sql .= " AND r.element_type = '".$db->escape($objcon->table_element)."' AND r.fk_element = ".((int) $objcon->id);
12421 }
12422
12423 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12424 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
12425 } elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
12426 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er";
12427 $sql .= " ON er.resource_type = 'dolresource'";
12428 $sql .= " AND er.element_id = a.id";
12429 $sql .= " AND er.resource_id = ".((int) $filterobj->id);
12430 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12431 $sql .= ", ".MAIN_DB_PREFIX."adherent as m";
12432 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12433 $sql .= ", ".MAIN_DB_PREFIX."commande_fournisseur as o";
12434 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12435 $sql .= ", ".MAIN_DB_PREFIX."product as o";
12436 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12437 $sql .= ", ".MAIN_DB_PREFIX."ticket as o";
12438 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12439 $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o";
12440 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12441 $sql .= ", ".MAIN_DB_PREFIX."contrat as o";
12442 }
12443
12444 $sql .= " WHERE a.entity IN (".getEntity('agenda').")";
12445 if ($force_filter_contact === false) {
12446 if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) {
12447 $sql .= " AND a.fk_soc = ".((int) $filterobj->id);
12448 } elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) {
12449 $sql .= " AND a.fk_project = ".((int) $filterobj->id);
12450 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12451 $sql .= " AND a.fk_element = m.rowid AND a.elementtype = 'member'";
12452 if ($filterobj->id) {
12453 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12454 }
12455 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12456 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'order_supplier'";
12457 if ($filterobj->id) {
12458 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12459 }
12460 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12461 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
12462 if ($filterobj->id) {
12463 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12464 }
12465 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12466 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'ticket'";
12467 if ($filterobj->id) {
12468 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12469 }
12470 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12471 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'bom'";
12472 if ($filterobj->id) {
12473 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12474 }
12475 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12476 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'contract'";
12477 if ($filterobj->id) {
12478 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12479 }
12480 }
12481 }
12482
12483 // Condition on actioncode
12484 if (!empty($actioncode)) {
12485 if (empty($conf->global->AGENDA_USE_EVENT_TYPE)) {
12486 if ($actioncode == 'AC_NON_AUTO') {
12487 $sql .= " AND c.type != 'systemauto'";
12488 } elseif ($actioncode == 'AC_ALL_AUTO') {
12489 $sql .= " AND c.type = 'systemauto'";
12490 } else {
12491 if ($actioncode == 'AC_OTH') {
12492 $sql .= " AND c.type != 'systemauto'";
12493 } elseif ($actioncode == 'AC_OTH_AUTO') {
12494 $sql .= " AND c.type = 'systemauto'";
12495 }
12496 }
12497 } else {
12498 if ($actioncode == 'AC_NON_AUTO') {
12499 $sql .= " AND c.type != 'systemauto'";
12500 } elseif ($actioncode == 'AC_ALL_AUTO') {
12501 $sql .= " AND c.type = 'systemauto'";
12502 } else {
12503 $sql .= " AND c.code = '".$db->escape($actioncode)."'";
12504 }
12505 }
12506 }
12507 if ($donetodo == 'todo') {
12508 $sql .= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
12509 } elseif ($donetodo == 'done') {
12510 $sql .= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
12511 }
12512 if (is_array($filters) && $filters['search_agenda_label']) {
12513 $sql .= natural_search('a.label', $filters['search_agenda_label']);
12514 }
12515 }
12516
12517 // Add also event from emailings. TODO This should be replaced by an automatic event ? May be it's too much for very large emailing.
12518 if (isModEnabled('mailing') && !empty($objcon->email)
12519 && (empty($actioncode) || $actioncode == 'AC_OTH_AUTO' || $actioncode == 'AC_EMAILING')) {
12520 $langs->load("mails");
12521
12522 $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";
12523 $sql2 .= ", null as fk_element, '' as elementtype, null as contact_id";
12524 $sql2 .= ", 'AC_EMAILING' as acode, '' as alabel, '' as apicto";
12525 $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
12526 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12527 $sql2 .= ", '' as lastname, '' as firstname";
12528 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12529 $sql2 .= ", '' as lastname, '' as firstname";
12530 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12531 $sql2 .= ", '' as ref";
12532 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12533 $sql2 .= ", '' as ref";
12534 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12535 $sql2 .= ", '' as ref";
12536 }
12537 $sql2 .= " FROM ".MAIN_DB_PREFIX."mailing as m, ".MAIN_DB_PREFIX."mailing_cibles as mc, ".MAIN_DB_PREFIX."user as u";
12538 $sql2 .= " WHERE mc.email = '".$db->escape($objcon->email)."'"; // Search is done on email.
12539 $sql2 .= " AND mc.statut = 1";
12540 $sql2 .= " AND u.rowid = m.fk_user_valid";
12541 $sql2 .= " AND mc.fk_mailing=m.rowid";
12542 }
12543
12544 if (!empty($sql) && !empty($sql2)) {
12545 $sql = $sql." UNION ".$sql2;
12546 } elseif (empty($sql) && !empty($sql2)) {
12547 $sql = $sql2;
12548 }
12549
12550 // TODO Add limit in nb of results
12551 if ($sql) { // May not be defined if module Agenda is not enabled and mailing module disabled too
12552 $sql .= $db->order($sortfield_new, $sortorder);
12553
12554 dol_syslog("function.lib::show_actions_messaging", LOG_DEBUG);
12555 $resql = $db->query($sql);
12556 if ($resql) {
12557 $i = 0;
12558 $num = $db->num_rows($resql);
12559
12560 while ($i < $num) {
12561 $obj = $db->fetch_object($resql);
12562
12563 if ($obj->type == 'action') {
12564 $contactaction = new ActionComm($db);
12565 $contactaction->id = $obj->id;
12566 $result = $contactaction->fetchResources();
12567 if ($result < 0) {
12568 dol_print_error($db);
12569 setEventMessage("actions.lib::show_actions_messaging Error fetch ressource", 'errors');
12570 }
12571
12572 //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
12573 //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
12574 $tododone = '';
12575 if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && $obj->dp > $now)) {
12576 $tododone = 'todo';
12577 }
12578
12579 $histo[$numaction] = array(
12580 'type'=>$obj->type,
12581 'tododone'=>$tododone,
12582 'id'=>$obj->id,
12583 'datestart'=>$db->jdate($obj->dp),
12584 'dateend'=>$db->jdate($obj->dp2),
12585 'note'=>$obj->label,
12586 'message'=>$obj->message,
12587 'percent'=>$obj->percent,
12588
12589 'userid'=>$obj->user_id,
12590 'login'=>$obj->user_login,
12591 'userfirstname'=>$obj->user_firstname,
12592 'userlastname'=>$obj->user_lastname,
12593 'userphoto'=>$obj->user_photo,
12594 'msg_from'=>$obj->msg_from,
12595
12596 'contact_id'=>$obj->fk_contact,
12597 'socpeopleassigned' => $contactaction->socpeopleassigned,
12598 'lastname' => (empty($obj->lastname) ? '' : $obj->lastname),
12599 'firstname' => (empty($obj->firstname) ? '' : $obj->firstname),
12600 'fk_element'=>$obj->fk_element,
12601 'elementtype'=>$obj->elementtype,
12602 // Type of event
12603 'acode'=>$obj->acode,
12604 'alabel'=>$obj->alabel,
12605 'libelle'=>$obj->alabel, // deprecated
12606 'apicto'=>$obj->apicto
12607 );
12608 } else {
12609 $histo[$numaction] = array(
12610 'type'=>$obj->type,
12611 'tododone'=>'done',
12612 'id'=>$obj->id,
12613 'datestart'=>$db->jdate($obj->dp),
12614 'dateend'=>$db->jdate($obj->dp2),
12615 'note'=>$obj->label,
12616 'message'=>$obj->message,
12617 'percent'=>$obj->percent,
12618 'acode'=>$obj->acode,
12619
12620 'userid'=>$obj->user_id,
12621 'login'=>$obj->user_login,
12622 'userfirstname'=>$obj->user_firstname,
12623 'userlastname'=>$obj->user_lastname,
12624 'userphoto'=>$obj->user_photo
12625 );
12626 }
12627
12628 $numaction++;
12629 $i++;
12630 }
12631 } else {
12632 dol_print_error($db);
12633 }
12634 }
12635
12636 // Set $out to show events
12637 $out = '';
12638
12639 if (!isModEnabled('agenda')) {
12640 $langs->loadLangs(array("admin", "errors"));
12641 $out = info_admin($langs->trans("WarningModuleXDisabledSoYouMayMissEventHere", $langs->transnoentitiesnoconv("Module2400Name")), 0, 0, 'warning');
12642 }
12643
12644 if (isModEnabled('agenda') || (isModEnabled('mailing') && !empty($objcon->email))) {
12645 $delay_warning = $conf->global->MAIN_DELAY_ACTIONS_TODO * 24 * 60 * 60;
12646
12647 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
12648 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
12649 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
12650 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
12651
12652 $formactions = new FormActions($db);
12653
12654 $actionstatic = new ActionComm($db);
12655 $userstatic = new User($db);
12656 $contactstatic = new Contact($db);
12657 $userGetNomUrlCache = array();
12658 $contactGetNomUrlCache = array();
12659
12660 $out .= '<div class="filters-container" >';
12661 $out .= '<form name="listactionsfilter" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
12662 $out .= '<input type="hidden" name="token" value="'.newToken().'">';
12663
12664 if ($objcon && get_class($objcon) == 'Contact' &&
12665 (is_null($filterobj) || get_class($filterobj) == 'Societe')) {
12666 $out .= '<input type="hidden" name="id" value="'.$objcon->id.'" />';
12667 } else {
12668 $out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
12669 }
12670 if ($filterobj && get_class($filterobj) == 'Societe') {
12671 $out .= '<input type="hidden" name="socid" value="'.$filterobj->id.'" />';
12672 }
12673
12674 $out .= "\n";
12675
12676 $out .= '<div class="div-table-responsive-no-min">';
12677 $out .= '<table class="noborder borderbottom centpercent">';
12678
12679 $out .= '<tr class="liste_titre">';
12680
12681 // Action column
12682 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
12683 $out .= '<th class="liste_titre width50 middle">';
12684 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
12685 $out .= $searchpicto;
12686 $out .= '</th>';
12687 }
12688
12689 $out .= getTitleFieldOfList('Date', 0, $_SERVER["PHP_SELF"], 'a.datep', '', $param, '', $sortfield, $sortorder, '')."\n";
12690
12691 $out .= '<th class="liste_titre"><strong class="hideonsmartphone">'.$langs->trans("Search").' : </strong></th>';
12692 if ($donetodo) {
12693 $out .= '<th class="liste_titre"></th>';
12694 }
12695 $out .= '<th class="liste_titre">';
12696 $out .= '<span class="fas fa-square inline-block fawidth30" style=" color: #ddd;" title="'.$langs->trans("ActionType").'"></span>';
12697 //$out .= img_picto($langs->trans("Type"), 'type');
12698 $out .= $formactions->select_type_actions($actioncode, "actioncode", '', empty($conf->global->AGENDA_USE_EVENT_TYPE) ? 1 : -1, 0, 0, 1, 'minwidth200imp');
12699 $out .= '</th>';
12700 $out .= '<th class="liste_titre maxwidth100onsmartphone">';
12701 $out .= '<input type="text" class="maxwidth100onsmartphone" name="search_agenda_label" value="'.$filters['search_agenda_label'].'" placeholder="'.$langs->trans("Label").'">';
12702 $out .= '</th>';
12703
12704 // Action column
12705 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
12706 $out .= '<th class="liste_titre width50 middle">';
12707 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
12708 $out .= $searchpicto;
12709 $out .= '</th>';
12710 }
12711
12712 $out .= '</tr>';
12713
12714
12715 $out .= '</table>';
12716
12717 $out .= '</form>';
12718 $out .= '</div>';
12719
12720 $out .= "\n";
12721
12722 $out .= '<ul class="timeline">';
12723
12724 if ($donetodo) {
12725 $tmp = '';
12726 if (get_class($filterobj) == 'Societe') {
12727 $tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&socid='.$filterobj->id.'&status=done">';
12728 }
12729 $tmp .= ($donetodo != 'done' ? $langs->trans("ActionsToDoShort") : '');
12730 $tmp .= ($donetodo != 'done' && $donetodo != 'todo' ? ' / ' : '');
12731 $tmp .= ($donetodo != 'todo' ? $langs->trans("ActionsDoneShort") : '');
12732 //$out.=$langs->trans("ActionsToDoShort").' / '.$langs->trans("ActionsDoneShort");
12733 if (get_class($filterobj) == 'Societe') {
12734 $tmp .= '</a>';
12735 }
12736 $out .= getTitleFieldOfList($tmp);
12737 }
12738
12739
12740 //require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
12741 //$caction=new CActionComm($db);
12742 //$arraylist=$caction->liste_array(1, 'code', '', (empty($conf->global->AGENDA_USE_EVENT_TYPE)?1:0), '', 1);
12743
12744 $actualCycleDate = false;
12745
12746 // Loop on each event to show it
12747 foreach ($histo as $key => $value) {
12748 $actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo
12749
12750 $actionstatic->type_picto = $histo[$key]['apicto'];
12751 $actionstatic->type_code = $histo[$key]['acode'];
12752
12753 $url = DOL_URL_ROOT.'/comm/action/card.php?id='.$histo[$key]['id'];
12754
12755 $tmpa = dol_getdate($histo[$key]['datestart'], false);
12756 if ($actualCycleDate !== $tmpa['year'].'-'.$tmpa['yday']) {
12757 $actualCycleDate = $tmpa['year'].'-'.$tmpa['yday'];
12758 $out .= '<!-- timeline time label -->';
12759 $out .= '<li class="time-label">';
12760 $out .= '<span class="timeline-badge-date">';
12761 $out .= dol_print_date($histo[$key]['datestart'], 'daytext', 'tzuserrel', $langs);
12762 $out .= '</span>';
12763 $out .= '</li>';
12764 $out .= '<!-- /.timeline-label -->';
12765 }
12766
12767
12768 $out .= '<!-- timeline item -->'."\n";
12769 $out .= '<li class="timeline-code-'.strtolower($actionstatic->code).'">';
12770
12771 $out .= getTimelineIcon($actionstatic, $histo, $key);
12772
12773 $out .= '<div class="timeline-item">'."\n";
12774
12775 $out .= '<span class="timeline-header-action">';
12776
12777 if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
12778 $out .= '<a class="timeline-btn" href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
12779 $out .= $histo[$key]['id'];
12780 $out .= '</a> ';
12781 } else {
12782 $out .= $actionstatic->getNomUrl(1, -1, 'valignmiddle').' ';
12783 }
12784
12785 if ($user->hasRight('agenda', 'allactions', 'create') ||
12786 (($actionstatic->authorid == $user->id || $actionstatic->userownerid == $user->id) && $user->hasRight('agenda', 'myactions', 'create'))) {
12787 $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>';
12788 }
12789
12790 $out .= '</span>';
12791 // Date
12792 $out .= '<span class="time"><i class="fa fa-clock-o valignmiddle"></i> <span class="valignmiddle">';
12793 $out .= dol_print_date($histo[$key]['datestart'], 'dayhour', 'tzuserrel');
12794 if ($histo[$key]['dateend'] && $histo[$key]['dateend'] != $histo[$key]['datestart']) {
12795 $tmpa = dol_getdate($histo[$key]['datestart'], true);
12796 $tmpb = dol_getdate($histo[$key]['dateend'], true);
12797 if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
12798 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'hour', 'tzuserrel');
12799 } else {
12800 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'dayhour', 'tzuserrel');
12801 }
12802 }
12803 $late = 0;
12804 if ($histo[$key]['percent'] == 0 && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12805 $late = 1;
12806 }
12807 if ($histo[$key]['percent'] == 0 && !$histo[$key]['datestart'] && $histo[$key]['dateend'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12808 $late = 1;
12809 }
12810 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && $histo[$key]['dateend'] && $histo[$key]['dateend'] < ($now - $delay_warning)) {
12811 $late = 1;
12812 }
12813 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && !$histo[$key]['dateend'] && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12814 $late = 1;
12815 }
12816 if ($late) {
12817 $out .= img_warning($langs->trans("Late")).' ';
12818 }
12819 $out .= "</span></span>\n";
12820
12821 // Ref
12822 $out .= '<h3 class="timeline-header">';
12823
12824 // Author of event
12825 $out .= '<div class="messaging-author inline-block tdoverflowmax150 valignmiddle marginrightonly">';
12826 if ($histo[$key]['userid'] > 0) {
12827 if (!isset($userGetNomUrlCache[$histo[$key]['userid']])) { // is in cache ?
12828 $userstatic->fetch($histo[$key]['userid']);
12829 $userGetNomUrlCache[$histo[$key]['userid']] = $userstatic->getNomUrl(-1, '', 0, 0, 16, 0, 'firstelselast', '');
12830 }
12831 $out .= $userGetNomUrlCache[$histo[$key]['userid']];
12832 } elseif (!empty($histo[$key]['msg_from']) && $actionstatic->code == 'TICKET_MSG') {
12833 if (!isset($contactGetNomUrlCache[$histo[$key]['msg_from']])) {
12834 if ($contactstatic->fetch(0, null, '', $histo[$key]['msg_from']) > 0) {
12835 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $contactstatic->getNomUrl(-1, '', 16);
12836 } else {
12837 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $histo[$key]['msg_from'];
12838 }
12839 }
12840 $out .= $contactGetNomUrlCache[$histo[$key]['msg_from']];
12841 }
12842 $out .= '</div>';
12843
12844 // Title
12845 $libelle = '';
12846 $out .= ' <div class="messaging-title inline-block">';
12847
12848 if (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12849 $out .= $langs->trans('TicketNewMessage');
12850 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12851 $out .= $langs->trans('TicketNewMessage').' <em>('.$langs->trans('Private').')</em>';
12852 } elseif (isset($histo[$key]['type'])) {
12853 if ($histo[$key]['type'] == 'action') {
12854 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
12855 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : $histo[$key]['alabel']);
12856 $libelle = $histo[$key]['note'];
12857 $actionstatic->id = $histo[$key]['id'];
12858 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12859 } elseif ($histo[$key]['type'] == 'mailing') {
12860 $out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
12861 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
12862 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : 'Send mass mailing');
12863 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12864 } else {
12865 $libelle .= $histo[$key]['note'];
12866 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12867 }
12868 }
12869
12870 $out .= '</div>';
12871
12872 $out .= '</h3>';
12873
12874 if (!empty($histo[$key]['message'] && $histo[$key]['message'] != $libelle)
12875 && $actionstatic->code != 'AC_TICKET_CREATE'
12876 && $actionstatic->code != 'AC_TICKET_MODIFY'
12877 ) {
12878 $out .= '<div class="timeline-body">';
12879 $out .= $histo[$key]['message'];
12880 $out .= '</div>';
12881 }
12882
12883 // Timeline footer
12884 $footer = '';
12885
12886 // Contact for this action
12887 if (isset($histo[$key]['socpeopleassigned']) && is_array($histo[$key]['socpeopleassigned']) && count($histo[$key]['socpeopleassigned']) > 0) {
12888 $contactList = '';
12889 foreach ($histo[$key]['socpeopleassigned'] as $cid => $Tab) {
12890 $contact = new Contact($db);
12891 $result = $contact->fetch($cid);
12892
12893 if ($result < 0) {
12894 dol_print_error($db, $contact->error);
12895 }
12896
12897 if ($result > 0) {
12898 $contactList .= !empty($contactList) ? ', ' : '';
12899 $contactList .= $contact->getNomUrl(1);
12900 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
12901 if (!empty($contact->phone_pro)) {
12902 $contactList .= '('.dol_print_phone($contact->phone_pro).')';
12903 }
12904 }
12905 }
12906 }
12907
12908 $footer .= $langs->trans('ActionOnContact').' : '.$contactList;
12909 } elseif (empty($objcon->id) && isset($histo[$key]['contact_id']) && $histo[$key]['contact_id'] > 0) {
12910 $contact = new Contact($db);
12911 $result = $contact->fetch($histo[$key]['contact_id']);
12912
12913 if ($result < 0) {
12914 dol_print_error($db, $contact->error);
12915 }
12916
12917 if ($result > 0) {
12918 $footer .= $contact->getNomUrl(1);
12919 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
12920 if (!empty($contact->phone_pro)) {
12921 $footer .= '('.dol_print_phone($contact->phone_pro).')';
12922 }
12923 }
12924 }
12925 }
12926
12927 $documents = getActionCommEcmList($actionstatic);
12928 if (!empty($documents)) {
12929 $footer .= '<div class="timeline-documents-container">';
12930 foreach ($documents as $doc) {
12931 $footer .= '<span id="document_'.$doc->id.'" class="timeline-documents" ';
12932 $footer .= ' data-id="'.$doc->id.'" ';
12933 $footer .= ' data-path="'.$doc->filepath.'"';
12934 $footer .= ' data-filename="'.dol_escape_htmltag($doc->filename).'" ';
12935 $footer .= '>';
12936
12937 $filePath = DOL_DATA_ROOT.'/'.$doc->filepath.'/'.$doc->filename;
12938 $mime = dol_mimetype($filePath);
12939 $file = $actionstatic->id.'/'.$doc->filename;
12940 $thumb = $actionstatic->id.'/thumbs/'.substr($doc->filename, 0, strrpos($doc->filename, '.')).'_mini'.substr($doc->filename, strrpos($doc->filename, '.'));
12941 $doclink = dol_buildpath('document.php', 1).'?modulepart=actions&attachment=0&file='.urlencode($file).'&entity='.$conf->entity;
12942 $viewlink = dol_buildpath('viewimage.php', 1).'?modulepart=actions&file='.urlencode($thumb).'&entity='.$conf->entity;
12943
12944 $mimeAttr = ' mime="'.$mime.'" ';
12945 $class = '';
12946 if (in_array($mime, array('image/png', 'image/jpeg', 'application/pdf'))) {
12947 $class .= ' documentpreview';
12948 }
12949
12950 $footer .= '<a href="'.$doclink.'" class="btn-link '.$class.'" target="_blank" rel="noopener noreferrer" '.$mimeAttr.' >';
12951 $footer .= img_mime($filePath).' '.$doc->filename;
12952 $footer .= '</a>';
12953
12954 $footer .= '</span>';
12955 }
12956 $footer .= '</div>';
12957 }
12958
12959 if (!empty($footer)) {
12960 $out .= '<div class="timeline-footer">'.$footer.'</div>';
12961 }
12962
12963 $out .= '</div>'."\n"; // end timeline-item
12964
12965 $out .= '</li>';
12966 $out .= '<!-- END timeline item -->';
12967
12968 $i++;
12969 }
12970
12971 $out .= "</ul>\n";
12972
12973 if (empty($histo)) {
12974 $out .= '<span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span>';
12975 }
12976 }
12977
12978 if ($noprint) {
12979 return $out;
12980 } else {
12981 print $out;
12982 }
12983}
12984
12995function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto')
12996{
12997 if ($hourTime === 'getpost') {
12998 $hour = GETPOSTINT($prefix . 'hour');
12999 $minute = GETPOSTINT($prefix . 'minute');
13000 $second = GETPOSTINT($prefix . 'second');
13001 } elseif (preg_match('/^(\d\d):(\d\d):(\d\d)$/', $hourTime, $m)) {
13002 $hour = intval($m[1]);
13003 $minute = intval($m[2]);
13004 $second = intval($m[3]);
13005 } else {
13006 $hour = $minute = $second = 0;
13007 }
13008 // normalize out of range values
13009 $hour = min($hour, 23);
13010 $minute = min($minute, 59);
13011 $second = min($second, 59);
13012 return dol_mktime($hour, $minute, $second, GETPOSTINT($prefix . 'month'), GETPOSTINT($prefix . 'day'), GETPOSTINT($prefix . 'year'), $gm);
13013}
13014
13026function buildParamDate($prefix, $timestamp = null, $hourTime = '', $gm = 'auto')
13027{
13028 if ($timestamp === null) $timestamp = GETPOSTDATE($prefix, $hourTime, $gm);
13029 $TParam = array(
13030 $prefix . 'day' => intval(dol_print_date($timestamp, '%d')),
13031 $prefix . 'month' => intval(dol_print_date($timestamp, '%m')),
13032 $prefix . 'year' => intval(dol_print_date($timestamp, '%Y')),
13033 );
13034 if ($hourTime === 'getpost' || ($timestamp !== null && dol_print_date($timestamp, '%H:%M:%S') !== '00:00:00')) {
13035 $TParam = array_merge($TParam, array(
13036 $prefix . 'hour' => intval(dol_print_date($timestamp, '%H')),
13037 $prefix . 'minute' => intval(dol_print_date($timestamp, '%M')),
13038 $prefix . 'second' => intval(dol_print_date($timestamp, '%S'))
13039 ));
13040 }
13041
13042 return '&' . http_build_query($TParam);
13043}
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:726
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:497
dol_get_next_day($day, $month, $year)
Return next day.
Definition date.lib.php:482
getServerTimeZoneInt($refgmtdate='now')
Return server timezone int.
Definition date.lib.php:84
dol_get_prev_day($day, $month, $year)
Return previous day.
Definition date.lib.php:466
dol_get_next_month($month, $year)
Return next month.
Definition date.lib.php:516
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.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='', $useCache=true)
Return an id or code from a code or id.
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_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.
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...
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.
conf($dolibarr_main_document_root)
Load conf file (file must exists)
Definition inc.php:400
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1649
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
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.