dolibarr 18.0.6
functions.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2000-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2003 Jean-Louis Bergamo <jlb@j1b.org>
4 * Copyright (C) 2004-2022 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
7 * Copyright (C) 2004 Christophe Combelles <ccomb@free.fr>
8 * Copyright (C) 2005-2019 Regis Houssin <regis.houssin@inodbox.com>
9 * Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr>
10 * Copyright (C) 2010-2018 Juanjo Menent <jmenent@2byte.es>
11 * Copyright (C) 2013 Cédric Salvador <csalvador@gpcsolutions.fr>
12 * Copyright (C) 2013-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
13 * Copyright (C) 2014 Cédric GROSS <c.gross@kreiz-it.fr>
14 * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
15 * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
16 * Copyright (C) 2018-2023 Frédéric France <frederic.france@netlogic.fr>
17 * Copyright (C) 2019-2023 Thibault Foucart <support@ptibogxiv.net>
18 * Copyright (C) 2020 Open-Dsi <support@open-dsi.fr>
19 * Copyright (C) 2021 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
20 * Copyright (C) 2022 Anthony Berton <anthony.berton@bb2a.fr>
21 * Copyright (C) 2022 Ferran Marcet <fmarcet@2byte.es>
22 * Copyright (C) 2022 Charlene Benke <charlene@patas-monkey.com>
23 * Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 3 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program. If not, see <https://www.gnu.org/licenses/>.
37 * or see https://www.gnu.org/
38 */
39
46include_once DOL_DOCUMENT_ROOT.'/core/lib/json.lib.php';
47
48// Function for better PHP x compatibility
49if (!function_exists('utf8_encode')) {
56 function utf8_encode($elements)
57 {
58 return mb_convert_encoding($elements, 'UTF-8', 'ISO-8859-1');
59 }
60}
61
62if (!function_exists('utf8_decode')) {
69 function utf8_decode($elements)
70 {
71 return mb_convert_encoding($elements, 'ISO-8859-1', 'UTF-8');
72 }
73}
74if (!function_exists('str_starts_with')) {
82 function str_starts_with($haystack, $needle)
83 {
84 return (string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0;
85 }
86}
87if (!function_exists('str_ends_with')) {
95 function str_ends_with($haystack, $needle)
96 {
97 return $needle !== '' && substr($haystack, -strlen($needle)) === (string) $needle;
98 }
99}
100if (!function_exists('str_contains')) {
108 function str_contains($haystack, $needle)
109 {
110 return $needle !== '' && mb_strpos($haystack, $needle) !== false;
111 }
112}
113
114
123function getMultidirOutput($object, $module = '')
124{
125 global $conf;
126 if (!is_object($object) && empty($module)) {
127 return null;
128 }
129 if (empty($module) && !empty($object->element)) {
130 $module = $object->element;
131 }
132 return $conf->$module->multidir_output[(!empty($object->entity) ? $object->entity : $conf->entity)];
133}
134
142function getDolGlobalString($key, $default = '')
143{
144 global $conf;
145 // return $conf->global->$key ?? $default;
146 return (string) (isset($conf->global->$key) ? $conf->global->$key : $default);
147}
148
156function getDolGlobalInt($key, $default = 0)
157{
158 global $conf;
159 // return $conf->global->$key ?? $default;
160 return (int) (isset($conf->global->$key) ? $conf->global->$key : $default);
161}
162
171function getDolUserString($key, $default = '', $tmpuser = null)
172{
173 if (empty($tmpuser)) {
174 global $user;
175 $tmpuser = $user;
176 }
177
178 // return $conf->global->$key ?? $default;
179 return (string) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
180}
181
190function getDolUserInt($key, $default = 0, $tmpuser = null)
191{
192 if (empty($tmpuser)) {
193 global $user;
194 $tmpuser = $user;
195 }
196
197 // return $conf->global->$key ?? $default;
198 return (int) (empty($tmpuser->conf->$key) ? $default : $tmpuser->conf->$key);
199}
200
207function isModEnabled($module)
208{
209 global $conf;
210
211 // Fix special cases
212 $arrayconv = array(
213 'bank' => 'banque',
214 'category' => 'categorie',
215 'contract' => 'contrat',
216 'project' => 'projet',
217 'delivery_note' => 'expedition'
218 );
219 if (empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) {
220 $arrayconv['supplier_order'] = 'fournisseur';
221 $arrayconv['supplier_invoice'] = 'fournisseur';
222 }
223 if (!empty($arrayconv[$module])) {
224 $module = $arrayconv[$module];
225 }
226
227 return !empty($conf->modules[$module]);
228 //return !empty($conf->$module->enabled);
229}
230
242function getDoliDBInstance($type, $host, $user, $pass, $name, $port)
243{
244 require_once DOL_DOCUMENT_ROOT."/core/db/".$type.'.class.php';
245
246 $class = 'DoliDB'.ucfirst($type);
247 $dolidb = new $class($type, $host, $user, $pass, $name, $port);
248 return $dolidb;
249}
250
268function getEntity($element, $shared = 1, $currentobject = null)
269{
270 global $conf, $mc, $hookmanager, $object, $action, $db;
271
272 if (!is_object($hookmanager)) {
273 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
274 $hookmanager = new HookManager($db);
275 }
276
277 // fix different element names (France to English)
278 switch ($element) {
279 case 'projet':
280 $element = 'project';
281 break;
282 case 'contrat':
283 $element = 'contract';
284 break; // "/contrat/class/contrat.class.php"
285 case 'order_supplier':
286 $element = 'supplier_order';
287 break; // "/fourn/class/fournisseur.commande.class.php"
288 case 'invoice_supplier':
289 $element = 'supplier_invoice';
290 break; // "/fourn/class/fournisseur.facture.class.php"
291 }
292
293 if (is_object($mc)) {
294 $out = $mc->getEntity($element, $shared, $currentobject);
295 } else {
296 $out = '';
297 $addzero = array('user', 'usergroup', 'cronjob', 'c_email_templates', 'email_template', 'default_values', 'overwrite_trans');
298 if (in_array($element, $addzero)) {
299 $out .= '0,';
300 }
301 $out .= ((int) $conf->entity);
302 }
303
304 // Manipulate entities to query on the fly
305 $parameters = array(
306 'element' => $element,
307 'shared' => $shared,
308 'object' => $object,
309 'currentobject' => $currentobject,
310 'out' => $out
311 );
312 $reshook = $hookmanager->executeHooks('hookGetEntity', $parameters, $currentobject, $action); // Note that $action and $object may have been modified by some hooks
313
314 if (is_numeric($reshook)) {
315 if ($reshook == 0 && !empty($hookmanager->resPrint)) {
316 $out .= ','.$hookmanager->resPrint; // add
317 } elseif ($reshook == 1) {
318 $out = $hookmanager->resPrint; // replace
319 }
320 }
321
322 return $out;
323}
324
331function setEntity($currentobject)
332{
333 global $conf, $mc;
334
335 if (is_object($mc) && method_exists($mc, 'setEntity')) {
336 return $mc->setEntity($currentobject);
337 } else {
338 return ((is_object($currentobject) && $currentobject->id > 0 && $currentobject->entity > 0) ? $currentobject->entity : $conf->entity);
339 }
340}
341
348function isASecretKey($keyname)
349{
350 return preg_match('/(_pass|password|_pw|_key|securekey|serverkey|secret\d?|p12key|exportkey|_PW_[a-z]+|token)$/i', $keyname);
351}
352
353
360function num2Alpha($n)
361{
362 for ($r = ""; $n >= 0; $n = intval($n / 26) - 1)
363 $r = chr($n % 26 + 0x41) . $r;
364 return $r;
365}
366
367
384function getBrowserInfo($user_agent)
385{
386 include_once DOL_DOCUMENT_ROOT.'/includes/mobiledetect/mobiledetectlib/Mobile_Detect.php';
387
388 $name = 'unknown';
389 $version = '';
390 $os = 'unknown';
391 $phone = '';
392
393 $user_agent = substr($user_agent, 0, 512); // Avoid to process too large user agent
394
395 $detectmobile = new Mobile_Detect(null, $user_agent);
396 $tablet = $detectmobile->isTablet();
397
398 if ($detectmobile->isMobile()) {
399 $phone = 'unknown';
400
401 // If phone/smartphone, we set phone os name.
402 if ($detectmobile->is('AndroidOS')) {
403 $os = $phone = 'android';
404 } elseif ($detectmobile->is('BlackBerryOS')) {
405 $os = $phone = 'blackberry';
406 } elseif ($detectmobile->is('iOS')) {
407 $os = 'ios';
408 $phone = 'iphone';
409 } elseif ($detectmobile->is('PalmOS')) {
410 $os = $phone = 'palm';
411 } elseif ($detectmobile->is('SymbianOS')) {
412 $os = 'symbian';
413 } elseif ($detectmobile->is('webOS')) {
414 $os = 'webos';
415 } elseif ($detectmobile->is('MaemoOS')) {
416 $os = 'maemo';
417 } elseif ($detectmobile->is('WindowsMobileOS') || $detectmobile->is('WindowsPhoneOS')) {
418 $os = 'windows';
419 }
420 }
421
422 // OS
423 if (preg_match('/linux/i', $user_agent)) {
424 $os = 'linux';
425 } elseif (preg_match('/macintosh/i', $user_agent)) {
426 $os = 'macintosh';
427 } elseif (preg_match('/windows/i', $user_agent)) {
428 $os = 'windows';
429 }
430
431 // Name
432 $reg = array();
433 if (preg_match('/firefox(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
434 $name = 'firefox';
435 $version = empty($reg[2]) ? '' : $reg[2];
436 } elseif (preg_match('/edge(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
437 $name = 'edge';
438 $version = empty($reg[2]) ? '' : $reg[2];
439 } elseif (preg_match('/chrome(\/|\s)([\d\.]+)/i', $user_agent, $reg)) {
440 $name = 'chrome';
441 $version = empty($reg[2]) ? '' : $reg[2];
442 } elseif (preg_match('/chrome/i', $user_agent, $reg)) {
443 // we can have 'chrome (Mozilla...) chrome x.y' in one string
444 $name = 'chrome';
445 } elseif (preg_match('/iceweasel/i', $user_agent)) {
446 $name = 'iceweasel';
447 } elseif (preg_match('/epiphany/i', $user_agent)) {
448 $name = 'epiphany';
449 } elseif (preg_match('/safari(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
450 $name = 'safari';
451 $version = empty($reg[2]) ? '' : $reg[2];
452 } elseif (preg_match('/opera(\/|\s)([\d\.]*)/i', $user_agent, $reg)) {
453 // Safari is often present in string for mobile but its not.
454 $name = 'opera';
455 $version = empty($reg[2]) ? '' : $reg[2];
456 } elseif (preg_match('/(MSIE\s([0-9]+\.[0-9]))|.*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
457 $name = 'ie';
458 $version = end($reg);
459 } elseif (preg_match('/(Windows NT\s([0-9]+\.[0-9])).*(Trident\/[0-9]+.[0-9];.*rv:([0-9]+\.[0-9]+))/i', $user_agent, $reg)) {
460 // MS products at end
461 $name = 'ie';
462 $version = end($reg);
463 } elseif (preg_match('/l[iy]n(x|ks)(\‍(|\/|\s)*([\d\.]+)/i', $user_agent, $reg)) {
464 // MS products at end
465 $name = 'lynxlinks';
466 $version = empty($reg[3]) ? '' : $reg[3];
467 }
468
469 if ($tablet) {
470 $layout = 'tablet';
471 } elseif ($phone) {
472 $layout = 'phone';
473 } else {
474 $layout = 'classic';
475 }
476
477 return array(
478 'browsername' => $name,
479 'browserversion' => $version,
480 'browseros' => $os,
481 'browserua' => $user_agent,
482 'layout' => $layout, // tablet, phone, classic
483 'phone' => $phone, // deprecated
484 'tablet' => $tablet // deprecated
485 );
486}
487
493function dol_shutdown()
494{
495 global $user, $langs, $db;
496 $disconnectdone = false;
497 $depth = 0;
498 if (is_object($db) && !empty($db->connected)) {
499 $depth = $db->transaction_opened;
500 $disconnectdone = $db->close();
501 }
502 dol_syslog("--- End access to ".$_SERVER["PHP_SELF"].(($disconnectdone && $depth) ? ' (Warn: db disconnection forced, transaction depth was '.$depth.')' : ''), (($disconnectdone && $depth) ? LOG_WARNING : LOG_INFO));
503}
504
514function GETPOSTISSET($paramname)
515{
516 $isset = false;
517
518 $relativepathstring = $_SERVER["PHP_SELF"];
519 // Clean $relativepathstring
520 if (constant('DOL_URL_ROOT')) {
521 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
522 }
523 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
524 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
525 //var_dump($relativepathstring);
526 //var_dump($user->default_values);
527
528 // Code for search criteria persistence.
529 // Retrieve values if restore_lastsearch_values
530 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
531 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
532 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
533 if (is_array($tmp)) {
534 foreach ($tmp as $key => $val) {
535 if ($key == $paramname) { // We are on the requested parameter
536 $isset = true;
537 break;
538 }
539 }
540 }
541 }
542 // If there is saved contextpage, limit, page or mode
543 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
544 $isset = true;
545 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
546 $isset = true;
547 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
548 $isset = true;
549 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
550 $isset = true;
551 }
552 } else {
553 $isset = (isset($_POST[$paramname]) || isset($_GET[$paramname])); // We must keep $_POST and $_GET here
554 }
555
556 return $isset;
557}
558
567function GETPOSTISARRAY($paramname, $method = 0)
568{
569 // for $method test need return the same $val as GETPOST
570 if (empty($method)) {
571 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
572 } elseif ($method == 1) {
573 $val = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
574 } elseif ($method == 2) {
575 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
576 } elseif ($method == 3) {
577 $val = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
578 } else {
579 $val = 'BadFirstParameterForGETPOST';
580 }
581
582 return is_array($val);
583}
584
614function GETPOST($paramname, $check = 'alphanohtml', $method = 0, $filter = null, $options = null, $noreplace = 0)
615{
616 global $mysoc, $user, $conf;
617
618 if (empty($paramname)) {
619 return 'BadFirstParameterForGETPOST';
620 }
621 if (empty($check)) {
622 dol_syslog("Deprecated use of GETPOST, called with 1st param = ".$paramname." and 2nd param is '', when calling page ".$_SERVER["PHP_SELF"], LOG_WARNING);
623 // Enable this line to know who call the GETPOST with '' $check parameter.
624 //var_dump(debug_backtrace()[0]);
625 }
626
627 if (empty($method)) {
628 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : (isset($_POST[$paramname]) ? $_POST[$paramname] : '');
629 } elseif ($method == 1) {
630 $out = isset($_GET[$paramname]) ? $_GET[$paramname] : '';
631 } elseif ($method == 2) {
632 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : '';
633 } elseif ($method == 3) {
634 $out = isset($_POST[$paramname]) ? $_POST[$paramname] : (isset($_GET[$paramname]) ? $_GET[$paramname] : '');
635 } else {
636 return 'BadThirdParameterForGETPOST';
637 }
638
639 if (empty($method) || $method == 3 || $method == 4) {
640 $relativepathstring = $_SERVER["PHP_SELF"];
641 // Clean $relativepathstring
642 if (constant('DOL_URL_ROOT')) {
643 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
644 }
645 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
646 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
647 //var_dump($relativepathstring);
648 //var_dump($user->default_values);
649
650 // Code for search criteria persistence.
651 // Retrieve values if restore_lastsearch_values
652 if (!empty($_GET['restore_lastsearch_values'])) { // Use $_GET here and not GETPOST
653 if (!empty($_SESSION['lastsearch_values_'.$relativepathstring])) { // If there is saved values
654 $tmp = json_decode($_SESSION['lastsearch_values_'.$relativepathstring], true);
655 if (is_array($tmp)) {
656 foreach ($tmp as $key => $val) {
657 if ($key == $paramname) { // We are on the requested parameter
658 $out = $val;
659 break;
660 }
661 }
662 }
663 }
664 // If there is saved contextpage, page or limit
665 if ($paramname == 'contextpage' && !empty($_SESSION['lastsearch_contextpage_'.$relativepathstring])) {
666 $out = $_SESSION['lastsearch_contextpage_'.$relativepathstring];
667 } elseif ($paramname == 'limit' && !empty($_SESSION['lastsearch_limit_'.$relativepathstring])) {
668 $out = $_SESSION['lastsearch_limit_'.$relativepathstring];
669 } elseif ($paramname == 'page' && !empty($_SESSION['lastsearch_page_'.$relativepathstring])) {
670 $out = $_SESSION['lastsearch_page_'.$relativepathstring];
671 } elseif ($paramname == 'mode' && !empty($_SESSION['lastsearch_mode_'.$relativepathstring])) {
672 $out = $_SESSION['lastsearch_mode_'.$relativepathstring];
673 }
674 } elseif (!isset($_GET['sortfield'])) {
675 // Else, retrieve default values if we are not doing a sort
676 // If we did a click on a field to sort, we do no apply default values. Same if option MAIN_ENABLE_DEFAULT_VALUES is not set
677 if (!empty($_GET['action']) && $_GET['action'] == 'create' && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
678 // Search default value from $object->field
679 global $object;
680 if (is_object($object) && isset($object->fields[$paramname]['default'])) {
681 $out = $object->fields[$paramname]['default'];
682 }
683 }
684 if (!empty($conf->global->MAIN_ENABLE_DEFAULT_VALUES)) {
685 if (!empty($_GET['action']) && (preg_match('/^create/', $_GET['action']) || preg_match('/^presend/', $_GET['action'])) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
686 // Now search in setup to overwrite default values
687 if (!empty($user->default_values)) { // $user->default_values defined from menu 'Setup - Default values'
688 if (isset($user->default_values[$relativepathstring]['createform'])) {
689 foreach ($user->default_values[$relativepathstring]['createform'] as $defkey => $defval) {
690 $qualified = 0;
691 if ($defkey != '_noquery_') {
692 $tmpqueryarraytohave = explode('&', $defkey);
693 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
694 $foundintru = 0;
695 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
696 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
697 $foundintru = 1;
698 }
699 }
700 if (!$foundintru) {
701 $qualified = 1;
702 }
703 //var_dump($defkey.'-'.$qualified);
704 } else {
705 $qualified = 1;
706 }
707
708 if ($qualified) {
709 if (isset($user->default_values[$relativepathstring]['createform'][$defkey][$paramname])) {
710 $out = $user->default_values[$relativepathstring]['createform'][$defkey][$paramname];
711 break;
712 }
713 }
714 }
715 }
716 }
717 } elseif (!empty($paramname) && !isset($_GET[$paramname]) && !isset($_POST[$paramname])) {
718 // Management of default search_filters and sort order
719 if (!empty($user->default_values)) {
720 // $user->default_values defined from menu 'Setup - Default values'
721 //var_dump($user->default_values[$relativepathstring]);
722 if ($paramname == 'sortfield' || $paramname == 'sortorder') {
723 // Sorted on which fields ? ASC or DESC ?
724 if (isset($user->default_values[$relativepathstring]['sortorder'])) {
725 // Even if paramname is sortfield, data are stored into ['sortorder...']
726 foreach ($user->default_values[$relativepathstring]['sortorder'] as $defkey => $defval) {
727 $qualified = 0;
728 if ($defkey != '_noquery_') {
729 $tmpqueryarraytohave = explode('&', $defkey);
730 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
731 $foundintru = 0;
732 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
733 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
734 $foundintru = 1;
735 }
736 }
737 if (!$foundintru) {
738 $qualified = 1;
739 }
740 //var_dump($defkey.'-'.$qualified);
741 } else {
742 $qualified = 1;
743 }
744
745 if ($qualified) {
746 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
747 foreach ($user->default_values[$relativepathstring]['sortorder'][$defkey] as $key => $val) {
748 if ($out) {
749 $out .= ', ';
750 }
751 if ($paramname == 'sortfield') {
752 $out .= dol_string_nospecial($key, '', $forbidden_chars_to_replace);
753 }
754 if ($paramname == 'sortorder') {
755 $out .= dol_string_nospecial($val, '', $forbidden_chars_to_replace);
756 }
757 }
758 //break; // No break for sortfield and sortorder so we can cumulate fields (is it realy usefull ?)
759 }
760 }
761 }
762 } elseif (isset($user->default_values[$relativepathstring]['filters'])) {
763 foreach ($user->default_values[$relativepathstring]['filters'] as $defkey => $defval) { // $defkey is a querystring like 'a=b&c=d', $defval is key of user
764 if (!empty($_GET['disabledefaultvalues'])) { // If set of default values has been disabled by a request parameter
765 continue;
766 }
767 $qualified = 0;
768 if ($defkey != '_noquery_') {
769 $tmpqueryarraytohave = explode('&', $defkey);
770 $tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
771 $foundintru = 0;
772 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
773 if (!in_array($tmpquerytohave, $tmpqueryarraywehave)) {
774 $foundintru = 1;
775 }
776 }
777 if (!$foundintru) {
778 $qualified = 1;
779 }
780 //var_dump($defkey.'-'.$qualified);
781 } else {
782 $qualified = 1;
783 }
784
785 if ($qualified && isset($user->default_values[$relativepathstring]['filters'][$defkey][$paramname])) {
786 // We must keep $_POST and $_GET here
787 if (isset($_POST['sall']) || isset($_POST['search_all']) || isset($_GET['sall']) || isset($_GET['search_all'])) {
788 // We made a search from quick search menu, do we still use default filter ?
789 if (empty($conf->global->MAIN_DISABLE_DEFAULT_FILTER_FOR_QUICK_SEARCH)) {
790 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
791 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
792 }
793 } else {
794 $forbidden_chars_to_replace = array(" ", "'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ";", "="); // we accept _, -, . and ,
795 $out = dol_string_nospecial($user->default_values[$relativepathstring]['filters'][$defkey][$paramname], '', $forbidden_chars_to_replace);
796 }
797 break;
798 }
799 }
800 }
801 }
802 }
803 }
804 }
805 }
806
807 // Substitution variables for GETPOST (used to get final url with variable parameters or final default value with variable parameters)
808 // Example of variables: __DAY__, __MONTH__, __YEAR__, __MYCOMPANY_COUNTRY_ID__, __USER_ID__, ...
809 // We do this only if var is a GET. If it is a POST, may be we want to post the text with vars as the setup text.
810 if (!is_array($out) && empty($_POST[$paramname]) && empty($noreplace)) {
811 $reg = array();
812 $maxloop = 20;
813 $loopnb = 0; // Protection against infinite loop
814 while (preg_match('/__([A-Z0-9]+_?[A-Z0-9]+)__/i', $out, $reg) && ($loopnb < $maxloop)) { // Detect '__ABCDEF__' as key 'ABCDEF' and '__ABC_DEF__' as key 'ABC_DEF'. Detection is also correct when 2 vars are side by side.
815 $loopnb++;
816 $newout = '';
817
818 if ($reg[1] == 'DAY') {
819 $tmp = dol_getdate(dol_now(), true);
820 $newout = $tmp['mday'];
821 } elseif ($reg[1] == 'MONTH') {
822 $tmp = dol_getdate(dol_now(), true);
823 $newout = $tmp['mon'];
824 } elseif ($reg[1] == 'YEAR') {
825 $tmp = dol_getdate(dol_now(), true);
826 $newout = $tmp['year'];
827 } elseif ($reg[1] == 'PREVIOUS_DAY') {
828 $tmp = dol_getdate(dol_now(), true);
829 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
830 $newout = $tmp2['day'];
831 } elseif ($reg[1] == 'PREVIOUS_MONTH') {
832 $tmp = dol_getdate(dol_now(), true);
833 $tmp2 = dol_get_prev_month($tmp['mon'], $tmp['year']);
834 $newout = $tmp2['month'];
835 } elseif ($reg[1] == 'PREVIOUS_YEAR') {
836 $tmp = dol_getdate(dol_now(), true);
837 $newout = ($tmp['year'] - 1);
838 } elseif ($reg[1] == 'NEXT_DAY') {
839 $tmp = dol_getdate(dol_now(), true);
840 $tmp2 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
841 $newout = $tmp2['day'];
842 } elseif ($reg[1] == 'NEXT_MONTH') {
843 $tmp = dol_getdate(dol_now(), true);
844 $tmp2 = dol_get_next_month($tmp['mon'], $tmp['year']);
845 $newout = $tmp2['month'];
846 } elseif ($reg[1] == 'NEXT_YEAR') {
847 $tmp = dol_getdate(dol_now(), true);
848 $newout = ($tmp['year'] + 1);
849 } elseif ($reg[1] == 'MYCOMPANY_COUNTRY_ID' || $reg[1] == 'MYCOUNTRY_ID' || $reg[1] == 'MYCOUNTRYID') {
850 $newout = $mysoc->country_id;
851 } elseif ($reg[1] == 'USER_ID' || $reg[1] == 'USERID') {
852 $newout = $user->id;
853 } elseif ($reg[1] == 'USER_SUPERVISOR_ID' || $reg[1] == 'SUPERVISOR_ID' || $reg[1] == 'SUPERVISORID') {
854 $newout = $user->fk_user;
855 } elseif ($reg[1] == 'ENTITY_ID' || $reg[1] == 'ENTITYID') {
856 $newout = $conf->entity;
857 } else {
858 $newout = ''; // Key not found, we replace with empty string
859 }
860 //var_dump('__'.$reg[1].'__ -> '.$newout);
861 $out = preg_replace('/__'.preg_quote($reg[1], '/').'__/', $newout, $out);
862 }
863 }
864
865 // Check rule
866 if (preg_match('/^array/', $check)) { // If 'array' or 'array:restricthtml' or 'array:aZ09' or 'array:intcomma'
867 if (!is_array($out) || empty($out)) {
868 $out = array();
869 } else {
870 $tmparray = explode(':', $check);
871 if (!empty($tmparray[1])) {
872 $tmpcheck = $tmparray[1];
873 } else {
874 $tmpcheck = 'alphanohtml';
875 }
876 foreach ($out as $outkey => $outval) {
877 $out[$outkey] = sanitizeVal($outval, $tmpcheck, $filter, $options);
878 }
879 }
880 } else {
881 // If field name is 'search_xxx' then we force the add of space after each < and > (when following char is numeric) because it means
882 // we use the < or > to make a search on a numeric value to do higher or lower so we can add a space to break html tags
883 if (strpos($paramname, 'search_') === 0) {
884 $out = preg_replace('/([<>])([-+]?\d)/', '\1 \2', $out);
885 }
886
887 $out = sanitizeVal($out, $check, $filter, $options);
888 }
889
890 // Sanitizing for special parameters.
891 // Note: There is no reason to allow the backtopage, backtolist or backtourl parameter to contains an external URL. Only relative URLs are allowed.
892 if ($paramname == 'backtopage' || $paramname == 'backtolist' || $paramname == 'backtourl') {
893 $out = str_replace('\\', '/', $out); // Can be before the loop because only 1 char is replaced. No risk to get it after other replacements.
894 $out = str_replace(array(':', ';', '@', "\t", ' '), '', $out); // Can be before the loop because only 1 char is replaced. No risk to retreive it after other replacements.
895 do {
896 $oldstringtoclean = $out;
897 $out = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $out);
898 $out = preg_replace(array('/^[^\?]*%/'), '', $out); // We remove any % chars before the ?. Example in url: '/product/stock/card.php?action=create&backtopage=%2Fdolibarr_dev%2Fhtdocs%2Fpro%25duct%2Fcard.php%3Fid%3Dabc'
899 $out = preg_replace(array('/^[a-z]*\/\s*\/+/i'), '', $out); // We remove schema*// to remove external URL
900 } while ($oldstringtoclean != $out);
901 }
902
903 // Code for search criteria persistence.
904 // Save data into session if key start with 'search_' or is 'smonth', 'syear', 'month', 'year'
905 if (empty($method) || $method == 3 || $method == 4) {
906 if (preg_match('/^search_/', $paramname) || in_array($paramname, array('sortorder', 'sortfield'))) {
907 //var_dump($paramname.' - '.$out.' '.$user->default_values[$relativepathstring]['filters'][$paramname]);
908
909 // We save search key only if $out not empty that means:
910 // - posted value not empty, or
911 // - if posted value is empty and a default value exists that is not empty (it means we did a filter to an empty value when default was not).
912
913 if ($out != '' && isset($user)) {// $out = '0' or 'abc', it is a search criteria to keep
914 $user->lastsearch_values_tmp[$relativepathstring][$paramname] = $out;
915 }
916 }
917 }
918
919 return $out;
920}
921
931function GETPOSTINT($paramname, $method = 0)
932{
933 return (int) GETPOST($paramname, 'int', $method, null, null, 0);
934}
935
936
947function checkVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
948{
949 return sanitizeVal($out, $check, $filter, $options);
950}
951
961function sanitizeVal($out = '', $check = 'alphanohtml', $filter = null, $options = null)
962{
963 // TODO : use class "Validate" to perform tests (and add missing tests) if needed for factorize
964 // Check is done after replacement
965 switch ($check) {
966 case 'none':
967 break;
968 case 'int': // Check param is a numeric value (integer but also float or hexadecimal)
969 if (!is_numeric($out)) {
970 $out = '';
971 }
972 break;
973 case 'intcomma':
974 if (is_array($out)) {
975 $out = implode(',', $out);
976 }
977 if (preg_match('/[^0-9,-]+/i', $out)) {
978 $out = '';
979 }
980 break;
981 case 'san_alpha':
982 $out = filter_var($out, FILTER_SANITIZE_STRING);
983 break;
984 case 'email':
985 $out = filter_var($out, FILTER_SANITIZE_EMAIL);
986 break;
987 case 'aZ':
988 if (!is_array($out)) {
989 $out = trim($out);
990 if (preg_match('/[^a-z]+/i', $out)) {
991 $out = '';
992 }
993 }
994 break;
995 case 'aZ09':
996 if (!is_array($out)) {
997 $out = trim($out);
998 if (preg_match('/[^a-z0-9_\-\.]+/i', $out)) {
999 $out = '';
1000 }
1001 }
1002 break;
1003 case 'aZ09arobase': // great to sanitize $objecttype parameter
1004 if (!is_array($out)) {
1005 $out = trim($out);
1006 if (preg_match('/[^a-z0-9_\-\.@]+/i', $out)) {
1007 $out = '';
1008 }
1009 }
1010 break;
1011 case 'aZ09comma': // great to sanitize $sortfield or $sortorder params that can be 't.abc,t.def_gh'
1012 if (!is_array($out)) {
1013 $out = trim($out);
1014 if (preg_match('/[^a-z0-9_\-\.,]+/i', $out)) {
1015 $out = '';
1016 }
1017 }
1018 break;
1019 case 'alpha': // No html and no ../ and "
1020 case 'alphanohtml': // Recommended for most scalar parameters and search parameters
1021 if (!is_array($out)) {
1022 $out = trim($out);
1023 do {
1024 $oldstringtoclean = $out;
1025 // Remove html tags
1026 $out = dol_string_nohtmltag($out, 0);
1027 // Remove also other dangerous string sequences
1028 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1029 // '../' or '..\' is dangerous because it allows dir transversals
1030 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1031 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1032 } while ($oldstringtoclean != $out);
1033 // keep lines feed
1034 }
1035 break;
1036 case 'alphawithlgt': // No " and no ../ but we keep balanced < > tags with no special chars inside. Can be used for email string like "Name <email>". Less secured than 'alphanohtml'
1037 if (!is_array($out)) {
1038 $out = trim($out);
1039 do {
1040 $oldstringtoclean = $out;
1041 // Remove html tags
1042 $out = dol_html_entity_decode($out, ENT_COMPAT | ENT_HTML5, 'UTF-8');
1043 // '"' is dangerous because param in url can close the href= or src= and add javascript functions.
1044 // '../' or '..\' is dangerous because it allows dir transversals
1045 // Note &#38, '&#0000038', '&#x26'... is a simple char like '&' alone but there is no reason to accept such way to encode input data.
1046 $out = str_ireplace(array('&#38', '&#0000038', '&#x26', '&quot', '&#34', '&#0000034', '&#x22', '"', '&#47', '&#0000047', '&#92', '&#0000092', '&#x2F', '../', '..\\'), '', $out);
1047 } while ($oldstringtoclean != $out);
1048 }
1049 break;
1050 case 'nohtml': // No html
1051 $out = dol_string_nohtmltag($out, 0);
1052 break;
1053 case 'restricthtmlnolink':
1054 case 'restricthtml': // Recommended for most html textarea
1055 case 'restricthtmlallowclass':
1056 case 'restricthtmlallowunvalid':
1057 $out = dol_htmlwithnojs($out, 1, $check);
1058 break;
1059 case 'custom':
1060 if (!empty($out)) {
1061 if (empty($filter)) {
1062 return 'BadParameterForGETPOST - Param 3 of sanitizeVal()';
1063 }
1064 /*if (empty($options)) {
1065 return 'BadParameterForGETPOST - Param 4 of sanitizeVal()';
1066 }*/
1067 $out = filter_var($out, $filter, $options);
1068 }
1069 break;
1070 }
1071
1072 return $out;
1073}
1074
1075
1076if (!function_exists('dol_getprefix')) {
1086 function dol_getprefix($mode = '')
1087 {
1088 // If prefix is for email (we need to have $conf already loaded for this case)
1089 if ($mode == 'email') {
1090 global $conf;
1091
1092 if (!empty($conf->global->MAIL_PREFIX_FOR_EMAIL_ID)) { // If MAIL_PREFIX_FOR_EMAIL_ID is set
1093 if ($conf->global->MAIL_PREFIX_FOR_EMAIL_ID != 'SERVER_NAME') {
1094 return $conf->global->MAIL_PREFIX_FOR_EMAIL_ID;
1095 } elseif (isset($_SERVER["SERVER_NAME"])) { // If MAIL_PREFIX_FOR_EMAIL_ID is set to 'SERVER_NAME'
1096 return $_SERVER["SERVER_NAME"];
1097 }
1098 }
1099
1100 // The recommended value if MAIL_PREFIX_FOR_EMAIL_ID is not defined (may be not defined for old versions)
1101 if (!empty($conf->file->instance_unique_id)) {
1102 return sha1('dolibarr'.$conf->file->instance_unique_id);
1103 }
1104
1105 // For backward compatibility when instance_unique_id is not set
1106 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1107 }
1108
1109 // If prefix is for session (no need to have $conf loaded)
1110 global $dolibarr_main_instance_unique_id, $dolibarr_main_cookie_cryptkey; // This is loaded by filefunc.inc.php
1111 $tmp_instance_unique_id = empty($dolibarr_main_instance_unique_id) ? (empty($dolibarr_main_cookie_cryptkey) ? '' : $dolibarr_main_cookie_cryptkey) : $dolibarr_main_instance_unique_id; // Unique id of instance
1112
1113 // The recommended value (may be not defined for old versions)
1114 if (!empty($tmp_instance_unique_id)) {
1115 return sha1('dolibarr'.$tmp_instance_unique_id);
1116 }
1117
1118 // For backward compatibility when instance_unique_id is not set
1119 if (isset($_SERVER["SERVER_NAME"]) && isset($_SERVER["DOCUMENT_ROOT"])) {
1120 return sha1($_SERVER["SERVER_NAME"].$_SERVER["DOCUMENT_ROOT"].DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1121 } else {
1122 return sha1(DOL_DOCUMENT_ROOT.DOL_URL_ROOT);
1123 }
1124 }
1125}
1126
1137function dol_include_once($relpath, $classname = '')
1138{
1139 global $conf, $langs, $user, $mysoc; // Do not remove this. They must be defined for files we include. Other globals var must be retrieved with $GLOBALS['var']
1140
1141 $fullpath = dol_buildpath($relpath);
1142
1143 if (!file_exists($fullpath)) {
1144 dol_syslog('functions::dol_include_once Tried to load unexisting file: '.$relpath, LOG_WARNING);
1145 return false;
1146 }
1147
1148 if (!empty($classname) && !class_exists($classname)) {
1149 return include $fullpath;
1150 } else {
1151 return include_once $fullpath;
1152 }
1153}
1154
1155
1166function dol_buildpath($path, $type = 0, $returnemptyifnotfound = 0)
1167{
1168 global $conf;
1169
1170 $path = preg_replace('/^\//', '', $path);
1171
1172 if (empty($type)) { // For a filesystem path
1173 $res = DOL_DOCUMENT_ROOT.'/'.$path; // Standard default path
1174 if (is_array($conf->file->dol_document_root)) {
1175 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array("main"=>"/home/main/htdocs", "alt0"=>"/home/dirmod/htdocs", ...)
1176 if ($key == 'main') {
1177 continue;
1178 }
1179 // if (@file_exists($dirroot.'/'.$path)) {
1180 if (@file_exists($dirroot.'/'.$path)) { // avoid [php:warn]
1181 $res = $dirroot.'/'.$path;
1182 return $res;
1183 }
1184 }
1185 }
1186 if ($returnemptyifnotfound) {
1187 // Not found into alternate dir
1188 if ($returnemptyifnotfound == 1 || !file_exists($res)) {
1189 return '';
1190 }
1191 }
1192 } else {
1193 // For an url path
1194 // We try to get local path of file on filesystem from url
1195 // Note that trying to know if a file on disk exist by forging path on disk from url
1196 // works only for some web server and some setup. This is bugged when
1197 // using proxy, rewriting, virtual path, etc...
1198 $res = '';
1199 if ($type == 1) {
1200 $res = DOL_URL_ROOT.'/'.$path; // Standard value
1201 }
1202 if ($type == 2) {
1203 $res = DOL_MAIN_URL_ROOT.'/'.$path; // Standard value
1204 }
1205 if ($type == 3) {
1206 $res = DOL_URL_ROOT.'/'.$path;
1207 }
1208
1209 foreach ($conf->file->dol_document_root as $key => $dirroot) { // ex: array(["main"]=>"/home/main/htdocs", ["alt0"]=>"/home/dirmod/htdocs", ...)
1210 if ($key == 'main') {
1211 if ($type == 3) {
1212 global $dolibarr_main_url_root;
1213
1214 // Define $urlwithroot
1215 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
1216 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1217 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1218
1219 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).'/'.$path; // Test on start with http is for old conf syntax
1220 }
1221 continue;
1222 }
1223 $regs = array();
1224 preg_match('/^([^\?]+(\.css\.php|\.css|\.js\.php|\.js|\.png|\.jpg|\.php)?)/i', $path, $regs); // Take part before '?'
1225 if (!empty($regs[1])) {
1226 //print $key.'-'.$dirroot.'/'.$path.'-'.$conf->file->dol_url_root[$type].'<br>'."\n";
1227 //if (file_exists($dirroot.'/'.$regs[1])) {
1228 if (@file_exists($dirroot.'/'.$regs[1])) { // avoid [php:warn]
1229 if ($type == 1) {
1230 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1231 }
1232 if ($type == 2) {
1233 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : DOL_MAIN_URL_ROOT).$conf->file->dol_url_root[$key].'/'.$path;
1234 }
1235 if ($type == 3) {
1236 global $dolibarr_main_url_root;
1237
1238 // Define $urlwithroot
1239 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
1240 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
1241 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
1242
1243 $res = (preg_match('/^http/i', $conf->file->dol_url_root[$key]) ? '' : $urlwithroot).$conf->file->dol_url_root[$key].'/'.$path; // Test on start with http is for old conf syntax
1244 }
1245 break;
1246 }
1247 }
1248 }
1249 }
1250
1251 return $res;
1252}
1253
1265function dol_clone($object, $native = 0)
1266{
1267 if ($native == 0) {
1268 // deprecated method, use the method with native = 2 instead
1269 $tmpsavdb = null;
1270 if (isset($object->db) && isset($object->db->db) && is_object($object->db->db) && get_class($object->db->db) == 'PgSql\Connection') {
1271 $tmpsavdb = $object->db;
1272 unset($object->db); // Such property can not be serialized with pgsl (when object->db->db = 'PgSql\Connection')
1273 }
1274
1275 $myclone = unserialize(serialize($object)); // serialize then unserialize is a hack to be sure to have a new object for all fields
1276
1277 if (!empty($tmpsavdb)) {
1278 $object->db = $tmpsavdb;
1279 }
1280 } elseif ($native == 2) {
1281 // recommended method to have a full isolated cloned object
1282 $myclone = new stdClass();
1283 $tmparray = get_object_vars($object); // return only public properties
1284
1285 if (is_array($tmparray)) {
1286 foreach ($tmparray as $propertykey => $propertyval) {
1287 if (is_scalar($propertyval) || is_array($propertyval)) {
1288 $myclone->$propertykey = $propertyval;
1289 }
1290 }
1291 }
1292 } else {
1293 $myclone = clone $object; // PHP clone is a shallow copy only, not a real clone, so properties of references will keep the reference (refering to the same target/variable)
1294 }
1295
1296 return $myclone;
1297}
1298
1308function dol_size($size, $type = '')
1309{
1310 global $conf;
1311 if (empty($conf->dol_optimize_smallscreen)) {
1312 return $size;
1313 }
1314 if ($type == 'width' && $size > 250) {
1315 return 250;
1316 } else {
1317 return 10;
1318 }
1319}
1320
1321
1333function dol_sanitizeFileName($str, $newstr = '_', $unaccent = 1)
1334{
1335 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1336 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1337 // Char '/' and '\' are file delimiters.
1338 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1339 $filesystem_forbidden_chars = array('<', '>', '/', '\\', '?', '*', '|', '"', ':', '°', '$', ';', '`');
1340 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1341 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1342 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1343 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1344 $tmp = str_replace('..', '', $tmp);
1345 return $tmp;
1346}
1347
1359function dol_sanitizePathName($str, $newstr = '_', $unaccent = 1)
1360{
1361 // List of special chars for filenames in windows are defined on page https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
1362 // Char '>' '<' '|' '$' and ';' are special chars for shells.
1363 // Chars '--' can be used into filename to inject special paramaters like --use-compress-program to make command with file as parameter making remote execution of command
1364 $filesystem_forbidden_chars = array('<', '>', '?', '*', '|', '"', '°', '$', ';', '`');
1365 $tmp = dol_string_nospecial($unaccent ? dol_string_unaccent($str) : $str, $newstr, $filesystem_forbidden_chars);
1366 $tmp = preg_replace('/\-\-+/', '_', $tmp);
1367 $tmp = preg_replace('/\s+\-([^\s])/', ' _$1', $tmp);
1368 $tmp = preg_replace('/\s+\-$/', '', $tmp);
1369 $tmp = str_replace('..', '', $tmp);
1370 return $tmp;
1371}
1372
1380function dol_sanitizeUrl($stringtoclean, $type = 1)
1381{
1382 // We clean string because some hacks try to obfuscate evil strings by inserting non printable chars. Example: 'java(ascci09)scr(ascii00)ipt' is processed like 'javascript' (whatever is place of evil ascii char)
1383 // We should use dol_string_nounprintableascii but function may not be yet loaded/available
1384 $stringtoclean = preg_replace('/[\x00-\x1F\x7F]/u', '', $stringtoclean); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1385 // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: on<!-- -->error=alert(1)
1386 $stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
1387
1388 $stringtoclean = str_replace('\\', '/', $stringtoclean);
1389 if ($type == 1) {
1390 // removing : should disable links to external url like http:aaa)
1391 // removing ';' should disable "named" html entities encode into an url (we should not have this into an url)
1392 $stringtoclean = str_replace(array(':', ';', '@'), '', $stringtoclean);
1393 }
1394
1395 do {
1396 $oldstringtoclean = $stringtoclean;
1397 // removing '&colon' should disable links to external url like http:aaa)
1398 // removing '&#' should disable "numeric" html entities encode into an url (we should not have this into an url)
1399 $stringtoclean = str_ireplace(array('javascript', 'vbscript', '&colon', '&#'), '', $stringtoclean);
1400 } while ($oldstringtoclean != $stringtoclean);
1401
1402 if ($type == 1) {
1403 // removing '//' should disable links to external url like //aaa or http//)
1404 $stringtoclean = preg_replace(array('/^[a-z]*\/\/+/i'), '', $stringtoclean);
1405 }
1406
1407 return $stringtoclean;
1408}
1409
1416function dol_sanitizeEmail($stringtoclean)
1417{
1418 do {
1419 $oldstringtoclean = $stringtoclean;
1420 $stringtoclean = str_ireplace(array('"', ':', '[', ']',"\n", "\r", '\\', '\/'), '', $stringtoclean);
1421 } while ($oldstringtoclean != $stringtoclean);
1422
1423 return $stringtoclean;
1424}
1425
1435{
1436 global $conf;
1437
1438 if (is_null($str)) {
1439 return '';
1440 }
1441
1442 if (utf8_check($str)) {
1443 if (extension_loaded('intl') && !empty($conf->global->MAIN_UNACCENT_USE_TRANSLITERATOR)) {
1444 $transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: NFC;', Transliterator::FORWARD);
1445 return $transliterator->transliterate($str);
1446 }
1447 // See http://www.utf8-chartable.de/
1448 $string = rawurlencode($str);
1449 $replacements = array(
1450 '%C3%80' => 'A', '%C3%81' => 'A', '%C3%82' => 'A', '%C3%83' => 'A', '%C3%84' => 'A', '%C3%85' => 'A',
1451 '%C3%87' => 'C',
1452 '%C3%88' => 'E', '%C3%89' => 'E', '%C3%8A' => 'E', '%C3%8B' => 'E',
1453 '%C3%8C' => 'I', '%C3%8D' => 'I', '%C3%8E' => 'I', '%C3%8F' => 'I',
1454 '%C3%91' => 'N',
1455 '%C3%92' => 'O', '%C3%93' => 'O', '%C3%94' => 'O', '%C3%95' => 'O', '%C3%96' => 'O',
1456 '%C5%A0' => 'S',
1457 '%C3%99' => 'U', '%C3%9A' => 'U', '%C3%9B' => 'U', '%C3%9C' => 'U',
1458 '%C3%9D' => 'Y', '%C5%B8' => 'y',
1459 '%C3%A0' => 'a', '%C3%A1' => 'a', '%C3%A2' => 'a', '%C3%A3' => 'a', '%C3%A4' => 'a', '%C3%A5' => 'a',
1460 '%C3%A7' => 'c',
1461 '%C3%A8' => 'e', '%C3%A9' => 'e', '%C3%AA' => 'e', '%C3%AB' => 'e',
1462 '%C3%AC' => 'i', '%C3%AD' => 'i', '%C3%AE' => 'i', '%C3%AF' => 'i',
1463 '%C3%B1' => 'n',
1464 '%C3%B2' => 'o', '%C3%B3' => 'o', '%C3%B4' => 'o', '%C3%B5' => 'o', '%C3%B6' => 'o',
1465 '%C5%A1' => 's',
1466 '%C3%B9' => 'u', '%C3%BA' => 'u', '%C3%BB' => 'u', '%C3%BC' => 'u',
1467 '%C3%BD' => 'y', '%C3%BF' => 'y'
1468 );
1469 $string = strtr($string, $replacements);
1470 return rawurldecode($string);
1471 } else {
1472 // See http://www.ascii-code.com/
1473 $string = strtr(
1474 $str,
1475 "\xC0\xC1\xC2\xC3\xC4\xC5\xC7
1476 \xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1
1477 \xD2\xD3\xD4\xD5\xD8\xD9\xDA\xDB\xDD
1478 \xE0\xE1\xE2\xE3\xE4\xE5\xE7\xE8\xE9\xEA\xEB
1479 \xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF8
1480 \xF9\xFA\xFB\xFC\xFD\xFF",
1481 "AAAAAAC
1482 EEEEIIIIDN
1483 OOOOOUUUY
1484 aaaaaaceeee
1485 iiiidnooooo
1486 uuuuyy"
1487 );
1488 $string = strtr($string, array("\xC4"=>"Ae", "\xC6"=>"AE", "\xD6"=>"Oe", "\xDC"=>"Ue", "\xDE"=>"TH", "\xDF"=>"ss", "\xE4"=>"ae", "\xE6"=>"ae", "\xF6"=>"oe", "\xFC"=>"ue", "\xFE"=>"th"));
1489 return $string;
1490 }
1491}
1492
1506function dol_string_nospecial($str, $newstr = '_', $badcharstoreplace = '', $badcharstoremove = '', $keepspaces = 0)
1507{
1508 $forbidden_chars_to_replace = array("'", "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "[", "]", ",", ";", "=", '°', '$', ';'); // more complete than dol_sanitizeFileName
1509 if (empty($keepspaces)) {
1510 $forbidden_chars_to_replace[] = " ";
1511 }
1512 $forbidden_chars_to_remove = array();
1513 //$forbidden_chars_to_remove=array("(",")");
1514
1515 if (is_array($badcharstoreplace)) {
1516 $forbidden_chars_to_replace = $badcharstoreplace;
1517 }
1518 if (is_array($badcharstoremove)) {
1519 $forbidden_chars_to_remove = $badcharstoremove;
1520 }
1521
1522 return str_replace($forbidden_chars_to_replace, $newstr, str_replace($forbidden_chars_to_remove, "", $str));
1523}
1524
1525
1539function dol_string_nounprintableascii($str, $removetabcrlf = 1)
1540{
1541 if ($removetabcrlf) {
1542 return preg_replace('/[\x00-\x1F\x7F]/u', '', $str); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
1543 } else {
1544 return preg_replace('/[\x00-\x08\x11-\x12\x14-\x1F\x7F]/u', '', $str); // /u operator should make UTF8 valid characters being ignored so are not included into the replace
1545 }
1546}
1547
1556function dol_escape_js($stringtoescape, $mode = 0, $noescapebackslashn = 0)
1557{
1558 if (is_null($stringtoescape)) {
1559 return '';
1560 }
1561
1562 // escape quotes and backslashes, newlines, etc.
1563 $substitjs = array("&#039;"=>"\\'", "\r"=>'\\r');
1564 //$substitjs['</']='<\/'; // We removed this. Should be useless.
1565 if (empty($noescapebackslashn)) {
1566 $substitjs["\n"] = '\\n';
1567 $substitjs['\\'] = '\\\\';
1568 }
1569 if (empty($mode)) {
1570 $substitjs["'"] = "\\'";
1571 $substitjs['"'] = "\\'";
1572 } elseif ($mode == 1) {
1573 $substitjs["'"] = "\\'";
1574 } elseif ($mode == 2) {
1575 $substitjs['"'] = '\\"';
1576 } elseif ($mode == 3) {
1577 $substitjs["'"] = "\\'";
1578 $substitjs['"'] = "\\\"";
1579 }
1580 return strtr($stringtoescape, $substitjs);
1581}
1582
1589function dol_escape_json($stringtoescape)
1590{
1591 return str_replace('"', '\"', $stringtoescape);
1592}
1593
1601function dolPrintLabel($s)
1602{
1604}
1605
1613function dolPrintHTML($s)
1614{
1615 return dol_escape_htmltag(dol_htmlwithnojs(dol_string_onlythesehtmltags(dol_htmlentitiesbr($s), 1, 1, 1)), 1, 1, 'common', 0, 1);
1616}
1617
1626{
1628}
1629
1630
1647function dol_escape_htmltag($stringtoescape, $keepb = 0, $keepn = 0, $noescapetags = '', $escapeonlyhtmltags = 0, $cleanalsojavascript = 0)
1648{
1649 if ($noescapetags == 'common') {
1650 $noescapetags = 'html,body,a,b,em,hr,i,u,ul,li,br,div,img,font,p,span,strong,table,tr,td,th,tbody';
1651 }
1652 if ($cleanalsojavascript) {
1653 $stringtoescape = dol_string_onlythesehtmltags($stringtoescape, 0, 0, $cleanalsojavascript, 0, array(), 0);
1654 }
1655
1656 // escape quotes and backslashes, newlines, etc.
1657 if ($escapeonlyhtmltags) {
1658 $tmp = htmlspecialchars_decode((string) $stringtoescape, ENT_COMPAT);
1659 } else {
1660 $tmp = html_entity_decode((string) $stringtoescape, ENT_COMPAT, 'UTF-8');
1661 }
1662 if (!$keepb) {
1663 $tmp = strtr($tmp, array("<b>"=>'', '</b>'=>'', '<strong>'=>'', '</strong>'=>''));
1664 }
1665 if (!$keepn) {
1666 $tmp = strtr($tmp, array("\r"=>'\\r', "\n"=>'\\n'));
1667 }
1668
1669 if ($escapeonlyhtmltags) {
1670 return htmlspecialchars($tmp, ENT_COMPAT, 'UTF-8');
1671 } else {
1672 // Escape tags to keep
1673 // TODO Does not works yet when there is attributes into tag
1674 $tmparrayoftags = array();
1675 if ($noescapetags) {
1676 $tmparrayoftags = explode(',', $noescapetags);
1677 }
1678 if (count($tmparrayoftags)) {
1679 foreach ($tmparrayoftags as $tagtoreplace) {
1680 $tmp = str_ireplace('<'.$tagtoreplace.'>', '__BEGINTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1681 $tmp = str_ireplace('</'.$tagtoreplace.'>', '__ENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1682 $tmp = str_ireplace('<'.$tagtoreplace.' />', '__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', $tmp);
1683 }
1684 }
1685
1686 $result = htmlentities($tmp, ENT_COMPAT, 'UTF-8');
1687
1688 if (count($tmparrayoftags)) {
1689 foreach ($tmparrayoftags as $tagtoreplace) {
1690 $result = str_ireplace('__BEGINTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.'>', $result);
1691 $result = str_ireplace('__ENDTAGTOREPLACE'.$tagtoreplace.'__', '</'.$tagtoreplace.'>', $result);
1692 $result = str_ireplace('__BEGINENDTAGTOREPLACE'.$tagtoreplace.'__', '<'.$tagtoreplace.' />', $result);
1693 }
1694 }
1695
1696 return $result;
1697 }
1698}
1699
1707function dol_strtolower($string, $encoding = "UTF-8")
1708{
1709 if (function_exists('mb_strtolower')) {
1710 return mb_strtolower($string, $encoding);
1711 } else {
1712 return strtolower($string);
1713 }
1714}
1715
1724function dol_strtoupper($string, $encoding = "UTF-8")
1725{
1726 if (function_exists('mb_strtoupper')) {
1727 return mb_strtoupper($string, $encoding);
1728 } else {
1729 return strtoupper($string);
1730 }
1731}
1732
1741function dol_ucfirst($string, $encoding = "UTF-8")
1742{
1743 if (function_exists('mb_substr')) {
1744 return mb_strtoupper(mb_substr($string, 0, 1, $encoding), $encoding).mb_substr($string, 1, null, $encoding);
1745 } else {
1746 return ucfirst($string);
1747 }
1748}
1749
1758function dol_ucwords($string, $encoding = "UTF-8")
1759{
1760 if (function_exists('mb_convert_case')) {
1761 return mb_convert_case($string, MB_CASE_TITLE, $encoding);
1762 } else {
1763 return ucwords($string);
1764 }
1765}
1766
1788function dol_syslog($message, $level = LOG_INFO, $ident = 0, $suffixinfilename = '', $restricttologhandler = '', $logcontext = null)
1789{
1790 global $conf, $user, $debugbar;
1791
1792 // If syslog module enabled
1793 if (!isModEnabled('syslog')) {
1794 return;
1795 }
1796
1797 // Check if we are into execution of code of a website
1798 if (defined('USEEXTERNALSERVER') && !defined('USEDOLIBARRSERVER') && !defined('USEDOLIBARREDITOR')) {
1799 global $website, $websitekey;
1800 if (is_object($website) && !empty($website->ref)) {
1801 $suffixinfilename .= '_website_'.$website->ref;
1802 } elseif (!empty($websitekey)) {
1803 $suffixinfilename .= '_website_'.$websitekey;
1804 }
1805 }
1806
1807 // Check if we have a forced suffix
1808 if (defined('USESUFFIXINLOG')) {
1809 $suffixinfilename .= constant('USESUFFIXINLOG');
1810 }
1811
1812 if ($ident < 0) {
1813 foreach ($conf->loghandlers as $loghandlerinstance) {
1814 $loghandlerinstance->setIdent($ident);
1815 }
1816 }
1817
1818 if (!empty($message)) {
1819 // Test log level
1820 $logLevels = array(LOG_EMERG=>'EMERG', LOG_ALERT=>'ALERT', LOG_CRIT=>'CRITICAL', LOG_ERR=>'ERR', LOG_WARNING=>'WARN', LOG_NOTICE=>'NOTICE', LOG_INFO=>'INFO', LOG_DEBUG=>'DEBUG');
1821 if (!array_key_exists($level, $logLevels)) {
1822 throw new Exception('Incorrect log level');
1823 }
1824 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
1825 return;
1826 }
1827
1828 if (empty($conf->global->MAIN_SHOW_PASSWORD_INTO_LOG)) {
1829 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
1830 }
1831
1832 // If adding log inside HTML page is required
1833 if ((!empty($_REQUEST['logtohtml']) && !empty($conf->global->MAIN_ENABLE_LOG_TO_HTML))
1834 || (!empty($user->rights->debugbar->read) && is_object($debugbar))) {
1835 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".$logLevels[$level]." ".$message;
1836 }
1837
1838 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
1839 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
1840 if (!empty($conf->global->MAIN_ENABLE_LOG_INLINE_HTML) && !empty($_GET["log"])) {
1841 print "\n\n<!-- Log start\n";
1842 print dol_escape_htmltag($message)."\n";
1843 print "Log end -->\n";
1844 }
1845
1846 $data = array(
1847 'message' => $message,
1848 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
1849 'level' => $level,
1850 'user' => ((is_object($user) && $user->id) ? $user->login : false),
1851 'ip' => false
1852 );
1853
1854 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
1855 if (!empty($remoteip)) {
1856 $data['ip'] = $remoteip;
1857 // This is when server run behind a reverse proxy
1858 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
1859 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
1860 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
1861 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
1862 }
1863 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
1864 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
1865 $data['ip'] = $_SERVER['SERVER_ADDR'];
1866 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
1867 // This is when PHP session is ran outside a web server, like from Windows command line (Not always defined, but useful if OS defined it).
1868 $data['ip'] = $_SERVER['COMPUTERNAME'].(empty($_SERVER['USERNAME']) ? '' : '@'.$_SERVER['USERNAME']);
1869 } elseif (!empty($_SERVER['LOGNAME'])) {
1870 // This is when PHP session is ran outside a web server, like from Linux command line (Not always defined, but usefull if OS defined it).
1871 $data['ip'] = '???@'.$_SERVER['LOGNAME'];
1872 }
1873
1874 // Loop on each log handler and send output
1875 foreach ($conf->loghandlers as $loghandlerinstance) {
1876 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
1877 continue;
1878 }
1879 $loghandlerinstance->export($data, $suffixinfilename);
1880 }
1881 unset($data);
1882 }
1883
1884 if ($ident > 0) {
1885 foreach ($conf->loghandlers as $loghandlerinstance) {
1886 $loghandlerinstance->setIdent($ident);
1887 }
1888 }
1889}
1890
1907function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
1908{
1909 global $conf;
1910
1911 if (strpos($url, '?') > 0) {
1912 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1913 } else {
1914 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1915 }
1916
1917 $out = '';
1918
1919 $backtopagejsfieldsid = ''; $backtopagejsfieldslabel = '';
1920 if ($backtopagejsfields) {
1921 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
1922 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
1923 $backtopagejsfields = $name.":".$backtopagejsfields;
1924 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
1925 } else {
1926 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
1927 }
1928 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
1929 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
1930 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
1931 }
1932
1933 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
1934 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
1935 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
1936 if (empty($conf->use_javascript_ajax)) {
1937 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
1938 } elseif ($jsonopen) {
1939 $out .= ' href="#" onclick="'.$jsonopen.'"';
1940 } else {
1941 $out .= ' href="#"';
1942 }
1943 $out .= '>'.$buttonstring.'</a>';
1944
1945 if (!empty($conf->use_javascript_ajax)) {
1946 // Add code to open url using the popup. Add also hidden field to retreive the returned variables
1947 $out .= '<!-- code to open popup and variables to retreive returned variables -->';
1948 $out .= '<div id="idfordialog'.$name.'" class="hidden">div for dialog</div>';
1949 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">div for returned id</div>';
1950 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">div for returned label</div>';
1951 $out .= '<!-- Add js code to open dialog popup on dialog -->';
1952 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
1953 jQuery(document).ready(function () {
1954 jQuery(".button_'.$name.'").click(function () {
1955 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
1956 var $tmpdialog = $(\'#idfordialog'.$name.'\');
1957 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
1958 $tmpdialog.dialog({
1959 autoOpen: false,
1960 modal: true,
1961 height: (window.innerHeight - 150),
1962 width: \'80%\',
1963 title: \''.dol_escape_js($label).'\',
1964 open: function (event, ui) {
1965 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
1966 },
1967 close: function (event, ui) {
1968 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
1969 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
1970 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
1971 if (returnedid != "" && returnedid != "div for returned id") {
1972 jQuery("#'.(empty($backtopagejsfieldsid)?"none":$backtopagejsfieldsid).'").val(returnedid);
1973 }
1974 if (returnedlabel != "" && returnedlabel != "div for returned label") {
1975 jQuery("#'.(empty($backtopagejsfieldslabel)?"none":$backtopagejsfieldslabel).'").val(returnedlabel);
1976 }
1977 }
1978 });
1979
1980 $tmpdialog.dialog(\'open\');
1981 return false;
1982 });
1983 });
1984 </script>';
1985 }
1986 return $out;
1987}
1988
2005function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2006{
2007 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2008}
2009
2026function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2027{
2028 global $conf, $langs, $hookmanager;
2029
2030 // Show title
2031 $showtitle = 1;
2032 if (!empty($conf->dol_optimize_smallscreen)) {
2033 $showtitle = 0;
2034 }
2035
2036 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2037
2038 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2039 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2040 }
2041
2042 // Show right part
2043 if ($morehtmlright) {
2044 $out .= '<div class="inline-block floatright tabsElem">'.$morehtmlright.'</div>'; // Output right area first so when space is missing, text is in front of tabs and not under.
2045 }
2046
2047 // Show title
2048 if (!empty($title) && $showtitle && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2049 $limittitle = 30;
2050 $out .= '<a class="tabTitle">';
2051 if ($picto) {
2052 $noprefix = $pictoisfullpath;
2053 if (strpos($picto, 'fontawesome_') !== false) {
2054 $noprefix = 1;
2055 }
2056 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2057 }
2058 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2059 $out .= '</a>';
2060 }
2061
2062 // Show tabs
2063
2064 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2065 $maxkey = -1;
2066 if (is_array($links) && !empty($links)) {
2067 $keys = array_keys($links);
2068 if (count($keys)) {
2069 $maxkey = max($keys);
2070 }
2071 }
2072
2073 // Show tabs
2074 // if =0 we don't use the feature
2075 if (empty($limittoshow)) {
2076 $limittoshow = (empty($conf->global->MAIN_MAXTABS_IN_CARD) ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2077 }
2078 if (!empty($conf->dol_optimize_smallscreen)) {
2079 $limittoshow = 2;
2080 }
2081
2082 $displaytab = 0;
2083 $nbintab = 0;
2084 $popuptab = 0;
2085 $outmore = '';
2086 for ($i = 0; $i <= $maxkey; $i++) {
2087 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2088 // If active tab is already present
2089 if ($i >= $limittoshow) {
2090 $limittoshow--;
2091 }
2092 }
2093 }
2094
2095 for ($i = 0; $i <= $maxkey; $i++) {
2096 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2097 $isactive = true;
2098 } else {
2099 $isactive = false;
2100 }
2101
2102 if ($i < $limittoshow || $isactive) {
2103 // Output entry with a visible tab
2104 $out .= '<div class="inline-block tabsElem'.($isactive ? ' tabsElemActive' : '').((!$isactive && !empty($conf->global->MAIN_HIDE_INACTIVETAB_ON_PRINT)) ? ' hideonprint' : '').'"><!-- id tab = '.(empty($links[$i][2]) ? '' : dol_escape_htmltag($links[$i][2])).' -->';
2105
2106 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2107 if (!empty($links[$i][0])) {
2108 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2109 } else {
2110 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2111 }
2112 } elseif (!empty($links[$i][1])) {
2113 //print "x $i $active ".$links[$i][2]." z";
2114 $out .= '<div class="tab tab'.($isactive?'active':'unactive').'" style="margin: 0 !important">';
2115 if (!empty($links[$i][0])) {
2116 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2117 $out .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="tab inline-block valignmiddle'.($morecss ? ' '.$morecss : '').(!empty($links[$i][5]) ? ' '.$links[$i][5] : '').'" href="'.$links[$i][0].'" title="'.dol_escape_htmltag($titletoshow).'">';
2118 }
2119 $out .= $links[$i][1];
2120 if (!empty($links[$i][0])) {
2121 $out .= '</a>'."\n";
2122 }
2123 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2124 $out .= '</div>';
2125 }
2126
2127 $out .= '</div>';
2128 } else {
2129 // Add entry into the combo popup with the other tabs
2130 if (!$popuptab) {
2131 $popuptab = 1;
2132 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2133 }
2134 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2135 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2136 if (!empty($links[$i][0])) {
2137 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2138 } else {
2139 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2140 }
2141 } elseif (!empty($links[$i][1])) {
2142 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2143 $outmore .= preg_replace('/([a-z])\|([a-z])/i', '\\1 | \\2', $links[$i][1]); // Replace x|y with x | y to allow wrap on long composed texts.
2144 $outmore .= '</a>'."\n";
2145 }
2146 $outmore .= '</div>';
2147
2148 $nbintab++;
2149 }
2150 $displaytab = $i;
2151 }
2152 if ($popuptab) {
2153 $outmore .= '</div>';
2154 }
2155
2156 if ($popuptab) { // If there is some tabs not shown
2157 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2158 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2159 $widthofpopup = 200;
2160
2161 $tabsname = $moretabssuffix;
2162 if (empty($tabsname)) {
2163 $tabsname = str_replace("@", "", $picto);
2164 }
2165 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2166 $out .= '<div class="tab"><a href="#" class="tab moretab inline-block tabunactive"><span class="hideonsmartphone">'.$langs->trans("More").'</span>... ('.$nbintab.')</a></div>'; // Do not use "reposition" class in the "More".
2167 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2168 $out .= $outmore;
2169 $out .= '</div>';
2170 $out .= '<div></div>';
2171 $out .= "</div>\n";
2172
2173 $out .= '<script nonce="'.getNonce().'">';
2174 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2175 var x = this.offsetLeft, y = this.offsetTop;
2176 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2177 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2178 $('#moretabsList".$tabsname."').css('".$right."','8px');
2179 }
2180 $('#moretabsList".$tabsname."').css('".$left."','auto');
2181 });
2182 ";
2183 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2184 $out .= "</script>";
2185 }
2186
2187 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2188 $out .= "</div>\n";
2189 }
2190
2191 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2192 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom'))).'">'."\n";
2193 }
2194 if (!empty($dragdropfile)) {
2195 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2196 }
2197 $parameters = array('tabname' => $active, 'out' => $out);
2198 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2199 if ($reshook > 0) {
2200 $out = $hookmanager->resPrint;
2201 }
2202
2203 return $out;
2204}
2205
2213function dol_fiche_end($notab = 0)
2214{
2215 print dol_get_fiche_end($notab);
2216}
2217
2224function dol_get_fiche_end($notab = 0)
2225{
2226 if (!$notab || $notab == -1) {
2227 return "\n</div>\n";
2228 } else {
2229 return '';
2230 }
2231}
2232
2252function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2253{
2254 global $conf, $form, $user, $langs, $hookmanager, $action;
2255
2256 $error = 0;
2257
2258 $maxvisiblephotos = 1;
2259 $showimage = 1;
2260 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2261 $showbarcode = empty($conf->barcode->enabled) ? 0 : (empty($object->barcode) ? 0 : 1);
2262 if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) {
2263 $showbarcode = 0;
2264 }
2265 $modulepart = 'unknown';
2266
2267 if ($object->element == 'societe' || $object->element == 'contact' || $object->element == 'product' || $object->element == 'ticket') {
2268 $modulepart = $object->element;
2269 } elseif ($object->element == 'member') {
2270 $modulepart = 'memberphoto';
2271 } elseif ($object->element == 'user') {
2272 $modulepart = 'userphoto';
2273 }
2274
2275 if (class_exists("Imagick")) {
2276 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2277 $modulepart = $object->element;
2278 } elseif ($object->element == 'fichinter') {
2279 $modulepart = 'ficheinter';
2280 } elseif ($object->element == 'contrat') {
2281 $modulepart = 'contract';
2282 } elseif ($object->element == 'order_supplier') {
2283 $modulepart = 'supplier_order';
2284 } elseif ($object->element == 'invoice_supplier') {
2285 $modulepart = 'supplier_invoice';
2286 }
2287 }
2288
2289 if ($object->element == 'product') {
2290 $width = 80;
2291 $cssclass = 'photowithmargin photoref';
2292 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2293 $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : 5);
2294 if ($conf->browser->layout == 'phone') {
2295 $maxvisiblephotos = 1;
2296 }
2297 if ($showimage) {
2298 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$object->show_photos('product', $conf->product->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, 0, $width, 0, '').'</div>';
2299 } else {
2300 if (!empty($conf->global->PRODUCT_NODISPLAYIFNOPHOTO)) {
2301 $nophoto = '';
2302 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2303 } else { // Show no photo link
2304 $nophoto = '/public/theme/common/nophoto.png';
2305 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" title="'.dol_escape_htmltag($langs->trans("UploadAnImageToSeeAPhotoHere", $langs->transnoentitiesnoconv("Documents"))).'" alt="No photo"'.($width ? ' style="width: '.$width.'px"' : '').' src="'.DOL_URL_ROOT.$nophoto.'"></div>';
2306 }
2307 }
2308 } elseif ($object->element == 'ticket') {
2309 $width = 80;
2310 $cssclass = 'photoref';
2311 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2312 $maxvisiblephotos = (isset($conf->global->TICKET_MAX_VISIBLE_PHOTO) ? $conf->global->TICKET_MAX_VISIBLE_PHOTO : 2);
2313 if ($conf->browser->layout == 'phone') {
2314 $maxvisiblephotos = 1;
2315 }
2316
2317 if ($showimage) {
2318 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2319 if ($object->nbphoto > 0) {
2320 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2321 } else {
2322 $showimage = 0;
2323 }
2324 }
2325 if (!$showimage) {
2326 if (!empty($conf->global->TICKET_NODISPLAYIFNOPHOTO)) {
2327 $nophoto = '';
2328 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2329 } else { // Show no photo link
2330 $nophoto = img_picto('No photo', 'object_ticket');
2331 $morehtmlleft .= '<!-- No photo to show -->';
2332 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2333 $morehtmlleft .= $nophoto;
2334 $morehtmlleft .= '</div></div>';
2335 }
2336 }
2337 } else {
2338 if ($showimage) {
2339 if ($modulepart != 'unknown') {
2340 $phototoshow = '';
2341 // Check if a preview file is available
2342 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2343 $objectref = dol_sanitizeFileName($object->ref);
2344 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2345 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2346 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2347 $subdir .= ((!empty($subdir) && !preg_match('/\/$/', $subdir)) ? '/' : '').$objectref; // the objectref dir is not included into get_exdir when used with level=2, so we add it at end
2348 } else {
2349 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2350 }
2351 if (empty($subdir)) {
2352 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2353 }
2354
2355 $filepath = $dir_output.$subdir."/";
2356
2357 $filepdf = $filepath.$objectref.".pdf";
2358 $relativepath = $subdir.'/'.$objectref.'.pdf';
2359
2360 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2361 $fileimage = $filepdf.'_preview.png';
2362 $relativepathimage = $relativepath.'_preview.png';
2363
2364 $pdfexists = file_exists($filepdf);
2365
2366 // If PDF file exists
2367 if ($pdfexists) {
2368 // Conversion du PDF en image png si fichier png non existant
2369 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2370 if (empty($conf->global->MAIN_DISABLE_PDF_THUMBS)) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2371 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2372 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2373 if ($ret < 0) {
2374 $error++;
2375 }
2376 }
2377 }
2378 }
2379
2380 if ($pdfexists && !$error) {
2381 $heightforphotref = 80;
2382 if (!empty($conf->dol_optimize_smallscreen)) {
2383 $heightforphotref = 60;
2384 }
2385 // If the preview file is found
2386 if (file_exists($fileimage)) {
2387 $phototoshow = '<div class="photoref">';
2388 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2389 $phototoshow .= '</div>';
2390 }
2391 }
2392 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo'
2393 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2394 }
2395
2396 if ($phototoshow) {
2397 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2398 $morehtmlleft .= $phototoshow;
2399 $morehtmlleft .= '</div>';
2400 }
2401 }
2402
2403 if (empty($phototoshow)) { // Show No photo link (picto of object)
2404 if ($object->element == 'action') {
2405 $width = 80;
2406 $cssclass = 'photorefcenter';
2407 $nophoto = img_picto('No photo', 'title_agenda');
2408 } else {
2409 $width = 14;
2410 $cssclass = 'photorefcenter';
2411 $picto = $object->picto;
2412 $prefix = 'object_';
2413 if ($object->element == 'project' && !$object->public) {
2414 $picto = 'project'; // instead of projectpub
2415 }
2416 if (strpos($picto, 'fontawesome_') !== false) {
2417 $prefix = '';
2418 }
2419 $nophoto = img_picto('No photo', $prefix.$picto);
2420 }
2421 $morehtmlleft .= '<!-- No photo to show -->';
2422 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2423 $morehtmlleft .= $nophoto;
2424 $morehtmlleft .= '</div></div>';
2425 }
2426 }
2427 }
2428
2429 // Show barcode
2430 if ($showbarcode) {
2431 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2432 }
2433
2434 if ($object->element == 'societe') {
2435 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2436 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2437 } else {
2438 $morehtmlstatus .= $object->getLibStatut(6);
2439 }
2440 } elseif ($object->element == 'product') {
2441 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2442 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2443 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2444 } else {
2445 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2446 }
2447 $morehtmlstatus .= ' &nbsp; ';
2448 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2449 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2450 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2451 } else {
2452 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2453 }
2454 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier'))) {
2455 $totalallpayments = $object->getSommePaiement(0);
2456 $totalallpayments += $object->getSumCreditNotesUsed(0);
2457 $totalallpayments += $object->getSumDepositsUsed(0);
2458 $tmptxt = $object->getLibStatut(6, $totalallpayments);
2459 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2460 $tmptxt = $object->getLibStatut(5, $totalallpayments);
2461 }
2462 $morehtmlstatus .= $tmptxt;
2463 } elseif (in_array($object->element, array('chargesociales', 'loan', 'tva'))) {
2464 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2465 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2466 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2467 }
2468 $morehtmlstatus .= $tmptxt;
2469 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2470 if ($object->statut == 0) {
2471 $morehtmlstatus .= $object->getLibStatut(5);
2472 } else {
2473 $morehtmlstatus .= $object->getLibStatut(4);
2474 }
2475 } elseif ($object->element == 'facturerec') {
2476 if ($object->frequency == 0) {
2477 $morehtmlstatus .= $object->getLibStatut(2);
2478 } else {
2479 $morehtmlstatus .= $object->getLibStatut(5);
2480 }
2481 } elseif ($object->element == 'project_task') {
2482 $object->fk_statut = 1;
2483 if ($object->progress > 0) {
2484 $object->fk_statut = 2;
2485 }
2486 if ($object->progress >= 100) {
2487 $object->fk_statut = 3;
2488 }
2489 $tmptxt = $object->getLibStatut(5);
2490 $morehtmlstatus .= $tmptxt; // No status on task
2491 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2492 $tmptxt = $object->getLibStatut(6);
2493 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2494 $tmptxt = $object->getLibStatut(5);
2495 }
2496 $morehtmlstatus .= $tmptxt;
2497 }
2498
2499 // Add if object was dispatched "into accountancy"
2500 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2501 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2502 if (method_exists($object, 'getVentilExportCompta')) {
2503 $accounted = $object->getVentilExportCompta();
2504 $langs->load("accountancy");
2505 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2506 }
2507 }
2508
2509 // Add alias for thirdparty
2510 if (!empty($object->name_alias)) {
2511 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
2512 }
2513
2514 // Add label
2515 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
2516 if (!empty($object->label)) {
2517 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
2518 }
2519 }
2520
2521 // Show address and email
2522 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
2523 $moreaddress = $object->getBannerAddress('refaddress', $object);
2524 if ($moreaddress) {
2525 $morehtmlref .= '<div class="refidno refaddress">';
2526 $morehtmlref .= $moreaddress;
2527 $morehtmlref .= '</div>';
2528 }
2529 }
2530 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)) {
2531 $morehtmlref .= '<div style="clear: both;"></div>';
2532 $morehtmlref .= '<div class="refidno opacitymedium">';
2533 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
2534 $morehtmlref .= '</div>';
2535 }
2536
2537 $parameters=array('morehtmlref'=>$morehtmlref);
2538 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
2539 if ($reshook < 0) {
2540 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2541 } elseif (empty($reshook)) {
2542 $morehtmlref .= $hookmanager->resPrint;
2543 } elseif ($reshook > 0) {
2544 $morehtmlref = $hookmanager->resPrint;
2545 }
2546
2547
2548 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
2549 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
2550 print '</div>';
2551 print '<div class="underrefbanner clearboth"></div>';
2552}
2553
2563function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
2564{
2565 global $langs;
2566 $ret = '';
2567 if ($fieldrequired) {
2568 $ret .= '<span class="fieldrequired">';
2569 }
2570 $ret .= '<label for="'.$fieldkey.'">';
2571 $ret .= $langs->trans($langkey);
2572 $ret .= '</label>';
2573 if ($fieldrequired) {
2574 $ret .= '</span>';
2575 }
2576 return $ret;
2577}
2578
2586function dol_bc($var, $moreclass = '')
2587{
2588 global $bc;
2589 $ret = ' '.$bc[$var];
2590 if ($moreclass) {
2591 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
2592 }
2593 return $ret;
2594}
2595
2609function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = '', $mode = 0, $extralangcode = '')
2610{
2611 global $conf, $langs, $hookmanager;
2612
2613 $ret = '';
2614 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
2615
2616 // See format of addresses on https://en.wikipedia.org/wiki/Address
2617 // Address
2618 if (empty($mode)) {
2619 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
2620 }
2621 // Zip/Town/State
2622 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || !empty($conf->global->MAIN_FORCE_STATE_INTO_ADDRESS)) {
2623 // US: title firstname name \n address lines \n town, state, zip \n country
2624 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2625 $ret .= (($ret && $town) ? $sep : '').$town;
2626
2627 if (!empty($object->state)) {
2628 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
2629 }
2630 if (!empty($object->zip)) {
2631 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
2632 }
2633 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
2634 // UK: title firstname name \n address lines \n town state \n zip \n country
2635 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2636 $ret .= ($ret ? $sep : '').$town;
2637 if (!empty($object->state)) {
2638 $ret .= ($ret ? ", " : '').$object->state;
2639 }
2640 if (!empty($object->zip)) {
2641 $ret .= ($ret ? $sep : '').$object->zip;
2642 }
2643 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
2644 // ES: title firstname name \n address lines \n zip town \n state \n country
2645 $ret .= ($ret ? $sep : '').$object->zip;
2646 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2647 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2648 if (!empty($object->state)) {
2649 $ret .= $sep.$object->state;
2650 }
2651 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
2652 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
2653 // See https://www.sljfaq.org/afaq/addresses.html
2654 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2655 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
2656 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
2657 // IT: title firstname name\n address lines \n zip town state_code \n country
2658 $ret .= ($ret ? $sep : '').$object->zip;
2659 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2660 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2661 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
2662 } else {
2663 // Other: title firstname name \n address lines \n zip town[, state] \n country
2664 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2665 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
2666 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
2667 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
2668 $ret .= ($ret ? ", " : '').$object->state;
2669 }
2670 }
2671
2672 if (!is_object($outputlangs)) {
2673 $outputlangs = $langs;
2674 }
2675 if ($withcountry) {
2676 $langs->load("dict");
2677 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
2678 }
2679 if ($hookmanager) {
2680 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
2681 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
2682 if ($reshook > 0) {
2683 $ret = '';
2684 }
2685 $ret .= $hookmanager->resPrint;
2686 }
2687
2688 return $ret;
2689}
2690
2691
2692
2701function dol_strftime($fmt, $ts = false, $is_gmt = false)
2702{
2703 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
2704 return ($is_gmt) ? @gmstrftime($fmt, $ts) : @strftime($fmt, $ts);
2705 } else {
2706 return 'Error date into a not supported range';
2707 }
2708}
2709
2731function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = '', $encodetooutput = false)
2732{
2733 global $conf, $langs;
2734
2735 // If date undefined or "", we return ""
2736 if (dol_strlen($time) == 0) {
2737 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
2738 }
2739
2740 if ($tzoutput === 'auto') {
2741 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
2742 }
2743
2744 // Clean parameters
2745 $to_gmt = false;
2746 $offsettz = $offsetdst = 0;
2747 if ($tzoutput) {
2748 $to_gmt = true; // For backward compatibility
2749 if (is_string($tzoutput)) {
2750 if ($tzoutput == 'tzserver') {
2751 $to_gmt = false;
2752 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
2753 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
2754 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
2755 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
2756 $to_gmt = true;
2757 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
2758
2759 if (class_exists('DateTimeZone')) {
2760 $user_date_tz = new DateTimeZone($offsettzstring);
2761 $user_dt = new DateTime();
2762 $user_dt->setTimezone($user_date_tz);
2763 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
2764 $offsettz = $user_dt->getOffset(); // should include dst ?
2765 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
2766 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
2767 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
2768 }
2769 }
2770 }
2771 }
2772 if (!is_object($outputlangs)) {
2773 $outputlangs = $langs;
2774 }
2775 if (!$format) {
2776 $format = 'daytextshort';
2777 }
2778
2779 // Do we have to reduce the length of date (year on 2 chars) to save space.
2780 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
2781 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour'))) ? 1 : 0; // Test on original $format param.
2782 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
2783 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
2784 if ($formatwithoutreduce != $format) {
2785 $format = $formatwithoutreduce;
2786 $reduceformat = 1;
2787 } // so format 'dayreduceformat' is processed like day
2788
2789 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
2790 // TODO Add format daysmallyear and dayhoursmallyear
2791 if ($format == 'day') {
2792 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
2793 } elseif ($format == 'hour') {
2794 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
2795 } elseif ($format == 'hourduration') {
2796 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
2797 } elseif ($format == 'daytext') {
2798 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
2799 } elseif ($format == 'daytextshort') {
2800 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
2801 } elseif ($format == 'dayhour') {
2802 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
2803 } elseif ($format == 'dayhoursec') {
2804 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
2805 } elseif ($format == 'dayhourtext') {
2806 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
2807 } elseif ($format == 'dayhourtextshort') {
2808 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
2809 } elseif ($format == 'dayhourlog') {
2810 // Format not sensitive to language
2811 $format = '%Y%m%d%H%M%S';
2812 } elseif ($format == 'dayhourlogsmall') {
2813 // Format not sensitive to language
2814 $format = '%y%m%d%H%M';
2815 } elseif ($format == 'dayhourldap') {
2816 $format = '%Y%m%d%H%M%SZ';
2817 } elseif ($format == 'dayhourxcard') {
2818 $format = '%Y%m%dT%H%M%SZ';
2819 } elseif ($format == 'dayxcard') {
2820 $format = '%Y%m%d';
2821 } elseif ($format == 'dayrfc') {
2822 $format = '%Y-%m-%d'; // DATE_RFC3339
2823 } elseif ($format == 'dayhourrfc') {
2824 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
2825 } elseif ($format == 'standard') {
2826 $format = '%Y-%m-%d %H:%M:%S';
2827 }
2828
2829 if ($reduceformat) {
2830 $format = str_replace('%Y', '%y', $format);
2831 $format = str_replace('yyyy', 'yy', $format);
2832 }
2833
2834 // Clean format
2835 if (preg_match('/%b/i', $format)) { // There is some text to translate
2836 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2837 $format = str_replace('%b', '__b__', $format);
2838 $format = str_replace('%B', '__B__', $format);
2839 }
2840 if (preg_match('/%a/i', $format)) { // There is some text to translate
2841 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2842 $format = str_replace('%a', '__a__', $format);
2843 $format = str_replace('%A', '__A__', $format);
2844 }
2845
2846 // Analyze date
2847 $reg = array();
2848 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
2849 dol_print_error('', "Functions.lib::dol_print_date function called with a bad value from page ".$_SERVER["PHP_SELF"]);
2850 return '';
2851 } 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
2852 // This part of code should not be used anymore.
2853 dol_syslog("Functions.lib::dol_print_date function called with a bad value from page ".$_SERVER["PHP_SELF"], LOG_WARNING);
2854 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
2855 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
2856 $syear = (!empty($reg[1]) ? $reg[1] : '');
2857 $smonth = (!empty($reg[2]) ? $reg[2] : '');
2858 $sday = (!empty($reg[3]) ? $reg[3] : '');
2859 $shour = (!empty($reg[4]) ? $reg[4] : '');
2860 $smin = (!empty($reg[5]) ? $reg[5] : '');
2861 $ssec = (!empty($reg[6]) ? $reg[6] : '');
2862
2863 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
2864
2865 if ($to_gmt) {
2866 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2867 } else {
2868 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2869 }
2870 $dtts = new DateTime();
2871 $dtts->setTimestamp($time);
2872 $dtts->setTimezone($tzo);
2873 $newformat = str_replace(
2874 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2875 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2876 $format);
2877 $ret = $dtts->format($newformat);
2878 $ret = str_replace(
2879 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2880 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2881 $ret
2882 );
2883 } else {
2884 // Date is a timestamps
2885 if ($time < 100000000000) { // Protection against bad date values
2886 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2887
2888 if ($to_gmt) {
2889 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2890 } else {
2891 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2892 }
2893 $dtts = new DateTime();
2894 $dtts->setTimestamp($timetouse);
2895 $dtts->setTimezone($tzo);
2896 $newformat = str_replace(
2897 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2898 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2899 $format);
2900 $ret = $dtts->format($newformat);
2901 $ret = str_replace(
2902 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2903 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2904 $ret
2905 );
2906 //var_dump($ret);exit;
2907 } else {
2908 $ret = 'Bad value '.$time.' for date';
2909 }
2910 }
2911
2912 if (preg_match('/__b__/i', $format)) {
2913 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2914
2915 if ($to_gmt) {
2916 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2917 } else {
2918 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2919 }
2920 $dtts = new DateTime();
2921 $dtts->setTimestamp($timetouse);
2922 $dtts->setTimezone($tzo);
2923 $month = $dtts->format("m");
2924 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
2925 if ($encodetooutput) {
2926 $monthtext = $outputlangs->transnoentities('Month'.$month);
2927 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
2928 } else {
2929 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
2930 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
2931 }
2932 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
2933 $ret = str_replace('__b__', $monthtextshort, $ret);
2934 $ret = str_replace('__B__', $monthtext, $ret);
2935 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
2936 //return $ret;
2937 }
2938 if (preg_match('/__a__/i', $format)) {
2939 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
2940 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
2941
2942 if ($to_gmt) {
2943 $tzo = new DateTimeZone('UTC');
2944 } else {
2945 $tzo = new DateTimeZone(date_default_timezone_get());
2946 }
2947 $dtts = new DateTime();
2948 $dtts->setTimestamp($timetouse);
2949 $dtts->setTimezone($tzo);
2950 $w = $dtts->format("w");
2951 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
2952
2953 $ret = str_replace('__A__', $dayweek, $ret);
2954 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
2955 }
2956
2957 return $ret;
2958}
2959
2960
2981function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
2982{
2983 $datetimeobj = new DateTime();
2984 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
2985 if ($forcetimezone) {
2986 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
2987 }
2988 $arrayinfo = array(
2989 'year'=>((int) date_format($datetimeobj, 'Y')),
2990 'mon'=>((int) date_format($datetimeobj, 'm')),
2991 'mday'=>((int) date_format($datetimeobj, 'd')),
2992 'wday'=>((int) date_format($datetimeobj, 'w')),
2993 'yday'=>((int) date_format($datetimeobj, 'z')),
2994 'hours'=>((int) date_format($datetimeobj, 'H')),
2995 'minutes'=>((int) date_format($datetimeobj, 'i')),
2996 'seconds'=>((int) date_format($datetimeobj, 's')),
2997 '0'=>$timestamp
2998 );
2999
3000 return $arrayinfo;
3001}
3002
3024function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3025{
3026 global $conf;
3027 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3028
3029 if ($gm === 'auto') {
3030 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3031 }
3032 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3033
3034 // Clean parameters
3035 if ($hour == -1 || empty($hour)) {
3036 $hour = 0;
3037 }
3038 if ($minute == -1 || empty($minute)) {
3039 $minute = 0;
3040 }
3041 if ($second == -1 || empty($second)) {
3042 $second = 0;
3043 }
3044
3045 // Check parameters
3046 if ($check) {
3047 if (!$month || !$day) {
3048 return '';
3049 }
3050 if ($day > 31) {
3051 return '';
3052 }
3053 if ($month > 12) {
3054 return '';
3055 }
3056 if ($hour < 0 || $hour > 24) {
3057 return '';
3058 }
3059 if ($minute < 0 || $minute > 60) {
3060 return '';
3061 }
3062 if ($second < 0 || $second > 60) {
3063 return '';
3064 }
3065 }
3066
3067 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3068 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3069 $localtz = new DateTimeZone($default_timezone);
3070 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3071 // We use dol_tz_string first because it is more reliable.
3072 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3073 try {
3074 $localtz = new DateTimeZone($default_timezone);
3075 } catch (Exception $e) {
3076 dol_syslog("Warning dol_tz_string contains an invalid value ".$_SESSION["dol_tz_string"], LOG_WARNING);
3077 $default_timezone = @date_default_timezone_get();
3078 }
3079 } elseif (strrpos($gm, "tz,") !== false) {
3080 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3081 try {
3082 $localtz = new DateTimeZone($timezone);
3083 } catch (Exception $e) {
3084 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3085 }
3086 }
3087
3088 if (empty($localtz)) {
3089 $localtz = new DateTimeZone('UTC');
3090 }
3091 //var_dump($localtz);
3092 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3093 $dt = new DateTime('now', $localtz);
3094 $dt->setDate((int) $year, (int) $month, (int) $day);
3095 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3096 $date = $dt->getTimestamp(); // should include daylight saving time
3097 //var_dump($date);
3098 return $date;
3099}
3100
3101
3112function dol_now($mode = 'auto')
3113{
3114 $ret = 0;
3115
3116 if ($mode === 'auto') {
3117 $mode = 'gmt';
3118 }
3119
3120 if ($mode == 'gmt') {
3121 $ret = time(); // Time for now at greenwich.
3122 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3123 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3124 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3125 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3126 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3127 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3128 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3129 // $ret=dol_now('gmt')+($tzsecond*3600);
3130 //}
3131 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3132 // Time for now with user timezone added
3133 //print 'time: '.time();
3134 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3135 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3136 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3137 }
3138
3139 return $ret;
3140}
3141
3142
3151function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3152{
3153 global $conf, $langs;
3154 $level = 1024;
3155
3156 if (!empty($conf->dol_optimize_smallscreen)) {
3157 $shortunit = 1;
3158 }
3159
3160 // Set value text
3161 if (empty($shortvalue) || $size < ($level * 10)) {
3162 $ret = $size;
3163 $textunitshort = $langs->trans("b");
3164 $textunitlong = $langs->trans("Bytes");
3165 } else {
3166 $ret = round($size / $level, 0);
3167 $textunitshort = $langs->trans("Kb");
3168 $textunitlong = $langs->trans("KiloBytes");
3169 }
3170 // Use long or short text unit
3171 if (empty($shortunit)) {
3172 $ret .= ' '.$textunitlong;
3173 } else {
3174 $ret .= ' '.$textunitshort;
3175 }
3176
3177 return $ret;
3178}
3179
3190function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = 'float')
3191{
3192 global $langs;
3193
3194 if (empty($url)) {
3195 return '';
3196 }
3197
3198 $link = '<a href="';
3199 if (!preg_match('/^http/i', $url)) {
3200 $link .= 'http://';
3201 }
3202 $link .= $url;
3203 $link .= '"';
3204 if ($target) {
3205 $link .= ' target="'.$target.'"';
3206 }
3207 $link .= '>';
3208 if (!preg_match('/^http/i', $url)) {
3209 $link .= 'http://';
3210 }
3211 $link .= dol_trunc($url, $max);
3212 $link .= '</a>';
3213
3214 if ($morecss == 'float') {
3215 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ?img_picto($langs->trans("Url"), 'globe').' ' : '').$link.'</div>';
3216 } else {
3217 return '<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ?img_picto($langs->trans("Url"), 'globe').' ' : '').$link.'</span>';
3218 }
3219}
3220
3233function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3234{
3235 global $conf, $user, $langs, $hookmanager;
3236
3237 $newemail = dol_escape_htmltag($email);
3238
3239 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && $withpicto) {
3240 $withpicto = 0;
3241 }
3242
3243 if (empty($email)) {
3244 return '&nbsp;';
3245 }
3246
3247 if (!empty($addlink)) {
3248 $newemail = '<a style="text-overflow: ellipsis;" href="';
3249 if (!preg_match('/^mailto:/i', $email)) {
3250 $newemail .= 'mailto:';
3251 }
3252 $newemail .= $email;
3253 $newemail .= '">';
3254 $newemail .= dol_trunc($email, $max);
3255 $newemail .= '</a>';
3256 if ($showinvalid && !isValidEmail($email)) {
3257 $langs->load("errors");
3258 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3259 }
3260
3261 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3262 $type = 'AC_EMAIL';
3263 $link = '';
3264 if (!empty($conf->global->AGENDA_ADDACTIONFOREMAIL)) {
3265 $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>';
3266 }
3267 if ($link) {
3268 $newemail = '<div>'.$newemail.' '.$link.'</div>';
3269 }
3270 }
3271 } else {
3272 if ($showinvalid && !isValidEmail($email)) {
3273 $langs->load("errors");
3274 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3275 }
3276 }
3277
3278 //$rep = '<div class="nospan" style="margin-right: 10px">';
3279 $rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto)).' ' : '').$newemail;
3280 //$rep .= '</div>';
3281 if ($hookmanager) {
3282 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3283
3284 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3285 if ($reshook > 0) {
3286 $rep = '';
3287 }
3288 $rep .= $hookmanager->resPrint;
3289 }
3290
3291 return $rep;
3292}
3293
3300{
3301 global $conf, $db;
3302
3303 $socialnetworks = array();
3304 // Enable caching of array
3305 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3306 $cachekey = 'socialnetworks_' . $conf->entity;
3307 $dataretrieved = dol_getcache($cachekey);
3308 if (!is_null($dataretrieved)) {
3309 $socialnetworks = $dataretrieved;
3310 } else {
3311 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3312 $sql .= " WHERE entity=".$conf->entity;
3313 $resql = $db->query($sql);
3314 if ($resql) {
3315 while ($obj = $db->fetch_object($resql)) {
3316 $socialnetworks[$obj->code] = array(
3317 'rowid' => $obj->rowid,
3318 'label' => $obj->label,
3319 'url' => $obj->url,
3320 'icon' => $obj->icon,
3321 'active' => $obj->active,
3322 );
3323 }
3324 }
3325 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3326 }
3327
3328 return $socialnetworks;
3329}
3330
3341function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3342{
3343 global $conf, $user, $langs;
3344
3345 $htmllink = $value;
3346
3347 if (empty($value)) {
3348 return '&nbsp;';
3349 }
3350
3351 if (!empty($type)) {
3352 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3353 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3354 $htmllink .= '<span class="fa pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3355 if ($type == 'skype') {
3356 $htmllink .= dol_escape_htmltag($value);
3357 $htmllink .= '&nbsp; <a href="skype:';
3358 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3359 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3360 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3361 $htmllink .= '</a><a href="skype:';
3362 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3363 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3364 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3365 $htmllink .= '</a>';
3366 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3367 $addlink = 'AC_SKYPE';
3368 $link = '';
3369 if (!empty($conf->global->AGENDA_ADDACTIONFORSKYPE)) {
3370 $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>';
3371 }
3372 $htmllink .= ($link ? ' '.$link : '');
3373 }
3374 } else {
3375 if (!empty($dictsocialnetworks[$type]['url'])) {
3376 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3377 if ($tmpvirginurl) {
3378 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3379 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3380
3381 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3382 if ($tmpvirginurl3) {
3383 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3384 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3385 }
3386
3387 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3388 if ($tmpvirginurl2) {
3389 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3390 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3391 }
3392 }
3393 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3394 if (preg_match('/^https?:\/\//i', $link)) {
3395 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3396 } else {
3397 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3398 }
3399 } else {
3400 $htmllink .= dol_escape_htmltag($value);
3401 }
3402 }
3403 $htmllink .= '</div>';
3404 } else {
3405 $langs->load("errors");
3406 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3407 }
3408 return $htmllink;
3409}
3410
3421function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1, $separ = '&nbsp;')
3422{
3423 global $mysoc;
3424
3425 if (empty($profID) || empty($profIDtype)) {
3426 return '';
3427 }
3428 if (empty($countrycode)) $countrycode = $mysoc->country_code;
3429 $newProfID = $profID;
3430 $id = substr($profIDtype, -1);
3431 $ret = '';
3432 if (strtoupper($countrycode) == 'FR') {
3433 // France
3434 if ($id == 1 && dol_strlen($newProfID) == 9) $newProfID = substr($newProfID, 0, 3).$separ.substr($newProfID, 3, 3).$separ.substr($newProfID, 6, 3);
3435 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);
3436 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);
3437 }
3438 if (!empty($addcpButton)) $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3439 else $ret = $newProfID;
3440 return $ret;
3441}
3442
3457function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0)
3458{
3459 global $conf, $user, $langs, $mysoc, $hookmanager;
3460
3461 // Clean phone parameter
3462 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
3463 if (empty($phone)) {
3464 return '';
3465 }
3466 if (!empty($conf->global->MAIN_PHONE_SEPAR)) {
3467 $separ = $conf->global->MAIN_PHONE_SEPAR;
3468 }
3469 if (empty($countrycode) && is_object($mysoc)) {
3470 $countrycode = $mysoc->country_code;
3471 }
3472
3473 // Short format for small screens
3474 if ($conf->dol_optimize_smallscreen) {
3475 $separ = '';
3476 }
3477
3478 $newphone = $phone;
3479 if (strtoupper($countrycode) == "FR") {
3480 // France
3481 if (dol_strlen($phone) == 10) {
3482 $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);
3483 } elseif (dol_strlen($phone) == 7) {
3484 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
3485 } elseif (dol_strlen($phone) == 9) {
3486 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
3487 } elseif (dol_strlen($phone) == 11) {
3488 $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);
3489 } elseif (dol_strlen($phone) == 12) {
3490 $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);
3491 } elseif (dol_strlen($phone) == 13) {
3492 $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);
3493 }
3494 } elseif (strtoupper($countrycode) == "CA") {
3495 if (dol_strlen($phone) == 10) {
3496 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
3497 }
3498 } elseif (strtoupper($countrycode) == "PT") {//Portugal
3499 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
3500 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3501 }
3502 } elseif (strtoupper($countrycode) == "SR") {//Suriname
3503 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
3504 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
3505 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
3506 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
3507 }
3508 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
3509 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
3510 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
3511 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
3512 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
3513 }
3514 } elseif (strtoupper($countrycode) == "ES") {//Espagne
3515 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
3516 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3517 }
3518 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
3519 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
3520 $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);
3521 }
3522 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
3523 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
3524 $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);
3525 }
3526 } elseif (strtoupper($countrycode) == "TR") {//Turquie
3527 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
3528 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3529 }
3530 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
3531 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
3532 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3533 }
3534 } elseif (strtoupper($countrycode) == "MX") {//Mexique
3535 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
3536 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3537 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
3538 $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);
3539 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
3540 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3541 }
3542 } elseif (strtoupper($countrycode) == "ML") {//Mali
3543 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
3544 $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);
3545 }
3546 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
3547 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
3548 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3549 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
3550 $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);
3551 }
3552 } elseif (strtoupper($countrycode) == "MU") {
3553 //Maurice
3554 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
3555 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3556 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
3557 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3558 }
3559 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
3560 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
3561 $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);
3562 }
3563 } elseif (strtoupper($countrycode) == "SY") {//Syrie
3564 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
3565 $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);
3566 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
3567 $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);
3568 }
3569 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
3570 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
3571 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3572 } elseif (dol_strlen($phone) == 13) {//ex: +971_ABC_DEF_GHI
3573 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3574 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
3575 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
3576 }
3577 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
3578 if (dol_strlen($phone) == 13) {//ex: +213_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 }
3581 } elseif (strtoupper($countrycode) == "BE") {//Belgique
3582 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
3583 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3584 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
3585 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3586 }
3587 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
3588 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
3589 $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);
3590 }
3591 } elseif (strtoupper($countrycode) == "CO") {//Colombie
3592 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
3593 $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);
3594 }
3595 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
3596 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
3597 $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);
3598 }
3599 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
3600 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
3601 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3602 }
3603 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
3604 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
3605 $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);
3606 }
3607 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
3608 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
3609 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3610 }
3611 } elseif (strtoupper($countrycode) == "CH") {//Suisse
3612 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
3613 $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);
3614 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
3615 $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);
3616 }
3617 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
3618 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
3619 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3620 }
3621 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
3622 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
3623 $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);
3624 }
3625 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
3626 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
3627 $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);
3628 }
3629 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
3630 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
3631 $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);
3632 }
3633 } elseif (strtoupper($countrycode) == "IT") {//Italie
3634 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
3635 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3636 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
3637 $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);
3638 }
3639 } elseif (strtoupper($countrycode) == "AU") {
3640 //Australie
3641 if (dol_strlen($phone) == 12) {
3642 //ex: +61_A_BCDE_FGHI
3643 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
3644 }
3645 } elseif (strtoupper($countrycode) == "LU") {
3646 // Luxembourg
3647 if (dol_strlen($phone) == 10) {// fixe 6 chiffres +352_AA_BB_CC
3648 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3649 } elseif (dol_strlen($phone) == 11) {// fixe 7 chiffres +352_AA_BB_CC_D
3650 $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);
3651 } elseif (dol_strlen($phone) == 12) {// fixe 8 chiffres +352_AA_BB_CC_DD
3652 $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);
3653 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
3654 $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);
3655 }
3656 }
3657 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
3658 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
3659 $newphoneform = $newphone;
3660 $newphone = '<a href="tel:'.$phone.'"';
3661 $newphone .= '>'.$newphoneform.'</a>';
3662 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
3663 if (empty($user->clicktodial_loaded)) {
3664 $user->fetch_clicktodial();
3665 }
3666
3667 // Define urlmask
3668 $urlmask = 'ErrorClickToDialModuleNotConfigured';
3669 if (!empty($conf->global->CLICKTODIAL_URL)) {
3670 $urlmask = $conf->global->CLICKTODIAL_URL;
3671 }
3672 if (!empty($user->clicktodial_url)) {
3673 $urlmask = $user->clicktodial_url;
3674 }
3675
3676 $clicktodial_poste = (!empty($user->clicktodial_poste) ?urlencode($user->clicktodial_poste) : '');
3677 $clicktodial_login = (!empty($user->clicktodial_login) ?urlencode($user->clicktodial_login) : '');
3678 $clicktodial_password = (!empty($user->clicktodial_password) ?urlencode($user->clicktodial_password) : '');
3679 // This line is for backward compatibility
3680 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
3681 // Thoose lines are for substitution
3682 $substitarray = array('__PHONEFROM__'=>$clicktodial_poste,
3683 '__PHONETO__'=>urlencode($phone),
3684 '__LOGIN__'=>$clicktodial_login,
3685 '__PASS__'=>$clicktodial_password);
3686 $url = make_substitutions($url, $substitarray);
3687 $newphonesav = $newphone;
3688 if (empty($conf->global->CLICKTODIAL_DO_NOT_USE_AJAX_CALL)) {
3689 // Default and recommended: New method using ajax without submiting a page making a javascript history.go(-1) back
3690 $newphone = '<a href="'.$url.'" class="cssforclicktodial"'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
3691 $newphone .= '>'.$newphonesav.'</a>';
3692 } else {
3693 // Old method
3694 $newphone = '<a href="'.$url.'"';
3695 if (!empty($conf->global->CLICKTODIAL_FORCENEWTARGET)) {
3696 $newphone .= ' target="_blank" rel="noopener noreferrer"';
3697 }
3698 $newphone .= '>'.$newphonesav.'</a>';
3699 }
3700 }
3701
3702 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
3703 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3704 $type = 'AC_TEL';
3705 $link = '';
3706 if ($addlink == 'AC_FAX') {
3707 $type = 'AC_FAX';
3708 }
3709 if (!empty($conf->global->AGENDA_ADDACTIONFORPHONE)) {
3710 $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>';
3711 }
3712 if ($link) {
3713 $newphone = '<div>'.$newphone.' '.$link.'</div>';
3714 }
3715 }
3716 }
3717
3718 if (empty($titlealt)) {
3719 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
3720 }
3721 $rep = '';
3722
3723 if ($hookmanager) {
3724 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
3725 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
3726 $rep .= $hookmanager->resPrint;
3727 }
3728 if (empty($reshook)) {
3729 $picto = '';
3730 if ($withpicto) {
3731 if ($withpicto == 'fax') {
3732 $picto = 'phoning_fax';
3733 } elseif ($withpicto == 'phone') {
3734 $picto = 'phoning';
3735 } elseif ($withpicto == 'mobile') {
3736 $picto = 'phoning_mobile';
3737 } else {
3738 $picto = '';
3739 }
3740 }
3741 if ($adddivfloat == 1) {
3742 $rep .= '<div class="nospan float" style="margin-right: 10px">';
3743 } elseif (empty($adddivfloat)) {
3744 $rep .= '<span style="margin-right: 10px;">';
3745 }
3746 $rep .= ($withpicto ?img_picto($titlealt, 'object_'.$picto.'.png').' ' : '').$newphone;
3747 if ($adddivfloat == 1) {
3748 $rep .= '</div>';
3749 } elseif (empty($adddivfloat)) {
3750 $rep .= '</span>';
3751 }
3752 }
3753
3754 return $rep;
3755}
3756
3764function dol_print_ip($ip, $mode = 0)
3765{
3766 global $conf, $langs;
3767
3768 $ret = '';
3769
3770 if (empty($mode)) {
3771 $ret .= $ip;
3772 }
3773
3774 if ($mode != 2) {
3775 $countrycode = dolGetCountryCodeFromIp($ip);
3776 if ($countrycode) { // If success, countrycode is us, fr, ...
3777 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
3778 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
3779 } else {
3780 $ret .= ' ('.$countrycode.')';
3781 }
3782 } else {
3783 // Nothing
3784 }
3785 }
3786
3787 return $ret;
3788}
3789
3799{
3800 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
3801 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
3802 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
3803 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
3804 } else {
3805 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
3806 }
3807 } else {
3808 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
3809 }
3810 } else {
3811 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
3812 }
3813 return $ip;
3814}
3815
3824function isHTTPS()
3825{
3826 $isSecure = false;
3827 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
3828 $isSecure = true;
3829 } 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') {
3830 $isSecure = true;
3831 }
3832 return $isSecure;
3833}
3834
3842{
3843 global $conf;
3844
3845 $countrycode = '';
3846
3847 if (!empty($conf->geoipmaxmind->enabled)) {
3848 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3849 //$ip='24.24.24.24';
3850 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
3851 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3852 $geoip = new DolGeoIP('country', $datafile);
3853 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
3854 $countrycode = $geoip->getCountryCodeFromIP($ip);
3855 }
3856
3857 return $countrycode;
3858}
3859
3860
3868{
3869 global $conf, $langs, $user;
3870
3871 //$ret=$user->xxx;
3872 $ret = '';
3873 if (!empty($conf->geoipmaxmind->enabled)) {
3874 $ip = getUserRemoteIP();
3875 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3876 //$ip='24.24.24.24';
3877 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
3878 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3879 $geoip = new DolGeoIP('country', $datafile);
3880 $countrycode = $geoip->getCountryCodeFromIP($ip);
3881 $ret = $countrycode;
3882 }
3883 return $ret;
3884}
3885
3898function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
3899{
3900 global $conf, $user, $langs, $hookmanager;
3901
3902 $out = '';
3903
3904 if ($address) {
3905 if ($hookmanager) {
3906 $parameters = array('element' => $element, 'id' => $id);
3907 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
3908 $out .= $hookmanager->resPrint;
3909 }
3910 if (empty($reshook)) {
3911 if (empty($charfornl)) {
3912 $out .= nl2br($address);
3913 } else {
3914 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
3915 }
3916
3917 // TODO Remove this block, we can add this using the hook now
3918 $showgmap = $showomap = 0;
3919 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS)) {
3920 $showgmap = 1;
3921 }
3922 if ($element == 'contact' && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS_CONTACTS)) {
3923 $showgmap = 1;
3924 }
3925 if ($element == 'member' && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS_MEMBERS)) {
3926 $showgmap = 1;
3927 }
3928 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS)) {
3929 $showomap = 1;
3930 }
3931 if ($element == 'contact' && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS_CONTACTS)) {
3932 $showomap = 1;
3933 }
3934 if ($element == 'member' && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS_MEMBERS)) {
3935 $showomap = 1;
3936 }
3937 if ($showgmap) {
3938 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
3939 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
3940 }
3941 if ($showomap) {
3942 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
3943 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
3944 }
3945 }
3946 }
3947 if ($noprint) {
3948 return $out;
3949 } else {
3950 print $out;
3951 }
3952}
3953
3954
3964function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
3965{
3966 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
3967 return true;
3968 }
3969 if ($acceptuserkey && $address == '__USER_EMAIL__') {
3970 return true;
3971 }
3972 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
3973 return true;
3974 }
3975
3976 return false;
3977}
3978
3987function isValidMXRecord($domain)
3988{
3989 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
3990 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
3991 return 0;
3992 }
3993 if (function_exists('getmxrr')) {
3994 $mxhosts = array();
3995 $weight = array();
3996 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
3997 if (count($mxhosts) > 1) {
3998 return 1;
3999 }
4000 if (count($mxhosts) == 1 && !empty($mxhosts[0])) {
4001 return 1;
4002 }
4003
4004 return 0;
4005 }
4006 }
4007
4008 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4009 return -1;
4010}
4011
4019function isValidPhone($phone)
4020{
4021 return true;
4022}
4023
4024
4034function dolGetFirstLetters($s, $nbofchar = 1)
4035{
4036 $ret = '';
4037 $tmparray = explode(' ', $s);
4038 foreach ($tmparray as $tmps) {
4039 $ret .= dol_substr($tmps, 0, $nbofchar);
4040 }
4041
4042 return $ret;
4043}
4044
4045
4053function dol_strlen($string, $stringencoding = 'UTF-8')
4054{
4055 if (is_null($string)) {
4056 return 0;
4057 }
4058
4059 if (function_exists('mb_strlen')) {
4060 return mb_strlen($string, $stringencoding);
4061 } else {
4062 return strlen($string);
4063 }
4064}
4065
4076function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4077{
4078 global $langs;
4079
4080 if (empty($stringencoding)) {
4081 $stringencoding = $langs->charset_output;
4082 }
4083
4084 $ret = '';
4085 if (empty($trunconbytes)) {
4086 if (function_exists('mb_substr')) {
4087 $ret = mb_substr($string, $start, $length, $stringencoding);
4088 } else {
4089 $ret = substr($string, $start, $length);
4090 }
4091 } else {
4092 if (function_exists('mb_strcut')) {
4093 $ret = mb_strcut($string, $start, $length, $stringencoding);
4094 } else {
4095 $ret = substr($string, $start, $length);
4096 }
4097 }
4098 return $ret;
4099}
4100
4101
4115function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4116{
4117 global $conf;
4118
4119 if (empty($size) || !empty($conf->global->MAIN_DISABLE_TRUNC)) {
4120 return $string;
4121 }
4122
4123 if (empty($stringencoding)) {
4124 $stringencoding = 'UTF-8';
4125 }
4126 // reduce for small screen
4127 if ($conf->dol_optimize_smallscreen == 1 && $display == 1) {
4128 $size = round($size / 3);
4129 }
4130
4131 // We go always here
4132 if ($trunc == 'right') {
4133 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4134 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4135 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4136 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4137 } else {
4138 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4139 return $string;
4140 }
4141 } elseif ($trunc == 'middle') {
4142 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4143 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4144 $size1 = round($size / 2);
4145 $size2 = round($size / 2);
4146 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4147 } else {
4148 return $string;
4149 }
4150 } elseif ($trunc == 'left') {
4151 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4152 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4153 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4154 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4155 } else {
4156 return $string;
4157 }
4158 } elseif ($trunc == 'wrap') {
4159 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4160 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4161 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4162 } else {
4163 return $string;
4164 }
4165 } else {
4166 return 'BadParam3CallingDolTrunc';
4167 }
4168}
4169
4191function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4192{
4193 global $conf, $langs;
4194
4195 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4196 $url = DOL_URL_ROOT;
4197 $theme = isset($conf->theme) ? $conf->theme : null;
4198 $path = 'theme/'.$theme;
4199 // Define fullpathpicto to use into src
4200 if ($pictoisfullpath) {
4201 // Clean parameters
4202 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4203 $picto .= '.png';
4204 }
4205 $fullpathpicto = $picto;
4206 $reg = array();
4207 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4208 $morecss .= ($morecss ? ' ' : '').$reg[1];
4209 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4210 }
4211 } else {
4212 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', $picto);
4213 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4214 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4215
4216 if (strpos($pictowithouttext, 'fontawesome_') !== false || preg_match('/^fa-/', $pictowithouttext)) {
4217 // This is a font awesome image 'fonwtawesome_xxx' or 'fa-xxx'
4218 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4219 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4220
4221 $pictowithouttextarray = explode('_', $pictowithouttext);
4222 $marginleftonlyshort = 0;
4223
4224 if (!empty($pictowithouttextarray[1])) {
4225 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4226 $fakey = 'fa-'.$pictowithouttextarray[0];
4227 $fa = empty($pictowithouttextarray[1]) ? 'fa' : $pictowithouttextarray[1];
4228 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4229 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4230 } else {
4231 $fakey = 'fa-'.$pictowithouttext;
4232 $fa = 'fa';
4233 $facolor = '';
4234 $fasize = '';
4235 }
4236
4237 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4238 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4239 $morestyle = '';
4240 $reg = array();
4241 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4242 $morecss .= ($morecss ? ' ' : '').$reg[1];
4243 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4244 }
4245 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4246 $morestyle = $reg[1];
4247 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4248 }
4249 $moreatt = trim($moreatt);
4250
4251 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4252 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4253 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4254 $enabledisablehtml .= $titlealt;
4255 }*/
4256 $enabledisablehtml .= '</span>';
4257
4258 return $enabledisablehtml;
4259 }
4260
4261 if (empty($srconly) && in_array($pictowithouttext, array(
4262 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4263 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'angle-double-down', 'angle-double-up', 'asset',
4264 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building',
4265 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4266 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4267 'currency', 'multicurrency',
4268 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4269 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4270 'filter', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus',
4271 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4272 'hands-helping', 'help', 'holiday',
4273 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4274 'knowledgemanagement',
4275 'label', 'language', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4276 'margin', 'map-marker-alt', 'member', 'meeting', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4277 'off', 'on', 'order',
4278 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4279 'stock', 'resize', 'service', 'stats', 'trip',
4280 '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',
4281 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4282 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies',
4283 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4284 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4285 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4286 'technic', 'ticket',
4287 'error', 'warning',
4288 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4289 'shapes', 'skill', 'square', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4290 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda',
4291 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4292 'conferenceorbooth', 'eventorganization',
4293 'stamp', 'signature'
4294 ))) {
4295 $fakey = $pictowithouttext;
4296 $facolor = '';
4297 $fasize = '';
4298 $fa = 'fas';
4299 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'))) {
4300 $fa = 'far';
4301 }
4302 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4303 $fa = 'fab';
4304 }
4305
4306 $arrayconvpictotofa = array(
4307 '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',
4308 'bank_account'=>'university',
4309 'bill'=>'file-invoice-dollar', 'billa'=>'file-excel', 'billr'=>'file-invoice-dollar', 'billd'=>'file-medical',
4310 'supplier_invoice'=>'file-invoice-dollar', 'supplier_invoicea'=>'file-excel', 'supplier_invoicer'=>'file-invoice-dollar', 'supplier_invoiced'=>'file-medical',
4311 'bom'=>'shapes',
4312 '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',
4313 'donation'=>'file-alt', 'dynamicprice'=>'hand-holding-usd',
4314 'setup'=>'cog', 'companies'=>'building', 'products'=>'cube', 'commercial'=>'suitcase', 'invoicing'=>'coins',
4315 'accounting'=>'search-dollar', 'category'=>'tag', 'dollyrevert'=>'dolly',
4316 'generate'=>'plus-square', 'hrm'=>'user-tie', 'incoterm'=>'truck-loading',
4317 'margin'=>'calculator', 'members'=>'user-friends', 'ticket'=>'ticket-alt', 'globe'=>'external-link-alt', 'lot'=>'barcode',
4318 'email'=>'at', 'establishment'=>'building', 'edit'=>'pencil-alt', 'entity'=>'globe',
4319 'graph'=>'chart-line', 'grip_title'=>'arrows-alt', 'grip'=>'arrows-alt', 'help'=>'question-circle',
4320 'generic'=>'file', 'holiday'=>'umbrella-beach',
4321 'info'=>'info-circle', 'inventory'=>'boxes', 'intracommreport'=>'globe-europe', 'jobprofile'=>'cogs',
4322 'knowledgemanagement'=>'ticket-alt', 'label'=>'layer-group', 'line'=>'bars', 'loan'=>'money-bill-alt',
4323 'member'=>'user-alt', 'meeting'=>'chalkboard-teacher', 'mrp'=>'cubes', 'next'=>'arrow-alt-circle-right',
4324 'trip'=>'wallet', 'expensereport'=>'wallet', 'group'=>'users', 'movement'=>'people-carry',
4325 'sign-out'=>'sign-out-alt',
4326 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_warning'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star',
4327 'bank'=>'university', 'close_title'=>'times', 'delete'=>'trash', 'filter'=>'filter',
4328 'list-alt'=>'list-alt', 'calendarlist'=>'bars', 'calendar'=>'calendar-alt', 'calendarmonth'=>'calendar-alt', 'calendarweek'=>'calendar-week', 'calendarday'=>'calendar-day', 'calendarperuser'=>'table',
4329 'intervention'=>'ambulance', 'invoice'=>'file-invoice-dollar', 'currency'=>'dollar-sign', 'multicurrency'=>'dollar-sign', 'order'=>'file-invoice',
4330 'error'=>'exclamation-triangle', 'warning'=>'exclamation-triangle',
4331 'other'=>'square',
4332 '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',
4333 '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',
4334 'recent' => 'check-square', 'reception'=>'dolly', 'recruitmentjobposition'=>'id-card-alt', 'recruitmentcandidature'=>'id-badge',
4335 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature',
4336 'refresh'=>'redo', 'region'=>'map-marked', 'replacement'=>'exchange-alt', 'resource'=>'laptop-house', 'recurring'=>'history',
4337 'service'=>'concierge-bell',
4338 'skill'=>'shapes', 'state'=>'map-marked-alt', 'security'=>'key', 'salary'=>'wallet', 'shipment'=>'dolly', 'stock'=>'box-open', 'stats' => 'chart-bar', 'split'=>'code-branch', 'stripe'=>'stripe-s',
4339 'supplier'=>'building', 'technic'=>'cogs',
4340 'timespent'=>'clock', 'title_setup'=>'tools', 'title_accountancy'=>'money-check-alt', 'title_bank'=>'university', 'title_hrm'=>'umbrella-beach',
4341 'title_agenda'=>'calendar-alt',
4342 'uncheck'=>'times', 'uparrow'=>'share', 'url'=>'external-link-alt', 'vat'=>'money-check-alt', 'vcard'=>'arrow-alt-circle-down',
4343 'jabber'=>'comment-o',
4344 'website'=>'globe-americas', 'workstation'=>'pallet', 'webhook'=>'bullseye', 'world'=>'globe', 'private'=>'user-lock',
4345 'conferenceorbooth'=>'chalkboard-teacher', 'eventorganization'=>'project-diagram'
4346 );
4347 if ($pictowithouttext == 'off') {
4348 $fakey = 'fa-square';
4349 $fasize = '1.3em';
4350 } elseif ($pictowithouttext == 'on') {
4351 $fakey = 'fa-check-square';
4352 $fasize = '1.3em';
4353 } elseif ($pictowithouttext == 'listlight') {
4354 $fakey = 'fa-download';
4355 $marginleftonlyshort = 1;
4356 } elseif ($pictowithouttext == 'printer') {
4357 $fakey = 'fa-print';
4358 $fasize = '1.2em';
4359 } elseif ($pictowithouttext == 'note') {
4360 $fakey = 'fa-sticky-note';
4361 $marginleftonlyshort = 1;
4362 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
4363 $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');
4364 $fakey = 'fa-'.$convertarray[$pictowithouttext];
4365 if (preg_match('/selected/', $pictowithouttext)) {
4366 $facolor = '#888';
4367 }
4368 $marginleftonlyshort = 1;
4369 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
4370 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
4371 } else {
4372 $fakey = 'fa-'.$pictowithouttext;
4373 }
4374
4375 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment'))) {
4376 $morecss .= ' em092';
4377 }
4378 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
4379 $morecss .= ' em088';
4380 }
4381 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
4382 $morecss .= ' em080';
4383 }
4384
4385 // Define $marginleftonlyshort
4386 $arrayconvpictotomarginleftonly = array(
4387 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
4388 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
4389 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
4390 );
4391 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
4392 $marginleftonlyshort = 0;
4393 }
4394
4395 // Add CSS
4396 $arrayconvpictotomorcess = array(
4397 'action'=>'infobox-action', 'account'=>'infobox-bank_account', 'accounting_account'=>'infobox-bank_account', 'accountline'=>'infobox-bank_account', 'accountancy'=>'infobox-bank_account', 'asset'=>'infobox-bank_account',
4398 'bank_account'=>'infobox-bank_account',
4399 'bill'=>'infobox-commande', 'billa'=>'infobox-commande', 'billr'=>'infobox-commande', 'billd'=>'infobox-commande',
4400 'margin'=>'infobox-bank_account', 'conferenceorbooth'=>'infobox-project',
4401 'cash-register'=>'infobox-bank_account', 'contract'=>'infobox-contrat', 'check'=>'font-status4', 'collab'=>'infobox-action', 'conversation'=>'infobox-contrat',
4402 'donation'=>'infobox-commande', 'dolly'=>'infobox-commande', 'dollyrevert'=>'flip infobox-order_supplier',
4403 'ecm'=>'infobox-action', 'eventorganization'=>'infobox-project',
4404 'hrm'=>'infobox-adherent', 'group'=>'infobox-adherent', 'intervention'=>'infobox-contrat',
4405 'incoterm'=>'infobox-supplier_proposal',
4406 'currency'=>'infobox-bank_account', 'multicurrency'=>'infobox-bank_account',
4407 'members'=>'infobox-adherent', 'member'=>'infobox-adherent', 'money-bill-alt'=>'infobox-bank_account',
4408 'order'=>'infobox-commande',
4409 'user'=>'infobox-adherent', 'users'=>'infobox-adherent',
4410 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_warning'=>'font-status4 warning', 'switch_on_red'=>'font-status8',
4411 'holiday'=>'infobox-holiday', 'info'=>'opacityhigh', 'invoice'=>'infobox-commande',
4412 'knowledgemanagement'=>'infobox-contrat rotate90', 'loan'=>'infobox-bank_account',
4413 'payment'=>'infobox-bank_account', 'payment_vat'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'pos'=>'infobox-bank_account', 'project'=>'infobox-project', 'projecttask'=>'infobox-project',
4414 'propal'=>'infobox-propal', 'proposal'=>'infobox-propal','private'=>'infobox-project',
4415 'reception'=>'flip', 'recruitmentjobposition'=>'infobox-adherent', 'recruitmentcandidature'=>'infobox-adherent',
4416 'resource'=>'infobox-action',
4417 'salary'=>'infobox-bank_account', 'shipment'=>'infobox-commande', 'supplier_invoice'=>'infobox-order_supplier', 'supplier_invoicea'=>'infobox-order_supplier', 'supplier_invoiced'=>'infobox-order_supplier',
4418 'supplier'=>'infobox-order_supplier', 'supplier_order'=>'infobox-order_supplier', 'supplier_proposal'=>'infobox-supplier_proposal',
4419 'ticket'=>'infobox-contrat', 'title_accountancy'=>'infobox-bank_account', 'title_hrm'=>'infobox-holiday', 'expensereport'=>'infobox-expensereport', 'trip'=>'infobox-expensereport', 'title_agenda'=>'infobox-action',
4420 'vat'=>'infobox-bank_account',
4421 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
4422 'list-alt'=>'imgforviewmode', 'calendar'=>'imgforviewmode', 'calendarweek'=>'imgforviewmode', 'calendarmonth'=>'imgforviewmode', 'calendarday'=>'imgforviewmode', 'calendarperuser'=>'imgforviewmode'
4423 );
4424 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4425 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
4426 }
4427
4428 // Define $color
4429 $arrayconvpictotocolor = array(
4430 'address'=>'#6c6aa8', 'building'=>'#6c6aa8', 'bom'=>'#a69944',
4431 'clone'=>'#999', 'cog'=>'#999', 'companies'=>'#6c6aa8', 'company'=>'#6c6aa8', 'contact'=>'#6c6aa8', 'cron'=>'#555',
4432 'dynamicprice'=>'#a69944',
4433 'edit'=>'#444', 'note'=>'#999', 'error'=>'', 'help'=>'#bbb', 'listlight'=>'#999', 'language'=>'#555',
4434 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
4435 'lock'=>'#ddd', 'lot'=>'#a69944',
4436 'map-marker-alt'=>'#aaa', 'mrp'=>'#a69944', 'product'=>'#a69944', 'service'=>'#a69944', 'inventory'=>'#a69944', 'stock'=>'#a69944', 'movement'=>'#a69944',
4437 'other'=>'#ddd', 'world'=>'#986c6a',
4438 'partnership'=>'#6c6aa8', 'playdisabled'=>'#ccc', 'printer'=>'#444', 'projectpub'=>'#986c6a', 'reception'=>'#a69944', 'resize'=>'#444', 'rss'=>'#cba',
4439 //'shipment'=>'#a69944',
4440 'security'=>'#999', 'square'=>'#888', 'stop-circle'=>'#888', 'stats'=>'#444', 'switch_off'=>'#999', 'technic'=>'#999', 'timespent'=>'#555',
4441 'uncheck'=>'#800', 'uparrow'=>'#555', 'user-cog'=>'#999', 'country'=>'#aaa', 'globe-americas'=>'#aaa', 'region'=>'#aaa', 'state'=>'#aaa',
4442 'website'=>'#304', 'workstation'=>'#a69944'
4443 );
4444 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4445 $facolor = $arrayconvpictotocolor[$pictowithouttext];
4446 }
4447
4448 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4449 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4450 $morestyle = '';
4451 $reg = array();
4452 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4453 $morecss .= ($morecss ? ' ' : '').$reg[1];
4454 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4455 }
4456 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4457 $morestyle = $reg[1];
4458 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4459 }
4460 $moreatt = trim($moreatt);
4461
4462 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4463 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4464 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4465 $enabledisablehtml .= $titlealt;
4466 }*/
4467 $enabledisablehtml .= '</span>';
4468
4469 return $enabledisablehtml;
4470 }
4471
4472 if (!empty($conf->global->MAIN_OVERWRITE_THEME_PATH)) {
4473 $path = $conf->global->MAIN_OVERWRITE_THEME_PATH.'/theme/'.$theme; // If the theme does not have the same name as the module
4474 } elseif (!empty($conf->global->MAIN_OVERWRITE_THEME_RES)) {
4475 $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
4476 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
4477 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
4478 }
4479
4480 // If we ask an image into $url/$mymodule/img (instead of default path)
4481 $regs = array();
4482 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
4483 $picto = $regs[1];
4484 $path = $regs[2]; // $path is $mymodule
4485 }
4486
4487 // Clean parameters
4488 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4489 $picto .= '.png';
4490 }
4491 // If alt path are defined, define url where img file is, according to physical path
4492 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
4493 foreach ($conf->file->dol_document_root as $type => $dirroot) {
4494 if ($type == 'main') {
4495 continue;
4496 }
4497 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommanded
4498 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
4499 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
4500 break;
4501 }
4502 }
4503
4504 // $url is '' or '/custom', $path is current theme or
4505 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
4506 }
4507
4508 if ($srconly) {
4509 return $fullpathpicto;
4510 }
4511
4512 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
4513 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
4514}
4515
4529function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0)
4530{
4531 if (strpos($picto, '^') === 0) {
4532 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
4533 } else {
4534 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
4535 }
4536}
4537
4549function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
4550{
4551 global $conf;
4552
4553 if (is_numeric($picto)) {
4554 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
4555 //$picto = $leveltopicto[$picto];
4556 return '<i class="fa fa-weather-level'.$picto.'"></i>';
4557 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4558 $picto .= '.png';
4559 }
4560
4561 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
4562
4563 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
4564}
4565
4577function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
4578{
4579 global $conf;
4580
4581 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4582 $picto .= '.png';
4583 }
4584
4585 if ($pictoisfullpath) {
4586 $path = $picto;
4587 } else {
4588 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
4589
4590 if (!empty($conf->global->MAIN_MODULE_CAN_OVERWRITE_COMMONICONS)) {
4591 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
4592
4593 if (file_exists($themepath)) {
4594 $path = $themepath;
4595 }
4596 }
4597 }
4598
4599 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
4600}
4601
4615function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
4616{
4617 global $langs;
4618
4619 if (empty($titlealt) || $titlealt == 'default') {
4620 if ($numaction == '-1' || $numaction == 'ST_NO') {
4621 $numaction = -1;
4622 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
4623 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
4624 $numaction = 0;
4625 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
4626 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
4627 $numaction = 1;
4628 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
4629 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
4630 $numaction = 2;
4631 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
4632 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
4633 $numaction = 3;
4634 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
4635 } else {
4636 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
4637 $numaction = 0;
4638 }
4639 }
4640 if (!is_numeric($numaction)) {
4641 $numaction = 0;
4642 }
4643
4644 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
4645}
4646
4654function img_pdf($titlealt = 'default', $size = 3)
4655{
4656 global $langs;
4657
4658 if ($titlealt == 'default') {
4659 $titlealt = $langs->trans('Show');
4660 }
4661
4662 return img_picto($titlealt, 'pdf'.$size.'.png');
4663}
4664
4672function img_edit_add($titlealt = 'default', $other = '')
4673{
4674 global $langs;
4675
4676 if ($titlealt == 'default') {
4677 $titlealt = $langs->trans('Add');
4678 }
4679
4680 return img_picto($titlealt, 'edit_add.png', $other);
4681}
4689function img_edit_remove($titlealt = 'default', $other = '')
4690{
4691 global $langs;
4692
4693 if ($titlealt == 'default') {
4694 $titlealt = $langs->trans('Remove');
4695 }
4696
4697 return img_picto($titlealt, 'edit_remove.png', $other);
4698}
4699
4708function img_edit($titlealt = 'default', $float = 0, $other = '')
4709{
4710 global $langs;
4711
4712 if ($titlealt == 'default') {
4713 $titlealt = $langs->trans('Modify');
4714 }
4715
4716 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
4717}
4718
4727function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
4728{
4729 global $langs;
4730
4731 if ($titlealt == 'default') {
4732 $titlealt = $langs->trans('View');
4733 }
4734
4735 $moreatt = ($float ? 'style="float: right" ' : '').$other;
4736
4737 return img_picto($titlealt, 'eye', $moreatt);
4738}
4739
4748function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
4749{
4750 global $langs;
4751
4752 if ($titlealt == 'default') {
4753 $titlealt = $langs->trans('Delete');
4754 }
4755
4756 return img_picto($titlealt, 'delete.png', $other, false, 0, 0, '', $morecss);
4757}
4758
4766function img_printer($titlealt = "default", $other = '')
4767{
4768 global $langs;
4769 if ($titlealt == "default") {
4770 $titlealt = $langs->trans("Print");
4771 }
4772 return img_picto($titlealt, 'printer.png', $other);
4773}
4774
4782function img_split($titlealt = 'default', $other = 'class="pictosplit"')
4783{
4784 global $langs;
4785
4786 if ($titlealt == 'default') {
4787 $titlealt = $langs->trans('Split');
4788 }
4789
4790 return img_picto($titlealt, 'split.png', $other);
4791}
4792
4800function img_help($usehelpcursor = 1, $usealttitle = 1)
4801{
4802 global $langs;
4803
4804 if ($usealttitle) {
4805 if (is_string($usealttitle)) {
4806 $usealttitle = dol_escape_htmltag($usealttitle);
4807 } else {
4808 $usealttitle = $langs->trans('Info');
4809 }
4810 }
4811
4812 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
4813}
4814
4821function img_info($titlealt = 'default')
4822{
4823 global $langs;
4824
4825 if ($titlealt == 'default') {
4826 $titlealt = $langs->trans('Informations');
4827 }
4828
4829 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
4830}
4831
4840function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
4841{
4842 global $langs;
4843
4844 if ($titlealt == 'default') {
4845 $titlealt = $langs->trans('Warning');
4846 }
4847
4848 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
4849 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
4850}
4851
4858function img_error($titlealt = 'default')
4859{
4860 global $langs;
4861
4862 if ($titlealt == 'default') {
4863 $titlealt = $langs->trans('Error');
4864 }
4865
4866 return img_picto($titlealt, 'error.png');
4867}
4868
4876function img_next($titlealt = 'default', $moreatt = '')
4877{
4878 global $langs;
4879
4880 if ($titlealt == 'default') {
4881 $titlealt = $langs->trans('Next');
4882 }
4883
4884 //return img_picto($titlealt, 'next.png', $moreatt);
4885 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
4886}
4887
4895function img_previous($titlealt = 'default', $moreatt = '')
4896{
4897 global $langs;
4898
4899 if ($titlealt == 'default') {
4900 $titlealt = $langs->trans('Previous');
4901 }
4902
4903 //return img_picto($titlealt, 'previous.png', $moreatt);
4904 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
4905}
4906
4915function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
4916{
4917 global $langs;
4918
4919 if ($titlealt == 'default') {
4920 $titlealt = $langs->trans('Down');
4921 }
4922
4923 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
4924}
4925
4934function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
4935{
4936 global $langs;
4937
4938 if ($titlealt == 'default') {
4939 $titlealt = $langs->trans('Up');
4940 }
4941
4942 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
4943}
4944
4953function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
4954{
4955 global $langs;
4956
4957 if ($titlealt == 'default') {
4958 $titlealt = $langs->trans('Left');
4959 }
4960
4961 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
4962}
4963
4972function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
4973{
4974 global $langs;
4975
4976 if ($titlealt == 'default') {
4977 $titlealt = $langs->trans('Right');
4978 }
4979
4980 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
4981}
4982
4990function img_allow($allow, $titlealt = 'default')
4991{
4992 global $langs;
4993
4994 if ($titlealt == 'default') {
4995 $titlealt = $langs->trans('Active');
4996 }
4997
4998 if ($allow == 1) {
4999 return img_picto($titlealt, 'tick.png');
5000 }
5001
5002 return '-';
5003}
5004
5012function img_credit_card($brand, $morecss = null)
5013{
5014 if (is_null($morecss)) {
5015 $morecss = 'fa-2x';
5016 }
5017
5018 if ($brand == 'visa' || $brand == 'Visa') {
5019 $brand = 'cc-visa';
5020 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5021 $brand = 'cc-mastercard';
5022 } elseif ($brand == 'amex' || $brand == 'American Express') {
5023 $brand = 'cc-amex';
5024 } elseif ($brand == 'discover' || $brand == 'Discover') {
5025 $brand = 'cc-discover';
5026 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5027 $brand = 'cc-jcb';
5028 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5029 $brand = 'cc-diners-club';
5030 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5031 $brand = 'credit-card';
5032 }
5033
5034 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5035}
5036
5045function img_mime($file, $titlealt = '', $morecss = '')
5046{
5047 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5048
5049 $mimetype = dol_mimetype($file, '', 1);
5050 $mimeimg = dol_mimetype($file, '', 2);
5051 $mimefa = dol_mimetype($file, '', 4);
5052
5053 if (empty($titlealt)) {
5054 $titlealt = 'Mime type: '.$mimetype;
5055 }
5056
5057 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5058 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5059}
5060
5061
5069function img_search($titlealt = 'default', $other = '')
5070{
5071 global $conf, $langs;
5072
5073 if ($titlealt == 'default') {
5074 $titlealt = $langs->trans('Search');
5075 }
5076
5077 $img = img_picto($titlealt, 'search.png', $other, false, 1);
5078
5079 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5080 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5081
5082 return $input;
5083}
5084
5092function img_searchclear($titlealt = 'default', $other = '')
5093{
5094 global $conf, $langs;
5095
5096 if ($titlealt == 'default') {
5097 $titlealt = $langs->trans('Search');
5098 }
5099
5100 $img = img_picto($titlealt, 'searchclear.png', $other, false, 1);
5101
5102 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5103 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5104
5105 return $input;
5106}
5107
5119function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '')
5120{
5121 global $conf, $langs;
5122
5123 if ($infoonimgalt) {
5124 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5125 } else {
5126 if (empty($conf->use_javascript_ajax)) {
5127 $textfordropdown = '';
5128 }
5129
5130 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5131 $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>');
5132
5133 if ($textfordropdown) {
5134 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5135 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5136 jQuery(document).ready(function() {
5137 jQuery(".'.$class.'text").click(function() {
5138 console.log("toggle text");
5139 jQuery(".'.$class.'").toggle();
5140 });
5141 });
5142 </script>';
5143
5144 $result = $tmpresult.$result;
5145 }
5146 }
5147
5148 return $result;
5149}
5150
5151
5163function dol_print_error($db = '', $error = '', $errors = null)
5164{
5165 global $conf, $langs, $argv;
5166 global $dolibarr_main_prod;
5167
5168 $out = '';
5169 $syslog = '';
5170
5171 // If error occurs before the $lang object was loaded
5172 if (!$langs) {
5173 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5174 $langs = new Translate('', $conf);
5175 $langs->load("main");
5176 }
5177
5178 // Load translation files required by the error messages
5179 $langs->loadLangs(array('main', 'errors'));
5180
5181 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5182 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5183 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5184 $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";
5185 }
5186 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5187
5188 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5189 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5190 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5191 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5192 }
5193 if (function_exists("phpversion")) {
5194 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5195 }
5196 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5197 if (function_exists("php_uname")) {
5198 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5199 }
5200 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5201 $out .= "<br>\n";
5202 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5203 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5204 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5205 $out .= "<br>\n";
5206 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5207 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5208 } else { // Mode CLI
5209 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5210 $syslog .= "pid=".dol_getmypid();
5211 }
5212
5213 if (!empty($conf->modules)) {
5214 $out .= "<b>".$langs->trans("Modules").":</b> ".join(', ', $conf->modules)."<br>\n";
5215 }
5216
5217 if (is_object($db)) {
5218 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5219 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5220 $lastqueryerror = $db->lastqueryerror();
5221 if (!utf8_check($lastqueryerror)) {
5222 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5223 }
5224 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5225 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5226 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5227 $out .= "<br>\n";
5228 } else { // Mode CLI
5229 // No dol_escape_htmltag for output, we are in CLI mode
5230 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5231 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5232 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5233 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5234 }
5235 $syslog .= ", sql=".$db->lastquery();
5236 $syslog .= ", db_error=".$db->lasterror();
5237 }
5238
5239 if ($error || $errors) {
5240 $langs->load("errors");
5241
5242 // Merge all into $errors array
5243 if (is_array($error) && is_array($errors)) {
5244 $errors = array_merge($error, $errors);
5245 } elseif (is_array($error)) {
5246 $errors = $error;
5247 } elseif (is_array($errors)) {
5248 $errors = array_merge(array($error), $errors);
5249 } else {
5250 $errors = array_merge(array($error), array($errors));
5251 }
5252
5253 foreach ($errors as $msg) {
5254 if (empty($msg)) {
5255 continue;
5256 }
5257 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5258 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5259 } else // Mode CLI
5260 {
5261 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5262 }
5263 $syslog .= ", msg=".$msg;
5264 }
5265 }
5266 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5267 xdebug_print_function_stack();
5268 $out .= '<b>XDebug informations:</b>'."<br>\n";
5269 $out .= 'File: '.xdebug_call_file()."<br>\n";
5270 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5271 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5272 $out .= "<br>\n";
5273 }
5274
5275 // Return a http header with error code if possible
5276 if (!headers_sent()) {
5277 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5278 top_httphead();
5279 }
5280 //http_response_code(500); // If we use 500, message is not ouput with some command line tools
5281 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
5282 }
5283
5284 if (empty($dolibarr_main_prod)) {
5285 print $out;
5286 } else {
5287 if (empty($langs->defaultlang)) {
5288 $langs->setDefaultLang();
5289 }
5290 $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.
5291 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5292 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";
5293 print $langs->trans("DolibarrHasDetectedError").'. ';
5294 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5295 if (!defined("MAIN_CORE_ERROR")) {
5296 define("MAIN_CORE_ERROR", 1);
5297 }
5298 }
5299
5300 dol_syslog("Error ".$syslog, LOG_ERR);
5301}
5302
5313function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5314{
5315 global $langs, $conf;
5316
5317 if (empty($email)) {
5318 $email = $conf->global->MAIN_INFO_SOCIETE_MAIL;
5319 }
5320
5321 $langs->load("errors");
5322 $now = dol_now();
5323
5324 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5325 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5326 if ($errormessage) {
5327 print '<br><br>'.$errormessage;
5328 }
5329 if (is_array($errormessages) && count($errormessages)) {
5330 foreach ($errormessages as $mesgtoshow) {
5331 print '<br><br>'.$mesgtoshow;
5332 }
5333 }
5334 print '</div></div>';
5335}
5336
5353function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
5354{
5355 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
5356}
5357
5376function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
5377{
5378 global $conf, $langs, $form;
5379 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
5380
5381 if ($moreattrib == 'class="right"') {
5382 $prefix .= 'right '; // For backward compatibility
5383 }
5384
5385 $sortorder = strtoupper($sortorder);
5386 $out = '';
5387 $sortimg = '';
5388
5389 $tag = 'th';
5390 if ($thead == 2) {
5391 $tag = 'div';
5392 }
5393
5394 $tmpsortfield = explode(',', $sortfield);
5395 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
5396 $tmpfield = explode(',', $field);
5397 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
5398
5399 if (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && empty($forcenowrapcolumntitle)) {
5400 $prefix = 'wrapcolumntitle '.$prefix;
5401 }
5402
5403 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
5404 // If field is used as sort criteria we use a specific css class liste_titre_sel
5405 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
5406 $liste_titre = 'liste_titre';
5407 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
5408 $liste_titre = 'liste_titre_sel';
5409 }
5410
5411 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
5412 //$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)).'"' : '');
5413 $tagstart .= ($name && empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
5414 $tagstart .= '>';
5415
5416 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5417 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5418 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5419 $options = preg_replace('/&+/i', '&', $options);
5420 if (!preg_match('/^&/', $options)) {
5421 $options = '&'.$options;
5422 }
5423
5424 $sortordertouseinlink = '';
5425 if ($field1 != $sortfield1) { // We are on another field than current sorted field
5426 if (preg_match('/^DESC/i', $sortorder)) {
5427 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5428 } else { // We reverse the var $sortordertouseinlink
5429 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5430 }
5431 } else { // We are on field that is the first current sorting criteria
5432 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
5433 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5434 } else {
5435 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5436 }
5437 }
5438 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
5439 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
5440 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5441 $out .= '>';
5442 }
5443 if ($tooltip) {
5444 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
5445 if (preg_match('/:\w+$/', $tooltip)) {
5446 $tmptooltip = explode(':', $tooltip);
5447 } else {
5448 $tmptooltip = array($tooltip);
5449 }
5450 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
5451 } else {
5452 $out .= $langs->trans($name);
5453 }
5454
5455 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5456 $out .= '</a>';
5457 }
5458
5459 if (empty($thead) && $field) { // If this is a sort field
5460 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5461 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5462 $options = preg_replace('/&+/i', '&', $options);
5463 if (!preg_match('/^&/', $options)) {
5464 $options = '&'.$options;
5465 }
5466
5467 if (!$sortorder || ($field1 != $sortfield1)) {
5468 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5469 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5470 } else {
5471 if (preg_match('/^DESC/', $sortorder)) {
5472 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5473 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
5474 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
5475 }
5476 if (preg_match('/^ASC/', $sortorder)) {
5477 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
5478 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5479 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
5480 }
5481 }
5482 }
5483
5484 $tagend = '</'.$tag.'>';
5485
5486 $out = $tagstart.$sortimg.$out.$tagend;
5487
5488 return $out;
5489}
5490
5499function print_titre($title)
5500{
5501 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
5502
5503 print '<div class="titre">'.$title.'</div>';
5504}
5505
5517function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
5518{
5519 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
5520}
5521
5535function load_fiche_titre($titre, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
5536{
5537 global $conf;
5538
5539 $return = '';
5540
5541 if ($picto == 'setup') {
5542 $picto = 'generic';
5543 }
5544
5545 $return .= "\n";
5546 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
5547 $return .= '<tr class="titre">';
5548 if ($picto) {
5549 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
5550 }
5551 $return .= '<td class="nobordernopadding valignmiddle col-title">';
5552 $return .= '<div class="titre inline-block">'.$titre.'</div>';
5553 $return .= '</td>';
5554 if (dol_strlen($morehtmlcenter)) {
5555 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5556 }
5557 if (dol_strlen($morehtmlright)) {
5558 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
5559 }
5560 $return .= '</tr></table>'."\n";
5561
5562 return $return;
5563}
5564
5588function 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 = '')
5589{
5590 global $conf, $langs;
5591
5592 $savlimit = $limit;
5593 $savtotalnboflines = $totalnboflines;
5594 $totalnboflines = abs((int) $totalnboflines);
5595
5596 $page = (int) $page;
5597
5598 if ($picto == 'setup') {
5599 $picto = 'title_setup.png';
5600 }
5601 if (($conf->browser->name == 'ie') && $picto == 'generic') {
5602 $picto = 'title.gif';
5603 }
5604 if ($limit < 0) {
5605 $limit = $conf->liste_limit;
5606 }
5607
5608 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
5609 $nextpage = 1;
5610 } else {
5611 $nextpage = 0;
5612 }
5613 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
5614
5615 print "\n";
5616 print "<!-- Begin title -->\n";
5617 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
5618
5619 // Left
5620
5621 if ($picto && $titre) {
5622 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
5623 }
5624
5625 print '<td class="nobordernopadding valignmiddle col-title">';
5626 print '<div class="titre inline-block">'.$titre;
5627 if (!empty($titre) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
5628 print '<span class="opacitymedium colorblack paddingleft">('.$totalnboflines.')</span>';
5629 }
5630 print '</div></td>';
5631
5632 // Center
5633 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
5634 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5635 }
5636
5637 // Right
5638 print '<td class="nobordernopadding valignmiddle right col-right">';
5639 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
5640 if ($sortfield) {
5641 $options .= "&sortfield=".urlencode($sortfield);
5642 }
5643 if ($sortorder) {
5644 $options .= "&sortorder=".urlencode($sortorder);
5645 }
5646 // Show navigation bar
5647 $pagelist = '';
5648 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
5649 if ($totalnboflines) { // If we know total nb of lines
5650 // Define nb of extra page links before and after selected page + ... + first or last
5651 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
5652
5653 if ($limit > 0) {
5654 $nbpages = ceil($totalnboflines / $limit);
5655 } else {
5656 $nbpages = 1;
5657 }
5658 $cpt = ($page - $maxnbofpage);
5659 if ($cpt < 0) {
5660 $cpt = 0;
5661 }
5662
5663 if ($cpt >= 1) {
5664 if (empty($pagenavastextinput)) {
5665 $pagelist .= '<li class="pagination"><a href="'.$file.'?page=0'.$options.'">1</a></li>';
5666 if ($cpt > 2) {
5667 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5668 } elseif ($cpt == 2) {
5669 $pagelist .= '<li class="pagination"><a href="'.$file.'?page=1'.$options.'">2</a></li>';
5670 }
5671 }
5672 }
5673
5674 do {
5675 if ($pagenavastextinput) {
5676 if ($cpt == $page) {
5677 $pagelist .= '<li class="pagination"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
5678 $pagelist .= '/';
5679 }
5680 } else {
5681 if ($cpt == $page) {
5682 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
5683 } else {
5684 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
5685 }
5686 }
5687 $cpt++;
5688 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
5689
5690 if (empty($pagenavastextinput)) {
5691 if ($cpt < $nbpages) {
5692 if ($cpt < $nbpages - 2) {
5693 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5694 } elseif ($cpt == $nbpages - 2) {
5695 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
5696 }
5697 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5698 }
5699 } else {
5700 //var_dump($page.' '.$cpt.' '.$nbpages);
5701 $pagelist .= '<li class="pagination paginationlastpage"><a href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5702 }
5703 } else {
5704 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
5705 }
5706 }
5707
5708 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
5709 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
5710 }
5711
5712 // js to autoselect page field on focus
5713 if ($pagenavastextinput) {
5714 print ajax_autoselect('.pageplusone');
5715 }
5716
5717 print '</td>';
5718 print '</tr>';
5719
5720 print '</table>'."\n";
5721
5722 // Center
5723 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
5724 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
5725 }
5726
5727 print "<!-- End title -->\n\n";
5728}
5729
5746function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
5747{
5748 global $conf, $langs;
5749
5750 print '<div class="pagination"><ul>';
5751 if ($beforearrows) {
5752 print '<li class="paginationbeforearrows">';
5753 print $beforearrows;
5754 print '</li>';
5755 }
5756
5757 if (empty($hidenavigation)) {
5758 if ((int) $limit > 0 && empty($hideselectlimit)) {
5759 $pagesizechoices = '10:10,15:15,20:20,30:30,40:40,50:50,100:100,250:250,500:500,1000:1000';
5760 $pagesizechoices .= ',5000:5000,10000:10000,20000:20000';
5761 //$pagesizechoices.=',0:'.$langs->trans("All"); // Not yet supported
5762 //$pagesizechoices.=',2:2';
5763 if (!empty($conf->global->MAIN_PAGESIZE_CHOICES)) {
5764 $pagesizechoices = $conf->global->MAIN_PAGESIZE_CHOICES;
5765 }
5766
5767 print '<li class="pagination">';
5768 print '<select class="flat selectlimit" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
5769 $tmpchoice = explode(',', $pagesizechoices);
5770 $tmpkey = $limit.':'.$limit;
5771 if (!in_array($tmpkey, $tmpchoice)) {
5772 $tmpchoice[] = $tmpkey;
5773 }
5774 $tmpkey = $conf->liste_limit.':'.$conf->liste_limit;
5775 if (!in_array($tmpkey, $tmpchoice)) {
5776 $tmpchoice[] = $tmpkey;
5777 }
5778 asort($tmpchoice, SORT_NUMERIC);
5779 foreach ($tmpchoice as $val) {
5780 $selected = '';
5781 $tmp = explode(':', $val);
5782 $key = $tmp[0];
5783 $val = $tmp[1];
5784 if ($key != '' && $val != '') {
5785 if ((int) $key == (int) $limit) {
5786 $selected = ' selected="selected"';
5787 }
5788 print '<option name="'.$key.'"'.$selected.'>'.dol_escape_htmltag($val).'</option>'."\n";
5789 }
5790 }
5791 print '</select>';
5792 if ($conf->use_javascript_ajax) {
5793 print '<!-- JS CODE TO ENABLE select limit to launch submit of page -->
5794 <script>
5795 jQuery(document).ready(function () {
5796 jQuery(".selectlimit").change(function() {
5797 console.log("Change limit. Send submit");
5798 $(this).parents(\'form:first\').submit();
5799 });
5800 });
5801 </script>
5802 ';
5803 }
5804 print '</li>';
5805 }
5806 if ($page > 0) {
5807 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>';
5808 }
5809 if ($betweenarrows) {
5810 print '<!--<div class="betweenarrows nowraponall inline-block">-->';
5811 print $betweenarrows;
5812 print '<!--</div>-->';
5813 }
5814 if ($nextpage > 0) {
5815 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>';
5816 }
5817 if ($afterarrows) {
5818 print '<li class="paginationafterarrows">';
5819 print $afterarrows;
5820 print '</li>';
5821 }
5822 }
5823 print '</ul></div>'."\n";
5824}
5825
5826
5838function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, $html = 0)
5839{
5840 $morelabel = '';
5841
5842 if (preg_match('/%/', $rate)) {
5843 $rate = str_replace('%', '', $rate);
5844 $addpercent = true;
5845 }
5846 $reg = array();
5847 if (preg_match('/\‍((.*)\‍)/', $rate, $reg)) {
5848 $morelabel = ' ('.$reg[1].')';
5849 $rate = preg_replace('/\s*'.preg_quote($morelabel, '/').'/', '', $rate);
5850 $morelabel = ' '.($html ? '<span class="opacitymedium">' : '').'('.$reg[1].')'.($html ? '</span>' : '');
5851 }
5852 if (preg_match('/\*/', $rate)) {
5853 $rate = str_replace('*', '', $rate);
5854 $info_bits |= 1;
5855 }
5856
5857 // If rate is '9/9/9' we don't change it. If rate is '9.000' we apply price()
5858 if (!preg_match('/\//', $rate)) {
5859 $ret = price($rate, 0, '', 0, 0).($addpercent ? '%' : '');
5860 } else {
5861 // TODO Split on / and output with a price2num to have clean numbers without ton of 000.
5862 $ret = $rate.($addpercent ? '%' : '');
5863 }
5864 if (($info_bits & 1) && $usestarfornpr >= 0) {
5865 $ret .= ' *';
5866 }
5867 $ret .= $morelabel;
5868 return $ret;
5869}
5870
5871
5887function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1, $currency_code = '')
5888{
5889 global $langs, $conf;
5890
5891 // Clean parameters
5892 if (empty($amount)) {
5893 $amount = 0; // To have a numeric value if amount not defined or = ''
5894 }
5895 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number)
5896 if ($rounding == -1) {
5897 $rounding = min($conf->global->MAIN_MAX_DECIMALS_UNIT, $conf->global->MAIN_MAX_DECIMALS_TOT);
5898 }
5899 $nbdecimal = $rounding;
5900
5901 if ($outlangs === 'none') {
5902 // Use international separators
5903 $dec = '.';
5904 $thousand = '';
5905 } else {
5906 // Output separators by default (french)
5907 $dec = ',';
5908 $thousand = ' ';
5909
5910 // If $outlangs not forced, we use use language
5911 if (!is_object($outlangs)) {
5912 $outlangs = $langs;
5913 }
5914
5915 if ($outlangs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
5916 $dec = $outlangs->transnoentitiesnoconv("SeparatorDecimal");
5917 }
5918 if ($outlangs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
5919 $thousand = $outlangs->transnoentitiesnoconv("SeparatorThousand");
5920 }
5921 if ($thousand == 'None') {
5922 $thousand = '';
5923 } elseif ($thousand == 'Space') {
5924 $thousand = ' ';
5925 }
5926 }
5927 //print "outlangs=".$outlangs->defaultlang." amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
5928
5929 //print "amount=".$amount."-";
5930 $amount = str_replace(',', '.', $amount); // should be useless
5931 //print $amount."-";
5932 $datas = explode('.', $amount);
5933 $decpart = isset($datas[1]) ? $datas[1] : '';
5934 $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
5935 //print "decpart=".$decpart."<br>";
5936 $end = '';
5937
5938 // We increase nbdecimal if there is more decimal than asked (to not loose information)
5939 if (dol_strlen($decpart) > $nbdecimal) {
5940 $nbdecimal = dol_strlen($decpart);
5941 }
5942 // Si on depasse max
5943 $max_nbdecimal = (int) str_replace('...', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'));
5944 if ($trunc && $nbdecimal > $max_nbdecimal) {
5945 $nbdecimal = $max_nbdecimal;
5946 if (preg_match('/\.\.\./i', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'))) {
5947 // Si un affichage est tronque, on montre des ...
5948 $end = '...';
5949 }
5950 }
5951
5952 // If force rounding
5953 if ((string) $forcerounding != '-1') {
5954 if ($forcerounding === 'MU') {
5955 $nbdecimal = $conf->global->MAIN_MAX_DECIMALS_UNIT;
5956 } elseif ($forcerounding === 'MT') {
5957 $nbdecimal = $conf->global->MAIN_MAX_DECIMALS_TOT;
5958 } elseif ($forcerounding >= 0) {
5959 $nbdecimal = $forcerounding;
5960 }
5961 }
5962
5963 // Format number
5964 $output = number_format($amount, $nbdecimal, $dec, $thousand);
5965 if ($form) {
5966 $output = preg_replace('/\s/', '&nbsp;', $output);
5967 $output = preg_replace('/\'/', '&#039;', $output);
5968 }
5969 // Add symbol of currency if requested
5970 $cursymbolbefore = $cursymbolafter = '';
5971 if ($currency_code && is_object($outlangs)) {
5972 if ($currency_code == 'auto') {
5973 $currency_code = $conf->currency;
5974 }
5975
5976 $listofcurrenciesbefore = array('AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD', 'CRC');
5977 $listoflanguagesbefore = array('nl_NL');
5978 if (in_array($currency_code, $listofcurrenciesbefore) || in_array($outlangs->defaultlang, $listoflanguagesbefore)) {
5979 $cursymbolbefore .= $outlangs->getCurrencySymbol($currency_code);
5980 } else {
5981 $tmpcur = $outlangs->getCurrencySymbol($currency_code);
5982 $cursymbolafter .= ($tmpcur == $currency_code ? ' '.$tmpcur : $tmpcur);
5983 }
5984 }
5985 $output = $cursymbolbefore.$output.$end.($cursymbolafter ? ' ' : '').$cursymbolafter;
5986
5987 return $output;
5988}
5989
6014function price2num($amount, $rounding = '', $option = 0)
6015{
6016 global $langs, $conf;
6017
6018 // Clean parameters
6019 if (is_null($amount)) {
6020 $amount = '';
6021 }
6022
6023 // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
6024 // Numbers must be '1234.56'
6025 // Decimal delimiter for PHP and database SQL requests must be '.'
6026 $dec = ',';
6027 $thousand = ' ';
6028 if (is_null($langs)) { // $langs is not defined, we use english values.
6029 $dec = '.';
6030 $thousand = ',';
6031 } else {
6032 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6033 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
6034 }
6035 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6036 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
6037 }
6038 }
6039 if ($thousand == 'None') {
6040 $thousand = '';
6041 } elseif ($thousand == 'Space') {
6042 $thousand = ' ';
6043 }
6044 //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6045
6046 // Convert value to universal number format (no thousand separator, '.' as decimal separator)
6047 if ($option != 1) { // If not a PHP number or unknown, we change or clean format
6048 //print "\n".'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'<br>';
6049 if (!is_numeric($amount)) {
6050 $amount = preg_replace('/[a-zA-Z\/\\\*\‍(\‍)<>\_]/', '', $amount);
6051 }
6052
6053 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
6054 $amount = str_replace($thousand, '', $amount);
6055 }
6056
6057 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6058 // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
6059 // So if number was already a good number, it is converted into local Dolibarr setup.
6060 if (is_numeric($amount)) {
6061 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6062 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6063 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6064 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6065 $amount = number_format($amount, $nbofdec, $dec, $thousand);
6066 }
6067 //print "QQ".$amount."<br>\n";
6068
6069 // Now make replace (the main goal of function)
6070 if ($thousand != ',' && $thousand != '.') {
6071 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6072 }
6073
6074 $amount = str_replace(' ', '', $amount); // To avoid spaces
6075 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6076 $amount = str_replace($dec, '.', $amount);
6077
6078 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6079 }
6080 //print ' XX'.$amount.' '.$rounding;
6081
6082 // Now, $amount is a real PHP float number. We make a rounding if required.
6083 if ($rounding) {
6084 $nbofdectoround = '';
6085 if ($rounding == 'MU') {
6086 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_UNIT;
6087 } elseif ($rounding == 'MT') {
6088 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_TOT;
6089 } elseif ($rounding == 'MS') {
6090 $nbofdectoround = isset($conf->global->MAIN_MAX_DECIMALS_STOCK) ? $conf->global->MAIN_MAX_DECIMALS_STOCK : 5;
6091 } elseif ($rounding == 'CU') {
6092 $nbofdectoround = max($conf->global->MAIN_MAX_DECIMALS_UNIT, 8); // TODO Use param of currency
6093 } elseif ($rounding == 'CT') {
6094 $nbofdectoround = max($conf->global->MAIN_MAX_DECIMALS_TOT, 8); // TODO Use param of currency
6095 } elseif (is_numeric($rounding)) {
6096 $nbofdectoround = (int) $rounding;
6097 }
6098
6099 //print " RR".$amount.' - '.$nbofdectoround.'<br>';
6100 if (dol_strlen($nbofdectoround)) {
6101 $amount = round(is_string($amount) ? (float) $amount : $amount, $nbofdectoround); // $nbofdectoround can be 0.
6102 } else {
6103 return 'ErrorBadParameterProvidedToFunction';
6104 }
6105 //print ' SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
6106
6107 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6108 // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
6109 if (is_numeric($amount)) {
6110 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6111 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6112 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6113 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6114 $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
6115 }
6116 //print "TT".$amount.'<br>';
6117
6118 // Always make replace because each math function (like round) replace
6119 // with local values and we want a number that has a SQL string format x.y
6120 if ($thousand != ',' && $thousand != '.') {
6121 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6122 }
6123
6124 $amount = str_replace(' ', '', $amount); // To avoid spaces
6125 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6126 $amount = str_replace($dec, '.', $amount);
6127
6128 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6129 }
6130
6131 return $amount;
6132}
6133
6146function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round = -1, $forceunitoutput = 'no', $use_short_label = 0)
6147{
6148 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
6149
6150 if (($forceunitoutput == 'no' && $dimension < 1 / 10000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -6)) {
6151 $dimension = $dimension * 1000000;
6152 $unit = $unit - 6;
6153 } elseif (($forceunitoutput == 'no' && $dimension < 1 / 10 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -3)) {
6154 $dimension = $dimension * 1000;
6155 $unit = $unit - 3;
6156 } elseif (($forceunitoutput == 'no' && $dimension > 100000000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 6)) {
6157 $dimension = $dimension / 1000000;
6158 $unit = $unit + 6;
6159 } elseif (($forceunitoutput == 'no' && $dimension > 100000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 3)) {
6160 $dimension = $dimension / 1000;
6161 $unit = $unit + 3;
6162 }
6163 // Special case when we want output unit into pound or ounce
6164 /* TODO
6165 if ($unit < 90 && $type == 'weight' && is_numeric($forceunitoutput) && (($forceunitoutput == 98) || ($forceunitoutput == 99))
6166 {
6167 $dimension = // convert dimension from standard unit into ounce or pound
6168 $unit = $forceunitoutput;
6169 }
6170 if ($unit > 90 && $type == 'weight' && is_numeric($forceunitoutput) && $forceunitoutput < 90)
6171 {
6172 $dimension = // convert dimension from standard unit into ounce or pound
6173 $unit = $forceunitoutput;
6174 }*/
6175
6176 $ret = price($dimension, 0, $outputlangs, 0, 0, $round);
6177 $ret .= ' '.measuringUnitString(0, $type, $unit, $use_short_label, $outputlangs);
6178
6179 return $ret;
6180}
6181
6182
6195function get_localtax($vatrate, $local, $thirdparty_buyer = "", $thirdparty_seller = "", $vatnpr = 0)
6196{
6197 global $db, $conf, $mysoc;
6198
6199 if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
6200 $thirdparty_seller = $mysoc;
6201 }
6202
6203 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);
6204
6205 $vatratecleaned = $vatrate;
6206 $reg = array();
6207 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6208 $vatratecleaned = trim($reg[1]);
6209 $vatratecode = $reg[2];
6210 }
6211
6212 /*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
6213 {
6214 return 0;
6215 }*/
6216
6217 // Some test to guess with no need to make database access
6218 if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
6219 if ($local == 1) {
6220 if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
6221 return 0;
6222 }
6223 if ($thirdparty_seller->id == $mysoc->id) {
6224 if (!$thirdparty_buyer->localtax1_assuj) {
6225 return 0;
6226 }
6227 } else {
6228 if (!$thirdparty_seller->localtax1_assuj) {
6229 return 0;
6230 }
6231 }
6232 }
6233
6234 if ($local == 2) {
6235 //if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
6236 if (!$mysoc->localtax2_assuj) {
6237 return 0; // If main vat is 0, IRPF may be different than 0.
6238 }
6239 if ($thirdparty_seller->id == $mysoc->id) {
6240 if (!$thirdparty_buyer->localtax2_assuj) {
6241 return 0;
6242 }
6243 } else {
6244 if (!$thirdparty_seller->localtax2_assuj) {
6245 return 0;
6246 }
6247 }
6248 }
6249 } else {
6250 if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
6251 return 0;
6252 }
6253 if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
6254 return 0;
6255 }
6256 }
6257
6258 // For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
6259 if (in_array($mysoc->country_code, array('ES'))) {
6260 $conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
6261 }
6262
6263 // Search local taxes
6264 if (!empty($conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY)) {
6265 if ($local == 1) {
6266 if ($thirdparty_seller != $mysoc) {
6267 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6268 return $thirdparty_seller->localtax1_value;
6269 }
6270 } else { // i am the seller
6271 if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
6272 return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
6273 }
6274 }
6275 }
6276 if ($local == 2) {
6277 if ($thirdparty_seller != $mysoc) {
6278 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6279 // TODO We should also return value defined on thirdparty only if defined
6280 return $thirdparty_seller->localtax2_value;
6281 }
6282 } else { // i am the seller
6283 if (in_array($mysoc->country_code, array('ES'))) {
6284 return $thirdparty_buyer->localtax2_value;
6285 } else {
6286 return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
6287 }
6288 }
6289 }
6290 }
6291
6292 // By default, search value of local tax on line of common tax
6293 $sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
6294 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6295 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
6296 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6297 if (!empty($vatratecode)) {
6298 $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
6299 } else {
6300 $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
6301 }
6302
6303 $resql = $db->query($sql);
6304
6305 if ($resql) {
6306 $obj = $db->fetch_object($resql);
6307 if ($obj) {
6308 if ($local == 1) {
6309 return $obj->localtax1;
6310 } elseif ($local == 2) {
6311 return $obj->localtax2;
6312 }
6313 }
6314 }
6315
6316 return 0;
6317}
6318
6319
6328function isOnlyOneLocalTax($local)
6329{
6330 $tax = get_localtax_by_third($local);
6331
6332 $valors = explode(":", $tax);
6333
6334 if (count($valors) > 1) {
6335 return false;
6336 } else {
6337 return true;
6338 }
6339}
6340
6348{
6349 global $db, $mysoc;
6350
6351 $sql = " SELECT t.localtax".$local." as localtax";
6352 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_pays";
6353 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.active = 1 AND t.taux = (";
6354 $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";
6355 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND tt.active = 1)";
6356 $sql .= " AND t.localtax".$local."_type <> '0'";
6357 $sql .= " ORDER BY t.rowid DESC";
6358
6359 $resql = $db->query($sql);
6360 if ($resql) {
6361 $obj = $db->fetch_object($resql);
6362 if ($obj) {
6363 return $obj->localtax;
6364 } else {
6365 return '0';
6366 }
6367 }
6368
6369 return 'Error';
6370}
6371
6372
6384function getTaxesFromId($vatrate, $buyer = null, $seller = null, $firstparamisid = 1)
6385{
6386 global $db, $mysoc;
6387
6388 dol_syslog("getTaxesFromId vat id or rate = ".$vatrate);
6389
6390 // Search local taxes
6391 $sql = "SELECT t.rowid, t.code, t.taux as rate, t.recuperableonly as npr, t.accountancy_code_sell, t.accountancy_code_buy,";
6392 $sql .= " t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type";
6393 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6394 if ($firstparamisid) {
6395 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6396 } else {
6397 $vatratecleaned = $vatrate;
6398 $vatratecode = '';
6399 $reg = array();
6400 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6401 $vatratecleaned = $reg[1];
6402 $vatratecode = $reg[2];
6403 }
6404
6405 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6406 /*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 ??
6407 else $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";*/
6408 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";
6409 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6410 if ($vatratecode) {
6411 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6412 }
6413 }
6414
6415 $resql = $db->query($sql);
6416 if ($resql) {
6417 $obj = $db->fetch_object($resql);
6418 if ($obj) {
6419 return array(
6420 'rowid'=>$obj->rowid,
6421 'code'=>$obj->code,
6422 'rate'=>$obj->rate,
6423 'localtax1'=>$obj->localtax1,
6424 'localtax1_type'=>$obj->localtax1_type,
6425 'localtax2'=>$obj->localtax2,
6426 'localtax2_type'=>$obj->localtax2_type,
6427 'npr'=>$obj->npr,
6428 'accountancy_code_sell'=>$obj->accountancy_code_sell,
6429 'accountancy_code_buy'=>$obj->accountancy_code_buy
6430 );
6431 } else {
6432 return array();
6433 }
6434 } else {
6435 dol_print_error($db);
6436 }
6437
6438 return array();
6439}
6440
6457function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid = 0)
6458{
6459 global $db, $mysoc;
6460
6461 dol_syslog("getLocalTaxesFromRate vatrate=".$vatrate." local=".$local);
6462
6463 // Search local taxes
6464 $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";
6465 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6466 if ($firstparamisid) {
6467 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6468 } else {
6469 $vatratecleaned = $vatrate;
6470 $vatratecode = '';
6471 $reg = array();
6472 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "x.x (yy)"
6473 $vatratecleaned = $reg[1];
6474 $vatratecode = $reg[2];
6475 }
6476
6477 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6478 if (!empty($mysoc) && $mysoc->country_code == 'ES') {
6479 $countrycodetouse = ((empty($buyer) || empty($buyer->country_code)) ? $mysoc->country_code : $buyer->country_code);
6480 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'"; // local tax in spain use the buyer country ??
6481 } else {
6482 $countrycodetouse = ((empty($seller) || empty($seller->country_code)) ? $mysoc->country_code : $seller->country_code);
6483 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'";
6484 }
6485 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6486 if ($vatratecode) {
6487 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6488 }
6489 }
6490
6491 $resql = $db->query($sql);
6492 if ($resql) {
6493 $obj = $db->fetch_object($resql);
6494
6495 if ($obj) {
6496 $vateratestring = $obj->rate.($obj->code ? ' ('.$obj->code.')' : '');
6497
6498 if ($local == 1) {
6499 return array($obj->localtax1_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6500 } elseif ($local == 2) {
6501 return array($obj->localtax2_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6502 } else {
6503 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);
6504 }
6505 }
6506 }
6507
6508 return array();
6509}
6510
6521function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice = 0)
6522{
6523 global $db, $conf, $mysoc;
6524
6525 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6526
6527 $ret = 0;
6528 $found = 0;
6529
6530 if ($idprod > 0) {
6531 // Load product
6532 $product = new Product($db);
6533 $product->fetch($idprod);
6534
6535 if ($mysoc->country_code == $thirdpartytouse->country_code) {
6536 // If country to consider is ours
6537 if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object
6538 $result = $product->get_buyprice($idprodfournprice, 0, 0, 0);
6539 if ($result > 0) {
6540 $ret = $product->vatrate_supplier;
6541 if ($product->default_vat_code_supplier) {
6542 $ret .= ' ('.$product->default_vat_code_supplier.')';
6543 }
6544 $found = 1;
6545 }
6546 }
6547 if (!$found) {
6548 $ret = $product->tva_tx; // Default sales vat of product
6549 if ($product->default_vat_code) {
6550 $ret .= ' ('.$product->default_vat_code.')';
6551 }
6552 $found = 1;
6553 }
6554 } else {
6555 // TODO Read default product vat according to product and another countrycode.
6556 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6557 }
6558 }
6559
6560 if (!$found) {
6561 if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) {
6562 // 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).
6563 $sql = "SELECT t.taux as vat_rate, t.code as default_vat_code";
6564 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6565 $sql .= " WHERE t.active = 1 AND t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdpartytouse->country_code)."'";
6566 $sql .= " ORDER BY t.use_default DESC, t.taux DESC, t.code ASC, t.recuperableonly ASC";
6567 $sql .= $db->plimit(1);
6568
6569 $resql = $db->query($sql);
6570 if ($resql) {
6571 $obj = $db->fetch_object($resql);
6572 if ($obj) {
6573 $ret = $obj->vat_rate;
6574 if ($obj->default_vat_code) {
6575 $ret .= ' ('.$obj->default_vat_code.')';
6576 }
6577 }
6578 $db->free($resql);
6579 } else {
6580 dol_print_error($db);
6581 }
6582 } else {
6583 // Forced value if autodetect fails. MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS can be
6584 // '1.23'
6585 // or '1.23 (CODE)'
6586 $defaulttx = '';
6587 if ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS != 'none') {
6588 $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6589 }
6590 /*if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6591 $defaultcode = $reg[1];
6592 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6593 }*/
6594
6595 $ret = $defaulttx;
6596 }
6597 }
6598
6599 dol_syslog("get_product_vat_for_country: ret=".$ret);
6600 return $ret;
6601}
6602
6612function get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
6613{
6614 global $db, $mysoc;
6615
6616 if (!class_exists('Product')) {
6617 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6618 }
6619
6620 $ret = 0;
6621 $found = 0;
6622
6623 if ($idprod > 0) {
6624 // Load product
6625 $product = new Product($db);
6626 $result = $product->fetch($idprod);
6627
6628 if ($mysoc->country_code == $thirdpartytouse->country_code) { // If selling country is ours
6629 /* Not defined yet, so we don't use this
6630 if ($local==1) $ret=$product->localtax1_tx;
6631 elseif ($local==2) $ret=$product->localtax2_tx;
6632 $found=1;
6633 */
6634 } else {
6635 // TODO Read default product vat according to product and another countrycode.
6636 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6637 }
6638 }
6639
6640 if (!$found) {
6641 // If vat of product for the country not found or not defined, we return higher vat of country.
6642 $sql = "SELECT taux as vat_rate, localtax1, localtax2";
6643 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6644 $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code='".$db->escape($thirdpartytouse->country_code)."'";
6645 $sql .= " ORDER BY t.taux DESC, t.recuperableonly ASC";
6646 $sql .= $db->plimit(1);
6647
6648 $resql = $db->query($sql);
6649 if ($resql) {
6650 $obj = $db->fetch_object($resql);
6651 if ($obj) {
6652 if ($local == 1) {
6653 $ret = $obj->localtax1;
6654 } elseif ($local == 2) {
6655 $ret = $obj->localtax2;
6656 }
6657 }
6658 } else {
6659 dol_print_error($db);
6660 }
6661 }
6662
6663 dol_syslog("get_product_localtax_for_country: ret=".$ret);
6664 return $ret;
6665}
6666
6683function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6684{
6685 global $conf;
6686
6687 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6688
6689 // Note: possible values for tva_assuj are 0/1 or franchise/reel
6690 $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;
6691
6692 $seller_country_code = $thirdparty_seller->country_code;
6693 $seller_in_cee = isInEEC($thirdparty_seller);
6694
6695 $buyer_country_code = $thirdparty_buyer->country_code;
6696 $buyer_in_cee = isInEEC($thirdparty_buyer);
6697
6698 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 : ''));
6699
6700 // 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)
6701 // we use the buyer VAT.
6702 if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) {
6703 if ($seller_in_cee && $buyer_in_cee) {
6704 $isacompany = $thirdparty_buyer->isACompany();
6705 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6706 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6707 if (!isValidVATID($thirdparty_buyer)) {
6708 $isacompany = 0;
6709 }
6710 }
6711
6712 if (!$isacompany) {
6713 //print 'VATRULE 0';
6714 return get_product_vat_for_country($idprod, $thirdparty_buyer, $idprodfournprice);
6715 }
6716 }
6717 }
6718
6719 // If seller does not use VAT, default VAT is 0. End of rule.
6720 if (!$seller_use_vat) {
6721 //print 'VATRULE 1';
6722 return 0;
6723 }
6724
6725 // If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule.
6726 if (($seller_country_code == $buyer_country_code)
6727 || (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC')))) { // Warning ->country_code not always defined
6728 //print 'VATRULE 2';
6729 $tmpvat = get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6730
6731 if ($seller_country_code == 'IN' && getDolGlobalString('MAIN_SALETAX_AUTOSWITCH_I_CS_FOR_INDIA')) {
6732 // Special case for india.
6733 //print 'VATRULE 2b';
6734 $reg = array();
6735 if (preg_match('/C+S-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id != $thirdparty_buyer->state_id) {
6736 // we must revert the C+S into I
6737 $tmpvat = str_replace("C+S", "I", $tmpvat);
6738 } elseif (preg_match('/I-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id == $thirdparty_buyer->state_id) {
6739 // we must revert the I into C+S
6740 $tmpvat = str_replace("I", "C+S", $tmpvat);
6741 }
6742 }
6743
6744 return $tmpvat;
6745 }
6746
6747 // 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.
6748 // 'VATRULE 3' - Not supported
6749
6750 // If (seller and buyer in the European Community) and (buyer = individual) then VAT by default = VAT of the product sold. End of rule
6751 // If (seller and buyer in European Community) and (buyer = company) then VAT by default=0. End of rule
6752 if (($seller_in_cee && $buyer_in_cee)) {
6753 $isacompany = $thirdparty_buyer->isACompany();
6754 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6755 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6756 if (!isValidVATID($thirdparty_buyer)) {
6757 $isacompany = 0;
6758 }
6759 }
6760
6761 if (!$isacompany) {
6762 //print 'VATRULE 4';
6763 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6764 } else {
6765 //print 'VATRULE 5';
6766 return 0;
6767 }
6768 }
6769
6770 // 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
6771 // I don't see any use case that need this rule.
6772 if (!empty($conf->global->MAIN_USE_VAT_OF_PRODUCT_FOR_INDIVIDUAL_CUSTOMER_OUT_OF_EEC) && empty($buyer_in_cee)) {
6773 $isacompany = $thirdparty_buyer->isACompany();
6774 if (!$isacompany) {
6775 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6776 //print 'VATRULE extra';
6777 }
6778 }
6779
6780 // Otherwise the VAT proposed by default=0. End of rule.
6781 // Rem: This means that at least one of the 2 is outside the European Community and the country differs
6782 //print 'VATRULE 6';
6783 return 0;
6784}
6785
6786
6797function get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6798{
6799 global $db;
6800
6801 if ($idprodfournprice > 0) {
6802 if (!class_exists('ProductFournisseur')) {
6803 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
6804 }
6805 $prodprice = new ProductFournisseur($db);
6806 $prodprice->fetch_product_fournisseur_price($idprodfournprice);
6807 return $prodprice->fourn_tva_npr;
6808 } elseif ($idprod > 0) {
6809 if (!class_exists('Product')) {
6810 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6811 }
6812 $prod = new Product($db);
6813 $prod->fetch($idprod);
6814 return $prod->tva_npr;
6815 }
6816
6817 return 0;
6818}
6819
6833function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod = 0)
6834{
6835 global $mysoc;
6836
6837 if (!is_object($thirdparty_seller)) {
6838 return -1;
6839 }
6840 if (!is_object($thirdparty_buyer)) {
6841 return -1;
6842 }
6843
6844 if ($local == 1) { // Localtax 1
6845 if ($mysoc->country_code == 'ES') {
6846 if (is_numeric($thirdparty_buyer->localtax1_assuj) && !$thirdparty_buyer->localtax1_assuj) {
6847 return 0;
6848 }
6849 } else {
6850 // Si vendeur non assujeti a Localtax1, localtax1 par default=0
6851 if (is_numeric($thirdparty_seller->localtax1_assuj) && !$thirdparty_seller->localtax1_assuj) {
6852 return 0;
6853 }
6854 if (!is_numeric($thirdparty_seller->localtax1_assuj) && $thirdparty_seller->localtax1_assuj == 'localtax1off') {
6855 return 0;
6856 }
6857 }
6858 } elseif ($local == 2) { //I Localtax 2
6859 // Si vendeur non assujeti a Localtax2, localtax2 par default=0
6860 if (is_numeric($thirdparty_seller->localtax2_assuj) && !$thirdparty_seller->localtax2_assuj) {
6861 return 0;
6862 }
6863 if (!is_numeric($thirdparty_seller->localtax2_assuj) && $thirdparty_seller->localtax2_assuj == 'localtax2off') {
6864 return 0;
6865 }
6866 }
6867
6868 if ($thirdparty_seller->country_code == $thirdparty_buyer->country_code) {
6869 return get_product_localtax_for_country($idprod, $local, $thirdparty_seller);
6870 }
6871
6872 return 0;
6873}
6874
6883function yn($yesno, $case = 1, $color = 0)
6884{
6885 global $langs;
6886
6887 $result = 'unknown';
6888 $classname = '';
6889 if ($yesno == 1 || (isset($yesno) && (strtolower($yesno) == 'yes' || strtolower($yesno) == 'true'))) { // A mettre avant test sur no a cause du == 0
6890 $result = $langs->trans('yes');
6891 if ($case == 1 || $case == 3) {
6892 $result = $langs->trans("Yes");
6893 }
6894 if ($case == 2) {
6895 $result = '<input type="checkbox" value="1" checked disabled>';
6896 }
6897 if ($case == 3) {
6898 $result = '<input type="checkbox" value="1" checked disabled> '.$result;
6899 }
6900
6901 $classname = 'ok';
6902 } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') {
6903 $result = $langs->trans("no");
6904 if ($case == 1 || $case == 3) {
6905 $result = $langs->trans("No");
6906 }
6907 if ($case == 2) {
6908 $result = '<input type="checkbox" value="0" disabled>';
6909 }
6910 if ($case == 3) {
6911 $result = '<input type="checkbox" value="0" disabled> '.$result;
6912 }
6913
6914 if ($color == 2) {
6915 $classname = 'ok';
6916 } else {
6917 $classname = 'error';
6918 }
6919 }
6920 if ($color) {
6921 return '<span class="'.$classname.'">'.$result.'</span>';
6922 }
6923 return $result;
6924}
6925
6941function get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart = '')
6942{
6943 global $conf;
6944
6945 if (empty($modulepart) && !empty($object->module)) {
6946 $modulepart = $object->module;
6947 }
6948
6949 $path = '';
6950
6951 $arrayforoldpath = array('cheque', 'category', 'holiday', 'supplier_invoice', 'invoice_supplier', 'mailing', 'supplier_payment');
6952 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
6953 $arrayforoldpath[] = 'product';
6954 }
6955 if (!empty($level) && in_array($modulepart, $arrayforoldpath)) {
6956 // This part should be removed once all code is using "get_exdir" to forge path, with parameter $object and $modulepart provided.
6957 if (empty($alpha)) {
6958 $num = preg_replace('/([^0-9])/i', '', $num);
6959 } else {
6960 $num = preg_replace('/^.*\-/i', '', $num);
6961 }
6962 $num = substr("000".$num, -$level);
6963 if ($level == 1) {
6964 $path = substr($num, 0, 1);
6965 }
6966 if ($level == 2) {
6967 $path = substr($num, 1, 1).'/'.substr($num, 0, 1);
6968 }
6969 if ($level == 3) {
6970 $path = substr($num, 2, 1).'/'.substr($num, 1, 1).'/'.substr($num, 0, 1);
6971 }
6972 } else {
6973 // We will enhance here a common way of forging path for document storage.
6974 // In a future, we may distribute directories on several levels depending on setup and object.
6975 // Here, $object->id, $object->ref and $modulepart are required.
6976 //var_dump($modulepart);
6977 $path = dol_sanitizeFileName(empty($object->ref) ? (string) $object->id : $object->ref);
6978 }
6979
6980 if (empty($withoutslash) && !empty($path)) {
6981 $path .= '/';
6982 }
6983
6984 return $path;
6985}
6986
6995function dol_mkdir($dir, $dataroot = '', $newmask = '')
6996{
6997 global $conf;
6998
6999 dol_syslog("functions.lib::dol_mkdir: dir=".$dir, LOG_INFO);
7000
7001 $dir_osencoded = dol_osencode($dir);
7002 if (@is_dir($dir_osencoded)) {
7003 return 0;
7004 }
7005
7006 $nberr = 0;
7007 $nbcreated = 0;
7008
7009 $ccdir = '';
7010 if (!empty($dataroot)) {
7011 // Remove data root from loop
7012 $dir = str_replace($dataroot.'/', '', $dir);
7013 $ccdir = $dataroot.'/';
7014 }
7015
7016 $cdir = explode("/", $dir);
7017 $num = count($cdir);
7018 for ($i = 0; $i < $num; $i++) {
7019 if ($i > 0) {
7020 $ccdir .= '/'.$cdir[$i];
7021 } else {
7022 $ccdir .= $cdir[$i];
7023 }
7024 $regs = array();
7025 if (preg_match("/^.:$/", $ccdir, $regs)) {
7026 continue; // Si chemin Windows incomplet, on poursuit par rep suivant
7027 }
7028
7029 // Attention, le is_dir() peut echouer bien que le rep existe.
7030 // (ex selon config de open_basedir)
7031 if ($ccdir) {
7032 $ccdir_osencoded = dol_osencode($ccdir);
7033 if (!@is_dir($ccdir_osencoded)) {
7034 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.", LOG_DEBUG);
7035
7036 umask(0);
7037 $dirmaskdec = octdec((string) $newmask);
7038 if (empty($newmask)) {
7039 $dirmaskdec = empty($conf->global->MAIN_UMASK) ? octdec('0755') : octdec($conf->global->MAIN_UMASK);
7040 }
7041 $dirmaskdec |= octdec('0111'); // Set x bit required for directories
7042 if (!@mkdir($ccdir_osencoded, $dirmaskdec)) {
7043 // Si le is_dir a renvoye une fausse info, alors on passe ici.
7044 dol_syslog("functions.lib::dol_mkdir: Fails to create directory '".$ccdir."' or directory already exists.", LOG_WARNING);
7045 $nberr++;
7046 } else {
7047 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' created", LOG_DEBUG);
7048 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignore
7049 $nbcreated++;
7050 }
7051 } else {
7052 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignores
7053 }
7054 }
7055 }
7056 return ($nberr ? -$nberr : $nbcreated);
7057}
7058
7059
7067function dolChmod($filepath, $newmask = '')
7068{
7069 global $conf;
7070
7071 if (!empty($newmask)) {
7072 @chmod($filepath, octdec($newmask));
7073 } elseif (!empty($conf->global->MAIN_UMASK)) {
7074 @chmod($filepath, octdec($conf->global->MAIN_UMASK));
7075 }
7076}
7077
7078
7085{
7086 return '<span class="fieldrequired">*</span>';
7087}
7088
7089
7106function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = 'UTF-8', $strip_tags = 0, $removedoublespaces = 1)
7107{
7108 if (is_null($stringtoclean)) {
7109 return '';
7110 }
7111
7112 if ($removelinefeed == 2) {
7113 $stringtoclean = preg_replace('/<br[^>]*>(\n|\r)+/ims', '<br>', $stringtoclean);
7114 }
7115 $temp = preg_replace('/<br[^>]*>/i', "\n", $stringtoclean);
7116
7117 // 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)
7118 $temp = dol_html_entity_decode($temp, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7119
7120 $temp = str_replace('< ', '__ltspace__', $temp);
7121
7122 if ($strip_tags) {
7123 $temp = strip_tags($temp);
7124 } else {
7125 // 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).
7126 $pattern = "/<[^<>]+>/";
7127 // Example of $temp: <a href="/myurl" title="<u>A title</u>">0000-021</a>
7128 // pass 1 - $temp after pass 1: <a href="/myurl" title="A title">0000-021
7129 // pass 2 - $temp after pass 2: 0000-021
7130 $tempbis = $temp;
7131 do {
7132 $temp = $tempbis;
7133 $tempbis = str_replace('<>', '', $temp); // No reason to have this into a text, except if value is to try bypass the next html cleaning
7134 $tempbis = preg_replace($pattern, '', $tempbis);
7135 //$idowhile++; print $temp.'-'.$tempbis."\n"; if ($idowhile > 100) break;
7136 } while ($tempbis != $temp);
7137
7138 $temp = $tempbis;
7139
7140 // 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).
7141 $temp = preg_replace('/<+([a-z]+)/i', '\1', $temp);
7142 }
7143
7144 $temp = dol_html_entity_decode($temp, ENT_COMPAT, $pagecodeto);
7145
7146 // Remove also carriage returns
7147 if ($removelinefeed == 1) {
7148 $temp = str_replace(array("\r\n", "\r", "\n"), " ", $temp);
7149 }
7150
7151 // And double quotes
7152 if ($removedoublespaces) {
7153 while (strpos($temp, " ")) {
7154 $temp = str_replace(" ", " ", $temp);
7155 }
7156 }
7157
7158 $temp = str_replace('__ltspace__', '< ', $temp);
7159
7160 return trim($temp);
7161}
7162
7178function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1, $cleanalsojavascript = 0, $allowiframe = 0, $allowed_tags = array(), $allowlink = 0)
7179{
7180 if (empty($allowed_tags)) {
7181 $allowed_tags = array(
7182 "html", "head", "meta", "body", "article", "a", "abbr", "b", "blockquote", "br", "cite", "div", "dl", "dd", "dt", "em", "font", "img", "ins", "hr", "i", "li",
7183 "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"
7184 );
7185 }
7186 $allowed_tags[] = "comment"; // this tags is added to manage comment <!--...--> that are replaced into <comment>...</comment>
7187 if ($allowiframe) {
7188 if (!in_array('iframe', $allowed_tags)) {
7189 $allowed_tags[] = "iframe";
7190 }
7191 }
7192 if ($allowlink) {
7193 if (!in_array('link', $allowed_tags)) {
7194 $allowed_tags[] = "link";
7195 }
7196 }
7197
7198 $allowed_tags_string = join("><", $allowed_tags);
7199 $allowed_tags_string = '<'.$allowed_tags_string.'>';
7200
7201 $stringtoclean = str_replace('<!DOCTYPE html>', '__!DOCTYPE_HTML__', $stringtoclean); // Replace DOCTYPE to avoid to have it removed by the strip_tags
7202
7203 $stringtoclean = dol_string_nounprintableascii($stringtoclean, 0);
7204
7205 //$stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
7206 $stringtoclean = preg_replace('/<!--([^>]*)-->/', '<comment>\1</comment>', $stringtoclean);
7207
7208 $stringtoclean = preg_replace('/&colon;/i', ':', $stringtoclean);
7209 $stringtoclean = preg_replace('/&#58;|&#0+58|&#x3A/i', '', $stringtoclean); // refused string ':' encoded (no reason to have a : encoded like this) to disable 'javascript:...'
7210
7211 $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
7212
7213 if ($cleanalsosomestyles) { // Clean for remaining html tags
7214 $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
7215 }
7216 if ($removeclassattribute) { // Clean for remaining html tags
7217 $temp = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $temp);
7218 }
7219
7220 // Remove 'javascript:' that we should not find into a text with
7221 // 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)).
7222 if ($cleanalsojavascript) {
7223 $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);
7224 }
7225
7226 $temp = str_replace('__!DOCTYPE_HTML__', '<!DOCTYPE html>', $temp); // Restore the DOCTYPE
7227
7228 $temp = preg_replace('/<comment>([^>]*)<\/comment>/', '<!--\1-->', $temp); // Restore html comments
7229
7230
7231 return $temp;
7232}
7233
7234
7246function dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes = array("allow", "allowfullscreen", "alt", "class", "contenteditable", "data-html", "frameborder", "height", "href", "id", "name", "src", "style", "target", "title", "width"))
7247{
7248 if (class_exists('DOMDocument') && !empty($stringtoclean)) {
7249 $stringtoclean = '<?xml encoding="UTF-8"><html><body>'.$stringtoclean.'</body></html>';
7250
7251 $dom = new DOMDocument(null, 'UTF-8');
7252 $dom->loadHTML($stringtoclean, LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7253
7254 if (is_object($dom)) {
7255 for ($els = $dom->getElementsByTagname('*'), $i = $els->length - 1; $i >= 0; $i--) {
7256 for ($attrs = $els->item($i)->attributes, $ii = $attrs->length - 1; $ii >= 0; $ii--) {
7257 //var_dump($attrs->item($ii));
7258 if (!empty($attrs->item($ii)->name)) {
7259 if (! in_array($attrs->item($ii)->name, $allowed_attributes)) {
7260 // Delete attribute if not into allowed_attributes
7261 $els->item($i)->removeAttribute($attrs->item($ii)->name);
7262 } elseif (in_array($attrs->item($ii)->name, array('style'))) {
7263 // If attribute is 'style'
7264 $valuetoclean = $attrs->item($ii)->value;
7265
7266 if (isset($valuetoclean)) {
7267 do {
7268 $oldvaluetoclean = $valuetoclean;
7269 $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments
7270 $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean);
7271 if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags.
7272 $valuetoclean = preg_replace('/display\s*:/mi', '', $valuetoclean);
7273 $valuetoclean = preg_replace('/z-index\s*:/mi', '', $valuetoclean);
7274 $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*:/mi', '', $valuetoclean);
7275 }
7276
7277 // We do not allow logout|passwordforgotten.php and action= into the content of a "style" tag
7278 $valuetoclean = preg_replace('/(logout|passwordforgotten)\.php/mi', '', $valuetoclean);
7279 $valuetoclean = preg_replace('/action=/mi', '', $valuetoclean);
7280 } while ($oldvaluetoclean != $valuetoclean);
7281 }
7282
7283 $attrs->item($ii)->value = $valuetoclean;
7284 }
7285 }
7286 }
7287 }
7288 }
7289
7290 $return = $dom->saveHTML(); // This may add a LF at end of lines, so we will trim later
7291 //$return = '<html><body>aaaa</p>bb<p>ssdd</p>'."\n<p>aaa</p>aa<p>bb</p>";
7292
7293 $return = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $return);
7294 $return = preg_replace('/^'.preg_quote('<html><body>', '/').'/', '', $return);
7295 $return = preg_replace('/'.preg_quote('</body></html>', '/').'$/', '', $return);
7296 return trim($return);
7297 } else {
7298 return $stringtoclean;
7299 }
7300}
7301
7313function dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags = array('textarea'), $cleanalsosomestyles = 0)
7314{
7315 $temp = $stringtoclean;
7316 foreach ($disallowed_tags as $tagtoremove) {
7317 $temp = preg_replace('/<\/?'.$tagtoremove.'>/', '', $temp);
7318 $temp = preg_replace('/<\/?'.$tagtoremove.'\s+[^>]*>/', '', $temp);
7319 }
7320
7321 if ($cleanalsosomestyles) {
7322 $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
7323 }
7324
7325 return $temp;
7326}
7327
7328
7338function dolGetFirstLineOfText($text, $nboflines = 1, $charset = 'UTF-8')
7339{
7340 if ($nboflines == 1) {
7341 if (dol_textishtml($text)) {
7342 $firstline = preg_replace('/<br[^>]*>.*$/s', '', $text); // The s pattern modifier means the . can match newline characters
7343 $firstline = preg_replace('/<div[^>]*>.*$/s', '', $firstline); // The s pattern modifier means the . can match newline characters
7344 } else {
7345 if (isset($text)) {
7346 $firstline = preg_replace('/[\n\r].*/', '', $text);
7347 } else {
7348 $firstline = '';
7349 }
7350 }
7351 return $firstline.(isset($firstline) && isset($text) && (strlen($firstline) != strlen($text)) ? '...' : '');
7352 } else {
7353 $ishtml = 0;
7354 if (dol_textishtml($text)) {
7355 $text = preg_replace('/\n/', '', $text);
7356 $ishtml = 1;
7357 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7358 } else {
7359 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7360 }
7361
7362 $text = strtr($text, $repTable);
7363 if ($charset == 'UTF-8') {
7364 $pattern = '/(<br[^>]*>)/Uu';
7365 } else {
7366 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7367 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7368 }
7369 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7370
7371 $firstline = '';
7372 $i = 0;
7373 $nba = count($a); // 2x nb of lines in $a because $a contains also a line for each new line separator
7374 while (($i < $nba) && ($i < ($nboflines * 2))) {
7375 if ($i % 2 == 0) {
7376 $firstline .= $a[$i];
7377 } elseif (($i < (($nboflines * 2) - 1)) && ($i < ($nba - 1))) {
7378 $firstline .= ($ishtml ? "<br>\n" : "\n");
7379 }
7380 $i++;
7381 }
7382 unset($a);
7383 return $firstline.(($i < $nba) ? '...' : '');
7384 }
7385}
7386
7387
7399function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false)
7400{
7401 if (is_null($stringtoencode)) {
7402 return '';
7403 }
7404
7405 if (!$nl2brmode) {
7406 return nl2br($stringtoencode, $forxml);
7407 } else {
7408 $ret = preg_replace('/(\r\n|\r|\n)/i', ($forxml ? '<br />' : '<br>'), $stringtoencode);
7409 return $ret;
7410 }
7411}
7412
7421function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = 'restricthtml')
7422{
7423 global $conf;
7424
7425 if (empty($nouseofiframesandbox) && !empty($conf->global->MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS)) {
7426 // TODO using sandbox on inline html content is not possible yet with current browsers
7427 //$s = '<iframe class="iframewithsandbox" sandbox><html><body>';
7428 //$s .= $stringtoencode;
7429 //$s .= '</body></html></iframe>';
7430 return $stringtoencode;
7431 } else {
7432 $out = $stringtoencode;
7433
7434 do {
7435 $oldstringtoclean = $out;
7436
7437 if (!empty($out) && !empty($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML) && $check != 'restricthtmlallowunvalid') {
7438 try {
7439 libxml_use_internal_errors(false); // Avoid to fill memory with xml errors
7440
7441 $dom = new DOMDocument;
7442 // Add a trick to solve pb with text without parent tag
7443 // like '<h1>Foo</h1><p>bar</p>' that wrongly ends up, without the trick, with '<h1>Foo<p>bar</p></h1>'
7444 // like 'abc' that wrongly ends up, without the trick, with '<p>abc</p>'
7445 $out = '<div class="tricktoremove">'.$out.'</div>';
7446 $dom->loadHTML($out, LIBXML_HTML_NODEFDTD|LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7447 $out = trim($dom->saveHTML());
7448
7449 // Remove the trick added to solve pb with text without parent tag
7450 $out = preg_replace('/^<div class="tricktoremove">/', '', $out);
7451 $out = preg_replace('/<\/div>$/', '', $out);
7452 } catch (Exception $e) {
7453 // If error, invalid HTML string with no way to clean it
7454 //print $e->getMessage();
7455 $out = 'InvalidHTMLStringCantBeCleaned';
7456 }
7457 }
7458
7459 // Clean some html entities that are useless so text is cleaner
7460 $out = preg_replace('/&(tab|newline);/i', ' ', $out);
7461
7462 // Ckeditor use the numeric entitic for apostrophe so we force it to text entity (all other special chars are
7463 // encoded using text entities) so we can then exclude all numeric entities.
7464 $out = preg_replace('/&#39;/i', '&apos;', $out);
7465
7466 // 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).
7467 // 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
7468 // using a non coventionnel way to be encoded, to not have them sanitized just after)
7469 $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) {
7470 return realCharForNumericEntities($m); }, $out);
7471
7472
7473 // Now we remove all remaining HTML entities starting with a number. We don't want such entities.
7474 $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'.
7475
7476 // Keep only some html tags and remove also some 'javascript:' strings
7477 $out = dol_string_onlythesehtmltags($out, 0, ($check == 'restricthtmlallowclass' ? 0 : 1), 1);
7478
7479 // Keep only some html attributes and exclude non expected HTML attributes and clean content of some attributes (keep only alt=, title=...).
7480 if (!empty($conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES)) {
7482 }
7483
7484 // Restore entity &apos; into &#39; (restricthtml is for html content so we can use html entity)
7485 $out = preg_replace('/&apos;/i', "&#39;", $out);
7486 } while ($oldstringtoclean != $out);
7487
7488 // Check the limit of external links that are automatically executed in a Rich text content. We count:
7489 // '<img' to avoid <img src="http...">
7490 // 'url(' to avoid inline style like background: url(http...
7491 // '<link' to avoid <link href="http...">
7492 $reg = array();
7493 preg_match_all('/(<img|url\‍(|<link)/i', $out, $reg);
7494 $nbextlink = count($reg[0]);
7495 if ($nbextlink > getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) {
7496 $out = 'TooManyLinksIntoHTMLString';
7497 }
7498 //
7499 if (!empty($conf->global->MAIN_DISALLOW_EXT_URL_INTO_DESCRIPTIONS) || $check == 'restricthtmlnolink') {
7500 if ($nbextlink > 0) {
7501 $out = 'ExternalLinksNotAllowed';
7502 }
7503 }
7504
7505 return $out;
7506 }
7507}
7508
7530function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UTF-8', $removelasteolbr = 1)
7531{
7532 if (is_null($stringtoencode)) {
7533 return '';
7534 }
7535
7536 $newstring = $stringtoencode;
7537 if (dol_textishtml($stringtoencode)) { // Check if text is already HTML or not
7538 $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.
7539 if ($removelasteolbr) {
7540 $newstring = preg_replace('/<br>$/i', '', $newstring); // Remove last <br> (remove only last one)
7541 }
7542 $newstring = strtr($newstring, array('&'=>'__and__', '<'=>'__lt__', '>'=>'__gt__', '"'=>'__dquot__'));
7543 $newstring = dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom); // Make entity encoding
7544 $newstring = strtr($newstring, array('__and__'=>'&', '__lt__'=>'<', '__gt__'=>'>', '__dquot__'=>'"'));
7545 } else {
7546 if ($removelasteolbr) {
7547 $newstring = preg_replace('/(\r\n|\r|\n)$/i', '', $newstring); // Remove last \n (may remove several)
7548 }
7549 $newstring = dol_nl2br(dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom), $nl2brmode);
7550 }
7551 // Other substitutions that htmlentities does not do
7552 //$newstring=str_replace(chr(128),'&euro;',$newstring); // 128 = 0x80. Not in html entity table. // Seems useles with TCPDF. Make bug with UTF8 languages
7553 return $newstring;
7554}
7555
7563function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8')
7564{
7565 $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7566 $ret = preg_replace('/'."\r\n".'<br(\s[\sa-zA-Z_="]*)?\/?>/i', "<br>", $ret);
7567 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\r\n".'/i', "\r\n", $ret);
7568 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\n".'/i', "\n", $ret);
7569 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', "\n", $ret);
7570 return $ret;
7571}
7572
7579function dol_htmlcleanlastbr($stringtodecode)
7580{
7581 $ret = preg_replace('/&nbsp;$/i', "", $stringtodecode); // Because wysiwyg editor may add a &nbsp; at end of last line
7582 $ret = preg_replace('/(<br>|<br(\s[\sa-zA-Z_="]*)?\/?>|'."\n".'|'."\r".')+$/i', "", $ret);
7583 return $ret;
7584}
7585
7595function dol_html_entity_decode($a, $b, $c = 'UTF-8', $keepsomeentities = 0)
7596{
7597 $newstring = $a;
7598 if ($keepsomeentities) {
7599 $newstring = strtr($newstring, array('&amp;'=>'__andamp__', '&lt;'=>'__andlt__', '&gt;'=>'__andgt__', '"'=>'__dquot__'));
7600 }
7601 $newstring = html_entity_decode((string) $newstring, (int) $b, (string) $c);
7602 if ($keepsomeentities) {
7603 $newstring = strtr($newstring, array('__andamp__'=>'&amp;', '__andlt__'=>'&lt;', '__andgt__'=>'&gt;', '__dquot__'=>'"'));
7604 }
7605 return $newstring;
7606}
7607
7618function dol_htmlentities($string, $flags = ENT_QUOTES|ENT_SUBSTITUTE, $encoding = 'UTF-8', $double_encode = false)
7619{
7620 return htmlentities($string, $flags, $encoding, $double_encode);
7621}
7622
7634function dol_string_is_good_iso($s, $clean = 0)
7635{
7636 $len = dol_strlen($s);
7637 $out = '';
7638 $ok = 1;
7639 for ($scursor = 0; $scursor < $len; $scursor++) {
7640 $ordchar = ord($s[$scursor]);
7641 //print $scursor.'-'.$ordchar.'<br>';
7642 if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) {
7643 $ok = 0;
7644 break;
7645 } elseif ($ordchar > 126 && $ordchar < 160) {
7646 $ok = 0;
7647 break;
7648 } elseif ($clean) {
7649 $out .= $s[$scursor];
7650 }
7651 }
7652 if ($clean) {
7653 return $out;
7654 }
7655 return $ok;
7656}
7657
7666function dol_nboflines($s, $maxchar = 0)
7667{
7668 if ($s == '') {
7669 return 0;
7670 }
7671 $arraystring = explode("\n", $s);
7672 $nb = count($arraystring);
7673
7674 return $nb;
7675}
7676
7677
7687function dol_nboflines_bis($text, $maxlinesize = 0, $charset = 'UTF-8')
7688{
7689 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7690 if (dol_textishtml($text)) {
7691 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7692 }
7693
7694 $text = strtr($text, $repTable);
7695 if ($charset == 'UTF-8') {
7696 $pattern = '/(<br[^>]*>)/Uu';
7697 } else {
7698 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7699 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7700 }
7701 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7702
7703 $nblines = (int) floor((count($a) + 1) / 2);
7704 // count possible auto line breaks
7705 if ($maxlinesize) {
7706 foreach ($a as $line) {
7707 if (dol_strlen($line) > $maxlinesize) {
7708 //$line_dec = html_entity_decode(strip_tags($line));
7709 $line_dec = html_entity_decode($line);
7710 if (dol_strlen($line_dec) > $maxlinesize) {
7711 $line_dec = wordwrap($line_dec, $maxlinesize, '\n', true);
7712 $nblines += substr_count($line_dec, '\n');
7713 }
7714 }
7715 }
7716 }
7717
7718 unset($a);
7719 return $nblines;
7720}
7721
7730function dol_textishtml($msg, $option = 0)
7731{
7732 if (is_null($msg)) {
7733 return false;
7734 }
7735
7736 if ($option == 1) {
7737 if (preg_match('/<html/i', $msg)) {
7738 return true;
7739 } elseif (preg_match('/<body/i', $msg)) {
7740 return true;
7741 } elseif (preg_match('/<\/textarea/i', $msg)) {
7742 return true;
7743 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
7744 return true;
7745 } elseif (preg_match('/<br/i', $msg)) {
7746 return true;
7747 }
7748 return false;
7749 } else {
7750 // Remove all urls because 'http://aa?param1=abc&amp;param2=def' must not be used inside detection
7751 $msg = preg_replace('/https?:\/\/[^"\'\s]+/i', '', $msg);
7752 if (preg_match('/<html/i', $msg)) {
7753 return true;
7754 } elseif (preg_match('/<body/i', $msg)) {
7755 return true;
7756 } elseif (preg_match('/<\/textarea/i', $msg)) {
7757 return true;
7758 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
7759 return true;
7760 } elseif (preg_match('/<(br|hr)\/>/i', $msg)) {
7761 return true;
7762 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)>/i', $msg)) {
7763 return true;
7764 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)\s+[^<>\/]*\/?>/i', $msg)) {
7765 return true;
7766 } elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i', $msg)) {
7767 return true; // must accept <img src="http://example.com/aaa.png" />
7768 } elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i', $msg)) {
7769 return true; // must accept <a href="http://example.com/aaa.png" />
7770 } elseif (preg_match('/<h[0-9]>/i', $msg)) {
7771 return true;
7772 } elseif (preg_match('/&[A-Z0-9]{1,6};/i', $msg)) {
7773 // TODO If content is 'A link https://aaa?param=abc&amp;param2=def', it return true but must be false
7774 return true; // Html entities names (http://www.w3schools.com/tags/ref_entities.asp)
7775 } elseif (preg_match('/&#[0-9]{2,3};/i', $msg)) {
7776 return true; // Html entities numbers (http://www.w3schools.com/tags/ref_entities.asp)
7777 }
7778
7779 return false;
7780 }
7781}
7782
7797function dol_concatdesc($text1, $text2, $forxml = false, $invert = false)
7798{
7799 if (!empty($invert)) {
7800 $tmp = $text1;
7801 $text1 = $text2;
7802 $text2 = $tmp;
7803 }
7804
7805 $ret = '';
7806 $ret .= (!dol_textishtml($text1) && dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text1, 0, 1, '', 1), 0, $forxml) : $text1;
7807 $ret .= (!empty($text1) && !empty($text2)) ? ((dol_textishtml($text1) || dol_textishtml($text2)) ? ($forxml ? "<br >\n" : "<br>\n") : "\n") : "";
7808 $ret .= (dol_textishtml($text1) && !dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text2, 0, 1, '', 1), 0, $forxml) : $text2;
7809 return $ret;
7810}
7811
7812
7813
7825function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null)
7826{
7827 global $db, $conf, $mysoc, $user, $extrafields;
7828
7829 $substitutionarray = array();
7830
7831 if ((empty($exclude) || !in_array('user', $exclude)) && (empty($include) || in_array('user', $include))) {
7832 // Add SIGNATURE into substitutionarray first, so, when we will make the substitution,
7833 // this will include signature content first and then replace var found into content of signature
7834 //var_dump($onlykey);
7835 $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()
7836 $usersignature = $user->signature;
7837 $substitutionarray = array_merge($substitutionarray, array(
7838 '__SENDEREMAIL_SIGNATURE__' => (string) ((empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN)) ? ($onlykey == 2 ? dol_trunc('SignatureFromTheSelectedSenderProfile', 30) : $emailsendersignature) : ''),
7839 '__USER_SIGNATURE__' => (string) (($usersignature && empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN)) ? ($onlykey == 2 ? dol_trunc(dol_string_nohtmltag($usersignature), 30) : $usersignature) : '')
7840 ));
7841
7842 if (is_object($user)) {
7843 $substitutionarray = array_merge($substitutionarray, array(
7844 '__USER_ID__' => (string) $user->id,
7845 '__USER_LOGIN__' => (string) $user->login,
7846 '__USER_EMAIL__' => (string) $user->email,
7847 '__USER_PHONE__' => (string) dol_print_phone($user->office_phone, '', 0, 0, '', " ", '', '', -1),
7848 '__USER_PHONEPRO__' => (string) dol_print_phone($user->user_mobile, '', 0, 0, '', " ", '', '', -1),
7849 '__USER_PHONEMOBILE__' => (string) dol_print_phone($user->personal_mobile, '', 0, 0, '', " ", '', '', -1),
7850 '__USER_FAX__' => (string) $user->office_fax,
7851 '__USER_LASTNAME__' => (string) $user->lastname,
7852 '__USER_FIRSTNAME__' => (string) $user->firstname,
7853 '__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
7854 '__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
7855 '__USER_JOB__' => (string) $user->job,
7856 '__USER_REMOTE_IP__' => (string) getUserRemoteIP(),
7857 '__USER_VCARD_URL__' => (string) $user->getOnlineVirtualCardUrl('', 'external')
7858 ));
7859 }
7860 }
7861 if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc) && (empty($include) || in_array('mycompany', $include))) {
7862 $substitutionarray = array_merge($substitutionarray, array(
7863 '__MYCOMPANY_NAME__' => $mysoc->name,
7864 '__MYCOMPANY_EMAIL__' => $mysoc->email,
7865 '__MYCOMPANY_PHONE__' => dol_print_phone($mysoc->phone, '', 0, 0, '', " ", '', '', -1),
7866 '__MYCOMPANY_FAX__' => dol_print_phone($mysoc->fax, '', 0, 0, '', " ", '', '', -1),
7867 '__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
7868 '__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
7869 '__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
7870 '__MYCOMPANY_PROFID4__' => $mysoc->idprof4,
7871 '__MYCOMPANY_PROFID5__' => $mysoc->idprof5,
7872 '__MYCOMPANY_PROFID6__' => $mysoc->idprof6,
7873 '__MYCOMPANY_CAPITAL__' => $mysoc->capital,
7874 '__MYCOMPANY_FULLADDRESS__' => (method_exists($mysoc, 'getFullAddress') ? $mysoc->getFullAddress(1, ', ') : ''), // $mysoc may be stdClass
7875 '__MYCOMPANY_ADDRESS__' => $mysoc->address,
7876 '__MYCOMPANY_ZIP__' => $mysoc->zip,
7877 '__MYCOMPANY_TOWN__' => $mysoc->town,
7878 '__MYCOMPANY_COUNTRY__' => $mysoc->country,
7879 '__MYCOMPANY_COUNTRY_ID__' => $mysoc->country_id,
7880 '__MYCOMPANY_COUNTRY_CODE__' => $mysoc->country_code,
7881 '__MYCOMPANY_CURRENCY_CODE__' => $conf->currency
7882 ));
7883 }
7884
7885 if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude)) && (empty($include) || in_array('object', $include))) {
7886 if ($onlykey) {
7887 $substitutionarray['__ID__'] = '__ID__';
7888 $substitutionarray['__REF__'] = '__REF__';
7889 $substitutionarray['__NEWREF__'] = '__NEWREF__';
7890 $substitutionarray['__LABEL__'] = '__LABEL__';
7891 $substitutionarray['__REF_CLIENT__'] = '__REF_CLIENT__';
7892 $substitutionarray['__REF_SUPPLIER__'] = '__REF_SUPPLIER__';
7893 $substitutionarray['__NOTE_PUBLIC__'] = '__NOTE_PUBLIC__';
7894 $substitutionarray['__NOTE_PRIVATE__'] = '__NOTE_PRIVATE__';
7895 $substitutionarray['__EXTRAFIELD_XXX__'] = '__EXTRAFIELD_XXX__';
7896
7897 if (isModEnabled("societe")) { // Most objects are concerned
7898 $substitutionarray['__THIRDPARTY_ID__'] = '__THIRDPARTY_ID__';
7899 $substitutionarray['__THIRDPARTY_NAME__'] = '__THIRDPARTY_NAME__';
7900 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = '__THIRDPARTY_NAME_ALIAS__';
7901 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = '__THIRDPARTY_CODE_CLIENT__';
7902 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = '__THIRDPARTY_CODE_FOURNISSEUR__';
7903 $substitutionarray['__THIRDPARTY_EMAIL__'] = '__THIRDPARTY_EMAIL__';
7904 $substitutionarray['__THIRDPARTY_PHONE__'] = '__THIRDPARTY_PHONE__';
7905 $substitutionarray['__THIRDPARTY_FAX__'] = '__THIRDPARTY_FAX__';
7906 $substitutionarray['__THIRDPARTY_ADDRESS__'] = '__THIRDPARTY_ADDRESS__';
7907 $substitutionarray['__THIRDPARTY_ZIP__'] = '__THIRDPARTY_ZIP__';
7908 $substitutionarray['__THIRDPARTY_TOWN__'] = '__THIRDPARTY_TOWN__';
7909 $substitutionarray['__THIRDPARTY_IDPROF1__'] = '__THIRDPARTY_IDPROF1__';
7910 $substitutionarray['__THIRDPARTY_IDPROF2__'] = '__THIRDPARTY_IDPROF2__';
7911 $substitutionarray['__THIRDPARTY_IDPROF3__'] = '__THIRDPARTY_IDPROF3__';
7912 $substitutionarray['__THIRDPARTY_IDPROF4__'] = '__THIRDPARTY_IDPROF4__';
7913 $substitutionarray['__THIRDPARTY_IDPROF5__'] = '__THIRDPARTY_IDPROF5__';
7914 $substitutionarray['__THIRDPARTY_IDPROF6__'] = '__THIRDPARTY_IDPROF6__';
7915 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = '__THIRDPARTY_TVAINTRA__';
7916 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = '__THIRDPARTY_NOTE_PUBLIC__';
7917 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = '__THIRDPARTY_NOTE_PRIVATE__';
7918 }
7919 if (isModEnabled('adherent') && (!is_object($object) || $object->element == 'adherent') && (empty($exclude) || !in_array('member', $exclude)) && (empty($include) || in_array('member', $include))) {
7920 $substitutionarray['__MEMBER_ID__'] = '__MEMBER_ID__';
7921 $substitutionarray['__MEMBER_CIVILITY__'] = '__MEMBER_CIVILITY__';
7922 $substitutionarray['__MEMBER_FIRSTNAME__'] = '__MEMBER_FIRSTNAME__';
7923 $substitutionarray['__MEMBER_LASTNAME__'] = '__MEMBER_LASTNAME__';
7924 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = 'Login and pass of the external user account';
7925 /*$substitutionarray['__MEMBER_NOTE_PUBLIC__'] = '__MEMBER_NOTE_PUBLIC__';
7926 $substitutionarray['__MEMBER_NOTE_PRIVATE__'] = '__MEMBER_NOTE_PRIVATE__';*/
7927 }
7928 // add variables subtitutions ticket
7929 if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket') && (empty($exclude) || !in_array('ticket', $exclude)) && (empty($include) || in_array('ticket', $include))) {
7930 $substitutionarray['__TICKET_TRACKID__'] = '__TICKET_TRACKID__';
7931 $substitutionarray['__TICKET_SUBJECT__'] = '__TICKET_SUBJECT__';
7932 $substitutionarray['__TICKET_TYPE__'] = '__TICKET_TYPE__';
7933 $substitutionarray['__TICKET_SEVERITY__'] = '__TICKET_SEVERITY__';
7934 $substitutionarray['__TICKET_CATEGORY__'] = '__TICKET_CATEGORY__';
7935 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = '__TICKET_ANALYTIC_CODE__';
7936 $substitutionarray['__TICKET_MESSAGE__'] = '__TICKET_MESSAGE__';
7937 $substitutionarray['__TICKET_PROGRESSION__'] = '__TICKET_PROGRESSION__';
7938 $substitutionarray['__TICKET_USER_ASSIGN__'] = '__TICKET_USER_ASSIGN__';
7939 }
7940
7941 if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature') && (empty($exclude) || !in_array('recruitment', $exclude)) && (empty($include) || in_array('recruitment', $include))) {
7942 $substitutionarray['__CANDIDATE_FULLNAME__'] = '__CANDIDATE_FULLNAME__';
7943 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = '__CANDIDATE_FIRSTNAME__';
7944 $substitutionarray['__CANDIDATE_LASTNAME__'] = '__CANDIDATE_LASTNAME__';
7945 }
7946 if (isModEnabled('project') && (empty($exclude) || !in_array('project', $exclude)) && (empty($include) || in_array('project', $include))) { // Most objects
7947 $substitutionarray['__PROJECT_ID__'] = '__PROJECT_ID__';
7948 $substitutionarray['__PROJECT_REF__'] = '__PROJECT_REF__';
7949 $substitutionarray['__PROJECT_NAME__'] = '__PROJECT_NAME__';
7950 /*$substitutionarray['__PROJECT_NOTE_PUBLIC__'] = '__PROJECT_NOTE_PUBLIC__';
7951 $substitutionarray['__PROJECT_NOTE_PRIVATE__'] = '__PROJECT_NOTE_PRIVATE__';*/
7952 }
7953 if (isModEnabled('contrat') && (!is_object($object) || $object->element == 'contract') && (empty($exclude) || !in_array('contract', $exclude)) && (empty($include) || in_array('contract', $include))) {
7954 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = 'Highest date planned for a service start';
7955 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = 'Highest date and hour planned for service start';
7956 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = 'Lowest data for planned expiration of service';
7957 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = 'Lowest date and hour for planned expiration of service';
7958 }
7959 if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal') && (empty($exclude) || !in_array('propal', $exclude)) && (empty($include) || in_array('propal', $include))) {
7960 $substitutionarray['__ONLINE_SIGN_URL__'] = 'ToOfferALinkForOnlineSignature';
7961 }
7962 if (isModEnabled("ficheinter") && (!is_object($object) || $object->element == 'fichinter') && (empty($exclude) || !in_array('intervention', $exclude)) && (empty($include) || in_array('intervention', $include))) {
7963 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = 'ToOfferALinkForOnlineSignature';
7964 }
7965 $substitutionarray['__ONLINE_PAYMENT_URL__'] = 'UrlToPayOnlineIfApplicable';
7966 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = 'TextAndUrlToPayOnlineIfApplicable';
7967 $substitutionarray['__SECUREKEYPAYMENT__'] = 'Security key (if key is not unique per record)';
7968 $substitutionarray['__SECUREKEYPAYMENT_MEMBER__'] = 'Security key for payment on a member subscription (one key per member)';
7969 $substitutionarray['__SECUREKEYPAYMENT_ORDER__'] = 'Security key for payment on an order';
7970 $substitutionarray['__SECUREKEYPAYMENT_INVOICE__'] = 'Security key for payment on an invoice';
7971 $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'Security key for payment on a service of a contract';
7972
7973 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = 'Direct download url of a proposal';
7974 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = 'Direct download url of an order';
7975 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = 'Direct download url of an invoice';
7976 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = 'Direct download url of a contract';
7977 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = 'Direct download url of a supplier proposal';
7978
7979 if (isModEnabled("expedition") && (!is_object($object) || $object->element == 'shipping')) {
7980 $substitutionarray['__SHIPPINGTRACKNUM__'] = 'Shipping tracking number';
7981 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = 'Shipping tracking url';
7982 }
7983 if (isModEnabled("reception") && (!is_object($object) || $object->element == 'reception')) {
7984 $substitutionarray['__RECEPTIONTRACKNUM__'] = 'Shippin tracking number of shipment';
7985 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = 'Shipping tracking url';
7986 }
7987 } else {
7988 $substitutionarray['__ID__'] = $object->id;
7989 $substitutionarray['__REF__'] = $object->ref;
7990 $substitutionarray['__NEWREF__'] = $object->newref;
7991 $substitutionarray['__LABEL__'] = (isset($object->label) ? $object->label : (isset($object->title) ? $object->title : null));
7992 $substitutionarray['__REF_CLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
7993 $substitutionarray['__REF_SUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
7994 $substitutionarray['__NOTE_PUBLIC__'] = (isset($object->note_public) ? $object->note_public : null);
7995 $substitutionarray['__NOTE_PRIVATE__'] = (isset($object->note_private) ? $object->note_private : null);
7996 if ($object->element == "shipping") {
7997 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, 'day', 0, $outputlangs) : '');
7998 } else {
7999 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, 'day', 0, $outputlangs) : '');
8000 }
8001 $substitutionarray['__DATE_DELIVERY_DAY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%d") : '');
8002 $substitutionarray['__DATE_DELIVERY_DAY_TEXT__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%A") : '');
8003 $substitutionarray['__DATE_DELIVERY_MON__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%m") : '');
8004 $substitutionarray['__DATE_DELIVERY_MON_TEXT__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%b") : '');
8005 $substitutionarray['__DATE_DELIVERY_YEAR__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%Y") : '');
8006 $substitutionarray['__DATE_DELIVERY_HH__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%H") : '');
8007 $substitutionarray['__DATE_DELIVERY_MM__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%M") : '');
8008 $substitutionarray['__DATE_DELIVERY_SS__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%S") : '');
8009
8010 // For backward compatibility (deprecated)
8011 $substitutionarray['__REFCLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8012 $substitutionarray['__REFSUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8013 $substitutionarray['__SUPPLIER_ORDER_DATE_DELIVERY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, 'day', 0, $outputlangs) : '');
8014 $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 : '')) : '');
8015
8016 if (is_object($object) && ($object->element == 'adherent' || $object->element == 'member') && $object->id > 0) {
8017 $birthday = (empty($object->birth) ? '' : dol_print_date($object->birth, 'day'));
8018
8019 $substitutionarray['__MEMBER_ID__'] = (isset($object->id) ? $object->id : '');
8020 if (method_exists($object, 'getCivilityLabel')) {
8021 $substitutionarray['__MEMBER_CIVILITY__'] = $object->getCivilityLabel();
8022 }
8023 $substitutionarray['__MEMBER_FIRSTNAME__'] = (isset($object->firstname) ? $object->firstname : '');
8024 $substitutionarray['__MEMBER_LASTNAME__'] = (isset($object->lastname) ? $object->lastname : '');
8025 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = '';
8026 if (method_exists($object, 'getFullName')) {
8027 $substitutionarray['__MEMBER_FULLNAME__'] = $object->getFullName($outputlangs);
8028 }
8029 $substitutionarray['__MEMBER_COMPANY__'] = (isset($object->societe) ? $object->societe : '');
8030 $substitutionarray['__MEMBER_ADDRESS__'] = (isset($object->address) ? $object->address : '');
8031 $substitutionarray['__MEMBER_ZIP__'] = (isset($object->zip) ? $object->zip : '');
8032 $substitutionarray['__MEMBER_TOWN__'] = (isset($object->town) ? $object->town : '');
8033 $substitutionarray['__MEMBER_COUNTRY__'] = (isset($object->country) ? $object->country : '');
8034 $substitutionarray['__MEMBER_EMAIL__'] = (isset($object->email) ? $object->email : '');
8035 $substitutionarray['__MEMBER_BIRTH__'] = (isset($birthday) ? $birthday : '');
8036 $substitutionarray['__MEMBER_PHOTO__'] = (isset($object->photo) ? $object->photo : '');
8037 $substitutionarray['__MEMBER_LOGIN__'] = (isset($object->login) ? $object->login : '');
8038 $substitutionarray['__MEMBER_PASSWORD__'] = (isset($object->pass) ? $object->pass : '');
8039 $substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? dol_print_phone($object->phone) : '');
8040 $substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? dol_print_phone($object->phone_perso) : '');
8041 $substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? dol_print_phone($object->phone_mobile) : '');
8042 $substitutionarray['__MEMBER_TYPE__'] = (isset($object->type) ? $object->type : '');
8043 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__'] = dol_print_date($object->first_subscription_date, 'day');
8044 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = (isset($object->first_subscription_date_start) ? dol_print_date($object->first_subscription_date_start, 'day') : '');
8045 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END__'] = (isset($object->first_subscription_date_end) ? dol_print_date($object->first_subscription_date_end, 'day') : '');
8046 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE__'] = dol_print_date($object->last_subscription_date, 'day');
8047 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->last_subscription_date_start, 'day');
8048 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END__'] = dol_print_date($object->last_subscription_date_end, 'day');
8049 }
8050
8051 if (is_object($object) && $object->element == 'societe') {
8052 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object) ? $object->id : '');
8053 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object) ? $object->name : '');
8054 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object) ? $object->name_alias : '');
8055 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object) ? $object->code_client : '');
8056 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object) ? $object->code_fournisseur : '');
8057 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object) ? $object->email : '');
8058 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? dol_print_phone($object->phone) : '');
8059 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? dol_print_phone($object->fax) : '');
8060 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object) ? $object->address : '');
8061 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object) ? $object->zip : '');
8062 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object) ? $object->town : '');
8063 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object) ? $object->country_id : '');
8064 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object) ? $object->country_code : '');
8065 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object) ? $object->idprof1 : '');
8066 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object) ? $object->idprof2 : '');
8067 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object) ? $object->idprof3 : '');
8068 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object) ? $object->idprof4 : '');
8069 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object) ? $object->idprof5 : '');
8070 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object) ? $object->idprof6 : '');
8071 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object) ? $object->tva_intra : '');
8072 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_public) : '');
8073 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_private) : '');
8074 } elseif (is_object($object->thirdparty)) {
8075 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->id : '');
8076 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object->thirdparty) ? $object->thirdparty->name : '');
8077 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object->thirdparty) ? $object->thirdparty->name_alias : '');
8078 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_client : '');
8079 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_fournisseur : '');
8080 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object->thirdparty) ? $object->thirdparty->email : '');
8081 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->phone) : '');
8082 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->fax) : '');
8083 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object->thirdparty) ? $object->thirdparty->address : '');
8084 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object->thirdparty) ? $object->thirdparty->zip : '');
8085 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object->thirdparty) ? $object->thirdparty->town : '');
8086 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_id : '');
8087 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_code : '');
8088 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof1 : '');
8089 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof2 : '');
8090 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof3 : '');
8091 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof4 : '');
8092 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof5 : '');
8093 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof6 : '');
8094 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object->thirdparty) ? $object->thirdparty->tva_intra : '');
8095 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_public) : '');
8096 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_private) : '');
8097 }
8098
8099 if (is_object($object) && $object->element == 'recruitmentcandidature') {
8100 $substitutionarray['__CANDIDATE_FULLNAME__'] = $object->getFullName($outputlangs);
8101 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8102 $substitutionarray['__CANDIDATE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8103 }
8104 if (is_object($object) && $object->element == 'conferenceorboothattendee') {
8105 $substitutionarray['__ATTENDEE_FULLNAME__'] = $object->getFullName($outputlangs);
8106 $substitutionarray['__ATTENDEE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8107 $substitutionarray['__ATTENDEE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8108 }
8109
8110 $project = null;
8111 if (is_object($object->project)) {
8112 $project = $object->project;
8113 } elseif (is_object($object->projet)) { // Deprecated, for backward compatibility
8114 $project = $object->projet;
8115 }
8116 if ($project) {
8117 $substitutionarray['__PROJECT_ID__'] = $project->id;
8118 $substitutionarray['__PROJECT_REF__'] = $project->ref;
8119 $substitutionarray['__PROJECT_NAME__'] = $project->title;
8120 }
8121 if (is_object($object) && $object->element == 'project') {
8122 $substitutionarray['__PROJECT_NAME__'] = $object->title;
8123 }
8124
8125 if (is_object($object) && $object->element == 'shipping') {
8126 $substitutionarray['__SHIPPINGTRACKNUM__'] = $object->tracking_number;
8127 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = $object->tracking_url;
8128 }
8129 if (is_object($object) && $object->element == 'reception') {
8130 $substitutionarray['__RECEPTIONTRACKNUM__'] = $object->tracking_number;
8131 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = $object->tracking_url;
8132 }
8133
8134 if (is_object($object) && $object->element == 'contrat' && $object->id > 0 && is_array($object->lines)) {
8135 $dateplannedstart = '';
8136 $datenextexpiration = '';
8137 foreach ($object->lines as $line) {
8138 if ($line->date_start > $dateplannedstart) {
8139 $dateplannedstart = $line->date_start;
8140 }
8141 if ($line->statut == 4 && $line->date_end && (!$datenextexpiration || $line->date_end < $datenextexpiration)) {
8142 $datenextexpiration = $line->date_end;
8143 }
8144 }
8145 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = dol_print_date($dateplannedstart, 'day');
8146 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = dol_print_date($dateplannedstart, 'standard');
8147 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = dol_print_date($datenextexpiration, 'day');
8148 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = dol_print_date($datenextexpiration, 'standard');
8149 }
8150 // add substition variable for ticket
8151 if (is_object($object) && $object->element == 'ticket') {
8152 $substitutionarray['__TICKET_TRACKID__'] = $object->track_id;
8153 $substitutionarray['__REF__'] = $object->ref;
8154 $substitutionarray['__TICKET_SUBJECT__'] = $object->subject;
8155 $substitutionarray['__TICKET_TYPE__'] = $object->type_code;
8156 $substitutionarray['__TICKET_SEVERITY__'] = $object->severity_code;
8157 $substitutionarray['__TICKET_CATEGORY__'] = $object->category_code; // For backward compatibility
8158 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = $object->category_code;
8159 $substitutionarray['__TICKET_MESSAGE__'] = $object->message;
8160 $substitutionarray['__TICKET_PROGRESSION__'] = $object->progress;
8161 $userstat = new User($db);
8162 if ($object->fk_user_assign > 0) {
8163 $userstat->fetch($object->fk_user_assign);
8164 $substitutionarray['__TICKET_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8165 }
8166
8167 if ($object->fk_user_create > 0) {
8168 $userstat->fetch($object->fk_user_create);
8169 $substitutionarray['__USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8170 }
8171 }
8172
8173 // Create dynamic tags for __EXTRAFIELD_FIELD__
8174 if ($object->table_element && $object->id > 0) {
8175 if (!is_object($extrafields)) {
8176 $extrafields = new ExtraFields($db);
8177 }
8178 $extrafields->fetch_name_optionals_label($object->table_element, true);
8179
8180 if ($object->fetch_optionals() > 0) {
8181 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) {
8182 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
8183 if ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
8184 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_date($object->array_options['options_'.$key], 'day');
8185 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = dol_print_date($object->array_options['options_'.$key], 'day', 'tzserver', $outputlangs);
8186 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = dol_print_date($object->array_options['options_'.$key], 'dayrfc');
8187 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'datetime') {
8188 $datetime = $object->array_options['options_'.$key];
8189 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour') : '');
8190 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : '');
8191 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_DAY_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'day', 'tzserver', $outputlangs) : '');
8192 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : '');
8193 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'phone') {
8194 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_phone($object->array_options['options_'.$key]);
8195 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
8196 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = $object->array_options['options_'.$key];
8197 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATED__'] = price($object->array_options['options_'.$key]);
8198 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] != 'separator') {
8199 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = !empty($object->array_options['options_'.$key]) ? $object->array_options['options_'.$key] :'';
8200 }
8201 }
8202 }
8203 }
8204 }
8205
8206 // Complete substitution array with the url to make online payment
8207 $paymenturl = '';
8208 if (empty($substitutionarray['__REF__'])) {
8209 $paymenturl = '';
8210 } else {
8211 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
8212 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
8213 $outputlangs->loadLangs(array('paypal', 'other'));
8214
8215 $amounttouse = 0;
8216 $typeforonlinepayment = 'free';
8217 if (is_object($object) && $object->element == 'commande') {
8218 $typeforonlinepayment = 'order';
8219 }
8220 if (is_object($object) && $object->element == 'facture') {
8221 $typeforonlinepayment = 'invoice';
8222 }
8223 if (is_object($object) && $object->element == 'member') {
8224 $typeforonlinepayment = 'member';
8225 if (!empty($object->last_subscription_amount)) {
8226 $amounttouse = $object->last_subscription_amount;
8227 }
8228 }
8229 if (is_object($object) && $object->element == 'contrat') {
8230 $typeforonlinepayment = 'contract';
8231 }
8232 if (is_object($object) && $object->element == 'fichinter') {
8233 $typeforonlinepayment = 'ficheinter';
8234 }
8235
8236 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__'], $amounttouse);
8237 $paymenturl = $url;
8238 }
8239
8240 if ($object->id > 0) {
8241 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ?str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : '');
8242 $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl;
8243
8244 if (!empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'propal') {
8245 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8246 } else {
8247 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = '';
8248 }
8249 if (!empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'commande') {
8250 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = $object->getLastMainDocLink($object->element);
8251 } else {
8252 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = '';
8253 }
8254 if (!empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'facture') {
8255 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = $object->getLastMainDocLink($object->element);
8256 } else {
8257 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = '';
8258 }
8259 if (!empty($conf->global->CONTRACT_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'contrat') {
8260 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = $object->getLastMainDocLink($object->element);
8261 } else {
8262 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = '';
8263 }
8264 if (!empty($conf->global->FICHINTER_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'fichinter') {
8265 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = $object->getLastMainDocLink($object->element);
8266 } else {
8267 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = '';
8268 }
8269 if (!empty($conf->global->SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'supplier_proposal') {
8270 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8271 } else {
8272 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = '';
8273 }
8274
8275 if (is_object($object) && $object->element == 'propal') {
8276 $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id;
8277 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8278 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref);
8279 }
8280 if (is_object($object) && $object->element == 'commande') {
8281 $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id;
8282 }
8283 if (is_object($object) && $object->element == 'facture') {
8284 $substitutionarray['__URL_INVOICE__'] = DOL_MAIN_URL_ROOT."/compta/facture/card.php?id=".$object->id;
8285 }
8286 if (is_object($object) && $object->element == 'contrat') {
8287 $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id;
8288 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8289 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref);
8290 }
8291 if (is_object($object) && $object->element == 'fichinter') {
8292 $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id;
8293 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8294 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref);
8295 }
8296 if (is_object($object) && $object->element == 'supplier_proposal') {
8297 $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id;
8298 }
8299 if (is_object($object) && $object->element == 'shipping') {
8300 $substitutionarray['__URL_SHIPMENT__'] = DOL_MAIN_URL_ROOT."/expedition/card.php?id=".$object->id;
8301 }
8302 }
8303
8304 if (is_object($object) && $object->element == 'action') {
8305 $substitutionarray['__EVENT_LABEL__'] = $object->label;
8306 $substitutionarray['__EVENT_DATE__'] = dol_print_date($object->datep, '%A %d %b %Y');
8307 $substitutionarray['__EVENT_TIME__'] = dol_print_date($object->datep, '%H:%M:%S');
8308 }
8309 }
8310 }
8311 if ((empty($exclude) || !in_array('objectamount', $exclude)) && (empty($include) || in_array('objectamount', $include))) {
8312 include_once DOL_DOCUMENT_ROOT.'/core/lib/functionsnumtoword.lib.php';
8313
8314 $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : '';
8315 $substitutionarray['__DATE_DUE_YMD__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs) : null) : '';
8316
8317 $already_payed_all = 0;
8318 if (is_object($object) && ($object instanceof Facture)) {
8319 $already_payed_all = $object->sumpayed + $object->sumdeposit + $object->sumcreditnote;
8320 }
8321
8322 $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : '';
8323
8324 $substitutionarray['__AMOUNT__'] = is_object($object) ? $object->total_ttc : '';
8325 $substitutionarray['__AMOUNT_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, '', true) : '';
8326 $substitutionarray['__AMOUNT_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, $conf->currency, true) : '';
8327
8328 $substitutionarray['__AMOUNT_REMAIN__'] = is_object($object) ? price2num($object->total_ttc - $already_payed_all, 'MT') : '';
8329
8330 $substitutionarray['__AMOUNT_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8331 $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)) : '';
8332 $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)) : '';
8333
8334 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8335 $substitutionarray['__AMOUNT_TAX2__'] = is_object($object) ? $object->total_localtax1 : '';
8336 }
8337 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8338 $substitutionarray['__AMOUNT_TAX3__'] = is_object($object) ? $object->total_localtax2 : '';
8339 }
8340
8341 // Amount keys formated in a currency
8342 $substitutionarray['__AMOUNT_EXCL_TAX_FORMATED__'] = is_object($object) ? ($object->total_ht ? price($object->total_ht, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8343 $substitutionarray['__AMOUNT_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8344 $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) : '';
8345 $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)) : '';
8346 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8347 $substitutionarray['__AMOUNT_TAX2_FORMATED__'] = is_object($object) ? ($object->total_localtax1 ? price($object->total_localtax1, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8348 }
8349 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8350 $substitutionarray['__AMOUNT_TAX3_FORMATED__'] = is_object($object) ? ($object->total_localtax2 ? price($object->total_localtax2, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8351 }
8352
8353 $substitutionarray['__AMOUNT_MULTICURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? $object->multicurrency_total_ttc : '';
8354 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXT__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, '', true) : '';
8355 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXTCURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, $object->multicurrency_code, true) : '';
8356 // TODO Add other keys for foreign multicurrency
8357
8358 // For backward compatibility
8359 if ($onlykey != 2) {
8360 $substitutionarray['__TOTAL_TTC__'] = is_object($object) ? $object->total_ttc : '';
8361 $substitutionarray['__TOTAL_HT__'] = is_object($object) ? $object->total_ht : '';
8362 $substitutionarray['__TOTAL_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8363 }
8364 }
8365
8366 //var_dump($substitutionarray['__AMOUNT_FORMATED__']);
8367 if ((empty($exclude) || !in_array('date', $exclude)) && (empty($include) || in_array('date', $include))) {
8368 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
8369
8370 $now = dol_now();
8371
8372 $tmp = dol_getdate($now, true);
8373 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8374 $tmp3 = dol_get_prev_month($tmp['mon'], $tmp['year']);
8375 $tmp4 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8376 $tmp5 = dol_get_next_month($tmp['mon'], $tmp['year']);
8377
8378 $daytext = $outputlangs->trans('Day'.$tmp['wday']);
8379
8380 $substitutionarray = array_merge($substitutionarray, array(
8381 '__NOW_TMS__' => (int) $now,
8382 '__NOW_TMS_YMD__' => dol_print_date($now, 'day', 0, $outputlangs),
8383 '__DAY__' => (string) $tmp['mday'],
8384 '__DAY_TEXT__' => $daytext, // Monday
8385 '__DAY_TEXT_SHORT__' => dol_trunc($daytext, 3, 'right', 'UTF-8', 1), // Mon
8386 '__DAY_TEXT_MIN__' => dol_trunc($daytext, 1, 'right', 'UTF-8', 1), // M
8387 '__MONTH__' => (string) $tmp['mon'],
8388 '__MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp['mon'])),
8389 '__MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp['mon'])),
8390 '__MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp['mon'])),
8391 '__YEAR__' => (string) $tmp['year'],
8392 '__PREVIOUS_DAY__' => (string) $tmp2['day'],
8393 '__PREVIOUS_MONTH__' => (string) $tmp3['month'],
8394 '__PREVIOUS_YEAR__' => (string) ($tmp['year'] - 1),
8395 '__NEXT_DAY__' => (string) $tmp4['day'],
8396 '__NEXT_MONTH__' => (string) $tmp5['month'],
8397 '__NEXT_YEAR__' => (string) ($tmp['year'] + 1),
8398 ));
8399 }
8400
8401 if (isModEnabled('multicompany')) {
8402 $substitutionarray = array_merge($substitutionarray, array('__ENTITY_ID__' => $conf->entity));
8403 }
8404 if ((empty($exclude) || !in_array('system', $exclude)) && (empty($include) || in_array('user', $include))) {
8405 $substitutionarray['__DOL_MAIN_URL_ROOT__'] = DOL_MAIN_URL_ROOT;
8406 $substitutionarray['__(AnyTranslationKey)__'] = $outputlangs->trans('TranslationOfKey');
8407 $substitutionarray['__(AnyTranslationKey|langfile)__'] = $outputlangs->trans('TranslationOfKey').' (load also language file before)';
8408 $substitutionarray['__[AnyConstantKey]__'] = $outputlangs->trans('ValueOfConstantKey');
8409 }
8410
8411 return $substitutionarray;
8412}
8413
8430function make_substitutions($text, $substitutionarray, $outputlangs = null, $converttextinhtmlifnecessary = 0)
8431{
8432 global $conf, $langs;
8433
8434 if (!is_array($substitutionarray)) {
8435 return 'ErrorBadParameterSubstitutionArrayWhenCalling_make_substitutions';
8436 }
8437
8438 if (empty($outputlangs)) {
8439 $outputlangs = $langs;
8440 }
8441
8442 // Is initial text HTML or simple text ?
8443 $msgishtml = 0;
8444 if (dol_textishtml($text, 1)) {
8445 $msgishtml = 1;
8446 }
8447
8448 // Make substitution for language keys: __(AnyTranslationKey)__ or __(AnyTranslationKey|langfile)__
8449 if (is_object($outputlangs)) {
8450 $reg = array();
8451 while (preg_match('/__\‍(([^\‍)]+)\‍)__/', $text, $reg)) {
8452 // If key is __(TranslationKey|langfile)__, then force load of langfile.lang
8453 $tmp = explode('|', $reg[1]);
8454 if (!empty($tmp[1])) {
8455 $outputlangs->load($tmp[1]);
8456 }
8457
8458 $value = $outputlangs->transnoentitiesnoconv($reg[1]);
8459
8460 if (empty($converttextinhtmlifnecessary)) {
8461 // convert $newval into HTML is necessary
8462 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8463 } else {
8464 if (! $msgishtml) {
8465 $valueishtml = dol_textishtml($value, 1);
8466 //var_dump("valueishtml=".$valueishtml);
8467
8468 if ($valueishtml) {
8469 $text = dol_htmlentitiesbr($text);
8470 $msgishtml = 1;
8471 }
8472 } else {
8473 $value = dol_nl2br("$value");
8474 }
8475
8476 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $value, $text);
8477 }
8478 }
8479 }
8480
8481 // Make substitution for constant keys.
8482 // Must be after the substitution of translation, so if the text of translation contains a string __[xxx]__, it is also converted.
8483 $reg = array();
8484 while (preg_match('/__\[([^\]]+)\]__/', $text, $reg)) {
8485 $keyfound = $reg[1];
8486 if (isASecretKey($keyfound)) {
8487 $value = '*****forbidden*****';
8488 } else {
8489 $value = empty($conf->global->$keyfound) ? '' : $conf->global->$keyfound;
8490 }
8491
8492 if (empty($converttextinhtmlifnecessary)) {
8493 // convert $newval into HTML is necessary
8494 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8495 } else {
8496 if (! $msgishtml) {
8497 $valueishtml = dol_textishtml($value, 1);
8498
8499 if ($valueishtml) {
8500 $text = dol_htmlentitiesbr($text);
8501 $msgishtml = 1;
8502 }
8503 } else {
8504 $value = dol_nl2br("$value");
8505 }
8506
8507 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $value, $text);
8508 }
8509 }
8510
8511 // Make substitution for array $substitutionarray
8512 foreach ($substitutionarray as $key => $value) {
8513 if (!isset($value)) {
8514 continue; // If value is null, it same than not having substitution key at all into array, we do not replace.
8515 }
8516
8517 if (($key == '__USER_SIGNATURE__' || $key == '__SENDEREMAIL_SIGNATURE__') && (!empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN))) {
8518 $value = ''; // Protection
8519 }
8520
8521 if (empty($converttextinhtmlifnecessary)) {
8522 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8523 } else {
8524 if (! $msgishtml) {
8525 $valueishtml = dol_textishtml($value, 1);
8526
8527 if ($valueishtml) {
8528 $text = dol_htmlentitiesbr($text);
8529 $msgishtml = 1;
8530 }
8531 } else {
8532 $value = dol_nl2br("$value");
8533 }
8534 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8535 }
8536 }
8537
8538 return $text;
8539}
8540
8553function complete_substitutions_array(&$substitutionarray, $outputlangs, $object = null, $parameters = null, $callfunc = "completesubstitutionarray")
8554{
8555 global $conf, $user;
8556
8557 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
8558
8559 // Note: substitution key for each extrafields, using key __EXTRA_XXX__ is already available into the getCommonSubstitutionArray used to build the substitution array.
8560
8561 // Check if there is external substitution to do, requested by plugins
8562 $dirsubstitutions = array_merge(array(), (array) $conf->modules_parts['substitutions']);
8563
8564 foreach ($dirsubstitutions as $reldir) {
8565 $dir = dol_buildpath($reldir, 0);
8566
8567 // Check if directory exists
8568 if (!dol_is_dir($dir)) {
8569 continue;
8570 }
8571
8572 $substitfiles = dol_dir_list($dir, 'files', 0, 'functions_');
8573 foreach ($substitfiles as $substitfile) {
8574 $reg = array();
8575 if (preg_match('/functions_(.*)\.lib\.php/i', $substitfile['name'], $reg)) {
8576 $module = $reg[1];
8577
8578 dol_syslog("Library ".$substitfile['name']." found into ".$dir);
8579 // Include the user's functions file
8580 require_once $dir.$substitfile['name'];
8581 // Call the user's function, and only if it is defined
8582 $function_name = $module."_".$callfunc;
8583 if (function_exists($function_name)) {
8584 $function_name($substitutionarray, $outputlangs, $object, $parameters);
8585 }
8586 }
8587 }
8588 }
8589 if (!empty($conf->global->ODT_ENABLE_ALL_TAGS_IN_SUBSTITUTIONS)) {
8590 // to list all tags in odt template
8591 $tags = '';
8592 foreach ($substitutionarray as $key => $value) {
8593 $tags .= '{'.$key.'} => '.$value."\n";
8594 }
8595 $substitutionarray = array_merge($substitutionarray, array('__ALL_TAGS__' => $tags));
8596 }
8597}
8598
8608function print_date_range($date_start, $date_end, $format = '', $outputlangs = '')
8609{
8610 print get_date_range($date_start, $date_end, $format, $outputlangs);
8611}
8612
8623function get_date_range($date_start, $date_end, $format = '', $outputlangs = '', $withparenthesis = 1)
8624{
8625 global $langs;
8626
8627 $out = '';
8628
8629 if (!is_object($outputlangs)) {
8630 $outputlangs = $langs;
8631 }
8632
8633 if ($date_start && $date_end) {
8634 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFromTo', dol_print_date($date_start, $format, false, $outputlangs), dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8635 }
8636 if ($date_start && !$date_end) {
8637 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($date_start, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8638 }
8639 if (!$date_start && $date_end) {
8640 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8641 }
8642
8643 return $out;
8644}
8645
8654function dolGetFirstLastname($firstname, $lastname, $nameorder = -1)
8655{
8656 global $conf;
8657
8658 $ret = '';
8659 // If order not defined, we use the setup
8660 if ($nameorder < 0) {
8661 $nameorder = (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION) ? 1 : 0);
8662 }
8663 if ($nameorder == 1) {
8664 $ret .= $firstname;
8665 if ($firstname && $lastname) {
8666 $ret .= ' ';
8667 }
8668 $ret .= $lastname;
8669 } elseif ($nameorder == 2 || $nameorder == 3) {
8670 $ret .= $firstname;
8671 if (empty($ret) && $nameorder == 3) {
8672 $ret .= $lastname;
8673 }
8674 } else { // 0, 4 or 5
8675 $ret .= $lastname;
8676 if (empty($ret) && $nameorder == 5) {
8677 $ret .= $firstname;
8678 }
8679 if ($nameorder == 0) {
8680 if ($firstname && $lastname) {
8681 $ret .= ' ';
8682 }
8683 $ret .= $firstname;
8684 }
8685 }
8686 return $ret;
8687}
8688
8689
8701function setEventMessage($mesgs, $style = 'mesgs', $noduplicate = 0)
8702{
8703 //dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING); This is not deprecated, it is used by setEventMessages function
8704 if (!is_array($mesgs)) {
8705 // If mesgs is a string
8706 if ($mesgs) {
8707 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesgs, $_SESSION['dol_events'][$style])) {
8708 return;
8709 }
8710 $_SESSION['dol_events'][$style][] = $mesgs;
8711 }
8712 } else {
8713 // If mesgs is an array
8714 foreach ($mesgs as $mesg) {
8715 if ($mesg) {
8716 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesg, $_SESSION['dol_events'][$style])) {
8717 return;
8718 }
8719 $_SESSION['dol_events'][$style][] = $mesg;
8720 }
8721 }
8722 }
8723}
8724
8737function setEventMessages($mesg, $mesgs, $style = 'mesgs', $messagekey = '', $noduplicate = 0)
8738{
8739 if (empty($mesg) && empty($mesgs)) {
8740 dol_syslog("Try to add a message in stack, but value to add is empty message", LOG_WARNING);
8741 } else {
8742 if ($messagekey) {
8743 // Complete message with a js link to set a cookie "DOLHIDEMESSAGE".$messagekey;
8744 // TODO
8745 $mesg .= '';
8746 }
8747 if (empty($messagekey) || empty($_COOKIE["DOLHIDEMESSAGE".$messagekey])) {
8748 if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
8749 dol_print_error('', 'Bad parameter style='.$style.' for setEventMessages');
8750 }
8751 if (empty($mesgs)) {
8752 setEventMessage($mesg, $style, $noduplicate);
8753 } else {
8754 if (!empty($mesg) && !in_array($mesg, $mesgs)) {
8755 setEventMessage($mesg, $style, $noduplicate); // Add message string if not already into array
8756 }
8757 setEventMessage($mesgs, $style, $noduplicate);
8758 }
8759 }
8760 }
8761}
8762
8772function dol_htmloutput_events($disabledoutputofmessages = 0)
8773{
8774 // Show mesgs
8775 if (isset($_SESSION['dol_events']['mesgs'])) {
8776 if (empty($disabledoutputofmessages)) {
8777 dol_htmloutput_mesg('', $_SESSION['dol_events']['mesgs']);
8778 }
8779 unset($_SESSION['dol_events']['mesgs']);
8780 }
8781 // Show errors
8782 if (isset($_SESSION['dol_events']['errors'])) {
8783 if (empty($disabledoutputofmessages)) {
8784 dol_htmloutput_mesg('', $_SESSION['dol_events']['errors'], 'error');
8785 }
8786 unset($_SESSION['dol_events']['errors']);
8787 }
8788
8789 // Show warnings
8790 if (isset($_SESSION['dol_events']['warnings'])) {
8791 if (empty($disabledoutputofmessages)) {
8792 dol_htmloutput_mesg('', $_SESSION['dol_events']['warnings'], 'warning');
8793 }
8794 unset($_SESSION['dol_events']['warnings']);
8795 }
8796}
8797
8812function get_htmloutput_mesg($mesgstring = '', $mesgarray = '', $style = 'ok', $keepembedded = 0)
8813{
8814 global $conf, $langs;
8815
8816 $ret = 0;
8817 $return = '';
8818 $out = '';
8819 $divstart = $divend = '';
8820
8821 // If inline message with no format, we add it.
8822 if ((empty($conf->use_javascript_ajax) || !empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) || $keepembedded) && !preg_match('/<div class=".*">/i', $out)) {
8823 $divstart = '<div class="'.$style.' clearboth">';
8824 $divend = '</div>';
8825 }
8826
8827 if ((is_array($mesgarray) && count($mesgarray)) || $mesgstring) {
8828 $langs->load("errors");
8829 $out .= $divstart;
8830 if (is_array($mesgarray) && count($mesgarray)) {
8831 foreach ($mesgarray as $message) {
8832 $ret++;
8833 $out .= $langs->trans($message);
8834 if ($ret < count($mesgarray)) {
8835 $out .= "<br>\n";
8836 }
8837 }
8838 }
8839 if ($mesgstring) {
8840 $ret++;
8841 $out .= $langs->trans($mesgstring);
8842 }
8843 $out .= $divend;
8844 }
8845
8846 if ($out) {
8847 if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) && empty($keepembedded)) {
8848 $return = '<script nonce="'.getNonce().'">
8849 $(document).ready(function() {
8850 var block = '.(!empty($conf->global->MAIN_USE_JQUERY_BLOCKUI) ? "true" : "false").'
8851 if (block) {
8852 $.dolEventValid("","'.dol_escape_js($out).'");
8853 } else {
8854 /* jnotify(message, preset of message type, keepmessage) */
8855 $.jnotify("'.dol_escape_js($out).'",
8856 "'.($style == "ok" ? 3000 : $style).'",
8857 '.($style == "ok" ? "false" : "true").',
8858 { remove: function (){} } );
8859 }
8860 });
8861 </script>';
8862 } else {
8863 $return = $out;
8864 }
8865 }
8866
8867 return $return;
8868}
8869
8881function get_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
8882{
8883 return get_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
8884}
8885
8899function dol_htmloutput_mesg($mesgstring = '', $mesgarray = array(), $style = 'ok', $keepembedded = 0)
8900{
8901 if (empty($mesgstring) && (!is_array($mesgarray) || count($mesgarray) == 0)) {
8902 return;
8903 }
8904
8905 $iserror = 0;
8906 $iswarning = 0;
8907 if (is_array($mesgarray)) {
8908 foreach ($mesgarray as $val) {
8909 if ($val && preg_match('/class="error"/i', $val)) {
8910 $iserror++;
8911 break;
8912 }
8913 if ($val && preg_match('/class="warning"/i', $val)) {
8914 $iswarning++;
8915 break;
8916 }
8917 }
8918 } elseif ($mesgstring && preg_match('/class="error"/i', $mesgstring)) {
8919 $iserror++;
8920 } elseif ($mesgstring && preg_match('/class="warning"/i', $mesgstring)) {
8921 $iswarning++;
8922 }
8923 if ($style == 'error') {
8924 $iserror++;
8925 }
8926 if ($style == 'warning') {
8927 $iswarning++;
8928 }
8929
8930 if ($iserror || $iswarning) {
8931 // Remove div from texts
8932 $mesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $mesgstring);
8933 $mesgstring = preg_replace('/<div class="(error|warning)">/', '', $mesgstring);
8934 $mesgstring = preg_replace('/<\/div>/', '', $mesgstring);
8935 // Remove div from texts array
8936 if (is_array($mesgarray)) {
8937 $newmesgarray = array();
8938 foreach ($mesgarray as $val) {
8939 if (is_string($val)) {
8940 $tmpmesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $val);
8941 $tmpmesgstring = preg_replace('/<div class="(error|warning)">/', '', $tmpmesgstring);
8942 $tmpmesgstring = preg_replace('/<\/div>/', '', $tmpmesgstring);
8943 $newmesgarray[] = $tmpmesgstring;
8944 } else {
8945 dol_syslog("Error call of dol_htmloutput_mesg with an array with a value that is not a string", LOG_WARNING);
8946 }
8947 }
8948 $mesgarray = $newmesgarray;
8949 }
8950 print get_htmloutput_mesg($mesgstring, $mesgarray, ($iserror ? 'error' : 'warning'), $keepembedded);
8951 } else {
8952 print get_htmloutput_mesg($mesgstring, $mesgarray, 'ok', $keepembedded);
8953 }
8954}
8955
8967function dol_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
8968{
8969 dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
8970}
8971
8986function dol_sort_array(&$array, $index, $order = 'asc', $natsort = 0, $case_sensitive = 0, $keepindex = 0)
8987{
8988 // Clean parameters
8989 $order = strtolower($order);
8990
8991 if (is_array($array)) {
8992 $sizearray = count($array);
8993 if ($sizearray > 0) {
8994 $temp = array();
8995 foreach (array_keys($array) as $key) {
8996 if (is_object($array[$key])) {
8997 $temp[$key] = empty($array[$key]->$index) ? 0 : $array[$key]->$index;
8998 } else {
8999 $temp[$key] = empty($array[$key][$index]) ? 0 : $array[$key][$index];
9000 }
9001 if ($natsort == -1) {
9002 $temp[$key] = '___'.$temp[$key]; // We add a string at begin of value to force an alpha order when using asort.
9003 }
9004 }
9005
9006 if (empty($natsort) || $natsort == -1) {
9007 if ($order == 'asc') {
9008 asort($temp);
9009 } else {
9010 arsort($temp);
9011 }
9012 } else {
9013 if ($case_sensitive) {
9014 natsort($temp);
9015 } else {
9016 natcasesort($temp); // natecasesort is not sensible to case
9017 }
9018 if ($order != 'asc') {
9019 $temp = array_reverse($temp, true);
9020 }
9021 }
9022
9023 $sorted = array();
9024
9025 foreach (array_keys($temp) as $key) {
9026 (is_numeric($key) && empty($keepindex)) ? $sorted[] = $array[$key] : $sorted[$key] = $array[$key];
9027 }
9028
9029 return $sorted;
9030 }
9031 }
9032 return $array;
9033}
9034
9035
9042function utf8_check($str)
9043{
9044 $str = (string) $str; // Sometimes string is an int.
9045
9046 // We must use here a binary strlen function (so not dol_strlen)
9047 $strLength = dol_strlen($str);
9048 for ($i = 0; $i < $strLength; $i++) {
9049 if (ord($str[$i]) < 0x80) {
9050 continue; // 0bbbbbbb
9051 } elseif ((ord($str[$i]) & 0xE0) == 0xC0) {
9052 $n = 1; // 110bbbbb
9053 } elseif ((ord($str[$i]) & 0xF0) == 0xE0) {
9054 $n = 2; // 1110bbbb
9055 } elseif ((ord($str[$i]) & 0xF8) == 0xF0) {
9056 $n = 3; // 11110bbb
9057 } elseif ((ord($str[$i]) & 0xFC) == 0xF8) {
9058 $n = 4; // 111110bb
9059 } elseif ((ord($str[$i]) & 0xFE) == 0xFC) {
9060 $n = 5; // 1111110b
9061 } else {
9062 return false; // Does not match any model
9063 }
9064 for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
9065 if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80)) {
9066 return false;
9067 }
9068 }
9069 }
9070 return true;
9071}
9072
9079function utf8_valid($str)
9080{
9081 /* 2 other methods to test if string is utf8
9082 $validUTF8 = mb_check_encoding($messagetext, 'UTF-8');
9083 $validUTF8b = ! (false === mb_detect_encoding($messagetext, 'UTF-8', true));
9084 */
9085 return preg_match('//u', $str) ? true : false;
9086}
9087
9088
9095function ascii_check($str)
9096{
9097 if (function_exists('mb_check_encoding')) {
9098 //if (mb_detect_encoding($str, 'ASCII', true) return false;
9099 if (!mb_check_encoding($str, 'ASCII')) {
9100 return false;
9101 }
9102 } else {
9103 if (preg_match('/[^\x00-\x7f]/', $str)) {
9104 return false; // Contains a byte > 7f
9105 }
9106 }
9107
9108 return true;
9109}
9110
9111
9119function dol_osencode($str)
9120{
9121 global $conf;
9122
9123 $tmp = ini_get("unicode.filesystem_encoding"); // Disponible avec PHP 6.0
9124 if (empty($tmp) && !empty($_SERVER["WINDIR"])) {
9125 $tmp = 'iso-8859-1'; // By default for windows
9126 }
9127 if (empty($tmp)) {
9128 $tmp = 'utf-8'; // By default for other
9129 }
9130 if (!empty($conf->global->MAIN_FILESYSTEM_ENCODING)) {
9131 $tmp = $conf->global->MAIN_FILESYSTEM_ENCODING;
9132 }
9133
9134 if ($tmp == 'iso-8859-1') {
9135 return mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8');
9136 }
9137 return $str;
9138}
9139
9140
9155function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '')
9156{
9157 global $cache_codes;
9158
9159 // If key empty
9160 if ($key == '') {
9161 return '';
9162 }
9163
9164 // Check in cache
9165 if (isset($cache_codes[$tablename][$key][$fieldid])) { // Can be defined to 0 or ''
9166 return $cache_codes[$tablename][$key][$fieldid]; // Found in cache
9167 }
9168
9169 dol_syslog('dol_getIdFromCode (value for field '.$fieldid.' from key '.$key.' not found into cache)', LOG_DEBUG);
9170
9171 $sql = "SELECT ".$fieldid." as valuetoget";
9172 $sql .= " FROM ".MAIN_DB_PREFIX.$tablename;
9173 $sql .= " WHERE ".$fieldkey." = '".$db->escape($key)."'";
9174 if (!empty($entityfilter)) {
9175 $sql .= " AND entity IN (".getEntity($tablename).")";
9176 }
9177 if ($filters) {
9178 $sql .= $filters;
9179 }
9180
9181 $resql = $db->query($sql);
9182 if ($resql) {
9183 $obj = $db->fetch_object($resql);
9184 if ($obj) {
9185 $cache_codes[$tablename][$key][$fieldid] = $obj->valuetoget;
9186 } else {
9187 $cache_codes[$tablename][$key][$fieldid] = '';
9188 }
9189 $db->free($resql);
9190 return $cache_codes[$tablename][$key][$fieldid];
9191 } else {
9192 return -1;
9193 }
9194}
9195
9202function verifCond($strToEvaluate)
9203{
9204 global $user, $conf, $langs;
9205 global $leftmenu;
9206 global $rights; // To export to dol_eval function
9207
9208 //print $strToEvaluate."<br>\n";
9209 $rights = true;
9210 if (isset($strToEvaluate) && $strToEvaluate !== '') {
9211 //var_dump($strToEvaluate);
9212 //$rep = dol_eval($strToEvaluate, 1, 0, '1'); // to show the error
9213 $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
9214 $rights = $rep && (!is_string($rep) || strpos($rep, 'Bad string syntax to evaluate') === false);
9215 //var_dump($rights);
9216 }
9217 return $rights;
9218}
9219
9230function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1')
9231{
9232 // Only global variables can be changed by eval function and returned to caller
9233 global $db, $langs, $user, $conf, $website, $websitepage;
9234 global $action, $mainmenu, $leftmenu;
9235 global $mysoc;
9236 global $objectoffield;
9237
9238 // Old variables used
9239 global $rights;
9240 global $object;
9241 global $obj; // To get $obj used into list when dol_eval is used for computed fields and $obj is not yet $object
9242 global $soc; // For backward compatibility
9243
9244 try {
9245 // Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing
9246 if ($onlysimplestring == '1') {
9247 // We must accept: '1 && getDolGlobalInt("doesnotexist1") && $conf->global->MAIN_FEATURES_LEVEL'
9248 // We must accept: '$conf->barcode->enabled || preg_match(\'/^AAA/\',$leftmenu)'
9249 // We must accept: '$user->rights->cabinetmed->read && !$object->canvas=="patient@cabinetmed"'
9250 if (preg_match('/[^a-z0-9\s'.preg_quote('^$_+-.*>&|=!?():"\',/@', '/').']/i', $s)) {
9251 if ($returnvalue) {
9252 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9253 } else {
9254 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9255 return '';
9256 }
9257 // TODO
9258 // We can exclude all parenthesis ( that are not '($db' and 'getDolGlobalInt(' and 'getDolGlobalString(' and 'preg_match(' and 'isModEnabled('
9259 // ...
9260 }
9261 } elseif ($onlysimplestring == '2') {
9262 // 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"
9263 if (preg_match('/[^a-z0-9\s'.preg_quote('^$_+-.*>&|=!?():"\',/@[]', '/').']/i', $s)) {
9264 if ($returnvalue) {
9265 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9266 } else {
9267 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9268 return '';
9269 }
9270 // TODO
9271 // We can exclude all parenthesis ( that are not '($db' and 'getDolGlobalInt(' and 'getDolGlobalString(' and 'preg_match(' and 'isModEnabled('
9272 // ...
9273 }
9274 }
9275 if (is_array($s) || $s === 'Array') {
9276 return 'Bad string syntax to evaluate (value is Array) '.var_export($s, true);
9277 }
9278 if (strpos($s, '::') !== false) {
9279 if ($returnvalue) {
9280 return 'Bad string syntax to evaluate (double : char is forbidden): '.$s;
9281 } else {
9282 dol_syslog('Bad string syntax to evaluate (double : char is forbidden): '.$s);
9283 return '';
9284 }
9285 }
9286 if (strpos($s, '`') !== false) {
9287 if ($returnvalue) {
9288 return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
9289 } else {
9290 dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s);
9291 return '';
9292 }
9293 }
9294 if (preg_match('/[^0-9]+\.[^0-9]+/', $s)) { // We refuse . if not between 2 numbers
9295 if ($returnvalue) {
9296 return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
9297 } else {
9298 dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s);
9299 return '';
9300 }
9301 }
9302
9303 // We block use of php exec or php file functions
9304 $forbiddenphpstrings = array('$$');
9305 $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
9306
9307 $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen");
9308 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
9309 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64_decode", "rawurldecode", "urldecode", "str_rot13", "hex2bin")); // decode string functions used to obfuscated function name
9310 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
9311 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
9312 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));
9313 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
9314 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
9315
9316 $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
9317
9318 $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
9319
9320 $forbiddenphpmethodsregex = '->('.implode('|', $forbiddenphpmethods).')';
9321
9322 do {
9323 $oldstringtoclean = $s;
9324 $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);
9325 $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);
9326 $s = preg_replace('/'.$forbiddenphpmethodsregex.'/i', '__forbiddenstring__', $s);
9327 //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\‍(/i', '', $s); // Remove $function( call and $mycall->mymethod(
9328 } while ($oldstringtoclean != $s);
9329
9330 if (strpos($s, '__forbiddenstring__') !== false) {
9331 dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
9332 if ($returnvalue) {
9333 return 'Bad string syntax to evaluate: '.$s;
9334 } else {
9335 dol_syslog('Bad string syntax to evaluate: '.$s);
9336 return '';
9337 }
9338 }
9339
9340 //print $s."<br>\n";
9341 if ($returnvalue) {
9342 if ($hideerrors) {
9343 return @eval('return '.$s.';');
9344 } else {
9345 return eval('return '.$s.';');
9346 }
9347 } else {
9348 if ($hideerrors) {
9349 @eval($s);
9350 } else {
9351 eval($s);
9352 }
9353 }
9354 } catch (Error $e) {
9355 $error = 'dol_eval try/catch error : ';
9356 $error .= $e->getMessage();
9357 dol_syslog($error);
9358 }
9359}
9360
9367function dol_validElement($element)
9368{
9369 return (trim($element) != '');
9370}
9371
9380function picto_from_langcode($codelang, $moreatt = '', $notitlealt = 0)
9381{
9382 if (empty($codelang)) {
9383 return '';
9384 }
9385
9386 if ($codelang == 'auto') {
9387 return '<span class="fa fa-language"></span>';
9388 }
9389
9390 $langtocountryflag = array(
9391 'ar_AR' => '',
9392 'ca_ES' => 'catalonia',
9393 'da_DA' => 'dk',
9394 'fr_CA' => 'mq',
9395 'sv_SV' => 'se',
9396 'sw_SW' => 'unknown',
9397 'AQ' => 'unknown',
9398 'CW' => 'unknown',
9399 'IM' => 'unknown',
9400 'JE' => 'unknown',
9401 'MF' => 'unknown',
9402 'BL' => 'unknown',
9403 'SX' => 'unknown'
9404 );
9405
9406 if (isset($langtocountryflag[$codelang])) {
9407 $flagImage = $langtocountryflag[$codelang];
9408 } else {
9409 $tmparray = explode('_', $codelang);
9410 $flagImage = empty($tmparray[1]) ? $tmparray[0] : $tmparray[1];
9411 }
9412
9413 return img_picto_common($codelang, 'flags/'.strtolower($flagImage).'.png', $moreatt, 0, $notitlealt);
9414}
9415
9424{
9425 global $mysoc;
9426
9427 if (empty($countrycode)) {
9428 return null;
9429 }
9430
9431 if (strtoupper($countrycode) == 'MQ') {
9432 return 'fr_CA';
9433 }
9434 if (strtoupper($countrycode) == 'SE') {
9435 return 'sv_SE'; // se_SE is Sami/Sweden, and we want in priority sv_SE for SE country
9436 }
9437 if (strtoupper($countrycode) == 'CH') {
9438 if ($mysoc->country_code == 'FR') {
9439 return 'fr_CH';
9440 }
9441 if ($mysoc->country_code == 'DE') {
9442 return 'de_CH';
9443 }
9444 if ($mysoc->country_code == 'IT') {
9445 return 'it_CH';
9446 }
9447 }
9448
9449 // Locale list taken from:
9450 // http://stackoverflow.com/questions/3191664/
9451 // list-of-all-locales-and-their-short-codes
9452 $locales = array(
9453 'af-ZA',
9454 'am-ET',
9455 'ar-AE',
9456 'ar-BH',
9457 'ar-DZ',
9458 'ar-EG',
9459 'ar-IQ',
9460 'ar-JO',
9461 'ar-KW',
9462 'ar-LB',
9463 'ar-LY',
9464 'ar-MA',
9465 'ar-OM',
9466 'ar-QA',
9467 'ar-SA',
9468 'ar-SY',
9469 'ar-TN',
9470 'ar-YE',
9471 //'as-IN', // Moved after en-IN
9472 'ba-RU',
9473 'be-BY',
9474 'bg-BG',
9475 'bn-BD',
9476 //'bn-IN', // Moved after en-IN
9477 'bo-CN',
9478 'br-FR',
9479 'ca-ES',
9480 'co-FR',
9481 'cs-CZ',
9482 'cy-GB',
9483 'da-DK',
9484 'de-AT',
9485 'de-CH',
9486 'de-DE',
9487 'de-LI',
9488 'de-LU',
9489 'dv-MV',
9490 'el-GR',
9491 'en-AU',
9492 'en-BZ',
9493 'en-CA',
9494 'en-GB',
9495 'en-IE',
9496 'en-IN',
9497 'as-IN', // as-IN must be after en-IN (en in priority if country is IN)
9498 'bn-IN', // bn-IN must be after en-IN (en in priority if country is IN)
9499 'en-JM',
9500 'en-MY',
9501 'en-NZ',
9502 'en-PH',
9503 'en-SG',
9504 'en-TT',
9505 'en-US',
9506 'en-ZA',
9507 'en-ZW',
9508 'es-AR',
9509 'es-BO',
9510 'es-CL',
9511 'es-CO',
9512 'es-CR',
9513 'es-DO',
9514 'es-EC',
9515 'es-ES',
9516 'es-GT',
9517 'es-HN',
9518 'es-MX',
9519 'es-NI',
9520 'es-PA',
9521 'es-PE',
9522 'es-PR',
9523 'es-PY',
9524 'es-SV',
9525 'es-US',
9526 'es-UY',
9527 'es-VE',
9528 'et-EE',
9529 'eu-ES',
9530 'fa-IR',
9531 'fi-FI',
9532 'fo-FO',
9533 'fr-BE',
9534 'fr-CA',
9535 'fr-CH',
9536 'fr-FR',
9537 'fr-LU',
9538 'fr-MC',
9539 'fy-NL',
9540 'ga-IE',
9541 'gd-GB',
9542 'gl-ES',
9543 'gu-IN',
9544 'he-IL',
9545 'hi-IN',
9546 'hr-BA',
9547 'hr-HR',
9548 'hu-HU',
9549 'hy-AM',
9550 'id-ID',
9551 'ig-NG',
9552 'ii-CN',
9553 'is-IS',
9554 'it-CH',
9555 'it-IT',
9556 'ja-JP',
9557 'ka-GE',
9558 'kk-KZ',
9559 'kl-GL',
9560 'km-KH',
9561 'kn-IN',
9562 'ko-KR',
9563 'ky-KG',
9564 'lb-LU',
9565 'lo-LA',
9566 'lt-LT',
9567 'lv-LV',
9568 'mi-NZ',
9569 'mk-MK',
9570 'ml-IN',
9571 'mn-MN',
9572 'mr-IN',
9573 'ms-BN',
9574 'ms-MY',
9575 'mt-MT',
9576 'nb-NO',
9577 'ne-NP',
9578 'nl-BE',
9579 'nl-NL',
9580 'nn-NO',
9581 'oc-FR',
9582 'or-IN',
9583 'pa-IN',
9584 'pl-PL',
9585 'ps-AF',
9586 'pt-BR',
9587 'pt-PT',
9588 'rm-CH',
9589 'ro-MD',
9590 'ro-RO',
9591 'ru-RU',
9592 'rw-RW',
9593 'sa-IN',
9594 'se-FI',
9595 'se-NO',
9596 'se-SE',
9597 'si-LK',
9598 'sk-SK',
9599 'sl-SI',
9600 'sq-AL',
9601 'sv-FI',
9602 'sv-SE',
9603 'sw-KE',
9604 'ta-IN',
9605 'te-IN',
9606 'th-TH',
9607 'tk-TM',
9608 'tn-ZA',
9609 'tr-TR',
9610 'tt-RU',
9611 'ug-CN',
9612 'uk-UA',
9613 'ur-PK',
9614 'vi-VN',
9615 'wo-SN',
9616 'xh-ZA',
9617 'yo-NG',
9618 'zh-CN',
9619 'zh-HK',
9620 'zh-MO',
9621 'zh-SG',
9622 'zh-TW',
9623 'zu-ZA',
9624 );
9625
9626 $buildprimarykeytotest = strtolower($countrycode).'-'.strtoupper($countrycode);
9627 if (in_array($buildprimarykeytotest, $locales)) {
9628 return strtolower($countrycode).'_'.strtoupper($countrycode);
9629 }
9630
9631 if (function_exists('locale_get_primary_language') && function_exists('locale_get_region')) { // Need extension php-intl
9632 foreach ($locales as $locale) {
9633 $locale_language = locale_get_primary_language($locale);
9634 $locale_region = locale_get_region($locale);
9635 if (strtoupper($countrycode) == $locale_region) {
9636 //var_dump($locale.' - '.$locale_language.' - '.$locale_region);
9637 return strtolower($locale_language).'_'.strtoupper($locale_region);
9638 }
9639 }
9640 } else {
9641 dol_syslog("Warning Exention php-intl is not available", LOG_WARNING);
9642 }
9643
9644 return null;
9645}
9646
9677function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode = 'add', $filterorigmodule = '')
9678{
9679 global $hookmanager, $db;
9680
9681 if (isset($conf->modules_parts['tabs'][$type]) && is_array($conf->modules_parts['tabs'][$type])) {
9682 foreach ($conf->modules_parts['tabs'][$type] as $value) {
9683 $values = explode(':', $value);
9684
9685 $reg = array();
9686 if ($mode == 'add' && !preg_match('/^\-/', $values[1])) {
9687 if (count($values) == 6) {
9688 // new declaration with permissions:
9689 // $value='objecttype:+tabname1:Title1:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
9690 // $value='objecttype:+tabname1:Title1,class,pathfile,method:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
9691 if ($values[0] != $type) {
9692 continue;
9693 }
9694
9695 if (verifCond($values[4])) {
9696 if ($values[3]) {
9697 if ($filterorigmodule) { // If a filter of module origin has been requested
9698 if (strpos($values[3], '@')) { // This is an external module
9699 if ($filterorigmodule != 'external') {
9700 continue;
9701 }
9702 } else { // This looks a core module
9703 if ($filterorigmodule != 'core') {
9704 continue;
9705 }
9706 }
9707 }
9708 $langs->load($values[3]);
9709 }
9710 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
9711 // If label is "SUBSTITUION_..."
9712 $substitutionarray = array();
9713 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
9714 $label = make_substitutions($reg[1], $substitutionarray);
9715 } else {
9716 // If label is "Label,Class,File,Method", we call the method to show content inside the badge
9717 $labeltemp = explode(',', $values[2]);
9718 $label = $langs->trans($labeltemp[0]);
9719
9720 if (!empty($labeltemp[1]) && is_object($object) && !empty($object->id)) {
9721 dol_include_once($labeltemp[2]);
9722 $classtoload = $labeltemp[1];
9723 if (class_exists($classtoload)) {
9724 $obj = new $classtoload($db);
9725 $function = $labeltemp[3];
9726 if ($obj && $function && method_exists($obj, $function)) {
9727 $nbrec = $obj->$function($object->id, $obj);
9728 if (!empty($nbrec)) {
9729 $label .= '<span class="badge marginleftonlyshort">'.$nbrec.'</span>';
9730 }
9731 }
9732 }
9733 }
9734 }
9735
9736 $head[$h][0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[5]), 1);
9737 $head[$h][1] = $label;
9738 $head[$h][2] = str_replace('+', '', $values[1]);
9739 $h++;
9740 }
9741 } elseif (count($values) == 5) { // case deprecated
9742 dol_syslog('Passing 5 values in tabs module_parts is deprecated. Please update to 6 with permissions.', LOG_WARNING);
9743
9744 if ($values[0] != $type) {
9745 continue;
9746 }
9747 if ($values[3]) {
9748 if ($filterorigmodule) { // If a filter of module origin has been requested
9749 if (strpos($values[3], '@')) { // This is an external module
9750 if ($filterorigmodule != 'external') {
9751 continue;
9752 }
9753 } else { // This looks a core module
9754 if ($filterorigmodule != 'core') {
9755 continue;
9756 }
9757 }
9758 }
9759 $langs->load($values[3]);
9760 }
9761 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
9762 $substitutionarray = array();
9763 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
9764 $label = make_substitutions($reg[1], $substitutionarray);
9765 } else {
9766 $label = $langs->trans($values[2]);
9767 }
9768
9769 $head[$h][0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[4]), 1);
9770 $head[$h][1] = $label;
9771 $head[$h][2] = str_replace('+', '', $values[1]);
9772 $h++;
9773 }
9774 } elseif ($mode == 'remove' && preg_match('/^\-/', $values[1])) {
9775 if ($values[0] != $type) {
9776 continue;
9777 }
9778 $tabname = str_replace('-', '', $values[1]);
9779 foreach ($head as $key => $val) {
9780 $condition = (!empty($values[3]) ? verifCond($values[3]) : 1);
9781 //var_dump($key.' - '.$tabname.' - '.$head[$key][2].' - '.$values[3].' - '.$condition);
9782 if ($head[$key][2] == $tabname && $condition) {
9783 unset($head[$key]);
9784 break;
9785 }
9786 }
9787 }
9788 }
9789 }
9790
9791 // No need to make a return $head. Var is modified as a reference
9792 if (!empty($hookmanager)) {
9793 $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule);
9794 $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters);
9795 if ($reshook > 0) { // Hook ask to replace completely the array
9796 $head = $hookmanager->resArray;
9797 } else { // Hook
9798 $head = array_merge($head, $hookmanager->resArray);
9799 }
9800 $h = count($head);
9801 }
9802}
9803
9815function printCommonFooter($zone = 'private')
9816{
9817 global $conf, $hookmanager, $user, $debugbar;
9818 global $action;
9819 global $micro_start_time;
9820
9821 if ($zone == 'private') {
9822 print "\n".'<!-- Common footer for private page -->'."\n";
9823 } else {
9824 print "\n".'<!-- Common footer for public page -->'."\n";
9825 }
9826
9827 // A div to store page_y POST parameter so we can read it using javascript
9828 print "\n<!-- A div to store page_y POST parameter -->\n";
9829 print '<div id="page_y" style="display: none;">'.(GETPOST('page_y') ? GETPOST('page_y') : '').'</div>'."\n";
9830
9831 $parameters = array();
9832 $reshook = $hookmanager->executeHooks('printCommonFooter', $parameters); // Note that $action and $object may have been modified by some hooks
9833 if (empty($reshook)) {
9834 if (!empty($conf->global->MAIN_HTML_FOOTER)) {
9835 print $conf->global->MAIN_HTML_FOOTER."\n";
9836 }
9837
9838 print "\n";
9839 if (!empty($conf->use_javascript_ajax)) {
9840 print "\n<!-- A script section to add menuhider handler on backoffice, manage focus and madatory fields, tuning info, ... -->\n";
9841 print '<script>'."\n";
9842 print 'jQuery(document).ready(function() {'."\n";
9843
9844 if ($zone == 'private' && empty($conf->dol_use_jmobile)) {
9845 print "\n";
9846 print '/* JS CODE TO ENABLE to manage handler to switch left menu page (menuhider) */'."\n";
9847 print 'jQuery("li.menuhider").click(function(event) {';
9848 print ' if (!$( "body" ).hasClass( "sidebar-collapse" )){ event.preventDefault(); }'."\n";
9849 print ' console.log("We click on .menuhider");'."\n";
9850 print ' $("body").toggleClass("sidebar-collapse")'."\n";
9851 print '});'."\n";
9852 }
9853
9854 // Management of focus and mandatory for fields
9855 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"])))) {
9856 print '/* JS CODE TO ENABLE to manage focus and mandatory form fields */'."\n";
9857 $relativepathstring = $_SERVER["PHP_SELF"];
9858 // Clean $relativepathstring
9859 if (constant('DOL_URL_ROOT')) {
9860 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
9861 }
9862 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
9863 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
9864 //$tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
9865 if (!empty($user->default_values[$relativepathstring]['focus'])) {
9866 foreach ($user->default_values[$relativepathstring]['focus'] as $defkey => $defval) {
9867 $qualified = 0;
9868 if ($defkey != '_noquery_') {
9869 $tmpqueryarraytohave = explode('&', $defkey);
9870 $foundintru = 0;
9871 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
9872 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
9873 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
9874 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
9875 $foundintru = 1;
9876 }
9877 }
9878 if (!$foundintru) {
9879 $qualified = 1;
9880 }
9881 //var_dump($defkey.'-'.$qualified);
9882 } else {
9883 $qualified = 1;
9884 }
9885
9886 if ($qualified) {
9887 foreach ($defval as $paramkey => $paramval) {
9888 // Set focus on field
9889 print 'jQuery("input[name=\''.$paramkey.'\']").focus();'."\n";
9890 print 'jQuery("textarea[name=\''.$paramkey.'\']").focus();'."\n";
9891 print 'jQuery("select[name=\''.$paramkey.'\']").focus();'."\n"; // Not really usefull, but we keep it in case of.
9892 }
9893 }
9894 }
9895 }
9896 if (!empty($user->default_values[$relativepathstring]['mandatory'])) {
9897 foreach ($user->default_values[$relativepathstring]['mandatory'] as $defkey => $defval) {
9898 $qualified = 0;
9899 if ($defkey != '_noquery_') {
9900 $tmpqueryarraytohave = explode('&', $defkey);
9901 $foundintru = 0;
9902 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
9903 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
9904 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
9905 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
9906 $foundintru = 1;
9907 }
9908 }
9909 if (!$foundintru) {
9910 $qualified = 1;
9911 }
9912 //var_dump($defkey.'-'.$qualified);
9913 } else {
9914 $qualified = 1;
9915 }
9916
9917 if ($qualified) {
9918 foreach ($defval as $paramkey => $paramval) {
9919 // Add property 'required' on input
9920 print 'jQuery("input[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
9921 print 'jQuery("textarea[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
9922 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";
9923 print 'jQuery("select[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
9924 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'-1\']").prop(\'value\', \'\');'."\n";
9925 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'0\']").prop(\'value\', \'\');'."\n";
9926
9927 // Add 'field required' class on closest td for all input elements : input, textarea and select
9928 print 'jQuery(":input[name=\'' . $paramkey . '\']").closest("tr").find("td:first").addClass("fieldrequired");' . "\n";
9929 }
9930 }
9931 }
9932 }
9933 }
9934
9935 print '});'."\n";
9936
9937 // End of tuning
9938 if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO']) || !empty($conf->global->MAIN_SHOW_TUNING_INFO)) {
9939 print "\n";
9940 print "/* JS CODE TO ENABLE to add memory info */\n";
9941 print 'window.console && console.log("';
9942 if (!empty($conf->global->MEMCACHED_SERVER)) {
9943 print 'MEMCACHED_SERVER='.$conf->global->MEMCACHED_SERVER.' - ';
9944 }
9945 print 'MAIN_OPTIMIZE_SPEED='.(isset($conf->global->MAIN_OPTIMIZE_SPEED) ? $conf->global->MAIN_OPTIMIZE_SPEED : 'off');
9946 if (!empty($micro_start_time)) { // Works only if MAIN_SHOW_TUNING_INFO is defined at $_SERVER level. Not in global variable.
9947 $micro_end_time = microtime(true);
9948 print ' - Build time: '.ceil(1000 * ($micro_end_time - $micro_start_time)).' ms';
9949 }
9950
9951 if (function_exists("memory_get_usage")) {
9952 print ' - Mem: '.memory_get_usage(); // Do not use true here, it seems it takes the peak amount
9953 }
9954 if (function_exists("memory_get_peak_usage")) {
9955 print ' - Real mem peak: '.memory_get_peak_usage(true);
9956 }
9957 if (function_exists("zend_loader_file_encoded")) {
9958 print ' - Zend encoded file: '.(zend_loader_file_encoded() ? 'yes' : 'no');
9959 }
9960 print '");'."\n";
9961 }
9962
9963 print "\n".'</script>'."\n";
9964
9965 // Google Analytics
9966 // TODO Add a hook here
9967 if (isModEnabled('google') && !empty($conf->global->MAIN_GOOGLE_AN_ID)) {
9968 $tmptagarray = explode(',', $conf->global->MAIN_GOOGLE_AN_ID);
9969 foreach ($tmptagarray as $tmptag) {
9970 print "\n";
9971 print "<!-- JS CODE TO ENABLE for google analtics tag -->\n";
9972 print '
9973 <!-- Global site tag (gtag.js) - Google Analytics -->
9974 <script nonce="'.getNonce().'" async src="https://www.googletagmanager.com/gtag/js?id='.trim($tmptag).'"></script>
9975 <script>
9976 window.dataLayer = window.dataLayer || [];
9977 function gtag(){dataLayer.push(arguments);}
9978 gtag(\'js\', new Date());
9979
9980 gtag(\'config\', \''.trim($tmptag).'\');
9981 </script>';
9982 print "\n";
9983 }
9984 }
9985 }
9986
9987 // Add Xdebug coverage of code
9988 if (defined('XDEBUGCOVERAGE')) {
9989 print_r(xdebug_get_code_coverage());
9990 }
9991
9992 // Add DebugBar data
9993 if (!empty($user->rights->debugbar->read) && is_object($debugbar)) {
9994 $debugbar['time']->stopMeasure('pageaftermaster');
9995 print '<!-- Output debugbar data -->'."\n";
9996 $renderer = $debugbar->getRenderer();
9997 print $debugbar->getRenderer()->render();
9998 } elseif (count($conf->logbuffer)) { // If there is some logs in buffer to show
9999 print "\n";
10000 print "<!-- Start of log output\n";
10001 //print '<div class="hidden">'."\n";
10002 foreach ($conf->logbuffer as $logline) {
10003 print $logline."<br>\n";
10004 }
10005 //print '</div>'."\n";
10006 print "End of log output -->\n";
10007 }
10008 }
10009}
10010
10020function dolExplodeIntoArray($string, $delimiter = ';', $kv = '=')
10021{
10022 if (is_null($string)) {
10023 return array();
10024 }
10025
10026 if (preg_match('/^\[.*\]$/sm', $delimiter) || preg_match('/^\‍(.*\‍)$/sm', $delimiter)) {
10027 // This is a regex string
10028 $newdelimiter = $delimiter;
10029 } else {
10030 // This is a simple string
10031 $newdelimiter = preg_quote($delimiter, '/');
10032 }
10033
10034 if ($a = preg_split('/'.$newdelimiter.'/', $string)) {
10035 $ka = array();
10036 foreach ($a as $s) { // each part
10037 if ($s) {
10038 if ($pos = strpos($s, $kv)) { // key/value delimiter
10039 $ka[trim(substr($s, 0, $pos))] = trim(substr($s, $pos + strlen($kv)));
10040 } else { // key delimiter not found
10041 $ka[] = trim($s);
10042 }
10043 }
10044 }
10045 return $ka;
10046 }
10047
10048 return array();
10049}
10050
10051
10058function dol_set_focus($selector)
10059{
10060 print "\n".'<!-- Set focus onto a specific field -->'."\n";
10061 print '<script nonce="'.getNonce().'">jQuery(document).ready(function() { jQuery("'.dol_escape_js($selector).'").focus(); });</script>'."\n";
10062}
10063
10064
10072function dol_getmypid()
10073{
10074 if (!function_exists('getmypid')) {
10075 return mt_rand(99900000, 99965535);
10076 } else {
10077 return getmypid(); // May be a number on 64 bits (depending on OS)
10078 }
10079}
10080
10081
10099function natural_search($fields, $value, $mode = 0, $nofirstand = 0)
10100{
10101 global $db, $langs;
10102
10103 $value = trim($value);
10104
10105 if ($mode == 0) {
10106 $value = preg_replace('/\*/', '%', $value); // Replace * with %
10107 }
10108 if ($mode == 1) {
10109 $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
10110 }
10111
10112 $value = preg_replace('/\s*\|\s*/', '|', $value);
10113
10114 $crits = explode(' ', $value);
10115 $res = '';
10116 if (!is_array($fields)) {
10117 $fields = array($fields);
10118 }
10119
10120 $i1 = 0; // count the nb of and criteria added (all fields / criterias)
10121 foreach ($crits as $crit) { // Loop on each AND criteria
10122 $crit = trim($crit);
10123 $i2 = 0; // count the nb of valid criteria added for this this first criteria
10124 $newres = '';
10125 foreach ($fields as $field) {
10126 if ($mode == 1) {
10127 $tmpcrits = explode('|', $crit);
10128 $i3 = 0; // count the nb of valid criteria added for this current field
10129 foreach ($tmpcrits as $tmpcrit) {
10130 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10131 continue;
10132 }
10133 $tmpcrit = trim($tmpcrit);
10134
10135 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10136
10137 $operator = '=';
10138 $newcrit = preg_replace('/([!<>=]+)/', '', $tmpcrit);
10139
10140 $reg = array();
10141 preg_match('/([!<>=]+)/', $tmpcrit, $reg);
10142 if (!empty($reg[1])) {
10143 $operator = $reg[1];
10144 }
10145 if ($newcrit != '') {
10146 $numnewcrit = price2num($newcrit);
10147 if (is_numeric($numnewcrit)) {
10148 $newres .= $field.' '.$operator.' '.((float) $numnewcrit); // should be a numeric
10149 } else {
10150 $newres .= '1 = 2'; // force false, we received a corrupted data
10151 }
10152 $i3++; // a criteria was added to string
10153 }
10154 }
10155 $i2++; // a criteria for 1 more field was added to string
10156 } elseif ($mode == 2 || $mode == -2) {
10157 $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer
10158 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -2 ? 'NOT ' : '');
10159 $newres .= $crit ? "IN (".$db->sanitize($db->escape($crit)).")" : "IN (0)";
10160 if ($mode == -2) {
10161 $newres .= ' OR '.$field.' IS NULL';
10162 }
10163 $i2++; // a criteria for 1 more field was added to string
10164 } elseif ($mode == 3 || $mode == -3) {
10165 $tmparray = explode(',', $crit);
10166 if (count($tmparray)) {
10167 $listofcodes = '';
10168 foreach ($tmparray as $val) {
10169 $val = trim($val);
10170 if ($val) {
10171 $listofcodes .= ($listofcodes ? ',' : '');
10172 $listofcodes .= "'".$db->escape($val)."'";
10173 }
10174 }
10175 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -3 ? 'NOT ' : '')."IN (".$db->sanitize($listofcodes, 1).")";
10176 $i2++; // a criteria for 1 more field was added to string
10177 }
10178 if ($mode == -3) {
10179 $newres .= ' OR '.$field.' IS NULL';
10180 }
10181 } elseif ($mode == 4) {
10182 $tmparray = explode(',', $crit);
10183 if (count($tmparray)) {
10184 $listofcodes = '';
10185 foreach ($tmparray as $val) {
10186 $val = trim($val);
10187 if ($val) {
10188 $newres .= ($i2 > 0 ? " OR (" : "(").$field." LIKE '".$db->escape($val).",%'";
10189 $newres .= ' OR '.$field." = '".$db->escape($val)."'";
10190 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val)."'";
10191 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val).",%'";
10192 $newres .= ')';
10193 $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)
10194 }
10195 }
10196 }
10197 } else { // $mode=0
10198 $tmpcrits = explode('|', $crit);
10199 $i3 = 0; // count the nb of valid criteria added for the current couple criteria/field
10200 foreach ($tmpcrits as $tmpcrit) { // loop on each OR criteria
10201 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10202 continue;
10203 }
10204 $tmpcrit = trim($tmpcrit);
10205
10206 if ($tmpcrit == '^$' || strpos($crit, '!') === 0) { // If we search empty, we must combined different OR fields with AND
10207 $newres .= (($i2 > 0 || $i3 > 0) ? ' AND ' : '');
10208 } else {
10209 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10210 }
10211
10212 if (preg_match('/\.(id|rowid)$/', $field)) { // Special case for rowid that is sometimes a ref so used as a search field
10213 $newres .= $field." = ".(is_numeric($tmpcrit) ? ((float) $tmpcrit) : '0');
10214 } else {
10215 $tmpcrit2 = $tmpcrit;
10216 $tmpbefore = '%';
10217 $tmpafter = '%';
10218 $tmps = '';
10219
10220 if (preg_match('/^!/', $tmpcrit)) {
10221 $tmps .= $field." NOT LIKE "; // ! as exclude character
10222 $tmpcrit2 = preg_replace('/^!/', '', $tmpcrit2);
10223 } else {
10224 $tmps .= $field." LIKE ";
10225 }
10226 $tmps .= "'";
10227
10228 if (preg_match('/^[\^\$]/', $tmpcrit)) {
10229 $tmpbefore = '';
10230 $tmpcrit2 = preg_replace('/^[\^\$]/', '', $tmpcrit2);
10231 }
10232 if (preg_match('/[\^\$]$/', $tmpcrit)) {
10233 $tmpafter = '';
10234 $tmpcrit2 = preg_replace('/[\^\$]$/', '', $tmpcrit2);
10235 }
10236
10237 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10238 $tmps = "(".$tmps;
10239 }
10240 $newres .= $tmps;
10241 $newres .= $tmpbefore;
10242 $newres .= $db->escape($tmpcrit2);
10243 $newres .= $tmpafter;
10244 $newres .= "'";
10245 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10246 $newres .= " OR ".$field." IS NULL)";
10247 }
10248 }
10249
10250 $i3++;
10251 }
10252
10253 $i2++; // a criteria for 1 more field was added to string
10254 }
10255 }
10256
10257 if ($newres) {
10258 $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : '');
10259 }
10260 $i1++;
10261 }
10262 $res = ($nofirstand ? "" : " AND ")."(".$res.")";
10263
10264 return $res;
10265}
10266
10273function showDirectDownloadLink($object)
10274{
10275 global $conf, $langs;
10276
10277 $out = '';
10278 $url = $object->getLastMainDocLink($object->element);
10279
10280 $out .= img_picto($langs->trans("PublicDownloadLinkDesc"), 'globe').' <span class="opacitymedium">'.$langs->trans("DirectDownloadLink").'</span><br>';
10281 if ($url) {
10282 $out .= '<div class="urllink"><input type="text" id="directdownloadlink" class="quatrevingtpercent" value="'.$url.'"></div>';
10283 $out .= ajax_autoselect("directdownloadlink", 0);
10284 } else {
10285 $out .= '<div class="urllink">'.$langs->trans("FileNotShared").'</div>';
10286 }
10287
10288 return $out;
10289}
10290
10299function getImageFileNameForSize($file, $extName, $extImgTarget = '')
10300{
10301 $dirName = dirname($file);
10302 if ($dirName == '.') {
10303 $dirName = '';
10304 }
10305
10306 $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.webp)$/i', '', $file); // We remove extension, whatever is its case
10307 $fileName = basename($fileName);
10308
10309 if (empty($extImgTarget)) {
10310 $extImgTarget = (preg_match('/\.jpg$/i', $file) ? '.jpg' : '');
10311 }
10312 if (empty($extImgTarget)) {
10313 $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '');
10314 }
10315 if (empty($extImgTarget)) {
10316 $extImgTarget = (preg_match('/\.gif$/i', $file) ? '.gif' : '');
10317 }
10318 if (empty($extImgTarget)) {
10319 $extImgTarget = (preg_match('/\.png$/i', $file) ? '.png' : '');
10320 }
10321 if (empty($extImgTarget)) {
10322 $extImgTarget = (preg_match('/\.bmp$/i', $file) ? '.bmp' : '');
10323 }
10324 if (empty($extImgTarget)) {
10325 $extImgTarget = (preg_match('/\.webp$/i', $file) ? '.webp' : '');
10326 }
10327
10328 if (!$extImgTarget) {
10329 return $file;
10330 }
10331
10332 $subdir = '';
10333 if ($extName) {
10334 $subdir = 'thumbs/';
10335 }
10336
10337 return ($dirName ? $dirName.'/' : '').$subdir.$fileName.$extName.$extImgTarget; // New filename for thumb
10338}
10339
10340
10350function getAdvancedPreviewUrl($modulepart, $relativepath, $alldata = 0, $param = '')
10351{
10352 global $conf, $langs;
10353
10354 if (empty($conf->use_javascript_ajax)) {
10355 return '';
10356 }
10357
10358 $isAllowedForPreview = dolIsAllowedForPreview($relativepath);
10359
10360 if ($alldata == 1) {
10361 if ($isAllowedForPreview) {
10362 return array('target'=>'_blank', 'css'=>'documentpreview', 'url'=>DOL_URL_ROOT.'/document.php?modulepart='.$modulepart.'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : ''), 'mime'=>dol_mimetype($relativepath));
10363 } else {
10364 return array();
10365 }
10366 }
10367
10368 // old behavior, return a string
10369 if ($isAllowedForPreview) {
10370 return 'javascript:document_preview(\''.dol_escape_js(DOL_URL_ROOT.'/document.php?modulepart='.$modulepart.'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : '')).'\', \''.dol_mimetype($relativepath).'\', \''.dol_escape_js($langs->trans('Preview')).'\')';
10371 } else {
10372 return '';
10373 }
10374}
10375
10376
10385function ajax_autoselect($htmlname, $addlink = '', $textonlink = 'Link')
10386{
10387 global $langs;
10388 $out = '<script nonce="'.getNonce().'">
10389 jQuery(document).ready(function () {
10390 jQuery("'.((strpos($htmlname, '.') === 0 ? '' : '#').$htmlname).'").click(function() { jQuery(this).select(); } );
10391 });
10392 </script>';
10393 if ($addlink) {
10394 if ($textonlink === 'image') {
10395 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.img_picto('', 'globe').'</a>';
10396 } else {
10397 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.$langs->trans("Link").'</a>';
10398 }
10399 }
10400 return $out;
10401}
10402
10411{
10412 global $conf;
10413
10414 // Check .noexe extension in filename
10415 if (preg_match('/\.noexe$/i', $file)) {
10416 return 0;
10417 }
10418
10419 // Check mime types
10420 $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'webp');
10421 if (!empty($conf->global->MAIN_ALLOW_SVG_FILES_AS_IMAGES)) {
10422 $mime_preview[] = 'svg+xml';
10423 }
10424 //$mime_preview[]='vnd.oasis.opendocument.presentation';
10425 //$mime_preview[]='archive';
10426 $num_mime = array_search(dol_mimetype($file, '', 1), $mime_preview);
10427 if ($num_mime !== false) {
10428 return 1;
10429 }
10430
10431 // By default, not allowed for preview
10432 return 0;
10433}
10434
10435
10445function dol_mimetype($file, $default = 'application/octet-stream', $mode = 0)
10446{
10447 $mime = $default;
10448 $imgmime = 'other.png';
10449 $famime = 'file-o';
10450 $srclang = '';
10451
10452 $tmpfile = preg_replace('/\.noexe$/', '', $file);
10453
10454 // Plain text files
10455 if (preg_match('/\.txt$/i', $tmpfile)) {
10456 $mime = 'text/plain';
10457 $imgmime = 'text.png';
10458 $famime = 'file-text-o';
10459 }
10460 if (preg_match('/\.rtx$/i', $tmpfile)) {
10461 $mime = 'text/richtext';
10462 $imgmime = 'text.png';
10463 $famime = 'file-text-o';
10464 }
10465 if (preg_match('/\.csv$/i', $tmpfile)) {
10466 $mime = 'text/csv';
10467 $imgmime = 'text.png';
10468 $famime = 'file-text-o';
10469 }
10470 if (preg_match('/\.tsv$/i', $tmpfile)) {
10471 $mime = 'text/tab-separated-values';
10472 $imgmime = 'text.png';
10473 $famime = 'file-text-o';
10474 }
10475 if (preg_match('/\.(cf|conf|log)$/i', $tmpfile)) {
10476 $mime = 'text/plain';
10477 $imgmime = 'text.png';
10478 $famime = 'file-text-o';
10479 }
10480 if (preg_match('/\.ini$/i', $tmpfile)) {
10481 $mime = 'text/plain';
10482 $imgmime = 'text.png';
10483 $srclang = 'ini';
10484 $famime = 'file-text-o';
10485 }
10486 if (preg_match('/\.md$/i', $tmpfile)) {
10487 $mime = 'text/plain';
10488 $imgmime = 'text.png';
10489 $srclang = 'md';
10490 $famime = 'file-text-o';
10491 }
10492 if (preg_match('/\.css$/i', $tmpfile)) {
10493 $mime = 'text/css';
10494 $imgmime = 'css.png';
10495 $srclang = 'css';
10496 $famime = 'file-text-o';
10497 }
10498 if (preg_match('/\.lang$/i', $tmpfile)) {
10499 $mime = 'text/plain';
10500 $imgmime = 'text.png';
10501 $srclang = 'lang';
10502 $famime = 'file-text-o';
10503 }
10504 // Certificate files
10505 if (preg_match('/\.(crt|cer|key|pub)$/i', $tmpfile)) {
10506 $mime = 'text/plain';
10507 $imgmime = 'text.png';
10508 $famime = 'file-text-o';
10509 }
10510 // XML based (HTML/XML/XAML)
10511 if (preg_match('/\.(html|htm|shtml)$/i', $tmpfile)) {
10512 $mime = 'text/html';
10513 $imgmime = 'html.png';
10514 $srclang = 'html';
10515 $famime = 'file-text-o';
10516 }
10517 if (preg_match('/\.(xml|xhtml)$/i', $tmpfile)) {
10518 $mime = 'text/xml';
10519 $imgmime = 'other.png';
10520 $srclang = 'xml';
10521 $famime = 'file-text-o';
10522 }
10523 if (preg_match('/\.xaml$/i', $tmpfile)) {
10524 $mime = 'text/xml';
10525 $imgmime = 'other.png';
10526 $srclang = 'xaml';
10527 $famime = 'file-text-o';
10528 }
10529 // Languages
10530 if (preg_match('/\.bas$/i', $tmpfile)) {
10531 $mime = 'text/plain';
10532 $imgmime = 'text.png';
10533 $srclang = 'bas';
10534 $famime = 'file-code-o';
10535 }
10536 if (preg_match('/\.(c)$/i', $tmpfile)) {
10537 $mime = 'text/plain';
10538 $imgmime = 'text.png';
10539 $srclang = 'c';
10540 $famime = 'file-code-o';
10541 }
10542 if (preg_match('/\.(cpp)$/i', $tmpfile)) {
10543 $mime = 'text/plain';
10544 $imgmime = 'text.png';
10545 $srclang = 'cpp';
10546 $famime = 'file-code-o';
10547 }
10548 if (preg_match('/\.cs$/i', $tmpfile)) {
10549 $mime = 'text/plain';
10550 $imgmime = 'text.png';
10551 $srclang = 'cs';
10552 $famime = 'file-code-o';
10553 }
10554 if (preg_match('/\.(h)$/i', $tmpfile)) {
10555 $mime = 'text/plain';
10556 $imgmime = 'text.png';
10557 $srclang = 'h';
10558 $famime = 'file-code-o';
10559 }
10560 if (preg_match('/\.(java|jsp)$/i', $tmpfile)) {
10561 $mime = 'text/plain';
10562 $imgmime = 'text.png';
10563 $srclang = 'java';
10564 $famime = 'file-code-o';
10565 }
10566 if (preg_match('/\.php([0-9]{1})?$/i', $tmpfile)) {
10567 $mime = 'text/plain';
10568 $imgmime = 'php.png';
10569 $srclang = 'php';
10570 $famime = 'file-code-o';
10571 }
10572 if (preg_match('/\.phtml$/i', $tmpfile)) {
10573 $mime = 'text/plain';
10574 $imgmime = 'php.png';
10575 $srclang = 'php';
10576 $famime = 'file-code-o';
10577 }
10578 if (preg_match('/\.(pl|pm)$/i', $tmpfile)) {
10579 $mime = 'text/plain';
10580 $imgmime = 'pl.png';
10581 $srclang = 'perl';
10582 $famime = 'file-code-o';
10583 }
10584 if (preg_match('/\.sql$/i', $tmpfile)) {
10585 $mime = 'text/plain';
10586 $imgmime = 'text.png';
10587 $srclang = 'sql';
10588 $famime = 'file-code-o';
10589 }
10590 if (preg_match('/\.js$/i', $tmpfile)) {
10591 $mime = 'text/x-javascript';
10592 $imgmime = 'jscript.png';
10593 $srclang = 'js';
10594 $famime = 'file-code-o';
10595 }
10596 // Open office
10597 if (preg_match('/\.odp$/i', $tmpfile)) {
10598 $mime = 'application/vnd.oasis.opendocument.presentation';
10599 $imgmime = 'ooffice.png';
10600 $famime = 'file-powerpoint-o';
10601 }
10602 if (preg_match('/\.ods$/i', $tmpfile)) {
10603 $mime = 'application/vnd.oasis.opendocument.spreadsheet';
10604 $imgmime = 'ooffice.png';
10605 $famime = 'file-excel-o';
10606 }
10607 if (preg_match('/\.odt$/i', $tmpfile)) {
10608 $mime = 'application/vnd.oasis.opendocument.text';
10609 $imgmime = 'ooffice.png';
10610 $famime = 'file-word-o';
10611 }
10612 // MS Office
10613 if (preg_match('/\.mdb$/i', $tmpfile)) {
10614 $mime = 'application/msaccess';
10615 $imgmime = 'mdb.png';
10616 $famime = 'file-o';
10617 }
10618 if (preg_match('/\.doc[xm]?$/i', $tmpfile)) {
10619 $mime = 'application/msword';
10620 $imgmime = 'doc.png';
10621 $famime = 'file-word-o';
10622 }
10623 if (preg_match('/\.dot[xm]?$/i', $tmpfile)) {
10624 $mime = 'application/msword';
10625 $imgmime = 'doc.png';
10626 $famime = 'file-word-o';
10627 }
10628 if (preg_match('/\.xlt(x)?$/i', $tmpfile)) {
10629 $mime = 'application/vnd.ms-excel';
10630 $imgmime = 'xls.png';
10631 $famime = 'file-excel-o';
10632 }
10633 if (preg_match('/\.xla(m)?$/i', $tmpfile)) {
10634 $mime = 'application/vnd.ms-excel';
10635 $imgmime = 'xls.png';
10636 $famime = 'file-excel-o';
10637 }
10638 if (preg_match('/\.xls$/i', $tmpfile)) {
10639 $mime = 'application/vnd.ms-excel';
10640 $imgmime = 'xls.png';
10641 $famime = 'file-excel-o';
10642 }
10643 if (preg_match('/\.xls[bmx]$/i', $tmpfile)) {
10644 $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
10645 $imgmime = 'xls.png';
10646 $famime = 'file-excel-o';
10647 }
10648 if (preg_match('/\.pps[mx]?$/i', $tmpfile)) {
10649 $mime = 'application/vnd.ms-powerpoint';
10650 $imgmime = 'ppt.png';
10651 $famime = 'file-powerpoint-o';
10652 }
10653 if (preg_match('/\.ppt[mx]?$/i', $tmpfile)) {
10654 $mime = 'application/x-mspowerpoint';
10655 $imgmime = 'ppt.png';
10656 $famime = 'file-powerpoint-o';
10657 }
10658 // Other
10659 if (preg_match('/\.pdf$/i', $tmpfile)) {
10660 $mime = 'application/pdf';
10661 $imgmime = 'pdf.png';
10662 $famime = 'file-pdf-o';
10663 }
10664 // Scripts
10665 if (preg_match('/\.bat$/i', $tmpfile)) {
10666 $mime = 'text/x-bat';
10667 $imgmime = 'script.png';
10668 $srclang = 'dos';
10669 $famime = 'file-code-o';
10670 }
10671 if (preg_match('/\.sh$/i', $tmpfile)) {
10672 $mime = 'text/x-sh';
10673 $imgmime = 'script.png';
10674 $srclang = 'bash';
10675 $famime = 'file-code-o';
10676 }
10677 if (preg_match('/\.ksh$/i', $tmpfile)) {
10678 $mime = 'text/x-ksh';
10679 $imgmime = 'script.png';
10680 $srclang = 'bash';
10681 $famime = 'file-code-o';
10682 }
10683 if (preg_match('/\.bash$/i', $tmpfile)) {
10684 $mime = 'text/x-bash';
10685 $imgmime = 'script.png';
10686 $srclang = 'bash';
10687 $famime = 'file-code-o';
10688 }
10689 // Images
10690 if (preg_match('/\.ico$/i', $tmpfile)) {
10691 $mime = 'image/x-icon';
10692 $imgmime = 'image.png';
10693 $famime = 'file-image-o';
10694 }
10695 if (preg_match('/\.(jpg|jpeg)$/i', $tmpfile)) {
10696 $mime = 'image/jpeg';
10697 $imgmime = 'image.png';
10698 $famime = 'file-image-o';
10699 }
10700 if (preg_match('/\.png$/i', $tmpfile)) {
10701 $mime = 'image/png';
10702 $imgmime = 'image.png';
10703 $famime = 'file-image-o';
10704 }
10705 if (preg_match('/\.gif$/i', $tmpfile)) {
10706 $mime = 'image/gif';
10707 $imgmime = 'image.png';
10708 $famime = 'file-image-o';
10709 }
10710 if (preg_match('/\.bmp$/i', $tmpfile)) {
10711 $mime = 'image/bmp';
10712 $imgmime = 'image.png';
10713 $famime = 'file-image-o';
10714 }
10715 if (preg_match('/\.(tif|tiff)$/i', $tmpfile)) {
10716 $mime = 'image/tiff';
10717 $imgmime = 'image.png';
10718 $famime = 'file-image-o';
10719 }
10720 if (preg_match('/\.svg$/i', $tmpfile)) {
10721 $mime = 'image/svg+xml';
10722 $imgmime = 'image.png';
10723 $famime = 'file-image-o';
10724 }
10725 if (preg_match('/\.webp$/i', $tmpfile)) {
10726 $mime = 'image/webp';
10727 $imgmime = 'image.png';
10728 $famime = 'file-image-o';
10729 }
10730 // Calendar
10731 if (preg_match('/\.vcs$/i', $tmpfile)) {
10732 $mime = 'text/calendar';
10733 $imgmime = 'other.png';
10734 $famime = 'file-text-o';
10735 }
10736 if (preg_match('/\.ics$/i', $tmpfile)) {
10737 $mime = 'text/calendar';
10738 $imgmime = 'other.png';
10739 $famime = 'file-text-o';
10740 }
10741 // Other
10742 if (preg_match('/\.torrent$/i', $tmpfile)) {
10743 $mime = 'application/x-bittorrent';
10744 $imgmime = 'other.png';
10745 $famime = 'file-o';
10746 }
10747 // Audio
10748 if (preg_match('/\.(mp3|ogg|au|wav|wma|mid)$/i', $tmpfile)) {
10749 $mime = 'audio';
10750 $imgmime = 'audio.png';
10751 $famime = 'file-audio-o';
10752 }
10753 // Video
10754 if (preg_match('/\.mp4$/i', $tmpfile)) {
10755 $mime = 'video/mp4';
10756 $imgmime = 'video.png';
10757 $famime = 'file-video-o';
10758 }
10759 if (preg_match('/\.ogv$/i', $tmpfile)) {
10760 $mime = 'video/ogg';
10761 $imgmime = 'video.png';
10762 $famime = 'file-video-o';
10763 }
10764 if (preg_match('/\.webm$/i', $tmpfile)) {
10765 $mime = 'video/webm';
10766 $imgmime = 'video.png';
10767 $famime = 'file-video-o';
10768 }
10769 if (preg_match('/\.avi$/i', $tmpfile)) {
10770 $mime = 'video/x-msvideo';
10771 $imgmime = 'video.png';
10772 $famime = 'file-video-o';
10773 }
10774 if (preg_match('/\.divx$/i', $tmpfile)) {
10775 $mime = 'video/divx';
10776 $imgmime = 'video.png';
10777 $famime = 'file-video-o';
10778 }
10779 if (preg_match('/\.xvid$/i', $tmpfile)) {
10780 $mime = 'video/xvid';
10781 $imgmime = 'video.png';
10782 $famime = 'file-video-o';
10783 }
10784 if (preg_match('/\.(wmv|mpg|mpeg)$/i', $tmpfile)) {
10785 $mime = 'video';
10786 $imgmime = 'video.png';
10787 $famime = 'file-video-o';
10788 }
10789 // Archive
10790 if (preg_match('/\.(zip|rar|gz|tgz|z|cab|bz2|7z|tar|lzh|zst)$/i', $tmpfile)) {
10791 $mime = 'archive';
10792 $imgmime = 'archive.png';
10793 $famime = 'file-archive-o';
10794 } // application/xxx where zzz is zip, ...
10795 // Exe
10796 if (preg_match('/\.(exe|com)$/i', $tmpfile)) {
10797 $mime = 'application/octet-stream';
10798 $imgmime = 'other.png';
10799 $famime = 'file-o';
10800 }
10801 // Lib
10802 if (preg_match('/\.(dll|lib|o|so|a)$/i', $tmpfile)) {
10803 $mime = 'library';
10804 $imgmime = 'library.png';
10805 $famime = 'file-o';
10806 }
10807 // Err
10808 if (preg_match('/\.err$/i', $tmpfile)) {
10809 $mime = 'error';
10810 $imgmime = 'error.png';
10811 $famime = 'file-text-o';
10812 }
10813
10814 // Return string
10815 if ($mode == 1) {
10816 $tmp = explode('/', $mime);
10817 return (!empty($tmp[1]) ? $tmp[1] : $tmp[0]);
10818 }
10819 if ($mode == 2) {
10820 return $imgmime;
10821 }
10822 if ($mode == 3) {
10823 return $srclang;
10824 }
10825 if ($mode == 4) {
10826 return $famime;
10827 }
10828 return $mime;
10829}
10830
10842function getDictionaryValue($tablename, $field, $id, $checkentity = false, $rowidfield = 'rowid')
10843{
10844 global $conf, $db;
10845
10846 $tablename = preg_replace('/^'.preg_quote(MAIN_DB_PREFIX, '/').'/', '', $tablename); // Clean name of table for backward compatibility.
10847
10848 $dictvalues = (isset($conf->cache['dictvalues_'.$tablename]) ? $conf->cache['dictvalues_'.$tablename] : null);
10849
10850 if (is_null($dictvalues)) {
10851 $dictvalues = array();
10852
10853 $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
10854 if ($checkentity) {
10855 $sql .= ' AND entity IN (0,'.getEntity($tablename).')';
10856 }
10857
10858 $resql = $db->query($sql);
10859 if ($resql) {
10860 while ($obj = $db->fetch_object($resql)) {
10861 $dictvalues[$obj->{$rowidfield}] = $obj; // $obj is stdClass
10862 }
10863 } else {
10864 dol_print_error($db);
10865 }
10866
10867 $conf->cache['dictvalues_'.$tablename] = $dictvalues;
10868 }
10869
10870 if (!empty($dictvalues[$id])) {
10871 // Found
10872 $tmp = $dictvalues[$id];
10873 return (property_exists($tmp, $field) ? $tmp->$field : '');
10874 } else {
10875 // Not found
10876 return '';
10877 }
10878}
10879
10886function colorIsLight($stringcolor)
10887{
10888 $stringcolor = str_replace('#', '', $stringcolor);
10889 $res = -1;
10890 if (!empty($stringcolor)) {
10891 $res = 0;
10892 $tmp = explode(',', $stringcolor);
10893 if (count($tmp) > 1) { // This is a comma RGB ('255','255','255')
10894 $r = $tmp[0];
10895 $g = $tmp[1];
10896 $b = $tmp[2];
10897 } else {
10898 $hexr = $stringcolor[0].$stringcolor[1];
10899 $hexg = $stringcolor[2].$stringcolor[3];
10900 $hexb = $stringcolor[4].$stringcolor[5];
10901 $r = hexdec($hexr);
10902 $g = hexdec($hexg);
10903 $b = hexdec($hexb);
10904 }
10905 $bright = (max($r, $g, $b) + min($r, $g, $b)) / 510.0; // HSL algorithm
10906 if ($bright > 0.6) {
10907 $res = 1;
10908 }
10909 }
10910 return $res;
10911}
10912
10921function isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
10922{
10923 global $conf;
10924
10925 //print 'type_user='.$type_user.' module='.$menuentry['module'].' enabled='.$menuentry['enabled'].' perms='.$menuentry['perms'];
10926 //print 'ok='.in_array($menuentry['module'], $listofmodulesforexternal);
10927 if (empty($menuentry['enabled'])) {
10928 return 0; // Entry disabled by condition
10929 }
10930 if ($type_user && $menuentry['module']) {
10931 $tmploops = explode('|', $menuentry['module']);
10932 $found = 0;
10933 foreach ($tmploops as $tmploop) {
10934 if (in_array($tmploop, $listofmodulesforexternal)) {
10935 $found++;
10936 break;
10937 }
10938 }
10939 if (!$found) {
10940 return 0; // Entry is for menus all excluded to external users
10941 }
10942 }
10943 if (!$menuentry['perms'] && $type_user) {
10944 return 0; // No permissions and user is external
10945 }
10946 if (!$menuentry['perms'] && !empty($conf->global->MAIN_MENU_HIDE_UNAUTHORIZED)) {
10947 return 0; // No permissions and option to hide when not allowed, even for internal user, is on
10948 }
10949 if (!$menuentry['perms']) {
10950 return 2; // No permissions and user is external
10951 }
10952 return 1;
10953}
10954
10962function roundUpToNextMultiple($n, $x = 5)
10963{
10964 return (ceil($n) % $x === 0) ? ceil($n) : round(($n + $x / 2) / $x) * $x;
10965}
10966
10978function dolGetBadge($label, $html = '', $type = 'primary', $mode = '', $url = '', $params = array())
10979{
10980 $attr = array(
10981 'class'=>'badge '.(!empty($mode) ? ' badge-'.$mode : '').(!empty($type) ? ' badge-'.$type : '').(empty($params['css']) ? '' : ' '.$params['css'])
10982 );
10983
10984 if (empty($html)) {
10985 $html = $label;
10986 }
10987
10988 if (!empty($url)) {
10989 $attr['href'] = $url;
10990 }
10991
10992 if ($mode === 'dot') {
10993 $attr['class'] .= ' classfortooltip';
10994 $attr['title'] = $html;
10995 $attr['aria-label'] = $label;
10996 $html = '';
10997 }
10998
10999 // Override attr
11000 if (!empty($params['attr']) && is_array($params['attr'])) {
11001 foreach ($params['attr'] as $key => $value) {
11002 if ($key == 'class') {
11003 $attr['class'] .= ' '.$value;
11004 } elseif ($key == 'classOverride') {
11005 $attr['class'] = $value;
11006 } else {
11007 $attr[$key] = $value;
11008 }
11009 }
11010 }
11011
11012 // TODO: add hook
11013
11014 // escape all attribute
11015 $attr = array_map('dol_escape_htmltag', $attr);
11016
11017 $TCompiledAttr = array();
11018 foreach ($attr as $key => $value) {
11019 $TCompiledAttr[] = $key.'="'.$value.'"';
11020 }
11021
11022 $compiledAttributes = !empty($TCompiledAttr) ?implode(' ', $TCompiledAttr) : '';
11023
11024 $tag = !empty($url) ? 'a' : 'span';
11025
11026 return '<'.$tag.' '.$compiledAttributes.'>'.$html.'</'.$tag.'>';
11027}
11028
11029
11042function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $statusType = 'status0', $displayMode = 0, $url = '', $params = array())
11043{
11044 global $conf;
11045
11046 $return = '';
11047 $dolGetBadgeParams = array();
11048
11049 if (!empty($params['badgeParams'])) {
11050 $dolGetBadgeParams = $params['badgeParams'];
11051 }
11052
11053 // TODO : add a hook
11054 if ($displayMode == 0) {
11055 $return = !empty($html) ? $html : (empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort));
11056 } elseif ($displayMode == 1) {
11057 $return = !empty($html) ? $html : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11058 } elseif (!empty($conf->global->MAIN_STATUS_USES_IMAGES)) {
11059 // Use status with images (for backward compatibility)
11060 $return = '';
11061 $htmlLabel = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : $statusLabel).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
11062 $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>' : '');
11063
11064 // For small screen, we always use the short label instead of long label.
11065 if (!empty($conf->dol_optimize_smallscreen)) {
11066 if ($displayMode == 0) {
11067 $displayMode = 1;
11068 } elseif ($displayMode == 4) {
11069 $displayMode = 2;
11070 } elseif ($displayMode == 6) {
11071 $displayMode = 5;
11072 }
11073 }
11074
11075 // For backward compatibility. Image's filename are still in French, so we use this array to convert
11076 $statusImg = array(
11077 'status0' => 'statut0',
11078 'status1' => 'statut1',
11079 'status2' => 'statut2',
11080 'status3' => 'statut3',
11081 'status4' => 'statut4',
11082 'status5' => 'statut5',
11083 'status6' => 'statut6',
11084 'status7' => 'statut7',
11085 'status8' => 'statut8',
11086 'status9' => 'statut9'
11087 );
11088
11089 if (!empty($statusImg[$statusType])) {
11090 $htmlImg = img_picto($statusLabel, $statusImg[$statusType]);
11091 } else {
11092 $htmlImg = img_picto($statusLabel, $statusType);
11093 }
11094
11095 if ($displayMode === 2) {
11096 $return = $htmlImg.' '.$htmlLabelShort;
11097 } elseif ($displayMode === 3) {
11098 $return = $htmlImg;
11099 } elseif ($displayMode === 4) {
11100 $return = $htmlImg.' '.$htmlLabel;
11101 } elseif ($displayMode === 5) {
11102 $return = $htmlLabelShort.' '.$htmlImg;
11103 } else { // $displayMode >= 6
11104 $return = $htmlLabel.' '.$htmlImg;
11105 }
11106 } elseif (empty($conf->global->MAIN_STATUS_USES_IMAGES) && !empty($displayMode)) {
11107 // Use new badge
11108 $statusLabelShort = (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11109
11110 $dolGetBadgeParams['attr']['class'] = 'badge-status';
11111 $dolGetBadgeParams['attr']['title'] = empty($params['tooltip']) ? $statusLabel : ($params['tooltip'] != 'no' ? $params['tooltip'] : '');
11112
11113 if ($displayMode == 3) {
11114 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), '', $statusType, 'dot', $url, $dolGetBadgeParams);
11115 } elseif ($displayMode === 5) {
11116 $return = dolGetBadge($statusLabelShort, $html, $statusType, '', $url, $dolGetBadgeParams);
11117 } else {
11118 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), $html, $statusType, '', $url, $dolGetBadgeParams);
11119 }
11120 }
11121
11122 return $return;
11123}
11124
11125
11160function dolGetButtonAction($label, $text = '', $actionType = 'default', $url = '', $id = '', $userRight = 1, $params = array())
11161{
11162 global $hookmanager, $action, $object, $langs;
11163
11164 // If $url is an array, we must build a dropdown button
11165 if (is_array($url)) {
11166 $out = '<div class="dropdown inline-block dropdown-holder">';
11167 $out .= '<a style="margin-right: auto;" class="dropdown-toggle butAction" data-toggle="dropdown">'.$label.'</a>';
11168 $out .= '<div class="dropdown-content">';
11169 foreach ($url as $subbutton) {
11170 if ($subbutton['enabled'] && $subbutton['perm']) {
11171 if (!empty($subbutton['lang'])) {
11172 $langs->load($subbutton['lang']);
11173 }
11174 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage'])), '', 1, array('isDropDown' => true));
11175 }
11176 }
11177 $out .= "</div>";
11178 $out .= "</div>";
11179
11180 return $out;
11181 }
11182
11183 // If $url is a simple link
11184 if (!empty($params['isDropdown']))
11185 $class = "dropdown-item";
11186 else {
11187 $class = 'butAction';
11188 if ($actionType == 'danger' || $actionType == 'delete') {
11189 $class = 'butActionDelete';
11190 if (!empty($url) && strpos($url, 'token=') === false) $url .= '&token='.newToken();
11191 }
11192 }
11193 $attr = array(
11194 'class' => $class,
11195 'href' => empty($url) ? '' : $url,
11196 'title' => $label
11197 );
11198
11199 if (empty($text)) {
11200 $text = $label;
11201 $attr['title'] = ''; // if html not set, leave label on title is redundant
11202 } else {
11203 $attr['title'] = $label;
11204 $attr['aria-label'] = $label;
11205 }
11206
11207 if (empty($userRight)) {
11208 $attr['class'] = 'butActionRefused';
11209 $attr['href'] = '';
11210 $attr['title'] = (($label && $text && $label != $text) ? $label : $langs->trans('NotEnoughPermissions'));
11211 }
11212
11213 if (!empty($id)) {
11214 $attr['id'] = $id;
11215 }
11216
11217 // Override attr
11218 if (!empty($params['attr']) && is_array($params['attr'])) {
11219 foreach ($params['attr'] as $key => $value) {
11220 if ($key == 'class') {
11221 $attr['class'] .= ' '.$value;
11222 } elseif ($key == 'classOverride') {
11223 $attr['class'] = $value;
11224 } else {
11225 $attr[$key] = $value;
11226 }
11227 }
11228 }
11229
11230 // automatic add tooltip when title is detected
11231 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
11232 $attr['class'].= ' classfortooltip';
11233 }
11234
11235 // Js Confirm button
11236 if ($userRight && !empty($params['confirm'])) {
11237 if (!is_array($params['confirm'])) {
11238 $params['confirm'] = array();
11239 }
11240
11241 if (empty($params['confirm']['url'])) {
11242 $params['confirm']['url'] = $url . (strpos($url, '?') > 0 ? '&' : '?') . 'confirm=yes';
11243 }
11244
11245 // for js desabled compatibility set $url as call to confirm action and $params['confirm']['url'] to confirmed action
11246 $attr['data-confirm-url'] = $params['confirm']['url'];
11247 $attr['data-confirm-title'] = !empty($params['confirm']['title']) ? $params['confirm']['title'] : $langs->trans('ConfirmBtnCommonTitle', $label);
11248 $attr['data-confirm-content'] = !empty($params['confirm']['content']) ? $params['confirm']['content'] : $langs->trans('ConfirmBtnCommonContent', $label);
11249 $attr['data-confirm-content'] = preg_replace("/\r|\n/", "", $attr['data-confirm-content']);
11250 $attr['data-confirm-action-btn-label'] = !empty($params['confirm']['action-btn-label']) ? $params['confirm']['action-btn-label'] : $langs->trans('Confirm');
11251 $attr['data-confirm-cancel-btn-label'] = !empty($params['confirm']['cancel-btn-label']) ? $params['confirm']['cancel-btn-label'] : $langs->trans('CloseDialog');
11252 $attr['data-confirm-modal'] = !empty($params['confirm']['modal']) ? $params['confirm']['modal'] : true;
11253
11254 $attr['class'].= ' butActionConfirm';
11255 }
11256
11257 if (isset($attr['href']) && empty($attr['href'])) {
11258 unset($attr['href']);
11259 }
11260
11261 // escape all attribute
11262 $attr = array_map('dol_escape_htmltag', $attr);
11263
11264 $TCompiledAttr = array();
11265 foreach ($attr as $key => $value) {
11266 $TCompiledAttr[] = $key.'= "'.$value.'"';
11267 }
11268
11269 $compiledAttributes = empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr);
11270
11271 $tag = !empty($attr['href']) ? 'a' : 'span';
11272
11273
11274 $parameters = array(
11275 'TCompiledAttr' => $TCompiledAttr, // array
11276 'compiledAttributes' => $compiledAttributes, // string
11277 'attr' => $attr,
11278 'tag' => $tag,
11279 'label' => $label,
11280 'html' => $text,
11281 'actionType' => $actionType,
11282 'url' => $url,
11283 'id' => $id,
11284 'userRight' => $userRight,
11285 'params' => $params
11286 );
11287
11288 $reshook = $hookmanager->executeHooks('dolGetButtonAction', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
11289 if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
11290
11291 if (empty($reshook)) {
11292 if (dol_textishtml($text)) { // If content already HTML encoded
11293 return '<' . $tag . ' ' . $compiledAttributes . '>' . $text . '</' . $tag . '>';
11294 } else {
11295 return '<' . $tag . ' ' . $compiledAttributes . '>' . dol_escape_htmltag($text) . '</' . $tag . '>';
11296 }
11297 } else {
11298 return $hookmanager->resPrint;
11299 }
11300}
11301
11308function dolGetButtonTitleSeparator($moreClass = "")
11309{
11310 return '<span class="button-title-separator '.$moreClass.'" ></span>';
11311}
11312
11319function getFieldErrorIcon($fieldValidationErrorMsg)
11320{
11321 $out = '';
11322 if (!empty($fieldValidationErrorMsg)) {
11323 $out.= '<span class="field-error-icon classfortooltip" title="'.dol_escape_htmltag($fieldValidationErrorMsg, 1).'" role="alert" >'; // role alert is used for accessibility
11324 $out.= '<span class="fa fa-exclamation-circle" aria-hidden="true" ></span>'; // For accessibility icon is separated and aria-hidden
11325 $out.= '</span>';
11326 }
11327
11328 return $out;
11329}
11330
11343function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $url = '', $id = '', $status = 1, $params = array())
11344{
11345 global $langs, $conf, $user;
11346
11347 // Actually this conf is used in css too for external module compatibility and smooth transition to this function
11348 if (!empty($conf->global->MAIN_BUTTON_HIDE_UNAUTHORIZED) && (!$user->admin) && $status <= 0) {
11349 return '';
11350 }
11351
11352 $class = 'btnTitle';
11353 if (in_array($iconClass, array('fa fa-plus-circle', 'fa fa-plus-circle size15x', 'fa fa-comment-dots', 'fa fa-paper-plane'))) {
11354 $class .= ' btnTitlePlus';
11355 }
11356 $useclassfortooltip = 1;
11357
11358 if (!empty($params['morecss'])) {
11359 $class .= ' '.$params['morecss'];
11360 }
11361
11362 $attr = array(
11363 'class' => $class,
11364 'href' => empty($url) ? '' : $url
11365 );
11366
11367 if (!empty($helpText)) {
11368 $attr['title'] = dol_escape_htmltag($helpText);
11369 } elseif (empty($attr['title']) && $label) {
11370 $attr['title'] = $label;
11371 $useclassfortooltip = 0;
11372 }
11373
11374 if ($status == 2) {
11375 $attr['class'] .= ' btnTitleSelected';
11376 } elseif ($status <= 0) {
11377 $attr['class'] .= ' refused';
11378
11379 $attr['href'] = '';
11380
11381 if ($status == -1) { // disable
11382 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("FeatureDisabled"));
11383 } elseif ($status == 0) { // Not enough permissions
11384 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions"));
11385 }
11386 }
11387
11388 if (!empty($attr['title']) && $useclassfortooltip) {
11389 $attr['class'] .= ' classfortooltip';
11390 }
11391
11392 if (!empty($id)) {
11393 $attr['id'] = $id;
11394 }
11395
11396 // Override attr
11397 if (!empty($params['attr']) && is_array($params['attr'])) {
11398 foreach ($params['attr'] as $key => $value) {
11399 if ($key == 'class') {
11400 $attr['class'] .= ' '.$value;
11401 } elseif ($key == 'classOverride') {
11402 $attr['class'] = $value;
11403 } else {
11404 $attr[$key] = $value;
11405 }
11406 }
11407 }
11408
11409 if (isset($attr['href']) && empty($attr['href'])) {
11410 unset($attr['href']);
11411 }
11412
11413 // TODO : add a hook
11414
11415 // escape all attribute
11416 $attr = array_map('dol_escape_htmltag', $attr);
11417
11418 $TCompiledAttr = array();
11419 foreach ($attr as $key => $value) {
11420 $TCompiledAttr[] = $key.'="'.$value.'"';
11421 }
11422
11423 $compiledAttributes = (empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr));
11424
11425 $tag = (empty($attr['href']) ? 'span' : 'a');
11426
11427 $button = '<'.$tag.' '.$compiledAttributes.'>';
11428 $button .= '<span class="'.$iconClass.' valignmiddle btnTitle-icon"></span>';
11429 if (!empty($params['forcenohideoftext'])) {
11430 $button .= '<span class="valignmiddle text-plus-circle btnTitle-label'.(empty($params['forcenohideoftext']) ? ' hideonsmartphone' : '').'">'.$label.'</span>';
11431 }
11432 $button .= '</'.$tag.'>';
11433
11434 return $button;
11435}
11436
11447function getElementProperties($element_type)
11448{
11449 global $conf;
11450
11451 $regs = array();
11452
11453 $classfile = $classname = $classpath = $subdir = $dir_output = '';
11454
11455 // Parse element/subelement
11456 $module = $element_type;
11457 $element = $element_type;
11458 $subelement = $element_type;
11459
11460 // If we ask a resource form external module (instead of default path)
11461 if (preg_match('/^([^@]+)@([^@]+)$/i', $element_type, $regs)) { // 'myobject@mymodule'
11462 $element = $subelement = $regs[1];
11463 $module = $regs[2];
11464 }
11465
11466 // If we ask a resource for a string with an element and a subelement
11467 // Example 'project_task'
11468 if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { // 'myobject_mysubobject' with myobject=mymodule
11469 $module = $element = $regs[1];
11470 $subelement = $regs[2];
11471 }
11472
11473 // For compat and To work with non standard path
11474 if ($element_type == "action") {
11475 $classpath = 'comm/action/class';
11476 $subelement = 'Actioncomm';
11477 $module = 'agenda';
11478 } elseif ($element_type == 'cronjob') {
11479 $classpath = 'cron/class';
11480 $module = 'cron';
11481 } elseif ($element_type == 'adherent_type') {
11482 $classpath = 'adherents/class';
11483 $classfile = 'adherent_type';
11484 $module = 'adherent';
11485 $subelement = 'adherent_type';
11486 $classname = 'AdherentType';
11487 } elseif ($element_type == 'bank_account') {
11488 $classpath = 'compta/bank/class';
11489 $module = 'bank'; // We need $conf->bank->dir_output and not $conf->banque->dir_output
11490 $classfile = 'account';
11491 $classname = 'Account';
11492 } elseif ($element_type == 'category') {
11493 $classpath = 'categories/class';
11494 $module = 'categorie';
11495 $subelement = 'categorie';
11496 } elseif ($element_type == 'contact') {
11497 $classpath = 'contact/class';
11498 $classfile = 'contact';
11499 $module = 'societe';
11500 $subelement = 'contact';
11501 } elseif ($element_type == 'stock') {
11502 $classpath = 'product/stock/class';
11503 $classfile = 'entrepot';
11504 $classname = 'Entrepot';
11505 } elseif ($element_type == 'project') {
11506 $classpath = 'projet/class';
11507 $module = 'projet';
11508 } elseif ($element_type == 'project_task') {
11509 $classpath = 'projet/class';
11510 $module = 'projet';
11511 $subelement = 'task';
11512 } elseif ($element_type == 'facture' || $element_type == 'invoice') {
11513 $classpath = 'compta/facture/class';
11514 $module = 'facture';
11515 $subelement = 'facture';
11516 } elseif ($element_type == 'commande' || $element_type == 'order') {
11517 $classpath = 'commande/class';
11518 $module = 'commande';
11519 $subelement = 'commande';
11520 } elseif ($element_type == 'propal') {
11521 $classpath = 'comm/propal/class';
11522 } elseif ($element_type == 'shipping') {
11523 $classpath = 'expedition/class';
11524 $classfile = 'expedition';
11525 $classname = 'Expedition';
11526 $module = 'expedition';
11527 } elseif ($element_type == 'supplier_proposal') {
11528 $classpath = 'supplier_proposal/class';
11529 $module = 'supplier_proposal';
11530 $element = 'supplierproposal';
11531 $classfile = 'supplier_proposal';
11532 $subelement = 'supplierproposal';
11533 } elseif ($element_type == 'shipping') {
11534 $classpath = 'expedition/class';
11535 $subelement = 'expedition';
11536 $module = 'expedition_bon';
11537 } elseif ($element_type == 'delivery') {
11538 $classpath = 'delivery/class';
11539 $subelement = 'delivery';
11540 $module = 'delivery_note';
11541 } elseif ($element_type == 'contract') {
11542 $classpath = 'contrat/class';
11543 $module = 'contrat';
11544 $subelement = 'contrat';
11545 } elseif ($element_type == 'mailing') {
11546 $classpath = 'comm/mailing/class';
11547 $module = 'mailing';
11548 $classfile = 'mailing';
11549 $classname = 'Mailing';
11550 $subelement = '';
11551 } elseif ($element_type == 'member') {
11552 $classpath = 'adherents/class';
11553 $module = 'adherent';
11554 $subelement = 'adherent';
11555 } elseif ($element_type == 'usergroup') {
11556 $classpath = 'user/class';
11557 $module = 'user';
11558 } elseif ($element_type == 'mo') {
11559 $classpath = 'mrp/class';
11560 $classfile = 'mo';
11561 $classname = 'Mo';
11562 $module = 'mrp';
11563 $subelement = '';
11564 } elseif ($element_type == 'cabinetmed_cons') {
11565 $classpath = 'cabinetmed/class';
11566 $module = 'cabinetmed';
11567 $subelement = 'cabinetmedcons';
11568 } elseif ($element_type == 'fichinter') {
11569 $classpath = 'fichinter/class';
11570 $module = 'ficheinter';
11571 $subelement = 'fichinter';
11572 } elseif ($element_type == 'dolresource' || $element_type == 'resource') {
11573 $classpath = 'resource/class';
11574 $module = 'resource';
11575 $subelement = 'dolresource';
11576 } elseif ($element_type == 'propaldet') {
11577 $classpath = 'comm/propal/class';
11578 $module = 'propal';
11579 $subelement = 'propaleligne';
11580 } elseif ($element_type == 'opensurvey_sondage') {
11581 $classpath = 'opensurvey/class';
11582 $module = 'opensurvey';
11583 $subelement = 'opensurveysondage';
11584 } elseif ($element_type == 'order_supplier') {
11585 $classpath = 'fourn/class';
11586 $module = 'fournisseur';
11587 $classfile = 'fournisseur.commande';
11588 $element = 'order_supplier';
11589 $subelement = '';
11590 $classname = 'CommandeFournisseur';
11591 } elseif ($element_type == 'invoice_supplier') {
11592 $classpath = 'fourn/class';
11593 $module = 'fournisseur';
11594 $classfile = 'fournisseur.facture';
11595 $element = 'invoice_supplier';
11596 $subelement = '';
11597 $classname = 'FactureFournisseur';
11598 } elseif ($element_type == "service") {
11599 $classpath = 'product/class';
11600 $subelement = 'product';
11601 } elseif ($element_type == 'salary') {
11602 $classpath = 'salaries/class';
11603 $module = 'salaries';
11604 } elseif ($element_type == 'productlot') {
11605 $module = 'productbatch';
11606 $classpath = 'product/stock/class';
11607 $classfile = 'productlot';
11608 $classname = 'Productlot';
11609 $element = 'productlot';
11610 $subelement = '';
11611 } elseif ($element_type == 'websitepage') {
11612 $classpath = 'website/class';
11613 $classfile = 'websitepage';
11614 $classname = 'Websitepage';
11615 $module = 'website';
11616 $subelement = 'websitepage';
11617 } elseif ($element_type == 'fiscalyear') {
11618 $classpath = 'core/class';
11619 $module = 'accounting';
11620 $subelement = 'fiscalyear';
11621 } elseif ($element_type == 'chargesociales') {
11622 $classpath = 'compta/sociales/class';
11623 $module = 'tax';
11624 } elseif ($element_type == 'tva') {
11625 $classpath = 'compta/tva/class';
11626 $module = 'tax';
11627 $subdir = '/vat';
11628 }
11629
11630 if (empty($classfile)) {
11631 $classfile = strtolower($subelement);
11632 }
11633 if (empty($classname)) {
11634 $classname = ucfirst($subelement);
11635 }
11636 if (empty($classpath)) {
11637 $classpath = $module.'/class';
11638 }
11639
11640 //print 'getElementProperties subdir='.$subdir;
11641
11642 // Set dir_output
11643 if ($module && isset($conf->$module)) { // The generic case
11644 if (!empty($conf->$module->multidir_output[$conf->entity])) {
11645 $dir_output = $conf->$module->multidir_output[$conf->entity];
11646 } elseif (!empty($conf->$module->output[$conf->entity])) {
11647 $dir_output = $conf->$module->output[$conf->entity];
11648 } elseif (!empty($conf->$module->dir_output)) {
11649 $dir_output = $conf->$module->dir_output;
11650 }
11651 }
11652
11653 // Overwrite value for special cases
11654 if ($element == 'order_supplier') {
11655 $dir_output = $conf->fournisseur->commande->dir_output;
11656 } elseif ($element == 'invoice_supplier') {
11657 $dir_output = $conf->fournisseur->facture->dir_output;
11658 }
11659 $dir_output .= $subdir;
11660
11661 $element_properties = array(
11662 'module' => $module,
11663 'element' => $element,
11664 'subelement' => $subelement,
11665 'classpath' => $classpath,
11666 'classfile' => $classfile,
11667 'classname' => $classname,
11668 'dir_output' => $dir_output
11669 );
11670 return $element_properties;
11671}
11672
11682function fetchObjectByElement($element_id, $element_type, $element_ref = '')
11683{
11684 global $db;
11685
11686 $ret = 0;
11687
11688 $element_prop = getElementProperties($element_type);
11689
11690 if (is_array($element_prop) && isModEnabled($element_prop['module'])) {
11691 dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php');
11692
11693 if (class_exists($element_prop['classname'])) {
11694 $classname = $element_prop['classname'];
11695 $objecttmp = new $classname($db);
11696 $ret = $objecttmp->fetch($element_id, $element_ref);
11697 if ($ret >= 0) {
11698 if (empty($objecttmp->module)) {
11699 $objecttmp->module = $element_prop['module'];
11700 }
11701
11702 return $objecttmp;
11703 }
11704 } else {
11705 return -1;
11706 }
11707 }
11708
11709 return $ret;
11710}
11711
11719{
11720 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)) {
11721 return true;
11722 }
11723
11724 return false;
11725}
11726
11734function newToken()
11735{
11736 return empty($_SESSION['newtoken']) ? '' : $_SESSION['newtoken'];
11737}
11738
11747{
11748 return isset($_SESSION['token']) ? $_SESSION['token'] : '';
11749}
11750
11756function getNonce()
11757{
11758 global $conf;
11759
11760 if (empty($conf->cache['nonce'])) {
11761 $conf->cache['nonce'] = dolGetRandomBytes(8);
11762 }
11763
11764 return $conf->cache['nonce'];
11765}
11766
11767
11780function startSimpleTable($header, $link = "", $arguments = "", $emptyRows = 0, $number = -1)
11781{
11782 global $langs;
11783
11784 print '<div class="div-table-responsive-no-min">';
11785 print '<table class="noborder centpercent">';
11786 print '<tr class="liste_titre">';
11787
11788 print $emptyRows < 1 ? '<th>' : '<th colspan="'.($emptyRows + 1).'">';
11789
11790 print $langs->trans($header);
11791
11792 // extra space between the first header and the number
11793 if ($number > -1) {
11794 print ' ';
11795 }
11796
11797 if (!empty($link)) {
11798 if (!empty($arguments)) {
11799 print '<a href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
11800 } else {
11801 print '<a href="'.DOL_URL_ROOT.'/'.$link.'">';
11802 }
11803 }
11804
11805 if ($number > -1) {
11806 print '<span class="badge">'.$number.'</span>';
11807 }
11808
11809 if (!empty($link)) {
11810 print '</a>';
11811 }
11812
11813 print '</th>';
11814
11815 if ($number < 0 && !empty($link)) {
11816 print '<th class="right">';
11817
11818 if (!empty($arguments)) {
11819 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
11820 } else {
11821 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'">';
11822 }
11823
11824 print $langs->trans("FullList");
11825 print '</a>';
11826 print '</th>';
11827 }
11828
11829 print '</tr>';
11830}
11831
11840function finishSimpleTable($addLineBreak = false)
11841{
11842 print '</table>';
11843 print '</div>';
11844
11845 if ($addLineBreak) {
11846 print '<br>';
11847 }
11848}
11849
11861function addSummaryTableLine($tableColumnCount, $num, $nbofloop = 0, $total = 0, $noneWord = "None", $extraRightColumn = false)
11862{
11863 global $langs;
11864
11865 if ($num === 0) {
11866 print '<tr class="oddeven">';
11867 print '<td colspan="'.$tableColumnCount.'" class="opacitymedium">'.$langs->trans($noneWord).'</td>';
11868 print '</tr>';
11869 return;
11870 }
11871
11872 if ($nbofloop === 0) {
11873 // don't show a summary line
11874 return;
11875 }
11876
11877 if ($num === 0) {
11878 $colspan = $tableColumnCount;
11879 } elseif ($num > $nbofloop) {
11880 $colspan = $tableColumnCount;
11881 } else {
11882 $colspan = $tableColumnCount - 1;
11883 }
11884
11885 if ($extraRightColumn) {
11886 $colspan--;
11887 }
11888
11889 print '<tr class="liste_total">';
11890
11891 if ($nbofloop > 0 && $num > $nbofloop) {
11892 print '<td colspan="'.$colspan.'" class="right">'.$langs->trans("XMoreLines", ($num - $nbofloop)).'</td>';
11893 } else {
11894 print '<td colspan="'.$colspan.'" class="right"> '.$langs->trans("Total").'</td>';
11895 print '<td class="right" width="100">'.price($total).'</td>';
11896 }
11897
11898 if ($extraRightColumn) {
11899 print '<td></td>';
11900 }
11901
11902 print '</tr>';
11903}
11904
11913function readfileLowMemory($fullpath_original_file_osencoded, $method = -1)
11914{
11915 global $conf;
11916
11917 if ($method == -1) {
11918 $method = 0;
11919 if (!empty($conf->global->MAIN_FORCE_READFILE_WITH_FREAD)) {
11920 $method = 1;
11921 }
11922 if (!empty($conf->global->MAIN_FORCE_READFILE_WITH_STREAM_COPY)) {
11923 $method = 2;
11924 }
11925 }
11926
11927 // Be sure we don't have output buffering enabled to have readfile working correctly
11928 while (ob_get_level()) {
11929 ob_end_flush();
11930 }
11931
11932 // Solution 0
11933 if ($method == 0) {
11934 readfile($fullpath_original_file_osencoded);
11935 } elseif ($method == 1) {
11936 // Solution 1
11937 $handle = fopen($fullpath_original_file_osencoded, "rb");
11938 while (!feof($handle)) {
11939 print fread($handle, 8192);
11940 }
11941 fclose($handle);
11942 } elseif ($method == 2) {
11943 // Solution 2
11944 $handle1 = fopen($fullpath_original_file_osencoded, "rb");
11945 $handle2 = fopen("php://output", "wb");
11946 stream_copy_to_stream($handle1, $handle2);
11947 fclose($handle1);
11948 fclose($handle2);
11949 }
11950}
11951
11961function showValueWithClipboardCPButton($valuetocopy, $showonlyonhover = 1, $texttoshow = '')
11962{
11963 /*
11964 global $conf;
11965
11966 if (!empty($conf->dol_no_mouse_hover)) {
11967 $showonlyonhover = 0;
11968 }*/
11969
11970 $tag = 'span'; // Using div (like any style of type 'block') does not work when using the js copy code.
11971 if ($texttoshow === 'none') {
11972 $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>';
11973 } elseif ($texttoshow) {
11974 $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>';
11975 } else {
11976 $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>';
11977 }
11978
11979 return $result;
11980}
11981
11982
11989function jsonOrUnserialize($stringtodecode)
11990{
11991 $result = json_decode($stringtodecode);
11992 if ($result === null) {
11993 $result = unserialize($stringtodecode);
11994 }
11995
11996 return $result;
11997}
11998
11999
12013function forgeSQLFromUniversalSearchCriteria($filter, &$errorstr = '', $noand = 0, $nopar = 0, $noerror = 0)
12014{
12015 if (!preg_match('/^\‍(.*\‍)$/', $filter)) { // If $filter does not start and end with ()
12016 $filter = '(' . $filter . ')';
12017 }
12018
12019 $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'
12020
12021 if (!dolCheckFilters($filter, $errorstr)) {
12022 if ($noerror) {
12023 return '1 = 2';
12024 } else {
12025 return 'Filter syntax error - '.$errorstr; // Bad balance of parenthesis, we return an error message or force a SQL not found
12026 }
12027 }
12028
12029 // Test the filter syntax
12030 $t = preg_replace_callback('/'.$regexstring.'/i', 'dolForgeDummyCriteriaCallback', $filter);
12031 $t = str_replace(array('and','or','AND','OR',' '), '', $t); // Remove the only strings allowed between each () criteria
12032 // If the string result contains something else than '()', the syntax was wrong
12033 if (preg_match('/[^\‍(\‍)]/', $t)) {
12034 $errorstr = 'Bad syntax of the search string';
12035 if ($noerror) {
12036 return '1 = 2';
12037 } else {
12038 return 'Filter syntax error - '.$errorstr; // Bad syntax of the search string, we return an error message or force a SQL not found
12039 }
12040 }
12041
12042 return ($noand ? "" : " AND ").($nopar ? "" : '(').preg_replace_callback('/'.$regexstring.'/i', 'dolForgeCriteriaCallback', $filter).($nopar ? "" : ')');
12043}
12044
12052function dolCheckFilters($sqlfilters, &$error = '')
12053{
12054 //$regexstring='\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^:\‍(\‍)]+)\‍)';
12055 //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
12056 $tmp = $sqlfilters;
12057 $i = 0; $nb = strlen($tmp);
12058 $counter = 0;
12059 while ($i < $nb) {
12060 if ($tmp[$i] == '(') {
12061 $counter++;
12062 }
12063 if ($tmp[$i] == ')') {
12064 $counter--;
12065 }
12066 if ($counter < 0) {
12067 $error = "Wrond balance of parenthesis in sqlfilters=".$sqlfilters;
12068 dol_syslog($error, LOG_WARNING);
12069 return false;
12070 }
12071 $i++;
12072 }
12073 return true;
12074}
12075
12084{
12085 //dol_syslog("Convert matches ".$matches[1]);
12086 if (empty($matches[1])) {
12087 return '';
12088 }
12089 $tmp = explode(':', $matches[1]);
12090 if (count($tmp) < 3) {
12091 return '';
12092 }
12093
12094 return '()'; // An empty criteria
12095}
12096
12106{
12107 global $db;
12108
12109 //dol_syslog("Convert matches ".$matches[1]);
12110 if (empty($matches[1])) {
12111 return '';
12112 }
12113 $tmp = explode(':', $matches[1]);
12114 if (count($tmp) < 3) {
12115 return '';
12116 }
12117
12118 $operand = preg_replace('/[^a-z0-9\._]/i', '', trim($tmp[0]));
12119
12120 $operator = strtoupper(preg_replace('/[^a-z<>!=]/i', '', trim($tmp[1])));
12121
12122 if ($operator == 'NOTLIKE') {
12123 $operator = 'NOT LIKE';
12124 }
12125 if ($operator == 'ISNOT') {
12126 $operator = 'IS NOT';
12127 }
12128 if ($operator == '!=') {
12129 $operator = '<>';
12130 }
12131
12132 $tmpescaped = $tmp[2];
12133 $regbis = array();
12134
12135 if ($operator == 'IN') { // IN is allowed for list of ID or code only
12136 //if (!preg_match('/^\‍(.*\‍)$/', $tmpescaped)) {
12137 $tmpescaped = '('.$db->escape($db->sanitize($tmpescaped, 1, 0)).')';
12138 //} else {
12139 // $tmpescaped = $db->escape($db->sanitize($tmpescaped, 1));
12140 //}
12141 } elseif ($operator == 'LIKE' || $operator == 'NOT LIKE') {
12142 if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12143 $tmpescaped = $regbis[1];
12144 }
12145 //$tmpescaped = "'".$db->escapeforlike($db->escape($regbis[1]))."'";
12146 $tmpescaped = "'".$db->escape($tmpescaped)."'"; // We do not escape the _ and % so the like will works
12147 } elseif (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12148 $tmpescaped = "'".$db->escape($regbis[1])."'";
12149 } else {
12150 if (strtoupper($tmpescaped) == 'NULL') {
12151 $tmpescaped = 'NULL';
12152 } elseif (is_int($tmpescaped)) {
12153 $tmpescaped = (int) $tmpescaped;
12154 } else {
12155 $tmpescaped = (float) $tmpescaped;
12156 }
12157 }
12158
12159 return '('.$db->escape($operand).' '.strtoupper($operator).' '.$tmpescaped.')';
12160}
12161
12162
12171function getTimelineIcon($actionstatic, &$histo, $key)
12172{
12173 global $conf, $langs;
12174 $out = '<!-- timeline icon -->'."\n";
12175 $iconClass = 'fa fa-comments';
12176 $img_picto = '';
12177 $colorClass = '';
12178 $pictoTitle = '';
12179
12180 if ($histo[$key]['percent'] == -1) {
12181 $colorClass = 'timeline-icon-not-applicble';
12182 $pictoTitle = $langs->trans('StatusNotApplicable');
12183 } elseif ($histo[$key]['percent'] == 0) {
12184 $colorClass = 'timeline-icon-todo';
12185 $pictoTitle = $langs->trans('StatusActionToDo').' (0%)';
12186 } elseif ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100) {
12187 $colorClass = 'timeline-icon-in-progress';
12188 $pictoTitle = $langs->trans('StatusActionInProcess').' ('.$histo[$key]['percent'].'%)';
12189 } elseif ($histo[$key]['percent'] >= 100) {
12190 $colorClass = 'timeline-icon-done';
12191 $pictoTitle = $langs->trans('StatusActionDone').' (100%)';
12192 }
12193
12194 if ($actionstatic->code == 'AC_TICKET_CREATE') {
12195 $iconClass = 'fa fa-ticket';
12196 } elseif ($actionstatic->code == 'AC_TICKET_MODIFY') {
12197 $iconClass = 'fa fa-pencilxxx';
12198 } elseif (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12199 $iconClass = 'fa fa-comments';
12200 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12201 $iconClass = 'fa fa-mask';
12202 } elseif (!empty($conf->global->AGENDA_USE_EVENT_TYPE)) {
12203 if ($actionstatic->type_picto) {
12204 $img_picto = img_picto('', $actionstatic->type_picto);
12205 } else {
12206 if ($actionstatic->type_code == 'AC_RDV') {
12207 $iconClass = 'fa fa-handshake';
12208 } elseif ($actionstatic->type_code == 'AC_TEL') {
12209 $iconClass = 'fa fa-phone';
12210 } elseif ($actionstatic->type_code == 'AC_FAX') {
12211 $iconClass = 'fa fa-fax';
12212 } elseif ($actionstatic->type_code == 'AC_EMAIL') {
12213 $iconClass = 'fa fa-envelope';
12214 } elseif ($actionstatic->type_code == 'AC_INT') {
12215 $iconClass = 'fa fa-shipping-fast';
12216 } elseif ($actionstatic->type_code == 'AC_OTH_AUTO') {
12217 $iconClass = 'fa fa-robot';
12218 } elseif (!preg_match('/_AUTO/', $actionstatic->type_code)) {
12219 $iconClass = 'fa fa-robot';
12220 }
12221 }
12222 }
12223
12224 $out .= '<i class="'.$iconClass.' '.$colorClass.'" title="'.$pictoTitle.'">'.$img_picto.'</i>'."\n";
12225 return $out;
12226}
12227
12234function getActionCommEcmList($object)
12235{
12236 global $conf, $db;
12237
12238 $documents = array();
12239
12240 $sql = 'SELECT ecm.rowid as id, ecm.src_object_type, ecm.src_object_id, ecm.filepath, ecm.filename';
12241 $sql .= ' FROM '.MAIN_DB_PREFIX.'ecm_files ecm';
12242 $sql .= " WHERE ecm.filepath = 'agenda/".((int) $object->id)."'";
12243 //$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
12244 $sql .= ' ORDER BY ecm.position ASC';
12245
12246 $resql = $db->query($sql);
12247 if ($resql) {
12248 if ($db->num_rows($resql)) {
12249 while ($obj = $db->fetch_object($resql)) {
12250 $documents[$obj->id] = $obj;
12251 }
12252 }
12253 }
12254
12255 return $documents;
12256}
12257
12258
12259
12277function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
12278{
12279 global $user, $conf;
12280 global $form;
12281
12282 global $param, $massactionbutton;
12283
12284 dol_include_once('/comm/action/class/actioncomm.class.php');
12285
12286 // Check parameters
12287 if (!is_object($filterobj) && !is_object($objcon)) {
12288 dol_print_error('', 'BadParameter');
12289 }
12290
12291 $histo = array();
12292 $numaction = 0;
12293 $now = dol_now();
12294
12295 $sortfield_list = explode(',', $sortfield);
12296 $sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent');
12297 $sortfield_new_list = array();
12298 foreach ($sortfield_list as $sortfield_value) {
12299 $sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)];
12300 }
12301 $sortfield_new = implode(',', $sortfield_new_list);
12302
12303 if (isModEnabled('agenda')) {
12304 // Search histo on actioncomm
12305 if (is_object($objcon) && $objcon->id > 0) {
12306 $sql = "SELECT DISTINCT a.id, a.label as label,";
12307 } else {
12308 $sql = "SELECT a.id, a.label as label,";
12309 }
12310 $sql .= " a.datep as dp,";
12311 $sql .= " a.note as message,";
12312 $sql .= " a.datep2 as dp2,";
12313 $sql .= " a.percent as percent, 'action' as type,";
12314 $sql .= " a.fk_element, a.elementtype,";
12315 $sql .= " a.fk_contact,";
12316 $sql .= " a.email_from as msg_from,";
12317 $sql .= " c.code as acode, c.libelle as alabel, c.picto as apicto,";
12318 $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";
12319 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12320 $sql .= ", sp.lastname, sp.firstname";
12321 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12322 $sql .= ", m.lastname, m.firstname";
12323 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12324 $sql .= ", o.ref";
12325 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12326 $sql .= ", o.ref";
12327 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12328 $sql .= ", o.ref";
12329 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12330 $sql .= ", o.ref";
12331 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12332 $sql .= ", o.ref";
12333 }
12334 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
12335 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
12336 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
12337
12338 $force_filter_contact = false;
12339 if (is_object($objcon) && $objcon->id > 0) {
12340 $force_filter_contact = true;
12341 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
12342 $sql .= " AND r.element_type = '".$db->escape($objcon->table_element)."' AND r.fk_element = ".((int) $objcon->id);
12343 }
12344
12345 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12346 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
12347 } elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
12348 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er";
12349 $sql .= " ON er.resource_type = 'dolresource'";
12350 $sql .= " AND er.element_id = a.id";
12351 $sql .= " AND er.resource_id = ".((int) $filterobj->id);
12352 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12353 $sql .= ", ".MAIN_DB_PREFIX."adherent as m";
12354 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12355 $sql .= ", ".MAIN_DB_PREFIX."commande_fournisseur as o";
12356 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12357 $sql .= ", ".MAIN_DB_PREFIX."product as o";
12358 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12359 $sql .= ", ".MAIN_DB_PREFIX."ticket as o";
12360 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12361 $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o";
12362 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12363 $sql .= ", ".MAIN_DB_PREFIX."contrat as o";
12364 }
12365
12366 $sql .= " WHERE a.entity IN (".getEntity('agenda').")";
12367 if ($force_filter_contact === false) {
12368 if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) {
12369 $sql .= " AND a.fk_soc = ".((int) $filterobj->id);
12370 } elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) {
12371 $sql .= " AND a.fk_project = ".((int) $filterobj->id);
12372 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12373 $sql .= " AND a.fk_element = m.rowid AND a.elementtype = 'member'";
12374 if ($filterobj->id) {
12375 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12376 }
12377 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12378 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'order_supplier'";
12379 if ($filterobj->id) {
12380 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12381 }
12382 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12383 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
12384 if ($filterobj->id) {
12385 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12386 }
12387 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12388 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'ticket'";
12389 if ($filterobj->id) {
12390 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12391 }
12392 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12393 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'bom'";
12394 if ($filterobj->id) {
12395 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12396 }
12397 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12398 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'contract'";
12399 if ($filterobj->id) {
12400 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12401 }
12402 }
12403 }
12404
12405 // Condition on actioncode
12406 if (!empty($actioncode)) {
12407 if (empty($conf->global->AGENDA_USE_EVENT_TYPE)) {
12408 if ($actioncode == 'AC_NON_AUTO') {
12409 $sql .= " AND c.type != 'systemauto'";
12410 } elseif ($actioncode == 'AC_ALL_AUTO') {
12411 $sql .= " AND c.type = 'systemauto'";
12412 } else {
12413 if ($actioncode == 'AC_OTH') {
12414 $sql .= " AND c.type != 'systemauto'";
12415 } elseif ($actioncode == 'AC_OTH_AUTO') {
12416 $sql .= " AND c.type = 'systemauto'";
12417 }
12418 }
12419 } else {
12420 if ($actioncode == 'AC_NON_AUTO') {
12421 $sql .= " AND c.type != 'systemauto'";
12422 } elseif ($actioncode == 'AC_ALL_AUTO') {
12423 $sql .= " AND c.type = 'systemauto'";
12424 } else {
12425 $sql .= " AND c.code = '".$db->escape($actioncode)."'";
12426 }
12427 }
12428 }
12429 if ($donetodo == 'todo') {
12430 $sql .= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
12431 } elseif ($donetodo == 'done') {
12432 $sql .= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
12433 }
12434 if (is_array($filters) && $filters['search_agenda_label']) {
12435 $sql .= natural_search('a.label', $filters['search_agenda_label']);
12436 }
12437 }
12438
12439 // Add also event from emailings. TODO This should be replaced by an automatic event ? May be it's too much for very large emailing.
12440 if (isModEnabled('mailing') && !empty($objcon->email)
12441 && (empty($actioncode) || $actioncode == 'AC_OTH_AUTO' || $actioncode == 'AC_EMAILING')) {
12442 $langs->load("mails");
12443
12444 $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";
12445 $sql2 .= ", null as fk_element, '' as elementtype, null as contact_id";
12446 $sql2 .= ", 'AC_EMAILING' as acode, '' as alabel, '' as apicto";
12447 $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
12448 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12449 $sql2 .= ", '' as lastname, '' as firstname";
12450 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12451 $sql2 .= ", '' as lastname, '' as firstname";
12452 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12453 $sql2 .= ", '' as ref";
12454 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12455 $sql2 .= ", '' as ref";
12456 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12457 $sql2 .= ", '' as ref";
12458 }
12459 $sql2 .= " FROM ".MAIN_DB_PREFIX."mailing as m, ".MAIN_DB_PREFIX."mailing_cibles as mc, ".MAIN_DB_PREFIX."user as u";
12460 $sql2 .= " WHERE mc.email = '".$db->escape($objcon->email)."'"; // Search is done on email.
12461 $sql2 .= " AND mc.statut = 1";
12462 $sql2 .= " AND u.rowid = m.fk_user_valid";
12463 $sql2 .= " AND mc.fk_mailing=m.rowid";
12464 }
12465
12466 if (!empty($sql) && !empty($sql2)) {
12467 $sql = $sql." UNION ".$sql2;
12468 } elseif (empty($sql) && !empty($sql2)) {
12469 $sql = $sql2;
12470 }
12471
12472 // TODO Add limit in nb of results
12473 if ($sql) { // May not be defined if module Agenda is not enabled and mailing module disabled too
12474 $sql .= $db->order($sortfield_new, $sortorder);
12475
12476 dol_syslog("function.lib::show_actions_messaging", LOG_DEBUG);
12477 $resql = $db->query($sql);
12478 if ($resql) {
12479 $i = 0;
12480 $num = $db->num_rows($resql);
12481
12482 while ($i < $num) {
12483 $obj = $db->fetch_object($resql);
12484
12485 if ($obj->type == 'action') {
12486 $contactaction = new ActionComm($db);
12487 $contactaction->id = $obj->id;
12488 $result = $contactaction->fetchResources();
12489 if ($result < 0) {
12490 dol_print_error($db);
12491 setEventMessage("actions.lib::show_actions_messaging Error fetch ressource", 'errors');
12492 }
12493
12494 //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
12495 //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
12496 $tododone = '';
12497 if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && $obj->dp > $now)) {
12498 $tododone = 'todo';
12499 }
12500
12501 $histo[$numaction] = array(
12502 'type'=>$obj->type,
12503 'tododone'=>$tododone,
12504 'id'=>$obj->id,
12505 'datestart'=>$db->jdate($obj->dp),
12506 'dateend'=>$db->jdate($obj->dp2),
12507 'note'=>$obj->label,
12508 'message'=>$obj->message,
12509 'percent'=>$obj->percent,
12510
12511 'userid'=>$obj->user_id,
12512 'login'=>$obj->user_login,
12513 'userfirstname'=>$obj->user_firstname,
12514 'userlastname'=>$obj->user_lastname,
12515 'userphoto'=>$obj->user_photo,
12516 'msg_from'=>$obj->msg_from,
12517
12518 'contact_id'=>$obj->fk_contact,
12519 'socpeopleassigned' => $contactaction->socpeopleassigned,
12520 'lastname' => (empty($obj->lastname) ? '' : $obj->lastname),
12521 'firstname' => (empty($obj->firstname) ? '' : $obj->firstname),
12522 'fk_element'=>$obj->fk_element,
12523 'elementtype'=>$obj->elementtype,
12524 // Type of event
12525 'acode'=>$obj->acode,
12526 'alabel'=>$obj->alabel,
12527 'libelle'=>$obj->alabel, // deprecated
12528 'apicto'=>$obj->apicto
12529 );
12530 } else {
12531 $histo[$numaction] = array(
12532 'type'=>$obj->type,
12533 'tododone'=>'done',
12534 'id'=>$obj->id,
12535 'datestart'=>$db->jdate($obj->dp),
12536 'dateend'=>$db->jdate($obj->dp2),
12537 'note'=>$obj->label,
12538 'message'=>$obj->message,
12539 'percent'=>$obj->percent,
12540 'acode'=>$obj->acode,
12541
12542 'userid'=>$obj->user_id,
12543 'login'=>$obj->user_login,
12544 'userfirstname'=>$obj->user_firstname,
12545 'userlastname'=>$obj->user_lastname,
12546 'userphoto'=>$obj->user_photo
12547 );
12548 }
12549
12550 $numaction++;
12551 $i++;
12552 }
12553 } else {
12554 dol_print_error($db);
12555 }
12556 }
12557
12558 // Set $out to show events
12559 $out = '';
12560
12561 if (!isModEnabled('agenda')) {
12562 $langs->loadLangs(array("admin", "errors"));
12563 $out = info_admin($langs->trans("WarningModuleXDisabledSoYouMayMissEventHere", $langs->transnoentitiesnoconv("Module2400Name")), 0, 0, 'warning');
12564 }
12565
12566 if (isModEnabled('agenda') || (isModEnabled('mailing') && !empty($objcon->email))) {
12567 $delay_warning = $conf->global->MAIN_DELAY_ACTIONS_TODO * 24 * 60 * 60;
12568
12569 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
12570 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
12571 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
12572 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
12573
12574 $formactions = new FormActions($db);
12575
12576 $actionstatic = new ActionComm($db);
12577 $userstatic = new User($db);
12578 $contactstatic = new Contact($db);
12579 $userGetNomUrlCache = array();
12580 $contactGetNomUrlCache = array();
12581
12582 $out .= '<div class="filters-container" >';
12583 $out .= '<form name="listactionsfilter" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
12584 $out .= '<input type="hidden" name="token" value="'.newToken().'">';
12585
12586 if ($objcon && get_class($objcon) == 'Contact' &&
12587 (is_null($filterobj) || get_class($filterobj) == 'Societe')) {
12588 $out .= '<input type="hidden" name="id" value="'.$objcon->id.'" />';
12589 } else {
12590 $out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
12591 }
12592 if ($filterobj && get_class($filterobj) == 'Societe') {
12593 $out .= '<input type="hidden" name="socid" value="'.$filterobj->id.'" />';
12594 }
12595
12596 $out .= "\n";
12597
12598 $out .= '<div class="div-table-responsive-no-min">';
12599 $out .= '<table class="noborder borderbottom centpercent">';
12600
12601 $out .= '<tr class="liste_titre">';
12602
12603 // Action column
12604 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
12605 $out .= '<th class="liste_titre width50 middle">';
12606 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
12607 $out .= $searchpicto;
12608 $out .= '</th>';
12609 }
12610
12611 $out .= getTitleFieldOfList('Date', 0, $_SERVER["PHP_SELF"], 'a.datep', '', $param, '', $sortfield, $sortorder, '')."\n";
12612
12613 $out .= '<th class="liste_titre"><strong class="hideonsmartphone">'.$langs->trans("Search").' : </strong></th>';
12614 if ($donetodo) {
12615 $out .= '<th class="liste_titre"></th>';
12616 }
12617 $out .= '<th class="liste_titre">';
12618 $out .= '<span class="fas fa-square inline-block fawidth30" style=" color: #ddd;" title="'.$langs->trans("ActionType").'"></span>';
12619 //$out .= img_picto($langs->trans("Type"), 'type');
12620 $out .= $formactions->select_type_actions($actioncode, "actioncode", '', empty($conf->global->AGENDA_USE_EVENT_TYPE) ? 1 : -1, 0, 0, 1, 'minwidth200imp');
12621 $out .= '</th>';
12622 $out .= '<th class="liste_titre maxwidth100onsmartphone">';
12623 $out .= '<input type="text" class="maxwidth100onsmartphone" name="search_agenda_label" value="'.$filters['search_agenda_label'].'" placeholder="'.$langs->trans("Label").'">';
12624 $out .= '</th>';
12625
12626 // Action column
12627 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
12628 $out .= '<th class="liste_titre width50 middle">';
12629 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
12630 $out .= $searchpicto;
12631 $out .= '</th>';
12632 }
12633
12634 $out .= '</tr>';
12635
12636
12637 $out .= '</table>';
12638
12639 $out .= '</form>';
12640 $out .= '</div>';
12641
12642 $out .= "\n";
12643
12644 $out .= '<ul class="timeline">';
12645
12646 if ($donetodo) {
12647 $tmp = '';
12648 if (get_class($filterobj) == 'Societe') {
12649 $tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&socid='.$filterobj->id.'&status=done">';
12650 }
12651 $tmp .= ($donetodo != 'done' ? $langs->trans("ActionsToDoShort") : '');
12652 $tmp .= ($donetodo != 'done' && $donetodo != 'todo' ? ' / ' : '');
12653 $tmp .= ($donetodo != 'todo' ? $langs->trans("ActionsDoneShort") : '');
12654 //$out.=$langs->trans("ActionsToDoShort").' / '.$langs->trans("ActionsDoneShort");
12655 if (get_class($filterobj) == 'Societe') {
12656 $tmp .= '</a>';
12657 }
12658 $out .= getTitleFieldOfList($tmp);
12659 }
12660
12661
12662 //require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
12663 //$caction=new CActionComm($db);
12664 //$arraylist=$caction->liste_array(1, 'code', '', (empty($conf->global->AGENDA_USE_EVENT_TYPE)?1:0), '', 1);
12665
12666 $actualCycleDate = false;
12667
12668 // Loop on each event to show it
12669 foreach ($histo as $key => $value) {
12670 $actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo
12671
12672 $actionstatic->type_picto = $histo[$key]['apicto'];
12673 $actionstatic->type_code = $histo[$key]['acode'];
12674
12675 $url = DOL_URL_ROOT.'/comm/action/card.php?id='.$histo[$key]['id'];
12676
12677 $tmpa = dol_getdate($histo[$key]['datestart'], false);
12678 if ($actualCycleDate !== $tmpa['year'].'-'.$tmpa['yday']) {
12679 $actualCycleDate = $tmpa['year'].'-'.$tmpa['yday'];
12680 $out .= '<!-- timeline time label -->';
12681 $out .= '<li class="time-label">';
12682 $out .= '<span class="timeline-badge-date">';
12683 $out .= dol_print_date($histo[$key]['datestart'], 'daytext', 'tzuserrel', $langs);
12684 $out .= '</span>';
12685 $out .= '</li>';
12686 $out .= '<!-- /.timeline-label -->';
12687 }
12688
12689
12690 $out .= '<!-- timeline item -->'."\n";
12691 $out .= '<li class="timeline-code-'.strtolower($actionstatic->code).'">';
12692
12693 $out .= getTimelineIcon($actionstatic, $histo, $key);
12694
12695 $out .= '<div class="timeline-item">'."\n";
12696
12697 $out .= '<span class="timeline-header-action">';
12698
12699 if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
12700 $out .= '<a class="timeline-btn" href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
12701 $out .= $histo[$key]['id'];
12702 $out .= '</a> ';
12703 } else {
12704 $out .= $actionstatic->getNomUrl(1, -1, 'valignmiddle').' ';
12705 }
12706
12707 if ($user->hasRight('agenda', 'allactions', 'create') ||
12708 (($actionstatic->authorid == $user->id || $actionstatic->userownerid == $user->id) && $user->hasRight('agenda', 'myactions', 'create'))) {
12709 $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>';
12710 }
12711
12712 $out .= '</span>';
12713 // Date
12714 $out .= '<span class="time"><i class="fa fa-clock-o valignmiddle"></i> <span class="valignmiddle">';
12715 $out .= dol_print_date($histo[$key]['datestart'], 'dayhour', 'tzuserrel');
12716 if ($histo[$key]['dateend'] && $histo[$key]['dateend'] != $histo[$key]['datestart']) {
12717 $tmpa = dol_getdate($histo[$key]['datestart'], true);
12718 $tmpb = dol_getdate($histo[$key]['dateend'], true);
12719 if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
12720 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'hour', 'tzuserrel');
12721 } else {
12722 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'dayhour', 'tzuserrel');
12723 }
12724 }
12725 $late = 0;
12726 if ($histo[$key]['percent'] == 0 && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12727 $late = 1;
12728 }
12729 if ($histo[$key]['percent'] == 0 && !$histo[$key]['datestart'] && $histo[$key]['dateend'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12730 $late = 1;
12731 }
12732 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && $histo[$key]['dateend'] && $histo[$key]['dateend'] < ($now - $delay_warning)) {
12733 $late = 1;
12734 }
12735 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && !$histo[$key]['dateend'] && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12736 $late = 1;
12737 }
12738 if ($late) {
12739 $out .= img_warning($langs->trans("Late")).' ';
12740 }
12741 $out .= "</span></span>\n";
12742
12743 // Ref
12744 $out .= '<h3 class="timeline-header">';
12745
12746 // Author of event
12747 $out .= '<div class="messaging-author inline-block tdoverflowmax150 valignmiddle marginrightonly">';
12748 if ($histo[$key]['userid'] > 0) {
12749 if (!isset($userGetNomUrlCache[$histo[$key]['userid']])) { // is in cache ?
12750 $userstatic->fetch($histo[$key]['userid']);
12751 $userGetNomUrlCache[$histo[$key]['userid']] = $userstatic->getNomUrl(-1, '', 0, 0, 16, 0, 'firstelselast', '');
12752 }
12753 $out .= $userGetNomUrlCache[$histo[$key]['userid']];
12754 } elseif (!empty($histo[$key]['msg_from']) && $actionstatic->code == 'TICKET_MSG') {
12755 if (!isset($contactGetNomUrlCache[$histo[$key]['msg_from']])) {
12756 if ($contactstatic->fetch(0, null, '', $histo[$key]['msg_from']) > 0) {
12757 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $contactstatic->getNomUrl(-1, '', 16);
12758 } else {
12759 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $histo[$key]['msg_from'];
12760 }
12761 }
12762 $out .= $contactGetNomUrlCache[$histo[$key]['msg_from']];
12763 }
12764 $out .= '</div>';
12765
12766 // Title
12767 $libelle = '';
12768 $out .= ' <div class="messaging-title inline-block">';
12769
12770 if (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12771 $out .= $langs->trans('TicketNewMessage');
12772 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12773 $out .= $langs->trans('TicketNewMessage').' <em>('.$langs->trans('Private').')</em>';
12774 } elseif (isset($histo[$key]['type'])) {
12775 if ($histo[$key]['type'] == 'action') {
12776 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
12777 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : $histo[$key]['alabel']);
12778 $libelle = $histo[$key]['note'];
12779 $actionstatic->id = $histo[$key]['id'];
12780 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12781 } elseif ($histo[$key]['type'] == 'mailing') {
12782 $out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
12783 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
12784 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : 'Send mass mailing');
12785 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12786 } else {
12787 $libelle .= $histo[$key]['note'];
12788 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12789 }
12790 }
12791
12792 $out .= '</div>';
12793
12794 $out .= '</h3>';
12795
12796 if (!empty($histo[$key]['message'] && $histo[$key]['message'] != $libelle)
12797 && $actionstatic->code != 'AC_TICKET_CREATE'
12798 && $actionstatic->code != 'AC_TICKET_MODIFY'
12799 ) {
12800 $out .= '<div class="timeline-body">';
12801 $out .= $histo[$key]['message'];
12802 $out .= '</div>';
12803 }
12804
12805 // Timeline footer
12806 $footer = '';
12807
12808 // Contact for this action
12809 if (isset($histo[$key]['socpeopleassigned']) && is_array($histo[$key]['socpeopleassigned']) && count($histo[$key]['socpeopleassigned']) > 0) {
12810 $contactList = '';
12811 foreach ($histo[$key]['socpeopleassigned'] as $cid => $Tab) {
12812 $contact = new Contact($db);
12813 $result = $contact->fetch($cid);
12814
12815 if ($result < 0) {
12816 dol_print_error($db, $contact->error);
12817 }
12818
12819 if ($result > 0) {
12820 $contactList .= !empty($contactList) ? ', ' : '';
12821 $contactList .= $contact->getNomUrl(1);
12822 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
12823 if (!empty($contact->phone_pro)) {
12824 $contactList .= '('.dol_print_phone($contact->phone_pro).')';
12825 }
12826 }
12827 }
12828 }
12829
12830 $footer .= $langs->trans('ActionOnContact').' : '.$contactList;
12831 } elseif (empty($objcon->id) && isset($histo[$key]['contact_id']) && $histo[$key]['contact_id'] > 0) {
12832 $contact = new Contact($db);
12833 $result = $contact->fetch($histo[$key]['contact_id']);
12834
12835 if ($result < 0) {
12836 dol_print_error($db, $contact->error);
12837 }
12838
12839 if ($result > 0) {
12840 $footer .= $contact->getNomUrl(1);
12841 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
12842 if (!empty($contact->phone_pro)) {
12843 $footer .= '('.dol_print_phone($contact->phone_pro).')';
12844 }
12845 }
12846 }
12847 }
12848
12849 $documents = getActionCommEcmList($actionstatic);
12850 if (!empty($documents)) {
12851 $footer .= '<div class="timeline-documents-container">';
12852 foreach ($documents as $doc) {
12853 $footer .= '<span id="document_'.$doc->id.'" class="timeline-documents" ';
12854 $footer .= ' data-id="'.$doc->id.'" ';
12855 $footer .= ' data-path="'.$doc->filepath.'"';
12856 $footer .= ' data-filename="'.dol_escape_htmltag($doc->filename).'" ';
12857 $footer .= '>';
12858
12859 $filePath = DOL_DATA_ROOT.'/'.$doc->filepath.'/'.$doc->filename;
12860 $mime = dol_mimetype($filePath);
12861 $file = $actionstatic->id.'/'.$doc->filename;
12862 $thumb = $actionstatic->id.'/thumbs/'.substr($doc->filename, 0, strrpos($doc->filename, '.')).'_mini'.substr($doc->filename, strrpos($doc->filename, '.'));
12863 $doclink = dol_buildpath('document.php', 1).'?modulepart=actions&attachment=0&file='.urlencode($file).'&entity='.$conf->entity;
12864 $viewlink = dol_buildpath('viewimage.php', 1).'?modulepart=actions&file='.urlencode($thumb).'&entity='.$conf->entity;
12865
12866 $mimeAttr = ' mime="'.$mime.'" ';
12867 $class = '';
12868 if (in_array($mime, array('image/png', 'image/jpeg', 'application/pdf'))) {
12869 $class .= ' documentpreview';
12870 }
12871
12872 $footer .= '<a href="'.$doclink.'" class="btn-link '.$class.'" target="_blank" rel="noopener noreferrer" '.$mimeAttr.' >';
12873 $footer .= img_mime($filePath).' '.$doc->filename;
12874 $footer .= '</a>';
12875
12876 $footer .= '</span>';
12877 }
12878 $footer .= '</div>';
12879 }
12880
12881 if (!empty($footer)) {
12882 $out .= '<div class="timeline-footer">'.$footer.'</div>';
12883 }
12884
12885 $out .= '</div>'."\n"; // end timeline-item
12886
12887 $out .= '</li>';
12888 $out .= '<!-- END timeline item -->';
12889
12890 $i++;
12891 }
12892
12893 $out .= "</ul>\n";
12894
12895 if (empty($histo)) {
12896 $out .= '<span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span>';
12897 }
12898 }
12899
12900 if ($noprint) {
12901 return $out;
12902 } else {
12903 print $out;
12904 }
12905}
12906
12917function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto')
12918{
12919 if ($hourTime === 'getpost') {
12920 $hour = GETPOSTINT($prefix . 'hour');
12921 $minute = GETPOSTINT($prefix . 'minute');
12922 $second = GETPOSTINT($prefix . 'second');
12923 } elseif (preg_match('/^(\d\d):(\d\d):(\d\d)$/', $hourTime, $m)) {
12924 $hour = intval($m[1]);
12925 $minute = intval($m[2]);
12926 $second = intval($m[3]);
12927 } else {
12928 $hour = $minute = $second = 0;
12929 }
12930 // normalize out of range values
12931 $hour = min($hour, 23);
12932 $minute = min($minute, 59);
12933 $second = min($second, 59);
12934 return dol_mktime($hour, $minute, $second, GETPOSTINT($prefix . 'month'), GETPOSTINT($prefix . 'day'), GETPOSTINT($prefix . 'year'), $gm);
12935}
12936
12948function buildParamDate($prefix, $timestamp = null, $hourTime = '', $gm = 'auto')
12949{
12950 if ($timestamp === null) $timestamp = GETPOSTDATE($prefix, $hourTime, $gm);
12951 $TParam = array(
12952 $prefix . 'day' => intval(dol_print_date($timestamp, '%d')),
12953 $prefix . 'month' => intval(dol_print_date($timestamp, '%m')),
12954 $prefix . 'year' => intval(dol_print_date($timestamp, '%Y')),
12955 );
12956 if ($hourTime === 'getpost' || ($timestamp !== null && dol_print_date($timestamp, '%H:%M:%S') !== '00:00:00')) {
12957 $TParam = array_merge($TParam, array(
12958 $prefix . 'hour' => intval(dol_print_date($timestamp, '%H')),
12959 $prefix . 'minute' => intval(dol_print_date($timestamp, '%M')),
12960 $prefix . 'second' => intval(dol_print_date($timestamp, '%S'))
12961 ));
12962 }
12963
12964 return '&' . http_build_query($TParam);
12965}
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.
finishSimpleTable($addLineBreak=false)
Add the correct HTML close tags for "startSimpleTable(...)" (use after the last table line)
startSimpleTable($header, $link="", $arguments="", $emptyRows=0, $number=-1)
Start a table with headers and a optinal clickable number (don't forget to use "finishSimpleTable()" ...
getLanguageCodeFromCountryCode($countrycode)
Return default language from country code.
setEntity($currentobject)
Set entity id to use when to create an object.
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formated for view output Used into pdf and HTML pages.
dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks=array())
Show social network link.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
dol_ucfirst($string, $encoding="UTF-8")
Convert first character of the first word of a string to upper.
img_right($titlealt='default', $selected=0, $moreatt='')
Show right arrow logo.
load_fiche_titre($titre, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
img_help($usehelpcursor=1, $usealttitle=1)
Show help logo with cursor "?".
dol_strtolower($string, $encoding="UTF-8")
Convert a string to lower.
showValueWithClipboardCPButton($valuetocopy, $showonlyonhover=1, $texttoshow='')
Create a button to copy $valuetocopy in the clipboard (for copy and paste feature).
dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto='UTF-8')
This function is called to decode a HTML string (it decodes entities and br tags)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
img_left($titlealt='default', $selected=0, $moreatt='')
Show left arrow logo.
dol_print_ip($ip, $mode=0)
Return an IP formated to be shown on screen.
img_delete($titlealt='default', $other='class="pictodelete"', $morecss='')
Show delete logo.
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
GETPOSTINT($paramname, $method=0)
Return value of a param into GET or POST supervariable.
isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
Function to test if an entry is enabled or not.
dolGetFirstLineOfText($text, $nboflines=1, $charset='UTF-8')
Return first line of text.
getDolUserInt($key, $default=0, $tmpuser=null)
Return Dolibarr user constant int value.
yn($yesno, $case=1, $color=0)
Return yes or no in current language.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0)
Show tabs of a record.
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
isASecretKey($keyname)
Return if string has a name dedicated to store a secret.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
print_fleche_navigation($page, $file, $options='', $nextpage=0, $betweenarrows='', $afterarrows='', $limit=-1, $totalnboflines=0, $hideselectlimit=0, $beforearrows='', $hidenavigation=0)
Function to show navigation arrows into lists.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
get_date_range($date_start, $date_end, $format='', $outputlangs='', $withparenthesis=1)
Format output for start and end date.
get_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Get formated error messages to output (Used to show messages on html output).
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
roundUpToNextMultiple($n, $x=5)
Round to next multiple.
dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled='', $morecss='classlink button bordertransp', $jsonopen='', $backtopagejsfields='', $accesskey='')
Return HTML code to output a button to open a dialog popup box.
dol_user_country()
Return country code for current user.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0)
Show a picto called object_picto (generic function)
dol_format_address($object, $withcountry=0, $sep="\n", $outputlangs='', $mode=0, $extralangcode='')
Return a formated address (part address/zip/town/state) according to country rules.
isHTTPS()
Return if we are using a HTTPS connexion Check HTTPS (no way to be modified by user but may be empty ...
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
picto_required()
Return picto saying a field is required.
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
img_action($titlealt, $numaction, $picto='', $moreatt='')
Show logo action.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0)
Set event message in dol_events session object.
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
GETPOSTDATE($prefix, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
printCommonFooter($zone='private')
Print common footer : conf->global->MAIN_HTML_FOOTER js for switch of menu hider js for conf->global-...
checkVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
img_down($titlealt='default', $selected=0, $moreclass='')
Show down arrow logo.
getTaxesFromId($vatrate, $buyer=null, $seller=null, $firstparamisid=1)
Get tax (VAT) main information from Id.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
utf8_valid($str)
Check if a string is in UTF8.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
getDolUserString($key, $default='', $tmpuser=null)
Return Dolibarr user constant string value.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
dol_print_email($email, $cid=0, $socid=0, $addlink=0, $max=64, $showinvalid=1, $withpicto=0)
Show EMail link formatted for HTML output.
img_allow($allow, $titlealt='default')
Show tick logo if allowed.
isValidMXRecord($domain)
Return if the domain name has a valid MX record.
GETPOSTISARRAY($paramname, $method=0)
Return true if the parameter $paramname is submit from a POST OR GET as an array.
get_htmloutput_mesg($mesgstring='', $mesgarray='', $style='ok', $keepembedded=0)
Get formated messages to output (Used to show messages on html output).
dol_print_phone($phone, $countrycode='', $cid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0)
Format phone numbers according to country.
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
dol_fiche_head($links=array(), $active='0', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='')
Show tab header of a card.
img_mime($file, $titlealt='', $morecss='')
Show MIME img of a file.
get_localtax_by_third($local)
Get values of localtaxes (1 or 2) for company country for the common vat with the highest value.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into javascript code.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles=1, $removeclassattribute=1, $cleanalsojavascript=0, $allowiframe=0, $allowed_tags=array(), $allowlink=0)
Clean a string to keep only desirable HTML tags.
getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid=0)
Get type and rate of localtaxes for a particular vat rate/country of a thirdparty.
ajax_autoselect($htmlname, $addlink='', $textonlink='Link')
Make content of an input box selected when we click into input field.
img_view($titlealt='default', $float=0, $other='class="valignmiddle"')
Show logo view card.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by second index function, which produces ascending (default) or descending output...
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round=-1, $forceunitoutput='no', $use_short_label=0)
Output a dimension with best unit.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_clone($object, $native=0)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_string_unaccent($str)
Clean a string from all accent characters to be used as ref, login or by dol_sanitizeFileName.
dol_eval($s, $returnvalue=0, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_strftime($fmt, $ts=false, $is_gmt=false)
Format a string.
img_picto_common($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $notitle=0)
Show picto (generic function)
img_search($titlealt='default', $other='')
Show search logo.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags=array('textarea'), $cleanalsosomestyles=0)
Clean a string from some undesirable HTML tags.
isValidPhone($phone)
Return true if phone number syntax is ok TODO Decide what to do with this.
print_liste_field_titre($name, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $tooltip="", $forcenowrapcolumntitle=0)
Show title line of an array.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
img_previous($titlealt='default', $moreatt='')
Show previous logo.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
dol_print_profids($profID, $profIDtype, $countrycode='', $addcpButton=1, $separ='&nbsp;')
Format profIDs according to country.
fieldLabel($langkey, $fieldkey, $fieldrequired=0)
Show a string with the label tag dedicated to the HTML edit field.
getBrowserInfo($user_agent)
Return information about user browser.
dolGetFirstLetters($s, $nbofchar=1)
Return first letters of a strings.
dol_strtoupper($string, $encoding="UTF-8")
Convert a string to upper.
dol_sanitizeUrl($stringtoclean, $type=1)
Clean a string to use it as an URL (into a href or src attribute)
img_printer($titlealt="default", $other='')
Show printer logo.
dol_htmloutput_events($disabledoutputofmessages=0)
Print formated messages to output (Used to show messages on html output).
getTitleFieldOfList($name, $thead=0, $file="", $field="", $begin="", $moreparam="", $moreattrib="", $sortfield="", $sortorder="", $prefix="", $disablesortlink=0, $tooltip='', $forcenowrapcolumntitle=0)
Get title line of an array.
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the "subst...
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
ascii_check($str)
Check if a string is in ASCII.
make_substitutions($text, $substitutionarray, $outputlangs=null, $converttextinhtmlifnecessary=0)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=>newva...
getArrayOfSocialNetworks()
Get array of social network dictionary.
dolGetButtonTitleSeparator($moreClass="")
Add space between dolGetButtonTitle.
dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes=array("allow", "allowfullscreen", "alt", "class", "contenteditable", "data-html", "frameborder", "height", "href", "id", "name", "src", "style", "target", "title", "width"))
Clean a string from some undesirable HTML tags.
num2Alpha($n)
Return a numeric value into an Excel like column number.
dol_size($size, $type='')
Optimize a size for some browsers (phone, smarphone, ...)
img_split($titlealt='default', $other='class="pictosplit"')
Show split logo.
img_pdf($titlealt='default', $size=3)
Show pdf logo.
dolGetCountryCodeFromIp($ip)
Return a country code from IP.
dol_textishtml($msg, $option=0)
Return if a text is a html content.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
colorIsLight($stringcolor)
Return true if the color is light.
readfileLowMemory($fullpath_original_file_osencoded, $method=-1)
Return a file on output using a low memory.
dolIsAllowedForPreview($file)
Return if a file is qualified for preview.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
dol_shutdown()
Function called at end of web php process.
dol_print_address($address, $htmlid, $element, $id, $noprint=0, $charfornl='')
Format address string.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_print_error_email($prefixcode, $errormessage='', $errormessages=array(), $morecss='error', $email='')
Show a public email and error code to contact if technical error.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='float')
Show Url link.
print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
dol_bc($var, $moreclass='')
Return string to add class property on html element with pair/impair.
print_titre($title)
Show a title.
getElementProperties($element_type)
Get an array with properties of an element.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_string_nounprintableascii($str, $removetabcrlf=1)
Clean a string from all non printable ASCII chars (0x00-0x1F and 0x7F).
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
img_error($titlealt='default')
Show error logo.
getTimelineIcon($actionstatic, &$histo, $key)
Get timeline icon.
dol_htmloutput_mesg($mesgstring='', $mesgarray=array(), $style='ok', $keepembedded=0)
Print formated messages to output (Used to show messages on html output).
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
buildParamDate($prefix, $timestamp=null, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
img_next($titlealt='default', $moreatt='')
Show next logo.
print_date_range($date_start, $date_end, $format='', $outputlangs='')
Format output for start and end date.
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_string_is_good_iso($s, $clean=0)
Check if a string is a correct iso string If not, it will not be considered as HTML encoded even if i...
getNonce()
Return a random string to be used as a nonce value for js.
complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode='add', $filterorigmodule='')
Complete or removed entries into a head array (used to build tabs).
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
Return localtax vat rate of a product in a particular country or default country vat if product is un...
getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $object=null, $include=null)
Return array of possible common substitutions.
dol_nboflines($s, $maxchar=0)
Return nb of lines of a clear text.
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js and dangerous content.
jsonOrUnserialize($stringtodecode)
Decode an encode string.
addSummaryTableLine($tableColumnCount, $num, $nbofloop=0, $total=0, $noneWord="None", $extraRightColumn=false)
Add a summary line to the current open table ("None", "XMoreLines" or "Total xxx")
isValidEmail($address, $acceptsupervisorkey=0, $acceptuserkey=0)
Return true if email syntax is ok.
getActionCommEcmList($object)
getActionCommEcmList
dol_ucwords($string, $encoding="UTF-8")
Convert first character of all the words of a string to upper.
img_edit_add($titlealt='default', $other='')
Show logo +.
verifCond($strToEvaluate)
Verify if condition in string is ok or not.
if(!function_exists( 'utf8_encode')) if(!function_exists('utf8_decode')) if(!function_exists( 'str_starts_with')) if(!function_exists('str_ends_with')) if(!function_exists( 'str_contains')) getMultidirOutput($object, $module='')
Return the full path of the directory where a module (or an object of a module) stores its files.
print_fiche_titre($title, $mesg='', $picto='generic', $pictoisfullpath=0, $id='')
Show a title with picto.
get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice=0)
Return vat rate of a product in a particular country, or default country vat if product is unknown.
dolForgeDummyCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
dol_escape_json($stringtoescape)
Returns text escaped for inclusion into javascript code.
dolForgeCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
getUserRemoteIP()
Return the IP of remote user.
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_validElement($element)
Return if var element is ok.
img_credit_card($brand, $morecss=null)
Return image of a credit card according to its brand name.
dolPrintHTML($s)
Return a string ready to be output on HTML page To use text inside an attribute, use can use only dol...
img_searchclear($titlealt='default', $other='')
Show search logo.
dolPrintLabel($s)
Return a string label ready to be output on HTML content To use text inside an attribute,...
fetchObjectByElement($element_id, $element_type, $element_ref='')
Fetch an object from its id and element_type Inclusion of classes is automatic.
utf8_check($str)
Check if a string is in UTF8.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
show_actions_messaging($conf, $langs, $db, $filterobj, $objcon='', $noprint=0, $actioncode='', $donetodo='done', $filters=array(), $sortfield='a.datep, a.id', $sortorder='DESC')
Show html area with actions in messaging format.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
getDictionaryValue($tablename, $field, $id, $checkentity=false, $rowidfield='rowid')
Return the value of a filed into a dictionary for the record $id.
img_up($titlealt='default', $selected=0, $moreclass='')
Show top arrow logo.
dol_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Print formated error messages to output (Used to show messages on html output).
getFieldErrorIcon($fieldValidationErrorMsg)
get field error icon
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
img_edit_remove($titlealt='default', $other='')
Show logo -.
img_info($titlealt='default')
Show info logo.
getDoliDBInstance($type, $host, $user, $pass, $name, $port)
Return a DoliDB instance (database handler).
dol_sanitizeEmail($stringtoclean)
Clean a string to use it as an Email.
dol_nboflines_bis($text, $maxlinesize=0, $charset='UTF-8')
Return nb of lines of a formated text with and (WARNING: string must not have mixed and br sepa...
dolPrintHTMLForTextArea($s)
Return a string ready to be output on input textarea To use text inside an attribute,...
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
dol_convertToWord($num, $langs, $currency='', $centimes=false)
Function to return a number into a text.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1632
document_preview(file, type, title)
Function show document preview.
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
if(!empty( $_SERVER[ 'MAIN_SHOW_TUNING_INFO'])) realCharForNumericEntities($matches)
Return the real char for a numeric entities.
Definition main.inc.php:63
dol_setcache($memoryid, $data, $expire=0)
Save data into a memory area shared by all users, all sessions on server.
dol_getcache($memoryid)
Read a memory area shared by all users, all sessions on server.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:120
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:123
dolGetRandomBytes($length)
Return a string of random bytes (hexa string) with length = $length fro cryptographic purposes.