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
1822 if (!array_key_exists($level, $logLevels)) {
1823 dol_syslog('Error Bad Log Level '.$level, LOG_ERR);
1824 $level = $logLevels[LOG_ERR];
1825 }
1826 if ($level > getDolGlobalInt('SYSLOG_LEVEL')) {
1827 return;
1828 }
1829
1830 if (empty($conf->global->MAIN_SHOW_PASSWORD_INTO_LOG)) {
1831 $message = preg_replace('/password=\'[^\']*\'/', 'password=\'hidden\'', $message); // protection to avoid to have value of password in log
1832 }
1833
1834 // If adding log inside HTML page is required
1835 if ((!empty($_REQUEST['logtohtml']) && !empty($conf->global->MAIN_ENABLE_LOG_TO_HTML))
1836 || (!empty($user->rights->debugbar->read) && is_object($debugbar))) {
1837 $conf->logbuffer[] = dol_print_date(time(), "%Y-%m-%d %H:%M:%S")." ".$logLevels[$level]." ".$message;
1838 }
1839
1840 //TODO: Remove this. MAIN_ENABLE_LOG_INLINE_HTML should be deprecated and use a log handler dedicated to HTML output
1841 // If html log tag enabled and url parameter log defined, we show output log on HTML comments
1842 if (!empty($conf->global->MAIN_ENABLE_LOG_INLINE_HTML) && !empty($_GET["log"])) {
1843 print "\n\n<!-- Log start\n";
1844 print dol_escape_htmltag($message)."\n";
1845 print "Log end -->\n";
1846 }
1847
1848 $data = array(
1849 'message' => $message,
1850 'script' => (isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF'], '.php') : false),
1851 'level' => $level,
1852 'user' => ((is_object($user) && $user->id) ? $user->login : false),
1853 'ip' => false
1854 );
1855
1856 $remoteip = getUserRemoteIP(); // Get ip when page run on a web server
1857 if (!empty($remoteip)) {
1858 $data['ip'] = $remoteip;
1859 // This is when server run behind a reverse proxy
1860 if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] != $remoteip) {
1861 $data['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'].' -> '.$data['ip'];
1862 } elseif (!empty($_SERVER['HTTP_CLIENT_IP']) && $_SERVER['HTTP_CLIENT_IP'] != $remoteip) {
1863 $data['ip'] = $_SERVER['HTTP_CLIENT_IP'].' -> '.$data['ip'];
1864 }
1865 } elseif (!empty($_SERVER['SERVER_ADDR'])) {
1866 // This is when PHP session is ran inside a web server but not inside a client request (example: init code of apache)
1867 $data['ip'] = $_SERVER['SERVER_ADDR'];
1868 } elseif (!empty($_SERVER['COMPUTERNAME'])) {
1869 // This is when PHP session is ran outside a web server, like from Windows command line (Not always defined, but useful if OS defined it).
1870 $data['ip'] = $_SERVER['COMPUTERNAME'].(empty($_SERVER['USERNAME']) ? '' : '@'.$_SERVER['USERNAME']);
1871 } elseif (!empty($_SERVER['LOGNAME'])) {
1872 // This is when PHP session is ran outside a web server, like from Linux command line (Not always defined, but usefull if OS defined it).
1873 $data['ip'] = '???@'.$_SERVER['LOGNAME'];
1874 }
1875
1876 // Loop on each log handler and send output
1877 foreach ($conf->loghandlers as $loghandlerinstance) {
1878 if ($restricttologhandler && $loghandlerinstance->code != $restricttologhandler) {
1879 continue;
1880 }
1881 $loghandlerinstance->export($data, $suffixinfilename);
1882 }
1883 unset($data);
1884 }
1885
1886 if ($ident > 0) {
1887 foreach ($conf->loghandlers as $loghandlerinstance) {
1888 $loghandlerinstance->setIdent($ident);
1889 }
1890 }
1891}
1892
1909function dolButtonToOpenUrlInDialogPopup($name, $label, $buttonstring, $url, $disabled = '', $morecss = 'classlink button bordertransp', $jsonopen = '', $backtopagejsfields = '', $accesskey = '')
1910{
1911 global $conf;
1912
1913 if (strpos($url, '?') > 0) {
1914 $url .= '&dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1915 } else {
1916 $url .= '?dol_hide_topmenu=1&dol_hide_leftmenu=1&dol_openinpopup='.urlencode($name);
1917 }
1918
1919 $out = '';
1920
1921 $backtopagejsfieldsid = ''; $backtopagejsfieldslabel = '';
1922 if ($backtopagejsfields) {
1923 $tmpbacktopagejsfields = explode(':', $backtopagejsfields);
1924 if (empty($tmpbacktopagejsfields[1])) { // If the part 'keyforpopupid:' is missing, we add $name for it.
1925 $backtopagejsfields = $name.":".$backtopagejsfields;
1926 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[0]);
1927 } else {
1928 $tmp2backtopagejsfields = explode(',', $tmpbacktopagejsfields[1]);
1929 }
1930 $backtopagejsfieldsid = empty($tmp2backtopagejsfields[0]) ? '' : $tmp2backtopagejsfields[0];
1931 $backtopagejsfieldslabel = empty($tmp2backtopagejsfields[1]) ? '' : $tmp2backtopagejsfields[1];
1932 $url .= '&backtopagejsfields='.urlencode($backtopagejsfields);
1933 }
1934
1935 //print '<input type="submit" class="button bordertransp"'.$disabled.' value="'.dol_escape_htmltag($langs->trans("MediaFiles")).'" name="file_manager">';
1936 $out .= '<!-- a link for button to open url into a dialog popup with backtopagejsfields = '.$backtopagejsfields.' -->';
1937 $out .= '<a '.($accesskey ? ' accesskey="'.$accesskey.'"' : '').' class="cursorpointer reposition button_'.$name.($morecss ? ' '.$morecss : '').'"'.$disabled.' title="'.dol_escape_htmltag($label).'"';
1938 if (empty($conf->use_javascript_ajax)) {
1939 $out .= ' href="'.DOL_URL_ROOT.$url.'" target="_blank"';
1940 } elseif ($jsonopen) {
1941 $out .= ' href="#" onclick="'.$jsonopen.'"';
1942 } else {
1943 $out .= ' href="#"';
1944 }
1945 $out .= '>'.$buttonstring.'</a>';
1946
1947 if (!empty($conf->use_javascript_ajax)) {
1948 // Add code to open url using the popup. Add also hidden field to retreive the returned variables
1949 $out .= '<!-- code to open popup and variables to retreive returned variables -->';
1950 $out .= '<div id="idfordialog'.$name.'" class="hidden">div for dialog</div>';
1951 $out .= '<div id="varforreturndialogid'.$name.'" class="hidden">div for returned id</div>';
1952 $out .= '<div id="varforreturndialoglabel'.$name.'" class="hidden">div for returned label</div>';
1953 $out .= '<!-- Add js code to open dialog popup on dialog -->';
1954 $out .= '<script nonce="'.getNonce().'" type="text/javascript">
1955 jQuery(document).ready(function () {
1956 jQuery(".button_'.$name.'").click(function () {
1957 console.log(\'Open popup with jQuery(...).dialog() on URL '.dol_escape_js(DOL_URL_ROOT.$url).'\');
1958 var $tmpdialog = $(\'#idfordialog'.$name.'\');
1959 $tmpdialog.html(\'<iframe class="iframedialog" id="iframedialog'.$name.'" style="border: 0px;" src="'.DOL_URL_ROOT.$url.'" width="100%" height="98%"></iframe>\');
1960 $tmpdialog.dialog({
1961 autoOpen: false,
1962 modal: true,
1963 height: (window.innerHeight - 150),
1964 width: \'80%\',
1965 title: \''.dol_escape_js($label).'\',
1966 open: function (event, ui) {
1967 console.log("open popup name='.$name.', backtopagejsfields='.$backtopagejsfields.'");
1968 },
1969 close: function (event, ui) {
1970 var returnedid = jQuery("#varforreturndialogid'.$name.'").text();
1971 var returnedlabel = jQuery("#varforreturndialoglabel'.$name.'").text();
1972 console.log("popup has been closed. returnedid (js var defined into parent page)="+returnedid+" returnedlabel="+returnedlabel);
1973 if (returnedid != "" && returnedid != "div for returned id") {
1974 jQuery("#'.(empty($backtopagejsfieldsid)?"none":$backtopagejsfieldsid).'").val(returnedid);
1975 }
1976 if (returnedlabel != "" && returnedlabel != "div for returned label") {
1977 jQuery("#'.(empty($backtopagejsfieldslabel)?"none":$backtopagejsfieldslabel).'").val(returnedlabel);
1978 }
1979 }
1980 });
1981
1982 $tmpdialog.dialog(\'open\');
1983 return false;
1984 });
1985 });
1986 </script>';
1987 }
1988 return $out;
1989}
1990
2007function dol_fiche_head($links = array(), $active = '0', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '')
2008{
2009 print dol_get_fiche_head($links, $active, $title, $notab, $picto, $pictoisfullpath, $morehtmlright, $morecss, $limittoshow, $moretabssuffix);
2010}
2011
2028function dol_get_fiche_head($links = array(), $active = '', $title = '', $notab = 0, $picto = '', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limittoshow = 0, $moretabssuffix = '', $dragdropfile = 0)
2029{
2030 global $conf, $langs, $hookmanager;
2031
2032 // Show title
2033 $showtitle = 1;
2034 if (!empty($conf->dol_optimize_smallscreen)) {
2035 $showtitle = 0;
2036 }
2037
2038 $out = "\n".'<!-- dol_fiche_head - dol_get_fiche_head -->';
2039
2040 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2041 $out .= '<div class="tabs'.($picto ? '' : ' nopaddingleft').'" data-role="controlgroup" data-type="horizontal">'."\n";
2042 }
2043
2044 // Show right part
2045 if ($morehtmlright) {
2046 $out .= '<div class="inline-block floatright tabsElem">'.$morehtmlright.'</div>'; // Output right area first so when space is missing, text is in front of tabs and not under.
2047 }
2048
2049 // Show title
2050 if (!empty($title) && $showtitle && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2051 $limittitle = 30;
2052 $out .= '<a class="tabTitle">';
2053 if ($picto) {
2054 $noprefix = $pictoisfullpath;
2055 if (strpos($picto, 'fontawesome_') !== false) {
2056 $noprefix = 1;
2057 }
2058 $out .= img_picto($title, ($noprefix ? '' : 'object_').$picto, '', $pictoisfullpath, 0, 0, '', 'imgTabTitle').' ';
2059 }
2060 $out .= '<span class="tabTitleText">'.dol_escape_htmltag(dol_trunc($title, $limittitle)).'</span>';
2061 $out .= '</a>';
2062 }
2063
2064 // Show tabs
2065
2066 // Define max of key (max may be higher than sizeof because of hole due to module disabling some tabs).
2067 $maxkey = -1;
2068 if (is_array($links) && !empty($links)) {
2069 $keys = array_keys($links);
2070 if (count($keys)) {
2071 $maxkey = max($keys);
2072 }
2073 }
2074
2075 // Show tabs
2076 // if =0 we don't use the feature
2077 if (empty($limittoshow)) {
2078 $limittoshow = (empty($conf->global->MAIN_MAXTABS_IN_CARD) ? 99 : $conf->global->MAIN_MAXTABS_IN_CARD);
2079 }
2080 if (!empty($conf->dol_optimize_smallscreen)) {
2081 $limittoshow = 2;
2082 }
2083
2084 $displaytab = 0;
2085 $nbintab = 0;
2086 $popuptab = 0;
2087 $outmore = '';
2088 for ($i = 0; $i <= $maxkey; $i++) {
2089 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2090 // If active tab is already present
2091 if ($i >= $limittoshow) {
2092 $limittoshow--;
2093 }
2094 }
2095 }
2096
2097 for ($i = 0; $i <= $maxkey; $i++) {
2098 if ((is_numeric($active) && $i == $active) || (!empty($links[$i][2]) && !is_numeric($active) && $active == $links[$i][2])) {
2099 $isactive = true;
2100 } else {
2101 $isactive = false;
2102 }
2103
2104 if ($i < $limittoshow || $isactive) {
2105 // Output entry with a visible tab
2106 $out .= '<div class="inline-block tabsElem'.($isactive ? ' tabsElemActive' : '').((!$isactive && !empty($conf->global->MAIN_HIDE_INACTIVETAB_ON_PRINT)) ? ' hideonprint' : '').'"><!-- id tab = '.(empty($links[$i][2]) ? '' : dol_escape_htmltag($links[$i][2])).' -->';
2107
2108 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2109 if (!empty($links[$i][0])) {
2110 $out .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2111 } else {
2112 $out .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2113 }
2114 } elseif (!empty($links[$i][1])) {
2115 //print "x $i $active ".$links[$i][2]." z";
2116 $out .= '<div class="tab tab'.($isactive?'active':'unactive').'" style="margin: 0 !important">';
2117 if (!empty($links[$i][0])) {
2118 $titletoshow = preg_replace('/<.*$/', '', $links[$i][1]);
2119 $out .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="tab inline-block valignmiddle'.($morecss ? ' '.$morecss : '').(!empty($links[$i][5]) ? ' '.$links[$i][5] : '').'" href="'.$links[$i][0].'" title="'.dol_escape_htmltag($titletoshow).'">';
2120 }
2121 $out .= $links[$i][1];
2122 if (!empty($links[$i][0])) {
2123 $out .= '</a>'."\n";
2124 }
2125 $out .= empty($links[$i][4]) ? '' : $links[$i][4];
2126 $out .= '</div>';
2127 }
2128
2129 $out .= '</div>';
2130 } else {
2131 // Add entry into the combo popup with the other tabs
2132 if (!$popuptab) {
2133 $popuptab = 1;
2134 $outmore .= '<div class="popuptabset wordwrap">'; // The css used to hide/show popup
2135 }
2136 $outmore .= '<div class="popuptab wordwrap" style="display:inherit;">';
2137 if (isset($links[$i][2]) && $links[$i][2] == 'image') {
2138 if (!empty($links[$i][0])) {
2139 $outmore .= '<a class="tabimage'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">'.$links[$i][1].'</a>'."\n";
2140 } else {
2141 $outmore .= '<span class="tabspan">'.$links[$i][1].'</span>'."\n";
2142 }
2143 } elseif (!empty($links[$i][1])) {
2144 $outmore .= '<a'.(!empty($links[$i][2]) ? ' id="'.$links[$i][2].'"' : '').' class="wordwrap inline-block'.($morecss ? ' '.$morecss : '').'" href="'.$links[$i][0].'">';
2145 $outmore .= preg_replace('/([a-z])\|([a-z])/i', '\\1 | \\2', $links[$i][1]); // Replace x|y with x | y to allow wrap on long composed texts.
2146 $outmore .= '</a>'."\n";
2147 }
2148 $outmore .= '</div>';
2149
2150 $nbintab++;
2151 }
2152 $displaytab = $i;
2153 }
2154 if ($popuptab) {
2155 $outmore .= '</div>';
2156 }
2157
2158 if ($popuptab) { // If there is some tabs not shown
2159 $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
2160 $right = ($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right');
2161 $widthofpopup = 200;
2162
2163 $tabsname = $moretabssuffix;
2164 if (empty($tabsname)) {
2165 $tabsname = str_replace("@", "", $picto);
2166 }
2167 $out .= '<div id="moretabs'.$tabsname.'" class="inline-block tabsElem valignmiddle">';
2168 $out .= '<div class="tab"><a href="#" class="tab moretab inline-block tabunactive"><span class="hideonsmartphone">'.$langs->trans("More").'</span>... ('.$nbintab.')</a></div>'; // Do not use "reposition" class in the "More".
2169 $out .= '<div id="moretabsList'.$tabsname.'" style="width: '.$widthofpopup.'px; position: absolute; '.$left.': -999em; text-align: '.$left.'; margin:0px; padding:2px; z-index:10;">';
2170 $out .= $outmore;
2171 $out .= '</div>';
2172 $out .= '<div></div>';
2173 $out .= "</div>\n";
2174
2175 $out .= '<script nonce="'.getNonce().'">';
2176 $out .= "$('#moretabs".$tabsname."').mouseenter( function() {
2177 var x = this.offsetLeft, y = this.offsetTop;
2178 console.log('mouseenter ".$left." x='+x+' y='+y+' window.innerWidth='+window.innerWidth);
2179 if ((window.innerWidth - x) < ".($widthofpopup + 10).") {
2180 $('#moretabsList".$tabsname."').css('".$right."','8px');
2181 }
2182 $('#moretabsList".$tabsname."').css('".$left."','auto');
2183 });
2184 ";
2185 $out .= "$('#moretabs".$tabsname."').mouseleave( function() { console.log('mouseleave ".$left."'); $('#moretabsList".$tabsname."').css('".$left."','-999em');});";
2186 $out .= "</script>";
2187 }
2188
2189 if ((!empty($title) && $showtitle) || $morehtmlright || !empty($links)) {
2190 $out .= "</div>\n";
2191 }
2192
2193 if (!$notab || $notab == -1 || $notab == -2 || $notab == -3) {
2194 $out .= "\n".'<div id="dragDropAreaTabBar" class="tabBar'.($notab == -1 ? '' : ($notab == -2 ? ' tabBarNoTop' : (($notab == -3 ? ' noborderbottom' : '').' tabBarWithBottom'))).'">'."\n";
2195 }
2196 if (!empty($dragdropfile)) {
2197 $out .= dragAndDropFileUpload("dragDropAreaTabBar");
2198 }
2199 $parameters = array('tabname' => $active, 'out' => $out);
2200 $reshook = $hookmanager->executeHooks('printTabsHead', $parameters); // This hook usage is called just before output the head of tabs. Take also a look at "completeTabsHead"
2201 if ($reshook > 0) {
2202 $out = $hookmanager->resPrint;
2203 }
2204
2205 return $out;
2206}
2207
2215function dol_fiche_end($notab = 0)
2216{
2217 print dol_get_fiche_end($notab);
2218}
2219
2226function dol_get_fiche_end($notab = 0)
2227{
2228 if (!$notab || $notab == -1) {
2229 return "\n</div>\n";
2230 } else {
2231 return '';
2232 }
2233}
2234
2254function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '')
2255{
2256 global $conf, $form, $user, $langs, $hookmanager, $action;
2257
2258 $error = 0;
2259
2260 $maxvisiblephotos = 1;
2261 $showimage = 1;
2262 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
2263 $showbarcode = empty($conf->barcode->enabled) ? 0 : (empty($object->barcode) ? 0 : 1);
2264 if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) {
2265 $showbarcode = 0;
2266 }
2267 $modulepart = 'unknown';
2268
2269 if ($object->element == 'societe' || $object->element == 'contact' || $object->element == 'product' || $object->element == 'ticket') {
2270 $modulepart = $object->element;
2271 } elseif ($object->element == 'member') {
2272 $modulepart = 'memberphoto';
2273 } elseif ($object->element == 'user') {
2274 $modulepart = 'userphoto';
2275 }
2276
2277 if (class_exists("Imagick")) {
2278 if ($object->element == 'expensereport' || $object->element == 'propal' || $object->element == 'commande' || $object->element == 'facture' || $object->element == 'supplier_proposal') {
2279 $modulepart = $object->element;
2280 } elseif ($object->element == 'fichinter') {
2281 $modulepart = 'ficheinter';
2282 } elseif ($object->element == 'contrat') {
2283 $modulepart = 'contract';
2284 } elseif ($object->element == 'order_supplier') {
2285 $modulepart = 'supplier_order';
2286 } elseif ($object->element == 'invoice_supplier') {
2287 $modulepart = 'supplier_invoice';
2288 }
2289 }
2290
2291 if ($object->element == 'product') {
2292 $width = 80;
2293 $cssclass = 'photowithmargin photoref';
2294 $showimage = $object->is_photo_available($conf->product->multidir_output[$entity]);
2295 $maxvisiblephotos = (isset($conf->global->PRODUCT_MAX_VISIBLE_PHOTO) ? $conf->global->PRODUCT_MAX_VISIBLE_PHOTO : 5);
2296 if ($conf->browser->layout == 'phone') {
2297 $maxvisiblephotos = 1;
2298 }
2299 if ($showimage) {
2300 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$object->show_photos('product', $conf->product->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, 0, $width, 0, '').'</div>';
2301 } else {
2302 if (!empty($conf->global->PRODUCT_NODISPLAYIFNOPHOTO)) {
2303 $nophoto = '';
2304 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2305 } else { // Show no photo link
2306 $nophoto = '/public/theme/common/nophoto.png';
2307 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><img class="photo'.$modulepart.($cssclass ? ' '.$cssclass : '').'" title="'.dol_escape_htmltag($langs->trans("UploadAnImageToSeeAPhotoHere", $langs->transnoentitiesnoconv("Documents"))).'" alt="No photo"'.($width ? ' style="width: '.$width.'px"' : '').' src="'.DOL_URL_ROOT.$nophoto.'"></div>';
2308 }
2309 }
2310 } elseif ($object->element == 'ticket') {
2311 $width = 80;
2312 $cssclass = 'photoref';
2313 $showimage = $object->is_photo_available($conf->ticket->multidir_output[$entity].'/'.$object->ref);
2314 $maxvisiblephotos = (isset($conf->global->TICKET_MAX_VISIBLE_PHOTO) ? $conf->global->TICKET_MAX_VISIBLE_PHOTO : 2);
2315 if ($conf->browser->layout == 'phone') {
2316 $maxvisiblephotos = 1;
2317 }
2318
2319 if ($showimage) {
2320 $showphoto = $object->show_photos('ticket', $conf->ticket->multidir_output[$entity], 'small', $maxvisiblephotos, 0, 0, 0, $width, 0);
2321 if ($object->nbphoto > 0) {
2322 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$showphoto.'</div>';
2323 } else {
2324 $showimage = 0;
2325 }
2326 }
2327 if (!$showimage) {
2328 if (!empty($conf->global->TICKET_NODISPLAYIFNOPHOTO)) {
2329 $nophoto = '';
2330 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"></div>';
2331 } else { // Show no photo link
2332 $nophoto = img_picto('No photo', 'object_ticket');
2333 $morehtmlleft .= '<!-- No photo to show -->';
2334 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2335 $morehtmlleft .= $nophoto;
2336 $morehtmlleft .= '</div></div>';
2337 }
2338 }
2339 } else {
2340 if ($showimage) {
2341 if ($modulepart != 'unknown') {
2342 $phototoshow = '';
2343 // Check if a preview file is available
2344 if (in_array($modulepart, array('propal', 'commande', 'facture', 'ficheinter', 'contract', 'supplier_order', 'supplier_proposal', 'supplier_invoice', 'expensereport')) && class_exists("Imagick")) {
2345 $objectref = dol_sanitizeFileName($object->ref);
2346 $dir_output = (empty($conf->$modulepart->multidir_output[$entity]) ? $conf->$modulepart->dir_output : $conf->$modulepart->multidir_output[$entity])."/";
2347 if (in_array($modulepart, array('invoice_supplier', 'supplier_invoice'))) {
2348 $subdir = get_exdir($object->id, 2, 0, 1, $object, $modulepart);
2349 $subdir .= ((!empty($subdir) && !preg_match('/\/$/', $subdir)) ? '/' : '').$objectref; // the objectref dir is not included into get_exdir when used with level=2, so we add it at end
2350 } else {
2351 $subdir = get_exdir($object->id, 0, 0, 1, $object, $modulepart);
2352 }
2353 if (empty($subdir)) {
2354 $subdir = 'errorgettingsubdirofobject'; // Protection to avoid to return empty path
2355 }
2356
2357 $filepath = $dir_output.$subdir."/";
2358
2359 $filepdf = $filepath.$objectref.".pdf";
2360 $relativepath = $subdir.'/'.$objectref.'.pdf';
2361
2362 // Define path to preview pdf file (preview precompiled "file.ext" are "file.ext_preview.png")
2363 $fileimage = $filepdf.'_preview.png';
2364 $relativepathimage = $relativepath.'_preview.png';
2365
2366 $pdfexists = file_exists($filepdf);
2367
2368 // If PDF file exists
2369 if ($pdfexists) {
2370 // Conversion du PDF en image png si fichier png non existant
2371 if (!file_exists($fileimage) || (filemtime($fileimage) < filemtime($filepdf))) {
2372 if (empty($conf->global->MAIN_DISABLE_PDF_THUMBS)) { // If you experience trouble with pdf thumb generation and imagick, you can disable here.
2373 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
2374 $ret = dol_convert_file($filepdf, 'png', $fileimage, '0'); // Convert first page of PDF into a file _preview.png
2375 if ($ret < 0) {
2376 $error++;
2377 }
2378 }
2379 }
2380 }
2381
2382 if ($pdfexists && !$error) {
2383 $heightforphotref = 80;
2384 if (!empty($conf->dol_optimize_smallscreen)) {
2385 $heightforphotref = 60;
2386 }
2387 // If the preview file is found
2388 if (file_exists($fileimage)) {
2389 $phototoshow = '<div class="photoref">';
2390 $phototoshow .= '<img height="'.$heightforphotref.'" class="photo photowithborder" src="'.DOL_URL_ROOT.'/viewimage.php?modulepart=apercu'.$modulepart.'&amp;file='.urlencode($relativepathimage).'">';
2391 $phototoshow .= '</div>';
2392 }
2393 }
2394 } elseif (!$phototoshow) { // example if modulepart = 'societe' or 'photo'
2395 $phototoshow .= $form->showphoto($modulepart, $object, 0, 0, 0, 'photowithmargin photoref', 'small', 1, 0, $maxvisiblephotos);
2396 }
2397
2398 if ($phototoshow) {
2399 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">';
2400 $morehtmlleft .= $phototoshow;
2401 $morehtmlleft .= '</div>';
2402 }
2403 }
2404
2405 if (empty($phototoshow)) { // Show No photo link (picto of object)
2406 if ($object->element == 'action') {
2407 $width = 80;
2408 $cssclass = 'photorefcenter';
2409 $nophoto = img_picto('No photo', 'title_agenda');
2410 } else {
2411 $width = 14;
2412 $cssclass = 'photorefcenter';
2413 $picto = $object->picto;
2414 $prefix = 'object_';
2415 if ($object->element == 'project' && !$object->public) {
2416 $picto = 'project'; // instead of projectpub
2417 }
2418 if (strpos($picto, 'fontawesome_') !== false) {
2419 $prefix = '';
2420 }
2421 $nophoto = img_picto('No photo', $prefix.$picto);
2422 }
2423 $morehtmlleft .= '<!-- No photo to show -->';
2424 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref"><div class="photoref">';
2425 $morehtmlleft .= $nophoto;
2426 $morehtmlleft .= '</div></div>';
2427 }
2428 }
2429 }
2430
2431 // Show barcode
2432 if ($showbarcode) {
2433 $morehtmlleft .= '<div class="floatleft inline-block valignmiddle divphotoref">'.$form->showbarcode($object, 100, 'photoref valignmiddle').'</div>';
2434 }
2435
2436 if ($object->element == 'societe') {
2437 if (!empty($conf->use_javascript_ajax) && $user->hasRight('societe', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2438 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'status', 'InActivity', 'ActivityCeased');
2439 } else {
2440 $morehtmlstatus .= $object->getLibStatut(6);
2441 }
2442 } elseif ($object->element == 'product') {
2443 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Sell").') ';
2444 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2445 $morehtmlstatus .= ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
2446 } else {
2447 $morehtmlstatus .= '<span class="statusrefsell">'.$object->getLibStatut(6, 0).'</span>';
2448 }
2449 $morehtmlstatus .= ' &nbsp; ';
2450 //$morehtmlstatus.=$langs->trans("Status").' ('.$langs->trans("Buy").') ';
2451 if (!empty($conf->use_javascript_ajax) && $user->hasRight('produit', 'creer') && !empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
2452 $morehtmlstatus .= ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
2453 } else {
2454 $morehtmlstatus .= '<span class="statusrefbuy">'.$object->getLibStatut(6, 1).'</span>';
2455 }
2456 } elseif (in_array($object->element, array('facture', 'invoice', 'invoice_supplier'))) {
2457 $totalallpayments = $object->getSommePaiement(0);
2458 $totalallpayments += $object->getSumCreditNotesUsed(0);
2459 $totalallpayments += $object->getSumDepositsUsed(0);
2460 $tmptxt = $object->getLibStatut(6, $totalallpayments);
2461 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2462 $tmptxt = $object->getLibStatut(5, $totalallpayments);
2463 }
2464 $morehtmlstatus .= $tmptxt;
2465 } elseif (in_array($object->element, array('chargesociales', 'loan', 'tva'))) {
2466 $tmptxt = $object->getLibStatut(6, $object->totalpaid);
2467 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2468 $tmptxt = $object->getLibStatut(5, $object->totalpaid);
2469 }
2470 $morehtmlstatus .= $tmptxt;
2471 } elseif ($object->element == 'contrat' || $object->element == 'contract') {
2472 if ($object->statut == 0) {
2473 $morehtmlstatus .= $object->getLibStatut(5);
2474 } else {
2475 $morehtmlstatus .= $object->getLibStatut(4);
2476 }
2477 } elseif ($object->element == 'facturerec') {
2478 if ($object->frequency == 0) {
2479 $morehtmlstatus .= $object->getLibStatut(2);
2480 } else {
2481 $morehtmlstatus .= $object->getLibStatut(5);
2482 }
2483 } elseif ($object->element == 'project_task') {
2484 $object->fk_statut = 1;
2485 if ($object->progress > 0) {
2486 $object->fk_statut = 2;
2487 }
2488 if ($object->progress >= 100) {
2489 $object->fk_statut = 3;
2490 }
2491 $tmptxt = $object->getLibStatut(5);
2492 $morehtmlstatus .= $tmptxt; // No status on task
2493 } elseif (method_exists($object, 'getLibStatut')) { // Generic case for status
2494 $tmptxt = $object->getLibStatut(6);
2495 if (empty($tmptxt) || $tmptxt == $object->getLibStatut(3)) {
2496 $tmptxt = $object->getLibStatut(5);
2497 }
2498 $morehtmlstatus .= $tmptxt;
2499 }
2500
2501 // Add if object was dispatched "into accountancy"
2502 if (isModEnabled('accounting') && in_array($object->element, array('bank', 'paiementcharge', 'facture', 'invoice', 'invoice_supplier', 'expensereport', 'payment_various'))) {
2503 // Note: For 'chargesociales', 'salaries'... this is the payments that are dispatched (so element = 'bank')
2504 if (method_exists($object, 'getVentilExportCompta')) {
2505 $accounted = $object->getVentilExportCompta();
2506 $langs->load("accountancy");
2507 $morehtmlstatus .= '</div><div class="statusref statusrefbis"><span class="opacitymedium">'.($accounted > 0 ? $langs->trans("Accounted") : $langs->trans("NotYetAccounted")).'</span>';
2508 }
2509 }
2510
2511 // Add alias for thirdparty
2512 if (!empty($object->name_alias)) {
2513 $morehtmlref .= '<div class="refidno opacitymedium">'.dol_escape_htmltag($object->name_alias).'</div>';
2514 }
2515
2516 // Add label
2517 if (in_array($object->element, array('product', 'bank_account', 'project_task'))) {
2518 if (!empty($object->label)) {
2519 $morehtmlref .= '<div class="refidno opacitymedium">'.$object->label.'</div>';
2520 }
2521 }
2522
2523 // Show address and email
2524 if (method_exists($object, 'getBannerAddress') && !in_array($object->element, array('product', 'bookmark', 'ecm_directories', 'ecm_files'))) {
2525 $moreaddress = $object->getBannerAddress('refaddress', $object);
2526 if ($moreaddress) {
2527 $morehtmlref .= '<div class="refidno refaddress">';
2528 $morehtmlref .= $moreaddress;
2529 $morehtmlref .= '</div>';
2530 }
2531 }
2532 if (!empty($conf->global->MAIN_SHOW_TECHNICAL_ID) && ($conf->global->MAIN_SHOW_TECHNICAL_ID == '1' || preg_match('/'.preg_quote($object->element, '/').'/i', $conf->global->MAIN_SHOW_TECHNICAL_ID)) && !empty($object->id)) {
2533 $morehtmlref .= '<div style="clear: both;"></div>';
2534 $morehtmlref .= '<div class="refidno opacitymedium">';
2535 $morehtmlref .= $langs->trans("TechnicalID").': '.((int) $object->id);
2536 $morehtmlref .= '</div>';
2537 }
2538
2539 $parameters=array('morehtmlref'=>$morehtmlref);
2540 $reshook = $hookmanager->executeHooks('formDolBanner', $parameters, $object, $action);
2541 if ($reshook < 0) {
2542 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
2543 } elseif (empty($reshook)) {
2544 $morehtmlref .= $hookmanager->resPrint;
2545 } elseif ($reshook > 0) {
2546 $morehtmlref = $hookmanager->resPrint;
2547 }
2548
2549
2550 print '<div class="'.($onlybanner ? 'arearefnobottom ' : 'arearef ').'heightref valignmiddle centpercent">';
2551 print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright);
2552 print '</div>';
2553 print '<div class="underrefbanner clearboth"></div>';
2554}
2555
2565function fieldLabel($langkey, $fieldkey, $fieldrequired = 0)
2566{
2567 global $langs;
2568 $ret = '';
2569 if ($fieldrequired) {
2570 $ret .= '<span class="fieldrequired">';
2571 }
2572 $ret .= '<label for="'.$fieldkey.'">';
2573 $ret .= $langs->trans($langkey);
2574 $ret .= '</label>';
2575 if ($fieldrequired) {
2576 $ret .= '</span>';
2577 }
2578 return $ret;
2579}
2580
2588function dol_bc($var, $moreclass = '')
2589{
2590 global $bc;
2591 $ret = ' '.$bc[$var];
2592 if ($moreclass) {
2593 $ret = preg_replace('/class=\"/', 'class="'.$moreclass.' ', $ret);
2594 }
2595 return $ret;
2596}
2597
2611function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs = '', $mode = 0, $extralangcode = '')
2612{
2613 global $conf, $langs, $hookmanager;
2614
2615 $ret = '';
2616 $countriesusingstate = array('AU', 'CA', 'US', 'IN', 'GB', 'ES', 'UK', 'TR', 'CN'); // See also MAIN_FORCE_STATE_INTO_ADDRESS
2617
2618 // See format of addresses on https://en.wikipedia.org/wiki/Address
2619 // Address
2620 if (empty($mode)) {
2621 $ret .= ($extralangcode ? $object->array_languages['address'][$extralangcode] : (empty($object->address) ? '' : preg_replace('/(\r\n|\r|\n)+/', $sep, $object->address)));
2622 }
2623 // Zip/Town/State
2624 if (isset($object->country_code) && in_array($object->country_code, array('AU', 'CA', 'US', 'CN')) || !empty($conf->global->MAIN_FORCE_STATE_INTO_ADDRESS)) {
2625 // US: title firstname name \n address lines \n town, state, zip \n country
2626 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2627 $ret .= (($ret && $town) ? $sep : '').$town;
2628
2629 if (!empty($object->state)) {
2630 $ret .= ($ret ? ($town ? ", " : $sep) : '').$object->state;
2631 }
2632 if (!empty($object->zip)) {
2633 $ret .= ($ret ? (($town || $object->state) ? ", " : $sep) : '').$object->zip;
2634 }
2635 } elseif (isset($object->country_code) && in_array($object->country_code, array('GB', 'UK'))) {
2636 // UK: title firstname name \n address lines \n town state \n zip \n country
2637 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2638 $ret .= ($ret ? $sep : '').$town;
2639 if (!empty($object->state)) {
2640 $ret .= ($ret ? ", " : '').$object->state;
2641 }
2642 if (!empty($object->zip)) {
2643 $ret .= ($ret ? $sep : '').$object->zip;
2644 }
2645 } elseif (isset($object->country_code) && in_array($object->country_code, array('ES', 'TR'))) {
2646 // ES: title firstname name \n address lines \n zip town \n state \n country
2647 $ret .= ($ret ? $sep : '').$object->zip;
2648 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2649 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2650 if (!empty($object->state)) {
2651 $ret .= $sep.$object->state;
2652 }
2653 } elseif (isset($object->country_code) && in_array($object->country_code, array('JP'))) {
2654 // JP: In romaji, title firstname name\n address lines \n [state,] town zip \n country
2655 // See https://www.sljfaq.org/afaq/addresses.html
2656 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2657 $ret .= ($ret ? $sep : '').($object->state ? $object->state.', ' : '').$town.($object->zip ? ' ' : '').$object->zip;
2658 } elseif (isset($object->country_code) && in_array($object->country_code, array('IT'))) {
2659 // IT: title firstname name\n address lines \n zip town state_code \n country
2660 $ret .= ($ret ? $sep : '').$object->zip;
2661 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2662 $ret .= ($town ? (($object->zip ? ' ' : '').$town) : '');
2663 $ret .= (empty($object->state_code) ? '' : (' '.$object->state_code));
2664 } else {
2665 // Other: title firstname name \n address lines \n zip town[, state] \n country
2666 $town = ($extralangcode ? $object->array_languages['town'][$extralangcode] : (empty($object->town) ? '' : $object->town));
2667 $ret .= !empty($object->zip) ? (($ret ? $sep : '').$object->zip) : '';
2668 $ret .= ($town ? (($object->zip ? ' ' : ($ret ? $sep : '')).$town) : '');
2669 if (!empty($object->state) && in_array($object->country_code, $countriesusingstate)) {
2670 $ret .= ($ret ? ", " : '').$object->state;
2671 }
2672 }
2673
2674 if (!is_object($outputlangs)) {
2675 $outputlangs = $langs;
2676 }
2677 if ($withcountry) {
2678 $langs->load("dict");
2679 $ret .= (empty($object->country_code) ? '' : ($ret ? $sep : '').$outputlangs->convToOutputCharset($outputlangs->transnoentitiesnoconv("Country".$object->country_code)));
2680 }
2681 if ($hookmanager) {
2682 $parameters = array('withcountry' => $withcountry, 'sep' => $sep, 'outputlangs' => $outputlangs,'mode' => $mode, 'extralangcode' => $extralangcode);
2683 $reshook = $hookmanager->executeHooks('formatAddress', $parameters, $object);
2684 if ($reshook > 0) {
2685 $ret = '';
2686 }
2687 $ret .= $hookmanager->resPrint;
2688 }
2689
2690 return $ret;
2691}
2692
2693
2694
2703function dol_strftime($fmt, $ts = false, $is_gmt = false)
2704{
2705 if ((abs($ts) <= 0x7FFFFFFF)) { // check if number in 32-bit signed range
2706 return ($is_gmt) ? @gmstrftime($fmt, $ts) : @strftime($fmt, $ts);
2707 } else {
2708 return 'Error date into a not supported range';
2709 }
2710}
2711
2733function dol_print_date($time, $format = '', $tzoutput = 'auto', $outputlangs = '', $encodetooutput = false)
2734{
2735 global $conf, $langs;
2736
2737 // If date undefined or "", we return ""
2738 if (dol_strlen($time) == 0) {
2739 return ''; // $time=0 allowed (it means 01/01/1970 00:00:00)
2740 }
2741
2742 if ($tzoutput === 'auto') {
2743 $tzoutput = (empty($conf) ? 'tzserver' : (isset($conf->tzuserinputkey) ? $conf->tzuserinputkey : 'tzserver'));
2744 }
2745
2746 // Clean parameters
2747 $to_gmt = false;
2748 $offsettz = $offsetdst = 0;
2749 if ($tzoutput) {
2750 $to_gmt = true; // For backward compatibility
2751 if (is_string($tzoutput)) {
2752 if ($tzoutput == 'tzserver') {
2753 $to_gmt = false;
2754 $offsettzstring = @date_default_timezone_get(); // Example 'Europe/Berlin' or 'Indian/Reunion'
2755 $offsettz = 0; // Timezone offset with server timezone (because to_gmt is false), so 0
2756 $offsetdst = 0; // Dst offset with server timezone (because to_gmt is false), so 0
2757 } elseif ($tzoutput == 'tzuser' || $tzoutput == 'tzuserrel') {
2758 $to_gmt = true;
2759 $offsettzstring = (empty($_SESSION['dol_tz_string']) ? 'UTC' : $_SESSION['dol_tz_string']); // Example 'Europe/Berlin' or 'Indian/Reunion'
2760
2761 if (class_exists('DateTimeZone')) {
2762 $user_date_tz = new DateTimeZone($offsettzstring);
2763 $user_dt = new DateTime();
2764 $user_dt->setTimezone($user_date_tz);
2765 $user_dt->setTimestamp($tzoutput == 'tzuser' ? dol_now() : (int) $time);
2766 $offsettz = $user_dt->getOffset(); // should include dst ?
2767 } else { // with old method (The 'tzuser' was processed like the 'tzuserrel')
2768 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60; // Will not be used anymore
2769 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60; // Will not be used anymore
2770 }
2771 }
2772 }
2773 }
2774 if (!is_object($outputlangs)) {
2775 $outputlangs = $langs;
2776 }
2777 if (!$format) {
2778 $format = 'daytextshort';
2779 }
2780
2781 // Do we have to reduce the length of date (year on 2 chars) to save space.
2782 // Note: dayinputnoreduce is same than day but no reduction of year length will be done
2783 $reduceformat = (!empty($conf->dol_optimize_smallscreen) && in_array($format, array('day', 'dayhour'))) ? 1 : 0; // Test on original $format param.
2784 $format = preg_replace('/inputnoreduce/', '', $format); // so format 'dayinputnoreduce' is processed like day
2785 $formatwithoutreduce = preg_replace('/reduceformat/', '', $format);
2786 if ($formatwithoutreduce != $format) {
2787 $format = $formatwithoutreduce;
2788 $reduceformat = 1;
2789 } // so format 'dayreduceformat' is processed like day
2790
2791 // Change predefined format into computer format. If found translation in lang file we use it, otherwise we use default.
2792 // TODO Add format daysmallyear and dayhoursmallyear
2793 if ($format == 'day') {
2794 $format = ($outputlangs->trans("FormatDateShort") != "FormatDateShort" ? $outputlangs->trans("FormatDateShort") : $conf->format_date_short);
2795 } elseif ($format == 'hour') {
2796 $format = ($outputlangs->trans("FormatHourShort") != "FormatHourShort" ? $outputlangs->trans("FormatHourShort") : $conf->format_hour_short);
2797 } elseif ($format == 'hourduration') {
2798 $format = ($outputlangs->trans("FormatHourShortDuration") != "FormatHourShortDuration" ? $outputlangs->trans("FormatHourShortDuration") : $conf->format_hour_short_duration);
2799 } elseif ($format == 'daytext') {
2800 $format = ($outputlangs->trans("FormatDateText") != "FormatDateText" ? $outputlangs->trans("FormatDateText") : $conf->format_date_text);
2801 } elseif ($format == 'daytextshort') {
2802 $format = ($outputlangs->trans("FormatDateTextShort") != "FormatDateTextShort" ? $outputlangs->trans("FormatDateTextShort") : $conf->format_date_text_short);
2803 } elseif ($format == 'dayhour') {
2804 $format = ($outputlangs->trans("FormatDateHourShort") != "FormatDateHourShort" ? $outputlangs->trans("FormatDateHourShort") : $conf->format_date_hour_short);
2805 } elseif ($format == 'dayhoursec') {
2806 $format = ($outputlangs->trans("FormatDateHourSecShort") != "FormatDateHourSecShort" ? $outputlangs->trans("FormatDateHourSecShort") : $conf->format_date_hour_sec_short);
2807 } elseif ($format == 'dayhourtext') {
2808 $format = ($outputlangs->trans("FormatDateHourText") != "FormatDateHourText" ? $outputlangs->trans("FormatDateHourText") : $conf->format_date_hour_text);
2809 } elseif ($format == 'dayhourtextshort') {
2810 $format = ($outputlangs->trans("FormatDateHourTextShort") != "FormatDateHourTextShort" ? $outputlangs->trans("FormatDateHourTextShort") : $conf->format_date_hour_text_short);
2811 } elseif ($format == 'dayhourlog') {
2812 // Format not sensitive to language
2813 $format = '%Y%m%d%H%M%S';
2814 } elseif ($format == 'dayhourlogsmall') {
2815 // Format not sensitive to language
2816 $format = '%y%m%d%H%M';
2817 } elseif ($format == 'dayhourldap') {
2818 $format = '%Y%m%d%H%M%SZ';
2819 } elseif ($format == 'dayhourxcard') {
2820 $format = '%Y%m%dT%H%M%SZ';
2821 } elseif ($format == 'dayxcard') {
2822 $format = '%Y%m%d';
2823 } elseif ($format == 'dayrfc') {
2824 $format = '%Y-%m-%d'; // DATE_RFC3339
2825 } elseif ($format == 'dayhourrfc') {
2826 $format = '%Y-%m-%dT%H:%M:%SZ'; // DATETIME RFC3339
2827 } elseif ($format == 'standard') {
2828 $format = '%Y-%m-%d %H:%M:%S';
2829 }
2830
2831 if ($reduceformat) {
2832 $format = str_replace('%Y', '%y', $format);
2833 $format = str_replace('yyyy', 'yy', $format);
2834 }
2835
2836 // Clean format
2837 if (preg_match('/%b/i', $format)) { // There is some text to translate
2838 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2839 $format = str_replace('%b', '__b__', $format);
2840 $format = str_replace('%B', '__B__', $format);
2841 }
2842 if (preg_match('/%a/i', $format)) { // There is some text to translate
2843 // We inhibate translation to text made by strftime functions. We will use trans instead later.
2844 $format = str_replace('%a', '__a__', $format);
2845 $format = str_replace('%A', '__A__', $format);
2846 }
2847
2848 // Analyze date
2849 $reg = array();
2850 if (preg_match('/^([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])$/i', $time, $reg)) { // Deprecated. Ex: 1970-01-01, 1970-01-01 01:00:00, 19700101010000
2851 dol_print_error('', "Functions.lib::dol_print_date function called with a bad value from page ".$_SERVER["PHP_SELF"]);
2852 return '';
2853 } elseif (preg_match('/^([0-9]+)\-([0-9]+)\-([0-9]+) ?([0-9]+)?:?([0-9]+)?:?([0-9]+)?/i', $time, $reg)) { // Still available to solve problems in extrafields of type date
2854 // This part of code should not be used anymore.
2855 dol_syslog("Functions.lib::dol_print_date function called with a bad value from page ".$_SERVER["PHP_SELF"], LOG_WARNING);
2856 //if (function_exists('debug_print_backtrace')) debug_print_backtrace();
2857 // Date has format 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'
2858 $syear = (!empty($reg[1]) ? $reg[1] : '');
2859 $smonth = (!empty($reg[2]) ? $reg[2] : '');
2860 $sday = (!empty($reg[3]) ? $reg[3] : '');
2861 $shour = (!empty($reg[4]) ? $reg[4] : '');
2862 $smin = (!empty($reg[5]) ? $reg[5] : '');
2863 $ssec = (!empty($reg[6]) ? $reg[6] : '');
2864
2865 $time = dol_mktime($shour, $smin, $ssec, $smonth, $sday, $syear, true);
2866
2867 if ($to_gmt) {
2868 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2869 } else {
2870 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2871 }
2872 $dtts = new DateTime();
2873 $dtts->setTimestamp($time);
2874 $dtts->setTimezone($tzo);
2875 $newformat = str_replace(
2876 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2877 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2878 $format);
2879 $ret = $dtts->format($newformat);
2880 $ret = str_replace(
2881 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2882 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2883 $ret
2884 );
2885 } else {
2886 // Date is a timestamps
2887 if ($time < 100000000000) { // Protection against bad date values
2888 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2889
2890 if ($to_gmt) {
2891 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2892 } else {
2893 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2894 }
2895 $dtts = new DateTime();
2896 $dtts->setTimestamp($timetouse);
2897 $dtts->setTimezone($tzo);
2898 $newformat = str_replace(
2899 array('%Y', '%y', '%m', '%d', '%H', '%I', '%M', '%S', '%p', '%w', 'T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2900 array('Y', 'y', 'm', 'd', 'H', 'h', 'i', 's', 'A', 'w', '__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2901 $format);
2902 $ret = $dtts->format($newformat);
2903 $ret = str_replace(
2904 array('__£__', '__$__', '__{__', '__}__', '__[__', '__]__'),
2905 array('T', 'Z', '__a__', '__A__', '__b__', '__B__'),
2906 $ret
2907 );
2908 //var_dump($ret);exit;
2909 } else {
2910 $ret = 'Bad value '.$time.' for date';
2911 }
2912 }
2913
2914 if (preg_match('/__b__/i', $format)) {
2915 $timetouse = $time + $offsettz + $offsetdst; // TODO We could be able to disable use of offsettz and offsetdst to use only offsettzstring.
2916
2917 if ($to_gmt) {
2918 $tzo = new DateTimeZone('UTC'); // when to_gmt is true, base for offsettz and offsetdst (so timetouse) is UTC
2919 } else {
2920 $tzo = new DateTimeZone(date_default_timezone_get()); // when to_gmt is false, base for offsettz and offsetdst (so timetouse) is PHP server
2921 }
2922 $dtts = new DateTime();
2923 $dtts->setTimestamp($timetouse);
2924 $dtts->setTimezone($tzo);
2925 $month = $dtts->format("m");
2926 $month = sprintf("%02d", $month); // $month may be return with format '06' on some installation and '6' on other, so we force it to '06'.
2927 if ($encodetooutput) {
2928 $monthtext = $outputlangs->transnoentities('Month'.$month);
2929 $monthtextshort = $outputlangs->transnoentities('MonthShort'.$month);
2930 } else {
2931 $monthtext = $outputlangs->transnoentitiesnoconv('Month'.$month);
2932 $monthtextshort = $outputlangs->transnoentitiesnoconv('MonthShort'.$month);
2933 }
2934 //print 'monthtext='.$monthtext.' monthtextshort='.$monthtextshort;
2935 $ret = str_replace('__b__', $monthtextshort, $ret);
2936 $ret = str_replace('__B__', $monthtext, $ret);
2937 //print 'x'.$outputlangs->charset_output.'-'.$ret.'x';
2938 //return $ret;
2939 }
2940 if (preg_match('/__a__/i', $format)) {
2941 //print "time=$time offsettz=$offsettz offsetdst=$offsetdst offsettzstring=$offsettzstring";
2942 $timetouse = $time + $offsettz + $offsetdst; // TODO Replace this with function Date PHP. We also should not use anymore offsettz and offsetdst but only offsettzstring.
2943
2944 if ($to_gmt) {
2945 $tzo = new DateTimeZone('UTC');
2946 } else {
2947 $tzo = new DateTimeZone(date_default_timezone_get());
2948 }
2949 $dtts = new DateTime();
2950 $dtts->setTimestamp($timetouse);
2951 $dtts->setTimezone($tzo);
2952 $w = $dtts->format("w");
2953 $dayweek = $outputlangs->transnoentitiesnoconv('Day'.$w);
2954
2955 $ret = str_replace('__A__', $dayweek, $ret);
2956 $ret = str_replace('__a__', dol_substr($dayweek, 0, 3), $ret);
2957 }
2958
2959 return $ret;
2960}
2961
2962
2983function dol_getdate($timestamp, $fast = false, $forcetimezone = '')
2984{
2985 if ($timestamp === '') {
2986 return array();
2987 }
2988
2989 $datetimeobj = new DateTime();
2990 $datetimeobj->setTimestamp($timestamp); // Use local PHP server timezone
2991 if ($forcetimezone) {
2992 $datetimeobj->setTimezone(new DateTimeZone($forcetimezone == 'gmt' ? 'UTC' : $forcetimezone)); // (add timezone relative to the date entered)
2993 }
2994 $arrayinfo = array(
2995 'year'=>((int) date_format($datetimeobj, 'Y')),
2996 'mon'=>((int) date_format($datetimeobj, 'm')),
2997 'mday'=>((int) date_format($datetimeobj, 'd')),
2998 'wday'=>((int) date_format($datetimeobj, 'w')),
2999 'yday'=>((int) date_format($datetimeobj, 'z')),
3000 'hours'=>((int) date_format($datetimeobj, 'H')),
3001 'minutes'=>((int) date_format($datetimeobj, 'i')),
3002 'seconds'=>((int) date_format($datetimeobj, 's')),
3003 '0'=>$timestamp
3004 );
3005
3006 return $arrayinfo;
3007}
3008
3030function dol_mktime($hour, $minute, $second, $month, $day, $year, $gm = 'auto', $check = 1)
3031{
3032 global $conf;
3033 //print "- ".$hour.",".$minute.",".$second.",".$month.",".$day.",".$year.",".$_SERVER["WINDIR"]." -";
3034
3035 if ($gm === 'auto') {
3036 $gm = (empty($conf) ? 'tzserver' : $conf->tzuserinputkey);
3037 }
3038 //print 'gm:'.$gm.' gm === auto:'.($gm === 'auto').'<br>';exit;
3039
3040 // Clean parameters
3041 if ($hour == -1 || empty($hour)) {
3042 $hour = 0;
3043 }
3044 if ($minute == -1 || empty($minute)) {
3045 $minute = 0;
3046 }
3047 if ($second == -1 || empty($second)) {
3048 $second = 0;
3049 }
3050
3051 // Check parameters
3052 if ($check) {
3053 if (!$month || !$day) {
3054 return '';
3055 }
3056 if ($day > 31) {
3057 return '';
3058 }
3059 if ($month > 12) {
3060 return '';
3061 }
3062 if ($hour < 0 || $hour > 24) {
3063 return '';
3064 }
3065 if ($minute < 0 || $minute > 60) {
3066 return '';
3067 }
3068 if ($second < 0 || $second > 60) {
3069 return '';
3070 }
3071 }
3072
3073 if (empty($gm) || ($gm === 'server' || $gm === 'tzserver')) {
3074 $default_timezone = @date_default_timezone_get(); // Example 'Europe/Berlin'
3075 $localtz = new DateTimeZone($default_timezone);
3076 } elseif ($gm === 'user' || $gm === 'tzuser' || $gm === 'tzuserrel') {
3077 // We use dol_tz_string first because it is more reliable.
3078 $default_timezone = (empty($_SESSION["dol_tz_string"]) ? @date_default_timezone_get() : $_SESSION["dol_tz_string"]); // Example 'Europe/Berlin'
3079 try {
3080 $localtz = new DateTimeZone($default_timezone);
3081 } catch (Exception $e) {
3082 dol_syslog("Warning dol_tz_string contains an invalid value ".$_SESSION["dol_tz_string"], LOG_WARNING);
3083 $default_timezone = @date_default_timezone_get();
3084 }
3085 } elseif (strrpos($gm, "tz,") !== false) {
3086 $timezone = str_replace("tz,", "", $gm); // Example 'tz,Europe/Berlin'
3087 try {
3088 $localtz = new DateTimeZone($timezone);
3089 } catch (Exception $e) {
3090 dol_syslog("Warning passed timezone contains an invalid value ".$timezone, LOG_WARNING);
3091 }
3092 }
3093
3094 if (empty($localtz)) {
3095 $localtz = new DateTimeZone('UTC');
3096 }
3097 //var_dump($localtz);
3098 //var_dump($year.'-'.$month.'-'.$day.'-'.$hour.'-'.$minute);
3099 $dt = new DateTime('now', $localtz);
3100 $dt->setDate((int) $year, (int) $month, (int) $day);
3101 $dt->setTime((int) $hour, (int) $minute, (int) $second);
3102 $date = $dt->getTimestamp(); // should include daylight saving time
3103 //var_dump($date);
3104 return $date;
3105}
3106
3107
3118function dol_now($mode = 'auto')
3119{
3120 $ret = 0;
3121
3122 if ($mode === 'auto') {
3123 $mode = 'gmt';
3124 }
3125
3126 if ($mode == 'gmt') {
3127 $ret = time(); // Time for now at greenwich.
3128 } elseif ($mode == 'tzserver') { // Time for now with PHP server timezone added
3129 require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3130 $tzsecond = getServerTimeZoneInt('now'); // Contains tz+dayling saving time
3131 $ret = (int) (dol_now('gmt') + ($tzsecond * 3600));
3132 //} elseif ($mode == 'tzref') {// Time for now with parent company timezone is added
3133 // require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3134 // $tzsecond=getParentCompanyTimeZoneInt(); // Contains tz+dayling saving time
3135 // $ret=dol_now('gmt')+($tzsecond*3600);
3136 //}
3137 } elseif ($mode == 'tzuser' || $mode == 'tzuserrel') {
3138 // Time for now with user timezone added
3139 //print 'time: '.time();
3140 $offsettz = (empty($_SESSION['dol_tz']) ? 0 : $_SESSION['dol_tz']) * 60 * 60;
3141 $offsetdst = (empty($_SESSION['dol_dst']) ? 0 : $_SESSION['dol_dst']) * 60 * 60;
3142 $ret = (int) (dol_now('gmt') + ($offsettz + $offsetdst));
3143 }
3144
3145 return $ret;
3146}
3147
3148
3157function dol_print_size($size, $shortvalue = 0, $shortunit = 0)
3158{
3159 global $conf, $langs;
3160 $level = 1024;
3161
3162 if (!empty($conf->dol_optimize_smallscreen)) {
3163 $shortunit = 1;
3164 }
3165
3166 // Set value text
3167 if (empty($shortvalue) || $size < ($level * 10)) {
3168 $ret = $size;
3169 $textunitshort = $langs->trans("b");
3170 $textunitlong = $langs->trans("Bytes");
3171 } else {
3172 $ret = round($size / $level, 0);
3173 $textunitshort = $langs->trans("Kb");
3174 $textunitlong = $langs->trans("KiloBytes");
3175 }
3176 // Use long or short text unit
3177 if (empty($shortunit)) {
3178 $ret .= ' '.$textunitlong;
3179 } else {
3180 $ret .= ' '.$textunitshort;
3181 }
3182
3183 return $ret;
3184}
3185
3196function dol_print_url($url, $target = '_blank', $max = 32, $withpicto = 0, $morecss = 'float')
3197{
3198 global $langs;
3199
3200 if (empty($url)) {
3201 return '';
3202 }
3203
3204 $link = '<a href="';
3205 if (!preg_match('/^http/i', $url)) {
3206 $link .= 'http://';
3207 }
3208 $link .= $url;
3209 $link .= '"';
3210 if ($target) {
3211 $link .= ' target="'.$target.'"';
3212 }
3213 $link .= '>';
3214 if (!preg_match('/^http/i', $url)) {
3215 $link .= 'http://';
3216 }
3217 $link .= dol_trunc($url, $max);
3218 $link .= '</a>';
3219
3220 if ($morecss == 'float') {
3221 return '<div class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ?img_picto($langs->trans("Url"), 'globe').' ' : '').$link.'</div>';
3222 } else {
3223 return '<span class="nospan'.($morecss ? ' '.$morecss : '').'" style="margin-right: 10px">'.($withpicto ?img_picto($langs->trans("Url"), 'globe').' ' : '').$link.'</span>';
3224 }
3225}
3226
3239function dol_print_email($email, $cid = 0, $socid = 0, $addlink = 0, $max = 64, $showinvalid = 1, $withpicto = 0)
3240{
3241 global $conf, $user, $langs, $hookmanager;
3242
3243 $newemail = dol_escape_htmltag($email);
3244
3245 if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && $withpicto) {
3246 $withpicto = 0;
3247 }
3248
3249 if (empty($email)) {
3250 return '&nbsp;';
3251 }
3252
3253 if (!empty($addlink)) {
3254 $newemail = '<a style="text-overflow: ellipsis;" href="';
3255 if (!preg_match('/^mailto:/i', $email)) {
3256 $newemail .= 'mailto:';
3257 }
3258 $newemail .= $email;
3259 $newemail .= '">';
3260 $newemail .= dol_trunc($email, $max);
3261 $newemail .= '</a>';
3262 if ($showinvalid && !isValidEmail($email)) {
3263 $langs->load("errors");
3264 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3265 }
3266
3267 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3268 $type = 'AC_EMAIL';
3269 $link = '';
3270 if (!empty($conf->global->AGENDA_ADDACTIONFOREMAIL)) {
3271 $link = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.$type.'&amp;contactid='.$cid.'&amp;socid='.$socid.'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3272 }
3273 if ($link) {
3274 $newemail = '<div>'.$newemail.' '.$link.'</div>';
3275 }
3276 }
3277 } else {
3278 if ($showinvalid && !isValidEmail($email)) {
3279 $langs->load("errors");
3280 $newemail .= img_warning($langs->trans("ErrorBadEMail", $email));
3281 }
3282 }
3283
3284 //$rep = '<div class="nospan" style="margin-right: 10px">';
3285 $rep = ($withpicto ? img_picto($langs->trans("EMail").' : '.$email, (is_numeric($withpicto) ? 'email' : $withpicto)).' ' : '').$newemail;
3286 //$rep .= '</div>';
3287 if ($hookmanager) {
3288 $parameters = array('cid' => $cid, 'socid' => $socid, 'addlink' => $addlink, 'picto' => $withpicto);
3289
3290 $reshook = $hookmanager->executeHooks('printEmail', $parameters, $email);
3291 if ($reshook > 0) {
3292 $rep = '';
3293 }
3294 $rep .= $hookmanager->resPrint;
3295 }
3296
3297 return $rep;
3298}
3299
3306{
3307 global $conf, $db;
3308
3309 $socialnetworks = array();
3310 // Enable caching of array
3311 require_once DOL_DOCUMENT_ROOT.'/core/lib/memory.lib.php';
3312 $cachekey = 'socialnetworks_' . $conf->entity;
3313 $dataretrieved = dol_getcache($cachekey);
3314 if (!is_null($dataretrieved)) {
3315 $socialnetworks = $dataretrieved;
3316 } else {
3317 $sql = "SELECT rowid, code, label, url, icon, active FROM ".MAIN_DB_PREFIX."c_socialnetworks";
3318 $sql .= " WHERE entity=".$conf->entity;
3319 $resql = $db->query($sql);
3320 if ($resql) {
3321 while ($obj = $db->fetch_object($resql)) {
3322 $socialnetworks[$obj->code] = array(
3323 'rowid' => $obj->rowid,
3324 'label' => $obj->label,
3325 'url' => $obj->url,
3326 'icon' => $obj->icon,
3327 'active' => $obj->active,
3328 );
3329 }
3330 }
3331 dol_setcache($cachekey, $socialnetworks); // If setting cache fails, this is not a problem, so we do not test result.
3332 }
3333
3334 return $socialnetworks;
3335}
3336
3347function dol_print_socialnetworks($value, $cid, $socid, $type, $dictsocialnetworks = array())
3348{
3349 global $conf, $user, $langs;
3350
3351 $htmllink = $value;
3352
3353 if (empty($value)) {
3354 return '&nbsp;';
3355 }
3356
3357 if (!empty($type)) {
3358 $htmllink = '<div class="divsocialnetwork inline-block valignmiddle">';
3359 // Use dictionary definition for picto $dictsocialnetworks[$type]['icon']
3360 $htmllink .= '<span class="fa pictofixedwidth '.($dictsocialnetworks[$type]['icon'] ? $dictsocialnetworks[$type]['icon'] : 'fa-link').'"></span>';
3361 if ($type == 'skype') {
3362 $htmllink .= dol_escape_htmltag($value);
3363 $htmllink .= '&nbsp; <a href="skype:';
3364 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3365 $htmllink .= '?call" alt="'.$langs->trans("Call").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Call").' '.$value).'">';
3366 $htmllink .= '<img src="'.DOL_URL_ROOT.'/theme/common/skype_callbutton.png" border="0">';
3367 $htmllink .= '</a><a href="skype:';
3368 $htmllink .= dol_string_nospecial($value, '_', '', array('@'));
3369 $htmllink .= '?chat" alt="'.$langs->trans("Chat").'&nbsp;'.$value.'" title="'.dol_escape_htmltag($langs->trans("Chat").' '.$value).'">';
3370 $htmllink .= '<img class="paddingleft" src="'.DOL_URL_ROOT.'/theme/common/skype_chatbutton.png" border="0">';
3371 $htmllink .= '</a>';
3372 if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create')) {
3373 $addlink = 'AC_SKYPE';
3374 $link = '';
3375 if (!empty($conf->global->AGENDA_ADDACTIONFORSKYPE)) {
3376 $link = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage=1&amp;actioncode='.$addlink.'&amp;contactid='.$cid.'&amp;socid='.$socid.'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3377 }
3378 $htmllink .= ($link ? ' '.$link : '');
3379 }
3380 } else {
3381 if (!empty($dictsocialnetworks[$type]['url'])) {
3382 $tmpvirginurl = preg_replace('/\/?{socialid}/', '', $dictsocialnetworks[$type]['url']);
3383 if ($tmpvirginurl) {
3384 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3385 $value = preg_replace('/^'.preg_quote($tmpvirginurl, '/').'\/?/', '', $value);
3386
3387 $tmpvirginurl3 = preg_replace('/^https:\/\//i', 'https://www.', $tmpvirginurl);
3388 if ($tmpvirginurl3) {
3389 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3390 $value = preg_replace('/^'.preg_quote($tmpvirginurl3, '/').'\/?/', '', $value);
3391 }
3392
3393 $tmpvirginurl2 = preg_replace('/^https?:\/\//i', '', $tmpvirginurl);
3394 if ($tmpvirginurl2) {
3395 $value = preg_replace('/^www\.'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3396 $value = preg_replace('/^'.preg_quote($tmpvirginurl2, '/').'\/?/', '', $value);
3397 }
3398 }
3399 $link = str_replace('{socialid}', $value, $dictsocialnetworks[$type]['url']);
3400 if (preg_match('/^https?:\/\//i', $link)) {
3401 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 0).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3402 } else {
3403 $htmllink .= '<a href="'.dol_sanitizeUrl($link, 1).'" target="_blank" rel="noopener noreferrer">'.dol_escape_htmltag($value).'</a>';
3404 }
3405 } else {
3406 $htmllink .= dol_escape_htmltag($value);
3407 }
3408 }
3409 $htmllink .= '</div>';
3410 } else {
3411 $langs->load("errors");
3412 $htmllink .= img_warning($langs->trans("ErrorBadSocialNetworkValue", $value));
3413 }
3414 return $htmllink;
3415}
3416
3427function dol_print_profids($profID, $profIDtype, $countrycode = '', $addcpButton = 1, $separ = '&nbsp;')
3428{
3429 global $mysoc;
3430
3431 if (empty($profID) || empty($profIDtype)) {
3432 return '';
3433 }
3434 if (empty($countrycode)) $countrycode = $mysoc->country_code;
3435 $newProfID = $profID;
3436 $id = substr($profIDtype, -1);
3437 $ret = '';
3438 if (strtoupper($countrycode) == 'FR') {
3439 // France
3440 if ($id == 1 && dol_strlen($newProfID) == 9) $newProfID = substr($newProfID, 0, 3).$separ.substr($newProfID, 3, 3).$separ.substr($newProfID, 6, 3);
3441 if ($id == 2 && dol_strlen($newProfID) == 14) $newProfID = substr($newProfID, 0, 3).$separ.substr($newProfID, 3, 3).$separ.substr($newProfID, 6, 3).$separ.substr($newProfID, 9, 5);
3442 if ($profIDtype === 'VAT' && dol_strlen($newProfID) == 13) $newProfID = substr($newProfID, 0, 4).$separ.substr($newProfID, 4, 3).$separ.substr($newProfID, 7, 3).$separ.substr($newProfID, 10, 3);
3443 }
3444 if (!empty($addcpButton)) $ret = showValueWithClipboardCPButton(dol_escape_htmltag($profID), ($addcpButton == 1 ? 1 : 0), $newProfID);
3445 else $ret = $newProfID;
3446 return $ret;
3447}
3448
3463function dol_print_phone($phone, $countrycode = '', $cid = 0, $socid = 0, $addlink = '', $separ = "&nbsp;", $withpicto = '', $titlealt = '', $adddivfloat = 0)
3464{
3465 global $conf, $user, $langs, $mysoc, $hookmanager;
3466
3467 // Clean phone parameter
3468 $phone = is_null($phone) ? '' : preg_replace("/[\s.-]/", "", trim($phone));
3469 if (empty($phone)) {
3470 return '';
3471 }
3472 if (!empty($conf->global->MAIN_PHONE_SEPAR)) {
3473 $separ = $conf->global->MAIN_PHONE_SEPAR;
3474 }
3475 if (empty($countrycode) && is_object($mysoc)) {
3476 $countrycode = $mysoc->country_code;
3477 }
3478
3479 // Short format for small screens
3480 if ($conf->dol_optimize_smallscreen) {
3481 $separ = '';
3482 }
3483
3484 $newphone = $phone;
3485 if (strtoupper($countrycode) == "FR") {
3486 // France
3487 if (dol_strlen($phone) == 10) {
3488 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 2).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3489 } elseif (dol_strlen($phone) == 7) {
3490 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2);
3491 } elseif (dol_strlen($phone) == 9) {
3492 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2);
3493 } elseif (dol_strlen($phone) == 11) {
3494 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3495 } elseif (dol_strlen($phone) == 12) {
3496 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3497 } elseif (dol_strlen($phone) == 13) {
3498 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 2);
3499 }
3500 } elseif (strtoupper($countrycode) == "CA") {
3501 if (dol_strlen($phone) == 10) {
3502 $newphone = ($separ != '' ? '(' : '').substr($newphone, 0, 3).($separ != '' ? ')' : '').$separ.substr($newphone, 3, 3).($separ != '' ? '-' : '').substr($newphone, 6, 4);
3503 }
3504 } elseif (strtoupper($countrycode) == "PT") {//Portugal
3505 if (dol_strlen($phone) == 13) {//ex: +351_ABC_DEF_GHI
3506 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3507 }
3508 } elseif (strtoupper($countrycode) == "SR") {//Suriname
3509 if (dol_strlen($phone) == 10) {//ex: +597_ABC_DEF
3510 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3);
3511 } elseif (dol_strlen($phone) == 11) {//ex: +597_ABC_DEFG
3512 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 4);
3513 }
3514 } elseif (strtoupper($countrycode) == "DE") {//Allemagne
3515 if (dol_strlen($phone) == 14) {//ex: +49_ABCD_EFGH_IJK
3516 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 4).$separ.substr($newphone, 11, 3);
3517 } elseif (dol_strlen($phone) == 13) {//ex: +49_ABC_DEFG_HIJ
3518 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 4).$separ.substr($newphone, 10, 3);
3519 }
3520 } elseif (strtoupper($countrycode) == "ES") {//Espagne
3521 if (dol_strlen($phone) == 12) {//ex: +34_ABC_DEF_GHI
3522 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3523 }
3524 } elseif (strtoupper($countrycode) == "BF") {// Burkina Faso
3525 if (dol_strlen($phone) == 12) {//ex : +22 A BC_DE_FG_HI
3526 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3527 }
3528 } elseif (strtoupper($countrycode) == "RO") {// Roumanie
3529 if (dol_strlen($phone) == 12) {//ex : +40 AB_CDE_FG_HI
3530 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3531 }
3532 } elseif (strtoupper($countrycode) == "TR") {//Turquie
3533 if (dol_strlen($phone) == 13) {//ex : +90 ABC_DEF_GHIJ
3534 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3535 }
3536 } elseif (strtoupper($countrycode) == "US") {//Etat-Unis
3537 if (dol_strlen($phone) == 12) {//ex: +1 ABC_DEF_GHIJ
3538 $newphone = substr($newphone, 0, 2).$separ.substr($newphone, 2, 3).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3539 }
3540 } elseif (strtoupper($countrycode) == "MX") {//Mexique
3541 if (dol_strlen($phone) == 12) {//ex: +52 ABCD_EFG_HI
3542 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3543 } elseif (dol_strlen($phone) == 11) {//ex: +52 AB_CD_EF_GH
3544 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 2).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3545 } elseif (dol_strlen($phone) == 13) {//ex: +52 ABC_DEF_GHIJ
3546 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 4);
3547 }
3548 } elseif (strtoupper($countrycode) == "ML") {//Mali
3549 if (dol_strlen($phone) == 12) {//ex: +223 AB_CD_EF_GH
3550 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3551 }
3552 } elseif (strtoupper($countrycode) == "TH") {//Thaïlande
3553 if (dol_strlen($phone) == 11) {//ex: +66_ABC_DE_FGH
3554 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3555 } elseif (dol_strlen($phone) == 12) {//ex: +66_A_BCD_EF_GHI
3556 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 3);
3557 }
3558 } elseif (strtoupper($countrycode) == "MU") {
3559 //Maurice
3560 if (dol_strlen($phone) == 11) {//ex: +230_ABC_DE_FG
3561 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3562 } elseif (dol_strlen($phone) == 12) {//ex: +230_ABCD_EF_GH
3563 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3564 }
3565 } elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud
3566 if (dol_strlen($phone) == 12) {//ex: +27_AB_CDE_FG_HI
3567 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3568 }
3569 } elseif (strtoupper($countrycode) == "SY") {//Syrie
3570 if (dol_strlen($phone) == 12) {//ex: +963_AB_CD_EF_GH
3571 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3572 } elseif (dol_strlen($phone) == 13) {//ex: +963_AB_CD_EF_GHI
3573 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 3);
3574 }
3575 } elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis
3576 if (dol_strlen($phone) == 12) {//ex: +971_ABC_DEF_GH
3577 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 2);
3578 } elseif (dol_strlen($phone) == 13) {//ex: +971_ABC_DEF_GHI
3579 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3580 } elseif (dol_strlen($phone) == 14) {//ex: +971_ABC_DEF_GHIK
3581 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 4);
3582 }
3583 } elseif (strtoupper($countrycode) == "DZ") {//Algérie
3584 if (dol_strlen($phone) == 13) {//ex: +213_ABC_DEF_GHI
3585 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3586 }
3587 } elseif (strtoupper($countrycode) == "BE") {//Belgique
3588 if (dol_strlen($phone) == 11) {//ex: +32_ABC_DE_FGH
3589 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3);
3590 } elseif (dol_strlen($phone) == 12) {//ex: +32_ABC_DEF_GHI
3591 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3592 }
3593 } elseif (strtoupper($countrycode) == "PF") {//Polynésie française
3594 if (dol_strlen($phone) == 12) {//ex: +689_AB_CD_EF_GH
3595 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3596 }
3597 } elseif (strtoupper($countrycode) == "CO") {//Colombie
3598 if (dol_strlen($phone) == 13) {//ex: +57_ABC_DEF_GH_IJ
3599 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3600 }
3601 } elseif (strtoupper($countrycode) == "JO") {//Jordanie
3602 if (dol_strlen($phone) == 12) {//ex: +962_A_BCD_EF_GH
3603 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 1).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2);
3604 }
3605 } elseif (strtoupper($countrycode) == "JM") {//Jamaïque
3606 if (dol_strlen($newphone) == 12) {//ex: +1867_ABC_DEFG
3607 $newphone = substr($newphone, 0, 5).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 4);
3608 }
3609 } elseif (strtoupper($countrycode) == "MG") {//Madagascar
3610 if (dol_strlen($phone) == 13) {//ex: +261_AB_CD_EFG_HI
3611 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 2);
3612 }
3613 } elseif (strtoupper($countrycode) == "GB") {//Royaume uni
3614 if (dol_strlen($phone) == 13) {//ex: +44_ABCD_EFG_HIJ
3615 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 4).$separ.substr($newphone, 7, 3).$separ.substr($newphone, 10, 3);
3616 }
3617 } elseif (strtoupper($countrycode) == "CH") {//Suisse
3618 if (dol_strlen($phone) == 12) {//ex: +41_AB_CDE_FG_HI
3619 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3620 } elseif (dol_strlen($phone) == 15) {// +41_AB_CDE_FGH_IJKL
3621 $newphone = $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 2).$separ.substr($newphone, 5, 3).$separ.substr($newphone, 8, 3).$separ.substr($newphone, 11, 4);
3622 }
3623 } elseif (strtoupper($countrycode) == "TN") {//Tunisie
3624 if (dol_strlen($phone) == 12) {//ex: +216_AB_CDE_FGH
3625 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3626 }
3627 } elseif (strtoupper($countrycode) == "GF") {//Guyane francaise
3628 if (dol_strlen($phone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau)
3629 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3630 }
3631 } elseif (strtoupper($countrycode) == "GP") {//Guadeloupe
3632 if (dol_strlen($phone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau)
3633 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3634 }
3635 } elseif (strtoupper($countrycode) == "MQ") {//Martinique
3636 if (dol_strlen($phone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau)
3637 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3638 }
3639 } elseif (strtoupper($countrycode) == "IT") {//Italie
3640 if (dol_strlen($phone) == 12) {//ex: +39_ABC_DEF_GHI
3641 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 3);
3642 } elseif (dol_strlen($phone) == 13) {//ex: +39_ABC_DEF_GH_IJ
3643 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 3).$separ.substr($newphone, 6, 3).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3644 }
3645 } elseif (strtoupper($countrycode) == "AU") {
3646 //Australie
3647 if (dol_strlen($phone) == 12) {
3648 //ex: +61_A_BCDE_FGHI
3649 $newphone = substr($newphone, 0, 3).$separ.substr($newphone, 3, 1).$separ.substr($newphone, 4, 4).$separ.substr($newphone, 8, 4);
3650 }
3651 } elseif (strtoupper($countrycode) == "LU") {
3652 // Luxembourg
3653 if (dol_strlen($phone) == 10) {// fixe 6 chiffres +352_AA_BB_CC
3654 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2);
3655 } elseif (dol_strlen($phone) == 11) {// fixe 7 chiffres +352_AA_BB_CC_D
3656 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 1);
3657 } elseif (dol_strlen($phone) == 12) {// fixe 8 chiffres +352_AA_BB_CC_DD
3658 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 2).$separ.substr($newphone, 6, 2).$separ.substr($newphone, 8, 2).$separ.substr($newphone, 10, 2);
3659 } elseif (dol_strlen($phone) == 13) {// mobile +352_AAA_BB_CC_DD
3660 $newphone = substr($newphone, 0, 4).$separ.substr($newphone, 4, 3).$separ.substr($newphone, 7, 2).$separ.substr($newphone, 9, 2).$separ.substr($newphone, 11, 2);
3661 }
3662 }
3663 if (!empty($addlink)) { // Link on phone number (+ link to add action if conf->global->AGENDA_ADDACTIONFORPHONE set)
3664 if ($addlink == 'tel' || $conf->browser->layout == 'phone' || (isModEnabled('clicktodial') && !empty($conf->global->CLICKTODIAL_USE_TEL_LINK_ON_PHONE_NUMBERS))) { // If phone or option for, we use link of phone
3665 $newphoneform = $newphone;
3666 $newphone = '<a href="tel:'.$phone.'"';
3667 $newphone .= '>'.$newphoneform.'</a>';
3668 } elseif (isModEnabled('clicktodial') && $addlink == 'AC_TEL') { // If click to dial, we use click to dial url
3669 if (empty($user->clicktodial_loaded)) {
3670 $user->fetch_clicktodial();
3671 }
3672
3673 // Define urlmask
3674 $urlmask = 'ErrorClickToDialModuleNotConfigured';
3675 if (!empty($conf->global->CLICKTODIAL_URL)) {
3676 $urlmask = $conf->global->CLICKTODIAL_URL;
3677 }
3678 if (!empty($user->clicktodial_url)) {
3679 $urlmask = $user->clicktodial_url;
3680 }
3681
3682 $clicktodial_poste = (!empty($user->clicktodial_poste) ?urlencode($user->clicktodial_poste) : '');
3683 $clicktodial_login = (!empty($user->clicktodial_login) ?urlencode($user->clicktodial_login) : '');
3684 $clicktodial_password = (!empty($user->clicktodial_password) ?urlencode($user->clicktodial_password) : '');
3685 // This line is for backward compatibility
3686 $url = sprintf($urlmask, urlencode($phone), $clicktodial_poste, $clicktodial_login, $clicktodial_password);
3687 // Thoose lines are for substitution
3688 $substitarray = array('__PHONEFROM__'=>$clicktodial_poste,
3689 '__PHONETO__'=>urlencode($phone),
3690 '__LOGIN__'=>$clicktodial_login,
3691 '__PASS__'=>$clicktodial_password);
3692 $url = make_substitutions($url, $substitarray);
3693 $newphonesav = $newphone;
3694 if (empty($conf->global->CLICKTODIAL_DO_NOT_USE_AJAX_CALL)) {
3695 // Default and recommended: New method using ajax without submiting a page making a javascript history.go(-1) back
3696 $newphone = '<a href="'.$url.'" class="cssforclicktodial"'; // Call of ajax is handled by the lib_foot.js.php on class 'cssforclicktodial'
3697 $newphone .= '>'.$newphonesav.'</a>';
3698 } else {
3699 // Old method
3700 $newphone = '<a href="'.$url.'"';
3701 if (!empty($conf->global->CLICKTODIAL_FORCENEWTARGET)) {
3702 $newphone .= ' target="_blank" rel="noopener noreferrer"';
3703 }
3704 $newphone .= '>'.$newphonesav.'</a>';
3705 }
3706 }
3707
3708 //if (($cid || $socid) && isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'create'))
3709 if (isModEnabled('agenda') && $user->hasRight("agenda", "myactions", "create")) {
3710 $type = 'AC_TEL';
3711 $link = '';
3712 if ($addlink == 'AC_FAX') {
3713 $type = 'AC_FAX';
3714 }
3715 if (!empty($conf->global->AGENDA_ADDACTIONFORPHONE)) {
3716 $link = '<a href="'.DOL_URL_ROOT.'/comm/action/card.php?action=create&amp;backtopage='. urlencode($_SERVER['REQUEST_URI']) .'&amp;actioncode='.$type.($cid ? '&amp;contactid='.$cid : '').($socid ? '&amp;socid='.$socid : '').'">'.img_object($langs->trans("AddAction"), "calendar").'</a>';
3717 }
3718 if ($link) {
3719 $newphone = '<div>'.$newphone.' '.$link.'</div>';
3720 }
3721 }
3722 }
3723
3724 if (empty($titlealt)) {
3725 $titlealt = ($withpicto == 'fax' ? $langs->trans("Fax") : $langs->trans("Phone"));
3726 }
3727 $rep = '';
3728
3729 if ($hookmanager) {
3730 $parameters = array('countrycode' => $countrycode, 'cid' => $cid, 'socid' => $socid, 'titlealt' => $titlealt, 'picto' => $withpicto);
3731 $reshook = $hookmanager->executeHooks('printPhone', $parameters, $phone);
3732 $rep .= $hookmanager->resPrint;
3733 }
3734 if (empty($reshook)) {
3735 $picto = '';
3736 if ($withpicto) {
3737 if ($withpicto == 'fax') {
3738 $picto = 'phoning_fax';
3739 } elseif ($withpicto == 'phone') {
3740 $picto = 'phoning';
3741 } elseif ($withpicto == 'mobile') {
3742 $picto = 'phoning_mobile';
3743 } else {
3744 $picto = '';
3745 }
3746 }
3747 if ($adddivfloat == 1) {
3748 $rep .= '<div class="nospan float" style="margin-right: 10px">';
3749 } elseif (empty($adddivfloat)) {
3750 $rep .= '<span style="margin-right: 10px;">';
3751 }
3752 $rep .= ($withpicto ?img_picto($titlealt, 'object_'.$picto.'.png').' ' : '').$newphone;
3753 if ($adddivfloat == 1) {
3754 $rep .= '</div>';
3755 } elseif (empty($adddivfloat)) {
3756 $rep .= '</span>';
3757 }
3758 }
3759
3760 return $rep;
3761}
3762
3770function dol_print_ip($ip, $mode = 0)
3771{
3772 global $conf, $langs;
3773
3774 $ret = '';
3775
3776 if (empty($mode)) {
3777 $ret .= $ip;
3778 }
3779
3780 if ($mode != 2) {
3781 $countrycode = dolGetCountryCodeFromIp($ip);
3782 if ($countrycode) { // If success, countrycode is us, fr, ...
3783 if (file_exists(DOL_DOCUMENT_ROOT.'/theme/common/flags/'.$countrycode.'.png')) {
3784 $ret .= ' '.img_picto($countrycode.' '.$langs->trans("AccordingToGeoIPDatabase"), DOL_URL_ROOT.'/theme/common/flags/'.$countrycode.'.png', '', 1);
3785 } else {
3786 $ret .= ' ('.$countrycode.')';
3787 }
3788 } else {
3789 // Nothing
3790 }
3791 }
3792
3793 return $ret;
3794}
3795
3805{
3806 if (empty($_SERVER['HTTP_X_FORWARDED_FOR']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
3807 if (empty($_SERVER['HTTP_CLIENT_IP']) || preg_match('/[^0-9\.\:,\[\]]/', $_SERVER['HTTP_CLIENT_IP'])) {
3808 if (empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
3809 $ip = (empty($_SERVER['REMOTE_ADDR']) ? '' : $_SERVER['REMOTE_ADDR']); // value may have been the IP of the proxy and not the client
3810 } else {
3811 $ip = $_SERVER["HTTP_CF_CONNECTING_IP"]; // value here may have been forged by client
3812 }
3813 } else {
3814 $ip = $_SERVER['HTTP_CLIENT_IP']; // value is clean here but may have been forged by proxy
3815 }
3816 } else {
3817 $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; // value is clean here but may have been forged by proxy
3818 }
3819 return $ip;
3820}
3821
3830function isHTTPS()
3831{
3832 $isSecure = false;
3833 if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
3834 $isSecure = true;
3835 } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_SERVER['HTTP_X_FORWARDED_SSL']) && $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
3836 $isSecure = true;
3837 }
3838 return $isSecure;
3839}
3840
3848{
3849 global $conf;
3850
3851 $countrycode = '';
3852
3853 if (!empty($conf->geoipmaxmind->enabled)) {
3854 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3855 //$ip='24.24.24.24';
3856 //$datafile='/usr/share/GeoIP/GeoIP.dat'; Note that this must be downloaded datafile (not same than datafile provided with ubuntu packages)
3857 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3858 $geoip = new DolGeoIP('country', $datafile);
3859 //print 'ip='.$ip.' databaseType='.$geoip->gi->databaseType." GEOIP_CITY_EDITION_REV1=".GEOIP_CITY_EDITION_REV1."\n";
3860 $countrycode = $geoip->getCountryCodeFromIP($ip);
3861 }
3862
3863 return $countrycode;
3864}
3865
3866
3874{
3875 global $conf, $langs, $user;
3876
3877 //$ret=$user->xxx;
3878 $ret = '';
3879 if (!empty($conf->geoipmaxmind->enabled)) {
3880 $ip = getUserRemoteIP();
3881 $datafile = getDolGlobalString('GEOIPMAXMIND_COUNTRY_DATAFILE');
3882 //$ip='24.24.24.24';
3883 //$datafile='E:\Mes Sites\Web\Admin1\awstats\maxmind\GeoIP.dat';
3884 include_once DOL_DOCUMENT_ROOT.'/core/class/dolgeoip.class.php';
3885 $geoip = new DolGeoIP('country', $datafile);
3886 $countrycode = $geoip->getCountryCodeFromIP($ip);
3887 $ret = $countrycode;
3888 }
3889 return $ret;
3890}
3891
3904function dol_print_address($address, $htmlid, $element, $id, $noprint = 0, $charfornl = '')
3905{
3906 global $conf, $user, $langs, $hookmanager;
3907
3908 $out = '';
3909
3910 if ($address) {
3911 if ($hookmanager) {
3912 $parameters = array('element' => $element, 'id' => $id);
3913 $reshook = $hookmanager->executeHooks('printAddress', $parameters, $address);
3914 $out .= $hookmanager->resPrint;
3915 }
3916 if (empty($reshook)) {
3917 if (empty($charfornl)) {
3918 $out .= nl2br($address);
3919 } else {
3920 $out .= preg_replace('/[\r\n]+/', $charfornl, $address);
3921 }
3922
3923 // TODO Remove this block, we can add this using the hook now
3924 $showgmap = $showomap = 0;
3925 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS)) {
3926 $showgmap = 1;
3927 }
3928 if ($element == 'contact' && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS_CONTACTS)) {
3929 $showgmap = 1;
3930 }
3931 if ($element == 'member' && isModEnabled('google') && !empty($conf->global->GOOGLE_ENABLE_GMAPS_MEMBERS)) {
3932 $showgmap = 1;
3933 }
3934 if (($element == 'thirdparty' || $element == 'societe') && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS)) {
3935 $showomap = 1;
3936 }
3937 if ($element == 'contact' && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS_CONTACTS)) {
3938 $showomap = 1;
3939 }
3940 if ($element == 'member' && isModEnabled('openstreetmap') && !empty($conf->global->OPENSTREETMAP_ENABLE_MAPS_MEMBERS)) {
3941 $showomap = 1;
3942 }
3943 if ($showgmap) {
3944 $url = dol_buildpath('/google/gmaps.php?mode='.$element.'&id='.$id, 1);
3945 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
3946 }
3947 if ($showomap) {
3948 $url = dol_buildpath('/openstreetmap/maps.php?mode='.$element.'&id='.$id, 1);
3949 $out .= ' <a href="'.$url.'" target="_gmaps"><img id="'.$htmlid.'_openstreetmap" class="valigntextbottom" src="'.DOL_URL_ROOT.'/theme/common/gmap.png"></a>';
3950 }
3951 }
3952 }
3953 if ($noprint) {
3954 return $out;
3955 } else {
3956 print $out;
3957 }
3958}
3959
3960
3970function isValidEmail($address, $acceptsupervisorkey = 0, $acceptuserkey = 0)
3971{
3972 if ($acceptsupervisorkey && $address == '__SUPERVISOREMAIL__') {
3973 return true;
3974 }
3975 if ($acceptuserkey && $address == '__USER_EMAIL__') {
3976 return true;
3977 }
3978 if (filter_var($address, FILTER_VALIDATE_EMAIL)) {
3979 return true;
3980 }
3981
3982 return false;
3983}
3984
3993function isValidMXRecord($domain)
3994{
3995 if (function_exists('idn_to_ascii') && function_exists('checkdnsrr')) {
3996 if (!checkdnsrr(idn_to_ascii($domain), 'MX')) {
3997 return 0;
3998 }
3999 if (function_exists('getmxrr')) {
4000 $mxhosts = array();
4001 $weight = array();
4002 getmxrr(idn_to_ascii($domain), $mxhosts, $weight);
4003 if (count($mxhosts) > 1) {
4004 return 1;
4005 }
4006 if (count($mxhosts) == 1 && !empty($mxhosts[0])) {
4007 return 1;
4008 }
4009
4010 return 0;
4011 }
4012 }
4013
4014 // function idn_to_ascii or checkdnsrr or getmxrr does not exists
4015 return -1;
4016}
4017
4025function isValidPhone($phone)
4026{
4027 return true;
4028}
4029
4030
4040function dolGetFirstLetters($s, $nbofchar = 1)
4041{
4042 $ret = '';
4043 $tmparray = explode(' ', $s);
4044 foreach ($tmparray as $tmps) {
4045 $ret .= dol_substr($tmps, 0, $nbofchar);
4046 }
4047
4048 return $ret;
4049}
4050
4051
4059function dol_strlen($string, $stringencoding = 'UTF-8')
4060{
4061 if (is_null($string)) {
4062 return 0;
4063 }
4064
4065 if (function_exists('mb_strlen')) {
4066 return mb_strlen($string, $stringencoding);
4067 } else {
4068 return strlen($string);
4069 }
4070}
4071
4082function dol_substr($string, $start, $length = null, $stringencoding = '', $trunconbytes = 0)
4083{
4084 global $langs;
4085
4086 if (empty($stringencoding)) {
4087 $stringencoding = $langs->charset_output;
4088 }
4089
4090 $ret = '';
4091 if (empty($trunconbytes)) {
4092 if (function_exists('mb_substr')) {
4093 $ret = mb_substr($string, $start, $length, $stringencoding);
4094 } else {
4095 $ret = substr($string, $start, $length);
4096 }
4097 } else {
4098 if (function_exists('mb_strcut')) {
4099 $ret = mb_strcut($string, $start, $length, $stringencoding);
4100 } else {
4101 $ret = substr($string, $start, $length);
4102 }
4103 }
4104 return $ret;
4105}
4106
4107
4121function dol_trunc($string, $size = 40, $trunc = 'right', $stringencoding = 'UTF-8', $nodot = 0, $display = 0)
4122{
4123 global $conf;
4124
4125 if (empty($size) || !empty($conf->global->MAIN_DISABLE_TRUNC)) {
4126 return $string;
4127 }
4128
4129 if (empty($stringencoding)) {
4130 $stringencoding = 'UTF-8';
4131 }
4132 // reduce for small screen
4133 if ($conf->dol_optimize_smallscreen == 1 && $display == 1) {
4134 $size = round($size / 3);
4135 }
4136
4137 // We go always here
4138 if ($trunc == 'right') {
4139 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4140 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4141 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4142 return dol_substr($newstring, 0, $size, $stringencoding).($nodot ? '' : '…');
4143 } else {
4144 //return 'u'.$size.'-'.$newstring.'-'.dol_strlen($newstring,$stringencoding).'-'.$string;
4145 return $string;
4146 }
4147 } elseif ($trunc == 'middle') {
4148 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4149 if (dol_strlen($newstring, $stringencoding) > 2 && dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4150 $size1 = round($size / 2);
4151 $size2 = round($size / 2);
4152 return dol_substr($newstring, 0, $size1, $stringencoding).'…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size2, $size2, $stringencoding);
4153 } else {
4154 return $string;
4155 }
4156 } elseif ($trunc == 'left') {
4157 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4158 if (dol_strlen($newstring, $stringencoding) > ($size + ($nodot ? 0 : 1))) {
4159 // If nodot is 0 and size is 1 chars more, we don't trunc and don't add …
4160 return '…'.dol_substr($newstring, dol_strlen($newstring, $stringencoding) - $size, $size, $stringencoding);
4161 } else {
4162 return $string;
4163 }
4164 } elseif ($trunc == 'wrap') {
4165 $newstring = dol_textishtml($string) ? dol_string_nohtmltag($string, 1) : $string;
4166 if (dol_strlen($newstring, $stringencoding) > ($size + 1)) {
4167 return dol_substr($newstring, 0, $size, $stringencoding)."\n".dol_trunc(dol_substr($newstring, $size, dol_strlen($newstring, $stringencoding) - $size, $stringencoding), $size, $trunc);
4168 } else {
4169 return $string;
4170 }
4171 } else {
4172 return 'BadParam3CallingDolTrunc';
4173 }
4174}
4175
4197function img_picto($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0, $alt = '', $morecss = '', $marginleftonlyshort = 2)
4198{
4199 global $conf, $langs;
4200
4201 // We forge fullpathpicto for image to $path/img/$picto. By default, we take DOL_URL_ROOT/theme/$conf->theme/img/$picto
4202 $url = DOL_URL_ROOT;
4203 $theme = isset($conf->theme) ? $conf->theme : null;
4204 $path = 'theme/'.$theme;
4205 // Define fullpathpicto to use into src
4206 if ($pictoisfullpath) {
4207 // Clean parameters
4208 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4209 $picto .= '.png';
4210 }
4211 $fullpathpicto = $picto;
4212 $reg = array();
4213 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4214 $morecss .= ($morecss ? ' ' : '').$reg[1];
4215 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4216 }
4217 } else {
4218 $pictowithouttext = preg_replace('/(\.png|\.gif|\.svg)$/', '', $picto);
4219 $pictowithouttext = str_replace('object_', '', $pictowithouttext);
4220 $pictowithouttext = str_replace('_nocolor', '', $pictowithouttext);
4221
4222 if (strpos($pictowithouttext, 'fontawesome_') !== false || preg_match('/^fa-/', $pictowithouttext)) {
4223 // This is a font awesome image 'fonwtawesome_xxx' or 'fa-xxx'
4224 $pictowithouttext = str_replace('fontawesome_', '', $pictowithouttext);
4225 $pictowithouttext = str_replace('fa-', '', $pictowithouttext);
4226
4227 $pictowithouttextarray = explode('_', $pictowithouttext);
4228 $marginleftonlyshort = 0;
4229
4230 if (!empty($pictowithouttextarray[1])) {
4231 // Syntax is 'fontawesome_fakey_faprefix_facolor_fasize' or 'fa-fakey_faprefix_facolor_fasize'
4232 $fakey = 'fa-'.$pictowithouttextarray[0];
4233 $fa = empty($pictowithouttextarray[1]) ? 'fa' : $pictowithouttextarray[1];
4234 $facolor = empty($pictowithouttextarray[2]) ? '' : $pictowithouttextarray[2];
4235 $fasize = empty($pictowithouttextarray[3]) ? '' : $pictowithouttextarray[3];
4236 } else {
4237 $fakey = 'fa-'.$pictowithouttext;
4238 $fa = 'fa';
4239 $facolor = '';
4240 $fasize = '';
4241 }
4242
4243 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4244 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4245 $morestyle = '';
4246 $reg = array();
4247 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4248 $morecss .= ($morecss ? ' ' : '').$reg[1];
4249 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4250 }
4251 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4252 $morestyle = $reg[1];
4253 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4254 }
4255 $moreatt = trim($moreatt);
4256
4257 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4258 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4259 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4260 $enabledisablehtml .= $titlealt;
4261 }*/
4262 $enabledisablehtml .= '</span>';
4263
4264 return $enabledisablehtml;
4265 }
4266
4267 if (empty($srconly) && in_array($pictowithouttext, array(
4268 '1downarrow', '1uparrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected',
4269 'accountancy', 'accounting_account', 'account', 'accountline', 'action', 'add', 'address', 'angle-double-down', 'angle-double-up', 'asset',
4270 'bank_account', 'barcode', 'bank', 'bell', 'bill', 'billa', 'billr', 'billd', 'birthday-cake', 'bookmark', 'bom', 'briefcase-medical', 'bug', 'building',
4271 'card', 'calendarlist', 'calendar', 'calendarmonth', 'calendarweek', 'calendarday', 'calendarperuser', 'calendarpertype',
4272 'cash-register', 'category', 'chart', 'check', 'clock', 'clone', 'close_title', 'cog', 'collab', 'company', 'contact', 'country', 'contract', 'conversation', 'cron', 'cross', 'cubes',
4273 'currency', 'multicurrency',
4274 'delete', 'dolly', 'dollyrevert', 'donation', 'download', 'dynamicprice',
4275 'edit', 'ellipsis-h', 'email', 'entity', 'envelope', 'eraser', 'establishment', 'expensereport', 'external-link-alt', 'external-link-square-alt', 'eye',
4276 'filter', 'file-code', 'file-export', 'file-import', 'file-upload', 'autofill', 'folder', 'folder-open', 'folder-plus',
4277 'gears', 'generate', 'generic', 'globe', 'globe-americas', 'graph', 'grip', 'grip_title', 'group',
4278 'hands-helping', 'help', 'holiday',
4279 'id-card', 'images', 'incoterm', 'info', 'intervention', 'inventory', 'intracommreport', 'jobprofile',
4280 'knowledgemanagement',
4281 'label', 'language', 'line', 'link', 'list', 'list-alt', 'listlight', 'loan', 'lock', 'lot', 'long-arrow-alt-right',
4282 'margin', 'map-marker-alt', 'member', 'meeting', 'money-bill-alt', 'movement', 'mrp', 'note', 'next',
4283 'off', 'on', 'order',
4284 'paiment', 'paragraph', 'play', 'pdf', 'phone', 'phoning', 'phoning_mobile', 'phoning_fax', 'playdisabled', 'previous', 'poll', 'pos', 'printer', 'product', 'propal', 'proposal', 'puce',
4285 'stock', 'resize', 'service', 'stats', 'trip',
4286 'security', 'setup', 'share-alt', 'sign-out', 'split', 'stripe', 'stripe-s', 'switch_off', 'switch_on', 'switch_on_warning', 'switch_on_red', 'tools', 'unlink', 'uparrow', 'user', 'user-tie', 'vcard', 'wrench',
4287 'github', 'google', 'jabber', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'youtube', 'google-plus-g', 'whatsapp',
4288 'chevron-left', 'chevron-right', 'chevron-down', 'chevron-top', 'commercial', 'companies',
4289 'generic', 'home', 'hrm', 'members', 'products', 'invoicing',
4290 'partnership', 'payment', 'payment_vat', 'pencil-ruler', 'pictoconfirm', 'preview', 'project', 'projectpub', 'projecttask', 'question', 'refresh', 'region',
4291 'salary', 'shipment', 'state', 'supplier_invoice', 'supplier_invoicea', 'supplier_invoicer', 'supplier_invoiced',
4292 'technic', 'ticket',
4293 'error', 'warning',
4294 'recent', 'reception', 'recruitmentcandidature', 'recruitmentjobposition', 'replacement', 'resource', 'recurring','rss',
4295 'shapes', 'skill', 'square', 'stop-circle', 'supplier', 'supplier_proposal', 'supplier_order', 'supplier_invoice',
4296 'timespent', 'title_setup', 'title_accountancy', 'title_bank', 'title_hrm', 'title_agenda',
4297 'uncheck', 'url', 'user-cog', 'user-injured', 'user-md', 'vat', 'website', 'workstation', 'webhook', 'world', 'private',
4298 'conferenceorbooth', 'eventorganization',
4299 'stamp', 'signature'
4300 ))) {
4301 $fakey = $pictowithouttext;
4302 $facolor = '';
4303 $fasize = '';
4304 $fa = 'fas';
4305 if (in_array($pictowithouttext, array('card', 'bell', 'clock', 'establishment', 'generic', 'minus-square', 'object_generic', 'pdf', 'plus-square', 'timespent', 'note', 'off', 'on', 'object_bookmark', 'bookmark', 'vcard'))) {
4306 $fa = 'far';
4307 }
4308 if (in_array($pictowithouttext, array('black-tie', 'github', 'google', 'microsoft', 'skype', 'twitter', 'facebook', 'linkedin', 'instagram', 'snapchat', 'stripe', 'stripe-s', 'youtube', 'google-plus-g', 'whatsapp'))) {
4309 $fa = 'fab';
4310 }
4311
4312 $arrayconvpictotofa = array(
4313 'account'=>'university', 'accounting_account'=>'clipboard-list', 'accountline'=>'receipt', 'accountancy'=>'search-dollar', 'action'=>'calendar-alt', 'add'=>'plus-circle', 'address'=> 'address-book', 'asset'=>'money-check-alt', 'autofill'=>'fill',
4314 'bank_account'=>'university',
4315 'bill'=>'file-invoice-dollar', 'billa'=>'file-excel', 'billr'=>'file-invoice-dollar', 'billd'=>'file-medical',
4316 'supplier_invoice'=>'file-invoice-dollar', 'supplier_invoicea'=>'file-excel', 'supplier_invoicer'=>'file-invoice-dollar', 'supplier_invoiced'=>'file-medical',
4317 'bom'=>'shapes',
4318 'card'=>'address-card', 'chart'=>'chart-line', 'company'=>'building', 'contact'=>'address-book', 'contract'=>'suitcase', 'collab'=>'people-arrows', 'conversation'=>'comments', 'country'=>'globe-americas', 'cron'=>'business-time', 'cross'=>'times',
4319 'donation'=>'file-alt', 'dynamicprice'=>'hand-holding-usd',
4320 'setup'=>'cog', 'companies'=>'building', 'products'=>'cube', 'commercial'=>'suitcase', 'invoicing'=>'coins',
4321 'accounting'=>'search-dollar', 'category'=>'tag', 'dollyrevert'=>'dolly',
4322 'generate'=>'plus-square', 'hrm'=>'user-tie', 'incoterm'=>'truck-loading',
4323 'margin'=>'calculator', 'members'=>'user-friends', 'ticket'=>'ticket-alt', 'globe'=>'external-link-alt', 'lot'=>'barcode',
4324 'email'=>'at', 'establishment'=>'building', 'edit'=>'pencil-alt', 'entity'=>'globe',
4325 'graph'=>'chart-line', 'grip_title'=>'arrows-alt', 'grip'=>'arrows-alt', 'help'=>'question-circle',
4326 'generic'=>'file', 'holiday'=>'umbrella-beach',
4327 'info'=>'info-circle', 'inventory'=>'boxes', 'intracommreport'=>'globe-europe', 'jobprofile'=>'cogs',
4328 'knowledgemanagement'=>'ticket-alt', 'label'=>'layer-group', 'line'=>'bars', 'loan'=>'money-bill-alt',
4329 'member'=>'user-alt', 'meeting'=>'chalkboard-teacher', 'mrp'=>'cubes', 'next'=>'arrow-alt-circle-right',
4330 'trip'=>'wallet', 'expensereport'=>'wallet', 'group'=>'users', 'movement'=>'people-carry',
4331 'sign-out'=>'sign-out-alt',
4332 'switch_off'=>'toggle-off', 'switch_on'=>'toggle-on', 'switch_on_warning'=>'toggle-on', 'switch_on_red'=>'toggle-on', 'check'=>'check', 'bookmark'=>'star',
4333 'bank'=>'university', 'close_title'=>'times', 'delete'=>'trash', 'filter'=>'filter',
4334 'list-alt'=>'list-alt', 'calendarlist'=>'bars', 'calendar'=>'calendar-alt', 'calendarmonth'=>'calendar-alt', 'calendarweek'=>'calendar-week', 'calendarday'=>'calendar-day', 'calendarperuser'=>'table',
4335 'intervention'=>'ambulance', 'invoice'=>'file-invoice-dollar', 'currency'=>'dollar-sign', 'multicurrency'=>'dollar-sign', 'order'=>'file-invoice',
4336 'error'=>'exclamation-triangle', 'warning'=>'exclamation-triangle',
4337 'other'=>'square',
4338 'playdisabled'=>'play', 'pdf'=>'file-pdf', 'poll'=>'check-double', 'pos'=>'cash-register', 'preview'=>'binoculars', 'project'=>'project-diagram', 'projectpub'=>'project-diagram', 'projecttask'=>'tasks', 'propal'=>'file-signature', 'proposal'=>'file-signature',
4339 'partnership'=>'handshake', 'payment'=>'money-check-alt', 'payment_vat'=>'money-check-alt', 'pictoconfirm'=>'check-square', 'phoning'=>'phone', 'phoning_mobile'=>'mobile-alt', 'phoning_fax'=>'fax', 'previous'=>'arrow-alt-circle-left', 'printer'=>'print', 'product'=>'cube', 'puce'=>'angle-right',
4340 'recent' => 'check-square', 'reception'=>'dolly', 'recruitmentjobposition'=>'id-card-alt', 'recruitmentcandidature'=>'id-badge',
4341 'resize'=>'crop', 'supplier_order'=>'dol-order_supplier', 'supplier_proposal'=>'file-signature',
4342 'refresh'=>'redo', 'region'=>'map-marked', 'replacement'=>'exchange-alt', 'resource'=>'laptop-house', 'recurring'=>'history',
4343 'service'=>'concierge-bell',
4344 'skill'=>'shapes', 'state'=>'map-marked-alt', 'security'=>'key', 'salary'=>'wallet', 'shipment'=>'dolly', 'stock'=>'box-open', 'stats' => 'chart-bar', 'split'=>'code-branch', 'stripe'=>'stripe-s',
4345 'supplier'=>'building', 'technic'=>'cogs',
4346 'timespent'=>'clock', 'title_setup'=>'tools', 'title_accountancy'=>'money-check-alt', 'title_bank'=>'university', 'title_hrm'=>'umbrella-beach',
4347 'title_agenda'=>'calendar-alt',
4348 'uncheck'=>'times', 'uparrow'=>'share', 'url'=>'external-link-alt', 'vat'=>'money-check-alt', 'vcard'=>'arrow-alt-circle-down',
4349 'jabber'=>'comment-o',
4350 'website'=>'globe-americas', 'workstation'=>'pallet', 'webhook'=>'bullseye', 'world'=>'globe', 'private'=>'user-lock',
4351 'conferenceorbooth'=>'chalkboard-teacher', 'eventorganization'=>'project-diagram'
4352 );
4353 if ($pictowithouttext == 'off') {
4354 $fakey = 'fa-square';
4355 $fasize = '1.3em';
4356 } elseif ($pictowithouttext == 'on') {
4357 $fakey = 'fa-check-square';
4358 $fasize = '1.3em';
4359 } elseif ($pictowithouttext == 'listlight') {
4360 $fakey = 'fa-download';
4361 $marginleftonlyshort = 1;
4362 } elseif ($pictowithouttext == 'printer') {
4363 $fakey = 'fa-print';
4364 $fasize = '1.2em';
4365 } elseif ($pictowithouttext == 'note') {
4366 $fakey = 'fa-sticky-note';
4367 $marginleftonlyshort = 1;
4368 } elseif (in_array($pictowithouttext, array('1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'))) {
4369 $convertarray = array('1uparrow'=>'caret-up', '1downarrow'=>'caret-down', '1leftarrow'=>'caret-left', '1rightarrow'=>'caret-right', '1uparrow_selected'=>'caret-up', '1downarrow_selected'=>'caret-down', '1leftarrow_selected'=>'caret-left', '1rightarrow_selected'=>'caret-right');
4370 $fakey = 'fa-'.$convertarray[$pictowithouttext];
4371 if (preg_match('/selected/', $pictowithouttext)) {
4372 $facolor = '#888';
4373 }
4374 $marginleftonlyshort = 1;
4375 } elseif (!empty($arrayconvpictotofa[$pictowithouttext])) {
4376 $fakey = 'fa-'.$arrayconvpictotofa[$pictowithouttext];
4377 } else {
4378 $fakey = 'fa-'.$pictowithouttext;
4379 }
4380
4381 if (in_array($pictowithouttext, array('dollyrevert', 'member', 'members', 'contract', 'group', 'resource', 'shipment'))) {
4382 $morecss .= ' em092';
4383 }
4384 if (in_array($pictowithouttext, array('conferenceorbooth', 'collab', 'eventorganization', 'holiday', 'info', 'project', 'workstation'))) {
4385 $morecss .= ' em088';
4386 }
4387 if (in_array($pictowithouttext, array('asset', 'intervention', 'payment', 'loan', 'partnership', 'stock', 'technic'))) {
4388 $morecss .= ' em080';
4389 }
4390
4391 // Define $marginleftonlyshort
4392 $arrayconvpictotomarginleftonly = array(
4393 'bank', 'check', 'delete', 'generic', 'grip', 'grip_title', 'jabber',
4394 'grip_title', 'grip', 'listlight', 'note', 'on', 'off', 'playdisabled', 'printer', 'resize', 'sign-out', 'stats', 'switch_on', 'switch_on_red', 'switch_off',
4395 'uparrow', '1uparrow', '1downarrow', '1leftarrow', '1rightarrow', '1uparrow_selected', '1downarrow_selected', '1leftarrow_selected', '1rightarrow_selected'
4396 );
4397 if (!isset($arrayconvpictotomarginleftonly[$pictowithouttext])) {
4398 $marginleftonlyshort = 0;
4399 }
4400
4401 // Add CSS
4402 $arrayconvpictotomorcess = array(
4403 'action'=>'infobox-action', 'account'=>'infobox-bank_account', 'accounting_account'=>'infobox-bank_account', 'accountline'=>'infobox-bank_account', 'accountancy'=>'infobox-bank_account', 'asset'=>'infobox-bank_account',
4404 'bank_account'=>'infobox-bank_account',
4405 'bill'=>'infobox-commande', 'billa'=>'infobox-commande', 'billr'=>'infobox-commande', 'billd'=>'infobox-commande',
4406 'margin'=>'infobox-bank_account', 'conferenceorbooth'=>'infobox-project',
4407 'cash-register'=>'infobox-bank_account', 'contract'=>'infobox-contrat', 'check'=>'font-status4', 'collab'=>'infobox-action', 'conversation'=>'infobox-contrat',
4408 'donation'=>'infobox-commande', 'dolly'=>'infobox-commande', 'dollyrevert'=>'flip infobox-order_supplier',
4409 'ecm'=>'infobox-action', 'eventorganization'=>'infobox-project',
4410 'hrm'=>'infobox-adherent', 'group'=>'infobox-adherent', 'intervention'=>'infobox-contrat',
4411 'incoterm'=>'infobox-supplier_proposal',
4412 'currency'=>'infobox-bank_account', 'multicurrency'=>'infobox-bank_account',
4413 'members'=>'infobox-adherent', 'member'=>'infobox-adherent', 'money-bill-alt'=>'infobox-bank_account',
4414 'order'=>'infobox-commande',
4415 'user'=>'infobox-adherent', 'users'=>'infobox-adherent',
4416 'error'=>'pictoerror', 'warning'=>'pictowarning', 'switch_on'=>'font-status4', 'switch_on_warning'=>'font-status4 warning', 'switch_on_red'=>'font-status8',
4417 'holiday'=>'infobox-holiday', 'info'=>'opacityhigh', 'invoice'=>'infobox-commande',
4418 'knowledgemanagement'=>'infobox-contrat rotate90', 'loan'=>'infobox-bank_account',
4419 'payment'=>'infobox-bank_account', 'payment_vat'=>'infobox-bank_account', 'poll'=>'infobox-adherent', 'pos'=>'infobox-bank_account', 'project'=>'infobox-project', 'projecttask'=>'infobox-project',
4420 'propal'=>'infobox-propal', 'proposal'=>'infobox-propal','private'=>'infobox-project',
4421 'reception'=>'flip', 'recruitmentjobposition'=>'infobox-adherent', 'recruitmentcandidature'=>'infobox-adherent',
4422 'resource'=>'infobox-action',
4423 'salary'=>'infobox-bank_account', 'shipment'=>'infobox-commande', 'supplier_invoice'=>'infobox-order_supplier', 'supplier_invoicea'=>'infobox-order_supplier', 'supplier_invoiced'=>'infobox-order_supplier',
4424 'supplier'=>'infobox-order_supplier', 'supplier_order'=>'infobox-order_supplier', 'supplier_proposal'=>'infobox-supplier_proposal',
4425 'ticket'=>'infobox-contrat', 'title_accountancy'=>'infobox-bank_account', 'title_hrm'=>'infobox-holiday', 'expensereport'=>'infobox-expensereport', 'trip'=>'infobox-expensereport', 'title_agenda'=>'infobox-action',
4426 'vat'=>'infobox-bank_account',
4427 //'title_setup'=>'infobox-action', 'tools'=>'infobox-action',
4428 'list-alt'=>'imgforviewmode', 'calendar'=>'imgforviewmode', 'calendarweek'=>'imgforviewmode', 'calendarmonth'=>'imgforviewmode', 'calendarday'=>'imgforviewmode', 'calendarperuser'=>'imgforviewmode'
4429 );
4430 if (!empty($arrayconvpictotomorcess[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4431 $morecss .= ($morecss ? ' ' : '').$arrayconvpictotomorcess[$pictowithouttext];
4432 }
4433
4434 // Define $color
4435 $arrayconvpictotocolor = array(
4436 'address'=>'#6c6aa8', 'building'=>'#6c6aa8', 'bom'=>'#a69944',
4437 'clone'=>'#999', 'cog'=>'#999', 'companies'=>'#6c6aa8', 'company'=>'#6c6aa8', 'contact'=>'#6c6aa8', 'cron'=>'#555',
4438 'dynamicprice'=>'#a69944',
4439 'edit'=>'#444', 'note'=>'#999', 'error'=>'', 'help'=>'#bbb', 'listlight'=>'#999', 'language'=>'#555',
4440 //'dolly'=>'#a69944', 'dollyrevert'=>'#a69944',
4441 'lock'=>'#ddd', 'lot'=>'#a69944',
4442 'map-marker-alt'=>'#aaa', 'mrp'=>'#a69944', 'product'=>'#a69944', 'service'=>'#a69944', 'inventory'=>'#a69944', 'stock'=>'#a69944', 'movement'=>'#a69944',
4443 'other'=>'#ddd', 'world'=>'#986c6a',
4444 'partnership'=>'#6c6aa8', 'playdisabled'=>'#ccc', 'printer'=>'#444', 'projectpub'=>'#986c6a', 'reception'=>'#a69944', 'resize'=>'#444', 'rss'=>'#cba',
4445 //'shipment'=>'#a69944',
4446 'security'=>'#999', 'square'=>'#888', 'stop-circle'=>'#888', 'stats'=>'#444', 'switch_off'=>'#999', 'technic'=>'#999', 'timespent'=>'#555',
4447 'uncheck'=>'#800', 'uparrow'=>'#555', 'user-cog'=>'#999', 'country'=>'#aaa', 'globe-americas'=>'#aaa', 'region'=>'#aaa', 'state'=>'#aaa',
4448 'website'=>'#304', 'workstation'=>'#a69944'
4449 );
4450 if (isset($arrayconvpictotocolor[$pictowithouttext]) && strpos($picto, '_nocolor') === false) {
4451 $facolor = $arrayconvpictotocolor[$pictowithouttext];
4452 }
4453
4454 // This snippet only needed since function img_edit accepts only one additional parameter: no separate one for css only.
4455 // class/style need to be extracted to avoid duplicate class/style validation errors when $moreatt is added to the end of the attributes.
4456 $morestyle = '';
4457 $reg = array();
4458 if (preg_match('/class="([^"]+)"/', $moreatt, $reg)) {
4459 $morecss .= ($morecss ? ' ' : '').$reg[1];
4460 $moreatt = str_replace('class="'.$reg[1].'"', '', $moreatt);
4461 }
4462 if (preg_match('/style="([^"]+)"/', $moreatt, $reg)) {
4463 $morestyle = $reg[1];
4464 $moreatt = str_replace('style="'.$reg[1].'"', '', $moreatt);
4465 }
4466 $moreatt = trim($moreatt);
4467
4468 $enabledisablehtml = '<span class="'.$fa.' '.$fakey.($marginleftonlyshort ? ($marginleftonlyshort == 1 ? ' marginleftonlyshort' : ' marginleftonly') : '');
4469 $enabledisablehtml .= ($morecss ? ' '.$morecss : '').'" style="'.($fasize ? ('font-size: '.$fasize.';') : '').($facolor ? (' color: '.$facolor.';') : '').($morestyle ? ' '.$morestyle : '').'"'.(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt : '').'>';
4470 /*if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
4471 $enabledisablehtml .= $titlealt;
4472 }*/
4473 $enabledisablehtml .= '</span>';
4474
4475 return $enabledisablehtml;
4476 }
4477
4478 if (!empty($conf->global->MAIN_OVERWRITE_THEME_PATH)) {
4479 $path = $conf->global->MAIN_OVERWRITE_THEME_PATH.'/theme/'.$theme; // If the theme does not have the same name as the module
4480 } elseif (!empty($conf->global->MAIN_OVERWRITE_THEME_RES)) {
4481 $path = $conf->global->MAIN_OVERWRITE_THEME_RES.'/theme/'.$conf->global->MAIN_OVERWRITE_THEME_RES; // To allow an external module to overwrite image resources whatever is activated theme
4482 } elseif (!empty($conf->modules_parts['theme']) && array_key_exists($theme, $conf->modules_parts['theme'])) {
4483 $path = $theme.'/theme/'.$theme; // If the theme have the same name as the module
4484 }
4485
4486 // If we ask an image into $url/$mymodule/img (instead of default path)
4487 $regs = array();
4488 if (preg_match('/^([^@]+)@([^@]+)$/i', $picto, $regs)) {
4489 $picto = $regs[1];
4490 $path = $regs[2]; // $path is $mymodule
4491 }
4492
4493 // Clean parameters
4494 if (!preg_match('/(\.png|\.gif|\.svg)$/i', $picto)) {
4495 $picto .= '.png';
4496 }
4497 // If alt path are defined, define url where img file is, according to physical path
4498 // ex: array(["main"]=>"/home/maindir/htdocs", ["alt0"]=>"/home/moddir0/htdocs", ...)
4499 foreach ($conf->file->dol_document_root as $type => $dirroot) {
4500 if ($type == 'main') {
4501 continue;
4502 }
4503 // This need a lot of time, that's why enabling alternative dir like "custom" dir is not recommanded
4504 if (file_exists($dirroot.'/'.$path.'/img/'.$picto)) {
4505 $url = DOL_URL_ROOT.$conf->file->dol_url_root[$type];
4506 break;
4507 }
4508 }
4509
4510 // $url is '' or '/custom', $path is current theme or
4511 $fullpathpicto = $url.'/'.$path.'/img/'.$picto;
4512 }
4513
4514 if ($srconly) {
4515 return $fullpathpicto;
4516 }
4517
4518 // tag title is used for tooltip on <a>, tag alt can be used with very simple text on image for blind people
4519 return '<img src="'.$fullpathpicto.'"'.($notitle ? '' : ' alt="'.dol_escape_htmltag($alt).'"').(($notitle || empty($titlealt)) ? '' : ' title="'.dol_escape_htmltag($titlealt).'"').($moreatt ? ' '.$moreatt.($morecss ? ' class="'.$morecss.'"' : '') : ' class="inline-block'.($morecss ? ' '.$morecss : '').'"').'>'; // Alt is used for accessibility, title for popup
4520}
4521
4535function img_object($titlealt, $picto, $moreatt = '', $pictoisfullpath = false, $srconly = 0, $notitle = 0)
4536{
4537 if (strpos($picto, '^') === 0) {
4538 return img_picto($titlealt, str_replace('^', '', $picto), $moreatt, $pictoisfullpath, $srconly, $notitle);
4539 } else {
4540 return img_picto($titlealt, 'object_'.$picto, $moreatt, $pictoisfullpath, $srconly, $notitle);
4541 }
4542}
4543
4555function img_weather($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $morecss = '')
4556{
4557 global $conf;
4558
4559 if (is_numeric($picto)) {
4560 //$leveltopicto = array(0=>'weather-clear.png', 1=>'weather-few-clouds.png', 2=>'weather-clouds.png', 3=>'weather-many-clouds.png', 4=>'weather-storm.png');
4561 //$picto = $leveltopicto[$picto];
4562 return '<i class="fa fa-weather-level'.$picto.'"></i>';
4563 } elseif (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4564 $picto .= '.png';
4565 }
4566
4567 $path = DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/weather/'.$picto;
4568
4569 return img_picto($titlealt, $path, $moreatt, 1, 0, 0, '', $morecss);
4570}
4571
4583function img_picto_common($titlealt, $picto, $moreatt = '', $pictoisfullpath = 0, $notitle = 0)
4584{
4585 global $conf;
4586
4587 if (!preg_match('/(\.png|\.gif)$/i', $picto)) {
4588 $picto .= '.png';
4589 }
4590
4591 if ($pictoisfullpath) {
4592 $path = $picto;
4593 } else {
4594 $path = DOL_URL_ROOT.'/theme/common/'.$picto;
4595
4596 if (!empty($conf->global->MAIN_MODULE_CAN_OVERWRITE_COMMONICONS)) {
4597 $themepath = DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/'.$picto;
4598
4599 if (file_exists($themepath)) {
4600 $path = $themepath;
4601 }
4602 }
4603 }
4604
4605 return img_picto($titlealt, $path, $moreatt, 1, 0, $notitle);
4606}
4607
4621function img_action($titlealt, $numaction, $picto = '', $moreatt = '')
4622{
4623 global $langs;
4624
4625 if (empty($titlealt) || $titlealt == 'default') {
4626 if ($numaction == '-1' || $numaction == 'ST_NO') {
4627 $numaction = -1;
4628 $titlealt = $langs->transnoentitiesnoconv('ChangeDoNotContact');
4629 } elseif ($numaction == '0' || $numaction == 'ST_NEVER') {
4630 $numaction = 0;
4631 $titlealt = $langs->transnoentitiesnoconv('ChangeNeverContacted');
4632 } elseif ($numaction == '1' || $numaction == 'ST_TODO') {
4633 $numaction = 1;
4634 $titlealt = $langs->transnoentitiesnoconv('ChangeToContact');
4635 } elseif ($numaction == '2' || $numaction == 'ST_PEND') {
4636 $numaction = 2;
4637 $titlealt = $langs->transnoentitiesnoconv('ChangeContactInProcess');
4638 } elseif ($numaction == '3' || $numaction == 'ST_DONE') {
4639 $numaction = 3;
4640 $titlealt = $langs->transnoentitiesnoconv('ChangeContactDone');
4641 } else {
4642 $titlealt = $langs->transnoentitiesnoconv('ChangeStatus '.$numaction);
4643 $numaction = 0;
4644 }
4645 }
4646 if (!is_numeric($numaction)) {
4647 $numaction = 0;
4648 }
4649
4650 return img_picto($titlealt, (empty($picto) ? 'stcomm'.$numaction.'.png' : $picto), $moreatt);
4651}
4652
4660function img_pdf($titlealt = 'default', $size = 3)
4661{
4662 global $langs;
4663
4664 if ($titlealt == 'default') {
4665 $titlealt = $langs->trans('Show');
4666 }
4667
4668 return img_picto($titlealt, 'pdf'.$size.'.png');
4669}
4670
4678function img_edit_add($titlealt = 'default', $other = '')
4679{
4680 global $langs;
4681
4682 if ($titlealt == 'default') {
4683 $titlealt = $langs->trans('Add');
4684 }
4685
4686 return img_picto($titlealt, 'edit_add.png', $other);
4687}
4695function img_edit_remove($titlealt = 'default', $other = '')
4696{
4697 global $langs;
4698
4699 if ($titlealt == 'default') {
4700 $titlealt = $langs->trans('Remove');
4701 }
4702
4703 return img_picto($titlealt, 'edit_remove.png', $other);
4704}
4705
4714function img_edit($titlealt = 'default', $float = 0, $other = '')
4715{
4716 global $langs;
4717
4718 if ($titlealt == 'default') {
4719 $titlealt = $langs->trans('Modify');
4720 }
4721
4722 return img_picto($titlealt, 'edit.png', ($float ? 'style="float: '.($langs->tab_translate["DIRECTION"] == 'rtl' ? 'left' : 'right').'"' : "").($other ? ' '.$other : ''));
4723}
4724
4733function img_view($titlealt = 'default', $float = 0, $other = 'class="valignmiddle"')
4734{
4735 global $langs;
4736
4737 if ($titlealt == 'default') {
4738 $titlealt = $langs->trans('View');
4739 }
4740
4741 $moreatt = ($float ? 'style="float: right" ' : '').$other;
4742
4743 return img_picto($titlealt, 'eye', $moreatt);
4744}
4745
4754function img_delete($titlealt = 'default', $other = 'class="pictodelete"', $morecss = '')
4755{
4756 global $langs;
4757
4758 if ($titlealt == 'default') {
4759 $titlealt = $langs->trans('Delete');
4760 }
4761
4762 return img_picto($titlealt, 'delete.png', $other, false, 0, 0, '', $morecss);
4763}
4764
4772function img_printer($titlealt = "default", $other = '')
4773{
4774 global $langs;
4775 if ($titlealt == "default") {
4776 $titlealt = $langs->trans("Print");
4777 }
4778 return img_picto($titlealt, 'printer.png', $other);
4779}
4780
4788function img_split($titlealt = 'default', $other = 'class="pictosplit"')
4789{
4790 global $langs;
4791
4792 if ($titlealt == 'default') {
4793 $titlealt = $langs->trans('Split');
4794 }
4795
4796 return img_picto($titlealt, 'split.png', $other);
4797}
4798
4806function img_help($usehelpcursor = 1, $usealttitle = 1)
4807{
4808 global $langs;
4809
4810 if ($usealttitle) {
4811 if (is_string($usealttitle)) {
4812 $usealttitle = dol_escape_htmltag($usealttitle);
4813 } else {
4814 $usealttitle = $langs->trans('Info');
4815 }
4816 }
4817
4818 return img_picto($usealttitle, 'info.png', 'style="vertical-align: middle;'.($usehelpcursor == 1 ? ' cursor: help' : ($usehelpcursor == 2 ? ' cursor: pointer' : '')).'"');
4819}
4820
4827function img_info($titlealt = 'default')
4828{
4829 global $langs;
4830
4831 if ($titlealt == 'default') {
4832 $titlealt = $langs->trans('Informations');
4833 }
4834
4835 return img_picto($titlealt, 'info.png', 'style="vertical-align: middle;"');
4836}
4837
4846function img_warning($titlealt = 'default', $moreatt = '', $morecss = 'pictowarning')
4847{
4848 global $langs;
4849
4850 if ($titlealt == 'default') {
4851 $titlealt = $langs->trans('Warning');
4852 }
4853
4854 //return '<div class="imglatecoin">'.img_picto($titlealt, 'warning_white.png', 'class="pictowarning valignmiddle"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt): '')).'</div>';
4855 return img_picto($titlealt, 'warning.png', 'class="'.$morecss.'"'.($moreatt ? ($moreatt == '1' ? ' style="float: right"' : ' '.$moreatt) : ''));
4856}
4857
4864function img_error($titlealt = 'default')
4865{
4866 global $langs;
4867
4868 if ($titlealt == 'default') {
4869 $titlealt = $langs->trans('Error');
4870 }
4871
4872 return img_picto($titlealt, 'error.png');
4873}
4874
4882function img_next($titlealt = 'default', $moreatt = '')
4883{
4884 global $langs;
4885
4886 if ($titlealt == 'default') {
4887 $titlealt = $langs->trans('Next');
4888 }
4889
4890 //return img_picto($titlealt, 'next.png', $moreatt);
4891 return '<span class="fa fa-chevron-right paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
4892}
4893
4901function img_previous($titlealt = 'default', $moreatt = '')
4902{
4903 global $langs;
4904
4905 if ($titlealt == 'default') {
4906 $titlealt = $langs->trans('Previous');
4907 }
4908
4909 //return img_picto($titlealt, 'previous.png', $moreatt);
4910 return '<span class="fa fa-chevron-left paddingright paddingleft" title="'.dol_escape_htmltag($titlealt).'"></span>';
4911}
4912
4921function img_down($titlealt = 'default', $selected = 0, $moreclass = '')
4922{
4923 global $langs;
4924
4925 if ($titlealt == 'default') {
4926 $titlealt = $langs->trans('Down');
4927 }
4928
4929 return img_picto($titlealt, ($selected ? '1downarrow_selected.png' : '1downarrow.png'), 'class="imgdown'.($moreclass ? " ".$moreclass : "").'"');
4930}
4931
4940function img_up($titlealt = 'default', $selected = 0, $moreclass = '')
4941{
4942 global $langs;
4943
4944 if ($titlealt == 'default') {
4945 $titlealt = $langs->trans('Up');
4946 }
4947
4948 return img_picto($titlealt, ($selected ? '1uparrow_selected.png' : '1uparrow.png'), 'class="imgup'.($moreclass ? " ".$moreclass : "").'"');
4949}
4950
4959function img_left($titlealt = 'default', $selected = 0, $moreatt = '')
4960{
4961 global $langs;
4962
4963 if ($titlealt == 'default') {
4964 $titlealt = $langs->trans('Left');
4965 }
4966
4967 return img_picto($titlealt, ($selected ? '1leftarrow_selected.png' : '1leftarrow.png'), $moreatt);
4968}
4969
4978function img_right($titlealt = 'default', $selected = 0, $moreatt = '')
4979{
4980 global $langs;
4981
4982 if ($titlealt == 'default') {
4983 $titlealt = $langs->trans('Right');
4984 }
4985
4986 return img_picto($titlealt, ($selected ? '1rightarrow_selected.png' : '1rightarrow.png'), $moreatt);
4987}
4988
4996function img_allow($allow, $titlealt = 'default')
4997{
4998 global $langs;
4999
5000 if ($titlealt == 'default') {
5001 $titlealt = $langs->trans('Active');
5002 }
5003
5004 if ($allow == 1) {
5005 return img_picto($titlealt, 'tick.png');
5006 }
5007
5008 return '-';
5009}
5010
5018function img_credit_card($brand, $morecss = null)
5019{
5020 if (is_null($morecss)) {
5021 $morecss = 'fa-2x';
5022 }
5023
5024 if ($brand == 'visa' || $brand == 'Visa') {
5025 $brand = 'cc-visa';
5026 } elseif ($brand == 'mastercard' || $brand == 'MasterCard') {
5027 $brand = 'cc-mastercard';
5028 } elseif ($brand == 'amex' || $brand == 'American Express') {
5029 $brand = 'cc-amex';
5030 } elseif ($brand == 'discover' || $brand == 'Discover') {
5031 $brand = 'cc-discover';
5032 } elseif ($brand == 'jcb' || $brand == 'JCB') {
5033 $brand = 'cc-jcb';
5034 } elseif ($brand == 'diners' || $brand == 'Diners club') {
5035 $brand = 'cc-diners-club';
5036 } elseif (!in_array($brand, array('cc-visa', 'cc-mastercard', 'cc-amex', 'cc-discover', 'cc-jcb', 'cc-diners-club'))) {
5037 $brand = 'credit-card';
5038 }
5039
5040 return '<span class="fa fa-'.$brand.' fa-fw'.($morecss ? ' '.$morecss : '').'"></span>';
5041}
5042
5051function img_mime($file, $titlealt = '', $morecss = '')
5052{
5053 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
5054
5055 $mimetype = dol_mimetype($file, '', 1);
5056 $mimeimg = dol_mimetype($file, '', 2);
5057 $mimefa = dol_mimetype($file, '', 4);
5058
5059 if (empty($titlealt)) {
5060 $titlealt = 'Mime type: '.$mimetype;
5061 }
5062
5063 //return img_picto_common($titlealt, 'mime/'.$mimeimg, 'class="'.$morecss.'"');
5064 return '<i class="fa fa-'.$mimefa.' paddingright'.($morecss ? ' '.$morecss : '').'"'.($titlealt ? ' title="'.$titlealt.'"' : '').'></i>';
5065}
5066
5067
5075function img_search($titlealt = 'default', $other = '')
5076{
5077 global $conf, $langs;
5078
5079 if ($titlealt == 'default') {
5080 $titlealt = $langs->trans('Search');
5081 }
5082
5083 $img = img_picto($titlealt, 'search.png', $other, false, 1);
5084
5085 $input = '<input type="image" class="liste_titre" name="button_search" src="'.$img.'" ';
5086 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5087
5088 return $input;
5089}
5090
5098function img_searchclear($titlealt = 'default', $other = '')
5099{
5100 global $conf, $langs;
5101
5102 if ($titlealt == 'default') {
5103 $titlealt = $langs->trans('Search');
5104 }
5105
5106 $img = img_picto($titlealt, 'searchclear.png', $other, false, 1);
5107
5108 $input = '<input type="image" class="liste_titre" name="button_removefilter" src="'.$img.'" ';
5109 $input .= 'value="'.dol_escape_htmltag($titlealt).'" title="'.dol_escape_htmltag($titlealt).'" >';
5110
5111 return $input;
5112}
5113
5125function info_admin($text, $infoonimgalt = 0, $nodiv = 0, $admin = '1', $morecss = 'hideonsmartphone', $textfordropdown = '')
5126{
5127 global $conf, $langs;
5128
5129 if ($infoonimgalt) {
5130 $result = img_picto($text, 'info', 'class="'.($morecss ? ' '.$morecss : '').'"');
5131 } else {
5132 if (empty($conf->use_javascript_ajax)) {
5133 $textfordropdown = '';
5134 }
5135
5136 $class = (empty($admin) ? 'undefined' : ($admin == '1' ? 'info' : $admin));
5137 $result = ($nodiv ? '' : '<div class="'.$class.($morecss ? ' '.$morecss : '').($textfordropdown ? ' hidden' : '').'">').'<span class="fa fa-info-circle" title="'.dol_escape_htmltag($admin ? $langs->trans('InfoAdmin') : $langs->trans('Note')).'"></span> '.$text.($nodiv ? '' : '</div>');
5138
5139 if ($textfordropdown) {
5140 $tmpresult = '<span class="'.$class.'text opacitymedium cursorpointer">'.$langs->trans($textfordropdown).' '.img_picto($langs->trans($textfordropdown), '1downarrow').'</span>';
5141 $tmpresult .= '<script nonce="'.getNonce().'" type="text/javascript">
5142 jQuery(document).ready(function() {
5143 jQuery(".'.$class.'text").click(function() {
5144 console.log("toggle text");
5145 jQuery(".'.$class.'").toggle();
5146 });
5147 });
5148 </script>';
5149
5150 $result = $tmpresult.$result;
5151 }
5152 }
5153
5154 return $result;
5155}
5156
5157
5169function dol_print_error($db = '', $error = '', $errors = null)
5170{
5171 global $conf, $langs, $argv;
5172 global $dolibarr_main_prod;
5173
5174 $out = '';
5175 $syslog = '';
5176
5177 // If error occurs before the $lang object was loaded
5178 if (!$langs) {
5179 require_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
5180 $langs = new Translate('', $conf);
5181 $langs->load("main");
5182 }
5183
5184 // Load translation files required by the error messages
5185 $langs->loadLangs(array('main', 'errors'));
5186
5187 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5188 $out .= $langs->trans("DolibarrHasDetectedError").".<br>\n";
5189 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) {
5190 $out .= "You use an experimental or develop level of features, so please do NOT report any bugs or vulnerability, except if problem is confirmed after moving option MAIN_FEATURES_LEVEL back to 0.<br>\n";
5191 }
5192 $out .= $langs->trans("InformationToHelpDiagnose").":<br>\n";
5193
5194 $out .= "<b>".$langs->trans("Date").":</b> ".dol_print_date(time(), 'dayhourlog')."<br>\n";
5195 $out .= "<b>".$langs->trans("Dolibarr").":</b> ".DOL_VERSION." - https://www.dolibarr.org<br>\n";
5196 if (isset($conf->global->MAIN_FEATURES_LEVEL)) {
5197 $out .= "<b>".$langs->trans("LevelOfFeature").":</b> ".getDolGlobalInt('MAIN_FEATURES_LEVEL')."<br>\n";
5198 }
5199 if (function_exists("phpversion")) {
5200 $out .= "<b>".$langs->trans("PHP").":</b> ".phpversion()."<br>\n";
5201 }
5202 $out .= "<b>".$langs->trans("Server").":</b> ".(isset($_SERVER["SERVER_SOFTWARE"]) ? dol_htmlentities($_SERVER["SERVER_SOFTWARE"], ENT_COMPAT) : '')."<br>\n";
5203 if (function_exists("php_uname")) {
5204 $out .= "<b>".$langs->trans("OS").":</b> ".php_uname()."<br>\n";
5205 }
5206 $out .= "<b>".$langs->trans("UserAgent").":</b> ".(isset($_SERVER["HTTP_USER_AGENT"]) ? dol_htmlentities($_SERVER["HTTP_USER_AGENT"], ENT_COMPAT) : '')."<br>\n";
5207 $out .= "<br>\n";
5208 $out .= "<b>".$langs->trans("RequestedUrl").":</b> ".dol_htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT)."<br>\n";
5209 $out .= "<b>".$langs->trans("Referer").":</b> ".(isset($_SERVER["HTTP_REFERER"]) ? dol_htmlentities($_SERVER["HTTP_REFERER"], ENT_COMPAT) : '')."<br>\n";
5210 $out .= "<b>".$langs->trans("MenuManager").":</b> ".(isset($conf->standard_menu) ? dol_htmlentities($conf->standard_menu, ENT_COMPAT) : '')."<br>\n";
5211 $out .= "<br>\n";
5212 $syslog .= "url=".dol_escape_htmltag($_SERVER["REQUEST_URI"]);
5213 $syslog .= ", query_string=".dol_escape_htmltag($_SERVER["QUERY_STRING"]);
5214 } else { // Mode CLI
5215 $out .= '> '.$langs->transnoentities("ErrorInternalErrorDetected").":\n".$argv[0]."\n";
5216 $syslog .= "pid=".dol_getmypid();
5217 }
5218
5219 if (!empty($conf->modules)) {
5220 $out .= "<b>".$langs->trans("Modules").":</b> ".join(', ', $conf->modules)."<br>\n";
5221 }
5222
5223 if (is_object($db)) {
5224 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5225 $out .= "<b>".$langs->trans("DatabaseTypeManager").":</b> ".$db->type."<br>\n";
5226 $lastqueryerror = $db->lastqueryerror();
5227 if (!utf8_check($lastqueryerror)) {
5228 $lastqueryerror = "SQL error string is not a valid UTF8 string. We can't show it.";
5229 }
5230 $out .= "<b>".$langs->trans("RequestLastAccessInError").":</b> ".($lastqueryerror ? dol_escape_htmltag($lastqueryerror) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5231 $out .= "<b>".$langs->trans("ReturnCodeLastAccessInError").":</b> ".($db->lasterrno() ? dol_escape_htmltag($db->lasterrno()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5232 $out .= "<b>".$langs->trans("InformationLastAccessInError").":</b> ".($db->lasterror() ? dol_escape_htmltag($db->lasterror()) : $langs->trans("ErrorNoRequestInError"))."<br>\n";
5233 $out .= "<br>\n";
5234 } else { // Mode CLI
5235 // No dol_escape_htmltag for output, we are in CLI mode
5236 $out .= '> '.$langs->transnoentities("DatabaseTypeManager").":\n".$db->type."\n";
5237 $out .= '> '.$langs->transnoentities("RequestLastAccessInError").":\n".($db->lastqueryerror() ? $db->lastqueryerror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5238 $out .= '> '.$langs->transnoentities("ReturnCodeLastAccessInError").":\n".($db->lasterrno() ? $db->lasterrno() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5239 $out .= '> '.$langs->transnoentities("InformationLastAccessInError").":\n".($db->lasterror() ? $db->lasterror() : $langs->transnoentities("ErrorNoRequestInError"))."\n";
5240 }
5241 $syslog .= ", sql=".$db->lastquery();
5242 $syslog .= ", db_error=".$db->lasterror();
5243 }
5244
5245 if ($error || $errors) {
5246 $langs->load("errors");
5247
5248 // Merge all into $errors array
5249 if (is_array($error) && is_array($errors)) {
5250 $errors = array_merge($error, $errors);
5251 } elseif (is_array($error)) {
5252 $errors = $error;
5253 } elseif (is_array($errors)) {
5254 $errors = array_merge(array($error), $errors);
5255 } else {
5256 $errors = array_merge(array($error), array($errors));
5257 }
5258
5259 foreach ($errors as $msg) {
5260 if (empty($msg)) {
5261 continue;
5262 }
5263 if ($_SERVER['DOCUMENT_ROOT']) { // Mode web
5264 $out .= "<b>".$langs->trans("Message").":</b> ".dol_escape_htmltag($msg)."<br>\n";
5265 } else // Mode CLI
5266 {
5267 $out .= '> '.$langs->transnoentities("Message").":\n".$msg."\n";
5268 }
5269 $syslog .= ", msg=".$msg;
5270 }
5271 }
5272 if (empty($dolibarr_main_prod) && $_SERVER['DOCUMENT_ROOT'] && function_exists('xdebug_print_function_stack') && function_exists('xdebug_call_file')) {
5273 xdebug_print_function_stack();
5274 $out .= '<b>XDebug informations:</b>'."<br>\n";
5275 $out .= 'File: '.xdebug_call_file()."<br>\n";
5276 $out .= 'Line: '.xdebug_call_line()."<br>\n";
5277 $out .= 'Function: '.xdebug_call_function()."<br>\n";
5278 $out .= "<br>\n";
5279 }
5280
5281 // Return a http header with error code if possible
5282 if (!headers_sent()) {
5283 if (function_exists('top_httphead')) { // In CLI context, the method does not exists
5284 top_httphead();
5285 }
5286 //http_response_code(500); // If we use 500, message is not ouput with some command line tools
5287 http_response_code(202); // If we use 202, this is not really an error message, but this allow to ouput message on command line tools
5288 }
5289
5290 if (empty($dolibarr_main_prod)) {
5291 print $out;
5292 } else {
5293 if (empty($langs->defaultlang)) {
5294 $langs->setDefaultLang();
5295 }
5296 $langs->loadLangs(array("main", "errors")); // Reload main because language may have been set only on previous line so we have to reload files we need.
5297 // This should not happen, except if there is a bug somewhere. Enabled and check log in such case.
5298 print 'This website or feature is currently temporarly not available or failed after a technical error.<br><br>This may be due to a maintenance operation. Current status of operation ('.dol_print_date(dol_now(), 'dayhourrfc').') are on next line...<br><br>'."\n";
5299 print $langs->trans("DolibarrHasDetectedError").'. ';
5300 print $langs->trans("YouCanSetOptionDolibarrMainProdToZero");
5301 if (!defined("MAIN_CORE_ERROR")) {
5302 define("MAIN_CORE_ERROR", 1);
5303 }
5304 }
5305
5306 dol_syslog("Error ".$syslog, LOG_ERR);
5307}
5308
5319function dol_print_error_email($prefixcode, $errormessage = '', $errormessages = array(), $morecss = 'error', $email = '')
5320{
5321 global $langs, $conf;
5322
5323 if (empty($email)) {
5324 $email = $conf->global->MAIN_INFO_SOCIETE_MAIL;
5325 }
5326
5327 $langs->load("errors");
5328 $now = dol_now();
5329
5330 print '<br><div class="center login_main_message"><div class="'.$morecss.'">';
5331 print $langs->trans("ErrorContactEMail", $email, $prefixcode.'-'.dol_print_date($now, '%Y%m%d%H%M%S'));
5332 if ($errormessage) {
5333 print '<br><br>'.$errormessage;
5334 }
5335 if (is_array($errormessages) && count($errormessages)) {
5336 foreach ($errormessages as $mesgtoshow) {
5337 print '<br><br>'.$mesgtoshow;
5338 }
5339 }
5340 print '</div></div>';
5341}
5342
5359function print_liste_field_titre($name, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $tooltip = "", $forcenowrapcolumntitle = 0)
5360{
5361 print getTitleFieldOfList($name, 0, $file, $field, $begin, $moreparam, $moreattrib, $sortfield, $sortorder, $prefix, 0, $tooltip, $forcenowrapcolumntitle);
5362}
5363
5382function getTitleFieldOfList($name, $thead = 0, $file = "", $field = "", $begin = "", $moreparam = "", $moreattrib = "", $sortfield = "", $sortorder = "", $prefix = "", $disablesortlink = 0, $tooltip = '', $forcenowrapcolumntitle = 0)
5383{
5384 global $conf, $langs, $form;
5385 //print "$name, $file, $field, $begin, $options, $moreattrib, $sortfield, $sortorder<br>\n";
5386
5387 if ($moreattrib == 'class="right"') {
5388 $prefix .= 'right '; // For backward compatibility
5389 }
5390
5391 $sortorder = strtoupper($sortorder);
5392 $out = '';
5393 $sortimg = '';
5394
5395 $tag = 'th';
5396 if ($thead == 2) {
5397 $tag = 'div';
5398 }
5399
5400 $tmpsortfield = explode(',', $sortfield);
5401 $sortfield1 = trim($tmpsortfield[0]); // If $sortfield is 'd.datep,d.id', it becomes 'd.datep'
5402 $tmpfield = explode(',', $field);
5403 $field1 = trim($tmpfield[0]); // If $field is 'd.datep,d.id', it becomes 'd.datep'
5404
5405 if (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && empty($forcenowrapcolumntitle)) {
5406 $prefix = 'wrapcolumntitle '.$prefix;
5407 }
5408
5409 //var_dump('field='.$field.' field1='.$field1.' sortfield='.$sortfield.' sortfield1='.$sortfield1);
5410 // If field is used as sort criteria we use a specific css class liste_titre_sel
5411 // Example if (sortfield,field)=("nom","xxx.nom") or (sortfield,field)=("nom","nom")
5412 $liste_titre = 'liste_titre';
5413 if ($field1 && ($sortfield1 == $field1 || $sortfield1 == preg_replace("/^[^\.]+\./", "", $field1))) {
5414 $liste_titre = 'liste_titre_sel';
5415 }
5416
5417 $tagstart = '<'.$tag.' class="'.$prefix.$liste_titre.'" '.$moreattrib;
5418 //$out .= (($field && empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && preg_match('/^[a-zA-Z_0-9\s\.\-:&;]*$/', $name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5419 $tagstart .= ($name && empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) && empty($forcenowrapcolumntitle) && !dol_textishtml($name)) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '';
5420 $tagstart .= '>';
5421
5422 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5423 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5424 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5425 $options = preg_replace('/&+/i', '&', $options);
5426 if (!preg_match('/^&/', $options)) {
5427 $options = '&'.$options;
5428 }
5429
5430 $sortordertouseinlink = '';
5431 if ($field1 != $sortfield1) { // We are on another field than current sorted field
5432 if (preg_match('/^DESC/i', $sortorder)) {
5433 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5434 } else { // We reverse the var $sortordertouseinlink
5435 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5436 }
5437 } else { // We are on field that is the first current sorting criteria
5438 if (preg_match('/^ASC/i', $sortorder)) { // We reverse the var $sortordertouseinlink
5439 $sortordertouseinlink .= str_repeat('desc,', count(explode(',', $field)));
5440 } else {
5441 $sortordertouseinlink .= str_repeat('asc,', count(explode(',', $field)));
5442 }
5443 }
5444 $sortordertouseinlink = preg_replace('/,$/', '', $sortordertouseinlink);
5445 $out .= '<a class="reposition" href="'.$file.'?sortfield='.$field.'&sortorder='.$sortordertouseinlink.'&begin='.$begin.$options.'"';
5446 //$out .= (empty($conf->global->MAIN_DISABLE_WRAPPING_ON_COLUMN_TITLE) ? ' title="'.dol_escape_htmltag($langs->trans($name)).'"' : '');
5447 $out .= '>';
5448 }
5449 if ($tooltip) {
5450 // You can also use 'TranslationString:keyfortooltiponclick' for a tooltip on click.
5451 if (preg_match('/:\w+$/', $tooltip)) {
5452 $tmptooltip = explode(':', $tooltip);
5453 } else {
5454 $tmptooltip = array($tooltip);
5455 }
5456 $out .= $form->textwithpicto($langs->trans($name), $langs->trans($tmptooltip[0]), 1, 'help', '', 0, 3, (empty($tmptooltip[1]) ? '' : 'extra_'.str_replace('.', '_', $field).'_'.$tmptooltip[1]));
5457 } else {
5458 $out .= $langs->trans($name);
5459 }
5460
5461 if (empty($thead) && $field && empty($disablesortlink)) { // If this is a sort field
5462 $out .= '</a>';
5463 }
5464
5465 if (empty($thead) && $field) { // If this is a sort field
5466 $options = preg_replace('/sortfield=([a-zA-Z0-9,\s\.]+)/i', '', (is_scalar($moreparam) ? $moreparam : ''));
5467 $options = preg_replace('/sortorder=([a-zA-Z0-9,\s\.]+)/i', '', $options);
5468 $options = preg_replace('/&+/i', '&', $options);
5469 if (!preg_match('/^&/', $options)) {
5470 $options = '&'.$options;
5471 }
5472
5473 if (!$sortorder || ($field1 != $sortfield1)) {
5474 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5475 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5476 } else {
5477 if (preg_match('/^DESC/', $sortorder)) {
5478 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",0).'</a>';
5479 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",1).'</a>';
5480 $sortimg .= '<span class="nowrap">'.img_up("Z-A", 0, 'paddingright').'</span>';
5481 }
5482 if (preg_match('/^ASC/', $sortorder)) {
5483 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=asc&begin='.$begin.$options.'">'.img_down("A-Z",1).'</a>';
5484 //$out.= '<a href="'.$file.'?sortfield='.$field.'&sortorder=desc&begin='.$begin.$options.'">'.img_up("Z-A",0).'</a>';
5485 $sortimg .= '<span class="nowrap">'.img_down("A-Z", 0, 'paddingright').'</span>';
5486 }
5487 }
5488 }
5489
5490 $tagend = '</'.$tag.'>';
5491
5492 $out = $tagstart.$sortimg.$out.$tagend;
5493
5494 return $out;
5495}
5496
5505function print_titre($title)
5506{
5507 dol_syslog(__FUNCTION__." is deprecated", LOG_WARNING);
5508
5509 print '<div class="titre">'.$title.'</div>';
5510}
5511
5523function print_fiche_titre($title, $mesg = '', $picto = 'generic', $pictoisfullpath = 0, $id = '')
5524{
5525 print load_fiche_titre($title, $mesg, $picto, $pictoisfullpath, $id);
5526}
5527
5541function load_fiche_titre($titre, $morehtmlright = '', $picto = 'generic', $pictoisfullpath = 0, $id = '', $morecssontable = '', $morehtmlcenter = '')
5542{
5543 global $conf;
5544
5545 $return = '';
5546
5547 if ($picto == 'setup') {
5548 $picto = 'generic';
5549 }
5550
5551 $return .= "\n";
5552 $return .= '<table '.($id ? 'id="'.$id.'" ' : '').'class="centpercent notopnoleftnoright table-fiche-title'.($morecssontable ? ' '.$morecssontable : '').'">'; // maring bottom must be same than into print_barre_list
5553 $return .= '<tr class="titre">';
5554 if ($picto) {
5555 $return .= '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle widthpictotitle pictotitle"', $pictoisfullpath).'</td>';
5556 }
5557 $return .= '<td class="nobordernopadding valignmiddle col-title">';
5558 $return .= '<div class="titre inline-block">'.$titre.'</div>';
5559 $return .= '</td>';
5560 if (dol_strlen($morehtmlcenter)) {
5561 $return .= '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5562 }
5563 if (dol_strlen($morehtmlright)) {
5564 $return .= '<td class="nobordernopadding titre_right wordbreakimp right valignmiddle col-right">'.$morehtmlright.'</td>';
5565 }
5566 $return .= '</tr></table>'."\n";
5567
5568 return $return;
5569}
5570
5594function print_barre_liste($titre, $page, $file, $options = '', $sortfield = '', $sortorder = '', $morehtmlcenter = '', $num = -1, $totalnboflines = '', $picto = 'generic', $pictoisfullpath = 0, $morehtmlright = '', $morecss = '', $limit = -1, $hideselectlimit = 0, $hidenavigation = 0, $pagenavastextinput = 0, $morehtmlrightbeforearrow = '')
5595{
5596 global $conf, $langs;
5597
5598 $savlimit = $limit;
5599 $savtotalnboflines = $totalnboflines;
5600 $totalnboflines = abs((int) $totalnboflines);
5601
5602 $page = (int) $page;
5603
5604 if ($picto == 'setup') {
5605 $picto = 'title_setup.png';
5606 }
5607 if (($conf->browser->name == 'ie') && $picto == 'generic') {
5608 $picto = 'title.gif';
5609 }
5610 if ($limit < 0) {
5611 $limit = $conf->liste_limit;
5612 }
5613
5614 if ($savlimit != 0 && (($num > $limit) || ($num == -1) || ($limit == 0))) {
5615 $nextpage = 1;
5616 } else {
5617 $nextpage = 0;
5618 }
5619 //print 'totalnboflines='.$totalnboflines.'-savlimit='.$savlimit.'-limit='.$limit.'-num='.$num.'-nextpage='.$nextpage.'-hideselectlimit='.$hideselectlimit.'-hidenavigation='.$hidenavigation;
5620
5621 print "\n";
5622 print "<!-- Begin title -->\n";
5623 print '<table class="centpercent notopnoleftnoright table-fiche-title'.($morecss ? ' '.$morecss : '').'"><tr>'; // maring bottom must be same than into load_fiche_tire
5624
5625 // Left
5626
5627 if ($picto && $titre) {
5628 print '<td class="nobordernopadding widthpictotitle valignmiddle col-picto">'.img_picto('', $picto, 'class="valignmiddle pictotitle widthpictotitle"', $pictoisfullpath).'</td>';
5629 }
5630
5631 print '<td class="nobordernopadding valignmiddle col-title">';
5632 print '<div class="titre inline-block">'.$titre;
5633 if (!empty($titre) && $savtotalnboflines >= 0 && (string) $savtotalnboflines != '') {
5634 print '<span class="opacitymedium colorblack paddingleft">('.$totalnboflines.')</span>';
5635 }
5636 print '</div></td>';
5637
5638 // Center
5639 if ($morehtmlcenter && empty($conf->dol_optimize_smallscreen)) {
5640 print '<td class="nobordernopadding center valignmiddle col-center">'.$morehtmlcenter.'</td>';
5641 }
5642
5643 // Right
5644 print '<td class="nobordernopadding valignmiddle right col-right">';
5645 print '<input type="hidden" name="pageplusoneold" value="'.((int) $page + 1).'">';
5646 if ($sortfield) {
5647 $options .= "&sortfield=".urlencode($sortfield);
5648 }
5649 if ($sortorder) {
5650 $options .= "&sortorder=".urlencode($sortorder);
5651 }
5652 // Show navigation bar
5653 $pagelist = '';
5654 if ($savlimit != 0 && ($page > 0 || $num > $limit)) {
5655 if ($totalnboflines) { // If we know total nb of lines
5656 // Define nb of extra page links before and after selected page + ... + first or last
5657 $maxnbofpage = (empty($conf->dol_optimize_smallscreen) ? 4 : 0);
5658
5659 if ($limit > 0) {
5660 $nbpages = ceil($totalnboflines / $limit);
5661 } else {
5662 $nbpages = 1;
5663 }
5664 $cpt = ($page - $maxnbofpage);
5665 if ($cpt < 0) {
5666 $cpt = 0;
5667 }
5668
5669 if ($cpt >= 1) {
5670 if (empty($pagenavastextinput)) {
5671 $pagelist .= '<li class="pagination"><a href="'.$file.'?page=0'.$options.'">1</a></li>';
5672 if ($cpt > 2) {
5673 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5674 } elseif ($cpt == 2) {
5675 $pagelist .= '<li class="pagination"><a href="'.$file.'?page=1'.$options.'">2</a></li>';
5676 }
5677 }
5678 }
5679
5680 do {
5681 if ($pagenavastextinput) {
5682 if ($cpt == $page) {
5683 $pagelist .= '<li class="pagination"><input type="text" class="'.($totalnboflines > 100 ? 'width40' : 'width25').' center pageplusone" name="pageplusone" value="'.($page + 1).'"></li>';
5684 $pagelist .= '/';
5685 }
5686 } else {
5687 if ($cpt == $page) {
5688 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1).'</span></li>';
5689 } else {
5690 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.$cpt.$options.'">'.($cpt + 1).'</a></li>';
5691 }
5692 }
5693 $cpt++;
5694 } while ($cpt < $nbpages && $cpt <= ($page + $maxnbofpage));
5695
5696 if (empty($pagenavastextinput)) {
5697 if ($cpt < $nbpages) {
5698 if ($cpt < $nbpages - 2) {
5699 $pagelist .= '<li class="pagination"><span class="inactive">...</span></li>';
5700 } elseif ($cpt == $nbpages - 2) {
5701 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.($nbpages - 2).$options.'">'.($nbpages - 1).'</a></li>';
5702 }
5703 $pagelist .= '<li class="pagination"><a href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5704 }
5705 } else {
5706 //var_dump($page.' '.$cpt.' '.$nbpages);
5707 $pagelist .= '<li class="pagination paginationlastpage"><a href="'.$file.'?page='.($nbpages - 1).$options.'">'.$nbpages.'</a></li>';
5708 }
5709 } else {
5710 $pagelist .= '<li class="pagination"><span class="active">'.($page + 1)."</li>";
5711 }
5712 }
5713
5714 if ($savlimit || $morehtmlright || $morehtmlrightbeforearrow) {
5715 print_fleche_navigation($page, $file, $options, $nextpage, $pagelist, $morehtmlright, $savlimit, $totalnboflines, $hideselectlimit, $morehtmlrightbeforearrow, $hidenavigation); // output the div and ul for previous/last completed with page numbers into $pagelist
5716 }
5717
5718 // js to autoselect page field on focus
5719 if ($pagenavastextinput) {
5720 print ajax_autoselect('.pageplusone');
5721 }
5722
5723 print '</td>';
5724 print '</tr>';
5725
5726 print '</table>'."\n";
5727
5728 // Center
5729 if ($morehtmlcenter && !empty($conf->dol_optimize_smallscreen)) {
5730 print '<div class="nobordernopadding marginbottomonly center valignmiddle col-center centpercent">'.$morehtmlcenter.'</div>';
5731 }
5732
5733 print "<!-- End title -->\n\n";
5734}
5735
5752function print_fleche_navigation($page, $file, $options = '', $nextpage = 0, $betweenarrows = '', $afterarrows = '', $limit = -1, $totalnboflines = 0, $hideselectlimit = 0, $beforearrows = '', $hidenavigation = 0)
5753{
5754 global $conf, $langs;
5755
5756 print '<div class="pagination"><ul>';
5757 if ($beforearrows) {
5758 print '<li class="paginationbeforearrows">';
5759 print $beforearrows;
5760 print '</li>';
5761 }
5762
5763 if (empty($hidenavigation)) {
5764 if ((int) $limit > 0 && empty($hideselectlimit)) {
5765 $pagesizechoices = '10:10,15:15,20:20,30:30,40:40,50:50,100:100,250:250,500:500,1000:1000';
5766 $pagesizechoices .= ',5000:5000,10000:10000,20000:20000';
5767 //$pagesizechoices.=',0:'.$langs->trans("All"); // Not yet supported
5768 //$pagesizechoices.=',2:2';
5769 if (!empty($conf->global->MAIN_PAGESIZE_CHOICES)) {
5770 $pagesizechoices = $conf->global->MAIN_PAGESIZE_CHOICES;
5771 }
5772
5773 print '<li class="pagination">';
5774 print '<select class="flat selectlimit" name="limit" title="'.dol_escape_htmltag($langs->trans("MaxNbOfRecordPerPage")).'">';
5775 $tmpchoice = explode(',', $pagesizechoices);
5776 $tmpkey = $limit.':'.$limit;
5777 if (!in_array($tmpkey, $tmpchoice)) {
5778 $tmpchoice[] = $tmpkey;
5779 }
5780 $tmpkey = $conf->liste_limit.':'.$conf->liste_limit;
5781 if (!in_array($tmpkey, $tmpchoice)) {
5782 $tmpchoice[] = $tmpkey;
5783 }
5784 asort($tmpchoice, SORT_NUMERIC);
5785 foreach ($tmpchoice as $val) {
5786 $selected = '';
5787 $tmp = explode(':', $val);
5788 $key = $tmp[0];
5789 $val = $tmp[1];
5790 if ($key != '' && $val != '') {
5791 if ((int) $key == (int) $limit) {
5792 $selected = ' selected="selected"';
5793 }
5794 print '<option name="'.$key.'"'.$selected.'>'.dol_escape_htmltag($val).'</option>'."\n";
5795 }
5796 }
5797 print '</select>';
5798 if ($conf->use_javascript_ajax) {
5799 print '<!-- JS CODE TO ENABLE select limit to launch submit of page -->
5800 <script>
5801 jQuery(document).ready(function () {
5802 jQuery(".selectlimit").change(function() {
5803 console.log("Change limit. Send submit");
5804 $(this).parents(\'form:first\').submit();
5805 });
5806 });
5807 </script>
5808 ';
5809 }
5810 print '</li>';
5811 }
5812 if ($page > 0) {
5813 print '<li class="pagination paginationpage paginationpageleft"><a class="paginationprevious" href="'.$file.'?page='.($page - 1).$options.'"><i class="fa fa-chevron-left" title="'.dol_escape_htmltag($langs->trans("Previous")).'"></i></a></li>';
5814 }
5815 if ($betweenarrows) {
5816 print '<!--<div class="betweenarrows nowraponall inline-block">-->';
5817 print $betweenarrows;
5818 print '<!--</div>-->';
5819 }
5820 if ($nextpage > 0) {
5821 print '<li class="pagination paginationpage paginationpageright"><a class="paginationnext" href="'.$file.'?page='.($page + 1).$options.'"><i class="fa fa-chevron-right" title="'.dol_escape_htmltag($langs->trans("Next")).'"></i></a></li>';
5822 }
5823 if ($afterarrows) {
5824 print '<li class="paginationafterarrows">';
5825 print $afterarrows;
5826 print '</li>';
5827 }
5828 }
5829 print '</ul></div>'."\n";
5830}
5831
5832
5844function vatrate($rate, $addpercent = false, $info_bits = 0, $usestarfornpr = 0, $html = 0)
5845{
5846 $morelabel = '';
5847
5848 if (preg_match('/%/', $rate)) {
5849 $rate = str_replace('%', '', $rate);
5850 $addpercent = true;
5851 }
5852 $reg = array();
5853 if (preg_match('/\‍((.*)\‍)/', $rate, $reg)) {
5854 $morelabel = ' ('.$reg[1].')';
5855 $rate = preg_replace('/\s*'.preg_quote($morelabel, '/').'/', '', $rate);
5856 $morelabel = ' '.($html ? '<span class="opacitymedium">' : '').'('.$reg[1].')'.($html ? '</span>' : '');
5857 }
5858 if (preg_match('/\*/', $rate)) {
5859 $rate = str_replace('*', '', $rate);
5860 $info_bits |= 1;
5861 }
5862
5863 // If rate is '9/9/9' we don't change it. If rate is '9.000' we apply price()
5864 if (!preg_match('/\//', $rate)) {
5865 $ret = price($rate, 0, '', 0, 0).($addpercent ? '%' : '');
5866 } else {
5867 // TODO Split on / and output with a price2num to have clean numbers without ton of 000.
5868 $ret = $rate.($addpercent ? '%' : '');
5869 }
5870 if (($info_bits & 1) && $usestarfornpr >= 0) {
5871 $ret .= ' *';
5872 }
5873 $ret .= $morelabel;
5874 return $ret;
5875}
5876
5877
5893function price($amount, $form = 0, $outlangs = '', $trunc = 1, $rounding = -1, $forcerounding = -1, $currency_code = '')
5894{
5895 global $langs, $conf;
5896
5897 // Clean parameters
5898 if (empty($amount)) {
5899 $amount = 0; // To have a numeric value if amount not defined or = ''
5900 }
5901 $amount = (is_numeric($amount) ? $amount : 0); // Check if amount is numeric, for example, an error occured when amount value = o (letter) instead 0 (number)
5902 if ($rounding == -1) {
5903 $rounding = min($conf->global->MAIN_MAX_DECIMALS_UNIT, $conf->global->MAIN_MAX_DECIMALS_TOT);
5904 }
5905 $nbdecimal = $rounding;
5906
5907 if ($outlangs === 'none') {
5908 // Use international separators
5909 $dec = '.';
5910 $thousand = '';
5911 } else {
5912 // Output separators by default (french)
5913 $dec = ',';
5914 $thousand = ' ';
5915
5916 // If $outlangs not forced, we use use language
5917 if (!is_object($outlangs)) {
5918 $outlangs = $langs;
5919 }
5920
5921 if ($outlangs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
5922 $dec = $outlangs->transnoentitiesnoconv("SeparatorDecimal");
5923 }
5924 if ($outlangs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
5925 $thousand = $outlangs->transnoentitiesnoconv("SeparatorThousand");
5926 }
5927 if ($thousand == 'None') {
5928 $thousand = '';
5929 } elseif ($thousand == 'Space') {
5930 $thousand = ' ';
5931 }
5932 }
5933 //print "outlangs=".$outlangs->defaultlang." amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
5934
5935 //print "amount=".$amount."-";
5936 $amount = str_replace(',', '.', $amount); // should be useless
5937 //print $amount."-";
5938 $datas = explode('.', $amount);
5939 $decpart = isset($datas[1]) ? $datas[1] : '';
5940 $decpart = preg_replace('/0+$/i', '', $decpart); // Supprime les 0 de fin de partie decimale
5941 //print "decpart=".$decpart."<br>";
5942 $end = '';
5943
5944 // We increase nbdecimal if there is more decimal than asked (to not loose information)
5945 if (dol_strlen($decpart) > $nbdecimal) {
5946 $nbdecimal = dol_strlen($decpart);
5947 }
5948 // Si on depasse max
5949 $max_nbdecimal = (int) str_replace('...', '', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'));
5950 if ($trunc && $nbdecimal > $max_nbdecimal) {
5951 $nbdecimal = $max_nbdecimal;
5952 if (preg_match('/\.\.\./i', getDolGlobalString('MAIN_MAX_DECIMALS_SHOWN'))) {
5953 // Si un affichage est tronque, on montre des ...
5954 $end = '...';
5955 }
5956 }
5957
5958 // If force rounding
5959 if ((string) $forcerounding != '-1') {
5960 if ($forcerounding === 'MU') {
5961 $nbdecimal = $conf->global->MAIN_MAX_DECIMALS_UNIT;
5962 } elseif ($forcerounding === 'MT') {
5963 $nbdecimal = $conf->global->MAIN_MAX_DECIMALS_TOT;
5964 } elseif ($forcerounding >= 0) {
5965 $nbdecimal = $forcerounding;
5966 }
5967 }
5968
5969 // Format number
5970 $output = number_format($amount, $nbdecimal, $dec, $thousand);
5971 if ($form) {
5972 $output = preg_replace('/\s/', '&nbsp;', $output);
5973 $output = preg_replace('/\'/', '&#039;', $output);
5974 }
5975 // Add symbol of currency if requested
5976 $cursymbolbefore = $cursymbolafter = '';
5977 if ($currency_code && is_object($outlangs)) {
5978 if ($currency_code == 'auto') {
5979 $currency_code = $conf->currency;
5980 }
5981
5982 $listofcurrenciesbefore = array('AUD', 'CAD', 'CNY', 'COP', 'CLP', 'GBP', 'HKD', 'MXN', 'PEN', 'USD', 'CRC');
5983 $listoflanguagesbefore = array('nl_NL');
5984 if (in_array($currency_code, $listofcurrenciesbefore) || in_array($outlangs->defaultlang, $listoflanguagesbefore)) {
5985 $cursymbolbefore .= $outlangs->getCurrencySymbol($currency_code);
5986 } else {
5987 $tmpcur = $outlangs->getCurrencySymbol($currency_code);
5988 $cursymbolafter .= ($tmpcur == $currency_code ? ' '.$tmpcur : $tmpcur);
5989 }
5990 }
5991 $output = $cursymbolbefore.$output.$end.($cursymbolafter ? ' ' : '').$cursymbolafter;
5992
5993 return $output;
5994}
5995
6020function price2num($amount, $rounding = '', $option = 0)
6021{
6022 global $langs, $conf;
6023
6024 // Clean parameters
6025 if (is_null($amount)) {
6026 $amount = '';
6027 }
6028
6029 // Round PHP function does not allow number like '1,234.56' nor '1.234,56' nor '1 234,56'
6030 // Numbers must be '1234.56'
6031 // Decimal delimiter for PHP and database SQL requests must be '.'
6032 $dec = ',';
6033 $thousand = ' ';
6034 if (is_null($langs)) { // $langs is not defined, we use english values.
6035 $dec = '.';
6036 $thousand = ',';
6037 } else {
6038 if ($langs->transnoentitiesnoconv("SeparatorDecimal") != "SeparatorDecimal") {
6039 $dec = $langs->transnoentitiesnoconv("SeparatorDecimal");
6040 }
6041 if ($langs->transnoentitiesnoconv("SeparatorThousand") != "SeparatorThousand") {
6042 $thousand = $langs->transnoentitiesnoconv("SeparatorThousand");
6043 }
6044 }
6045 if ($thousand == 'None') {
6046 $thousand = '';
6047 } elseif ($thousand == 'Space') {
6048 $thousand = ' ';
6049 }
6050 //print "amount=".$amount." html=".$form." trunc=".$trunc." nbdecimal=".$nbdecimal." dec='".$dec."' thousand='".$thousand."'<br>";
6051
6052 // Convert value to universal number format (no thousand separator, '.' as decimal separator)
6053 if ($option != 1) { // If not a PHP number or unknown, we change or clean format
6054 //print "\n".'PP'.$amount.' - '.$dec.' - '.$thousand.' - '.intval($amount).'<br>';
6055 if (!is_numeric($amount)) {
6056 $amount = preg_replace('/[a-zA-Z\/\\\*\‍(\‍)<>\_]/', '', $amount);
6057 }
6058
6059 if ($option == 2 && $thousand == '.' && preg_match('/\.(\d\d\d)$/', (string) $amount)) { // It means the . is used as a thousand separator and string come from input data, so 1.123 is 1123
6060 $amount = str_replace($thousand, '', $amount);
6061 }
6062
6063 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6064 // to format defined by LC_NUMERIC after a calculation and we want source format to be like defined by Dolibarr setup.
6065 // So if number was already a good number, it is converted into local Dolibarr setup.
6066 if (is_numeric($amount)) {
6067 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6068 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6069 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6070 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6071 $amount = number_format($amount, $nbofdec, $dec, $thousand);
6072 }
6073 //print "QQ".$amount."<br>\n";
6074
6075 // Now make replace (the main goal of function)
6076 if ($thousand != ',' && $thousand != '.') {
6077 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6078 }
6079
6080 $amount = str_replace(' ', '', $amount); // To avoid spaces
6081 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6082 $amount = str_replace($dec, '.', $amount);
6083
6084 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6085 }
6086 //print ' XX'.$amount.' '.$rounding;
6087
6088 // Now, $amount is a real PHP float number. We make a rounding if required.
6089 if ($rounding) {
6090 $nbofdectoround = '';
6091 if ($rounding == 'MU') {
6092 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_UNIT;
6093 } elseif ($rounding == 'MT') {
6094 $nbofdectoround = $conf->global->MAIN_MAX_DECIMALS_TOT;
6095 } elseif ($rounding == 'MS') {
6096 $nbofdectoround = isset($conf->global->MAIN_MAX_DECIMALS_STOCK) ? $conf->global->MAIN_MAX_DECIMALS_STOCK : 5;
6097 } elseif ($rounding == 'CU') {
6098 $nbofdectoround = max($conf->global->MAIN_MAX_DECIMALS_UNIT, 8); // TODO Use param of currency
6099 } elseif ($rounding == 'CT') {
6100 $nbofdectoround = max($conf->global->MAIN_MAX_DECIMALS_TOT, 8); // TODO Use param of currency
6101 } elseif (is_numeric($rounding)) {
6102 $nbofdectoround = (int) $rounding;
6103 }
6104
6105 //print " RR".$amount.' - '.$nbofdectoround.'<br>';
6106 if (dol_strlen($nbofdectoround)) {
6107 $amount = round(is_string($amount) ? (float) $amount : $amount, $nbofdectoround); // $nbofdectoround can be 0.
6108 } else {
6109 return 'ErrorBadParameterProvidedToFunction';
6110 }
6111 //print ' SS'.$amount.' - '.$nbofdec.' - '.$dec.' - '.$thousand.' - '.$nbofdectoround.'<br>';
6112
6113 // Convert amount to format with dolibarr dec and thousand (this is because PHP convert a number
6114 // to format defined by LC_NUMERIC after a calculation and we want source format to be defined by Dolibarr setup.
6115 if (is_numeric($amount)) {
6116 // We put in temps value of decimal ("0.00001"). Works with 0 and 2.0E-5 and 9999.10
6117 $temps = sprintf("%0.10F", $amount - intval($amount)); // temps=0.0000000000 or 0.0000200000 or 9999.1000000000
6118 $temps = preg_replace('/([\.1-9])0+$/', '\\1', $temps); // temps=0. or 0.00002 or 9999.1
6119 $nbofdec = max(0, dol_strlen($temps) - 2); // -2 to remove "0."
6120 $amount = number_format($amount, min($nbofdec, $nbofdectoround), $dec, $thousand); // Convert amount to format with dolibarr dec and thousand
6121 }
6122 //print "TT".$amount.'<br>';
6123
6124 // Always make replace because each math function (like round) replace
6125 // with local values and we want a number that has a SQL string format x.y
6126 if ($thousand != ',' && $thousand != '.') {
6127 $amount = str_replace(',', '.', $amount); // To accept 2 notations for french users
6128 }
6129
6130 $amount = str_replace(' ', '', $amount); // To avoid spaces
6131 $amount = str_replace($thousand, '', $amount); // Replace of thousand before replace of dec to avoid pb if thousand is .
6132 $amount = str_replace($dec, '.', $amount);
6133
6134 $amount = preg_replace('/[^0-9\-\.]/', '', $amount); // Clean non numeric chars (so it clean some UTF8 spaces for example.
6135 }
6136
6137 return $amount;
6138}
6139
6152function showDimensionInBestUnit($dimension, $unit, $type, $outputlangs, $round = -1, $forceunitoutput = 'no', $use_short_label = 0)
6153{
6154 require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
6155
6156 if (($forceunitoutput == 'no' && $dimension < 1 / 10000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -6)) {
6157 $dimension = $dimension * 1000000;
6158 $unit = $unit - 6;
6159 } elseif (($forceunitoutput == 'no' && $dimension < 1 / 10 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == -3)) {
6160 $dimension = $dimension * 1000;
6161 $unit = $unit - 3;
6162 } elseif (($forceunitoutput == 'no' && $dimension > 100000000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 6)) {
6163 $dimension = $dimension / 1000000;
6164 $unit = $unit + 6;
6165 } elseif (($forceunitoutput == 'no' && $dimension > 100000 && $unit < 90) || (is_numeric($forceunitoutput) && $forceunitoutput == 3)) {
6166 $dimension = $dimension / 1000;
6167 $unit = $unit + 3;
6168 }
6169 // Special case when we want output unit into pound or ounce
6170 /* TODO
6171 if ($unit < 90 && $type == 'weight' && is_numeric($forceunitoutput) && (($forceunitoutput == 98) || ($forceunitoutput == 99))
6172 {
6173 $dimension = // convert dimension from standard unit into ounce or pound
6174 $unit = $forceunitoutput;
6175 }
6176 if ($unit > 90 && $type == 'weight' && is_numeric($forceunitoutput) && $forceunitoutput < 90)
6177 {
6178 $dimension = // convert dimension from standard unit into ounce or pound
6179 $unit = $forceunitoutput;
6180 }*/
6181
6182 $ret = price($dimension, 0, $outputlangs, 0, 0, $round);
6183 $ret .= ' '.measuringUnitString(0, $type, $unit, $use_short_label, $outputlangs);
6184
6185 return $ret;
6186}
6187
6188
6201function get_localtax($vatrate, $local, $thirdparty_buyer = "", $thirdparty_seller = "", $vatnpr = 0)
6202{
6203 global $db, $conf, $mysoc;
6204
6205 if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
6206 $thirdparty_seller = $mysoc;
6207 }
6208
6209 dol_syslog("get_localtax tva=".$vatrate." local=".$local." thirdparty_buyer id=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->id : '')."/country_code=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->country_code : '')." thirdparty_seller id=".$thirdparty_seller->id."/country_code=".$thirdparty_seller->country_code." thirdparty_seller localtax1_assuj=".$thirdparty_seller->localtax1_assuj." thirdparty_seller localtax2_assuj=".$thirdparty_seller->localtax2_assuj);
6210
6211 $vatratecleaned = $vatrate;
6212 $reg = array();
6213 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6214 $vatratecleaned = trim($reg[1]);
6215 $vatratecode = $reg[2];
6216 }
6217
6218 /*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
6219 {
6220 return 0;
6221 }*/
6222
6223 // Some test to guess with no need to make database access
6224 if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
6225 if ($local == 1) {
6226 if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
6227 return 0;
6228 }
6229 if ($thirdparty_seller->id == $mysoc->id) {
6230 if (!$thirdparty_buyer->localtax1_assuj) {
6231 return 0;
6232 }
6233 } else {
6234 if (!$thirdparty_seller->localtax1_assuj) {
6235 return 0;
6236 }
6237 }
6238 }
6239
6240 if ($local == 2) {
6241 //if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
6242 if (!$mysoc->localtax2_assuj) {
6243 return 0; // If main vat is 0, IRPF may be different than 0.
6244 }
6245 if ($thirdparty_seller->id == $mysoc->id) {
6246 if (!$thirdparty_buyer->localtax2_assuj) {
6247 return 0;
6248 }
6249 } else {
6250 if (!$thirdparty_seller->localtax2_assuj) {
6251 return 0;
6252 }
6253 }
6254 }
6255 } else {
6256 if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
6257 return 0;
6258 }
6259 if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
6260 return 0;
6261 }
6262 }
6263
6264 // For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
6265 if (in_array($mysoc->country_code, array('ES'))) {
6266 $conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
6267 }
6268
6269 // Search local taxes
6270 if (!empty($conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY)) {
6271 if ($local == 1) {
6272 if ($thirdparty_seller != $mysoc) {
6273 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6274 return $thirdparty_seller->localtax1_value;
6275 }
6276 } else { // i am the seller
6277 if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
6278 return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
6279 }
6280 }
6281 }
6282 if ($local == 2) {
6283 if ($thirdparty_seller != $mysoc) {
6284 if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
6285 // TODO We should also return value defined on thirdparty only if defined
6286 return $thirdparty_seller->localtax2_value;
6287 }
6288 } else { // i am the seller
6289 if (in_array($mysoc->country_code, array('ES'))) {
6290 return $thirdparty_buyer->localtax2_value;
6291 } else {
6292 return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
6293 }
6294 }
6295 }
6296 }
6297
6298 // By default, search value of local tax on line of common tax
6299 $sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
6300 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6301 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
6302 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6303 if (!empty($vatratecode)) {
6304 $sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
6305 } else {
6306 $sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
6307 }
6308
6309 $resql = $db->query($sql);
6310
6311 if ($resql) {
6312 $obj = $db->fetch_object($resql);
6313 if ($obj) {
6314 if ($local == 1) {
6315 return $obj->localtax1;
6316 } elseif ($local == 2) {
6317 return $obj->localtax2;
6318 }
6319 }
6320 }
6321
6322 return 0;
6323}
6324
6325
6334function isOnlyOneLocalTax($local)
6335{
6336 $tax = get_localtax_by_third($local);
6337
6338 $valors = explode(":", $tax);
6339
6340 if (count($valors) > 1) {
6341 return false;
6342 } else {
6343 return true;
6344 }
6345}
6346
6354{
6355 global $db, $mysoc;
6356
6357 $sql = " SELECT t.localtax".$local." as localtax";
6358 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = t.fk_pays";
6359 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND t.active = 1 AND t.taux = (";
6360 $sql .= "SELECT MAX(tt.taux) FROM ".MAIN_DB_PREFIX."c_tva as tt INNER JOIN ".MAIN_DB_PREFIX."c_country as c ON c.rowid = tt.fk_pays";
6361 $sql .= " WHERE c.code = '".$db->escape($mysoc->country_code)."' AND tt.active = 1)";
6362 $sql .= " AND t.localtax".$local."_type <> '0'";
6363 $sql .= " ORDER BY t.rowid DESC";
6364
6365 $resql = $db->query($sql);
6366 if ($resql) {
6367 $obj = $db->fetch_object($resql);
6368 if ($obj) {
6369 return $obj->localtax;
6370 } else {
6371 return '0';
6372 }
6373 }
6374
6375 return 'Error';
6376}
6377
6378
6390function getTaxesFromId($vatrate, $buyer = null, $seller = null, $firstparamisid = 1)
6391{
6392 global $db, $mysoc;
6393
6394 dol_syslog("getTaxesFromId vat id or rate = ".$vatrate);
6395
6396 // Search local taxes
6397 $sql = "SELECT t.rowid, t.code, t.taux as rate, t.recuperableonly as npr, t.accountancy_code_sell, t.accountancy_code_buy,";
6398 $sql .= " t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type";
6399 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6400 if ($firstparamisid) {
6401 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6402 } else {
6403 $vatratecleaned = $vatrate;
6404 $vatratecode = '';
6405 $reg = array();
6406 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
6407 $vatratecleaned = $reg[1];
6408 $vatratecode = $reg[2];
6409 }
6410
6411 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6412 /*if ($mysoc->country_code == 'ES') $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($buyer->country_code)."'"; // vat in spain use the buyer country ??
6413 else $sql.= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";*/
6414 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($seller->country_code)."'";
6415 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6416 if ($vatratecode) {
6417 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6418 }
6419 }
6420
6421 $resql = $db->query($sql);
6422 if ($resql) {
6423 $obj = $db->fetch_object($resql);
6424 if ($obj) {
6425 return array(
6426 'rowid'=>$obj->rowid,
6427 'code'=>$obj->code,
6428 'rate'=>$obj->rate,
6429 'localtax1'=>$obj->localtax1,
6430 'localtax1_type'=>$obj->localtax1_type,
6431 'localtax2'=>$obj->localtax2,
6432 'localtax2_type'=>$obj->localtax2_type,
6433 'npr'=>$obj->npr,
6434 'accountancy_code_sell'=>$obj->accountancy_code_sell,
6435 'accountancy_code_buy'=>$obj->accountancy_code_buy
6436 );
6437 } else {
6438 return array();
6439 }
6440 } else {
6441 dol_print_error($db);
6442 }
6443
6444 return array();
6445}
6446
6463function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid = 0)
6464{
6465 global $db, $mysoc;
6466
6467 dol_syslog("getLocalTaxesFromRate vatrate=".$vatrate." local=".$local);
6468
6469 // Search local taxes
6470 $sql = "SELECT t.taux as rate, t.code, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.accountancy_code_sell, t.accountancy_code_buy";
6471 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
6472 if ($firstparamisid) {
6473 $sql .= " WHERE t.rowid = ".(int) $vatrate;
6474 } else {
6475 $vatratecleaned = $vatrate;
6476 $vatratecode = '';
6477 $reg = array();
6478 if (preg_match('/^(.*)\s*\‍((.*)\‍)$/', $vatrate, $reg)) { // If vat is "x.x (yy)"
6479 $vatratecleaned = $reg[1];
6480 $vatratecode = $reg[2];
6481 }
6482
6483 $sql .= ", ".MAIN_DB_PREFIX."c_country as c";
6484 if (!empty($mysoc) && $mysoc->country_code == 'ES') {
6485 $countrycodetouse = ((empty($buyer) || empty($buyer->country_code)) ? $mysoc->country_code : $buyer->country_code);
6486 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'"; // local tax in spain use the buyer country ??
6487 } else {
6488 $countrycodetouse = ((empty($seller) || empty($seller->country_code)) ? $mysoc->country_code : $seller->country_code);
6489 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($countrycodetouse)."'";
6490 }
6491 $sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
6492 if ($vatratecode) {
6493 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
6494 }
6495 }
6496
6497 $resql = $db->query($sql);
6498 if ($resql) {
6499 $obj = $db->fetch_object($resql);
6500
6501 if ($obj) {
6502 $vateratestring = $obj->rate.($obj->code ? ' ('.$obj->code.')' : '');
6503
6504 if ($local == 1) {
6505 return array($obj->localtax1_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6506 } elseif ($local == 2) {
6507 return array($obj->localtax2_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6508 } else {
6509 return array($obj->localtax1_type, get_localtax($vateratestring, 1, $buyer, $seller), $obj->localtax2_type, get_localtax($vateratestring, 2, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
6510 }
6511 }
6512 }
6513
6514 return array();
6515}
6516
6527function get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice = 0)
6528{
6529 global $db, $conf, $mysoc;
6530
6531 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6532
6533 $ret = 0;
6534 $found = 0;
6535
6536 if ($idprod > 0) {
6537 // Load product
6538 $product = new Product($db);
6539 $product->fetch($idprod);
6540
6541 if ($mysoc->country_code == $thirdpartytouse->country_code) {
6542 // If country to consider is ours
6543 if ($idprodfournprice > 0) { // We want vat for product for a "supplier" object
6544 $result = $product->get_buyprice($idprodfournprice, 0, 0, 0);
6545 if ($result > 0) {
6546 $ret = $product->vatrate_supplier;
6547 if ($product->default_vat_code_supplier) {
6548 $ret .= ' ('.$product->default_vat_code_supplier.')';
6549 }
6550 $found = 1;
6551 }
6552 }
6553 if (!$found) {
6554 $ret = $product->tva_tx; // Default sales vat of product
6555 if ($product->default_vat_code) {
6556 $ret .= ' ('.$product->default_vat_code.')';
6557 }
6558 $found = 1;
6559 }
6560 } else {
6561 // TODO Read default product vat according to product and another countrycode.
6562 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6563 }
6564 }
6565
6566 if (!$found) {
6567 if (empty($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS)) {
6568 // If vat of product for the country not found or not defined, we return the first rate found (sorting on use_default, then on higher vat of country).
6569 $sql = "SELECT t.taux as vat_rate, t.code as default_vat_code";
6570 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6571 $sql .= " WHERE t.active = 1 AND t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdpartytouse->country_code)."'";
6572 $sql .= " ORDER BY t.use_default DESC, t.taux DESC, t.code ASC, t.recuperableonly ASC";
6573 $sql .= $db->plimit(1);
6574
6575 $resql = $db->query($sql);
6576 if ($resql) {
6577 $obj = $db->fetch_object($resql);
6578 if ($obj) {
6579 $ret = $obj->vat_rate;
6580 if ($obj->default_vat_code) {
6581 $ret .= ' ('.$obj->default_vat_code.')';
6582 }
6583 }
6584 $db->free($resql);
6585 } else {
6586 dol_print_error($db);
6587 }
6588 } else {
6589 // Forced value if autodetect fails. MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS can be
6590 // '1.23'
6591 // or '1.23 (CODE)'
6592 $defaulttx = '';
6593 if ($conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS != 'none') {
6594 $defaulttx = $conf->global->MAIN_VAT_DEFAULT_IF_AUTODETECT_FAILS;
6595 }
6596 /*if (preg_match('/\‍((.*)\‍)/', $defaulttx, $reg)) {
6597 $defaultcode = $reg[1];
6598 $defaulttx = preg_replace('/\s*\‍(.*\‍)/', '', $defaulttx);
6599 }*/
6600
6601 $ret = $defaulttx;
6602 }
6603 }
6604
6605 dol_syslog("get_product_vat_for_country: ret=".$ret);
6606 return $ret;
6607}
6608
6618function get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
6619{
6620 global $db, $mysoc;
6621
6622 if (!class_exists('Product')) {
6623 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6624 }
6625
6626 $ret = 0;
6627 $found = 0;
6628
6629 if ($idprod > 0) {
6630 // Load product
6631 $product = new Product($db);
6632 $result = $product->fetch($idprod);
6633
6634 if ($mysoc->country_code == $thirdpartytouse->country_code) { // If selling country is ours
6635 /* Not defined yet, so we don't use this
6636 if ($local==1) $ret=$product->localtax1_tx;
6637 elseif ($local==2) $ret=$product->localtax2_tx;
6638 $found=1;
6639 */
6640 } else {
6641 // TODO Read default product vat according to product and another countrycode.
6642 // Vat for couple anothercountrycode/product is data that is not managed and store yet, so we will fallback on next rule.
6643 }
6644 }
6645
6646 if (!$found) {
6647 // If vat of product for the country not found or not defined, we return higher vat of country.
6648 $sql = "SELECT taux as vat_rate, localtax1, localtax2";
6649 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
6650 $sql .= " WHERE t.active=1 AND t.fk_pays = c.rowid AND c.code='".$db->escape($thirdpartytouse->country_code)."'";
6651 $sql .= " ORDER BY t.taux DESC, t.recuperableonly ASC";
6652 $sql .= $db->plimit(1);
6653
6654 $resql = $db->query($sql);
6655 if ($resql) {
6656 $obj = $db->fetch_object($resql);
6657 if ($obj) {
6658 if ($local == 1) {
6659 $ret = $obj->localtax1;
6660 } elseif ($local == 2) {
6661 $ret = $obj->localtax2;
6662 }
6663 }
6664 } else {
6665 dol_print_error($db);
6666 }
6667 }
6668
6669 dol_syslog("get_product_localtax_for_country: ret=".$ret);
6670 return $ret;
6671}
6672
6689function get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6690{
6691 global $conf;
6692
6693 require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
6694
6695 // Note: possible values for tva_assuj are 0/1 or franchise/reel
6696 $seller_use_vat = ((is_numeric($thirdparty_seller->tva_assuj) && !$thirdparty_seller->tva_assuj) || (!is_numeric($thirdparty_seller->tva_assuj) && $thirdparty_seller->tva_assuj == 'franchise')) ? 0 : 1;
6697
6698 $seller_country_code = $thirdparty_seller->country_code;
6699 $seller_in_cee = isInEEC($thirdparty_seller);
6700
6701 $buyer_country_code = $thirdparty_buyer->country_code;
6702 $buyer_in_cee = isInEEC($thirdparty_buyer);
6703
6704 dol_syslog("get_default_tva: seller use vat=".$seller_use_vat.", seller country=".$seller_country_code.", seller in cee=".$seller_in_cee.", buyer vat number=".$thirdparty_buyer->tva_intra." buyer country=".$buyer_country_code.", buyer in cee=".$buyer_in_cee.", idprod=".$idprod.", idprodfournprice=".$idprodfournprice.", SERVICE_ARE_ECOMMERCE_200238EC=".(!empty($conf->global->SERVICES_ARE_ECOMMERCE_200238EC) ? $conf->global->SERVICES_ARE_ECOMMERCE_200238EC : ''));
6705
6706 // If services are eServices according to EU Council Directive 2002/38/EC (http://ec.europa.eu/taxation_customs/taxation/vat/traders/e-commerce/article_1610_en.htm)
6707 // we use the buyer VAT.
6708 if (!empty($conf->global->SERVICE_ARE_ECOMMERCE_200238EC)) {
6709 if ($seller_in_cee && $buyer_in_cee) {
6710 $isacompany = $thirdparty_buyer->isACompany();
6711 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6712 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6713 if (!isValidVATID($thirdparty_buyer)) {
6714 $isacompany = 0;
6715 }
6716 }
6717
6718 if (!$isacompany) {
6719 //print 'VATRULE 0';
6720 return get_product_vat_for_country($idprod, $thirdparty_buyer, $idprodfournprice);
6721 }
6722 }
6723 }
6724
6725 // If seller does not use VAT, default VAT is 0. End of rule.
6726 if (!$seller_use_vat) {
6727 //print 'VATRULE 1';
6728 return 0;
6729 }
6730
6731 // If the (seller country = buyer country) then the default VAT = VAT of the product sold. End of rule.
6732 if (($seller_country_code == $buyer_country_code)
6733 || (in_array($seller_country_code, array('FR', 'MC')) && in_array($buyer_country_code, array('FR', 'MC')))) { // Warning ->country_code not always defined
6734 //print 'VATRULE 2';
6735 $tmpvat = get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6736
6737 if ($seller_country_code == 'IN' && getDolGlobalString('MAIN_SALETAX_AUTOSWITCH_I_CS_FOR_INDIA')) {
6738 // Special case for india.
6739 //print 'VATRULE 2b';
6740 $reg = array();
6741 if (preg_match('/C+S-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id != $thirdparty_buyer->state_id) {
6742 // we must revert the C+S into I
6743 $tmpvat = str_replace("C+S", "I", $tmpvat);
6744 } elseif (preg_match('/I-(\d+)/', $tmpvat, $reg) && $thirdparty_seller->state_id == $thirdparty_buyer->state_id) {
6745 // we must revert the I into C+S
6746 $tmpvat = str_replace("I", "C+S", $tmpvat);
6747 }
6748 }
6749
6750 return $tmpvat;
6751 }
6752
6753 // If (seller and buyer in the European Community) and (property sold = new means of transport such as car, boat, plane) then VAT by default = 0 (VAT must be paid by the buyer to the tax center of his country and not to the seller). End of rule.
6754 // 'VATRULE 3' - Not supported
6755
6756 // If (seller and buyer in the European Community) and (buyer = individual) then VAT by default = VAT of the product sold. End of rule
6757 // If (seller and buyer in European Community) and (buyer = company) then VAT by default=0. End of rule
6758 if (($seller_in_cee && $buyer_in_cee)) {
6759 $isacompany = $thirdparty_buyer->isACompany();
6760 if ($isacompany && getDolGlobalString('MAIN_USE_VAT_COMPANIES_IN_EEC_WITH_INVALID_VAT_ID_ARE_INDIVIDUAL')) {
6761 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
6762 if (!isValidVATID($thirdparty_buyer)) {
6763 $isacompany = 0;
6764 }
6765 }
6766
6767 if (!$isacompany) {
6768 //print 'VATRULE 4';
6769 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6770 } else {
6771 //print 'VATRULE 5';
6772 return 0;
6773 }
6774 }
6775
6776 // If (seller in the European Community and buyer outside the European Community and private buyer) then VAT by default = VAT of the product sold. End of rule
6777 // I don't see any use case that need this rule.
6778 if (!empty($conf->global->MAIN_USE_VAT_OF_PRODUCT_FOR_INDIVIDUAL_CUSTOMER_OUT_OF_EEC) && empty($buyer_in_cee)) {
6779 $isacompany = $thirdparty_buyer->isACompany();
6780 if (!$isacompany) {
6781 return get_product_vat_for_country($idprod, $thirdparty_seller, $idprodfournprice);
6782 //print 'VATRULE extra';
6783 }
6784 }
6785
6786 // Otherwise the VAT proposed by default=0. End of rule.
6787 // Rem: This means that at least one of the 2 is outside the European Community and the country differs
6788 //print 'VATRULE 6';
6789 return 0;
6790}
6791
6792
6803function get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod = 0, $idprodfournprice = 0)
6804{
6805 global $db;
6806
6807 if ($idprodfournprice > 0) {
6808 if (!class_exists('ProductFournisseur')) {
6809 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
6810 }
6811 $prodprice = new ProductFournisseur($db);
6812 $prodprice->fetch_product_fournisseur_price($idprodfournprice);
6813 return $prodprice->fourn_tva_npr;
6814 } elseif ($idprod > 0) {
6815 if (!class_exists('Product')) {
6816 require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
6817 }
6818 $prod = new Product($db);
6819 $prod->fetch($idprod);
6820 return $prod->tva_npr;
6821 }
6822
6823 return 0;
6824}
6825
6839function get_default_localtax($thirdparty_seller, $thirdparty_buyer, $local, $idprod = 0)
6840{
6841 global $mysoc;
6842
6843 if (!is_object($thirdparty_seller)) {
6844 return -1;
6845 }
6846 if (!is_object($thirdparty_buyer)) {
6847 return -1;
6848 }
6849
6850 if ($local == 1) { // Localtax 1
6851 if ($mysoc->country_code == 'ES') {
6852 if (is_numeric($thirdparty_buyer->localtax1_assuj) && !$thirdparty_buyer->localtax1_assuj) {
6853 return 0;
6854 }
6855 } else {
6856 // Si vendeur non assujeti a Localtax1, localtax1 par default=0
6857 if (is_numeric($thirdparty_seller->localtax1_assuj) && !$thirdparty_seller->localtax1_assuj) {
6858 return 0;
6859 }
6860 if (!is_numeric($thirdparty_seller->localtax1_assuj) && $thirdparty_seller->localtax1_assuj == 'localtax1off') {
6861 return 0;
6862 }
6863 }
6864 } elseif ($local == 2) { //I Localtax 2
6865 // Si vendeur non assujeti a Localtax2, localtax2 par default=0
6866 if (is_numeric($thirdparty_seller->localtax2_assuj) && !$thirdparty_seller->localtax2_assuj) {
6867 return 0;
6868 }
6869 if (!is_numeric($thirdparty_seller->localtax2_assuj) && $thirdparty_seller->localtax2_assuj == 'localtax2off') {
6870 return 0;
6871 }
6872 }
6873
6874 if ($thirdparty_seller->country_code == $thirdparty_buyer->country_code) {
6875 return get_product_localtax_for_country($idprod, $local, $thirdparty_seller);
6876 }
6877
6878 return 0;
6879}
6880
6889function yn($yesno, $case = 1, $color = 0)
6890{
6891 global $langs;
6892
6893 $result = 'unknown';
6894 $classname = '';
6895 if ($yesno == 1 || (isset($yesno) && (strtolower($yesno) == 'yes' || strtolower($yesno) == 'true'))) { // A mettre avant test sur no a cause du == 0
6896 $result = $langs->trans('yes');
6897 if ($case == 1 || $case == 3) {
6898 $result = $langs->trans("Yes");
6899 }
6900 if ($case == 2) {
6901 $result = '<input type="checkbox" value="1" checked disabled>';
6902 }
6903 if ($case == 3) {
6904 $result = '<input type="checkbox" value="1" checked disabled> '.$result;
6905 }
6906
6907 $classname = 'ok';
6908 } elseif ($yesno == 0 || strtolower($yesno) == 'no' || strtolower($yesno) == 'false') {
6909 $result = $langs->trans("no");
6910 if ($case == 1 || $case == 3) {
6911 $result = $langs->trans("No");
6912 }
6913 if ($case == 2) {
6914 $result = '<input type="checkbox" value="0" disabled>';
6915 }
6916 if ($case == 3) {
6917 $result = '<input type="checkbox" value="0" disabled> '.$result;
6918 }
6919
6920 if ($color == 2) {
6921 $classname = 'ok';
6922 } else {
6923 $classname = 'error';
6924 }
6925 }
6926 if ($color) {
6927 return '<span class="'.$classname.'">'.$result.'</span>';
6928 }
6929 return $result;
6930}
6931
6947function get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart = '')
6948{
6949 global $conf;
6950
6951 if (empty($modulepart) && !empty($object->module)) {
6952 $modulepart = $object->module;
6953 }
6954
6955 $path = '';
6956
6957 $arrayforoldpath = array('cheque', 'category', 'holiday', 'supplier_invoice', 'invoice_supplier', 'mailing', 'supplier_payment');
6958 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) {
6959 $arrayforoldpath[] = 'product';
6960 }
6961 if (!empty($level) && in_array($modulepart, $arrayforoldpath)) {
6962 // This part should be removed once all code is using "get_exdir" to forge path, with parameter $object and $modulepart provided.
6963 if (empty($alpha)) {
6964 $num = preg_replace('/([^0-9])/i', '', $num);
6965 } else {
6966 $num = preg_replace('/^.*\-/i', '', $num);
6967 }
6968 $num = substr("000".$num, -$level);
6969 if ($level == 1) {
6970 $path = substr($num, 0, 1);
6971 }
6972 if ($level == 2) {
6973 $path = substr($num, 1, 1).'/'.substr($num, 0, 1);
6974 }
6975 if ($level == 3) {
6976 $path = substr($num, 2, 1).'/'.substr($num, 1, 1).'/'.substr($num, 0, 1);
6977 }
6978 } else {
6979 // We will enhance here a common way of forging path for document storage.
6980 // In a future, we may distribute directories on several levels depending on setup and object.
6981 // Here, $object->id, $object->ref and $modulepart are required.
6982 //var_dump($modulepart);
6983 $path = dol_sanitizeFileName(empty($object->ref) ? (string) $object->id : $object->ref);
6984 }
6985
6986 if (empty($withoutslash) && !empty($path)) {
6987 $path .= '/';
6988 }
6989
6990 return $path;
6991}
6992
7001function dol_mkdir($dir, $dataroot = '', $newmask = '')
7002{
7003 global $conf;
7004
7005 dol_syslog("functions.lib::dol_mkdir: dir=".$dir, LOG_INFO);
7006
7007 $dir_osencoded = dol_osencode($dir);
7008 if (@is_dir($dir_osencoded)) {
7009 return 0;
7010 }
7011
7012 $nberr = 0;
7013 $nbcreated = 0;
7014
7015 $ccdir = '';
7016 if (!empty($dataroot)) {
7017 // Remove data root from loop
7018 $dir = str_replace($dataroot.'/', '', $dir);
7019 $ccdir = $dataroot.'/';
7020 }
7021
7022 $cdir = explode("/", $dir);
7023 $num = count($cdir);
7024 for ($i = 0; $i < $num; $i++) {
7025 if ($i > 0) {
7026 $ccdir .= '/'.$cdir[$i];
7027 } else {
7028 $ccdir .= $cdir[$i];
7029 }
7030 $regs = array();
7031 if (preg_match("/^.:$/", $ccdir, $regs)) {
7032 continue; // Si chemin Windows incomplet, on poursuit par rep suivant
7033 }
7034
7035 // Attention, le is_dir() peut echouer bien que le rep existe.
7036 // (ex selon config de open_basedir)
7037 if ($ccdir) {
7038 $ccdir_osencoded = dol_osencode($ccdir);
7039 if (!@is_dir($ccdir_osencoded)) {
7040 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' does not exists or is outside open_basedir PHP setting.", LOG_DEBUG);
7041
7042 umask(0);
7043 $dirmaskdec = octdec((string) $newmask);
7044 if (empty($newmask)) {
7045 $dirmaskdec = empty($conf->global->MAIN_UMASK) ? octdec('0755') : octdec($conf->global->MAIN_UMASK);
7046 }
7047 $dirmaskdec |= octdec('0111'); // Set x bit required for directories
7048 if (!@mkdir($ccdir_osencoded, $dirmaskdec)) {
7049 // Si le is_dir a renvoye une fausse info, alors on passe ici.
7050 dol_syslog("functions.lib::dol_mkdir: Fails to create directory '".$ccdir."' or directory already exists.", LOG_WARNING);
7051 $nberr++;
7052 } else {
7053 dol_syslog("functions.lib::dol_mkdir: Directory '".$ccdir."' created", LOG_DEBUG);
7054 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignore
7055 $nbcreated++;
7056 }
7057 } else {
7058 $nberr = 0; // On remet a zero car si on arrive ici, cela veut dire que les echecs precedents peuvent etre ignores
7059 }
7060 }
7061 }
7062 return ($nberr ? -$nberr : $nbcreated);
7063}
7064
7065
7073function dolChmod($filepath, $newmask = '')
7074{
7075 global $conf;
7076
7077 if (!empty($newmask)) {
7078 @chmod($filepath, octdec($newmask));
7079 } elseif (!empty($conf->global->MAIN_UMASK)) {
7080 @chmod($filepath, octdec($conf->global->MAIN_UMASK));
7081 }
7082}
7083
7084
7091{
7092 return '<span class="fieldrequired">*</span>';
7093}
7094
7095
7112function dol_string_nohtmltag($stringtoclean, $removelinefeed = 1, $pagecodeto = 'UTF-8', $strip_tags = 0, $removedoublespaces = 1)
7113{
7114 if (is_null($stringtoclean)) {
7115 return '';
7116 }
7117
7118 if ($removelinefeed == 2) {
7119 $stringtoclean = preg_replace('/<br[^>]*>(\n|\r)+/ims', '<br>', $stringtoclean);
7120 }
7121 $temp = preg_replace('/<br[^>]*>/i', "\n", $stringtoclean);
7122
7123 // We remove entities BEFORE stripping (in case of an open separator char that is entity encoded and not the closing other, the strip will fails)
7124 $temp = dol_html_entity_decode($temp, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7125
7126 $temp = str_replace('< ', '__ltspace__', $temp);
7127
7128 if ($strip_tags) {
7129 $temp = strip_tags($temp);
7130 } else {
7131 // Remove '<' into remainging, so remove non closing html tags like '<abc' or '<<abc'. Note: '<123abc' is not a html tag (can be kept), but '<abc123' is (must be removed).
7132 $pattern = "/<[^<>]+>/";
7133 // Example of $temp: <a href="/myurl" title="<u>A title</u>">0000-021</a>
7134 // pass 1 - $temp after pass 1: <a href="/myurl" title="A title">0000-021
7135 // pass 2 - $temp after pass 2: 0000-021
7136 $tempbis = $temp;
7137 do {
7138 $temp = $tempbis;
7139 $tempbis = str_replace('<>', '', $temp); // No reason to have this into a text, except if value is to try bypass the next html cleaning
7140 $tempbis = preg_replace($pattern, '', $tempbis);
7141 //$idowhile++; print $temp.'-'.$tempbis."\n"; if ($idowhile > 100) break;
7142 } while ($tempbis != $temp);
7143
7144 $temp = $tempbis;
7145
7146 // Remove '<' into remaining, so remove non closing html tags like '<abc' or '<<abc'. Note: '<123abc' is not a html tag (can be kept), but '<abc123' is (must be removed).
7147 $temp = preg_replace('/<+([a-z]+)/i', '\1', $temp);
7148 }
7149
7150 $temp = dol_html_entity_decode($temp, ENT_COMPAT, $pagecodeto);
7151
7152 // Remove also carriage returns
7153 if ($removelinefeed == 1) {
7154 $temp = str_replace(array("\r\n", "\r", "\n"), " ", $temp);
7155 }
7156
7157 // And double quotes
7158 if ($removedoublespaces) {
7159 while (strpos($temp, " ")) {
7160 $temp = str_replace(" ", " ", $temp);
7161 }
7162 }
7163
7164 $temp = str_replace('__ltspace__', '< ', $temp);
7165
7166 return trim($temp);
7167}
7168
7184function dol_string_onlythesehtmltags($stringtoclean, $cleanalsosomestyles = 1, $removeclassattribute = 1, $cleanalsojavascript = 0, $allowiframe = 0, $allowed_tags = array(), $allowlink = 0)
7185{
7186 if (empty($allowed_tags)) {
7187 $allowed_tags = array(
7188 "html", "head", "meta", "body", "article", "a", "abbr", "b", "blockquote", "br", "cite", "div", "dl", "dd", "dt", "em", "font", "img", "ins", "hr", "i", "li",
7189 "ol", "p", "q", "s", "section", "span", "strike", "strong", "title", "table", "tr", "th", "td", "u", "ul", "sup", "sub", "blockquote", "pre", "h1", "h2", "h3", "h4", "h5", "h6"
7190 );
7191 }
7192 $allowed_tags[] = "comment"; // this tags is added to manage comment <!--...--> that are replaced into <comment>...</comment>
7193 if ($allowiframe) {
7194 if (!in_array('iframe', $allowed_tags)) {
7195 $allowed_tags[] = "iframe";
7196 }
7197 }
7198 if ($allowlink) {
7199 if (!in_array('link', $allowed_tags)) {
7200 $allowed_tags[] = "link";
7201 }
7202 }
7203
7204 $allowed_tags_string = join("><", $allowed_tags);
7205 $allowed_tags_string = '<'.$allowed_tags_string.'>';
7206
7207 $stringtoclean = str_replace('<!DOCTYPE html>', '__!DOCTYPE_HTML__', $stringtoclean); // Replace DOCTYPE to avoid to have it removed by the strip_tags
7208
7209 $stringtoclean = dol_string_nounprintableascii($stringtoclean, 0);
7210
7211 //$stringtoclean = preg_replace('/<!--[^>]*-->/', '', $stringtoclean);
7212 $stringtoclean = preg_replace('/<!--([^>]*)-->/', '<comment>\1</comment>', $stringtoclean);
7213
7214 $stringtoclean = preg_replace('/&colon;/i', ':', $stringtoclean);
7215 $stringtoclean = preg_replace('/&#58;|&#0+58|&#x3A/i', '', $stringtoclean); // refused string ':' encoded (no reason to have a : encoded like this) to disable 'javascript:...'
7216
7217 $temp = strip_tags($stringtoclean, $allowed_tags_string); // Warning: This remove also undesired </>, so may changes string obfuscated with </> that pass the injection detection into a harmfull string
7218
7219 if ($cleanalsosomestyles) { // Clean for remaining html tags
7220 $temp = preg_replace('/position\s*:\s*(absolute|fixed)\s*!\s*important/i', '', $temp); // Note: If hacker try to introduce css comment into string to bypass this regex, the string must also be encoded by the dol_htmlentitiesbr during output so it become harmless
7221 }
7222 if ($removeclassattribute) { // Clean for remaining html tags
7223 $temp = preg_replace('/(<[^>]+)\s+class=((["\']).*?\\3|\\w*)/i', '\\1', $temp);
7224 }
7225
7226 // Remove 'javascript:' that we should not find into a text with
7227 // Warning: This is not reliable to fight against obfuscated javascript, there is a lot of other solution to include js into a common html tag (only filtered by a GETPOST(.., powerfullfilter)).
7228 if ($cleanalsojavascript) {
7229 $temp = preg_replace('/j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*:/i', '', $temp);
7230 }
7231
7232 $temp = str_replace('__!DOCTYPE_HTML__', '<!DOCTYPE html>', $temp); // Restore the DOCTYPE
7233
7234 $temp = preg_replace('/<comment>([^>]*)<\/comment>/', '<!--\1-->', $temp); // Restore html comments
7235
7236
7237 return $temp;
7238}
7239
7240
7252function dol_string_onlythesehtmlattributes($stringtoclean, $allowed_attributes = array("allow", "allowfullscreen", "alt", "class", "contenteditable", "data-html", "frameborder", "height", "href", "id", "name", "src", "style", "target", "title", "width"))
7253{
7254 if (class_exists('DOMDocument') && !empty($stringtoclean)) {
7255 $stringtoclean = '<?xml encoding="UTF-8"><html><body>'.$stringtoclean.'</body></html>';
7256
7257 $dom = new DOMDocument(null, 'UTF-8');
7258 $dom->loadHTML($stringtoclean, LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7259
7260 if (is_object($dom)) {
7261 for ($els = $dom->getElementsByTagname('*'), $i = $els->length - 1; $i >= 0; $i--) {
7262 for ($attrs = $els->item($i)->attributes, $ii = $attrs->length - 1; $ii >= 0; $ii--) {
7263 //var_dump($attrs->item($ii));
7264 if (!empty($attrs->item($ii)->name)) {
7265 if (! in_array($attrs->item($ii)->name, $allowed_attributes)) {
7266 // Delete attribute if not into allowed_attributes
7267 $els->item($i)->removeAttribute($attrs->item($ii)->name);
7268 } elseif (in_array($attrs->item($ii)->name, array('style'))) {
7269 // If attribute is 'style'
7270 $valuetoclean = $attrs->item($ii)->value;
7271
7272 if (isset($valuetoclean)) {
7273 do {
7274 $oldvaluetoclean = $valuetoclean;
7275 $valuetoclean = preg_replace('/\/\*.*\*\//m', '', $valuetoclean); // clean css comments
7276 $valuetoclean = preg_replace('/position\s*:\s*[a-z]+/mi', '', $valuetoclean);
7277 if ($els->item($i)->tagName == 'a') { // more paranoiac cleaning for clickable tags.
7278 $valuetoclean = preg_replace('/display\s*:/mi', '', $valuetoclean);
7279 $valuetoclean = preg_replace('/z-index\s*:/mi', '', $valuetoclean);
7280 $valuetoclean = preg_replace('/\s+(top|left|right|bottom)\s*:/mi', '', $valuetoclean);
7281 }
7282
7283 // We do not allow logout|passwordforgotten.php and action= into the content of a "style" tag
7284 $valuetoclean = preg_replace('/(logout|passwordforgotten)\.php/mi', '', $valuetoclean);
7285 $valuetoclean = preg_replace('/action=/mi', '', $valuetoclean);
7286 } while ($oldvaluetoclean != $valuetoclean);
7287 }
7288
7289 $attrs->item($ii)->value = $valuetoclean;
7290 }
7291 }
7292 }
7293 }
7294 }
7295
7296 $return = $dom->saveHTML(); // This may add a LF at end of lines, so we will trim later
7297 //$return = '<html><body>aaaa</p>bb<p>ssdd</p>'."\n<p>aaa</p>aa<p>bb</p>";
7298
7299 $return = preg_replace('/^'.preg_quote('<?xml encoding="UTF-8">', '/').'/', '', $return);
7300 $return = preg_replace('/^'.preg_quote('<html><body>', '/').'/', '', $return);
7301 $return = preg_replace('/'.preg_quote('</body></html>', '/').'$/', '', $return);
7302 return trim($return);
7303 } else {
7304 return $stringtoclean;
7305 }
7306}
7307
7319function dol_string_neverthesehtmltags($stringtoclean, $disallowed_tags = array('textarea'), $cleanalsosomestyles = 0)
7320{
7321 $temp = $stringtoclean;
7322 foreach ($disallowed_tags as $tagtoremove) {
7323 $temp = preg_replace('/<\/?'.$tagtoremove.'>/', '', $temp);
7324 $temp = preg_replace('/<\/?'.$tagtoremove.'\s+[^>]*>/', '', $temp);
7325 }
7326
7327 if ($cleanalsosomestyles) {
7328 $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
7329 }
7330
7331 return $temp;
7332}
7333
7334
7344function dolGetFirstLineOfText($text, $nboflines = 1, $charset = 'UTF-8')
7345{
7346 if ($nboflines == 1) {
7347 if (dol_textishtml($text)) {
7348 $firstline = preg_replace('/<br[^>]*>.*$/s', '', $text); // The s pattern modifier means the . can match newline characters
7349 $firstline = preg_replace('/<div[^>]*>.*$/s', '', $firstline); // The s pattern modifier means the . can match newline characters
7350 } else {
7351 if (isset($text)) {
7352 $firstline = preg_replace('/[\n\r].*/', '', $text);
7353 } else {
7354 $firstline = '';
7355 }
7356 }
7357 return $firstline.(isset($firstline) && isset($text) && (strlen($firstline) != strlen($text)) ? '...' : '');
7358 } else {
7359 $ishtml = 0;
7360 if (dol_textishtml($text)) {
7361 $text = preg_replace('/\n/', '', $text);
7362 $ishtml = 1;
7363 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7364 } else {
7365 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7366 }
7367
7368 $text = strtr($text, $repTable);
7369 if ($charset == 'UTF-8') {
7370 $pattern = '/(<br[^>]*>)/Uu';
7371 } else {
7372 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7373 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7374 }
7375 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7376
7377 $firstline = '';
7378 $i = 0;
7379 $nba = count($a); // 2x nb of lines in $a because $a contains also a line for each new line separator
7380 while (($i < $nba) && ($i < ($nboflines * 2))) {
7381 if ($i % 2 == 0) {
7382 $firstline .= $a[$i];
7383 } elseif (($i < (($nboflines * 2) - 1)) && ($i < ($nba - 1))) {
7384 $firstline .= ($ishtml ? "<br>\n" : "\n");
7385 }
7386 $i++;
7387 }
7388 unset($a);
7389 return $firstline.(($i < $nba) ? '...' : '');
7390 }
7391}
7392
7393
7405function dol_nl2br($stringtoencode, $nl2brmode = 0, $forxml = false)
7406{
7407 if (is_null($stringtoencode)) {
7408 return '';
7409 }
7410
7411 if (!$nl2brmode) {
7412 return nl2br($stringtoencode, $forxml);
7413 } else {
7414 $ret = preg_replace('/(\r\n|\r|\n)/i', ($forxml ? '<br />' : '<br>'), $stringtoencode);
7415 return $ret;
7416 }
7417}
7418
7427function dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox = 0, $check = 'restricthtml')
7428{
7429 global $conf;
7430
7431 if (empty($nouseofiframesandbox) && !empty($conf->global->MAIN_SECURITY_USE_SANDBOX_FOR_HTMLWITHNOJS)) {
7432 // TODO using sandbox on inline html content is not possible yet with current browsers
7433 //$s = '<iframe class="iframewithsandbox" sandbox><html><body>';
7434 //$s .= $stringtoencode;
7435 //$s .= '</body></html></iframe>';
7436 return $stringtoencode;
7437 } else {
7438 $out = $stringtoencode;
7439
7440 do {
7441 $oldstringtoclean = $out;
7442
7443 if (!empty($out) && !empty($conf->global->MAIN_RESTRICTHTML_ONLY_VALID_HTML) && $check != 'restricthtmlallowunvalid') {
7444 try {
7445 libxml_use_internal_errors(false); // Avoid to fill memory with xml errors
7446
7447 $dom = new DOMDocument;
7448 // Add a trick to solve pb with text without parent tag
7449 // like '<h1>Foo</h1><p>bar</p>' that wrongly ends up, without the trick, with '<h1>Foo<p>bar</p></h1>'
7450 // like 'abc' that wrongly ends up, without the trick, with '<p>abc</p>'
7451 $out = '<div class="tricktoremove">'.$out.'</div>';
7452 $dom->loadHTML($out, LIBXML_HTML_NODEFDTD|LIBXML_ERR_NONE|LIBXML_HTML_NOIMPLIED|LIBXML_NONET|LIBXML_NOWARNING|LIBXML_NOXMLDECL);
7453 $out = trim($dom->saveHTML());
7454
7455 // Remove the trick added to solve pb with text without parent tag
7456 $out = preg_replace('/^<div class="tricktoremove">/', '', $out);
7457 $out = preg_replace('/<\/div>$/', '', $out);
7458 } catch (Exception $e) {
7459 // If error, invalid HTML string with no way to clean it
7460 //print $e->getMessage();
7461 $out = 'InvalidHTMLStringCantBeCleaned';
7462 }
7463 }
7464
7465 // Clean some html entities that are useless so text is cleaner
7466 $out = preg_replace('/&(tab|newline);/i', ' ', $out);
7467
7468 // Ckeditor use the numeric entitic for apostrophe so we force it to text entity (all other special chars are
7469 // encoded using text entities) so we can then exclude all numeric entities.
7470 $out = preg_replace('/&#39;/i', '&apos;', $out);
7471
7472 // 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).
7473 // 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
7474 // using a non coventionnel way to be encoded, to not have them sanitized just after)
7475 $out = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) {
7476 return realCharForNumericEntities($m); }, $out);
7477
7478
7479 // Now we remove all remaining HTML entities starting with a number. We don't want such entities.
7480 $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'.
7481
7482 // Keep only some html tags and remove also some 'javascript:' strings
7483 $out = dol_string_onlythesehtmltags($out, 0, ($check == 'restricthtmlallowclass' ? 0 : 1), 1);
7484
7485 // Keep only some html attributes and exclude non expected HTML attributes and clean content of some attributes (keep only alt=, title=...).
7486 if (!empty($conf->global->MAIN_RESTRICTHTML_REMOVE_ALSO_BAD_ATTRIBUTES)) {
7488 }
7489
7490 // Restore entity &apos; into &#39; (restricthtml is for html content so we can use html entity)
7491 $out = preg_replace('/&apos;/i', "&#39;", $out);
7492 } while ($oldstringtoclean != $out);
7493
7494 // Check the limit of external links that are automatically executed in a Rich text content. We count:
7495 // '<img' to avoid <img src="http...">
7496 // 'url(' to avoid inline style like background: url(http...
7497 // '<link' to avoid <link href="http...">
7498 $reg = array();
7499 preg_match_all('/(<img|url\‍(|<link)/i', $out, $reg);
7500 $nbextlink = count($reg[0]);
7501 if ($nbextlink > getDolGlobalInt("MAIN_SECURITY_MAX_IMG_IN_HTML_CONTENT", 1000)) {
7502 $out = 'TooManyLinksIntoHTMLString';
7503 }
7504 //
7505 if (!empty($conf->global->MAIN_DISALLOW_EXT_URL_INTO_DESCRIPTIONS) || $check == 'restricthtmlnolink') {
7506 if ($nbextlink > 0) {
7507 $out = 'ExternalLinksNotAllowed';
7508 }
7509 }
7510
7511 return $out;
7512 }
7513}
7514
7536function dol_htmlentitiesbr($stringtoencode, $nl2brmode = 0, $pagecodefrom = 'UTF-8', $removelasteolbr = 1)
7537{
7538 if (is_null($stringtoencode)) {
7539 return '';
7540 }
7541
7542 $newstring = $stringtoencode;
7543 if (dol_textishtml($stringtoencode)) { // Check if text is already HTML or not
7544 $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.
7545 if ($removelasteolbr) {
7546 $newstring = preg_replace('/<br>$/i', '', $newstring); // Remove last <br> (remove only last one)
7547 }
7548 $newstring = strtr($newstring, array('&'=>'__and__', '<'=>'__lt__', '>'=>'__gt__', '"'=>'__dquot__'));
7549 $newstring = dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom); // Make entity encoding
7550 $newstring = strtr($newstring, array('__and__'=>'&', '__lt__'=>'<', '__gt__'=>'>', '__dquot__'=>'"'));
7551 } else {
7552 if ($removelasteolbr) {
7553 $newstring = preg_replace('/(\r\n|\r|\n)$/i', '', $newstring); // Remove last \n (may remove several)
7554 }
7555 $newstring = dol_nl2br(dol_htmlentities($newstring, ENT_COMPAT, $pagecodefrom), $nl2brmode);
7556 }
7557 // Other substitutions that htmlentities does not do
7558 //$newstring=str_replace(chr(128),'&euro;',$newstring); // 128 = 0x80. Not in html entity table. // Seems useles with TCPDF. Make bug with UTF8 languages
7559 return $newstring;
7560}
7561
7569function dol_htmlentitiesbr_decode($stringtodecode, $pagecodeto = 'UTF-8')
7570{
7571 $ret = dol_html_entity_decode($stringtodecode, ENT_COMPAT | ENT_HTML5, $pagecodeto);
7572 $ret = preg_replace('/'."\r\n".'<br(\s[\sa-zA-Z_="]*)?\/?>/i', "<br>", $ret);
7573 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\r\n".'/i', "\r\n", $ret);
7574 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>'."\n".'/i', "\n", $ret);
7575 $ret = preg_replace('/<br(\s[\sa-zA-Z_="]*)?\/?>/i', "\n", $ret);
7576 return $ret;
7577}
7578
7585function dol_htmlcleanlastbr($stringtodecode)
7586{
7587 $ret = preg_replace('/&nbsp;$/i', "", $stringtodecode); // Because wysiwyg editor may add a &nbsp; at end of last line
7588 $ret = preg_replace('/(<br>|<br(\s[\sa-zA-Z_="]*)?\/?>|'."\n".'|'."\r".')+$/i', "", $ret);
7589 return $ret;
7590}
7591
7601function dol_html_entity_decode($a, $b, $c = 'UTF-8', $keepsomeentities = 0)
7602{
7603 $newstring = $a;
7604 if ($keepsomeentities) {
7605 $newstring = strtr($newstring, array('&amp;'=>'__andamp__', '&lt;'=>'__andlt__', '&gt;'=>'__andgt__', '"'=>'__dquot__'));
7606 }
7607 $newstring = html_entity_decode((string) $newstring, (int) $b, (string) $c);
7608 if ($keepsomeentities) {
7609 $newstring = strtr($newstring, array('__andamp__'=>'&amp;', '__andlt__'=>'&lt;', '__andgt__'=>'&gt;', '__dquot__'=>'"'));
7610 }
7611 return $newstring;
7612}
7613
7624function dol_htmlentities($string, $flags = ENT_QUOTES|ENT_SUBSTITUTE, $encoding = 'UTF-8', $double_encode = false)
7625{
7626 return htmlentities($string, $flags, $encoding, $double_encode);
7627}
7628
7640function dol_string_is_good_iso($s, $clean = 0)
7641{
7642 $len = dol_strlen($s);
7643 $out = '';
7644 $ok = 1;
7645 for ($scursor = 0; $scursor < $len; $scursor++) {
7646 $ordchar = ord($s[$scursor]);
7647 //print $scursor.'-'.$ordchar.'<br>';
7648 if ($ordchar < 32 && $ordchar != 13 && $ordchar != 10) {
7649 $ok = 0;
7650 break;
7651 } elseif ($ordchar > 126 && $ordchar < 160) {
7652 $ok = 0;
7653 break;
7654 } elseif ($clean) {
7655 $out .= $s[$scursor];
7656 }
7657 }
7658 if ($clean) {
7659 return $out;
7660 }
7661 return $ok;
7662}
7663
7672function dol_nboflines($s, $maxchar = 0)
7673{
7674 if ($s == '') {
7675 return 0;
7676 }
7677 $arraystring = explode("\n", $s);
7678 $nb = count($arraystring);
7679
7680 return $nb;
7681}
7682
7683
7693function dol_nboflines_bis($text, $maxlinesize = 0, $charset = 'UTF-8')
7694{
7695 $repTable = array("\t" => " ", "\n" => "<br>", "\r" => " ", "\0" => " ", "\x0B" => " ");
7696 if (dol_textishtml($text)) {
7697 $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
7698 }
7699
7700 $text = strtr($text, $repTable);
7701 if ($charset == 'UTF-8') {
7702 $pattern = '/(<br[^>]*>)/Uu';
7703 } else {
7704 // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
7705 $pattern = '/(<br[^>]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
7706 }
7707 $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
7708
7709 $nblines = (int) floor((count($a) + 1) / 2);
7710 // count possible auto line breaks
7711 if ($maxlinesize) {
7712 foreach ($a as $line) {
7713 if (dol_strlen($line) > $maxlinesize) {
7714 //$line_dec = html_entity_decode(strip_tags($line));
7715 $line_dec = html_entity_decode($line);
7716 if (dol_strlen($line_dec) > $maxlinesize) {
7717 $line_dec = wordwrap($line_dec, $maxlinesize, '\n', true);
7718 $nblines += substr_count($line_dec, '\n');
7719 }
7720 }
7721 }
7722 }
7723
7724 unset($a);
7725 return $nblines;
7726}
7727
7736function dol_textishtml($msg, $option = 0)
7737{
7738 if (is_null($msg)) {
7739 return false;
7740 }
7741
7742 if ($option == 1) {
7743 if (preg_match('/<html/i', $msg)) {
7744 return true;
7745 } elseif (preg_match('/<body/i', $msg)) {
7746 return true;
7747 } elseif (preg_match('/<\/textarea/i', $msg)) {
7748 return true;
7749 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
7750 return true;
7751 } elseif (preg_match('/<br/i', $msg)) {
7752 return true;
7753 }
7754 return false;
7755 } else {
7756 // Remove all urls because 'http://aa?param1=abc&amp;param2=def' must not be used inside detection
7757 $msg = preg_replace('/https?:\/\/[^"\'\s]+/i', '', $msg);
7758 if (preg_match('/<html/i', $msg)) {
7759 return true;
7760 } elseif (preg_match('/<body/i', $msg)) {
7761 return true;
7762 } elseif (preg_match('/<\/textarea/i', $msg)) {
7763 return true;
7764 } elseif (preg_match('/<(b|em|i|u)(\s+[^>]+)?>/i', $msg)) {
7765 return true;
7766 } elseif (preg_match('/<(br|hr)\/>/i', $msg)) {
7767 return true;
7768 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)>/i', $msg)) {
7769 return true;
7770 } elseif (preg_match('/<(br|hr|div|font|li|p|span|strong|table)\s+[^<>\/]*\/?>/i', $msg)) {
7771 return true;
7772 } elseif (preg_match('/<img\s+[^<>]*src[^<>]*>/i', $msg)) {
7773 return true; // must accept <img src="http://example.com/aaa.png" />
7774 } elseif (preg_match('/<a\s+[^<>]*href[^<>]*>/i', $msg)) {
7775 return true; // must accept <a href="http://example.com/aaa.png" />
7776 } elseif (preg_match('/<h[0-9]>/i', $msg)) {
7777 return true;
7778 } elseif (preg_match('/&[A-Z0-9]{1,6};/i', $msg)) {
7779 // TODO If content is 'A link https://aaa?param=abc&amp;param2=def', it return true but must be false
7780 return true; // Html entities names (http://www.w3schools.com/tags/ref_entities.asp)
7781 } elseif (preg_match('/&#[0-9]{2,3};/i', $msg)) {
7782 return true; // Html entities numbers (http://www.w3schools.com/tags/ref_entities.asp)
7783 }
7784
7785 return false;
7786 }
7787}
7788
7803function dol_concatdesc($text1, $text2, $forxml = false, $invert = false)
7804{
7805 if (!empty($invert)) {
7806 $tmp = $text1;
7807 $text1 = $text2;
7808 $text2 = $tmp;
7809 }
7810
7811 $ret = '';
7812 $ret .= (!dol_textishtml($text1) && dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text1, 0, 1, '', 1), 0, $forxml) : $text1;
7813 $ret .= (!empty($text1) && !empty($text2)) ? ((dol_textishtml($text1) || dol_textishtml($text2)) ? ($forxml ? "<br >\n" : "<br>\n") : "\n") : "";
7814 $ret .= (dol_textishtml($text1) && !dol_textishtml($text2)) ? dol_nl2br(dol_escape_htmltag($text2, 0, 1, '', 1), 0, $forxml) : $text2;
7815 return $ret;
7816}
7817
7818
7819
7831function getCommonSubstitutionArray($outputlangs, $onlykey = 0, $exclude = null, $object = null, $include = null)
7832{
7833 global $db, $conf, $mysoc, $user, $extrafields;
7834
7835 $substitutionarray = array();
7836
7837 if ((empty($exclude) || !in_array('user', $exclude)) && (empty($include) || in_array('user', $include))) {
7838 // Add SIGNATURE into substitutionarray first, so, when we will make the substitution,
7839 // this will include signature content first and then replace var found into content of signature
7840 //var_dump($onlykey);
7841 $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()
7842 $usersignature = $user->signature;
7843 $substitutionarray = array_merge($substitutionarray, array(
7844 '__SENDEREMAIL_SIGNATURE__' => (string) ((empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN)) ? ($onlykey == 2 ? dol_trunc('SignatureFromTheSelectedSenderProfile', 30) : $emailsendersignature) : ''),
7845 '__USER_SIGNATURE__' => (string) (($usersignature && empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN)) ? ($onlykey == 2 ? dol_trunc(dol_string_nohtmltag($usersignature), 30) : $usersignature) : '')
7846 ));
7847
7848 if (is_object($user)) {
7849 $substitutionarray = array_merge($substitutionarray, array(
7850 '__USER_ID__' => (string) $user->id,
7851 '__USER_LOGIN__' => (string) $user->login,
7852 '__USER_EMAIL__' => (string) $user->email,
7853 '__USER_PHONE__' => (string) dol_print_phone($user->office_phone, '', 0, 0, '', " ", '', '', -1),
7854 '__USER_PHONEPRO__' => (string) dol_print_phone($user->user_mobile, '', 0, 0, '', " ", '', '', -1),
7855 '__USER_PHONEMOBILE__' => (string) dol_print_phone($user->personal_mobile, '', 0, 0, '', " ", '', '', -1),
7856 '__USER_FAX__' => (string) $user->office_fax,
7857 '__USER_LASTNAME__' => (string) $user->lastname,
7858 '__USER_FIRSTNAME__' => (string) $user->firstname,
7859 '__USER_FULLNAME__' => (string) $user->getFullName($outputlangs),
7860 '__USER_SUPERVISOR_ID__' => (string) ($user->fk_user ? $user->fk_user : '0'),
7861 '__USER_JOB__' => (string) $user->job,
7862 '__USER_REMOTE_IP__' => (string) getUserRemoteIP(),
7863 '__USER_VCARD_URL__' => (string) $user->getOnlineVirtualCardUrl('', 'external')
7864 ));
7865 }
7866 }
7867 if ((empty($exclude) || !in_array('mycompany', $exclude)) && is_object($mysoc) && (empty($include) || in_array('mycompany', $include))) {
7868 $substitutionarray = array_merge($substitutionarray, array(
7869 '__MYCOMPANY_NAME__' => $mysoc->name,
7870 '__MYCOMPANY_EMAIL__' => $mysoc->email,
7871 '__MYCOMPANY_PHONE__' => dol_print_phone($mysoc->phone, '', 0, 0, '', " ", '', '', -1),
7872 '__MYCOMPANY_FAX__' => dol_print_phone($mysoc->fax, '', 0, 0, '', " ", '', '', -1),
7873 '__MYCOMPANY_PROFID1__' => $mysoc->idprof1,
7874 '__MYCOMPANY_PROFID2__' => $mysoc->idprof2,
7875 '__MYCOMPANY_PROFID3__' => $mysoc->idprof3,
7876 '__MYCOMPANY_PROFID4__' => $mysoc->idprof4,
7877 '__MYCOMPANY_PROFID5__' => $mysoc->idprof5,
7878 '__MYCOMPANY_PROFID6__' => $mysoc->idprof6,
7879 '__MYCOMPANY_CAPITAL__' => $mysoc->capital,
7880 '__MYCOMPANY_FULLADDRESS__' => (method_exists($mysoc, 'getFullAddress') ? $mysoc->getFullAddress(1, ', ') : ''), // $mysoc may be stdClass
7881 '__MYCOMPANY_ADDRESS__' => $mysoc->address,
7882 '__MYCOMPANY_ZIP__' => $mysoc->zip,
7883 '__MYCOMPANY_TOWN__' => $mysoc->town,
7884 '__MYCOMPANY_COUNTRY__' => $mysoc->country,
7885 '__MYCOMPANY_COUNTRY_ID__' => $mysoc->country_id,
7886 '__MYCOMPANY_COUNTRY_CODE__' => $mysoc->country_code,
7887 '__MYCOMPANY_CURRENCY_CODE__' => $conf->currency
7888 ));
7889 }
7890
7891 if (($onlykey || is_object($object)) && (empty($exclude) || !in_array('object', $exclude)) && (empty($include) || in_array('object', $include))) {
7892 if ($onlykey) {
7893 $substitutionarray['__ID__'] = '__ID__';
7894 $substitutionarray['__REF__'] = '__REF__';
7895 $substitutionarray['__NEWREF__'] = '__NEWREF__';
7896 $substitutionarray['__LABEL__'] = '__LABEL__';
7897 $substitutionarray['__REF_CLIENT__'] = '__REF_CLIENT__';
7898 $substitutionarray['__REF_SUPPLIER__'] = '__REF_SUPPLIER__';
7899 $substitutionarray['__NOTE_PUBLIC__'] = '__NOTE_PUBLIC__';
7900 $substitutionarray['__NOTE_PRIVATE__'] = '__NOTE_PRIVATE__';
7901 $substitutionarray['__EXTRAFIELD_XXX__'] = '__EXTRAFIELD_XXX__';
7902
7903 if (isModEnabled("societe")) { // Most objects are concerned
7904 $substitutionarray['__THIRDPARTY_ID__'] = '__THIRDPARTY_ID__';
7905 $substitutionarray['__THIRDPARTY_NAME__'] = '__THIRDPARTY_NAME__';
7906 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = '__THIRDPARTY_NAME_ALIAS__';
7907 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = '__THIRDPARTY_CODE_CLIENT__';
7908 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = '__THIRDPARTY_CODE_FOURNISSEUR__';
7909 $substitutionarray['__THIRDPARTY_EMAIL__'] = '__THIRDPARTY_EMAIL__';
7910 $substitutionarray['__THIRDPARTY_PHONE__'] = '__THIRDPARTY_PHONE__';
7911 $substitutionarray['__THIRDPARTY_FAX__'] = '__THIRDPARTY_FAX__';
7912 $substitutionarray['__THIRDPARTY_ADDRESS__'] = '__THIRDPARTY_ADDRESS__';
7913 $substitutionarray['__THIRDPARTY_ZIP__'] = '__THIRDPARTY_ZIP__';
7914 $substitutionarray['__THIRDPARTY_TOWN__'] = '__THIRDPARTY_TOWN__';
7915 $substitutionarray['__THIRDPARTY_IDPROF1__'] = '__THIRDPARTY_IDPROF1__';
7916 $substitutionarray['__THIRDPARTY_IDPROF2__'] = '__THIRDPARTY_IDPROF2__';
7917 $substitutionarray['__THIRDPARTY_IDPROF3__'] = '__THIRDPARTY_IDPROF3__';
7918 $substitutionarray['__THIRDPARTY_IDPROF4__'] = '__THIRDPARTY_IDPROF4__';
7919 $substitutionarray['__THIRDPARTY_IDPROF5__'] = '__THIRDPARTY_IDPROF5__';
7920 $substitutionarray['__THIRDPARTY_IDPROF6__'] = '__THIRDPARTY_IDPROF6__';
7921 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = '__THIRDPARTY_TVAINTRA__';
7922 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = '__THIRDPARTY_NOTE_PUBLIC__';
7923 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = '__THIRDPARTY_NOTE_PRIVATE__';
7924 }
7925 if (isModEnabled('adherent') && (!is_object($object) || $object->element == 'adherent') && (empty($exclude) || !in_array('member', $exclude)) && (empty($include) || in_array('member', $include))) {
7926 $substitutionarray['__MEMBER_ID__'] = '__MEMBER_ID__';
7927 $substitutionarray['__MEMBER_CIVILITY__'] = '__MEMBER_CIVILITY__';
7928 $substitutionarray['__MEMBER_FIRSTNAME__'] = '__MEMBER_FIRSTNAME__';
7929 $substitutionarray['__MEMBER_LASTNAME__'] = '__MEMBER_LASTNAME__';
7930 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = 'Login and pass of the external user account';
7931 /*$substitutionarray['__MEMBER_NOTE_PUBLIC__'] = '__MEMBER_NOTE_PUBLIC__';
7932 $substitutionarray['__MEMBER_NOTE_PRIVATE__'] = '__MEMBER_NOTE_PRIVATE__';*/
7933 }
7934 // add variables subtitutions ticket
7935 if (isModEnabled('ticket') && (!is_object($object) || $object->element == 'ticket') && (empty($exclude) || !in_array('ticket', $exclude)) && (empty($include) || in_array('ticket', $include))) {
7936 $substitutionarray['__TICKET_TRACKID__'] = '__TICKET_TRACKID__';
7937 $substitutionarray['__TICKET_SUBJECT__'] = '__TICKET_SUBJECT__';
7938 $substitutionarray['__TICKET_TYPE__'] = '__TICKET_TYPE__';
7939 $substitutionarray['__TICKET_SEVERITY__'] = '__TICKET_SEVERITY__';
7940 $substitutionarray['__TICKET_CATEGORY__'] = '__TICKET_CATEGORY__';
7941 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = '__TICKET_ANALYTIC_CODE__';
7942 $substitutionarray['__TICKET_MESSAGE__'] = '__TICKET_MESSAGE__';
7943 $substitutionarray['__TICKET_PROGRESSION__'] = '__TICKET_PROGRESSION__';
7944 $substitutionarray['__TICKET_USER_ASSIGN__'] = '__TICKET_USER_ASSIGN__';
7945 }
7946
7947 if (isModEnabled('recruitment') && (!is_object($object) || $object->element == 'recruitmentcandidature') && (empty($exclude) || !in_array('recruitment', $exclude)) && (empty($include) || in_array('recruitment', $include))) {
7948 $substitutionarray['__CANDIDATE_FULLNAME__'] = '__CANDIDATE_FULLNAME__';
7949 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = '__CANDIDATE_FIRSTNAME__';
7950 $substitutionarray['__CANDIDATE_LASTNAME__'] = '__CANDIDATE_LASTNAME__';
7951 }
7952 if (isModEnabled('project') && (empty($exclude) || !in_array('project', $exclude)) && (empty($include) || in_array('project', $include))) { // Most objects
7953 $substitutionarray['__PROJECT_ID__'] = '__PROJECT_ID__';
7954 $substitutionarray['__PROJECT_REF__'] = '__PROJECT_REF__';
7955 $substitutionarray['__PROJECT_NAME__'] = '__PROJECT_NAME__';
7956 /*$substitutionarray['__PROJECT_NOTE_PUBLIC__'] = '__PROJECT_NOTE_PUBLIC__';
7957 $substitutionarray['__PROJECT_NOTE_PRIVATE__'] = '__PROJECT_NOTE_PRIVATE__';*/
7958 }
7959 if (isModEnabled('contrat') && (!is_object($object) || $object->element == 'contract') && (empty($exclude) || !in_array('contract', $exclude)) && (empty($include) || in_array('contract', $include))) {
7960 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = 'Highest date planned for a service start';
7961 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = 'Highest date and hour planned for service start';
7962 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = 'Lowest data for planned expiration of service';
7963 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = 'Lowest date and hour for planned expiration of service';
7964 }
7965 if (isModEnabled("propal") && (!is_object($object) || $object->element == 'propal') && (empty($exclude) || !in_array('propal', $exclude)) && (empty($include) || in_array('propal', $include))) {
7966 $substitutionarray['__ONLINE_SIGN_URL__'] = 'ToOfferALinkForOnlineSignature';
7967 }
7968 if (isModEnabled("ficheinter") && (!is_object($object) || $object->element == 'fichinter') && (empty($exclude) || !in_array('intervention', $exclude)) && (empty($include) || in_array('intervention', $include))) {
7969 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = 'ToOfferALinkForOnlineSignature';
7970 }
7971 $substitutionarray['__ONLINE_PAYMENT_URL__'] = 'UrlToPayOnlineIfApplicable';
7972 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = 'TextAndUrlToPayOnlineIfApplicable';
7973 $substitutionarray['__SECUREKEYPAYMENT__'] = 'Security key (if key is not unique per record)';
7974 $substitutionarray['__SECUREKEYPAYMENT_MEMBER__'] = 'Security key for payment on a member subscription (one key per member)';
7975 $substitutionarray['__SECUREKEYPAYMENT_ORDER__'] = 'Security key for payment on an order';
7976 $substitutionarray['__SECUREKEYPAYMENT_INVOICE__'] = 'Security key for payment on an invoice';
7977 $substitutionarray['__SECUREKEYPAYMENT_CONTRACTLINE__'] = 'Security key for payment on a service of a contract';
7978
7979 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = 'Direct download url of a proposal';
7980 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = 'Direct download url of an order';
7981 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = 'Direct download url of an invoice';
7982 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = 'Direct download url of a contract';
7983 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = 'Direct download url of a supplier proposal';
7984
7985 if (isModEnabled("expedition") && (!is_object($object) || $object->element == 'shipping')) {
7986 $substitutionarray['__SHIPPINGTRACKNUM__'] = 'Shipping tracking number';
7987 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = 'Shipping tracking url';
7988 }
7989 if (isModEnabled("reception") && (!is_object($object) || $object->element == 'reception')) {
7990 $substitutionarray['__RECEPTIONTRACKNUM__'] = 'Shippin tracking number of shipment';
7991 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = 'Shipping tracking url';
7992 }
7993 } else {
7994 $substitutionarray['__ID__'] = $object->id;
7995 $substitutionarray['__REF__'] = $object->ref;
7996 $substitutionarray['__NEWREF__'] = $object->newref;
7997 $substitutionarray['__LABEL__'] = (isset($object->label) ? $object->label : (isset($object->title) ? $object->title : null));
7998 $substitutionarray['__REF_CLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
7999 $substitutionarray['__REF_SUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8000 $substitutionarray['__NOTE_PUBLIC__'] = (isset($object->note_public) ? $object->note_public : null);
8001 $substitutionarray['__NOTE_PRIVATE__'] = (isset($object->note_private) ? $object->note_private : null);
8002 if ($object->element == "shipping") {
8003 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_delivery) ? dol_print_date($object->date_delivery, 'day', 0, $outputlangs) : '');
8004 } else {
8005 $substitutionarray['__DATE_DELIVERY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, 'day', 0, $outputlangs) : '');
8006 }
8007 $substitutionarray['__DATE_DELIVERY_DAY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%d") : '');
8008 $substitutionarray['__DATE_DELIVERY_DAY_TEXT__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%A") : '');
8009 $substitutionarray['__DATE_DELIVERY_MON__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%m") : '');
8010 $substitutionarray['__DATE_DELIVERY_MON_TEXT__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%b") : '');
8011 $substitutionarray['__DATE_DELIVERY_YEAR__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%Y") : '');
8012 $substitutionarray['__DATE_DELIVERY_HH__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%H") : '');
8013 $substitutionarray['__DATE_DELIVERY_MM__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%M") : '');
8014 $substitutionarray['__DATE_DELIVERY_SS__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, "%S") : '');
8015
8016 // For backward compatibility (deprecated)
8017 $substitutionarray['__REFCLIENT__'] = (isset($object->ref_client) ? $object->ref_client : (isset($object->ref_customer) ? $object->ref_customer : null));
8018 $substitutionarray['__REFSUPPLIER__'] = (isset($object->ref_supplier) ? $object->ref_supplier : null);
8019 $substitutionarray['__SUPPLIER_ORDER_DATE_DELIVERY__'] = (isset($object->date_livraison) ? dol_print_date($object->date_livraison, 'day', 0, $outputlangs) : '');
8020 $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 : '')) : '');
8021
8022 if (is_object($object) && ($object->element == 'adherent' || $object->element == 'member') && $object->id > 0) {
8023 $birthday = (empty($object->birth) ? '' : dol_print_date($object->birth, 'day'));
8024
8025 $substitutionarray['__MEMBER_ID__'] = (isset($object->id) ? $object->id : '');
8026 if (method_exists($object, 'getCivilityLabel')) {
8027 $substitutionarray['__MEMBER_CIVILITY__'] = $object->getCivilityLabel();
8028 }
8029 $substitutionarray['__MEMBER_FIRSTNAME__'] = (isset($object->firstname) ? $object->firstname : '');
8030 $substitutionarray['__MEMBER_LASTNAME__'] = (isset($object->lastname) ? $object->lastname : '');
8031 $substitutionarray['__MEMBER_USER_LOGIN_INFORMATION__'] = '';
8032 if (method_exists($object, 'getFullName')) {
8033 $substitutionarray['__MEMBER_FULLNAME__'] = $object->getFullName($outputlangs);
8034 }
8035 $substitutionarray['__MEMBER_COMPANY__'] = (isset($object->societe) ? $object->societe : '');
8036 $substitutionarray['__MEMBER_ADDRESS__'] = (isset($object->address) ? $object->address : '');
8037 $substitutionarray['__MEMBER_ZIP__'] = (isset($object->zip) ? $object->zip : '');
8038 $substitutionarray['__MEMBER_TOWN__'] = (isset($object->town) ? $object->town : '');
8039 $substitutionarray['__MEMBER_COUNTRY__'] = (isset($object->country) ? $object->country : '');
8040 $substitutionarray['__MEMBER_EMAIL__'] = (isset($object->email) ? $object->email : '');
8041 $substitutionarray['__MEMBER_BIRTH__'] = (isset($birthday) ? $birthday : '');
8042 $substitutionarray['__MEMBER_PHOTO__'] = (isset($object->photo) ? $object->photo : '');
8043 $substitutionarray['__MEMBER_LOGIN__'] = (isset($object->login) ? $object->login : '');
8044 $substitutionarray['__MEMBER_PASSWORD__'] = (isset($object->pass) ? $object->pass : '');
8045 $substitutionarray['__MEMBER_PHONE__'] = (isset($object->phone) ? dol_print_phone($object->phone) : '');
8046 $substitutionarray['__MEMBER_PHONEPRO__'] = (isset($object->phone_perso) ? dol_print_phone($object->phone_perso) : '');
8047 $substitutionarray['__MEMBER_PHONEMOBILE__'] = (isset($object->phone_mobile) ? dol_print_phone($object->phone_mobile) : '');
8048 $substitutionarray['__MEMBER_TYPE__'] = (isset($object->type) ? $object->type : '');
8049 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE__'] = dol_print_date($object->first_subscription_date, 'day');
8050 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_START__'] = (isset($object->first_subscription_date_start) ? dol_print_date($object->first_subscription_date_start, 'day') : '');
8051 $substitutionarray['__MEMBER_FIRST_SUBSCRIPTION_DATE_END__'] = (isset($object->first_subscription_date_end) ? dol_print_date($object->first_subscription_date_end, 'day') : '');
8052 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE__'] = dol_print_date($object->last_subscription_date, 'day');
8053 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_START__'] = dol_print_date($object->last_subscription_date_start, 'day');
8054 $substitutionarray['__MEMBER_LAST_SUBSCRIPTION_DATE_END__'] = dol_print_date($object->last_subscription_date_end, 'day');
8055 }
8056
8057 if (is_object($object) && $object->element == 'societe') {
8058 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object) ? $object->id : '');
8059 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object) ? $object->name : '');
8060 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object) ? $object->name_alias : '');
8061 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object) ? $object->code_client : '');
8062 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object) ? $object->code_fournisseur : '');
8063 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object) ? $object->email : '');
8064 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object) ? dol_print_phone($object->phone) : '');
8065 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object) ? dol_print_phone($object->fax) : '');
8066 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object) ? $object->address : '');
8067 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object) ? $object->zip : '');
8068 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object) ? $object->town : '');
8069 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object) ? $object->country_id : '');
8070 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object) ? $object->country_code : '');
8071 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object) ? $object->idprof1 : '');
8072 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object) ? $object->idprof2 : '');
8073 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object) ? $object->idprof3 : '');
8074 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object) ? $object->idprof4 : '');
8075 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object) ? $object->idprof5 : '');
8076 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object) ? $object->idprof6 : '');
8077 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object) ? $object->tva_intra : '');
8078 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_public) : '');
8079 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object) ? dol_htmlentitiesbr($object->note_private) : '');
8080 } elseif (is_object($object->thirdparty)) {
8081 $substitutionarray['__THIRDPARTY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->id : '');
8082 $substitutionarray['__THIRDPARTY_NAME__'] = (is_object($object->thirdparty) ? $object->thirdparty->name : '');
8083 $substitutionarray['__THIRDPARTY_NAME_ALIAS__'] = (is_object($object->thirdparty) ? $object->thirdparty->name_alias : '');
8084 $substitutionarray['__THIRDPARTY_CODE_CLIENT__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_client : '');
8085 $substitutionarray['__THIRDPARTY_CODE_FOURNISSEUR__'] = (is_object($object->thirdparty) ? $object->thirdparty->code_fournisseur : '');
8086 $substitutionarray['__THIRDPARTY_EMAIL__'] = (is_object($object->thirdparty) ? $object->thirdparty->email : '');
8087 $substitutionarray['__THIRDPARTY_PHONE__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->phone) : '');
8088 $substitutionarray['__THIRDPARTY_FAX__'] = (is_object($object->thirdparty) ? dol_print_phone($object->thirdparty->fax) : '');
8089 $substitutionarray['__THIRDPARTY_ADDRESS__'] = (is_object($object->thirdparty) ? $object->thirdparty->address : '');
8090 $substitutionarray['__THIRDPARTY_ZIP__'] = (is_object($object->thirdparty) ? $object->thirdparty->zip : '');
8091 $substitutionarray['__THIRDPARTY_TOWN__'] = (is_object($object->thirdparty) ? $object->thirdparty->town : '');
8092 $substitutionarray['__THIRDPARTY_COUNTRY_ID__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_id : '');
8093 $substitutionarray['__THIRDPARTY_COUNTRY_CODE__'] = (is_object($object->thirdparty) ? $object->thirdparty->country_code : '');
8094 $substitutionarray['__THIRDPARTY_IDPROF1__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof1 : '');
8095 $substitutionarray['__THIRDPARTY_IDPROF2__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof2 : '');
8096 $substitutionarray['__THIRDPARTY_IDPROF3__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof3 : '');
8097 $substitutionarray['__THIRDPARTY_IDPROF4__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof4 : '');
8098 $substitutionarray['__THIRDPARTY_IDPROF5__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof5 : '');
8099 $substitutionarray['__THIRDPARTY_IDPROF6__'] = (is_object($object->thirdparty) ? $object->thirdparty->idprof6 : '');
8100 $substitutionarray['__THIRDPARTY_TVAINTRA__'] = (is_object($object->thirdparty) ? $object->thirdparty->tva_intra : '');
8101 $substitutionarray['__THIRDPARTY_NOTE_PUBLIC__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_public) : '');
8102 $substitutionarray['__THIRDPARTY_NOTE_PRIVATE__'] = (is_object($object->thirdparty) ? dol_htmlentitiesbr($object->thirdparty->note_private) : '');
8103 }
8104
8105 if (is_object($object) && $object->element == 'recruitmentcandidature') {
8106 $substitutionarray['__CANDIDATE_FULLNAME__'] = $object->getFullName($outputlangs);
8107 $substitutionarray['__CANDIDATE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8108 $substitutionarray['__CANDIDATE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8109 }
8110 if (is_object($object) && $object->element == 'conferenceorboothattendee') {
8111 $substitutionarray['__ATTENDEE_FULLNAME__'] = $object->getFullName($outputlangs);
8112 $substitutionarray['__ATTENDEE_FIRSTNAME__'] = isset($object->firstname) ? $object->firstname : '';
8113 $substitutionarray['__ATTENDEE_LASTNAME__'] = isset($object->lastname) ? $object->lastname : '';
8114 }
8115
8116 $project = null;
8117 if (is_object($object->project)) {
8118 $project = $object->project;
8119 } elseif (is_object($object->projet)) { // Deprecated, for backward compatibility
8120 $project = $object->projet;
8121 }
8122 if ($project) {
8123 $substitutionarray['__PROJECT_ID__'] = $project->id;
8124 $substitutionarray['__PROJECT_REF__'] = $project->ref;
8125 $substitutionarray['__PROJECT_NAME__'] = $project->title;
8126 }
8127 if (is_object($object) && $object->element == 'project') {
8128 $substitutionarray['__PROJECT_NAME__'] = $object->title;
8129 }
8130
8131 if (is_object($object) && $object->element == 'shipping') {
8132 $substitutionarray['__SHIPPINGTRACKNUM__'] = $object->tracking_number;
8133 $substitutionarray['__SHIPPINGTRACKNUMURL__'] = $object->tracking_url;
8134 }
8135 if (is_object($object) && $object->element == 'reception') {
8136 $substitutionarray['__RECEPTIONTRACKNUM__'] = $object->tracking_number;
8137 $substitutionarray['__RECEPTIONTRACKNUMURL__'] = $object->tracking_url;
8138 }
8139
8140 if (is_object($object) && $object->element == 'contrat' && $object->id > 0 && is_array($object->lines)) {
8141 $dateplannedstart = '';
8142 $datenextexpiration = '';
8143 foreach ($object->lines as $line) {
8144 if ($line->date_start > $dateplannedstart) {
8145 $dateplannedstart = $line->date_start;
8146 }
8147 if ($line->statut == 4 && $line->date_end && (!$datenextexpiration || $line->date_end < $datenextexpiration)) {
8148 $datenextexpiration = $line->date_end;
8149 }
8150 }
8151 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATE__'] = dol_print_date($dateplannedstart, 'day');
8152 $substitutionarray['__CONTRACT_HIGHEST_PLANNED_START_DATETIME__'] = dol_print_date($dateplannedstart, 'standard');
8153 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATE__'] = dol_print_date($datenextexpiration, 'day');
8154 $substitutionarray['__CONTRACT_LOWEST_EXPIRATION_DATETIME__'] = dol_print_date($datenextexpiration, 'standard');
8155 }
8156 // add substition variable for ticket
8157 if (is_object($object) && $object->element == 'ticket') {
8158 $substitutionarray['__TICKET_TRACKID__'] = $object->track_id;
8159 $substitutionarray['__REF__'] = $object->ref;
8160 $substitutionarray['__TICKET_SUBJECT__'] = $object->subject;
8161 $substitutionarray['__TICKET_TYPE__'] = $object->type_code;
8162 $substitutionarray['__TICKET_SEVERITY__'] = $object->severity_code;
8163 $substitutionarray['__TICKET_CATEGORY__'] = $object->category_code; // For backward compatibility
8164 $substitutionarray['__TICKET_ANALYTIC_CODE__'] = $object->category_code;
8165 $substitutionarray['__TICKET_MESSAGE__'] = $object->message;
8166 $substitutionarray['__TICKET_PROGRESSION__'] = $object->progress;
8167 $userstat = new User($db);
8168 if ($object->fk_user_assign > 0) {
8169 $userstat->fetch($object->fk_user_assign);
8170 $substitutionarray['__TICKET_USER_ASSIGN__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8171 }
8172
8173 if ($object->fk_user_create > 0) {
8174 $userstat->fetch($object->fk_user_create);
8175 $substitutionarray['__USER_CREATE__'] = dolGetFirstLastname($userstat->firstname, $userstat->lastname);
8176 }
8177 }
8178
8179 // Create dynamic tags for __EXTRAFIELD_FIELD__
8180 if ($object->table_element && $object->id > 0) {
8181 if (!is_object($extrafields)) {
8182 $extrafields = new ExtraFields($db);
8183 }
8184 $extrafields->fetch_name_optionals_label($object->table_element, true);
8185
8186 if ($object->fetch_optionals() > 0) {
8187 if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label']) > 0) {
8188 foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $label) {
8189 if ($extrafields->attributes[$object->table_element]['type'][$key] == 'date') {
8190 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_date($object->array_options['options_'.$key], 'day');
8191 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = dol_print_date($object->array_options['options_'.$key], 'day', 'tzserver', $outputlangs);
8192 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = dol_print_date($object->array_options['options_'.$key], 'dayrfc');
8193 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'datetime') {
8194 $datetime = $object->array_options['options_'.$key];
8195 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour') : '');
8196 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhour', 'tzserver', $outputlangs) : '');
8197 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_DAY_LOCALE__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'day', 'tzserver', $outputlangs) : '');
8198 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_RFC__'] = ($datetime != "0000-00-00 00:00:00" ? dol_print_date($datetime, 'dayhourrfc') : '');
8199 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'phone') {
8200 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = dol_print_phone($object->array_options['options_'.$key]);
8201 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] == 'price') {
8202 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = $object->array_options['options_'.$key];
8203 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'_FORMATED__'] = price($object->array_options['options_'.$key]);
8204 } elseif ($extrafields->attributes[$object->table_element]['type'][$key] != 'separator') {
8205 $substitutionarray['__EXTRAFIELD_'.strtoupper($key).'__'] = !empty($object->array_options['options_'.$key]) ? $object->array_options['options_'.$key] :'';
8206 }
8207 }
8208 }
8209 }
8210 }
8211
8212 // Complete substitution array with the url to make online payment
8213 $paymenturl = '';
8214 if (empty($substitutionarray['__REF__'])) {
8215 $paymenturl = '';
8216 } else {
8217 // Set the online payment url link into __ONLINE_PAYMENT_URL__ key
8218 require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
8219 $outputlangs->loadLangs(array('paypal', 'other'));
8220
8221 $amounttouse = 0;
8222 $typeforonlinepayment = 'free';
8223 if (is_object($object) && $object->element == 'commande') {
8224 $typeforonlinepayment = 'order';
8225 }
8226 if (is_object($object) && $object->element == 'facture') {
8227 $typeforonlinepayment = 'invoice';
8228 }
8229 if (is_object($object) && $object->element == 'member') {
8230 $typeforonlinepayment = 'member';
8231 if (!empty($object->last_subscription_amount)) {
8232 $amounttouse = $object->last_subscription_amount;
8233 }
8234 }
8235 if (is_object($object) && $object->element == 'contrat') {
8236 $typeforonlinepayment = 'contract';
8237 }
8238 if (is_object($object) && $object->element == 'fichinter') {
8239 $typeforonlinepayment = 'ficheinter';
8240 }
8241
8242 $url = getOnlinePaymentUrl(0, $typeforonlinepayment, $substitutionarray['__REF__'], $amounttouse);
8243 $paymenturl = $url;
8244 }
8245
8246 if ($object->id > 0) {
8247 $substitutionarray['__ONLINE_PAYMENT_TEXT_AND_URL__'] = ($paymenturl ?str_replace('\n', "\n", $outputlangs->trans("PredefinedMailContentLink", $paymenturl)) : '');
8248 $substitutionarray['__ONLINE_PAYMENT_URL__'] = $paymenturl;
8249
8250 if (!empty($conf->global->PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'propal') {
8251 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8252 } else {
8253 $substitutionarray['__DIRECTDOWNLOAD_URL_PROPOSAL__'] = '';
8254 }
8255 if (!empty($conf->global->ORDER_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'commande') {
8256 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = $object->getLastMainDocLink($object->element);
8257 } else {
8258 $substitutionarray['__DIRECTDOWNLOAD_URL_ORDER__'] = '';
8259 }
8260 if (!empty($conf->global->INVOICE_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'facture') {
8261 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = $object->getLastMainDocLink($object->element);
8262 } else {
8263 $substitutionarray['__DIRECTDOWNLOAD_URL_INVOICE__'] = '';
8264 }
8265 if (!empty($conf->global->CONTRACT_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'contrat') {
8266 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = $object->getLastMainDocLink($object->element);
8267 } else {
8268 $substitutionarray['__DIRECTDOWNLOAD_URL_CONTRACT__'] = '';
8269 }
8270 if (!empty($conf->global->FICHINTER_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'fichinter') {
8271 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = $object->getLastMainDocLink($object->element);
8272 } else {
8273 $substitutionarray['__DIRECTDOWNLOAD_URL_FICHINTER__'] = '';
8274 }
8275 if (!empty($conf->global->SUPPLIER_PROPOSAL_ALLOW_EXTERNAL_DOWNLOAD) && is_object($object) && $object->element == 'supplier_proposal') {
8276 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = $object->getLastMainDocLink($object->element);
8277 } else {
8278 $substitutionarray['__DIRECTDOWNLOAD_URL_SUPPLIER_PROPOSAL__'] = '';
8279 }
8280
8281 if (is_object($object) && $object->element == 'propal') {
8282 $substitutionarray['__URL_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/comm/propal/card.php?id=".$object->id;
8283 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8284 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'proposal', $object->ref);
8285 }
8286 if (is_object($object) && $object->element == 'commande') {
8287 $substitutionarray['__URL_ORDER__'] = DOL_MAIN_URL_ROOT."/commande/card.php?id=".$object->id;
8288 }
8289 if (is_object($object) && $object->element == 'facture') {
8290 $substitutionarray['__URL_INVOICE__'] = DOL_MAIN_URL_ROOT."/compta/facture/card.php?id=".$object->id;
8291 }
8292 if (is_object($object) && $object->element == 'contrat') {
8293 $substitutionarray['__URL_CONTRACT__'] = DOL_MAIN_URL_ROOT."/contrat/card.php?id=".$object->id;
8294 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8295 $substitutionarray['__ONLINE_SIGN_URL__'] = getOnlineSignatureUrl(0, 'contract', $object->ref);
8296 }
8297 if (is_object($object) && $object->element == 'fichinter') {
8298 $substitutionarray['__URL_FICHINTER__'] = DOL_MAIN_URL_ROOT."/fichinter/card.php?id=".$object->id;
8299 require_once DOL_DOCUMENT_ROOT.'/core/lib/signature.lib.php';
8300 $substitutionarray['__ONLINE_SIGN_FICHINTER_URL__'] = getOnlineSignatureUrl(0, 'fichinter', $object->ref);
8301 }
8302 if (is_object($object) && $object->element == 'supplier_proposal') {
8303 $substitutionarray['__URL_SUPPLIER_PROPOSAL__'] = DOL_MAIN_URL_ROOT."/supplier_proposal/card.php?id=".$object->id;
8304 }
8305 if (is_object($object) && $object->element == 'shipping') {
8306 $substitutionarray['__URL_SHIPMENT__'] = DOL_MAIN_URL_ROOT."/expedition/card.php?id=".$object->id;
8307 }
8308 }
8309
8310 if (is_object($object) && $object->element == 'action') {
8311 $substitutionarray['__EVENT_LABEL__'] = $object->label;
8312 $substitutionarray['__EVENT_DATE__'] = dol_print_date($object->datep, '%A %d %b %Y');
8313 $substitutionarray['__EVENT_TIME__'] = dol_print_date($object->datep, '%H:%M:%S');
8314 }
8315 }
8316 }
8317 if ((empty($exclude) || !in_array('objectamount', $exclude)) && (empty($include) || in_array('objectamount', $include))) {
8318 include_once DOL_DOCUMENT_ROOT.'/core/lib/functionsnumtoword.lib.php';
8319
8320 $substitutionarray['__DATE_YMD__'] = is_object($object) ? (isset($object->date) ? dol_print_date($object->date, 'day', 0, $outputlangs) : null) : '';
8321 $substitutionarray['__DATE_DUE_YMD__'] = is_object($object) ? (isset($object->date_lim_reglement) ? dol_print_date($object->date_lim_reglement, 'day', 0, $outputlangs) : null) : '';
8322
8323 $already_payed_all = 0;
8324 if (is_object($object) && ($object instanceof Facture)) {
8325 $already_payed_all = $object->sumpayed + $object->sumdeposit + $object->sumcreditnote;
8326 }
8327
8328 $substitutionarray['__AMOUNT_EXCL_TAX__'] = is_object($object) ? $object->total_ht : '';
8329
8330 $substitutionarray['__AMOUNT__'] = is_object($object) ? $object->total_ttc : '';
8331 $substitutionarray['__AMOUNT_TEXT__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, '', true) : '';
8332 $substitutionarray['__AMOUNT_TEXTCURRENCY__'] = is_object($object) ? dol_convertToWord($object->total_ttc, $outputlangs, $conf->currency, true) : '';
8333
8334 $substitutionarray['__AMOUNT_REMAIN__'] = is_object($object) ? price2num($object->total_ttc - $already_payed_all, 'MT') : '';
8335
8336 $substitutionarray['__AMOUNT_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8337 $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)) : '';
8338 $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)) : '';
8339
8340 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8341 $substitutionarray['__AMOUNT_TAX2__'] = is_object($object) ? $object->total_localtax1 : '';
8342 }
8343 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8344 $substitutionarray['__AMOUNT_TAX3__'] = is_object($object) ? $object->total_localtax2 : '';
8345 }
8346
8347 // Amount keys formated in a currency
8348 $substitutionarray['__AMOUNT_EXCL_TAX_FORMATED__'] = is_object($object) ? ($object->total_ht ? price($object->total_ht, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8349 $substitutionarray['__AMOUNT_FORMATED__'] = is_object($object) ? ($object->total_ttc ? price($object->total_ttc, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8350 $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) : '';
8351 $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)) : '';
8352 if ($onlykey != 2 || $mysoc->useLocalTax(1)) {
8353 $substitutionarray['__AMOUNT_TAX2_FORMATED__'] = is_object($object) ? ($object->total_localtax1 ? price($object->total_localtax1, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8354 }
8355 if ($onlykey != 2 || $mysoc->useLocalTax(2)) {
8356 $substitutionarray['__AMOUNT_TAX3_FORMATED__'] = is_object($object) ? ($object->total_localtax2 ? price($object->total_localtax2, 0, $outputlangs, 0, -1, -1, $conf->currency) : null) : '';
8357 }
8358
8359 $substitutionarray['__AMOUNT_MULTICURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? $object->multicurrency_total_ttc : '';
8360 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXT__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, '', true) : '';
8361 $substitutionarray['__AMOUNT_MULTICURRENCY_TEXTCURRENCY__'] = (is_object($object) && isset($object->multicurrency_total_ttc)) ? dol_convertToWord($object->multicurrency_total_ttc, $outputlangs, $object->multicurrency_code, true) : '';
8362 // TODO Add other keys for foreign multicurrency
8363
8364 // For backward compatibility
8365 if ($onlykey != 2) {
8366 $substitutionarray['__TOTAL_TTC__'] = is_object($object) ? $object->total_ttc : '';
8367 $substitutionarray['__TOTAL_HT__'] = is_object($object) ? $object->total_ht : '';
8368 $substitutionarray['__TOTAL_VAT__'] = is_object($object) ? (isset($object->total_vat) ? $object->total_vat : $object->total_tva) : '';
8369 }
8370 }
8371
8372 //var_dump($substitutionarray['__AMOUNT_FORMATED__']);
8373 if ((empty($exclude) || !in_array('date', $exclude)) && (empty($include) || in_array('date', $include))) {
8374 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
8375
8376 $now = dol_now();
8377
8378 $tmp = dol_getdate($now, true);
8379 $tmp2 = dol_get_prev_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8380 $tmp3 = dol_get_prev_month($tmp['mon'], $tmp['year']);
8381 $tmp4 = dol_get_next_day($tmp['mday'], $tmp['mon'], $tmp['year']);
8382 $tmp5 = dol_get_next_month($tmp['mon'], $tmp['year']);
8383
8384 $daytext = $outputlangs->trans('Day'.$tmp['wday']);
8385
8386 $substitutionarray = array_merge($substitutionarray, array(
8387 '__NOW_TMS__' => (int) $now,
8388 '__NOW_TMS_YMD__' => dol_print_date($now, 'day', 0, $outputlangs),
8389 '__DAY__' => (string) $tmp['mday'],
8390 '__DAY_TEXT__' => $daytext, // Monday
8391 '__DAY_TEXT_SHORT__' => dol_trunc($daytext, 3, 'right', 'UTF-8', 1), // Mon
8392 '__DAY_TEXT_MIN__' => dol_trunc($daytext, 1, 'right', 'UTF-8', 1), // M
8393 '__MONTH__' => (string) $tmp['mon'],
8394 '__MONTH_TEXT__' => $outputlangs->trans('Month'.sprintf("%02d", $tmp['mon'])),
8395 '__MONTH_TEXT_SHORT__' => $outputlangs->trans('MonthShort'.sprintf("%02d", $tmp['mon'])),
8396 '__MONTH_TEXT_MIN__' => $outputlangs->trans('MonthVeryShort'.sprintf("%02d", $tmp['mon'])),
8397 '__YEAR__' => (string) $tmp['year'],
8398 '__PREVIOUS_DAY__' => (string) $tmp2['day'],
8399 '__PREVIOUS_MONTH__' => (string) $tmp3['month'],
8400 '__PREVIOUS_YEAR__' => (string) ($tmp['year'] - 1),
8401 '__NEXT_DAY__' => (string) $tmp4['day'],
8402 '__NEXT_MONTH__' => (string) $tmp5['month'],
8403 '__NEXT_YEAR__' => (string) ($tmp['year'] + 1),
8404 ));
8405 }
8406
8407 if (isModEnabled('multicompany')) {
8408 $substitutionarray = array_merge($substitutionarray, array('__ENTITY_ID__' => $conf->entity));
8409 }
8410 if ((empty($exclude) || !in_array('system', $exclude)) && (empty($include) || in_array('user', $include))) {
8411 $substitutionarray['__DOL_MAIN_URL_ROOT__'] = DOL_MAIN_URL_ROOT;
8412 $substitutionarray['__(AnyTranslationKey)__'] = $outputlangs->trans('TranslationOfKey');
8413 $substitutionarray['__(AnyTranslationKey|langfile)__'] = $outputlangs->trans('TranslationOfKey').' (load also language file before)';
8414 $substitutionarray['__[AnyConstantKey]__'] = $outputlangs->trans('ValueOfConstantKey');
8415 }
8416
8417 return $substitutionarray;
8418}
8419
8436function make_substitutions($text, $substitutionarray, $outputlangs = null, $converttextinhtmlifnecessary = 0)
8437{
8438 global $conf, $langs;
8439
8440 if (!is_array($substitutionarray)) {
8441 return 'ErrorBadParameterSubstitutionArrayWhenCalling_make_substitutions';
8442 }
8443
8444 if (empty($outputlangs)) {
8445 $outputlangs = $langs;
8446 }
8447
8448 // Is initial text HTML or simple text ?
8449 $msgishtml = 0;
8450 if (dol_textishtml($text, 1)) {
8451 $msgishtml = 1;
8452 }
8453
8454 // Make substitution for language keys: __(AnyTranslationKey)__ or __(AnyTranslationKey|langfile)__
8455 if (is_object($outputlangs)) {
8456 $reg = array();
8457 while (preg_match('/__\‍(([^\‍)]+)\‍)__/', $text, $reg)) {
8458 // If key is __(TranslationKey|langfile)__, then force load of langfile.lang
8459 $tmp = explode('|', $reg[1]);
8460 if (!empty($tmp[1])) {
8461 $outputlangs->load($tmp[1]);
8462 }
8463
8464 $value = $outputlangs->transnoentitiesnoconv($reg[1]);
8465
8466 if (empty($converttextinhtmlifnecessary)) {
8467 // convert $newval into HTML is necessary
8468 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8469 } else {
8470 if (! $msgishtml) {
8471 $valueishtml = dol_textishtml($value, 1);
8472 //var_dump("valueishtml=".$valueishtml);
8473
8474 if ($valueishtml) {
8475 $text = dol_htmlentitiesbr($text);
8476 $msgishtml = 1;
8477 }
8478 } else {
8479 $value = dol_nl2br("$value");
8480 }
8481
8482 $text = preg_replace('/__\‍('.preg_quote($reg[1], '/').'\‍)__/', $value, $text);
8483 }
8484 }
8485 }
8486
8487 // Make substitution for constant keys.
8488 // Must be after the substitution of translation, so if the text of translation contains a string __[xxx]__, it is also converted.
8489 $reg = array();
8490 while (preg_match('/__\[([^\]]+)\]__/', $text, $reg)) {
8491 $keyfound = $reg[1];
8492 if (isASecretKey($keyfound)) {
8493 $value = '*****forbidden*****';
8494 } else {
8495 $value = empty($conf->global->$keyfound) ? '' : $conf->global->$keyfound;
8496 }
8497
8498 if (empty($converttextinhtmlifnecessary)) {
8499 // convert $newval into HTML is necessary
8500 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $msgishtml ? dol_htmlentitiesbr($value) : $value, $text);
8501 } else {
8502 if (! $msgishtml) {
8503 $valueishtml = dol_textishtml($value, 1);
8504
8505 if ($valueishtml) {
8506 $text = dol_htmlentitiesbr($text);
8507 $msgishtml = 1;
8508 }
8509 } else {
8510 $value = dol_nl2br("$value");
8511 }
8512
8513 $text = preg_replace('/__\['.preg_quote($keyfound, '/').'\]__/', $value, $text);
8514 }
8515 }
8516
8517 // Make substitution for array $substitutionarray
8518 foreach ($substitutionarray as $key => $value) {
8519 if (!isset($value)) {
8520 continue; // If value is null, it same than not having substitution key at all into array, we do not replace.
8521 }
8522
8523 if (($key == '__USER_SIGNATURE__' || $key == '__SENDEREMAIL_SIGNATURE__') && (!empty($conf->global->MAIN_MAIL_DO_NOT_USE_SIGN))) {
8524 $value = ''; // Protection
8525 }
8526
8527 if (empty($converttextinhtmlifnecessary)) {
8528 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8529 } else {
8530 if (! $msgishtml) {
8531 $valueishtml = dol_textishtml($value, 1);
8532
8533 if ($valueishtml) {
8534 $text = dol_htmlentitiesbr($text);
8535 $msgishtml = 1;
8536 }
8537 } else {
8538 $value = dol_nl2br("$value");
8539 }
8540 $text = str_replace("$key", "$value", $text); // We must keep the " to work when value is 123.5 for example
8541 }
8542 }
8543
8544 return $text;
8545}
8546
8559function complete_substitutions_array(&$substitutionarray, $outputlangs, $object = null, $parameters = null, $callfunc = "completesubstitutionarray")
8560{
8561 global $conf, $user;
8562
8563 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
8564
8565 // Note: substitution key for each extrafields, using key __EXTRA_XXX__ is already available into the getCommonSubstitutionArray used to build the substitution array.
8566
8567 // Check if there is external substitution to do, requested by plugins
8568 $dirsubstitutions = array_merge(array(), (array) $conf->modules_parts['substitutions']);
8569
8570 foreach ($dirsubstitutions as $reldir) {
8571 $dir = dol_buildpath($reldir, 0);
8572
8573 // Check if directory exists
8574 if (!dol_is_dir($dir)) {
8575 continue;
8576 }
8577
8578 $substitfiles = dol_dir_list($dir, 'files', 0, 'functions_');
8579 foreach ($substitfiles as $substitfile) {
8580 $reg = array();
8581 if (preg_match('/functions_(.*)\.lib\.php/i', $substitfile['name'], $reg)) {
8582 $module = $reg[1];
8583
8584 dol_syslog("Library ".$substitfile['name']." found into ".$dir);
8585 // Include the user's functions file
8586 require_once $dir.$substitfile['name'];
8587 // Call the user's function, and only if it is defined
8588 $function_name = $module."_".$callfunc;
8589 if (function_exists($function_name)) {
8590 $function_name($substitutionarray, $outputlangs, $object, $parameters);
8591 }
8592 }
8593 }
8594 }
8595 if (!empty($conf->global->ODT_ENABLE_ALL_TAGS_IN_SUBSTITUTIONS)) {
8596 // to list all tags in odt template
8597 $tags = '';
8598 foreach ($substitutionarray as $key => $value) {
8599 $tags .= '{'.$key.'} => '.$value."\n";
8600 }
8601 $substitutionarray = array_merge($substitutionarray, array('__ALL_TAGS__' => $tags));
8602 }
8603}
8604
8614function print_date_range($date_start, $date_end, $format = '', $outputlangs = '')
8615{
8616 print get_date_range($date_start, $date_end, $format, $outputlangs);
8617}
8618
8629function get_date_range($date_start, $date_end, $format = '', $outputlangs = '', $withparenthesis = 1)
8630{
8631 global $langs;
8632
8633 $out = '';
8634
8635 if (!is_object($outputlangs)) {
8636 $outputlangs = $langs;
8637 }
8638
8639 if ($date_start && $date_end) {
8640 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFromTo', dol_print_date($date_start, $format, false, $outputlangs), dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8641 }
8642 if ($date_start && !$date_end) {
8643 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateFrom', dol_print_date($date_start, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8644 }
8645 if (!$date_start && $date_end) {
8646 $out .= ($withparenthesis ? ' (' : '').$outputlangs->transnoentitiesnoconv('DateUntil', dol_print_date($date_end, $format, false, $outputlangs)).($withparenthesis ? ')' : '');
8647 }
8648
8649 return $out;
8650}
8651
8660function dolGetFirstLastname($firstname, $lastname, $nameorder = -1)
8661{
8662 global $conf;
8663
8664 $ret = '';
8665 // If order not defined, we use the setup
8666 if ($nameorder < 0) {
8667 $nameorder = (empty($conf->global->MAIN_FIRSTNAME_NAME_POSITION) ? 1 : 0);
8668 }
8669 if ($nameorder == 1) {
8670 $ret .= $firstname;
8671 if ($firstname && $lastname) {
8672 $ret .= ' ';
8673 }
8674 $ret .= $lastname;
8675 } elseif ($nameorder == 2 || $nameorder == 3) {
8676 $ret .= $firstname;
8677 if (empty($ret) && $nameorder == 3) {
8678 $ret .= $lastname;
8679 }
8680 } else { // 0, 4 or 5
8681 $ret .= $lastname;
8682 if (empty($ret) && $nameorder == 5) {
8683 $ret .= $firstname;
8684 }
8685 if ($nameorder == 0) {
8686 if ($firstname && $lastname) {
8687 $ret .= ' ';
8688 }
8689 $ret .= $firstname;
8690 }
8691 }
8692 return $ret;
8693}
8694
8695
8707function setEventMessage($mesgs, $style = 'mesgs', $noduplicate = 0)
8708{
8709 //dol_syslog(__FUNCTION__ . " is deprecated", LOG_WARNING); This is not deprecated, it is used by setEventMessages function
8710 if (!is_array($mesgs)) {
8711 // If mesgs is a string
8712 if ($mesgs) {
8713 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesgs, $_SESSION['dol_events'][$style])) {
8714 return;
8715 }
8716 $_SESSION['dol_events'][$style][] = $mesgs;
8717 }
8718 } else {
8719 // If mesgs is an array
8720 foreach ($mesgs as $mesg) {
8721 if ($mesg) {
8722 if (!empty($noduplicate) && isset($_SESSION['dol_events'][$style]) && in_array($mesg, $_SESSION['dol_events'][$style])) {
8723 return;
8724 }
8725 $_SESSION['dol_events'][$style][] = $mesg;
8726 }
8727 }
8728 }
8729}
8730
8743function setEventMessages($mesg, $mesgs, $style = 'mesgs', $messagekey = '', $noduplicate = 0)
8744{
8745 if (empty($mesg) && empty($mesgs)) {
8746 dol_syslog("Try to add a message in stack, but value to add is empty message", LOG_WARNING);
8747 } else {
8748 if ($messagekey) {
8749 // Complete message with a js link to set a cookie "DOLHIDEMESSAGE".$messagekey;
8750 // TODO
8751 $mesg .= '';
8752 }
8753 if (empty($messagekey) || empty($_COOKIE["DOLHIDEMESSAGE".$messagekey])) {
8754 if (!in_array((string) $style, array('mesgs', 'warnings', 'errors'))) {
8755 dol_print_error('', 'Bad parameter style='.$style.' for setEventMessages');
8756 }
8757 if (empty($mesgs)) {
8758 setEventMessage($mesg, $style, $noduplicate);
8759 } else {
8760 if (!empty($mesg) && !in_array($mesg, $mesgs)) {
8761 setEventMessage($mesg, $style, $noduplicate); // Add message string if not already into array
8762 }
8763 setEventMessage($mesgs, $style, $noduplicate);
8764 }
8765 }
8766 }
8767}
8768
8778function dol_htmloutput_events($disabledoutputofmessages = 0)
8779{
8780 // Show mesgs
8781 if (isset($_SESSION['dol_events']['mesgs'])) {
8782 if (empty($disabledoutputofmessages)) {
8783 dol_htmloutput_mesg('', $_SESSION['dol_events']['mesgs']);
8784 }
8785 unset($_SESSION['dol_events']['mesgs']);
8786 }
8787 // Show errors
8788 if (isset($_SESSION['dol_events']['errors'])) {
8789 if (empty($disabledoutputofmessages)) {
8790 dol_htmloutput_mesg('', $_SESSION['dol_events']['errors'], 'error');
8791 }
8792 unset($_SESSION['dol_events']['errors']);
8793 }
8794
8795 // Show warnings
8796 if (isset($_SESSION['dol_events']['warnings'])) {
8797 if (empty($disabledoutputofmessages)) {
8798 dol_htmloutput_mesg('', $_SESSION['dol_events']['warnings'], 'warning');
8799 }
8800 unset($_SESSION['dol_events']['warnings']);
8801 }
8802}
8803
8818function get_htmloutput_mesg($mesgstring = '', $mesgarray = '', $style = 'ok', $keepembedded = 0)
8819{
8820 global $conf, $langs;
8821
8822 $ret = 0;
8823 $return = '';
8824 $out = '';
8825 $divstart = $divend = '';
8826
8827 // If inline message with no format, we add it.
8828 if ((empty($conf->use_javascript_ajax) || !empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) || $keepembedded) && !preg_match('/<div class=".*">/i', $out)) {
8829 $divstart = '<div class="'.$style.' clearboth">';
8830 $divend = '</div>';
8831 }
8832
8833 if ((is_array($mesgarray) && count($mesgarray)) || $mesgstring) {
8834 $langs->load("errors");
8835 $out .= $divstart;
8836 if (is_array($mesgarray) && count($mesgarray)) {
8837 foreach ($mesgarray as $message) {
8838 $ret++;
8839 $out .= $langs->trans($message);
8840 if ($ret < count($mesgarray)) {
8841 $out .= "<br>\n";
8842 }
8843 }
8844 }
8845 if ($mesgstring) {
8846 $ret++;
8847 $out .= $langs->trans($mesgstring);
8848 }
8849 $out .= $divend;
8850 }
8851
8852 if ($out) {
8853 if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) && empty($keepembedded)) {
8854 $return = '<script nonce="'.getNonce().'">
8855 $(document).ready(function() {
8856 var block = '.(!empty($conf->global->MAIN_USE_JQUERY_BLOCKUI) ? "true" : "false").'
8857 if (block) {
8858 $.dolEventValid("","'.dol_escape_js($out).'");
8859 } else {
8860 /* jnotify(message, preset of message type, keepmessage) */
8861 $.jnotify("'.dol_escape_js($out).'",
8862 "'.($style == "ok" ? 3000 : $style).'",
8863 '.($style == "ok" ? "false" : "true").',
8864 { remove: function (){} } );
8865 }
8866 });
8867 </script>';
8868 } else {
8869 $return = $out;
8870 }
8871 }
8872
8873 return $return;
8874}
8875
8887function get_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
8888{
8889 return get_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
8890}
8891
8905function dol_htmloutput_mesg($mesgstring = '', $mesgarray = array(), $style = 'ok', $keepembedded = 0)
8906{
8907 if (empty($mesgstring) && (!is_array($mesgarray) || count($mesgarray) == 0)) {
8908 return;
8909 }
8910
8911 $iserror = 0;
8912 $iswarning = 0;
8913 if (is_array($mesgarray)) {
8914 foreach ($mesgarray as $val) {
8915 if ($val && preg_match('/class="error"/i', $val)) {
8916 $iserror++;
8917 break;
8918 }
8919 if ($val && preg_match('/class="warning"/i', $val)) {
8920 $iswarning++;
8921 break;
8922 }
8923 }
8924 } elseif ($mesgstring && preg_match('/class="error"/i', $mesgstring)) {
8925 $iserror++;
8926 } elseif ($mesgstring && preg_match('/class="warning"/i', $mesgstring)) {
8927 $iswarning++;
8928 }
8929 if ($style == 'error') {
8930 $iserror++;
8931 }
8932 if ($style == 'warning') {
8933 $iswarning++;
8934 }
8935
8936 if ($iserror || $iswarning) {
8937 // Remove div from texts
8938 $mesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $mesgstring);
8939 $mesgstring = preg_replace('/<div class="(error|warning)">/', '', $mesgstring);
8940 $mesgstring = preg_replace('/<\/div>/', '', $mesgstring);
8941 // Remove div from texts array
8942 if (is_array($mesgarray)) {
8943 $newmesgarray = array();
8944 foreach ($mesgarray as $val) {
8945 if (is_string($val)) {
8946 $tmpmesgstring = preg_replace('/<\/div><div class="(error|warning)">/', '<br>', $val);
8947 $tmpmesgstring = preg_replace('/<div class="(error|warning)">/', '', $tmpmesgstring);
8948 $tmpmesgstring = preg_replace('/<\/div>/', '', $tmpmesgstring);
8949 $newmesgarray[] = $tmpmesgstring;
8950 } else {
8951 dol_syslog("Error call of dol_htmloutput_mesg with an array with a value that is not a string", LOG_WARNING);
8952 }
8953 }
8954 $mesgarray = $newmesgarray;
8955 }
8956 print get_htmloutput_mesg($mesgstring, $mesgarray, ($iserror ? 'error' : 'warning'), $keepembedded);
8957 } else {
8958 print get_htmloutput_mesg($mesgstring, $mesgarray, 'ok', $keepembedded);
8959 }
8960}
8961
8973function dol_htmloutput_errors($mesgstring = '', $mesgarray = array(), $keepembedded = 0)
8974{
8975 dol_htmloutput_mesg($mesgstring, $mesgarray, 'error', $keepembedded);
8976}
8977
8992function dol_sort_array(&$array, $index, $order = 'asc', $natsort = 0, $case_sensitive = 0, $keepindex = 0)
8993{
8994 // Clean parameters
8995 $order = strtolower($order);
8996
8997 if (is_array($array)) {
8998 $sizearray = count($array);
8999 if ($sizearray > 0) {
9000 $temp = array();
9001 foreach (array_keys($array) as $key) {
9002 if (is_object($array[$key])) {
9003 $temp[$key] = empty($array[$key]->$index) ? 0 : $array[$key]->$index;
9004 } else {
9005 $temp[$key] = empty($array[$key][$index]) ? 0 : $array[$key][$index];
9006 }
9007 if ($natsort == -1) {
9008 $temp[$key] = '___'.$temp[$key]; // We add a string at begin of value to force an alpha order when using asort.
9009 }
9010 }
9011
9012 if (empty($natsort) || $natsort == -1) {
9013 if ($order == 'asc') {
9014 asort($temp);
9015 } else {
9016 arsort($temp);
9017 }
9018 } else {
9019 if ($case_sensitive) {
9020 natsort($temp);
9021 } else {
9022 natcasesort($temp); // natecasesort is not sensible to case
9023 }
9024 if ($order != 'asc') {
9025 $temp = array_reverse($temp, true);
9026 }
9027 }
9028
9029 $sorted = array();
9030
9031 foreach (array_keys($temp) as $key) {
9032 (is_numeric($key) && empty($keepindex)) ? $sorted[] = $array[$key] : $sorted[$key] = $array[$key];
9033 }
9034
9035 return $sorted;
9036 }
9037 }
9038 return $array;
9039}
9040
9041
9048function utf8_check($str)
9049{
9050 $str = (string) $str; // Sometimes string is an int.
9051
9052 // We must use here a binary strlen function (so not dol_strlen)
9053 $strLength = dol_strlen($str);
9054 for ($i = 0; $i < $strLength; $i++) {
9055 if (ord($str[$i]) < 0x80) {
9056 continue; // 0bbbbbbb
9057 } elseif ((ord($str[$i]) & 0xE0) == 0xC0) {
9058 $n = 1; // 110bbbbb
9059 } elseif ((ord($str[$i]) & 0xF0) == 0xE0) {
9060 $n = 2; // 1110bbbb
9061 } elseif ((ord($str[$i]) & 0xF8) == 0xF0) {
9062 $n = 3; // 11110bbb
9063 } elseif ((ord($str[$i]) & 0xFC) == 0xF8) {
9064 $n = 4; // 111110bb
9065 } elseif ((ord($str[$i]) & 0xFE) == 0xFC) {
9066 $n = 5; // 1111110b
9067 } else {
9068 return false; // Does not match any model
9069 }
9070 for ($j = 0; $j < $n; $j++) { // n bytes matching 10bbbbbb follow ?
9071 if ((++$i == strlen($str)) || ((ord($str[$i]) & 0xC0) != 0x80)) {
9072 return false;
9073 }
9074 }
9075 }
9076 return true;
9077}
9078
9085function utf8_valid($str)
9086{
9087 /* 2 other methods to test if string is utf8
9088 $validUTF8 = mb_check_encoding($messagetext, 'UTF-8');
9089 $validUTF8b = ! (false === mb_detect_encoding($messagetext, 'UTF-8', true));
9090 */
9091 return preg_match('//u', $str) ? true : false;
9092}
9093
9094
9101function ascii_check($str)
9102{
9103 if (function_exists('mb_check_encoding')) {
9104 //if (mb_detect_encoding($str, 'ASCII', true) return false;
9105 if (!mb_check_encoding($str, 'ASCII')) {
9106 return false;
9107 }
9108 } else {
9109 if (preg_match('/[^\x00-\x7f]/', $str)) {
9110 return false; // Contains a byte > 7f
9111 }
9112 }
9113
9114 return true;
9115}
9116
9117
9125function dol_osencode($str)
9126{
9127 global $conf;
9128
9129 $tmp = ini_get("unicode.filesystem_encoding"); // Disponible avec PHP 6.0
9130 if (empty($tmp) && !empty($_SERVER["WINDIR"])) {
9131 $tmp = 'iso-8859-1'; // By default for windows
9132 }
9133 if (empty($tmp)) {
9134 $tmp = 'utf-8'; // By default for other
9135 }
9136 if (!empty($conf->global->MAIN_FILESYSTEM_ENCODING)) {
9137 $tmp = $conf->global->MAIN_FILESYSTEM_ENCODING;
9138 }
9139
9140 if ($tmp == 'iso-8859-1') {
9141 return mb_convert_encoding($str, 'ISO-8859-1', 'UTF-8');
9142 }
9143 return $str;
9144}
9145
9146
9161function dol_getIdFromCode($db, $key, $tablename, $fieldkey = 'code', $fieldid = 'id', $entityfilter = 0, $filters = '')
9162{
9163 global $cache_codes;
9164
9165 // If key empty
9166 if ($key == '') {
9167 return '';
9168 }
9169
9170 // Check in cache
9171 if (isset($cache_codes[$tablename][$key][$fieldid])) { // Can be defined to 0 or ''
9172 return $cache_codes[$tablename][$key][$fieldid]; // Found in cache
9173 }
9174
9175 dol_syslog('dol_getIdFromCode (value for field '.$fieldid.' from key '.$key.' not found into cache)', LOG_DEBUG);
9176
9177 $sql = "SELECT ".$fieldid." as valuetoget";
9178 $sql .= " FROM ".MAIN_DB_PREFIX.$tablename;
9179 $sql .= " WHERE ".$fieldkey." = '".$db->escape($key)."'";
9180 if (!empty($entityfilter)) {
9181 $sql .= " AND entity IN (".getEntity($tablename).")";
9182 }
9183 if ($filters) {
9184 $sql .= $filters;
9185 }
9186
9187 $resql = $db->query($sql);
9188 if ($resql) {
9189 $obj = $db->fetch_object($resql);
9190 if ($obj) {
9191 $cache_codes[$tablename][$key][$fieldid] = $obj->valuetoget;
9192 } else {
9193 $cache_codes[$tablename][$key][$fieldid] = '';
9194 }
9195 $db->free($resql);
9196 return $cache_codes[$tablename][$key][$fieldid];
9197 } else {
9198 return -1;
9199 }
9200}
9201
9208function verifCond($strToEvaluate)
9209{
9210 global $user, $conf, $langs;
9211 global $leftmenu;
9212 global $rights; // To export to dol_eval function
9213
9214 //print $strToEvaluate."<br>\n";
9215 $rights = true;
9216 if (isset($strToEvaluate) && $strToEvaluate !== '') {
9217 //var_dump($strToEvaluate);
9218 //$rep = dol_eval($strToEvaluate, 1, 0, '1'); // to show the error
9219 $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
9220 $rights = $rep && (!is_string($rep) || strpos($rep, 'Bad string syntax to evaluate') === false);
9221 //var_dump($rights);
9222 }
9223 return $rights;
9224}
9225
9236function dol_eval($s, $returnvalue = 0, $hideerrors = 1, $onlysimplestring = '1')
9237{
9238 // Only global variables can be changed by eval function and returned to caller
9239 global $db, $langs, $user, $conf, $website, $websitepage;
9240 global $action, $mainmenu, $leftmenu;
9241 global $mysoc;
9242 global $objectoffield;
9243
9244 // Old variables used
9245 global $rights;
9246 global $object;
9247 global $obj; // To get $obj used into list when dol_eval is used for computed fields and $obj is not yet $object
9248 global $soc; // For backward compatibility
9249
9250 try {
9251 // Test on dangerous char (used for RCE), we allow only characters to make PHP variable testing
9252 if ($onlysimplestring == '1') {
9253 // We must accept: '1 && getDolGlobalInt("doesnotexist1") && $conf->global->MAIN_FEATURES_LEVEL'
9254 // We must accept: '$conf->barcode->enabled || preg_match(\'/^AAA/\',$leftmenu)'
9255 // We must accept: '$user->rights->cabinetmed->read && !$object->canvas=="patient@cabinetmed"'
9256 if (preg_match('/[^a-z0-9\s'.preg_quote('^$_+-.*>&|=!?():"\',/@', '/').']/i', $s)) {
9257 if ($returnvalue) {
9258 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9259 } else {
9260 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9261 return '';
9262 }
9263 // TODO
9264 // We can exclude all parenthesis ( that are not '($db' and 'getDolGlobalInt(' and 'getDolGlobalString(' and 'preg_match(' and 'isModEnabled('
9265 // ...
9266 }
9267 } elseif ($onlysimplestring == '2') {
9268 // 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"
9269 if (preg_match('/[^a-z0-9\s'.preg_quote('^$_+-.*>&|=!?():"\',/@[]', '/').']/i', $s)) {
9270 if ($returnvalue) {
9271 return 'Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s;
9272 } else {
9273 dol_syslog('Bad string syntax to evaluate (found chars that are not chars for simplestring): '.$s);
9274 return '';
9275 }
9276 // TODO
9277 // We can exclude all parenthesis ( that are not '($db' and 'getDolGlobalInt(' and 'getDolGlobalString(' and 'preg_match(' and 'isModEnabled('
9278 // ...
9279 }
9280 }
9281 if (is_array($s) || $s === 'Array') {
9282 return 'Bad string syntax to evaluate (value is Array) '.var_export($s, true);
9283 }
9284 if (strpos($s, '::') !== false) {
9285 if ($returnvalue) {
9286 return 'Bad string syntax to evaluate (double : char is forbidden): '.$s;
9287 } else {
9288 dol_syslog('Bad string syntax to evaluate (double : char is forbidden): '.$s);
9289 return '';
9290 }
9291 }
9292 if (strpos($s, '`') !== false) {
9293 if ($returnvalue) {
9294 return 'Bad string syntax to evaluate (backtick char is forbidden): '.$s;
9295 } else {
9296 dol_syslog('Bad string syntax to evaluate (backtick char is forbidden): '.$s);
9297 return '';
9298 }
9299 }
9300 if (preg_match('/[^0-9]+\.[^0-9]+/', $s)) { // We refuse . if not between 2 numbers
9301 if ($returnvalue) {
9302 return 'Bad string syntax to evaluate (dot char is forbidden): '.$s;
9303 } else {
9304 dol_syslog('Bad string syntax to evaluate (dot char is forbidden): '.$s);
9305 return '';
9306 }
9307 }
9308
9309 // We block use of php exec or php file functions
9310 $forbiddenphpstrings = array('$$');
9311 $forbiddenphpstrings = array_merge($forbiddenphpstrings, array('_ENV', '_SESSION', '_COOKIE', '_GET', '_POST', '_REQUEST', 'ReflectionFunction'));
9312
9313 $forbiddenphpfunctions = array("exec", "passthru", "shell_exec", "system", "proc_open", "popen");
9314 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("dol_eval", "executeCLI", "verifCond")); // native dolibarr functions
9315 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("base64_decode", "rawurldecode", "urldecode", "str_rot13", "hex2bin")); // decode string functions used to obfuscated function name
9316 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("fopen", "file_put_contents", "fputs", "fputscsv", "fwrite", "fpassthru", "require", "include", "mkdir", "rmdir", "symlink", "touch", "unlink", "umask"));
9317 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("get_defined_functions", "get_defined_vars", "get_defined_constants", "get_declared_classes"));
9318 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("function", "call_user_func"));
9319 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("require", "include", "require_once", "include_once"));
9320 $forbiddenphpfunctions = array_merge($forbiddenphpfunctions, array("eval", "create_function", "assert", "mb_ereg_replace")); // function with eval capabilities
9321
9322 $forbiddenphpmethods = array('invoke', 'invokeArgs'); // Method of ReflectionFunction to execute a function
9323
9324 $forbiddenphpregex = 'global\s+\$|\b('.implode('|', $forbiddenphpfunctions).')\b';
9325
9326 $forbiddenphpmethodsregex = '->('.implode('|', $forbiddenphpmethods).')';
9327
9328 do {
9329 $oldstringtoclean = $s;
9330 $s = str_ireplace($forbiddenphpstrings, '__forbiddenstring__', $s);
9331 $s = preg_replace('/'.$forbiddenphpregex.'/i', '__forbiddenstring__', $s);
9332 $s = preg_replace('/'.$forbiddenphpmethodsregex.'/i', '__forbiddenstring__', $s);
9333 //$s = preg_replace('/\$[a-zA-Z0-9_\->\$]+\‍(/i', '', $s); // Remove $function( call and $mycall->mymethod(
9334 } while ($oldstringtoclean != $s);
9335
9336 if (strpos($s, '__forbiddenstring__') !== false) {
9337 dol_syslog('Bad string syntax to evaluate: '.$s, LOG_WARNING);
9338 if ($returnvalue) {
9339 return 'Bad string syntax to evaluate: '.$s;
9340 } else {
9341 dol_syslog('Bad string syntax to evaluate: '.$s);
9342 return '';
9343 }
9344 }
9345
9346 //print $s."<br>\n";
9347 if ($returnvalue) {
9348 if ($hideerrors) {
9349 return @eval('return '.$s.';');
9350 } else {
9351 return eval('return '.$s.';');
9352 }
9353 } else {
9354 if ($hideerrors) {
9355 @eval($s);
9356 } else {
9357 eval($s);
9358 }
9359 }
9360 } catch (Error $e) {
9361 $error = 'dol_eval try/catch error : ';
9362 $error .= $e->getMessage();
9363 dol_syslog($error);
9364 }
9365}
9366
9373function dol_validElement($element)
9374{
9375 return (trim($element) != '');
9376}
9377
9386function picto_from_langcode($codelang, $moreatt = '', $notitlealt = 0)
9387{
9388 if (empty($codelang)) {
9389 return '';
9390 }
9391
9392 if ($codelang == 'auto') {
9393 return '<span class="fa fa-language"></span>';
9394 }
9395
9396 $langtocountryflag = array(
9397 'ar_AR' => '',
9398 'ca_ES' => 'catalonia',
9399 'da_DA' => 'dk',
9400 'fr_CA' => 'mq',
9401 'sv_SV' => 'se',
9402 'sw_SW' => 'unknown',
9403 'AQ' => 'unknown',
9404 'CW' => 'unknown',
9405 'IM' => 'unknown',
9406 'JE' => 'unknown',
9407 'MF' => 'unknown',
9408 'BL' => 'unknown',
9409 'SX' => 'unknown'
9410 );
9411
9412 if (isset($langtocountryflag[$codelang])) {
9413 $flagImage = $langtocountryflag[$codelang];
9414 } else {
9415 $tmparray = explode('_', $codelang);
9416 $flagImage = empty($tmparray[1]) ? $tmparray[0] : $tmparray[1];
9417 }
9418
9419 return img_picto_common($codelang, 'flags/'.strtolower($flagImage).'.png', $moreatt, 0, $notitlealt);
9420}
9421
9430{
9431 global $mysoc;
9432
9433 if (empty($countrycode)) {
9434 return null;
9435 }
9436
9437 if (strtoupper($countrycode) == 'MQ') {
9438 return 'fr_CA';
9439 }
9440 if (strtoupper($countrycode) == 'SE') {
9441 return 'sv_SE'; // se_SE is Sami/Sweden, and we want in priority sv_SE for SE country
9442 }
9443 if (strtoupper($countrycode) == 'CH') {
9444 if ($mysoc->country_code == 'FR') {
9445 return 'fr_CH';
9446 }
9447 if ($mysoc->country_code == 'DE') {
9448 return 'de_CH';
9449 }
9450 if ($mysoc->country_code == 'IT') {
9451 return 'it_CH';
9452 }
9453 }
9454
9455 // Locale list taken from:
9456 // http://stackoverflow.com/questions/3191664/
9457 // list-of-all-locales-and-their-short-codes
9458 $locales = array(
9459 'af-ZA',
9460 'am-ET',
9461 'ar-AE',
9462 'ar-BH',
9463 'ar-DZ',
9464 'ar-EG',
9465 'ar-IQ',
9466 'ar-JO',
9467 'ar-KW',
9468 'ar-LB',
9469 'ar-LY',
9470 'ar-MA',
9471 'ar-OM',
9472 'ar-QA',
9473 'ar-SA',
9474 'ar-SY',
9475 'ar-TN',
9476 'ar-YE',
9477 //'as-IN', // Moved after en-IN
9478 'ba-RU',
9479 'be-BY',
9480 'bg-BG',
9481 'bn-BD',
9482 //'bn-IN', // Moved after en-IN
9483 'bo-CN',
9484 'br-FR',
9485 'ca-ES',
9486 'co-FR',
9487 'cs-CZ',
9488 'cy-GB',
9489 'da-DK',
9490 'de-AT',
9491 'de-CH',
9492 'de-DE',
9493 'de-LI',
9494 'de-LU',
9495 'dv-MV',
9496 'el-GR',
9497 'en-AU',
9498 'en-BZ',
9499 'en-CA',
9500 'en-GB',
9501 'en-IE',
9502 'en-IN',
9503 'as-IN', // as-IN must be after en-IN (en in priority if country is IN)
9504 'bn-IN', // bn-IN must be after en-IN (en in priority if country is IN)
9505 'en-JM',
9506 'en-MY',
9507 'en-NZ',
9508 'en-PH',
9509 'en-SG',
9510 'en-TT',
9511 'en-US',
9512 'en-ZA',
9513 'en-ZW',
9514 'es-AR',
9515 'es-BO',
9516 'es-CL',
9517 'es-CO',
9518 'es-CR',
9519 'es-DO',
9520 'es-EC',
9521 'es-ES',
9522 'es-GT',
9523 'es-HN',
9524 'es-MX',
9525 'es-NI',
9526 'es-PA',
9527 'es-PE',
9528 'es-PR',
9529 'es-PY',
9530 'es-SV',
9531 'es-US',
9532 'es-UY',
9533 'es-VE',
9534 'et-EE',
9535 'eu-ES',
9536 'fa-IR',
9537 'fi-FI',
9538 'fo-FO',
9539 'fr-BE',
9540 'fr-CA',
9541 'fr-CH',
9542 'fr-FR',
9543 'fr-LU',
9544 'fr-MC',
9545 'fy-NL',
9546 'ga-IE',
9547 'gd-GB',
9548 'gl-ES',
9549 'gu-IN',
9550 'he-IL',
9551 'hi-IN',
9552 'hr-BA',
9553 'hr-HR',
9554 'hu-HU',
9555 'hy-AM',
9556 'id-ID',
9557 'ig-NG',
9558 'ii-CN',
9559 'is-IS',
9560 'it-CH',
9561 'it-IT',
9562 'ja-JP',
9563 'ka-GE',
9564 'kk-KZ',
9565 'kl-GL',
9566 'km-KH',
9567 'kn-IN',
9568 'ko-KR',
9569 'ky-KG',
9570 'lb-LU',
9571 'lo-LA',
9572 'lt-LT',
9573 'lv-LV',
9574 'mi-NZ',
9575 'mk-MK',
9576 'ml-IN',
9577 'mn-MN',
9578 'mr-IN',
9579 'ms-BN',
9580 'ms-MY',
9581 'mt-MT',
9582 'nb-NO',
9583 'ne-NP',
9584 'nl-BE',
9585 'nl-NL',
9586 'nn-NO',
9587 'oc-FR',
9588 'or-IN',
9589 'pa-IN',
9590 'pl-PL',
9591 'ps-AF',
9592 'pt-BR',
9593 'pt-PT',
9594 'rm-CH',
9595 'ro-MD',
9596 'ro-RO',
9597 'ru-RU',
9598 'rw-RW',
9599 'sa-IN',
9600 'se-FI',
9601 'se-NO',
9602 'se-SE',
9603 'si-LK',
9604 'sk-SK',
9605 'sl-SI',
9606 'sq-AL',
9607 'sv-FI',
9608 'sv-SE',
9609 'sw-KE',
9610 'ta-IN',
9611 'te-IN',
9612 'th-TH',
9613 'tk-TM',
9614 'tn-ZA',
9615 'tr-TR',
9616 'tt-RU',
9617 'ug-CN',
9618 'uk-UA',
9619 'ur-PK',
9620 'vi-VN',
9621 'wo-SN',
9622 'xh-ZA',
9623 'yo-NG',
9624 'zh-CN',
9625 'zh-HK',
9626 'zh-MO',
9627 'zh-SG',
9628 'zh-TW',
9629 'zu-ZA',
9630 );
9631
9632 $buildprimarykeytotest = strtolower($countrycode).'-'.strtoupper($countrycode);
9633 if (in_array($buildprimarykeytotest, $locales)) {
9634 return strtolower($countrycode).'_'.strtoupper($countrycode);
9635 }
9636
9637 if (function_exists('locale_get_primary_language') && function_exists('locale_get_region')) { // Need extension php-intl
9638 foreach ($locales as $locale) {
9639 $locale_language = locale_get_primary_language($locale);
9640 $locale_region = locale_get_region($locale);
9641 if (strtoupper($countrycode) == $locale_region) {
9642 //var_dump($locale.' - '.$locale_language.' - '.$locale_region);
9643 return strtolower($locale_language).'_'.strtoupper($locale_region);
9644 }
9645 }
9646 } else {
9647 dol_syslog("Warning Exention php-intl is not available", LOG_WARNING);
9648 }
9649
9650 return null;
9651}
9652
9683function complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode = 'add', $filterorigmodule = '')
9684{
9685 global $hookmanager, $db;
9686
9687 if (isset($conf->modules_parts['tabs'][$type]) && is_array($conf->modules_parts['tabs'][$type])) {
9688 foreach ($conf->modules_parts['tabs'][$type] as $value) {
9689 $values = explode(':', $value);
9690
9691 $reg = array();
9692 if ($mode == 'add' && !preg_match('/^\-/', $values[1])) {
9693 if (count($values) == 6) {
9694 // new declaration with permissions:
9695 // $value='objecttype:+tabname1:Title1:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
9696 // $value='objecttype:+tabname1:Title1,class,pathfile,method:langfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__'
9697 if ($values[0] != $type) {
9698 continue;
9699 }
9700
9701 if (verifCond($values[4])) {
9702 if ($values[3]) {
9703 if ($filterorigmodule) { // If a filter of module origin has been requested
9704 if (strpos($values[3], '@')) { // This is an external module
9705 if ($filterorigmodule != 'external') {
9706 continue;
9707 }
9708 } else { // This looks a core module
9709 if ($filterorigmodule != 'core') {
9710 continue;
9711 }
9712 }
9713 }
9714 $langs->load($values[3]);
9715 }
9716 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
9717 // If label is "SUBSTITUION_..."
9718 $substitutionarray = array();
9719 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
9720 $label = make_substitutions($reg[1], $substitutionarray);
9721 } else {
9722 // If label is "Label,Class,File,Method", we call the method to show content inside the badge
9723 $labeltemp = explode(',', $values[2]);
9724 $label = $langs->trans($labeltemp[0]);
9725
9726 if (!empty($labeltemp[1]) && is_object($object) && !empty($object->id)) {
9727 dol_include_once($labeltemp[2]);
9728 $classtoload = $labeltemp[1];
9729 if (class_exists($classtoload)) {
9730 $obj = new $classtoload($db);
9731 $function = $labeltemp[3];
9732 if ($obj && $function && method_exists($obj, $function)) {
9733 $nbrec = $obj->$function($object->id, $obj);
9734 if (!empty($nbrec)) {
9735 $label .= '<span class="badge marginleftonlyshort">'.$nbrec.'</span>';
9736 }
9737 }
9738 }
9739 }
9740 }
9741
9742 $head[$h][0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[5]), 1);
9743 $head[$h][1] = $label;
9744 $head[$h][2] = str_replace('+', '', $values[1]);
9745 $h++;
9746 }
9747 } elseif (count($values) == 5) { // case deprecated
9748 dol_syslog('Passing 5 values in tabs module_parts is deprecated. Please update to 6 with permissions.', LOG_WARNING);
9749
9750 if ($values[0] != $type) {
9751 continue;
9752 }
9753 if ($values[3]) {
9754 if ($filterorigmodule) { // If a filter of module origin has been requested
9755 if (strpos($values[3], '@')) { // This is an external module
9756 if ($filterorigmodule != 'external') {
9757 continue;
9758 }
9759 } else { // This looks a core module
9760 if ($filterorigmodule != 'core') {
9761 continue;
9762 }
9763 }
9764 }
9765 $langs->load($values[3]);
9766 }
9767 if (preg_match('/SUBSTITUTION_([^_]+)/i', $values[2], $reg)) {
9768 $substitutionarray = array();
9769 complete_substitutions_array($substitutionarray, $langs, $object, array('needforkey'=>$values[2]));
9770 $label = make_substitutions($reg[1], $substitutionarray);
9771 } else {
9772 $label = $langs->trans($values[2]);
9773 }
9774
9775 $head[$h][0] = dol_buildpath(preg_replace('/__ID__/i', ((is_object($object) && !empty($object->id)) ? $object->id : ''), $values[4]), 1);
9776 $head[$h][1] = $label;
9777 $head[$h][2] = str_replace('+', '', $values[1]);
9778 $h++;
9779 }
9780 } elseif ($mode == 'remove' && preg_match('/^\-/', $values[1])) {
9781 if ($values[0] != $type) {
9782 continue;
9783 }
9784 $tabname = str_replace('-', '', $values[1]);
9785 foreach ($head as $key => $val) {
9786 $condition = (!empty($values[3]) ? verifCond($values[3]) : 1);
9787 //var_dump($key.' - '.$tabname.' - '.$head[$key][2].' - '.$values[3].' - '.$condition);
9788 if ($head[$key][2] == $tabname && $condition) {
9789 unset($head[$key]);
9790 break;
9791 }
9792 }
9793 }
9794 }
9795 }
9796
9797 // No need to make a return $head. Var is modified as a reference
9798 if (!empty($hookmanager)) {
9799 $parameters = array('object' => $object, 'mode' => $mode, 'head' => &$head, 'filterorigmodule' => $filterorigmodule);
9800 $reshook = $hookmanager->executeHooks('completeTabsHead', $parameters);
9801 if ($reshook > 0) { // Hook ask to replace completely the array
9802 $head = $hookmanager->resArray;
9803 } else { // Hook
9804 $head = array_merge($head, $hookmanager->resArray);
9805 }
9806 $h = count($head);
9807 }
9808}
9809
9821function printCommonFooter($zone = 'private')
9822{
9823 global $conf, $hookmanager, $user, $debugbar;
9824 global $action;
9825 global $micro_start_time;
9826
9827 if ($zone == 'private') {
9828 print "\n".'<!-- Common footer for private page -->'."\n";
9829 } else {
9830 print "\n".'<!-- Common footer for public page -->'."\n";
9831 }
9832
9833 // A div to store page_y POST parameter so we can read it using javascript
9834 print "\n<!-- A div to store page_y POST parameter -->\n";
9835 print '<div id="page_y" style="display: none;">'.(GETPOST('page_y') ? GETPOST('page_y') : '').'</div>'."\n";
9836
9837 $parameters = array();
9838 $reshook = $hookmanager->executeHooks('printCommonFooter', $parameters); // Note that $action and $object may have been modified by some hooks
9839 if (empty($reshook)) {
9840 if (!empty($conf->global->MAIN_HTML_FOOTER)) {
9841 print $conf->global->MAIN_HTML_FOOTER."\n";
9842 }
9843
9844 print "\n";
9845 if (!empty($conf->use_javascript_ajax)) {
9846 print "\n<!-- A script section to add menuhider handler on backoffice, manage focus and madatory fields, tuning info, ... -->\n";
9847 print '<script>'."\n";
9848 print 'jQuery(document).ready(function() {'."\n";
9849
9850 if ($zone == 'private' && empty($conf->dol_use_jmobile)) {
9851 print "\n";
9852 print '/* JS CODE TO ENABLE to manage handler to switch left menu page (menuhider) */'."\n";
9853 print 'jQuery("li.menuhider").click(function(event) {';
9854 print ' if (!$( "body" ).hasClass( "sidebar-collapse" )){ event.preventDefault(); }'."\n";
9855 print ' console.log("We click on .menuhider");'."\n";
9856 print ' $("body").toggleClass("sidebar-collapse")'."\n";
9857 print '});'."\n";
9858 }
9859
9860 // Management of focus and mandatory for fields
9861 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"])))) {
9862 print '/* JS CODE TO ENABLE to manage focus and mandatory form fields */'."\n";
9863 $relativepathstring = $_SERVER["PHP_SELF"];
9864 // Clean $relativepathstring
9865 if (constant('DOL_URL_ROOT')) {
9866 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
9867 }
9868 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
9869 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
9870 //$tmpqueryarraywehave = explode('&', dol_string_nohtmltag($_SERVER['QUERY_STRING']));
9871 if (!empty($user->default_values[$relativepathstring]['focus'])) {
9872 foreach ($user->default_values[$relativepathstring]['focus'] as $defkey => $defval) {
9873 $qualified = 0;
9874 if ($defkey != '_noquery_') {
9875 $tmpqueryarraytohave = explode('&', $defkey);
9876 $foundintru = 0;
9877 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
9878 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
9879 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
9880 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
9881 $foundintru = 1;
9882 }
9883 }
9884 if (!$foundintru) {
9885 $qualified = 1;
9886 }
9887 //var_dump($defkey.'-'.$qualified);
9888 } else {
9889 $qualified = 1;
9890 }
9891
9892 if ($qualified) {
9893 foreach ($defval as $paramkey => $paramval) {
9894 // Set focus on field
9895 print 'jQuery("input[name=\''.$paramkey.'\']").focus();'."\n";
9896 print 'jQuery("textarea[name=\''.$paramkey.'\']").focus();'."\n";
9897 print 'jQuery("select[name=\''.$paramkey.'\']").focus();'."\n"; // Not really usefull, but we keep it in case of.
9898 }
9899 }
9900 }
9901 }
9902 if (!empty($user->default_values[$relativepathstring]['mandatory'])) {
9903 foreach ($user->default_values[$relativepathstring]['mandatory'] as $defkey => $defval) {
9904 $qualified = 0;
9905 if ($defkey != '_noquery_') {
9906 $tmpqueryarraytohave = explode('&', $defkey);
9907 $foundintru = 0;
9908 foreach ($tmpqueryarraytohave as $tmpquerytohave) {
9909 $tmpquerytohaveparam = explode('=', $tmpquerytohave);
9910 //print "console.log('".$tmpquerytohaveparam[0]." ".$tmpquerytohaveparam[1]." ".GETPOST($tmpquerytohaveparam[0])."');";
9911 if (!GETPOSTISSET($tmpquerytohaveparam[0]) || ($tmpquerytohaveparam[1] != GETPOST($tmpquerytohaveparam[0]))) {
9912 $foundintru = 1;
9913 }
9914 }
9915 if (!$foundintru) {
9916 $qualified = 1;
9917 }
9918 //var_dump($defkey.'-'.$qualified);
9919 } else {
9920 $qualified = 1;
9921 }
9922
9923 if ($qualified) {
9924 foreach ($defval as $paramkey => $paramval) {
9925 // Add property 'required' on input
9926 print 'jQuery("input[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
9927 print 'jQuery("textarea[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
9928 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";
9929 print 'jQuery("select[name=\''.$paramkey.'\']").prop(\'required\',true);'."\n";
9930 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'-1\']").prop(\'value\', \'\');'."\n";
9931 print 'jQuery("select[name=\''.$paramkey.'\'] option[value=\'0\']").prop(\'value\', \'\');'."\n";
9932
9933 // Add 'field required' class on closest td for all input elements : input, textarea and select
9934 print 'jQuery(":input[name=\'' . $paramkey . '\']").closest("tr").find("td:first").addClass("fieldrequired");' . "\n";
9935 }
9936 }
9937 }
9938 }
9939 }
9940
9941 print '});'."\n";
9942
9943 // End of tuning
9944 if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO']) || !empty($conf->global->MAIN_SHOW_TUNING_INFO)) {
9945 print "\n";
9946 print "/* JS CODE TO ENABLE to add memory info */\n";
9947 print 'window.console && console.log("';
9948 if (!empty($conf->global->MEMCACHED_SERVER)) {
9949 print 'MEMCACHED_SERVER='.$conf->global->MEMCACHED_SERVER.' - ';
9950 }
9951 print 'MAIN_OPTIMIZE_SPEED='.(isset($conf->global->MAIN_OPTIMIZE_SPEED) ? $conf->global->MAIN_OPTIMIZE_SPEED : 'off');
9952 if (!empty($micro_start_time)) { // Works only if MAIN_SHOW_TUNING_INFO is defined at $_SERVER level. Not in global variable.
9953 $micro_end_time = microtime(true);
9954 print ' - Build time: '.ceil(1000 * ($micro_end_time - $micro_start_time)).' ms';
9955 }
9956
9957 if (function_exists("memory_get_usage")) {
9958 print ' - Mem: '.memory_get_usage(); // Do not use true here, it seems it takes the peak amount
9959 }
9960 if (function_exists("memory_get_peak_usage")) {
9961 print ' - Real mem peak: '.memory_get_peak_usage(true);
9962 }
9963 if (function_exists("zend_loader_file_encoded")) {
9964 print ' - Zend encoded file: '.(zend_loader_file_encoded() ? 'yes' : 'no');
9965 }
9966 print '");'."\n";
9967 }
9968
9969 print "\n".'</script>'."\n";
9970
9971 // Google Analytics
9972 // TODO Add a hook here
9973 if (isModEnabled('google') && !empty($conf->global->MAIN_GOOGLE_AN_ID)) {
9974 $tmptagarray = explode(',', $conf->global->MAIN_GOOGLE_AN_ID);
9975 foreach ($tmptagarray as $tmptag) {
9976 print "\n";
9977 print "<!-- JS CODE TO ENABLE for google analtics tag -->\n";
9978 print '
9979 <!-- Global site tag (gtag.js) - Google Analytics -->
9980 <script nonce="'.getNonce().'" async src="https://www.googletagmanager.com/gtag/js?id='.trim($tmptag).'"></script>
9981 <script>
9982 window.dataLayer = window.dataLayer || [];
9983 function gtag(){dataLayer.push(arguments);}
9984 gtag(\'js\', new Date());
9985
9986 gtag(\'config\', \''.trim($tmptag).'\');
9987 </script>';
9988 print "\n";
9989 }
9990 }
9991 }
9992
9993 // Add Xdebug coverage of code
9994 if (defined('XDEBUGCOVERAGE')) {
9995 print_r(xdebug_get_code_coverage());
9996 }
9997
9998 // Add DebugBar data
9999 if (!empty($user->rights->debugbar->read) && is_object($debugbar)) {
10000 $debugbar['time']->stopMeasure('pageaftermaster');
10001 print '<!-- Output debugbar data -->'."\n";
10002 $renderer = $debugbar->getRenderer();
10003 print $debugbar->getRenderer()->render();
10004 } elseif (count($conf->logbuffer)) { // If there is some logs in buffer to show
10005 print "\n";
10006 print "<!-- Start of log output\n";
10007 //print '<div class="hidden">'."\n";
10008 foreach ($conf->logbuffer as $logline) {
10009 print $logline."<br>\n";
10010 }
10011 //print '</div>'."\n";
10012 print "End of log output -->\n";
10013 }
10014 }
10015}
10016
10026function dolExplodeIntoArray($string, $delimiter = ';', $kv = '=')
10027{
10028 if (is_null($string)) {
10029 return array();
10030 }
10031
10032 if (preg_match('/^\[.*\]$/sm', $delimiter) || preg_match('/^\‍(.*\‍)$/sm', $delimiter)) {
10033 // This is a regex string
10034 $newdelimiter = $delimiter;
10035 } else {
10036 // This is a simple string
10037 $newdelimiter = preg_quote($delimiter, '/');
10038 }
10039
10040 if ($a = preg_split('/'.$newdelimiter.'/', $string)) {
10041 $ka = array();
10042 foreach ($a as $s) { // each part
10043 if ($s) {
10044 if ($pos = strpos($s, $kv)) { // key/value delimiter
10045 $ka[trim(substr($s, 0, $pos))] = trim(substr($s, $pos + strlen($kv)));
10046 } else { // key delimiter not found
10047 $ka[] = trim($s);
10048 }
10049 }
10050 }
10051 return $ka;
10052 }
10053
10054 return array();
10055}
10056
10057
10064function dol_set_focus($selector)
10065{
10066 print "\n".'<!-- Set focus onto a specific field -->'."\n";
10067 print '<script nonce="'.getNonce().'">jQuery(document).ready(function() { jQuery("'.dol_escape_js($selector).'").focus(); });</script>'."\n";
10068}
10069
10070
10078function dol_getmypid()
10079{
10080 if (!function_exists('getmypid')) {
10081 return mt_rand(99900000, 99965535);
10082 } else {
10083 return getmypid(); // May be a number on 64 bits (depending on OS)
10084 }
10085}
10086
10087
10105function natural_search($fields, $value, $mode = 0, $nofirstand = 0)
10106{
10107 global $db, $langs;
10108
10109 $value = trim($value);
10110
10111 if ($mode == 0) {
10112 $value = preg_replace('/\*/', '%', $value); // Replace * with %
10113 }
10114 if ($mode == 1) {
10115 $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
10116 }
10117
10118 $value = preg_replace('/\s*\|\s*/', '|', $value);
10119
10120 $crits = explode(' ', $value);
10121 $res = '';
10122 if (!is_array($fields)) {
10123 $fields = array($fields);
10124 }
10125
10126 $i1 = 0; // count the nb of and criteria added (all fields / criterias)
10127 foreach ($crits as $crit) { // Loop on each AND criteria
10128 $crit = trim($crit);
10129 $i2 = 0; // count the nb of valid criteria added for this this first criteria
10130 $newres = '';
10131 foreach ($fields as $field) {
10132 if ($mode == 1) {
10133 $tmpcrits = explode('|', $crit);
10134 $i3 = 0; // count the nb of valid criteria added for this current field
10135 foreach ($tmpcrits as $tmpcrit) {
10136 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10137 continue;
10138 }
10139 $tmpcrit = trim($tmpcrit);
10140
10141 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10142
10143 $operator = '=';
10144 $newcrit = preg_replace('/([!<>=]+)/', '', $tmpcrit);
10145
10146 $reg = array();
10147 preg_match('/([!<>=]+)/', $tmpcrit, $reg);
10148 if (!empty($reg[1])) {
10149 $operator = $reg[1];
10150 }
10151 if ($newcrit != '') {
10152 $numnewcrit = price2num($newcrit);
10153 if (is_numeric($numnewcrit)) {
10154 $newres .= $field.' '.$operator.' '.((float) $numnewcrit); // should be a numeric
10155 } else {
10156 $newres .= '1 = 2'; // force false, we received a corrupted data
10157 }
10158 $i3++; // a criteria was added to string
10159 }
10160 }
10161 $i2++; // a criteria for 1 more field was added to string
10162 } elseif ($mode == 2 || $mode == -2) {
10163 $crit = preg_replace('/[^0-9,]/', '', $crit); // ID are always integer
10164 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -2 ? 'NOT ' : '');
10165 $newres .= $crit ? "IN (".$db->sanitize($db->escape($crit)).")" : "IN (0)";
10166 if ($mode == -2) {
10167 $newres .= ' OR '.$field.' IS NULL';
10168 }
10169 $i2++; // a criteria for 1 more field was added to string
10170 } elseif ($mode == 3 || $mode == -3) {
10171 $tmparray = explode(',', $crit);
10172 if (count($tmparray)) {
10173 $listofcodes = '';
10174 foreach ($tmparray as $val) {
10175 $val = trim($val);
10176 if ($val) {
10177 $listofcodes .= ($listofcodes ? ',' : '');
10178 $listofcodes .= "'".$db->escape($val)."'";
10179 }
10180 }
10181 $newres .= ($i2 > 0 ? ' OR ' : '').$field." ".($mode == -3 ? 'NOT ' : '')."IN (".$db->sanitize($listofcodes, 1).")";
10182 $i2++; // a criteria for 1 more field was added to string
10183 }
10184 if ($mode == -3) {
10185 $newres .= ' OR '.$field.' IS NULL';
10186 }
10187 } elseif ($mode == 4) {
10188 $tmparray = explode(',', $crit);
10189 if (count($tmparray)) {
10190 $listofcodes = '';
10191 foreach ($tmparray as $val) {
10192 $val = trim($val);
10193 if ($val) {
10194 $newres .= ($i2 > 0 ? " OR (" : "(").$field." LIKE '".$db->escape($val).",%'";
10195 $newres .= ' OR '.$field." = '".$db->escape($val)."'";
10196 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val)."'";
10197 $newres .= ' OR '.$field." LIKE '%,".$db->escape($val).",%'";
10198 $newres .= ')';
10199 $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)
10200 }
10201 }
10202 }
10203 } else { // $mode=0
10204 $tmpcrits = explode('|', $crit);
10205 $i3 = 0; // count the nb of valid criteria added for the current couple criteria/field
10206 foreach ($tmpcrits as $tmpcrit) { // loop on each OR criteria
10207 if ($tmpcrit !== '0' && empty($tmpcrit)) {
10208 continue;
10209 }
10210 $tmpcrit = trim($tmpcrit);
10211
10212 if ($tmpcrit == '^$' || strpos($crit, '!') === 0) { // If we search empty, we must combined different OR fields with AND
10213 $newres .= (($i2 > 0 || $i3 > 0) ? ' AND ' : '');
10214 } else {
10215 $newres .= (($i2 > 0 || $i3 > 0) ? ' OR ' : '');
10216 }
10217
10218 if (preg_match('/\.(id|rowid)$/', $field)) { // Special case for rowid that is sometimes a ref so used as a search field
10219 $newres .= $field." = ".(is_numeric($tmpcrit) ? ((float) $tmpcrit) : '0');
10220 } else {
10221 $tmpcrit2 = $tmpcrit;
10222 $tmpbefore = '%';
10223 $tmpafter = '%';
10224 $tmps = '';
10225
10226 if (preg_match('/^!/', $tmpcrit)) {
10227 $tmps .= $field." NOT LIKE "; // ! as exclude character
10228 $tmpcrit2 = preg_replace('/^!/', '', $tmpcrit2);
10229 } else {
10230 $tmps .= $field." LIKE ";
10231 }
10232 $tmps .= "'";
10233
10234 if (preg_match('/^[\^\$]/', $tmpcrit)) {
10235 $tmpbefore = '';
10236 $tmpcrit2 = preg_replace('/^[\^\$]/', '', $tmpcrit2);
10237 }
10238 if (preg_match('/[\^\$]$/', $tmpcrit)) {
10239 $tmpafter = '';
10240 $tmpcrit2 = preg_replace('/[\^\$]$/', '', $tmpcrit2);
10241 }
10242
10243 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10244 $tmps = "(".$tmps;
10245 }
10246 $newres .= $tmps;
10247 $newres .= $tmpbefore;
10248 $newres .= $db->escape($tmpcrit2);
10249 $newres .= $tmpafter;
10250 $newres .= "'";
10251 if ($tmpcrit2 == '' || preg_match('/^!/', $tmpcrit)) {
10252 $newres .= " OR ".$field." IS NULL)";
10253 }
10254 }
10255
10256 $i3++;
10257 }
10258
10259 $i2++; // a criteria for 1 more field was added to string
10260 }
10261 }
10262
10263 if ($newres) {
10264 $res = $res.($res ? ' AND ' : '').($i2 > 1 ? '(' : '').$newres.($i2 > 1 ? ')' : '');
10265 }
10266 $i1++;
10267 }
10268 $res = ($nofirstand ? "" : " AND ")."(".$res.")";
10269
10270 return $res;
10271}
10272
10279function showDirectDownloadLink($object)
10280{
10281 global $conf, $langs;
10282
10283 $out = '';
10284 $url = $object->getLastMainDocLink($object->element);
10285
10286 $out .= img_picto($langs->trans("PublicDownloadLinkDesc"), 'globe').' <span class="opacitymedium">'.$langs->trans("DirectDownloadLink").'</span><br>';
10287 if ($url) {
10288 $out .= '<div class="urllink"><input type="text" id="directdownloadlink" class="quatrevingtpercent" value="'.$url.'"></div>';
10289 $out .= ajax_autoselect("directdownloadlink", 0);
10290 } else {
10291 $out .= '<div class="urllink">'.$langs->trans("FileNotShared").'</div>';
10292 }
10293
10294 return $out;
10295}
10296
10305function getImageFileNameForSize($file, $extName, $extImgTarget = '')
10306{
10307 $dirName = dirname($file);
10308 if ($dirName == '.') {
10309 $dirName = '';
10310 }
10311
10312 $fileName = preg_replace('/(\.gif|\.jpeg|\.jpg|\.png|\.bmp|\.webp)$/i', '', $file); // We remove extension, whatever is its case
10313 $fileName = basename($fileName);
10314
10315 if (empty($extImgTarget)) {
10316 $extImgTarget = (preg_match('/\.jpg$/i', $file) ? '.jpg' : '');
10317 }
10318 if (empty($extImgTarget)) {
10319 $extImgTarget = (preg_match('/\.jpeg$/i', $file) ? '.jpeg' : '');
10320 }
10321 if (empty($extImgTarget)) {
10322 $extImgTarget = (preg_match('/\.gif$/i', $file) ? '.gif' : '');
10323 }
10324 if (empty($extImgTarget)) {
10325 $extImgTarget = (preg_match('/\.png$/i', $file) ? '.png' : '');
10326 }
10327 if (empty($extImgTarget)) {
10328 $extImgTarget = (preg_match('/\.bmp$/i', $file) ? '.bmp' : '');
10329 }
10330 if (empty($extImgTarget)) {
10331 $extImgTarget = (preg_match('/\.webp$/i', $file) ? '.webp' : '');
10332 }
10333
10334 if (!$extImgTarget) {
10335 return $file;
10336 }
10337
10338 $subdir = '';
10339 if ($extName) {
10340 $subdir = 'thumbs/';
10341 }
10342
10343 return ($dirName ? $dirName.'/' : '').$subdir.$fileName.$extName.$extImgTarget; // New filename for thumb
10344}
10345
10346
10356function getAdvancedPreviewUrl($modulepart, $relativepath, $alldata = 0, $param = '')
10357{
10358 global $conf, $langs;
10359
10360 if (empty($conf->use_javascript_ajax)) {
10361 return '';
10362 }
10363
10364 $isAllowedForPreview = dolIsAllowedForPreview($relativepath);
10365
10366 if ($alldata == 1) {
10367 if ($isAllowedForPreview) {
10368 return array('target'=>'_blank', 'css'=>'documentpreview', 'url'=>DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : ''), 'mime'=>dol_mimetype($relativepath));
10369 } else {
10370 return array();
10371 }
10372 }
10373
10374 // old behavior, return a string
10375 if ($isAllowedForPreview) {
10376 $tmpurl = DOL_URL_ROOT.'/document.php?modulepart='.urlencode($modulepart).'&attachment=0&file='.urlencode($relativepath).($param ? '&'.$param : '');
10377 $title = $langs->transnoentities("Preview");
10378 //$title = '%27-alert(document.domain)-%27';
10379 //$tmpurl = 'file='.urlencode("'-alert(document.domain)-'_small.jpg");
10380
10381 // We need to urlencode the parameter after the dol_escape_js($tmpurl) because $tmpurl may contain n url with param file=abc%27def if file has a ' inside.
10382 // and when we click on href with this javascript string, a urlcode is done by browser, converted the %27 of file param
10383 return 'javascript:document_preview(\''.urlencode(dol_escape_js($tmpurl)).'\', \''.urlencode(dol_mimetype($relativepath)).'\', \''.rawurlencode(dol_escape_js($title)).'\')';
10384 } else {
10385 return '';
10386 }
10387}
10388
10389
10398function ajax_autoselect($htmlname, $addlink = '', $textonlink = 'Link')
10399{
10400 global $langs;
10401 $out = '<script nonce="'.getNonce().'">
10402 jQuery(document).ready(function () {
10403 jQuery("'.((strpos($htmlname, '.') === 0 ? '' : '#').$htmlname).'").click(function() { jQuery(this).select(); } );
10404 });
10405 </script>';
10406 if ($addlink) {
10407 if ($textonlink === 'image') {
10408 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.img_picto('', 'globe').'</a>';
10409 } else {
10410 $out .= ' <a href="'.$addlink.'" target="_blank" rel="noopener noreferrer">'.$langs->trans("Link").'</a>';
10411 }
10412 }
10413 return $out;
10414}
10415
10423function dolIsAllowedForPreview($file)
10424{
10425 global $conf;
10426
10427 // Check .noexe extension in filename
10428 if (preg_match('/\.noexe$/i', $file)) {
10429 return 0;
10430 }
10431
10432 // Check mime types
10433 $mime_preview = array('bmp', 'jpeg', 'png', 'gif', 'tiff', 'pdf', 'plain', 'css', 'webp');
10434 if (!empty($conf->global->MAIN_ALLOW_SVG_FILES_AS_IMAGES)) {
10435 $mime_preview[] = 'svg+xml';
10436 }
10437 //$mime_preview[]='vnd.oasis.opendocument.presentation';
10438 //$mime_preview[]='archive';
10439 $num_mime = array_search(dol_mimetype($file, '', 1), $mime_preview);
10440 if ($num_mime !== false) {
10441 return 1;
10442 }
10443
10444 // By default, not allowed for preview
10445 return 0;
10446}
10447
10448
10458function dol_mimetype($file, $default = 'application/octet-stream', $mode = 0)
10459{
10460 $mime = $default;
10461 $imgmime = 'other.png';
10462 $famime = 'file-o';
10463 $srclang = '';
10464
10465 $tmpfile = preg_replace('/\.noexe$/', '', $file);
10466
10467 // Plain text files
10468 if (preg_match('/\.txt$/i', $tmpfile)) {
10469 $mime = 'text/plain';
10470 $imgmime = 'text.png';
10471 $famime = 'file-text-o';
10472 }
10473 if (preg_match('/\.rtx$/i', $tmpfile)) {
10474 $mime = 'text/richtext';
10475 $imgmime = 'text.png';
10476 $famime = 'file-text-o';
10477 }
10478 if (preg_match('/\.csv$/i', $tmpfile)) {
10479 $mime = 'text/csv';
10480 $imgmime = 'text.png';
10481 $famime = 'file-text-o';
10482 }
10483 if (preg_match('/\.tsv$/i', $tmpfile)) {
10484 $mime = 'text/tab-separated-values';
10485 $imgmime = 'text.png';
10486 $famime = 'file-text-o';
10487 }
10488 if (preg_match('/\.(cf|conf|log)$/i', $tmpfile)) {
10489 $mime = 'text/plain';
10490 $imgmime = 'text.png';
10491 $famime = 'file-text-o';
10492 }
10493 if (preg_match('/\.ini$/i', $tmpfile)) {
10494 $mime = 'text/plain';
10495 $imgmime = 'text.png';
10496 $srclang = 'ini';
10497 $famime = 'file-text-o';
10498 }
10499 if (preg_match('/\.md$/i', $tmpfile)) {
10500 $mime = 'text/plain';
10501 $imgmime = 'text.png';
10502 $srclang = 'md';
10503 $famime = 'file-text-o';
10504 }
10505 if (preg_match('/\.css$/i', $tmpfile)) {
10506 $mime = 'text/css';
10507 $imgmime = 'css.png';
10508 $srclang = 'css';
10509 $famime = 'file-text-o';
10510 }
10511 if (preg_match('/\.lang$/i', $tmpfile)) {
10512 $mime = 'text/plain';
10513 $imgmime = 'text.png';
10514 $srclang = 'lang';
10515 $famime = 'file-text-o';
10516 }
10517 // Certificate files
10518 if (preg_match('/\.(crt|cer|key|pub)$/i', $tmpfile)) {
10519 $mime = 'text/plain';
10520 $imgmime = 'text.png';
10521 $famime = 'file-text-o';
10522 }
10523 // XML based (HTML/XML/XAML)
10524 if (preg_match('/\.(html|htm|shtml)$/i', $tmpfile)) {
10525 $mime = 'text/html';
10526 $imgmime = 'html.png';
10527 $srclang = 'html';
10528 $famime = 'file-text-o';
10529 }
10530 if (preg_match('/\.(xml|xhtml)$/i', $tmpfile)) {
10531 $mime = 'text/xml';
10532 $imgmime = 'other.png';
10533 $srclang = 'xml';
10534 $famime = 'file-text-o';
10535 }
10536 if (preg_match('/\.xaml$/i', $tmpfile)) {
10537 $mime = 'text/xml';
10538 $imgmime = 'other.png';
10539 $srclang = 'xaml';
10540 $famime = 'file-text-o';
10541 }
10542 // Languages
10543 if (preg_match('/\.bas$/i', $tmpfile)) {
10544 $mime = 'text/plain';
10545 $imgmime = 'text.png';
10546 $srclang = 'bas';
10547 $famime = 'file-code-o';
10548 }
10549 if (preg_match('/\.(c)$/i', $tmpfile)) {
10550 $mime = 'text/plain';
10551 $imgmime = 'text.png';
10552 $srclang = 'c';
10553 $famime = 'file-code-o';
10554 }
10555 if (preg_match('/\.(cpp)$/i', $tmpfile)) {
10556 $mime = 'text/plain';
10557 $imgmime = 'text.png';
10558 $srclang = 'cpp';
10559 $famime = 'file-code-o';
10560 }
10561 if (preg_match('/\.cs$/i', $tmpfile)) {
10562 $mime = 'text/plain';
10563 $imgmime = 'text.png';
10564 $srclang = 'cs';
10565 $famime = 'file-code-o';
10566 }
10567 if (preg_match('/\.(h)$/i', $tmpfile)) {
10568 $mime = 'text/plain';
10569 $imgmime = 'text.png';
10570 $srclang = 'h';
10571 $famime = 'file-code-o';
10572 }
10573 if (preg_match('/\.(java|jsp)$/i', $tmpfile)) {
10574 $mime = 'text/plain';
10575 $imgmime = 'text.png';
10576 $srclang = 'java';
10577 $famime = 'file-code-o';
10578 }
10579 if (preg_match('/\.php([0-9]{1})?$/i', $tmpfile)) {
10580 $mime = 'text/plain';
10581 $imgmime = 'php.png';
10582 $srclang = 'php';
10583 $famime = 'file-code-o';
10584 }
10585 if (preg_match('/\.phtml$/i', $tmpfile)) {
10586 $mime = 'text/plain';
10587 $imgmime = 'php.png';
10588 $srclang = 'php';
10589 $famime = 'file-code-o';
10590 }
10591 if (preg_match('/\.(pl|pm)$/i', $tmpfile)) {
10592 $mime = 'text/plain';
10593 $imgmime = 'pl.png';
10594 $srclang = 'perl';
10595 $famime = 'file-code-o';
10596 }
10597 if (preg_match('/\.sql$/i', $tmpfile)) {
10598 $mime = 'text/plain';
10599 $imgmime = 'text.png';
10600 $srclang = 'sql';
10601 $famime = 'file-code-o';
10602 }
10603 if (preg_match('/\.js$/i', $tmpfile)) {
10604 $mime = 'text/x-javascript';
10605 $imgmime = 'jscript.png';
10606 $srclang = 'js';
10607 $famime = 'file-code-o';
10608 }
10609 // Open office
10610 if (preg_match('/\.odp$/i', $tmpfile)) {
10611 $mime = 'application/vnd.oasis.opendocument.presentation';
10612 $imgmime = 'ooffice.png';
10613 $famime = 'file-powerpoint-o';
10614 }
10615 if (preg_match('/\.ods$/i', $tmpfile)) {
10616 $mime = 'application/vnd.oasis.opendocument.spreadsheet';
10617 $imgmime = 'ooffice.png';
10618 $famime = 'file-excel-o';
10619 }
10620 if (preg_match('/\.odt$/i', $tmpfile)) {
10621 $mime = 'application/vnd.oasis.opendocument.text';
10622 $imgmime = 'ooffice.png';
10623 $famime = 'file-word-o';
10624 }
10625 // MS Office
10626 if (preg_match('/\.mdb$/i', $tmpfile)) {
10627 $mime = 'application/msaccess';
10628 $imgmime = 'mdb.png';
10629 $famime = 'file-o';
10630 }
10631 if (preg_match('/\.doc[xm]?$/i', $tmpfile)) {
10632 $mime = 'application/msword';
10633 $imgmime = 'doc.png';
10634 $famime = 'file-word-o';
10635 }
10636 if (preg_match('/\.dot[xm]?$/i', $tmpfile)) {
10637 $mime = 'application/msword';
10638 $imgmime = 'doc.png';
10639 $famime = 'file-word-o';
10640 }
10641 if (preg_match('/\.xlt(x)?$/i', $tmpfile)) {
10642 $mime = 'application/vnd.ms-excel';
10643 $imgmime = 'xls.png';
10644 $famime = 'file-excel-o';
10645 }
10646 if (preg_match('/\.xla(m)?$/i', $tmpfile)) {
10647 $mime = 'application/vnd.ms-excel';
10648 $imgmime = 'xls.png';
10649 $famime = 'file-excel-o';
10650 }
10651 if (preg_match('/\.xls$/i', $tmpfile)) {
10652 $mime = 'application/vnd.ms-excel';
10653 $imgmime = 'xls.png';
10654 $famime = 'file-excel-o';
10655 }
10656 if (preg_match('/\.xls[bmx]$/i', $tmpfile)) {
10657 $mime = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
10658 $imgmime = 'xls.png';
10659 $famime = 'file-excel-o';
10660 }
10661 if (preg_match('/\.pps[mx]?$/i', $tmpfile)) {
10662 $mime = 'application/vnd.ms-powerpoint';
10663 $imgmime = 'ppt.png';
10664 $famime = 'file-powerpoint-o';
10665 }
10666 if (preg_match('/\.ppt[mx]?$/i', $tmpfile)) {
10667 $mime = 'application/x-mspowerpoint';
10668 $imgmime = 'ppt.png';
10669 $famime = 'file-powerpoint-o';
10670 }
10671 // Other
10672 if (preg_match('/\.pdf$/i', $tmpfile)) {
10673 $mime = 'application/pdf';
10674 $imgmime = 'pdf.png';
10675 $famime = 'file-pdf-o';
10676 }
10677 // Scripts
10678 if (preg_match('/\.bat$/i', $tmpfile)) {
10679 $mime = 'text/x-bat';
10680 $imgmime = 'script.png';
10681 $srclang = 'dos';
10682 $famime = 'file-code-o';
10683 }
10684 if (preg_match('/\.sh$/i', $tmpfile)) {
10685 $mime = 'text/x-sh';
10686 $imgmime = 'script.png';
10687 $srclang = 'bash';
10688 $famime = 'file-code-o';
10689 }
10690 if (preg_match('/\.ksh$/i', $tmpfile)) {
10691 $mime = 'text/x-ksh';
10692 $imgmime = 'script.png';
10693 $srclang = 'bash';
10694 $famime = 'file-code-o';
10695 }
10696 if (preg_match('/\.bash$/i', $tmpfile)) {
10697 $mime = 'text/x-bash';
10698 $imgmime = 'script.png';
10699 $srclang = 'bash';
10700 $famime = 'file-code-o';
10701 }
10702 // Images
10703 if (preg_match('/\.ico$/i', $tmpfile)) {
10704 $mime = 'image/x-icon';
10705 $imgmime = 'image.png';
10706 $famime = 'file-image-o';
10707 }
10708 if (preg_match('/\.(jpg|jpeg)$/i', $tmpfile)) {
10709 $mime = 'image/jpeg';
10710 $imgmime = 'image.png';
10711 $famime = 'file-image-o';
10712 }
10713 if (preg_match('/\.png$/i', $tmpfile)) {
10714 $mime = 'image/png';
10715 $imgmime = 'image.png';
10716 $famime = 'file-image-o';
10717 }
10718 if (preg_match('/\.gif$/i', $tmpfile)) {
10719 $mime = 'image/gif';
10720 $imgmime = 'image.png';
10721 $famime = 'file-image-o';
10722 }
10723 if (preg_match('/\.bmp$/i', $tmpfile)) {
10724 $mime = 'image/bmp';
10725 $imgmime = 'image.png';
10726 $famime = 'file-image-o';
10727 }
10728 if (preg_match('/\.(tif|tiff)$/i', $tmpfile)) {
10729 $mime = 'image/tiff';
10730 $imgmime = 'image.png';
10731 $famime = 'file-image-o';
10732 }
10733 if (preg_match('/\.svg$/i', $tmpfile)) {
10734 $mime = 'image/svg+xml';
10735 $imgmime = 'image.png';
10736 $famime = 'file-image-o';
10737 }
10738 if (preg_match('/\.webp$/i', $tmpfile)) {
10739 $mime = 'image/webp';
10740 $imgmime = 'image.png';
10741 $famime = 'file-image-o';
10742 }
10743 // Calendar
10744 if (preg_match('/\.vcs$/i', $tmpfile)) {
10745 $mime = 'text/calendar';
10746 $imgmime = 'other.png';
10747 $famime = 'file-text-o';
10748 }
10749 if (preg_match('/\.ics$/i', $tmpfile)) {
10750 $mime = 'text/calendar';
10751 $imgmime = 'other.png';
10752 $famime = 'file-text-o';
10753 }
10754 // Other
10755 if (preg_match('/\.torrent$/i', $tmpfile)) {
10756 $mime = 'application/x-bittorrent';
10757 $imgmime = 'other.png';
10758 $famime = 'file-o';
10759 }
10760 // Audio
10761 if (preg_match('/\.(mp3|ogg|au|wav|wma|mid)$/i', $tmpfile)) {
10762 $mime = 'audio';
10763 $imgmime = 'audio.png';
10764 $famime = 'file-audio-o';
10765 }
10766 // Video
10767 if (preg_match('/\.mp4$/i', $tmpfile)) {
10768 $mime = 'video/mp4';
10769 $imgmime = 'video.png';
10770 $famime = 'file-video-o';
10771 }
10772 if (preg_match('/\.ogv$/i', $tmpfile)) {
10773 $mime = 'video/ogg';
10774 $imgmime = 'video.png';
10775 $famime = 'file-video-o';
10776 }
10777 if (preg_match('/\.webm$/i', $tmpfile)) {
10778 $mime = 'video/webm';
10779 $imgmime = 'video.png';
10780 $famime = 'file-video-o';
10781 }
10782 if (preg_match('/\.avi$/i', $tmpfile)) {
10783 $mime = 'video/x-msvideo';
10784 $imgmime = 'video.png';
10785 $famime = 'file-video-o';
10786 }
10787 if (preg_match('/\.divx$/i', $tmpfile)) {
10788 $mime = 'video/divx';
10789 $imgmime = 'video.png';
10790 $famime = 'file-video-o';
10791 }
10792 if (preg_match('/\.xvid$/i', $tmpfile)) {
10793 $mime = 'video/xvid';
10794 $imgmime = 'video.png';
10795 $famime = 'file-video-o';
10796 }
10797 if (preg_match('/\.(wmv|mpg|mpeg)$/i', $tmpfile)) {
10798 $mime = 'video';
10799 $imgmime = 'video.png';
10800 $famime = 'file-video-o';
10801 }
10802 // Archive
10803 if (preg_match('/\.(zip|rar|gz|tgz|z|cab|bz2|7z|tar|lzh|zst)$/i', $tmpfile)) {
10804 $mime = 'archive';
10805 $imgmime = 'archive.png';
10806 $famime = 'file-archive-o';
10807 } // application/xxx where zzz is zip, ...
10808 // Exe
10809 if (preg_match('/\.(exe|com)$/i', $tmpfile)) {
10810 $mime = 'application/octet-stream';
10811 $imgmime = 'other.png';
10812 $famime = 'file-o';
10813 }
10814 // Lib
10815 if (preg_match('/\.(dll|lib|o|so|a)$/i', $tmpfile)) {
10816 $mime = 'library';
10817 $imgmime = 'library.png';
10818 $famime = 'file-o';
10819 }
10820 // Err
10821 if (preg_match('/\.err$/i', $tmpfile)) {
10822 $mime = 'error';
10823 $imgmime = 'error.png';
10824 $famime = 'file-text-o';
10825 }
10826
10827 // Return string
10828 if ($mode == 1) {
10829 $tmp = explode('/', $mime);
10830 return (!empty($tmp[1]) ? $tmp[1] : $tmp[0]);
10831 }
10832 if ($mode == 2) {
10833 return $imgmime;
10834 }
10835 if ($mode == 3) {
10836 return $srclang;
10837 }
10838 if ($mode == 4) {
10839 return $famime;
10840 }
10841 return $mime;
10842}
10843
10855function getDictionaryValue($tablename, $field, $id, $checkentity = false, $rowidfield = 'rowid')
10856{
10857 global $conf, $db;
10858
10859 $tablename = preg_replace('/^'.preg_quote(MAIN_DB_PREFIX, '/').'/', '', $tablename); // Clean name of table for backward compatibility.
10860
10861 $dictvalues = (isset($conf->cache['dictvalues_'.$tablename]) ? $conf->cache['dictvalues_'.$tablename] : null);
10862
10863 if (is_null($dictvalues)) {
10864 $dictvalues = array();
10865
10866 $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
10867 if ($checkentity) {
10868 $sql .= ' AND entity IN (0,'.getEntity($tablename).')';
10869 }
10870
10871 $resql = $db->query($sql);
10872 if ($resql) {
10873 while ($obj = $db->fetch_object($resql)) {
10874 $dictvalues[$obj->{$rowidfield}] = $obj; // $obj is stdClass
10875 }
10876 } else {
10877 dol_print_error($db);
10878 }
10879
10880 $conf->cache['dictvalues_'.$tablename] = $dictvalues;
10881 }
10882
10883 if (!empty($dictvalues[$id])) {
10884 // Found
10885 $tmp = $dictvalues[$id];
10886 return (property_exists($tmp, $field) ? $tmp->$field : '');
10887 } else {
10888 // Not found
10889 return '';
10890 }
10891}
10892
10899function colorIsLight($stringcolor)
10900{
10901 $stringcolor = str_replace('#', '', $stringcolor);
10902 $res = -1;
10903 if (!empty($stringcolor)) {
10904 $res = 0;
10905 $tmp = explode(',', $stringcolor);
10906 if (count($tmp) > 1) { // This is a comma RGB ('255','255','255')
10907 $r = $tmp[0];
10908 $g = $tmp[1];
10909 $b = $tmp[2];
10910 } else {
10911 $hexr = $stringcolor[0].$stringcolor[1];
10912 $hexg = $stringcolor[2].$stringcolor[3];
10913 $hexb = $stringcolor[4].$stringcolor[5];
10914 $r = hexdec($hexr);
10915 $g = hexdec($hexg);
10916 $b = hexdec($hexb);
10917 }
10918 $bright = (max($r, $g, $b) + min($r, $g, $b)) / 510.0; // HSL algorithm
10919 if ($bright > 0.6) {
10920 $res = 1;
10921 }
10922 }
10923 return $res;
10924}
10925
10934function isVisibleToUserType($type_user, &$menuentry, &$listofmodulesforexternal)
10935{
10936 global $conf;
10937
10938 //print 'type_user='.$type_user.' module='.$menuentry['module'].' enabled='.$menuentry['enabled'].' perms='.$menuentry['perms'];
10939 //print 'ok='.in_array($menuentry['module'], $listofmodulesforexternal);
10940 if (empty($menuentry['enabled'])) {
10941 return 0; // Entry disabled by condition
10942 }
10943 if ($type_user && $menuentry['module']) {
10944 $tmploops = explode('|', $menuentry['module']);
10945 $found = 0;
10946 foreach ($tmploops as $tmploop) {
10947 if (in_array($tmploop, $listofmodulesforexternal)) {
10948 $found++;
10949 break;
10950 }
10951 }
10952 if (!$found) {
10953 return 0; // Entry is for menus all excluded to external users
10954 }
10955 }
10956 if (!$menuentry['perms'] && $type_user) {
10957 return 0; // No permissions and user is external
10958 }
10959 if (!$menuentry['perms'] && !empty($conf->global->MAIN_MENU_HIDE_UNAUTHORIZED)) {
10960 return 0; // No permissions and option to hide when not allowed, even for internal user, is on
10961 }
10962 if (!$menuentry['perms']) {
10963 return 2; // No permissions and user is external
10964 }
10965 return 1;
10966}
10967
10975function roundUpToNextMultiple($n, $x = 5)
10976{
10977 return (ceil($n) % $x === 0) ? ceil($n) : round(($n + $x / 2) / $x) * $x;
10978}
10979
10991function dolGetBadge($label, $html = '', $type = 'primary', $mode = '', $url = '', $params = array())
10992{
10993 $attr = array(
10994 'class'=>'badge '.(!empty($mode) ? ' badge-'.$mode : '').(!empty($type) ? ' badge-'.$type : '').(empty($params['css']) ? '' : ' '.$params['css'])
10995 );
10996
10997 if (empty($html)) {
10998 $html = $label;
10999 }
11000
11001 if (!empty($url)) {
11002 $attr['href'] = $url;
11003 }
11004
11005 if ($mode === 'dot') {
11006 $attr['class'] .= ' classfortooltip';
11007 $attr['title'] = $html;
11008 $attr['aria-label'] = $label;
11009 $html = '';
11010 }
11011
11012 // Override attr
11013 if (!empty($params['attr']) && is_array($params['attr'])) {
11014 foreach ($params['attr'] as $key => $value) {
11015 if ($key == 'class') {
11016 $attr['class'] .= ' '.$value;
11017 } elseif ($key == 'classOverride') {
11018 $attr['class'] = $value;
11019 } else {
11020 $attr[$key] = $value;
11021 }
11022 }
11023 }
11024
11025 // TODO: add hook
11026
11027 // escape all attribute
11028 $attr = array_map('dol_escape_htmltag', $attr);
11029
11030 $TCompiledAttr = array();
11031 foreach ($attr as $key => $value) {
11032 $TCompiledAttr[] = $key.'="'.$value.'"';
11033 }
11034
11035 $compiledAttributes = !empty($TCompiledAttr) ?implode(' ', $TCompiledAttr) : '';
11036
11037 $tag = !empty($url) ? 'a' : 'span';
11038
11039 return '<'.$tag.' '.$compiledAttributes.'>'.$html.'</'.$tag.'>';
11040}
11041
11042
11055function dolGetStatus($statusLabel = '', $statusLabelShort = '', $html = '', $statusType = 'status0', $displayMode = 0, $url = '', $params = array())
11056{
11057 global $conf;
11058
11059 $return = '';
11060 $dolGetBadgeParams = array();
11061
11062 if (!empty($params['badgeParams'])) {
11063 $dolGetBadgeParams = $params['badgeParams'];
11064 }
11065
11066 // TODO : add a hook
11067 if ($displayMode == 0) {
11068 $return = !empty($html) ? $html : (empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort));
11069 } elseif ($displayMode == 1) {
11070 $return = !empty($html) ? $html : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11071 } elseif (!empty($conf->global->MAIN_STATUS_USES_IMAGES)) {
11072 // Use status with images (for backward compatibility)
11073 $return = '';
11074 $htmlLabel = (in_array($displayMode, array(1, 2, 5)) ? '<span class="hideonsmartphone">' : '').(!empty($html) ? $html : $statusLabel).(in_array($displayMode, array(1, 2, 5)) ? '</span>' : '');
11075 $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>' : '');
11076
11077 // For small screen, we always use the short label instead of long label.
11078 if (!empty($conf->dol_optimize_smallscreen)) {
11079 if ($displayMode == 0) {
11080 $displayMode = 1;
11081 } elseif ($displayMode == 4) {
11082 $displayMode = 2;
11083 } elseif ($displayMode == 6) {
11084 $displayMode = 5;
11085 }
11086 }
11087
11088 // For backward compatibility. Image's filename are still in French, so we use this array to convert
11089 $statusImg = array(
11090 'status0' => 'statut0',
11091 'status1' => 'statut1',
11092 'status2' => 'statut2',
11093 'status3' => 'statut3',
11094 'status4' => 'statut4',
11095 'status5' => 'statut5',
11096 'status6' => 'statut6',
11097 'status7' => 'statut7',
11098 'status8' => 'statut8',
11099 'status9' => 'statut9'
11100 );
11101
11102 if (!empty($statusImg[$statusType])) {
11103 $htmlImg = img_picto($statusLabel, $statusImg[$statusType]);
11104 } else {
11105 $htmlImg = img_picto($statusLabel, $statusType);
11106 }
11107
11108 if ($displayMode === 2) {
11109 $return = $htmlImg.' '.$htmlLabelShort;
11110 } elseif ($displayMode === 3) {
11111 $return = $htmlImg;
11112 } elseif ($displayMode === 4) {
11113 $return = $htmlImg.' '.$htmlLabel;
11114 } elseif ($displayMode === 5) {
11115 $return = $htmlLabelShort.' '.$htmlImg;
11116 } else { // $displayMode >= 6
11117 $return = $htmlLabel.' '.$htmlImg;
11118 }
11119 } elseif (empty($conf->global->MAIN_STATUS_USES_IMAGES) && !empty($displayMode)) {
11120 // Use new badge
11121 $statusLabelShort = (empty($statusLabelShort) ? $statusLabel : $statusLabelShort);
11122
11123 $dolGetBadgeParams['attr']['class'] = 'badge-status';
11124 $dolGetBadgeParams['attr']['title'] = empty($params['tooltip']) ? $statusLabel : ($params['tooltip'] != 'no' ? $params['tooltip'] : '');
11125
11126 if ($displayMode == 3) {
11127 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), '', $statusType, 'dot', $url, $dolGetBadgeParams);
11128 } elseif ($displayMode === 5) {
11129 $return = dolGetBadge($statusLabelShort, $html, $statusType, '', $url, $dolGetBadgeParams);
11130 } else {
11131 $return = dolGetBadge((empty($conf->dol_optimize_smallscreen) ? $statusLabel : (empty($statusLabelShort) ? $statusLabel : $statusLabelShort)), $html, $statusType, '', $url, $dolGetBadgeParams);
11132 }
11133 }
11134
11135 return $return;
11136}
11137
11138
11173function dolGetButtonAction($label, $text = '', $actionType = 'default', $url = '', $id = '', $userRight = 1, $params = array())
11174{
11175 global $hookmanager, $action, $object, $langs;
11176
11177 // If $url is an array, we must build a dropdown button
11178 if (is_array($url)) {
11179 $out = '<div class="dropdown inline-block dropdown-holder">';
11180 $out .= '<a style="margin-right: auto;" class="dropdown-toggle butAction" data-toggle="dropdown">'.$label.'</a>';
11181 $out .= '<div class="dropdown-content">';
11182 foreach ($url as $subbutton) {
11183 if ($subbutton['enabled'] && $subbutton['perm']) {
11184 if (!empty($subbutton['lang'])) {
11185 $langs->load($subbutton['lang']);
11186 }
11187 $out .= dolGetButtonAction('', $langs->trans($subbutton['label']), 'default', DOL_URL_ROOT.$subbutton['url'].(empty($params['backtopage']) ? '' : '&amp;backtopage='.urlencode($params['backtopage'])), '', 1, array('isDropDown' => true));
11188 }
11189 }
11190 $out .= "</div>";
11191 $out .= "</div>";
11192
11193 return $out;
11194 }
11195
11196 // If $url is a simple link
11197 if (!empty($params['isDropdown']))
11198 $class = "dropdown-item";
11199 else {
11200 $class = 'butAction';
11201 if ($actionType == 'danger' || $actionType == 'delete') {
11202 $class = 'butActionDelete';
11203 if (!empty($url) && strpos($url, 'token=') === false) $url .= '&token='.newToken();
11204 }
11205 }
11206 $attr = array(
11207 'class' => $class,
11208 'href' => empty($url) ? '' : $url,
11209 'title' => $label
11210 );
11211
11212 if (empty($text)) {
11213 $text = $label;
11214 $attr['title'] = ''; // if html not set, leave label on title is redundant
11215 } else {
11216 $attr['title'] = $label;
11217 $attr['aria-label'] = $label;
11218 }
11219
11220 if (empty($userRight)) {
11221 $attr['class'] = 'butActionRefused';
11222 $attr['href'] = '';
11223 $attr['title'] = (($label && $text && $label != $text) ? $label : $langs->trans('NotEnoughPermissions'));
11224 }
11225
11226 if (!empty($id)) {
11227 $attr['id'] = $id;
11228 }
11229
11230 // Override attr
11231 if (!empty($params['attr']) && is_array($params['attr'])) {
11232 foreach ($params['attr'] as $key => $value) {
11233 if ($key == 'class') {
11234 $attr['class'] .= ' '.$value;
11235 } elseif ($key == 'classOverride') {
11236 $attr['class'] = $value;
11237 } else {
11238 $attr[$key] = $value;
11239 }
11240 }
11241 }
11242
11243 // automatic add tooltip when title is detected
11244 if (!empty($attr['title']) && !empty($attr['class']) && strpos($attr['class'], 'classfortooltip') === false) {
11245 $attr['class'].= ' classfortooltip';
11246 }
11247
11248 // Js Confirm button
11249 if ($userRight && !empty($params['confirm'])) {
11250 if (!is_array($params['confirm'])) {
11251 $params['confirm'] = array();
11252 }
11253
11254 if (empty($params['confirm']['url'])) {
11255 $params['confirm']['url'] = $url . (strpos($url, '?') > 0 ? '&' : '?') . 'confirm=yes';
11256 }
11257
11258 // for js desabled compatibility set $url as call to confirm action and $params['confirm']['url'] to confirmed action
11259 $attr['data-confirm-url'] = $params['confirm']['url'];
11260 $attr['data-confirm-title'] = !empty($params['confirm']['title']) ? $params['confirm']['title'] : $langs->trans('ConfirmBtnCommonTitle', $label);
11261 $attr['data-confirm-content'] = !empty($params['confirm']['content']) ? $params['confirm']['content'] : $langs->trans('ConfirmBtnCommonContent', $label);
11262 $attr['data-confirm-content'] = preg_replace("/\r|\n/", "", $attr['data-confirm-content']);
11263 $attr['data-confirm-action-btn-label'] = !empty($params['confirm']['action-btn-label']) ? $params['confirm']['action-btn-label'] : $langs->trans('Confirm');
11264 $attr['data-confirm-cancel-btn-label'] = !empty($params['confirm']['cancel-btn-label']) ? $params['confirm']['cancel-btn-label'] : $langs->trans('CloseDialog');
11265 $attr['data-confirm-modal'] = !empty($params['confirm']['modal']) ? $params['confirm']['modal'] : true;
11266
11267 $attr['class'].= ' butActionConfirm';
11268 }
11269
11270 if (isset($attr['href']) && empty($attr['href'])) {
11271 unset($attr['href']);
11272 }
11273
11274 // escape all attribute
11275 $attr = array_map('dol_escape_htmltag', $attr);
11276
11277 $TCompiledAttr = array();
11278 foreach ($attr as $key => $value) {
11279 $TCompiledAttr[] = $key.'= "'.$value.'"';
11280 }
11281
11282 $compiledAttributes = empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr);
11283
11284 $tag = !empty($attr['href']) ? 'a' : 'span';
11285
11286
11287 $parameters = array(
11288 'TCompiledAttr' => $TCompiledAttr, // array
11289 'compiledAttributes' => $compiledAttributes, // string
11290 'attr' => $attr,
11291 'tag' => $tag,
11292 'label' => $label,
11293 'html' => $text,
11294 'actionType' => $actionType,
11295 'url' => $url,
11296 'id' => $id,
11297 'userRight' => $userRight,
11298 'params' => $params
11299 );
11300
11301 $reshook = $hookmanager->executeHooks('dolGetButtonAction', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
11302 if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
11303
11304 if (empty($reshook)) {
11305 if (dol_textishtml($text)) { // If content already HTML encoded
11306 return '<' . $tag . ' ' . $compiledAttributes . '>' . $text . '</' . $tag . '>';
11307 } else {
11308 return '<' . $tag . ' ' . $compiledAttributes . '>' . dol_escape_htmltag($text) . '</' . $tag . '>';
11309 }
11310 } else {
11311 return $hookmanager->resPrint;
11312 }
11313}
11314
11321function dolGetButtonTitleSeparator($moreClass = "")
11322{
11323 return '<span class="button-title-separator '.$moreClass.'" ></span>';
11324}
11325
11332function getFieldErrorIcon($fieldValidationErrorMsg)
11333{
11334 $out = '';
11335 if (!empty($fieldValidationErrorMsg)) {
11336 $out.= '<span class="field-error-icon classfortooltip" title="'.dol_escape_htmltag($fieldValidationErrorMsg, 1).'" role="alert" >'; // role alert is used for accessibility
11337 $out.= '<span class="fa fa-exclamation-circle" aria-hidden="true" ></span>'; // For accessibility icon is separated and aria-hidden
11338 $out.= '</span>';
11339 }
11340
11341 return $out;
11342}
11343
11356function dolGetButtonTitle($label, $helpText = '', $iconClass = 'fa fa-file', $url = '', $id = '', $status = 1, $params = array())
11357{
11358 global $langs, $conf, $user;
11359
11360 // Actually this conf is used in css too for external module compatibility and smooth transition to this function
11361 if (!empty($conf->global->MAIN_BUTTON_HIDE_UNAUTHORIZED) && (!$user->admin) && $status <= 0) {
11362 return '';
11363 }
11364
11365 $class = 'btnTitle';
11366 if (in_array($iconClass, array('fa fa-plus-circle', 'fa fa-plus-circle size15x', 'fa fa-comment-dots', 'fa fa-paper-plane'))) {
11367 $class .= ' btnTitlePlus';
11368 }
11369 $useclassfortooltip = 1;
11370
11371 if (!empty($params['morecss'])) {
11372 $class .= ' '.$params['morecss'];
11373 }
11374
11375 $attr = array(
11376 'class' => $class,
11377 'href' => empty($url) ? '' : $url
11378 );
11379
11380 if (!empty($helpText)) {
11381 $attr['title'] = dol_escape_htmltag($helpText);
11382 } elseif (empty($attr['title']) && $label) {
11383 $attr['title'] = $label;
11384 $useclassfortooltip = 0;
11385 }
11386
11387 if ($status == 2) {
11388 $attr['class'] .= ' btnTitleSelected';
11389 } elseif ($status <= 0) {
11390 $attr['class'] .= ' refused';
11391
11392 $attr['href'] = '';
11393
11394 if ($status == -1) { // disable
11395 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("FeatureDisabled"));
11396 } elseif ($status == 0) { // Not enough permissions
11397 $attr['title'] = dol_escape_htmltag($langs->transnoentitiesnoconv("NotEnoughPermissions"));
11398 }
11399 }
11400
11401 if (!empty($attr['title']) && $useclassfortooltip) {
11402 $attr['class'] .= ' classfortooltip';
11403 }
11404
11405 if (!empty($id)) {
11406 $attr['id'] = $id;
11407 }
11408
11409 // Override attr
11410 if (!empty($params['attr']) && is_array($params['attr'])) {
11411 foreach ($params['attr'] as $key => $value) {
11412 if ($key == 'class') {
11413 $attr['class'] .= ' '.$value;
11414 } elseif ($key == 'classOverride') {
11415 $attr['class'] = $value;
11416 } else {
11417 $attr[$key] = $value;
11418 }
11419 }
11420 }
11421
11422 if (isset($attr['href']) && empty($attr['href'])) {
11423 unset($attr['href']);
11424 }
11425
11426 // TODO : add a hook
11427
11428 // escape all attribute
11429 $attr = array_map('dol_escape_htmltag', $attr);
11430
11431 $TCompiledAttr = array();
11432 foreach ($attr as $key => $value) {
11433 $TCompiledAttr[] = $key.'="'.$value.'"';
11434 }
11435
11436 $compiledAttributes = (empty($TCompiledAttr) ? '' : implode(' ', $TCompiledAttr));
11437
11438 $tag = (empty($attr['href']) ? 'span' : 'a');
11439
11440 $button = '<'.$tag.' '.$compiledAttributes.'>';
11441 $button .= '<span class="'.$iconClass.' valignmiddle btnTitle-icon"></span>';
11442 if (!empty($params['forcenohideoftext'])) {
11443 $button .= '<span class="valignmiddle text-plus-circle btnTitle-label'.(empty($params['forcenohideoftext']) ? ' hideonsmartphone' : '').'">'.$label.'</span>';
11444 }
11445 $button .= '</'.$tag.'>';
11446
11447 return $button;
11448}
11449
11460function getElementProperties($element_type)
11461{
11462 global $conf;
11463
11464 $regs = array();
11465
11466 $classfile = $classname = $classpath = $subdir = $dir_output = '';
11467
11468 // Parse element/subelement
11469 $module = $element_type;
11470 $element = $element_type;
11471 $subelement = $element_type;
11472
11473 // If we ask a resource form external module (instead of default path)
11474 if (preg_match('/^([^@]+)@([^@]+)$/i', $element_type, $regs)) { // 'myobject@mymodule'
11475 $element = $subelement = $regs[1];
11476 $module = $regs[2];
11477 }
11478
11479 // If we ask a resource for a string with an element and a subelement
11480 // Example 'project_task'
11481 if (preg_match('/^([^_]+)_([^_]+)/i', $element, $regs)) { // 'myobject_mysubobject' with myobject=mymodule
11482 $module = $element = $regs[1];
11483 $subelement = $regs[2];
11484 }
11485
11486 // For compat and To work with non standard path
11487 if ($element_type == "action") {
11488 $classpath = 'comm/action/class';
11489 $subelement = 'Actioncomm';
11490 $module = 'agenda';
11491 } elseif ($element_type == 'cronjob') {
11492 $classpath = 'cron/class';
11493 $module = 'cron';
11494 } elseif ($element_type == 'adherent_type') {
11495 $classpath = 'adherents/class';
11496 $classfile = 'adherent_type';
11497 $module = 'adherent';
11498 $subelement = 'adherent_type';
11499 $classname = 'AdherentType';
11500 } elseif ($element_type == 'bank_account') {
11501 $classpath = 'compta/bank/class';
11502 $module = 'bank'; // We need $conf->bank->dir_output and not $conf->banque->dir_output
11503 $classfile = 'account';
11504 $classname = 'Account';
11505 } elseif ($element_type == 'category') {
11506 $classpath = 'categories/class';
11507 $module = 'categorie';
11508 $subelement = 'categorie';
11509 } elseif ($element_type == 'contact') {
11510 $classpath = 'contact/class';
11511 $classfile = 'contact';
11512 $module = 'societe';
11513 $subelement = 'contact';
11514 } elseif ($element_type == 'stock') {
11515 $classpath = 'product/stock/class';
11516 $classfile = 'entrepot';
11517 $classname = 'Entrepot';
11518 } elseif ($element_type == 'project') {
11519 $classpath = 'projet/class';
11520 $module = 'projet';
11521 } elseif ($element_type == 'project_task') {
11522 $classpath = 'projet/class';
11523 $module = 'projet';
11524 $subelement = 'task';
11525 } elseif ($element_type == 'facture' || $element_type == 'invoice') {
11526 $classpath = 'compta/facture/class';
11527 $module = 'facture';
11528 $subelement = 'facture';
11529 } elseif ($element_type == 'commande' || $element_type == 'order') {
11530 $classpath = 'commande/class';
11531 $module = 'commande';
11532 $subelement = 'commande';
11533 } elseif ($element_type == 'propal') {
11534 $classpath = 'comm/propal/class';
11535 } elseif ($element_type == 'shipping') {
11536 $classpath = 'expedition/class';
11537 $classfile = 'expedition';
11538 $classname = 'Expedition';
11539 $module = 'expedition';
11540 } elseif ($element_type == 'supplier_proposal') {
11541 $classpath = 'supplier_proposal/class';
11542 $module = 'supplier_proposal';
11543 $element = 'supplierproposal';
11544 $classfile = 'supplier_proposal';
11545 $subelement = 'supplierproposal';
11546 } elseif ($element_type == 'shipping') {
11547 $classpath = 'expedition/class';
11548 $subelement = 'expedition';
11549 $module = 'expedition_bon';
11550 } elseif ($element_type == 'delivery') {
11551 $classpath = 'delivery/class';
11552 $subelement = 'delivery';
11553 $module = 'delivery_note';
11554 } elseif ($element_type == 'contract') {
11555 $classpath = 'contrat/class';
11556 $module = 'contrat';
11557 $subelement = 'contrat';
11558 } elseif ($element_type == 'mailing') {
11559 $classpath = 'comm/mailing/class';
11560 $module = 'mailing';
11561 $classfile = 'mailing';
11562 $classname = 'Mailing';
11563 $subelement = '';
11564 } elseif ($element_type == 'member') {
11565 $classpath = 'adherents/class';
11566 $module = 'adherent';
11567 $subelement = 'adherent';
11568 } elseif ($element_type == 'usergroup') {
11569 $classpath = 'user/class';
11570 $module = 'user';
11571 } elseif ($element_type == 'mo') {
11572 $classpath = 'mrp/class';
11573 $classfile = 'mo';
11574 $classname = 'Mo';
11575 $module = 'mrp';
11576 $subelement = '';
11577 } elseif ($element_type == 'cabinetmed_cons') {
11578 $classpath = 'cabinetmed/class';
11579 $module = 'cabinetmed';
11580 $subelement = 'cabinetmedcons';
11581 } elseif ($element_type == 'fichinter') {
11582 $classpath = 'fichinter/class';
11583 $module = 'ficheinter';
11584 $subelement = 'fichinter';
11585 } elseif ($element_type == 'dolresource' || $element_type == 'resource') {
11586 $classpath = 'resource/class';
11587 $module = 'resource';
11588 $subelement = 'dolresource';
11589 } elseif ($element_type == 'propaldet') {
11590 $classpath = 'comm/propal/class';
11591 $module = 'propal';
11592 $subelement = 'propaleligne';
11593 } elseif ($element_type == 'opensurvey_sondage') {
11594 $classpath = 'opensurvey/class';
11595 $module = 'opensurvey';
11596 $subelement = 'opensurveysondage';
11597 } elseif ($element_type == 'order_supplier') {
11598 $classpath = 'fourn/class';
11599 $module = 'fournisseur';
11600 $classfile = 'fournisseur.commande';
11601 $element = 'order_supplier';
11602 $subelement = '';
11603 $classname = 'CommandeFournisseur';
11604 } elseif ($element_type == 'invoice_supplier') {
11605 $classpath = 'fourn/class';
11606 $module = 'fournisseur';
11607 $classfile = 'fournisseur.facture';
11608 $element = 'invoice_supplier';
11609 $subelement = '';
11610 $classname = 'FactureFournisseur';
11611 } elseif ($element_type == "service") {
11612 $classpath = 'product/class';
11613 $subelement = 'product';
11614 } elseif ($element_type == 'salary') {
11615 $classpath = 'salaries/class';
11616 $module = 'salaries';
11617 } elseif ($element_type == 'productlot') {
11618 $module = 'productbatch';
11619 $classpath = 'product/stock/class';
11620 $classfile = 'productlot';
11621 $classname = 'Productlot';
11622 $element = 'productlot';
11623 $subelement = '';
11624 } elseif ($element_type == 'websitepage') {
11625 $classpath = 'website/class';
11626 $classfile = 'websitepage';
11627 $classname = 'Websitepage';
11628 $module = 'website';
11629 $subelement = 'websitepage';
11630 } elseif ($element_type == 'fiscalyear') {
11631 $classpath = 'core/class';
11632 $module = 'accounting';
11633 $subelement = 'fiscalyear';
11634 } elseif ($element_type == 'chargesociales') {
11635 $classpath = 'compta/sociales/class';
11636 $module = 'tax';
11637 } elseif ($element_type == 'tva') {
11638 $classpath = 'compta/tva/class';
11639 $module = 'tax';
11640 $subdir = '/vat';
11641 }
11642
11643 if (empty($classfile)) {
11644 $classfile = strtolower($subelement);
11645 }
11646 if (empty($classname)) {
11647 $classname = ucfirst($subelement);
11648 }
11649 if (empty($classpath)) {
11650 $classpath = $module.'/class';
11651 }
11652
11653 //print 'getElementProperties subdir='.$subdir;
11654
11655 // Set dir_output
11656 if ($module && isset($conf->$module)) { // The generic case
11657 if (!empty($conf->$module->multidir_output[$conf->entity])) {
11658 $dir_output = $conf->$module->multidir_output[$conf->entity];
11659 } elseif (!empty($conf->$module->output[$conf->entity])) {
11660 $dir_output = $conf->$module->output[$conf->entity];
11661 } elseif (!empty($conf->$module->dir_output)) {
11662 $dir_output = $conf->$module->dir_output;
11663 }
11664 }
11665
11666 // Overwrite value for special cases
11667 if ($element == 'order_supplier') {
11668 $dir_output = $conf->fournisseur->commande->dir_output;
11669 } elseif ($element == 'invoice_supplier') {
11670 $dir_output = $conf->fournisseur->facture->dir_output;
11671 }
11672 $dir_output .= $subdir;
11673
11674 $element_properties = array(
11675 'module' => $module,
11676 'element' => $element,
11677 'subelement' => $subelement,
11678 'classpath' => $classpath,
11679 'classfile' => $classfile,
11680 'classname' => $classname,
11681 'dir_output' => $dir_output
11682 );
11683 return $element_properties;
11684}
11685
11695function fetchObjectByElement($element_id, $element_type, $element_ref = '')
11696{
11697 global $db;
11698
11699 $ret = 0;
11700
11701 $element_prop = getElementProperties($element_type);
11702
11703 if (is_array($element_prop) && isModEnabled($element_prop['module'])) {
11704 dol_include_once('/'.$element_prop['classpath'].'/'.$element_prop['classfile'].'.class.php');
11705
11706 if (class_exists($element_prop['classname'])) {
11707 $classname = $element_prop['classname'];
11708 $objecttmp = new $classname($db);
11709 $ret = $objecttmp->fetch($element_id, $element_ref);
11710 if ($ret >= 0) {
11711 if (empty($objecttmp->module)) {
11712 $objecttmp->module = $element_prop['module'];
11713 }
11714
11715 return $objecttmp;
11716 }
11717 } else {
11718 return -1;
11719 }
11720 }
11721
11722 return $ret;
11723}
11724
11732{
11733 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)) {
11734 return true;
11735 }
11736
11737 return false;
11738}
11739
11747function newToken()
11748{
11749 return empty($_SESSION['newtoken']) ? '' : $_SESSION['newtoken'];
11750}
11751
11760{
11761 return isset($_SESSION['token']) ? $_SESSION['token'] : '';
11762}
11763
11769function getNonce()
11770{
11771 global $conf;
11772
11773 if (empty($conf->cache['nonce'])) {
11774 $conf->cache['nonce'] = dolGetRandomBytes(8);
11775 }
11776
11777 return $conf->cache['nonce'];
11778}
11779
11780
11793function startSimpleTable($header, $link = "", $arguments = "", $emptyRows = 0, $number = -1)
11794{
11795 global $langs;
11796
11797 print '<div class="div-table-responsive-no-min">';
11798 print '<table class="noborder centpercent">';
11799 print '<tr class="liste_titre">';
11800
11801 print $emptyRows < 1 ? '<th>' : '<th colspan="'.($emptyRows + 1).'">';
11802
11803 print $langs->trans($header);
11804
11805 // extra space between the first header and the number
11806 if ($number > -1) {
11807 print ' ';
11808 }
11809
11810 if (!empty($link)) {
11811 if (!empty($arguments)) {
11812 print '<a href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
11813 } else {
11814 print '<a href="'.DOL_URL_ROOT.'/'.$link.'">';
11815 }
11816 }
11817
11818 if ($number > -1) {
11819 print '<span class="badge">'.$number.'</span>';
11820 }
11821
11822 if (!empty($link)) {
11823 print '</a>';
11824 }
11825
11826 print '</th>';
11827
11828 if ($number < 0 && !empty($link)) {
11829 print '<th class="right">';
11830
11831 if (!empty($arguments)) {
11832 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'?'.$arguments.'">';
11833 } else {
11834 print '<a class="commonlink" href="'.DOL_URL_ROOT.'/'.$link.'">';
11835 }
11836
11837 print $langs->trans("FullList");
11838 print '</a>';
11839 print '</th>';
11840 }
11841
11842 print '</tr>';
11843}
11844
11853function finishSimpleTable($addLineBreak = false)
11854{
11855 print '</table>';
11856 print '</div>';
11857
11858 if ($addLineBreak) {
11859 print '<br>';
11860 }
11861}
11862
11874function addSummaryTableLine($tableColumnCount, $num, $nbofloop = 0, $total = 0, $noneWord = "None", $extraRightColumn = false)
11875{
11876 global $langs;
11877
11878 if ($num === 0) {
11879 print '<tr class="oddeven">';
11880 print '<td colspan="'.$tableColumnCount.'" class="opacitymedium">'.$langs->trans($noneWord).'</td>';
11881 print '</tr>';
11882 return;
11883 }
11884
11885 if ($nbofloop === 0) {
11886 // don't show a summary line
11887 return;
11888 }
11889
11890 if ($num === 0) {
11891 $colspan = $tableColumnCount;
11892 } elseif ($num > $nbofloop) {
11893 $colspan = $tableColumnCount;
11894 } else {
11895 $colspan = $tableColumnCount - 1;
11896 }
11897
11898 if ($extraRightColumn) {
11899 $colspan--;
11900 }
11901
11902 print '<tr class="liste_total">';
11903
11904 if ($nbofloop > 0 && $num > $nbofloop) {
11905 print '<td colspan="'.$colspan.'" class="right">'.$langs->trans("XMoreLines", ($num - $nbofloop)).'</td>';
11906 } else {
11907 print '<td colspan="'.$colspan.'" class="right"> '.$langs->trans("Total").'</td>';
11908 print '<td class="right" width="100">'.price($total).'</td>';
11909 }
11910
11911 if ($extraRightColumn) {
11912 print '<td></td>';
11913 }
11914
11915 print '</tr>';
11916}
11917
11926function readfileLowMemory($fullpath_original_file_osencoded, $method = -1)
11927{
11928 global $conf;
11929
11930 if ($method == -1) {
11931 $method = 0;
11932 if (!empty($conf->global->MAIN_FORCE_READFILE_WITH_FREAD)) {
11933 $method = 1;
11934 }
11935 if (!empty($conf->global->MAIN_FORCE_READFILE_WITH_STREAM_COPY)) {
11936 $method = 2;
11937 }
11938 }
11939
11940 // Be sure we don't have output buffering enabled to have readfile working correctly
11941 while (ob_get_level()) {
11942 ob_end_flush();
11943 }
11944
11945 // Solution 0
11946 if ($method == 0) {
11947 readfile($fullpath_original_file_osencoded);
11948 } elseif ($method == 1) {
11949 // Solution 1
11950 $handle = fopen($fullpath_original_file_osencoded, "rb");
11951 while (!feof($handle)) {
11952 print fread($handle, 8192);
11953 }
11954 fclose($handle);
11955 } elseif ($method == 2) {
11956 // Solution 2
11957 $handle1 = fopen($fullpath_original_file_osencoded, "rb");
11958 $handle2 = fopen("php://output", "wb");
11959 stream_copy_to_stream($handle1, $handle2);
11960 fclose($handle1);
11961 fclose($handle2);
11962 }
11963}
11964
11974function showValueWithClipboardCPButton($valuetocopy, $showonlyonhover = 1, $texttoshow = '')
11975{
11976 /*
11977 global $conf;
11978
11979 if (!empty($conf->dol_no_mouse_hover)) {
11980 $showonlyonhover = 0;
11981 }*/
11982
11983 $tag = 'span'; // Using div (like any style of type 'block') does not work when using the js copy code.
11984 if ($texttoshow === 'none') {
11985 $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>';
11986 } elseif ($texttoshow) {
11987 $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>';
11988 } else {
11989 $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>';
11990 }
11991
11992 return $result;
11993}
11994
11995
12002function jsonOrUnserialize($stringtodecode)
12003{
12004 $result = json_decode($stringtodecode);
12005 if ($result === null) {
12006 $result = unserialize($stringtodecode);
12007 }
12008
12009 return $result;
12010}
12011
12012
12026function forgeSQLFromUniversalSearchCriteria($filter, &$errorstr = '', $noand = 0, $nopar = 0, $noerror = 0)
12027{
12028 if (!preg_match('/^\‍(.*\‍)$/', $filter)) { // If $filter does not start and end with ()
12029 $filter = '(' . $filter . ')';
12030 }
12031
12032 $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'
12033
12034 if (!dolCheckFilters($filter, $errorstr)) {
12035 if ($noerror) {
12036 return '1 = 2';
12037 } else {
12038 return 'Filter syntax error - '.$errorstr; // Bad balance of parenthesis, we return an error message or force a SQL not found
12039 }
12040 }
12041
12042 // Test the filter syntax
12043 $t = preg_replace_callback('/'.$regexstring.'/i', 'dolForgeDummyCriteriaCallback', $filter);
12044 $t = str_replace(array('and','or','AND','OR',' '), '', $t); // Remove the only strings allowed between each () criteria
12045 // If the string result contains something else than '()', the syntax was wrong
12046 if (preg_match('/[^\‍(\‍)]/', $t)) {
12047 $errorstr = 'Bad syntax of the search string';
12048 if ($noerror) {
12049 return '1 = 2';
12050 } else {
12051 return 'Filter syntax error - '.$errorstr; // Bad syntax of the search string, we return an error message or force a SQL not found
12052 }
12053 }
12054
12055 return ($noand ? "" : " AND ").($nopar ? "" : '(').preg_replace_callback('/'.$regexstring.'/i', 'dolForgeCriteriaCallback', $filter).($nopar ? "" : ')');
12056}
12057
12065function dolCheckFilters($sqlfilters, &$error = '')
12066{
12067 //$regexstring='\‍(([^:\'\‍(\‍)]+:[^:\'\‍(\‍)]+:[^:\‍(\‍)]+)\‍)';
12068 //$tmp=preg_replace_all('/'.$regexstring.'/', '', $sqlfilters);
12069 $tmp = $sqlfilters;
12070 $i = 0; $nb = strlen($tmp);
12071 $counter = 0;
12072 while ($i < $nb) {
12073 if ($tmp[$i] == '(') {
12074 $counter++;
12075 }
12076 if ($tmp[$i] == ')') {
12077 $counter--;
12078 }
12079 if ($counter < 0) {
12080 $error = "Wrond balance of parenthesis in sqlfilters=".$sqlfilters;
12081 dol_syslog($error, LOG_WARNING);
12082 return false;
12083 }
12084 $i++;
12085 }
12086 return true;
12087}
12088
12097{
12098 //dol_syslog("Convert matches ".$matches[1]);
12099 if (empty($matches[1])) {
12100 return '';
12101 }
12102 $tmp = explode(':', $matches[1]);
12103 if (count($tmp) < 3) {
12104 return '';
12105 }
12106
12107 return '()'; // An empty criteria
12108}
12109
12119{
12120 global $db;
12121
12122 //dol_syslog("Convert matches ".$matches[1]);
12123 if (empty($matches[1])) {
12124 return '';
12125 }
12126 $tmp = explode(':', $matches[1]);
12127 if (count($tmp) < 3) {
12128 return '';
12129 }
12130
12131 $operand = preg_replace('/[^a-z0-9\._]/i', '', trim($tmp[0]));
12132
12133 $operator = strtoupper(preg_replace('/[^a-z<>!=]/i', '', trim($tmp[1])));
12134
12135 if ($operator == 'NOTLIKE') {
12136 $operator = 'NOT LIKE';
12137 }
12138 if ($operator == 'ISNOT') {
12139 $operator = 'IS NOT';
12140 }
12141 if ($operator == '!=') {
12142 $operator = '<>';
12143 }
12144
12145 $tmpescaped = $tmp[2];
12146 $regbis = array();
12147
12148 if ($operator == 'IN') { // IN is allowed for list of ID or code only
12149 //if (!preg_match('/^\‍(.*\‍)$/', $tmpescaped)) {
12150 $tmpescaped = '('.$db->escape($db->sanitize($tmpescaped, 1, 0)).')';
12151 //} else {
12152 // $tmpescaped = $db->escape($db->sanitize($tmpescaped, 1));
12153 //}
12154 } elseif ($operator == 'LIKE' || $operator == 'NOT LIKE') {
12155 if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12156 $tmpescaped = $regbis[1];
12157 }
12158 //$tmpescaped = "'".$db->escapeforlike($db->escape($regbis[1]))."'";
12159 $tmpescaped = "'".$db->escape($tmpescaped)."'"; // We do not escape the _ and % so the like will works
12160 } elseif (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) {
12161 $tmpescaped = "'".$db->escape($regbis[1])."'";
12162 } else {
12163 if (strtoupper($tmpescaped) == 'NULL') {
12164 $tmpescaped = 'NULL';
12165 } elseif (is_int($tmpescaped)) {
12166 $tmpescaped = (int) $tmpescaped;
12167 } else {
12168 $tmpescaped = (float) $tmpescaped;
12169 }
12170 }
12171
12172 return '('.$db->escape($operand).' '.strtoupper($operator).' '.$tmpescaped.')';
12173}
12174
12175
12184function getTimelineIcon($actionstatic, &$histo, $key)
12185{
12186 global $conf, $langs;
12187 $out = '<!-- timeline icon -->'."\n";
12188 $iconClass = 'fa fa-comments';
12189 $img_picto = '';
12190 $colorClass = '';
12191 $pictoTitle = '';
12192
12193 if ($histo[$key]['percent'] == -1) {
12194 $colorClass = 'timeline-icon-not-applicble';
12195 $pictoTitle = $langs->trans('StatusNotApplicable');
12196 } elseif ($histo[$key]['percent'] == 0) {
12197 $colorClass = 'timeline-icon-todo';
12198 $pictoTitle = $langs->trans('StatusActionToDo').' (0%)';
12199 } elseif ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100) {
12200 $colorClass = 'timeline-icon-in-progress';
12201 $pictoTitle = $langs->trans('StatusActionInProcess').' ('.$histo[$key]['percent'].'%)';
12202 } elseif ($histo[$key]['percent'] >= 100) {
12203 $colorClass = 'timeline-icon-done';
12204 $pictoTitle = $langs->trans('StatusActionDone').' (100%)';
12205 }
12206
12207 if ($actionstatic->code == 'AC_TICKET_CREATE') {
12208 $iconClass = 'fa fa-ticket';
12209 } elseif ($actionstatic->code == 'AC_TICKET_MODIFY') {
12210 $iconClass = 'fa fa-pencilxxx';
12211 } elseif (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12212 $iconClass = 'fa fa-comments';
12213 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12214 $iconClass = 'fa fa-mask';
12215 } elseif (!empty($conf->global->AGENDA_USE_EVENT_TYPE)) {
12216 if ($actionstatic->type_picto) {
12217 $img_picto = img_picto('', $actionstatic->type_picto);
12218 } else {
12219 if ($actionstatic->type_code == 'AC_RDV') {
12220 $iconClass = 'fa fa-handshake';
12221 } elseif ($actionstatic->type_code == 'AC_TEL') {
12222 $iconClass = 'fa fa-phone';
12223 } elseif ($actionstatic->type_code == 'AC_FAX') {
12224 $iconClass = 'fa fa-fax';
12225 } elseif ($actionstatic->type_code == 'AC_EMAIL') {
12226 $iconClass = 'fa fa-envelope';
12227 } elseif ($actionstatic->type_code == 'AC_INT') {
12228 $iconClass = 'fa fa-shipping-fast';
12229 } elseif ($actionstatic->type_code == 'AC_OTH_AUTO') {
12230 $iconClass = 'fa fa-robot';
12231 } elseif (!preg_match('/_AUTO/', $actionstatic->type_code)) {
12232 $iconClass = 'fa fa-robot';
12233 }
12234 }
12235 }
12236
12237 $out .= '<i class="'.$iconClass.' '.$colorClass.'" title="'.$pictoTitle.'">'.$img_picto.'</i>'."\n";
12238 return $out;
12239}
12240
12247function getActionCommEcmList($object)
12248{
12249 global $conf, $db;
12250
12251 $documents = array();
12252
12253 $sql = 'SELECT ecm.rowid as id, ecm.src_object_type, ecm.src_object_id, ecm.filepath, ecm.filename';
12254 $sql .= ' FROM '.MAIN_DB_PREFIX.'ecm_files ecm';
12255 $sql .= " WHERE ecm.filepath = 'agenda/".((int) $object->id)."'";
12256 //$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
12257 $sql .= ' ORDER BY ecm.position ASC';
12258
12259 $resql = $db->query($sql);
12260 if ($resql) {
12261 if ($db->num_rows($resql)) {
12262 while ($obj = $db->fetch_object($resql)) {
12263 $documents[$obj->id] = $obj;
12264 }
12265 }
12266 }
12267
12268 return $documents;
12269}
12270
12271
12272
12290function show_actions_messaging($conf, $langs, $db, $filterobj, $objcon = '', $noprint = 0, $actioncode = '', $donetodo = 'done', $filters = array(), $sortfield = 'a.datep,a.id', $sortorder = 'DESC')
12291{
12292 global $user, $conf;
12293 global $form;
12294
12295 global $param, $massactionbutton;
12296
12297 dol_include_once('/comm/action/class/actioncomm.class.php');
12298
12299 // Check parameters
12300 if (!is_object($filterobj) && !is_object($objcon)) {
12301 dol_print_error('', 'BadParameter');
12302 }
12303
12304 $histo = array();
12305 $numaction = 0;
12306 $now = dol_now();
12307
12308 $sortfield_list = explode(',', $sortfield);
12309 $sortfield_label_list = array('a.id' => 'id', 'a.datep' => 'dp', 'a.percent' => 'percent');
12310 $sortfield_new_list = array();
12311 foreach ($sortfield_list as $sortfield_value) {
12312 $sortfield_new_list[] = $sortfield_label_list[trim($sortfield_value)];
12313 }
12314 $sortfield_new = implode(',', $sortfield_new_list);
12315
12316 if (isModEnabled('agenda')) {
12317 // Search histo on actioncomm
12318 if (is_object($objcon) && $objcon->id > 0) {
12319 $sql = "SELECT DISTINCT a.id, a.label as label,";
12320 } else {
12321 $sql = "SELECT a.id, a.label as label,";
12322 }
12323 $sql .= " a.datep as dp,";
12324 $sql .= " a.note as message,";
12325 $sql .= " a.datep2 as dp2,";
12326 $sql .= " a.percent as percent, 'action' as type,";
12327 $sql .= " a.fk_element, a.elementtype,";
12328 $sql .= " a.fk_contact,";
12329 $sql .= " a.email_from as msg_from,";
12330 $sql .= " c.code as acode, c.libelle as alabel, c.picto as apicto,";
12331 $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";
12332 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12333 $sql .= ", sp.lastname, sp.firstname";
12334 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12335 $sql .= ", m.lastname, m.firstname";
12336 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12337 $sql .= ", o.ref";
12338 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12339 $sql .= ", o.ref";
12340 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12341 $sql .= ", o.ref";
12342 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12343 $sql .= ", o.ref";
12344 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12345 $sql .= ", o.ref";
12346 }
12347 $sql .= " FROM ".MAIN_DB_PREFIX."actioncomm as a";
12348 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u on u.rowid = a.fk_user_action";
12349 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_actioncomm as c ON a.fk_action = c.id";
12350
12351 $force_filter_contact = false;
12352 if (is_object($objcon) && $objcon->id > 0) {
12353 $force_filter_contact = true;
12354 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."actioncomm_resources as r ON a.id = r.fk_actioncomm";
12355 $sql .= " AND r.element_type = '".$db->escape($objcon->table_element)."' AND r.fk_element = ".((int) $objcon->id);
12356 }
12357
12358 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12359 $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."socpeople as sp ON a.fk_contact = sp.rowid";
12360 } elseif (is_object($filterobj) && get_class($filterobj) == 'Dolresource') {
12361 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."element_resources as er";
12362 $sql .= " ON er.resource_type = 'dolresource'";
12363 $sql .= " AND er.element_id = a.id";
12364 $sql .= " AND er.resource_id = ".((int) $filterobj->id);
12365 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12366 $sql .= ", ".MAIN_DB_PREFIX."adherent as m";
12367 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12368 $sql .= ", ".MAIN_DB_PREFIX."commande_fournisseur as o";
12369 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12370 $sql .= ", ".MAIN_DB_PREFIX."product as o";
12371 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12372 $sql .= ", ".MAIN_DB_PREFIX."ticket as o";
12373 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12374 $sql .= ", ".MAIN_DB_PREFIX."bom_bom as o";
12375 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12376 $sql .= ", ".MAIN_DB_PREFIX."contrat as o";
12377 }
12378
12379 $sql .= " WHERE a.entity IN (".getEntity('agenda').")";
12380 if ($force_filter_contact === false) {
12381 if (is_object($filterobj) && in_array(get_class($filterobj), array('Societe', 'Client', 'Fournisseur')) && $filterobj->id) {
12382 $sql .= " AND a.fk_soc = ".((int) $filterobj->id);
12383 } elseif (is_object($filterobj) && get_class($filterobj) == 'Project' && $filterobj->id) {
12384 $sql .= " AND a.fk_project = ".((int) $filterobj->id);
12385 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12386 $sql .= " AND a.fk_element = m.rowid AND a.elementtype = 'member'";
12387 if ($filterobj->id) {
12388 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12389 }
12390 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12391 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'order_supplier'";
12392 if ($filterobj->id) {
12393 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12394 }
12395 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12396 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'product'";
12397 if ($filterobj->id) {
12398 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12399 }
12400 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12401 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'ticket'";
12402 if ($filterobj->id) {
12403 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12404 }
12405 } elseif (is_object($filterobj) && get_class($filterobj) == 'BOM') {
12406 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'bom'";
12407 if ($filterobj->id) {
12408 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12409 }
12410 } elseif (is_object($filterobj) && get_class($filterobj) == 'Contrat') {
12411 $sql .= " AND a.fk_element = o.rowid AND a.elementtype = 'contract'";
12412 if ($filterobj->id) {
12413 $sql .= " AND a.fk_element = ".((int) $filterobj->id);
12414 }
12415 }
12416 }
12417
12418 // Condition on actioncode
12419 if (!empty($actioncode)) {
12420 if (empty($conf->global->AGENDA_USE_EVENT_TYPE)) {
12421 if ($actioncode == 'AC_NON_AUTO') {
12422 $sql .= " AND c.type != 'systemauto'";
12423 } elseif ($actioncode == 'AC_ALL_AUTO') {
12424 $sql .= " AND c.type = 'systemauto'";
12425 } else {
12426 if ($actioncode == 'AC_OTH') {
12427 $sql .= " AND c.type != 'systemauto'";
12428 } elseif ($actioncode == 'AC_OTH_AUTO') {
12429 $sql .= " AND c.type = 'systemauto'";
12430 }
12431 }
12432 } else {
12433 if ($actioncode == 'AC_NON_AUTO') {
12434 $sql .= " AND c.type != 'systemauto'";
12435 } elseif ($actioncode == 'AC_ALL_AUTO') {
12436 $sql .= " AND c.type = 'systemauto'";
12437 } else {
12438 $sql .= " AND c.code = '".$db->escape($actioncode)."'";
12439 }
12440 }
12441 }
12442 if ($donetodo == 'todo') {
12443 $sql .= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
12444 } elseif ($donetodo == 'done') {
12445 $sql .= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
12446 }
12447 if (is_array($filters) && $filters['search_agenda_label']) {
12448 $sql .= natural_search('a.label', $filters['search_agenda_label']);
12449 }
12450 }
12451
12452 // Add also event from emailings. TODO This should be replaced by an automatic event ? May be it's too much for very large emailing.
12453 if (isModEnabled('mailing') && !empty($objcon->email)
12454 && (empty($actioncode) || $actioncode == 'AC_OTH_AUTO' || $actioncode == 'AC_EMAILING')) {
12455 $langs->load("mails");
12456
12457 $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";
12458 $sql2 .= ", null as fk_element, '' as elementtype, null as contact_id";
12459 $sql2 .= ", 'AC_EMAILING' as acode, '' as alabel, '' as apicto";
12460 $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
12461 if (is_object($filterobj) && get_class($filterobj) == 'Societe') {
12462 $sql2 .= ", '' as lastname, '' as firstname";
12463 } elseif (is_object($filterobj) && get_class($filterobj) == 'Adherent') {
12464 $sql2 .= ", '' as lastname, '' as firstname";
12465 } elseif (is_object($filterobj) && get_class($filterobj) == 'CommandeFournisseur') {
12466 $sql2 .= ", '' as ref";
12467 } elseif (is_object($filterobj) && get_class($filterobj) == 'Product') {
12468 $sql2 .= ", '' as ref";
12469 } elseif (is_object($filterobj) && get_class($filterobj) == 'Ticket') {
12470 $sql2 .= ", '' as ref";
12471 }
12472 $sql2 .= " FROM ".MAIN_DB_PREFIX."mailing as m, ".MAIN_DB_PREFIX."mailing_cibles as mc, ".MAIN_DB_PREFIX."user as u";
12473 $sql2 .= " WHERE mc.email = '".$db->escape($objcon->email)."'"; // Search is done on email.
12474 $sql2 .= " AND mc.statut = 1";
12475 $sql2 .= " AND u.rowid = m.fk_user_valid";
12476 $sql2 .= " AND mc.fk_mailing=m.rowid";
12477 }
12478
12479 if (!empty($sql) && !empty($sql2)) {
12480 $sql = $sql." UNION ".$sql2;
12481 } elseif (empty($sql) && !empty($sql2)) {
12482 $sql = $sql2;
12483 }
12484
12485 // TODO Add limit in nb of results
12486 if ($sql) { // May not be defined if module Agenda is not enabled and mailing module disabled too
12487 $sql .= $db->order($sortfield_new, $sortorder);
12488
12489 dol_syslog("function.lib::show_actions_messaging", LOG_DEBUG);
12490 $resql = $db->query($sql);
12491 if ($resql) {
12492 $i = 0;
12493 $num = $db->num_rows($resql);
12494
12495 while ($i < $num) {
12496 $obj = $db->fetch_object($resql);
12497
12498 if ($obj->type == 'action') {
12499 $contactaction = new ActionComm($db);
12500 $contactaction->id = $obj->id;
12501 $result = $contactaction->fetchResources();
12502 if ($result < 0) {
12503 dol_print_error($db);
12504 setEventMessage("actions.lib::show_actions_messaging Error fetch ressource", 'errors');
12505 }
12506
12507 //if ($donetodo == 'todo') $sql.= " AND ((a.percent >= 0 AND a.percent < 100) OR (a.percent = -1 AND a.datep > '".$db->idate($now)."'))";
12508 //elseif ($donetodo == 'done') $sql.= " AND (a.percent = 100 OR (a.percent = -1 AND a.datep <= '".$db->idate($now)."'))";
12509 $tododone = '';
12510 if (($obj->percent >= 0 and $obj->percent < 100) || ($obj->percent == -1 && $obj->dp > $now)) {
12511 $tododone = 'todo';
12512 }
12513
12514 $histo[$numaction] = array(
12515 'type'=>$obj->type,
12516 'tododone'=>$tododone,
12517 'id'=>$obj->id,
12518 'datestart'=>$db->jdate($obj->dp),
12519 'dateend'=>$db->jdate($obj->dp2),
12520 'note'=>$obj->label,
12521 'message'=>$obj->message,
12522 'percent'=>$obj->percent,
12523
12524 'userid'=>$obj->user_id,
12525 'login'=>$obj->user_login,
12526 'userfirstname'=>$obj->user_firstname,
12527 'userlastname'=>$obj->user_lastname,
12528 'userphoto'=>$obj->user_photo,
12529 'msg_from'=>$obj->msg_from,
12530
12531 'contact_id'=>$obj->fk_contact,
12532 'socpeopleassigned' => $contactaction->socpeopleassigned,
12533 'lastname' => (empty($obj->lastname) ? '' : $obj->lastname),
12534 'firstname' => (empty($obj->firstname) ? '' : $obj->firstname),
12535 'fk_element'=>$obj->fk_element,
12536 'elementtype'=>$obj->elementtype,
12537 // Type of event
12538 'acode'=>$obj->acode,
12539 'alabel'=>$obj->alabel,
12540 'libelle'=>$obj->alabel, // deprecated
12541 'apicto'=>$obj->apicto
12542 );
12543 } else {
12544 $histo[$numaction] = array(
12545 'type'=>$obj->type,
12546 'tododone'=>'done',
12547 'id'=>$obj->id,
12548 'datestart'=>$db->jdate($obj->dp),
12549 'dateend'=>$db->jdate($obj->dp2),
12550 'note'=>$obj->label,
12551 'message'=>$obj->message,
12552 'percent'=>$obj->percent,
12553 'acode'=>$obj->acode,
12554
12555 'userid'=>$obj->user_id,
12556 'login'=>$obj->user_login,
12557 'userfirstname'=>$obj->user_firstname,
12558 'userlastname'=>$obj->user_lastname,
12559 'userphoto'=>$obj->user_photo
12560 );
12561 }
12562
12563 $numaction++;
12564 $i++;
12565 }
12566 } else {
12567 dol_print_error($db);
12568 }
12569 }
12570
12571 // Set $out to show events
12572 $out = '';
12573
12574 if (!isModEnabled('agenda')) {
12575 $langs->loadLangs(array("admin", "errors"));
12576 $out = info_admin($langs->trans("WarningModuleXDisabledSoYouMayMissEventHere", $langs->transnoentitiesnoconv("Module2400Name")), 0, 0, 'warning');
12577 }
12578
12579 if (isModEnabled('agenda') || (isModEnabled('mailing') && !empty($objcon->email))) {
12580 $delay_warning = $conf->global->MAIN_DELAY_ACTIONS_TODO * 24 * 60 * 60;
12581
12582 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
12583 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
12584 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
12585 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
12586
12587 $formactions = new FormActions($db);
12588
12589 $actionstatic = new ActionComm($db);
12590 $userstatic = new User($db);
12591 $contactstatic = new Contact($db);
12592 $userGetNomUrlCache = array();
12593 $contactGetNomUrlCache = array();
12594
12595 $out .= '<div class="filters-container" >';
12596 $out .= '<form name="listactionsfilter" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'" method="POST">';
12597 $out .= '<input type="hidden" name="token" value="'.newToken().'">';
12598
12599 if ($objcon && get_class($objcon) == 'Contact' &&
12600 (is_null($filterobj) || get_class($filterobj) == 'Societe')) {
12601 $out .= '<input type="hidden" name="id" value="'.$objcon->id.'" />';
12602 } else {
12603 $out .= '<input type="hidden" name="id" value="'.$filterobj->id.'" />';
12604 }
12605 if ($filterobj && get_class($filterobj) == 'Societe') {
12606 $out .= '<input type="hidden" name="socid" value="'.$filterobj->id.'" />';
12607 }
12608
12609 $out .= "\n";
12610
12611 $out .= '<div class="div-table-responsive-no-min">';
12612 $out .= '<table class="noborder borderbottom centpercent">';
12613
12614 $out .= '<tr class="liste_titre">';
12615
12616 // Action column
12617 if (getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
12618 $out .= '<th class="liste_titre width50 middle">';
12619 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
12620 $out .= $searchpicto;
12621 $out .= '</th>';
12622 }
12623
12624 $out .= getTitleFieldOfList('Date', 0, $_SERVER["PHP_SELF"], 'a.datep', '', $param, '', $sortfield, $sortorder, '')."\n";
12625
12626 $out .= '<th class="liste_titre"><strong class="hideonsmartphone">'.$langs->trans("Search").' : </strong></th>';
12627 if ($donetodo) {
12628 $out .= '<th class="liste_titre"></th>';
12629 }
12630 $out .= '<th class="liste_titre">';
12631 $out .= '<span class="fas fa-square inline-block fawidth30" style=" color: #ddd;" title="'.$langs->trans("ActionType").'"></span>';
12632 //$out .= img_picto($langs->trans("Type"), 'type');
12633 $out .= $formactions->select_type_actions($actioncode, "actioncode", '', empty($conf->global->AGENDA_USE_EVENT_TYPE) ? 1 : -1, 0, 0, 1, 'minwidth200imp');
12634 $out .= '</th>';
12635 $out .= '<th class="liste_titre maxwidth100onsmartphone">';
12636 $out .= '<input type="text" class="maxwidth100onsmartphone" name="search_agenda_label" value="'.$filters['search_agenda_label'].'" placeholder="'.$langs->trans("Label").'">';
12637 $out .= '</th>';
12638
12639 // Action column
12640 if (!getDolGlobalString('MAIN_CHECKBOX_LEFT_COLUMN')) {
12641 $out .= '<th class="liste_titre width50 middle">';
12642 $searchpicto = $form->showFilterAndCheckAddButtons($massactionbutton ? 1 : 0, 'checkforselect', 1);
12643 $out .= $searchpicto;
12644 $out .= '</th>';
12645 }
12646
12647 $out .= '</tr>';
12648
12649
12650 $out .= '</table>';
12651
12652 $out .= '</form>';
12653 $out .= '</div>';
12654
12655 $out .= "\n";
12656
12657 $out .= '<ul class="timeline">';
12658
12659 if ($donetodo) {
12660 $tmp = '';
12661 if (get_class($filterobj) == 'Societe') {
12662 $tmp .= '<a href="'.DOL_URL_ROOT.'/comm/action/list.php?mode=show_list&socid='.$filterobj->id.'&status=done">';
12663 }
12664 $tmp .= ($donetodo != 'done' ? $langs->trans("ActionsToDoShort") : '');
12665 $tmp .= ($donetodo != 'done' && $donetodo != 'todo' ? ' / ' : '');
12666 $tmp .= ($donetodo != 'todo' ? $langs->trans("ActionsDoneShort") : '');
12667 //$out.=$langs->trans("ActionsToDoShort").' / '.$langs->trans("ActionsDoneShort");
12668 if (get_class($filterobj) == 'Societe') {
12669 $tmp .= '</a>';
12670 }
12671 $out .= getTitleFieldOfList($tmp);
12672 }
12673
12674
12675 //require_once DOL_DOCUMENT_ROOT.'/comm/action/class/cactioncomm.class.php';
12676 //$caction=new CActionComm($db);
12677 //$arraylist=$caction->liste_array(1, 'code', '', (empty($conf->global->AGENDA_USE_EVENT_TYPE)?1:0), '', 1);
12678
12679 $actualCycleDate = false;
12680
12681 // Loop on each event to show it
12682 foreach ($histo as $key => $value) {
12683 $actionstatic->fetch($histo[$key]['id']); // TODO Do we need this, we already have a lot of data of line into $histo
12684
12685 $actionstatic->type_picto = $histo[$key]['apicto'];
12686 $actionstatic->type_code = $histo[$key]['acode'];
12687
12688 $url = DOL_URL_ROOT.'/comm/action/card.php?id='.$histo[$key]['id'];
12689
12690 $tmpa = dol_getdate($histo[$key]['datestart'], false);
12691 if ($actualCycleDate !== $tmpa['year'].'-'.$tmpa['yday']) {
12692 $actualCycleDate = $tmpa['year'].'-'.$tmpa['yday'];
12693 $out .= '<!-- timeline time label -->';
12694 $out .= '<li class="time-label">';
12695 $out .= '<span class="timeline-badge-date">';
12696 $out .= dol_print_date($histo[$key]['datestart'], 'daytext', 'tzuserrel', $langs);
12697 $out .= '</span>';
12698 $out .= '</li>';
12699 $out .= '<!-- /.timeline-label -->';
12700 }
12701
12702
12703 $out .= '<!-- timeline item -->'."\n";
12704 $out .= '<li class="timeline-code-'.strtolower($actionstatic->code).'">';
12705
12706 $out .= getTimelineIcon($actionstatic, $histo, $key);
12707
12708 $out .= '<div class="timeline-item">'."\n";
12709
12710 $out .= '<span class="timeline-header-action">';
12711
12712 if (isset($histo[$key]['type']) && $histo[$key]['type'] == 'mailing') {
12713 $out .= '<a class="timeline-btn" href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
12714 $out .= $histo[$key]['id'];
12715 $out .= '</a> ';
12716 } else {
12717 $out .= $actionstatic->getNomUrl(1, -1, 'valignmiddle').' ';
12718 }
12719
12720 if ($user->hasRight('agenda', 'allactions', 'create') ||
12721 (($actionstatic->authorid == $user->id || $actionstatic->userownerid == $user->id) && $user->hasRight('agenda', 'myactions', 'create'))) {
12722 $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>';
12723 }
12724
12725 $out .= '</span>';
12726 // Date
12727 $out .= '<span class="time"><i class="fa fa-clock-o valignmiddle"></i> <span class="valignmiddle">';
12728 $out .= dol_print_date($histo[$key]['datestart'], 'dayhour', 'tzuserrel');
12729 if ($histo[$key]['dateend'] && $histo[$key]['dateend'] != $histo[$key]['datestart']) {
12730 $tmpa = dol_getdate($histo[$key]['datestart'], true);
12731 $tmpb = dol_getdate($histo[$key]['dateend'], true);
12732 if ($tmpa['mday'] == $tmpb['mday'] && $tmpa['mon'] == $tmpb['mon'] && $tmpa['year'] == $tmpb['year']) {
12733 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'hour', 'tzuserrel');
12734 } else {
12735 $out .= '-'.dol_print_date($histo[$key]['dateend'], 'dayhour', 'tzuserrel');
12736 }
12737 }
12738 $late = 0;
12739 if ($histo[$key]['percent'] == 0 && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12740 $late = 1;
12741 }
12742 if ($histo[$key]['percent'] == 0 && !$histo[$key]['datestart'] && $histo[$key]['dateend'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12743 $late = 1;
12744 }
12745 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && $histo[$key]['dateend'] && $histo[$key]['dateend'] < ($now - $delay_warning)) {
12746 $late = 1;
12747 }
12748 if ($histo[$key]['percent'] > 0 && $histo[$key]['percent'] < 100 && !$histo[$key]['dateend'] && $histo[$key]['datestart'] && $histo[$key]['datestart'] < ($now - $delay_warning)) {
12749 $late = 1;
12750 }
12751 if ($late) {
12752 $out .= img_warning($langs->trans("Late")).' ';
12753 }
12754 $out .= "</span></span>\n";
12755
12756 // Ref
12757 $out .= '<h3 class="timeline-header">';
12758
12759 // Author of event
12760 $out .= '<div class="messaging-author inline-block tdoverflowmax150 valignmiddle marginrightonly">';
12761 if ($histo[$key]['userid'] > 0) {
12762 if (!isset($userGetNomUrlCache[$histo[$key]['userid']])) { // is in cache ?
12763 $userstatic->fetch($histo[$key]['userid']);
12764 $userGetNomUrlCache[$histo[$key]['userid']] = $userstatic->getNomUrl(-1, '', 0, 0, 16, 0, 'firstelselast', '');
12765 }
12766 $out .= $userGetNomUrlCache[$histo[$key]['userid']];
12767 } elseif (!empty($histo[$key]['msg_from']) && $actionstatic->code == 'TICKET_MSG') {
12768 if (!isset($contactGetNomUrlCache[$histo[$key]['msg_from']])) {
12769 if ($contactstatic->fetch(0, null, '', $histo[$key]['msg_from']) > 0) {
12770 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $contactstatic->getNomUrl(-1, '', 16);
12771 } else {
12772 $contactGetNomUrlCache[$histo[$key]['msg_from']] = $histo[$key]['msg_from'];
12773 }
12774 }
12775 $out .= $contactGetNomUrlCache[$histo[$key]['msg_from']];
12776 }
12777 $out .= '</div>';
12778
12779 // Title
12780 $libelle = '';
12781 $out .= ' <div class="messaging-title inline-block">';
12782
12783 if (preg_match('/^TICKET_MSG/', $actionstatic->code)) {
12784 $out .= $langs->trans('TicketNewMessage');
12785 } elseif (preg_match('/^TICKET_MSG_PRIVATE/', $actionstatic->code)) {
12786 $out .= $langs->trans('TicketNewMessage').' <em>('.$langs->trans('Private').')</em>';
12787 } elseif (isset($histo[$key]['type'])) {
12788 if ($histo[$key]['type'] == 'action') {
12789 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
12790 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : $histo[$key]['alabel']);
12791 $libelle = $histo[$key]['note'];
12792 $actionstatic->id = $histo[$key]['id'];
12793 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12794 } elseif ($histo[$key]['type'] == 'mailing') {
12795 $out .= '<a href="'.DOL_URL_ROOT.'/comm/mailing/card.php?id='.$histo[$key]['id'].'">'.img_object($langs->trans("ShowEMailing"), "email").' ';
12796 $transcode = $langs->transnoentitiesnoconv("Action".$histo[$key]['acode']);
12797 $libelle = ($transcode != "Action".$histo[$key]['acode'] ? $transcode : 'Send mass mailing');
12798 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12799 } else {
12800 $libelle .= $histo[$key]['note'];
12801 $out .= dol_escape_htmltag(dol_trunc($libelle, 120));
12802 }
12803 }
12804
12805 $out .= '</div>';
12806
12807 $out .= '</h3>';
12808
12809 if (!empty($histo[$key]['message'] && $histo[$key]['message'] != $libelle)
12810 && $actionstatic->code != 'AC_TICKET_CREATE'
12811 && $actionstatic->code != 'AC_TICKET_MODIFY'
12812 ) {
12813 $out .= '<div class="timeline-body">';
12814 $out .= $histo[$key]['message'];
12815 $out .= '</div>';
12816 }
12817
12818 // Timeline footer
12819 $footer = '';
12820
12821 // Contact for this action
12822 if (isset($histo[$key]['socpeopleassigned']) && is_array($histo[$key]['socpeopleassigned']) && count($histo[$key]['socpeopleassigned']) > 0) {
12823 $contactList = '';
12824 foreach ($histo[$key]['socpeopleassigned'] as $cid => $Tab) {
12825 $contact = new Contact($db);
12826 $result = $contact->fetch($cid);
12827
12828 if ($result < 0) {
12829 dol_print_error($db, $contact->error);
12830 }
12831
12832 if ($result > 0) {
12833 $contactList .= !empty($contactList) ? ', ' : '';
12834 $contactList .= $contact->getNomUrl(1);
12835 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
12836 if (!empty($contact->phone_pro)) {
12837 $contactList .= '('.dol_print_phone($contact->phone_pro).')';
12838 }
12839 }
12840 }
12841 }
12842
12843 $footer .= $langs->trans('ActionOnContact').' : '.$contactList;
12844 } elseif (empty($objcon->id) && isset($histo[$key]['contact_id']) && $histo[$key]['contact_id'] > 0) {
12845 $contact = new Contact($db);
12846 $result = $contact->fetch($histo[$key]['contact_id']);
12847
12848 if ($result < 0) {
12849 dol_print_error($db, $contact->error);
12850 }
12851
12852 if ($result > 0) {
12853 $footer .= $contact->getNomUrl(1);
12854 if (isset($histo[$key]['acode']) && $histo[$key]['acode'] == 'AC_TEL') {
12855 if (!empty($contact->phone_pro)) {
12856 $footer .= '('.dol_print_phone($contact->phone_pro).')';
12857 }
12858 }
12859 }
12860 }
12861
12862 $documents = getActionCommEcmList($actionstatic);
12863 if (!empty($documents)) {
12864 $footer .= '<div class="timeline-documents-container">';
12865 foreach ($documents as $doc) {
12866 $footer .= '<span id="document_'.$doc->id.'" class="timeline-documents" ';
12867 $footer .= ' data-id="'.$doc->id.'" ';
12868 $footer .= ' data-path="'.$doc->filepath.'"';
12869 $footer .= ' data-filename="'.dol_escape_htmltag($doc->filename).'" ';
12870 $footer .= '>';
12871
12872 $filePath = DOL_DATA_ROOT.'/'.$doc->filepath.'/'.$doc->filename;
12873 $mime = dol_mimetype($filePath);
12874 $file = $actionstatic->id.'/'.$doc->filename;
12875 $thumb = $actionstatic->id.'/thumbs/'.substr($doc->filename, 0, strrpos($doc->filename, '.')).'_mini'.substr($doc->filename, strrpos($doc->filename, '.'));
12876 $doclink = dol_buildpath('document.php', 1).'?modulepart=actions&attachment=0&file='.urlencode($file).'&entity='.$conf->entity;
12877 $viewlink = dol_buildpath('viewimage.php', 1).'?modulepart=actions&file='.urlencode($thumb).'&entity='.$conf->entity;
12878
12879 $mimeAttr = ' mime="'.$mime.'" ';
12880 $class = '';
12881 if (in_array($mime, array('image/png', 'image/jpeg', 'application/pdf'))) {
12882 $class .= ' documentpreview';
12883 }
12884
12885 $footer .= '<a href="'.$doclink.'" class="btn-link '.$class.'" target="_blank" rel="noopener noreferrer" '.$mimeAttr.' >';
12886 $footer .= img_mime($filePath).' '.$doc->filename;
12887 $footer .= '</a>';
12888
12889 $footer .= '</span>';
12890 }
12891 $footer .= '</div>';
12892 }
12893
12894 if (!empty($footer)) {
12895 $out .= '<div class="timeline-footer">'.$footer.'</div>';
12896 }
12897
12898 $out .= '</div>'."\n"; // end timeline-item
12899
12900 $out .= '</li>';
12901 $out .= '<!-- END timeline item -->';
12902
12903 $i++;
12904 }
12905
12906 $out .= "</ul>\n";
12907
12908 if (empty($histo)) {
12909 $out .= '<span class="opacitymedium">'.$langs->trans("NoRecordFound").'</span>';
12910 }
12911 }
12912
12913 if ($noprint) {
12914 return $out;
12915 } else {
12916 print $out;
12917 }
12918}
12919
12930function GETPOSTDATE($prefix, $hourTime = '', $gm = 'auto')
12931{
12932 if ($hourTime === 'getpost') {
12933 $hour = GETPOSTINT($prefix . 'hour');
12934 $minute = GETPOSTINT($prefix . 'minute');
12935 $second = GETPOSTINT($prefix . 'second');
12936 } elseif (preg_match('/^(\d\d):(\d\d):(\d\d)$/', $hourTime, $m)) {
12937 $hour = intval($m[1]);
12938 $minute = intval($m[2]);
12939 $second = intval($m[3]);
12940 } else {
12941 $hour = $minute = $second = 0;
12942 }
12943 // normalize out of range values
12944 $hour = min($hour, 23);
12945 $minute = min($minute, 59);
12946 $second = min($second, 59);
12947 return dol_mktime($hour, $minute, $second, GETPOSTINT($prefix . 'month'), GETPOSTINT($prefix . 'day'), GETPOSTINT($prefix . 'year'), $gm);
12948}
12949
12961function buildParamDate($prefix, $timestamp = null, $hourTime = '', $gm = 'auto')
12962{
12963 if ($timestamp === null) $timestamp = GETPOSTDATE($prefix, $hourTime, $gm);
12964 $TParam = array(
12965 $prefix . 'day' => intval(dol_print_date($timestamp, '%d')),
12966 $prefix . 'month' => intval(dol_print_date($timestamp, '%m')),
12967 $prefix . 'year' => intval(dol_print_date($timestamp, '%Y')),
12968 );
12969 if ($hourTime === 'getpost' || ($timestamp !== null && dol_print_date($timestamp, '%H:%M:%S') !== '00:00:00')) {
12970 $TParam = array_merge($TParam, array(
12971 $prefix . 'hour' => intval(dol_print_date($timestamp, '%H')),
12972 $prefix . 'minute' => intval(dol_print_date($timestamp, '%M')),
12973 $prefix . 'second' => intval(dol_print_date($timestamp, '%S'))
12974 ));
12975 }
12976
12977 return '&' . http_build_query($TParam);
12978}
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.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
dol_shutdown()
Function called at end of web php process.
dol_print_address($address, $htmlid, $element, $id, $noprint=0, $charfornl='')
Format address string.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
dol_print_error_email($prefixcode, $errormessage='', $errormessages=array(), $morecss='error', $email='')
Show a public email and error code to contact if technical error.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='float')
Show Url link.
print_barre_liste($titre, $page, $file, $options='', $sortfield='', $sortorder='', $morehtmlcenter='', $num=-1, $totalnboflines='', $picto='generic', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limit=-1, $hideselectlimit=0, $hidenavigation=0, $pagenavastextinput=0, $morehtmlrightbeforearrow='')
Print a title with navigation controls for pagination.
dol_bc($var, $moreclass='')
Return string to add class property on html element with pair/impair.
print_titre($title)
Show a title.
getElementProperties($element_type)
Get an array with properties of an element.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_string_nounprintableascii($str, $removetabcrlf=1)
Clean a string from all non printable ASCII chars (0x00-0x1F and 0x7F).
get_localtax($vatrate, $local, $thirdparty_buyer="", $thirdparty_seller="", $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
img_error($titlealt='default')
Show error logo.
getTimelineIcon($actionstatic, &$histo, $key)
Get timeline icon.
dol_htmloutput_mesg($mesgstring='', $mesgarray=array(), $style='ok', $keepembedded=0)
Print formated messages to output (Used to show messages on html output).
dol_sanitizeFileName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a file name.
buildParamDate($prefix, $timestamp=null, $hourTime='', $gm='auto')
Helper function that combines values of a dolibarr DatePicker (such as Form\selectDate) for year,...
img_next($titlealt='default', $moreatt='')
Show next logo.
print_date_range($date_start, $date_end, $format='', $outputlangs='')
Format output for start and end date.
isAFileWithExecutableContent($filename)
Return if a file can contains executable content.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_string_is_good_iso($s, $clean=0)
Check if a string is a correct iso string If not, it will not be considered as HTML encoded even if i...
getNonce()
Return a random string to be used as a nonce value for js.
complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode='add', $filterorigmodule='')
Complete or removed entries into a head array (used to build tabs).
dol_htmlentitiesbr($stringtoencode, $nl2brmode=0, $pagecodefrom='UTF-8', $removelasteolbr=1)
This function is called to encode a string into a HTML string but differs from htmlentities because a...
get_product_localtax_for_country($idprod, $local, $thirdpartytouse)
Return localtax vat rate of a product in a particular country or default country vat if product is un...
getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $object=null, $include=null)
Return array of possible common substitutions.
dol_nboflines($s, $maxchar=0)
Return nb of lines of a clear text.
dol_htmlwithnojs($stringtoencode, $nouseofiframesandbox=0, $check='restricthtml')
Sanitize a HTML to remove js and dangerous content.
jsonOrUnserialize($stringtodecode)
Decode an encode string.
addSummaryTableLine($tableColumnCount, $num, $nbofloop=0, $total=0, $noneWord="None", $extraRightColumn=false)
Add a summary line to the current open table ("None", "XMoreLines" or "Total xxx")
isValidEmail($address, $acceptsupervisorkey=0, $acceptuserkey=0)
Return true if email syntax is ok.
getActionCommEcmList($object)
getActionCommEcmList
dol_ucwords($string, $encoding="UTF-8")
Convert first character of all the words of a string to upper.
img_edit_add($titlealt='default', $other='')
Show logo +.
verifCond($strToEvaluate)
Verify if condition in string is ok or not.
if(!function_exists( 'utf8_encode')) if(!function_exists('utf8_decode')) if(!function_exists( 'str_starts_with')) if(!function_exists('str_ends_with')) if(!function_exists( 'str_contains')) getMultidirOutput($object, $module='')
Return the full path of the directory where a module (or an object of a module) stores its files.
print_fiche_titre($title, $mesg='', $picto='generic', $pictoisfullpath=0, $id='')
Show a title with picto.
get_product_vat_for_country($idprod, $thirdpartytouse, $idprodfournprice=0)
Return vat rate of a product in a particular country, or default country vat if product is unknown.
dolForgeDummyCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
dol_escape_json($stringtoescape)
Returns text escaped for inclusion into javascript code.
dolForgeCriteriaCallback($matches)
Function to forge a SQL criteria from a Dolibarr filter syntax string.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
getUserRemoteIP()
Return the IP of remote user.
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.
dol_validElement($element)
Return if var element is ok.
img_credit_card($brand, $morecss=null)
Return image of a credit card according to its brand name.
dolPrintHTML($s)
Return a string ready to be output on HTML page To use text inside an attribute, use can use only dol...
img_searchclear($titlealt='default', $other='')
Show search logo.
dolPrintLabel($s)
Return a string label ready to be output on HTML content To use text inside an attribute,...
fetchObjectByElement($element_id, $element_type, $element_ref='')
Fetch an object from its id and element_type Inclusion of classes is automatic.
utf8_check($str)
Check if a string is in UTF8.
img_edit($titlealt='default', $float=0, $other='')
Show logo editer/modifier fiche.
show_actions_messaging($conf, $langs, $db, $filterobj, $objcon='', $noprint=0, $actioncode='', $donetodo='done', $filters=array(), $sortfield='a.datep, a.id', $sortorder='DESC')
Show html area with actions in messaging format.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
img_up($titlealt='default', $selected=0, $moreclass='')
Show top arrow logo.
dol_htmloutput_errors($mesgstring='', $mesgarray=array(), $keepembedded=0)
Print formated error messages to output (Used to show messages on html output).
getFieldErrorIcon($fieldValidationErrorMsg)
get field error icon
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
dol_sanitizePathName($str, $newstr='_', $unaccent=1)
Clean a string to use it as a path name.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
dol_mkdir($dir, $dataroot='', $newmask='')
Creation of a directory (this can create recursive subdir)
img_edit_remove($titlealt='default', $other='')
Show logo -.
img_info($titlealt='default')
Show info logo.
getDoliDBInstance($type, $host, $user, $pass, $name, $port)
Return a DoliDB instance (database handler).
dol_sanitizeEmail($stringtoclean)
Clean a string to use it as an Email.
dol_nboflines_bis($text, $maxlinesize=0, $charset='UTF-8')
Return nb of lines of a formated text with and (WARNING: string must not have mixed and br sepa...
dolPrintHTMLForTextArea($s)
Return a string ready to be output on input textarea To use text inside an attribute,...
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
dol_convertToWord($num, $langs, $currency='', $centimes=false)
Function to return a number into a text.
conf($dolibarr_main_document_root)
Load conf file (file must exists)
Definition inc.php:400
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1632
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
if(!defined( 'NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
if(!empty( $_SERVER[ 'MAIN_SHOW_TUNING_INFO'])) realCharForNumericEntities($matches)
Return the real char for a numeric entities.
Definition main.inc.php:63
dol_setcache($memoryid, $data, $expire=0)
Save data into a memory area shared by all users, all sessions on server.
dol_getcache($memoryid)
Read a memory area shared by all users, all sessions on server.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:120
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:123
dolGetRandomBytes($length)
Return a string of random bytes (hexa string) with length = $length fro cryptographic purposes.