dolibarr  18.0.0-beta
main.inc.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3  * Copyright (C) 2003 Xavier Dutoit <doli@sydesy.com>
4  * Copyright (C) 2004-2021 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) 2005-2021 Regis Houssin <regis.houssin@inodbox.com>
8  * Copyright (C) 2011-2014 Philippe Grand <philippe.grand@atoo-net.com>
9  * Copyright (C) 2008 Matteli
10  * Copyright (C) 2011-2016 Juanjo Menent <jmenent@2byte.es>
11  * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
12  * Copyright (C) 2014-2015 Marcos García <marcosgdf@gmail.com>
13  * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
14  * Copyright (C) 2020 Demarest Maxime <maxime@indelog.fr>
15  * Copyright (C) 2020 Charlene Benke <charlie@patas-monkey.com>
16  * Copyright (C) 2021 Frédéric France <frederic.france@netlogic.fr>
17  * Copyright (C) 2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
18  * Copyright (C) 2023 Joachim Küter <git-jk@bloxera.com>
19  * Copyright (C) 2023 Eric Seigne <eric.seigne@cap-rel.fr>
20  *
21  * This program is free software; you can redistribute it and/or modify
22  * it under the terms of the GNU General Public License as published by
23  * the Free Software Foundation; either version 3 of the License, or
24  * (at your option) any later version.
25  *
26  * This program is distributed in the hope that it will be useful,
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29  * GNU General Public License for more details.
30  *
31  * You should have received a copy of the GNU General Public License
32  * along with this program. If not, see <https://www.gnu.org/licenses/>.
33  */
34 
41 //@ini_set('memory_limit', '128M'); // This may be useless if memory is hard limited by your PHP
42 
43 // For optional tuning. Enabled if environment variable MAIN_SHOW_TUNING_INFO is defined.
44 $micro_start_time = 0;
45 if (!empty($_SERVER['MAIN_SHOW_TUNING_INFO'])) {
46  list($usec, $sec) = explode(" ", microtime());
47  $micro_start_time = ((float) $usec + (float) $sec);
48  // Add Xdebug code coverage
49  //define('XDEBUGCOVERAGE',1);
50  if (defined('XDEBUGCOVERAGE')) {
51  xdebug_start_code_coverage();
52  }
53 }
54 
55 
63 function realCharForNumericEntities($matches)
64 {
65  $newstringnumentity = preg_replace('/;$/', '', $matches[1]);
66  //print ' $newstringnumentity='.$newstringnumentity;
67 
68  if (preg_match('/^x/i', $newstringnumentity)) {
69  $newstringnumentity = hexdec(preg_replace('/^x/i', '', $newstringnumentity));
70  }
71 
72  // The numeric value we don't want as entities because they encode ascii char, and why using html entities on ascii except for haking ?
73  if (($newstringnumentity >= 65 && $newstringnumentity <= 90) || ($newstringnumentity >= 97 && $newstringnumentity <= 122)) {
74  return chr((int) $newstringnumentity);
75  }
76 
77  return '&#'.$matches[1]; // Value will be unchanged because regex was /&#( )/
78 }
79 
89 function testSqlAndScriptInject($val, $type)
90 {
91  // Decode string first because a lot of things are obfuscated by encoding or multiple encoding.
92  // So <svg o&#110;load='console.log(&quot;123&quot;)' become <svg onload='console.log(&quot;123&quot;)'
93  // So "&colon;&apos;" become ":'" (due to ENT_HTML5)
94  // So "&Tab;&NewLine;" become ""
95  // So "&lpar;&rpar;" become "()"
96 
97  // Loop to decode until no more things to decode.
98  //print "before decoding $val\n";
99  do {
100  $oldval = $val;
101  $val = html_entity_decode($val, ENT_QUOTES | ENT_HTML5); // Decode '&colon;', '&apos;', '&Tab;', '&NewLine', ...
102  // Sometimes we have entities without the ; at end so html_entity_decode does not work but entities is still interpreted by browser.
103  $val = preg_replace_callback('/&#(x?[0-9][0-9a-f]+;?)/i', function ($m) {
104  // Decode '&#110;', ...
105  return realCharForNumericEntities($m); }, $val);
106 
107  // We clean html comments because some hacks try to obfuscate evil strings by inserting HTML comments. Example: on<!-- -->error=alert(1)
108  $val = preg_replace('/<!--[^>]*-->/', '', $val);
109  $val = preg_replace('/[\r\n\t]/', '', $val);
110  } while ($oldval != $val);
111  //print "type = ".$type." after decoding: ".$val."\n";
112 
113  $inj = 0;
114 
115  // We check 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)
116  // We should use dol_string_nounprintableascii but function is not yet loaded/available
117  // Example of valid UTF8 chars:
118  // utf8=utf8mb3: '\x09', '\x0A', '\x0D', '\x7E'
119  // utf8=utf8mb3: '\xE0\xA0\x80'
120  // utf8mb4: '\xF0\x9D\x84\x9E' (but this may be refused by the database insert if pagecode is utf8=utf8mb3)
121  $newval = preg_replace('/[\x00-\x08\x0B-\x0C\x0E-\x1F\x7F]/u', '', $val); // /u operator makes UTF8 valid characters being ignored so are not included into the replace
122 
123  // Note that $newval may also be completely empty '' when non valid UTF8 are found.
124  if ($newval != $val) {
125  // If $val has changed after removing non valid UTF8 chars, it means we have an evil string.
126  $inj += 1;
127  }
128  //print 'type='.$type.'-val='.$val.'-newval='.$newval."-inj=".$inj."\n";
129 
130  // For SQL Injection (only GET are used to scan for such injection strings)
131  if ($type == 1 || $type == 3) {
132  // Note the \s+ is replaced into \s* because some spaces may have been modified in previous loop
133  $inj += preg_match('/delete\s*from/i', $val);
134  $inj += preg_match('/create\s*table/i', $val);
135  $inj += preg_match('/insert\s*into/i', $val);
136  $inj += preg_match('/select\s*from/i', $val);
137  $inj += preg_match('/into\s*(outfile|dumpfile)/i', $val);
138  $inj += preg_match('/user\s*\(/i', $val); // avoid to use function user() or mysql_user() that return current database login
139  $inj += preg_match('/information_schema/i', $val); // avoid to use request that read information_schema database
140  $inj += preg_match('/<svg/i', $val); // <svg can be allowed in POST
141  $inj += preg_match('/update[^&].*set.+=/i', $val); // the [^&] test is to avoir error when request is like action=update&...set...
142  $inj += preg_match('/union.+select/i', $val);
143  }
144  if ($type == 3) {
145  // Note the \s+ is replaced into \s* because some spaces may have been modified in previous loop
146  $inj += preg_match('/select|update|delete|truncate|replace|group\s*by|concat|count|from|union/i', $val);
147  }
148  if ($type != 2) { // Not common key strings, so we can check them both on GET and POST
149  $inj += preg_match('/updatexml\(/i', $val);
150  $inj += preg_match('/(\.\.%2f)+/i', $val);
151  $inj += preg_match('/\s@@/', $val);
152  }
153  // For XSS Injection done by closing textarea to execute content into a textarea field
154  $inj += preg_match('/<\/textarea/i', $val);
155  // For XSS Injection done by adding javascript with script
156  // This is all cases a browser consider text is javascript:
157  // When it found '<script', 'javascript:', '<style', 'onload\s=' on body tag, '="&' on a tag size with old browsers
158  // All examples on page: http://ha.ckers.org/xss.html#XSScalc
159  // More on https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
160  $inj += preg_match('/<audio/i', $val);
161  $inj += preg_match('/<embed/i', $val);
162  $inj += preg_match('/<iframe/i', $val);
163  $inj += preg_match('/<object/i', $val);
164  $inj += preg_match('/<script/i', $val);
165  $inj += preg_match('/Set\.constructor/i', $val); // ECMA script 6
166  if (!defined('NOSTYLECHECK')) {
167  $inj += preg_match('/<style/i', $val);
168  }
169  $inj += preg_match('/base\s+href/si', $val);
170  $inj += preg_match('/=data:/si', $val);
171  // List of dom events is on https://www.w3schools.com/jsref/dom_obj_event.asp and https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers
172  $inj += preg_match('/on(mouse|drag|key|load|touch|pointer|select|transition)([a-z]*)\s*=/i', $val); // onmousexxx can be set on img or any html tag like <img title='...' onmouseover=alert(1)>
173  $inj += preg_match('/on(abort|afterprint|animation|auxclick|beforecopy|beforecut|beforeprint|beforeunload|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|copy|cut)\s*=/i', $val);
174  $inj += preg_match('/on(dblclick|drop|durationchange|emptied|end|ended|error|focus|focusin|focusout|formdata|gotpointercapture|hashchange|input|invalid)\s*=/i', $val);
175  $inj += preg_match('/on(lostpointercapture|offline|online|pagehide|pageshow)\s*=/i', $val);
176  $inj += preg_match('/on(paste|pause|play|playing|progress|ratechange|reset|resize|scroll|search|seeked|seeking|show|stalled|start|submit|suspend)\s*=/i', $val);
177  $inj += preg_match('/on(timeupdate|toggle|unload|volumechange|waiting|wheel)\s*=/i', $val);
178  // More not into the previous list
179  $inj += preg_match('/on(repeat|begin|finish|beforeinput)\s*=/i', $val);
180 
181  // We refuse html into html because some hacks try to obfuscate evil strings by inserting HTML into HTML. Example: <img on<a>error=alert(1) to bypass test on onerror
182  $tmpval = preg_replace('/<[^<]+>/', '', $val);
183  // List of dom events is on https://www.w3schools.com/jsref/dom_obj_event.asp and https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers
184  $inj += preg_match('/on(mouse|drag|key|load|touch|pointer|select|transition)([a-z]*)\s*=/i', $tmpval); // onmousexxx can be set on img or any html tag like <img title='...' onmouseover=alert(1)>
185  $inj += preg_match('/on(abort|afterprint|animation|auxclick|beforecopy|beforecut|beforeprint|beforeunload|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|copy|cut)\s*=/i', $tmpval);
186  $inj += preg_match('/on(dblclick|drop|durationchange|emptied|end|ended|error|focus|focusin|focusout|formdata|gotpointercapture|hashchange|input|invalid)\s*=/i', $tmpval);
187  $inj += preg_match('/on(lostpointercapture|offline|online|pagehide|pageshow)\s*=/i', $tmpval);
188  $inj += preg_match('/on(paste|pause|play|playing|progress|ratechange|reset|resize|scroll|search|seeked|seeking|show|stalled|start|submit|suspend)\s*=/i', $tmpval);
189  $inj += preg_match('/on(timeupdate|toggle|unload|volumechange|waiting|wheel)\s*=/i', $tmpval);
190  // More not into the previous list
191  $inj += preg_match('/on(repeat|begin|finish|beforeinput)\s*=/i', $tmpval);
192 
193  //$inj += preg_match('/on[A-Z][a-z]+\*=/', $val); // To lock event handlers onAbort(), ...
194  $inj += preg_match('/&#58;|&#0000058|&#x3A/i', $val); // refused string ':' encoded (no reason to have it encoded) to lock 'javascript:...'
195  $inj += preg_match('/j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t\s*:/i', $val);
196  $inj += preg_match('/vbscript\s*:/i', $val);
197  // For XSS Injection done by adding javascript closing html tags like with onmousemove, etc... (closing a src or href tag with not cleaned param)
198  if ($type == 1 || $type == 3) {
199  $val = str_replace('enclosure="', 'enclosure=X', $val); // We accept enclosure=" for the export/import module
200  $inj += preg_match('/"/i', $val); // We refused " in GET parameters value.
201  }
202  if ($type == 2) {
203  $inj += preg_match('/[:;"\'<>\?\(\){}\$%]/', $val); // PHP_SELF is a file system (or url path without parameters). It can contains spaces.
204  }
205 
206  return $inj;
207 }
208 
217 {
218  if (is_array($var)) {
219  foreach ($var as $key => $value) { // Warning, $key may also be used for attacks
221  //$var[$key] = $value; // This is useless
222  } else {
223  // Get remote IP: PS: We do not use getRemoteIP(), function is not yet loaded and we need a value that can't be spoofed
224  $ip = (empty($_SERVER['REMOTE_ADDR']) ? 'unknown' : $_SERVER['REMOTE_ADDR']);
225  $errormessage = 'Access refused to '.htmlentities($ip, ENT_COMPAT, 'UTF-8').' by SQL or Script injection protection in main.inc.php - GETPOST type='.htmlentities($type, ENT_COMPAT, 'UTF-8').' paramkey='.htmlentities($key, ENT_COMPAT, 'UTF-8').' paramvalue='.htmlentities($value, ENT_COMPAT, 'UTF-8').' page='.htmlentities($_SERVER["REQUEST_URI"], ENT_COMPAT, 'UTF-8');
226  print $errormessage;
227  // Add entry into error log
228  if (function_exists('error_log')) {
229  error_log($errormessage);
230  }
231  // TODO Add entry into security audit table
232  exit;
233  }
234  }
235  return true;
236  } else {
237  return (testSqlAndScriptInject($var, $type) <= 0);
238  }
239 }
240 
241 // To disable the WAF for GET and POST and PHP_SELF, uncomment this
242 //define('NOSCANPHPSELFFORINJECTION', 1);
243 //define('NOSCANGETFORINJECTION', 1);
244 //define('NOSCANPOSTFORINJECTION', 1);
245 
246 // Check consistency of NOREQUIREXXX DEFINES
247 if ((defined('NOREQUIREDB') || defined('NOREQUIRETRAN')) && !defined('NOREQUIREMENU')) {
248  print 'If define NOREQUIREDB or NOREQUIRETRAN are set, you must also set NOREQUIREMENU or not set them.';
249  exit;
250 }
251 if (defined('NOREQUIREUSER') && !defined('NOREQUIREMENU')) {
252  print 'If define NOREQUIREUSER is set, you must also set NOREQUIREMENU or not set it.';
253  exit;
254 }
255 
256 // Sanity check on URL
257 if (!defined('NOSCANPHPSELFFORINJECTION') && !empty($_SERVER["PHP_SELF"])) {
258  $morevaltochecklikepost = array($_SERVER["PHP_SELF"]);
259  analyseVarsForSqlAndScriptsInjection($morevaltochecklikepost, 2);
260 }
261 // Sanity check on GET parameters
262 if (!defined('NOSCANGETFORINJECTION') && !empty($_SERVER["QUERY_STRING"])) {
263  // Note: QUERY_STRING is url encoded, but $_GET and $_POST are already decoded
264  // Because the analyseVarsForSqlAndScriptsInjection is designed for already url decoded value, we must decode QUERY_STRING
265  // Another solution is to provide $_GET as parameter
266  $morevaltochecklikeget = array(urldecode($_SERVER["QUERY_STRING"]));
267  analyseVarsForSqlAndScriptsInjection($morevaltochecklikeget, 1);
268 }
269 // Sanity check on POST
270 if (!defined('NOSCANPOSTFORINJECTION')) {
272 }
273 
274 // This is to make Dolibarr working with Plesk
275 if (!empty($_SERVER['DOCUMENT_ROOT']) && substr($_SERVER['DOCUMENT_ROOT'], -6) !== 'htdocs') {
276  set_include_path($_SERVER['DOCUMENT_ROOT'].'/htdocs');
277 }
278 
279 // Include the conf.php and functions.lib.php and security.lib.php. This defined the constants like DOL_DOCUMENT_ROOT, DOL_DATA_ROOT, DOL_URL_ROOT...
280 require_once 'filefunc.inc.php';
281 
282 // If there is a POST parameter to tell to save automatically some POST parameters into cookies, we do it.
283 // This is used for example by form of boxes to save personalization of some options.
284 // DOL_AUTOSET_COOKIE=cookiename:val1,val2 and cookiename_val1=aaa cookiename_val2=bbb will set cookie_name with value json_encode(array('val1'=> , ))
285 if (!empty($_POST["DOL_AUTOSET_COOKIE"])) {
286  $tmpautoset = explode(':', $_POST["DOL_AUTOSET_COOKIE"], 2);
287  $tmplist = explode(',', $tmpautoset[1]);
288  $cookiearrayvalue = array();
289  foreach ($tmplist as $tmpkey) {
290  $postkey = $tmpautoset[0].'_'.$tmpkey;
291  //var_dump('tmpkey='.$tmpkey.' postkey='.$postkey.' value='.$_POST[$postkey]);
292  if (!empty($_POST[$postkey])) {
293  $cookiearrayvalue[$tmpkey] = $_POST[$postkey];
294  }
295  }
296  $cookiename = $tmpautoset[0];
297  $cookievalue = json_encode($cookiearrayvalue);
298  //var_dump('setcookie cookiename='.$cookiename.' cookievalue='.$cookievalue);
299  if (PHP_VERSION_ID < 70300) {
300  setcookie($cookiename, empty($cookievalue) ? '' : $cookievalue, empty($cookievalue) ? 0 : (time() + (86400 * 354)), '/', null, ((empty($dolibarr_main_force_https) && isHTTPS() === false) ? false : true), true); // keep cookie 1 year and add tag httponly
301  } else {
302  // Only available for php >= 7.3
303  $cookieparams = array(
304  'expires' => empty($cookievalue) ? 0 : (time() + (86400 * 354)),
305  'path' => '/',
306  //'domain' => '.mywebsite.com', // the dot at the beginning allows compatibility with subdomains
307  'secure' => ((empty($dolibarr_main_force_https) && isHTTPS() === false) ? false : true),
308  'httponly' => true,
309  'samesite' => 'Lax' // None || Lax || Strict
310  );
311  setcookie($cookiename, empty($cookievalue) ? '' : $cookievalue, $cookieparams);
312  }
313  if (empty($cookievalue)) {
314  unset($_COOKIE[$cookiename]);
315  }
316 }
317 
318 // Set the handler of session
319 // if (ini_get('session.save_handler') == 'user')
320 if (!empty($php_session_save_handler) && $php_session_save_handler == 'db') {
321  require_once 'core/lib/phpsessionin'.$php_session_save_handler.'.lib.php';
322 }
323 
324 // Init session. Name of session is specific to Dolibarr instance.
325 // Must be done after the include of filefunc.inc.php so global variables of conf file are defined (like $dolibarr_main_instance_unique_id or $dolibarr_main_force_https).
326 // Note: the function dol_getprefix() is defined into functions.lib.php but may have been defined to return a different key to manage another area to protect.
327 $prefix = dol_getprefix('');
328 $sessionname = 'DOLSESSID_'.$prefix;
329 $sessiontimeout = 'DOLSESSTIMEOUT_'.$prefix;
330 if (!empty($_COOKIE[$sessiontimeout])) {
331  ini_set('session.gc_maxlifetime', $_COOKIE[$sessiontimeout]);
332 }
333 
334 // This create lock, released by session_write_close() or end of page.
335 // We need this lock as long as we read/write $_SESSION ['vars']. We can remove lock when finished.
336 if (!defined('NOSESSION')) {
337  if (PHP_VERSION_ID < 70300) {
338  session_set_cookie_params(0, '/', null, ((empty($dolibarr_main_force_https) && isHTTPS() === false) ? false : true), true); // Add tag secure and httponly on session cookie (same as setting session.cookie_httponly into php.ini). Must be called before the session_start.
339  } else {
340  // Only available for php >= 7.3
341  $sessioncookieparams = array(
342  'lifetime' => 0,
343  'path' => '/',
344  //'domain' => '.mywebsite.com', // the dot at the beginning allows compatibility with subdomains
345  'secure' => ((empty($dolibarr_main_force_https) && isHTTPS() === false) ? false : true),
346  'httponly' => true,
347  'samesite' => 'Lax' // None || Lax || Strict
348  );
349  session_set_cookie_params($sessioncookieparams);
350  }
351  session_name($sessionname);
352  session_start(); // This call the open and read of session handler
353  //exit; // this exist generates a call to write and close
354 }
355 
356 
357 // Init the 6 global objects, this include will make the 'new Xxx()' and set properties for: $conf, $db, $langs, $user, $mysoc, $hookmanager
358 require_once 'master.inc.php';
359 
360 // If software has been locked. Only login $conf->global->MAIN_ONLY_LOGIN_ALLOWED is allowed.
361 if (!empty($conf->global->MAIN_ONLY_LOGIN_ALLOWED)) {
362  $ok = 0;
363  if ((!session_id() || !isset($_SESSION["dol_login"])) && !isset($_POST["username"]) && !empty($_SERVER["GATEWAY_INTERFACE"])) {
364  $ok = 1; // We let working pages if not logged and inside a web browser (login form, to allow login by admin)
365  } elseif (isset($_POST["username"]) && $_POST["username"] == $conf->global->MAIN_ONLY_LOGIN_ALLOWED) {
366  $ok = 1; // We let working pages that is a login submission (login submit, to allow login by admin)
367  } elseif (defined('NOREQUIREDB')) {
368  $ok = 1; // We let working pages that don't need database access (xxx.css.php)
369  } elseif (defined('EVEN_IF_ONLY_LOGIN_ALLOWED')) {
370  $ok = 1; // We let working pages that ask to work even if only login enabled (logout.php)
371  } elseif (session_id() && isset($_SESSION["dol_login"]) && $_SESSION["dol_login"] == $conf->global->MAIN_ONLY_LOGIN_ALLOWED) {
372  $ok = 1; // We let working if user is allowed admin
373  }
374  if (!$ok) {
375  if (session_id() && isset($_SESSION["dol_login"]) && $_SESSION["dol_login"] != $conf->global->MAIN_ONLY_LOGIN_ALLOWED) {
376  print 'Sorry, your application is offline.'."\n";
377  print 'You are logged with user "'.$_SESSION["dol_login"].'" and only administrator user "'.$conf->global->MAIN_ONLY_LOGIN_ALLOWED.'" is allowed to connect for the moment.'."\n";
378  $nexturl = DOL_URL_ROOT.'/user/logout.php?token='.newToken();
379  print 'Please try later or <a href="'.$nexturl.'">click here to disconnect and change login user</a>...'."\n";
380  } else {
381  print 'Sorry, your application is offline. Only administrator user "'.$conf->global->MAIN_ONLY_LOGIN_ALLOWED.'" is allowed to connect for the moment.'."\n";
382  $nexturl = DOL_URL_ROOT.'/';
383  print 'Please try later or <a href="'.$nexturl.'">click here to change login user</a>...'."\n";
384  }
385  exit;
386  }
387 }
388 
389 
390 // Activate end of page function
391 register_shutdown_function('dol_shutdown');
392 
393 // Load debugbar
394 if (isModEnabled('debugbar') && !GETPOST('dol_use_jmobile') && empty($_SESSION['dol_use_jmobile'])) {
395  global $debugbar;
396  include_once DOL_DOCUMENT_ROOT.'/debugbar/class/DebugBar.php';
397  $debugbar = new DolibarrDebugBar();
398  $renderer = $debugbar->getRenderer();
399  if (empty($conf->global->MAIN_HTML_HEADER)) {
400  $conf->global->MAIN_HTML_HEADER = '';
401  }
402  $conf->global->MAIN_HTML_HEADER .= $renderer->renderHead();
403 
404  $debugbar['time']->startMeasure('pageaftermaster', 'Page generation (after environment init)');
405 }
406 
407 // Detection browser
408 if (isset($_SERVER["HTTP_USER_AGENT"])) {
409  $tmp = getBrowserInfo($_SERVER["HTTP_USER_AGENT"]);
410  $conf->browser->name = $tmp['browsername'];
411  $conf->browser->os = $tmp['browseros'];
412  $conf->browser->version = $tmp['browserversion'];
413  $conf->browser->layout = $tmp['layout']; // 'classic', 'phone', 'tablet'
414  //var_dump($conf->browser);
415 
416  if ($conf->browser->layout == 'phone') {
417  $conf->dol_no_mouse_hover = 1;
418  }
419 }
420 
421 // If theme is forced
422 if (GETPOST('theme', 'aZ09')) {
423  $conf->theme = GETPOST('theme', 'aZ09');
424  $conf->css = "/theme/".$conf->theme."/style.css.php";
425 }
426 
427 // Set global MAIN_OPTIMIZEFORTEXTBROWSER (must be before login part)
428 if (GETPOST('textbrowser', 'int') || (!empty($conf->browser->name) && $conf->browser->name == 'lynxlinks')) { // If we must enable text browser
429  $conf->global->MAIN_OPTIMIZEFORTEXTBROWSER = 1;
430 }
431 
432 // Force HTTPS if required ($conf->file->main_force_https is 0/1 or 'https dolibarr root url')
433 // $_SERVER["HTTPS"] is 'on' when link is https, otherwise $_SERVER["HTTPS"] is empty or 'off'
434 if (!empty($conf->file->main_force_https) && (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] != 'on')) {
435  $newurl = '';
436  if (is_numeric($conf->file->main_force_https)) {
437  if ($conf->file->main_force_https == '1' && !empty($_SERVER["SCRIPT_URI"])) { // If SCRIPT_URI supported by server
438  if (preg_match('/^http:/i', $_SERVER["SCRIPT_URI"]) && !preg_match('/^https:/i', $_SERVER["SCRIPT_URI"])) { // If link is http
439  $newurl = preg_replace('/^http:/i', 'https:', $_SERVER["SCRIPT_URI"]);
440  }
441  } else {
442  // Check HTTPS environment variable (Apache/mod_ssl only)
443  $newurl = preg_replace('/^http:/i', 'https:', DOL_MAIN_URL_ROOT).$_SERVER["REQUEST_URI"];
444  }
445  } else {
446  // Check HTTPS environment variable (Apache/mod_ssl only)
447  $newurl = $conf->file->main_force_https.$_SERVER["REQUEST_URI"];
448  }
449  // Start redirect
450  if ($newurl) {
451  header_remove(); // Clean header already set to be sure to remove any header like "Set-Cookie: DOLSESSID_..." from non HTTPS answers
452  dol_syslog("main.inc: dolibarr_main_force_https is on, we make a redirect to ".$newurl);
453  header("Location: ".$newurl);
454  exit;
455  } else {
456  dol_syslog("main.inc: dolibarr_main_force_https is on but we failed to forge new https url so no redirect is done", LOG_WARNING);
457  }
458 }
459 
460 if (!defined('NOLOGIN') && !defined('NOIPCHECK') && !empty($dolibarr_main_restrict_ip)) {
461  $listofip = explode(',', $dolibarr_main_restrict_ip);
462  $found = false;
463  foreach ($listofip as $ip) {
464  $ip = trim($ip);
465  if ($ip == $_SERVER['REMOTE_ADDR']) {
466  $found = true;
467  break;
468  }
469  }
470  if (!$found) {
471  print 'Access refused by IP protection. Your detected IP is '.$_SERVER['REMOTE_ADDR'];
472  exit;
473  }
474 }
475 
476 // Loading of additional presentation includes
477 if (!defined('NOREQUIREHTML')) {
478  require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; // Need 660ko memory (800ko in 2.2)
479 }
480 if (!defined('NOREQUIREAJAX')) {
481  require_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; // Need 22ko memory
482 }
483 
484 // If install or upgrade process not done or not completely finished, we call the install page.
485 if (!empty($conf->global->MAIN_NOT_INSTALLED) || !empty($conf->global->MAIN_NOT_UPGRADED)) {
486  dol_syslog("main.inc: A previous install or upgrade was not complete. Redirect to install page.", LOG_WARNING);
487  header("Location: ".DOL_URL_ROOT."/install/index.php");
488  exit;
489 }
490 // If an upgrade process is required, we call the install page.
491 if ((!empty($conf->global->MAIN_VERSION_LAST_UPGRADE) && ($conf->global->MAIN_VERSION_LAST_UPGRADE != DOL_VERSION))
492 || (empty($conf->global->MAIN_VERSION_LAST_UPGRADE) && !empty($conf->global->MAIN_VERSION_LAST_INSTALL) && ($conf->global->MAIN_VERSION_LAST_INSTALL != DOL_VERSION))) {
493  $versiontocompare = empty($conf->global->MAIN_VERSION_LAST_UPGRADE) ? $conf->global->MAIN_VERSION_LAST_INSTALL : $conf->global->MAIN_VERSION_LAST_UPGRADE;
494  require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
495  $dolibarrversionlastupgrade = preg_split('/[.-]/', $versiontocompare);
496  $dolibarrversionprogram = preg_split('/[.-]/', DOL_VERSION);
497  $rescomp = versioncompare($dolibarrversionprogram, $dolibarrversionlastupgrade);
498  if ($rescomp > 0) { // Programs have a version higher than database.
499  if (empty($conf->global->MAIN_NO_UPGRADE_REDIRECT_ON_LEVEL_3_CHANGE) || $rescomp < 3) {
500  // We did not add "&& $rescomp < 3" because we want upgrade process for build upgrades
501  dol_syslog("main.inc: database version ".$versiontocompare." is lower than programs version ".DOL_VERSION.". Redirect to install/upgrade page.", LOG_WARNING);
502  header("Location: ".DOL_URL_ROOT."/install/index.php");
503  exit;
504  }
505  }
506 }
507 
508 // Creation of a token against CSRF vulnerabilities
509 if (!defined('NOTOKENRENEWAL') && !defined('NOSESSION')) {
510  // No token renewal on .css.php, .js.php and .json.php (even if the NOTOKENRENEWAL was not provided)
511  if (!preg_match('/\.(css|js|json)\.php$/', $_SERVER["PHP_SELF"])) {
512  // Rolling token at each call ($_SESSION['token'] contains token of previous page)
513  if (isset($_SESSION['newtoken'])) {
514  $_SESSION['token'] = $_SESSION['newtoken'];
515  }
516 
517  if (!isset($_SESSION['newtoken']) || getDolGlobalInt('MAIN_SECURITY_CSRF_TOKEN_RENEWAL_ON_EACH_CALL')) {
518  // Note: Using MAIN_SECURITY_CSRF_TOKEN_RENEWAL_ON_EACH_CALL is not recommended: if a user succeed in entering a data from
519  // a public page with a link that make a token regeneration, it can make use of the backoffice no more possible !
520  // Save in $_SESSION['newtoken'] what will be next token. Into forms, we will add param token = $_SESSION['newtoken']
521  $token = dol_hash(uniqid(mt_rand(), false), 'md5'); // Generates a hash of a random number. We don't need a secured hash, just a changing random value.
522  $_SESSION['newtoken'] = $token;
523  dol_syslog("NEW TOKEN generated by : ".$_SERVER['PHP_SELF'], LOG_DEBUG);
524  }
525  }
526 }
527 
528 //dol_syslog("aaaa - ".defined('NOCSRFCHECK')." - ".$dolibarr_nocsrfcheck." - ".$conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN." - ".$_SERVER['REQUEST_METHOD']." - ".GETPOST('token', 'alpha'));
529 
530 // Check validity of token, only if option MAIN_SECURITY_CSRF_WITH_TOKEN enabled or if constant CSRFCHECK_WITH_TOKEN is set into page
531 if ((!defined('NOCSRFCHECK') && empty($dolibarr_nocsrfcheck) && getDolGlobalInt('MAIN_SECURITY_CSRF_WITH_TOKEN')) || defined('CSRFCHECK_WITH_TOKEN')) {
532  // Array of action code where CSRFCHECK with token will be forced (so token must be provided on url request)
533  $sensitiveget = false;
534  if ((GETPOSTISSET('massaction') || GETPOST('action', 'aZ09')) && getDolGlobalInt('MAIN_SECURITY_CSRF_WITH_TOKEN') >= 3) {
535  // All GET actions and mass actions are processed as sensitive.
536  if (GETPOSTISSET('massaction') || !in_array(GETPOST('action', 'aZ09'), array('create', 'createsite', 'createcard', 'edit', 'editvalidator', 'file_manager', 'presend', 'presend_addmessage', 'preview', 'specimen'))) { // We exclude some action that are legitimate
537  $sensitiveget = true;
538  }
539  } elseif (getDolGlobalInt('MAIN_SECURITY_CSRF_WITH_TOKEN') >= 2) {
540  // Few GET actions coded with a &token into url are processed as sensitive.
541  $arrayofactiontoforcetokencheck = array(
542  'activate',
543  'doprev', 'donext', 'dvprev', 'dvnext',
544  'freezone', 'install',
545  'reopen'
546  );
547  if (in_array(GETPOST('action', 'aZ09'), $arrayofactiontoforcetokencheck)) {
548  $sensitiveget = true;
549  }
550  // We also match for value with just a simple string that must match
551  if (preg_match('/^(add|classify|close|confirm|copy|del|disable|enable|remove|set|unset|update|save)/', GETPOST('action', 'aZ09'))) {
552  $sensitiveget = true;
553  }
554  }
555 
556  // Check a token is provided for all cases that need a mandatory token
557  // (all POST actions + all sensitive GET actions + all mass actions + all login/actions/logout on pages with CSRFCHECK_WITH_TOKEN set)
558  if (
559  $_SERVER['REQUEST_METHOD'] == 'POST' ||
560  $sensitiveget ||
561  GETPOSTISSET('massaction') ||
562  ((GETPOSTISSET('actionlogin') || GETPOSTISSET('action')) && defined('CSRFCHECK_WITH_TOKEN'))
563  ) {
564  // If token is not provided or empty, error (we are in case it is mandatory)
565  if (!GETPOST('token', 'alpha') || GETPOST('token', 'alpha') == 'notrequired') {
566  top_httphead();
567  if (GETPOST('uploadform', 'int')) {
568  dol_syslog("--- Access to ".(empty($_SERVER["REQUEST_METHOD"]) ? '' : $_SERVER["REQUEST_METHOD"].' ').$_SERVER["PHP_SELF"]." refused. File size too large or not provided.");
569  $langs->loadLangs(array("errors", "install"));
570  print $langs->trans("ErrorFileSizeTooLarge").' ';
571  print $langs->trans("ErrorGoBackAndCorrectParameters");
572  } else {
573  http_response_code(403);
574  if (defined('CSRFCHECK_WITH_TOKEN')) {
575  dol_syslog("--- Access to ".(empty($_SERVER["REQUEST_METHOD"]) ? '' : $_SERVER["REQUEST_METHOD"].' ').$_SERVER["PHP_SELF"]." refused by CSRF protection (CSRFCHECK_WITH_TOKEN protection) in main.inc.php. Token not provided.", LOG_WARNING);
576  print "Access to a page that needs a token (constant CSRFCHECK_WITH_TOKEN is defined) is refused by CSRF protection in main.inc.php. Token not provided.\n";
577  } else {
578  dol_syslog("--- Access to ".(empty($_SERVER["REQUEST_METHOD"]) ? '' : $_SERVER["REQUEST_METHOD"].' ').$_SERVER["PHP_SELF"]." refused by CSRF protection (POST method or GET with a sensible value for 'action' parameter) in main.inc.php. Token not provided.", LOG_WARNING);
579  print "Access to this page this way (POST method or GET with a sensible value for 'action' parameter) is refused by CSRF protection in main.inc.php. Token not provided.\n";
580  print "If you access your server behind a proxy using url rewriting and the parameter is provided by caller, you might check that all HTTP header are propagated (or add the line \$dolibarr_nocsrfcheck=1 into your conf.php file or MAIN_SECURITY_CSRF_WITH_TOKEN to 0";
581  if (!empty($conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN)) {
582  print " instead of ".$conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN;
583  }
584  print " into setup).\n";
585  }
586  }
587  die;
588  }
589  }
590 
591  $sessiontokenforthisurl = (empty($_SESSION['token']) ? '' : $_SESSION['token']);
592  // TODO Get the sessiontokenforthisurl into an array of session token (one array per base URL so we can use the CSRF per page and we keep ability for several tabs per url in a browser)
593  if (GETPOSTISSET('token') && GETPOST('token') != 'notrequired' && GETPOST('token', 'alpha') != $sessiontokenforthisurl) {
594  dol_syslog("--- Access to ".(empty($_SERVER["REQUEST_METHOD"]) ? '' : $_SERVER["REQUEST_METHOD"].' ').$_SERVER["PHP_SELF"]." refused by CSRF protection (invalid token), so we disable POST and some GET parameters - referer=".(empty($_SERVER['HTTP_REFERER'])?'':$_SERVER['HTTP_REFERER']).", action=".GETPOST('action', 'aZ09').", _GET|POST['token']=".GETPOST('token', 'alpha'), LOG_WARNING);
595  //dol_syslog("_SESSION['token']=".$sessiontokenforthisurl, LOG_DEBUG);
596  // Do not output anything on standard output because this create problems when using the BACK button on browsers. So we just set a message into session.
597  if (!defined('NOTOKENRENEWAL')) {
598  // If the page is not a page that disable the token renewal, we report a warning message to explain token has epired.
599  setEventMessages('SecurityTokenHasExpiredSoActionHasBeenCanceledPleaseRetry', null, 'warnings', '', 1);
600  }
601  $savid = null;
602  if (isset($_POST['id'])) {
603  $savid = ((int) $_POST['id']);
604  }
605  unset($_POST);
606  unset($_GET['confirm']);
607  unset($_GET['action']);
608  unset($_GET['confirmmassaction']);
609  unset($_GET['massaction']);
610  unset($_GET['token']); // TODO Make a redirect if we have a token in url to remove it ?
611  if (isset($savid)) {
612  $_POST['id'] = ((int) $savid);
613  }
614  // So rest of code can know something was wrong here
615  $_GET['errorcode'] = 'InvalidToken';
616  }
617 
618  // Note: There is another CSRF protection into the filefunc.inc.php
619 }
620 
621 // Disable modules (this must be after session_start and after conf has been loaded)
622 if (GETPOSTISSET('disablemodules')) {
623  $_SESSION["disablemodules"] = GETPOST('disablemodules', 'alpha');
624 }
625 if (!empty($_SESSION["disablemodules"])) {
626  $modulepartkeys = array('css', 'js', 'tabs', 'triggers', 'login', 'substitutions', 'menus', 'theme', 'sms', 'tpl', 'barcode', 'models', 'societe', 'hooks', 'dir', 'syslog', 'tpllinkable', 'contactelement', 'moduleforexternal');
627 
628  $disabled_modules = explode(',', $_SESSION["disablemodules"]);
629  foreach ($disabled_modules as $module) {
630  if ($module) {
631  if (empty($conf->$module)) {
632  $conf->$module = new stdClass(); // To avoid warnings
633  }
634  $conf->$module->enabled = false;
635  foreach ($modulepartkeys as $modulepartkey) {
636  unset($conf->modules_parts[$modulepartkey][$module]);
637  }
638  if ($module == 'fournisseur') { // Special case
639  $conf->supplier_order->enabled = 0;
640  $conf->supplier_invoice->enabled = 0;
641  }
642  }
643  }
644 }
645 
646 // Set current modulepart
647 $modulepart = explode("/", $_SERVER["PHP_SELF"]);
648 if (is_array($modulepart) && count($modulepart) > 0) {
649  foreach ($conf->modules as $module) {
650  if (in_array($module, $modulepart)) {
651  $modulepart = $module;
652  break;
653  }
654  }
655 }
656 if (is_array($modulepart)) {
657  $modulepart = '';
658 }
659 
660 
661 /*
662  * Phase authentication / login
663  */
664 $login = '';
665 if (!defined('NOLOGIN')) {
666  // $authmode lists the different method of identification to be tested in order of preference.
667  // Example: 'http', 'dolibarr', 'ldap', 'http,forceuser', '...'
668 
669  if (defined('MAIN_AUTHENTICATION_MODE')) {
670  $dolibarr_main_authentication = constant('MAIN_AUTHENTICATION_MODE');
671  } else {
672  // Authentication mode
673  if (empty($dolibarr_main_authentication)) {
674  $dolibarr_main_authentication = 'dolibarr';
675  }
676  // Authentication mode: forceuser
677  if ($dolibarr_main_authentication == 'forceuser' && empty($dolibarr_auto_user)) {
678  $dolibarr_auto_user = 'auto';
679  }
680  }
681  // Set authmode
682  $authmode = explode(',', $dolibarr_main_authentication);
683 
684  // No authentication mode
685  if (!count($authmode)) {
686  $langs->load('main');
687  dol_print_error('', $langs->trans("ErrorConfigParameterNotDefined", 'dolibarr_main_authentication'));
688  exit;
689  }
690 
691  // If login request was already post, we retrieve login from the session
692  // Call module if not realized that his request.
693  // At the end of this phase, the variable $login is defined.
694  $resultFetchUser = '';
695  $test = true;
696  if (!isset($_SESSION["dol_login"])) {
697  // It is not already authenticated and it requests the login / password
698  include_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
699 
700  $dol_dst_observed = GETPOST("dst_observed", 'int', 3);
701  $dol_dst_first = GETPOST("dst_first", 'int', 3);
702  $dol_dst_second = GETPOST("dst_second", 'int', 3);
703  $dol_screenwidth = GETPOST("screenwidth", 'int', 3);
704  $dol_screenheight = GETPOST("screenheight", 'int', 3);
705  $dol_hide_topmenu = GETPOST('dol_hide_topmenu', 'int', 3);
706  $dol_hide_leftmenu = GETPOST('dol_hide_leftmenu', 'int', 3);
707  $dol_optimize_smallscreen = GETPOST('dol_optimize_smallscreen', 'int', 3);
708  $dol_no_mouse_hover = GETPOST('dol_no_mouse_hover', 'int', 3);
709  $dol_use_jmobile = GETPOST('dol_use_jmobile', 'int', 3); // 0=default, 1=to say we use app from a webview app, 2=to say we use app from a webview app and keep ajax
710  //dol_syslog("POST key=".join(array_keys($_POST),',').' value='.join($_POST,','));
711 
712  // If in demo mode, we check we go to home page through the public/demo/index.php page
713  if (!empty($dolibarr_main_demo) && $_SERVER['PHP_SELF'] == DOL_URL_ROOT.'/index.php') { // We ask index page
714  if (empty($_SERVER['HTTP_REFERER']) || !preg_match('/public/', $_SERVER['HTTP_REFERER'])) {
715  dol_syslog("Call index page from another url than demo page (call is done from page ".$_SERVER['HTTP_REFERER'].")");
716  $url = '';
717  $url .= ($url ? '&' : '').($dol_hide_topmenu ? 'dol_hide_topmenu='.$dol_hide_topmenu : '');
718  $url .= ($url ? '&' : '').($dol_hide_leftmenu ? 'dol_hide_leftmenu='.$dol_hide_leftmenu : '');
719  $url .= ($url ? '&' : '').($dol_optimize_smallscreen ? 'dol_optimize_smallscreen='.$dol_optimize_smallscreen : '');
720  $url .= ($url ? '&' : '').($dol_no_mouse_hover ? 'dol_no_mouse_hover='.$dol_no_mouse_hover : '');
721  $url .= ($url ? '&' : '').($dol_use_jmobile ? 'dol_use_jmobile='.$dol_use_jmobile : '');
722  $url = DOL_URL_ROOT.'/public/demo/index.php'.($url ? '?'.$url : '');
723  header("Location: ".$url);
724  exit;
725  }
726  }
727 
728  // Hooks for security access
729  $action = '';
730  $hookmanager->initHooks(array('login'));
731  $parameters = array();
732  $reshook = $hookmanager->executeHooks('beforeLoginAuthentication', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
733  if ($reshook < 0) {
734  $test = false;
735  $error++;
736  }
737 
738  // Verification security graphic code
739  if ($test && GETPOST("username", "alpha", 2) && !empty($conf->global->MAIN_SECURITY_ENABLECAPTCHA) && !isset($_SESSION['dol_bypass_antispam'])) {
740  $sessionkey = 'dol_antispam_value';
741  $ok = (array_key_exists($sessionkey, $_SESSION) === true && (strtolower($_SESSION[$sessionkey]) === strtolower(GETPOST('code', 'restricthtml'))));
742 
743  // Check code
744  if (!$ok) {
745  dol_syslog('Bad value for code, connexion refused');
746  // Load translation files required by page
747  $langs->loadLangs(array('main', 'errors'));
748 
749  $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorBadValueForCode");
750  $test = false;
751 
752  // Call trigger for the "security events" log
753  $user->trigger_mesg = 'ErrorBadValueForCode - login='.GETPOST("username", "alpha", 2);
754 
755  // Call trigger
756  $result = $user->call_trigger('USER_LOGIN_FAILED', $user);
757  if ($result < 0) {
758  $error++;
759  }
760  // End call triggers
761 
762  // Hooks on failed login
763  $action = '';
764  $hookmanager->initHooks(array('login'));
765  $parameters = array('dol_authmode'=>$authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
766  $reshook = $hookmanager->executeHooks('afterLoginFailed', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
767  if ($reshook < 0) {
768  $error++;
769  }
770 
771  // Note: exit is done later
772  }
773  }
774 
775  $allowedmethodtopostusername = 3;
776  if (defined('MAIN_AUTHENTICATION_POST_METHOD')) {
777  $allowedmethodtopostusername = constant('MAIN_AUTHENTICATION_POST_METHOD'); // Note a value of 2 is not compatible with some authentication methods that put username as GET parameter
778  }
779  // TODO Remove use of $_COOKIE['login_dolibarr'] ? Replace $usertotest = with $usertotest = GETPOST("username", "alpha", $allowedmethodtopostusername);
780  $usertotest = (!empty($_COOKIE['login_dolibarr']) ? preg_replace('/[^a-zA-Z0-9_@\-\.]/', '', $_COOKIE['login_dolibarr']) : GETPOST("username", "alpha", $allowedmethodtopostusername));
781  $passwordtotest = GETPOST('password', 'none', $allowedmethodtopostusername);
782  $entitytotest = (GETPOST('entity', 'int') ? GETPOST('entity', 'int') : (!empty($conf->entity) ? $conf->entity : 1));
783 
784  // Define if we received the correct data to go into the test of the login with the checkLoginPassEntity().
785  $goontestloop = false;
786  if (isset($_SERVER["REMOTE_USER"]) && in_array('http', $authmode)) { // For http basic login test
787  $goontestloop = true;
788  }
789  if ($dolibarr_main_authentication == 'forceuser' && !empty($dolibarr_auto_user)) { // For automatic login with a forced user
790  $goontestloop = true;
791  }
792  if (GETPOST("username", "alpha", $allowedmethodtopostusername)) { // For posting the login form
793  $goontestloop = true;
794  }
795  if (GETPOST('openid_mode', 'alpha', 1)) { // For openid_connect ?
796  $goontestloop = true;
797  }
798  if (GETPOST('beforeoauthloginredirect', 'int') || GETPOST('afteroauthloginreturn')) { // For oauth login
799  $goontestloop = true;
800  }
801  if (!empty($_COOKIE['login_dolibarr'])) { // TODO For ? Remove this ?
802  $goontestloop = true;
803  }
804 
805  if (!is_object($langs)) { // This can occurs when calling page with NOREQUIRETRAN defined, however we need langs for error messages.
806  include_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
807  $langs = new Translate("", $conf);
808  $langcode = (GETPOST('lang', 'aZ09', 1) ?GETPOST('lang', 'aZ09', 1) : (empty($conf->global->MAIN_LANG_DEFAULT) ? 'auto' : $conf->global->MAIN_LANG_DEFAULT));
809  if (defined('MAIN_LANG_DEFAULT')) {
810  $langcode = constant('MAIN_LANG_DEFAULT');
811  }
812  $langs->setDefaultLang($langcode);
813  }
814 
815  // Validation of login/pass/entity
816  // If ok, the variable login will be returned
817  // If error, we will put error message in session under the name dol_loginmesg
818  // Note authmode is an array for example: array('0'=>'dolibarr', '1'=>'googleoauth');
819  if ($test && $goontestloop && (GETPOST('actionlogin', 'aZ09') == 'login' || $dolibarr_main_authentication != 'dolibarr')) {
820  $login = checkLoginPassEntity($usertotest, $passwordtotest, $entitytotest, $authmode);
821  if ($login === '--bad-login-validity--') {
822  $login = '';
823  }
824 
825  $dol_authmode = '';
826 
827  if ($login) {
828  $dol_authmode = $conf->authmode; // This properties is defined only when logged, to say what mode was successfully used
829  $dol_tz = $_POST["tz"];
830  $dol_tz_string = $_POST["tz_string"];
831  $dol_tz_string = preg_replace('/\s*\(.+\)$/', '', $dol_tz_string);
832  $dol_tz_string = preg_replace('/,/', '/', $dol_tz_string);
833  $dol_tz_string = preg_replace('/\s/', '_', $dol_tz_string);
834  $dol_dst = 0;
835  // Keep $_POST here. Do not use GETPOSTISSET
836  if (isset($_POST["dst_first"]) && isset($_POST["dst_second"])) {
837  include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
838  $datenow = dol_now();
839  $datefirst = dol_stringtotime($_POST["dst_first"]);
840  $datesecond = dol_stringtotime($_POST["dst_second"]);
841  if ($datenow >= $datefirst && $datenow < $datesecond) {
842  $dol_dst = 1;
843  }
844  }
845  //print $datefirst.'-'.$datesecond.'-'.$datenow.'-'.$dol_tz.'-'.$dol_tzstring.'-'.$dol_dst; exit;
846  }
847 
848  if (!$login) {
849  dol_syslog('Bad password, connexion refused', LOG_DEBUG);
850  // Load translation files required by page
851  $langs->loadLangs(array('main', 'errors'));
852 
853  // Bad password. No authmode has found a good password.
854  // We set a generic message if not defined inside function checkLoginPassEntity or subfunctions
855  if (empty($_SESSION["dol_loginmesg"])) {
856  $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorBadLoginPassword");
857  }
858 
859  // Call trigger for the "security events" log
860  $user->trigger_mesg = $langs->trans("ErrorBadLoginPassword").' - login='.GETPOST("username", "alpha", 2);
861 
862  // Call trigger
863  $result = $user->call_trigger('USER_LOGIN_FAILED', $user);
864  if ($result < 0) {
865  $error++;
866  }
867  // End call triggers
868 
869  // Hooks on failed login
870  $action = '';
871  $hookmanager->initHooks(array('login'));
872  $parameters = array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
873  $reshook = $hookmanager->executeHooks('afterLoginFailed', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
874  if ($reshook < 0) {
875  $error++;
876  }
877 
878  // Note: exit is done in next chapter
879  }
880  }
881 
882  // End test login / passwords
883  if (!$login || (in_array('ldap', $authmode) && empty($passwordtotest))) { // With LDAP we refused empty password because some LDAP are "opened" for anonymous access so connexion is a success.
884  // No data to test login, so we show the login page.
885  dol_syslog("--- Access to ".(empty($_SERVER["REQUEST_METHOD"]) ? '' : $_SERVER["REQUEST_METHOD"].' ').$_SERVER["PHP_SELF"]." - action=".GETPOST('action', 'aZ09')." - actionlogin=".GETPOST('actionlogin', 'aZ09')." - showing the login form and exit", LOG_NOTICE);
886  if (defined('NOREDIRECTBYMAINTOLOGIN')) {
887  // When used with NOREDIRECTBYMAINTOLOGIN set, the http header must already be set when including the main.
888  // See example with selectsearchbox.php. This case is reserverd for the selectesearchbox.php so we can
889  // report a message to ask to login when search ajax component is used after a timeout.
890  //top_httphead();
891  return 'ERROR_NOT_LOGGED';
892  } else {
893  if ($_SERVER["HTTP_USER_AGENT"] == 'securitytest') {
894  http_response_code(401); // It makes easier to understand if session was broken during security tests
895  }
896  dol_loginfunction($langs, $conf, (!empty($mysoc) ? $mysoc : '')); // This include http headers
897  }
898  exit;
899  }
900 
901  $resultFetchUser = $user->fetch('', $login, '', 1, ($entitytotest > 0 ? $entitytotest : -1)); // value for $login was retrieved previously when checking password.
902  if ($resultFetchUser <= 0 || $user->isNotIntoValidityDateRange()) {
903  dol_syslog('User not found or not valid, connexion refused');
904  session_destroy();
905  session_set_cookie_params(0, '/', null, (empty($dolibarr_main_force_https) ? false : true), true); // Add tag secure and httponly on session cookie
906  session_name($sessionname);
907  session_start();
908 
909  if ($resultFetchUser == 0) {
910  // Load translation files required by page
911  $langs->loadLangs(array('main', 'errors'));
912 
913  $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorCantLoadUserFromDolibarrDatabase", $login);
914 
915  $user->trigger_mesg = 'ErrorCantLoadUserFromDolibarrDatabase - login='.$login;
916  } elseif ($resultFetchUser < 0) {
917  $_SESSION["dol_loginmesg"] = $user->error;
918 
919  $user->trigger_mesg = $user->error;
920  } else {
921  // Load translation files required by the page
922  $langs->loadLangs(array('main', 'errors'));
923 
924  $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorLoginDateValidity");
925 
926  $user->trigger_mesg = $langs->trans("ErrorLoginDateValidity").' - login='.$login;
927  }
928 
929  // Call trigger
930  $result = $user->call_trigger('USER_LOGIN_FAILED', $user);
931  if ($result < 0) {
932  $error++;
933  }
934  // End call triggers
935 
936 
937  // Hooks on failed login
938  $action = '';
939  $hookmanager->initHooks(array('login'));
940  $parameters = array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
941  $reshook = $hookmanager->executeHooks('afterLoginFailed', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
942  if ($reshook < 0) {
943  $error++;
944  }
945 
946  $paramsurl = array();
947  if (GETPOST('textbrowser', 'int')) {
948  $paramsurl[] = 'textbrowser='.GETPOST('textbrowser', 'int');
949  }
950  if (GETPOST('nojs', 'int')) {
951  $paramsurl[] = 'nojs='.GETPOST('nojs', 'int');
952  }
953  if (GETPOST('lang', 'aZ09')) {
954  $paramsurl[] = 'lang='.GETPOST('lang', 'aZ09');
955  }
956  header('Location: '.DOL_URL_ROOT.'/index.php'.(count($paramsurl) ? '?'.implode('&', $paramsurl) : ''));
957  exit;
958  } else {
959  // User is loaded, we may need to change language for him according to its choice
960  if (!empty($user->conf->MAIN_LANG_DEFAULT)) {
961  $langs->setDefaultLang($user->conf->MAIN_LANG_DEFAULT);
962  }
963  }
964  } else {
965  // We are already into an authenticated session
966  $login = $_SESSION["dol_login"];
967  $entity = isset($_SESSION["dol_entity"]) ? $_SESSION["dol_entity"] : 0;
968  dol_syslog("- This is an already logged session. _SESSION['dol_login']=".$login." _SESSION['dol_entity']=".$entity, LOG_DEBUG);
969 
970  $resultFetchUser = $user->fetch('', $login, '', 1, ($entity > 0 ? $entity : -1));
971 
972  //var_dump(dol_print_date($user->flagdelsessionsbefore, 'dayhour', 'gmt')." ".dol_print_date($_SESSION["dol_logindate"], 'dayhour', 'gmt'));
973 
974  if ($resultFetchUser <= 0
975  || ($user->flagdelsessionsbefore && !empty($_SESSION["dol_logindate"]) && $user->flagdelsessionsbefore > $_SESSION["dol_logindate"])
976  || ($user->status != $user::STATUS_ENABLED)
977  || ($user->isNotIntoValidityDateRange())) {
978  if ($resultFetchUser <= 0) {
979  // Account has been removed after login
980  dol_syslog("Can't load user even if session logged. _SESSION['dol_login']=".$login, LOG_WARNING);
981  } elseif ($user->flagdelsessionsbefore && !empty($_SESSION["dol_logindate"]) && $user->flagdelsessionsbefore > $_SESSION["dol_logindate"]) {
982  // Session is no more valid
983  dol_syslog("The user has a date for session invalidation = ".$user->flagdelsessionsbefore." and a session date = ".$_SESSION["dol_logindate"].". We must invalidate its sessions.");
984  } elseif ($user->status != $user::STATUS_ENABLED) {
985  // User is not enabled
986  dol_syslog("The user login is disabled");
987  } else {
988  // User validity dates are no more valid
989  dol_syslog("The user login has a validity between [".$user->datestartvalidity." and ".$user->dateendvalidity."], curren date is ".dol_now());
990  }
991  session_destroy();
992  session_set_cookie_params(0, '/', null, (empty($dolibarr_main_force_https) ? false : true), true); // Add tag secure and httponly on session cookie
993  session_name($sessionname);
994  session_start();
995 
996  if ($resultFetchUser == 0) {
997  $langs->loadLangs(array('main', 'errors'));
998 
999  $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorCantLoadUserFromDolibarrDatabase", $login);
1000 
1001  $user->trigger_mesg = 'ErrorCantLoadUserFromDolibarrDatabase - login='.$login;
1002  } elseif ($resultFetchUser < 0) {
1003  $_SESSION["dol_loginmesg"] = $user->error;
1004 
1005  $user->trigger_mesg = $user->error;
1006  } else {
1007  $langs->loadLangs(array('main', 'errors'));
1008 
1009  $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorSessionInvalidatedAfterPasswordChange");
1010 
1011  $user->trigger_mesg = 'ErrorUserSessionWasInvalidated - login='.$login;
1012  }
1013 
1014  // Call trigger
1015  $result = $user->call_trigger('USER_LOGIN_FAILED', $user);
1016  if ($result < 0) {
1017  $error++;
1018  }
1019  // End call triggers
1020 
1021  // Hooks on failed login
1022  $action = '';
1023  $hookmanager->initHooks(array('login'));
1024  $parameters = array('dol_authmode' => (isset($dol_authmode) ? $dol_authmode : ''), 'dol_loginmesg' => $_SESSION["dol_loginmesg"]);
1025  $reshook = $hookmanager->executeHooks('afterLoginFailed', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
1026  if ($reshook < 0) {
1027  $error++;
1028  }
1029 
1030  $paramsurl = array();
1031  if (GETPOST('textbrowser', 'int')) {
1032  $paramsurl[] = 'textbrowser='.GETPOST('textbrowser', 'int');
1033  }
1034  if (GETPOST('nojs', 'int')) {
1035  $paramsurl[] = 'nojs='.GETPOST('nojs', 'int');
1036  }
1037  if (GETPOST('lang', 'aZ09')) {
1038  $paramsurl[] = 'lang='.GETPOST('lang', 'aZ09');
1039  }
1040  header('Location: '.DOL_URL_ROOT.'/index.php'.(count($paramsurl) ? '?'.implode('&', $paramsurl) : ''));
1041  exit;
1042  } else {
1043  // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
1044  $hookmanager->initHooks(array('main'));
1045 
1046  // Code for search criteria persistence.
1047  if (!empty($_GET['save_lastsearch_values']) && !empty($_SERVER["HTTP_REFERER"])) { // We must use $_GET here
1048  $relativepathstring = preg_replace('/\?.*$/', '', $_SERVER["HTTP_REFERER"]);
1049  $relativepathstring = preg_replace('/^https?:\/\/[^\/]*/', '', $relativepathstring); // Get full path except host server
1050  // Clean $relativepathstring
1051  if (constant('DOL_URL_ROOT')) {
1052  $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
1053  }
1054  $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
1055  $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
1056  //var_dump($relativepathstring);
1057 
1058  // We click on a link that leave a page we have to save search criteria, contextpage, limit and page and mode. We save them from tmp to no tmp
1059  if (!empty($_SESSION['lastsearch_values_tmp_'.$relativepathstring])) {
1060  $_SESSION['lastsearch_values_'.$relativepathstring] = $_SESSION['lastsearch_values_tmp_'.$relativepathstring];
1061  unset($_SESSION['lastsearch_values_tmp_'.$relativepathstring]);
1062  }
1063  if (!empty($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring])) {
1064  $_SESSION['lastsearch_contextpage_'.$relativepathstring] = $_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring];
1065  unset($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]);
1066  }
1067  if (!empty($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]) && $_SESSION['lastsearch_limit_tmp_'.$relativepathstring] != $conf->liste_limit) {
1068  $_SESSION['lastsearch_limit_'.$relativepathstring] = $_SESSION['lastsearch_limit_tmp_'.$relativepathstring];
1069  unset($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]);
1070  }
1071  if (!empty($_SESSION['lastsearch_page_tmp_'.$relativepathstring]) && $_SESSION['lastsearch_page_tmp_'.$relativepathstring] > 0) {
1072  $_SESSION['lastsearch_page_'.$relativepathstring] = $_SESSION['lastsearch_page_tmp_'.$relativepathstring];
1073  unset($_SESSION['lastsearch_page_tmp_'.$relativepathstring]);
1074  }
1075  if (!empty($_SESSION['lastsearch_mode_tmp_'.$relativepathstring])) {
1076  $_SESSION['lastsearch_mode_'.$relativepathstring] = $_SESSION['lastsearch_mode_tmp_'.$relativepathstring];
1077  unset($_SESSION['lastsearch_mode_tmp_'.$relativepathstring]);
1078  }
1079  }
1080 
1081  $action = '';
1082  $reshook = $hookmanager->executeHooks('updateSession', array(), $user, $action);
1083  if ($reshook < 0) {
1084  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1085  }
1086  }
1087  }
1088 
1089  // Is it a new session that has started ?
1090  // If we are here, this means authentication was successfull.
1091  if (!isset($_SESSION["dol_login"])) {
1092  // New session for this login has started.
1093  $error = 0;
1094 
1095  // Store value into session (values always stored)
1096  $_SESSION["dol_login"] = $user->login;
1097  $_SESSION["dol_logindate"] = dol_now('gmt');
1098  $_SESSION["dol_authmode"] = isset($dol_authmode) ? $dol_authmode : '';
1099  $_SESSION["dol_tz"] = isset($dol_tz) ? $dol_tz : '';
1100  $_SESSION["dol_tz_string"] = isset($dol_tz_string) ? $dol_tz_string : '';
1101  $_SESSION["dol_dst"] = isset($dol_dst) ? $dol_dst : '';
1102  $_SESSION["dol_dst_observed"] = isset($dol_dst_observed) ? $dol_dst_observed : '';
1103  $_SESSION["dol_dst_first"] = isset($dol_dst_first) ? $dol_dst_first : '';
1104  $_SESSION["dol_dst_second"] = isset($dol_dst_second) ? $dol_dst_second : '';
1105  $_SESSION["dol_screenwidth"] = isset($dol_screenwidth) ? $dol_screenwidth : '';
1106  $_SESSION["dol_screenheight"] = isset($dol_screenheight) ? $dol_screenheight : '';
1107  $_SESSION["dol_company"] = getDolGlobalString("MAIN_INFO_SOCIETE_NOM");
1108  $_SESSION["dol_entity"] = $conf->entity;
1109  // Store value into session (values stored only if defined)
1110  if (!empty($dol_hide_topmenu)) {
1111  $_SESSION['dol_hide_topmenu'] = $dol_hide_topmenu;
1112  }
1113  if (!empty($dol_hide_leftmenu)) {
1114  $_SESSION['dol_hide_leftmenu'] = $dol_hide_leftmenu;
1115  }
1116  if (!empty($dol_optimize_smallscreen)) {
1117  $_SESSION['dol_optimize_smallscreen'] = $dol_optimize_smallscreen;
1118  }
1119  if (!empty($dol_no_mouse_hover)) {
1120  $_SESSION['dol_no_mouse_hover'] = $dol_no_mouse_hover;
1121  }
1122  if (!empty($dol_use_jmobile)) {
1123  $_SESSION['dol_use_jmobile'] = $dol_use_jmobile;
1124  }
1125 
1126  dol_syslog("This is a new started user session. _SESSION['dol_login']=".$_SESSION["dol_login"]." Session id=".session_id());
1127 
1128  $db->begin();
1129 
1130  $user->update_last_login_date();
1131 
1132  $loginfo = 'TZ='.$_SESSION["dol_tz"].';TZString='.$_SESSION["dol_tz_string"].';Screen='.$_SESSION["dol_screenwidth"].'x'.$_SESSION["dol_screenheight"];
1133 
1134  // Call triggers for the "security events" log
1135  $user->trigger_mesg = $loginfo;
1136 
1137  // Call trigger
1138  $result = $user->call_trigger('USER_LOGIN', $user);
1139  if ($result < 0) {
1140  $error++;
1141  }
1142  // End call triggers
1143 
1144  // Hooks on successfull login
1145  $action = '';
1146  $hookmanager->initHooks(array('login'));
1147  $parameters = array('dol_authmode'=>$dol_authmode, 'dol_loginfo'=>$loginfo);
1148  $reshook = $hookmanager->executeHooks('afterLogin', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
1149  if ($reshook < 0) {
1150  $error++;
1151  }
1152 
1153  if ($error) {
1154  $db->rollback();
1155  session_destroy();
1156  dol_print_error($db, 'Error in some triggers USER_LOGIN or in some hooks afterLogin');
1157  exit;
1158  } else {
1159  $db->commit();
1160  }
1161 
1162  // Change landing page if defined.
1163  $landingpage = (empty($user->conf->MAIN_LANDING_PAGE) ? (empty($conf->global->MAIN_LANDING_PAGE) ? '' : $conf->global->MAIN_LANDING_PAGE) : $user->conf->MAIN_LANDING_PAGE);
1164  if (!empty($landingpage)) { // Example: /index.php
1165  $newpath = dol_buildpath($landingpage, 1);
1166  if ($_SERVER["PHP_SELF"] != $newpath) { // not already on landing page (avoid infinite loop)
1167  header('Location: '.$newpath);
1168  exit;
1169  }
1170  }
1171  }
1172 
1173 
1174  // If user admin, we force the rights-based modules
1175  if ($user->admin) {
1176  $user->rights->user->user->lire = 1;
1177  $user->rights->user->user->creer = 1;
1178  $user->rights->user->user->password = 1;
1179  $user->rights->user->user->supprimer = 1;
1180  $user->rights->user->self->creer = 1;
1181  $user->rights->user->self->password = 1;
1182 
1183  //Required if advanced permissions are used with MAIN_USE_ADVANCED_PERMS
1184  if (!empty($conf->global->MAIN_USE_ADVANCED_PERMS)) {
1185  if (empty($user->rights->user->user_advance)) {
1186  $user->rights->user->user_advance = new stdClass(); // To avoid warnings
1187  }
1188  if (empty($user->rights->user->self_advance)) {
1189  $user->rights->user->self_advance = new stdClass(); // To avoid warnings
1190  }
1191  if (empty($user->rights->user->group_advance)) {
1192  $user->rights->user->group_advance = new stdClass(); // To avoid warnings
1193  }
1194 
1195  $user->rights->user->user_advance->readperms = 1;
1196  $user->rights->user->user_advance->write = 1;
1197  $user->rights->user->self_advance->readperms = 1;
1198  $user->rights->user->self_advance->writeperms = 1;
1199  $user->rights->user->group_advance->read = 1;
1200  $user->rights->user->group_advance->readperms = 1;
1201  $user->rights->user->group_advance->write = 1;
1202  $user->rights->user->group_advance->delete = 1;
1203  }
1204  }
1205 
1206  /*
1207  * Overwrite some configs globals (try to avoid this and have code to use instead $user->conf->xxx)
1208  */
1209 
1210  // Set liste_limit
1211  if (isset($user->conf->MAIN_SIZE_LISTE_LIMIT)) {
1212  $conf->liste_limit = $user->conf->MAIN_SIZE_LISTE_LIMIT; // Can be 0
1213  }
1214  if (isset($user->conf->PRODUIT_LIMIT_SIZE)) {
1215  $conf->product->limit_size = $user->conf->PRODUIT_LIMIT_SIZE; // Can be 0
1216  }
1217 
1218  // Replace conf->css by personalized value if theme not forced
1219  if (empty($conf->global->MAIN_FORCETHEME) && !empty($user->conf->MAIN_THEME)) {
1220  $conf->theme = $user->conf->MAIN_THEME;
1221  $conf->css = "/theme/".$conf->theme."/style.css.php";
1222  }
1223 } else {
1224  // We may have NOLOGIN set, but NOREQUIREUSER not
1225  if (!empty($user) && method_exists($user, 'loadDefaultValues')) {
1226  $user->loadDefaultValues(); // Load default values for everybody (works even if $user->id = 0
1227  }
1228 }
1229 
1230 
1231 // Case forcing style from url
1232 if (GETPOST('theme', 'aZ09')) {
1233  $conf->theme = GETPOST('theme', 'aZ09', 1);
1234  $conf->css = "/theme/".$conf->theme."/style.css.php";
1235 }
1236 
1237 // Set javascript option
1238 if (GETPOST('nojs', 'int')) { // If javascript was not disabled on URL
1239  $conf->use_javascript_ajax = 0;
1240 } else {
1241  if (!empty($user->conf->MAIN_DISABLE_JAVASCRIPT)) {
1242  $conf->use_javascript_ajax = !$user->conf->MAIN_DISABLE_JAVASCRIPT;
1243  }
1244 }
1245 
1246 // Set MAIN_OPTIMIZEFORTEXTBROWSER for user (must be after login part)
1247 if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && !empty($user->conf->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1248  $conf->global->MAIN_OPTIMIZEFORTEXTBROWSER = $user->conf->MAIN_OPTIMIZEFORTEXTBROWSER;
1249 }
1250 
1251 // set MAIN_OPTIMIZEFORCOLORBLIND for user
1252 $conf->global->MAIN_OPTIMIZEFORCOLORBLIND = empty($user->conf->MAIN_OPTIMIZEFORCOLORBLIND) ? '' : $user->conf->MAIN_OPTIMIZEFORCOLORBLIND;
1253 
1254 // Set terminal output option according to conf->browser.
1255 if (GETPOST('dol_hide_leftmenu', 'int') || !empty($_SESSION['dol_hide_leftmenu'])) {
1256  $conf->dol_hide_leftmenu = 1;
1257 }
1258 if (GETPOST('dol_hide_topmenu', 'int') || !empty($_SESSION['dol_hide_topmenu'])) {
1259  $conf->dol_hide_topmenu = 1;
1260 }
1261 if (GETPOST('dol_optimize_smallscreen', 'int') || !empty($_SESSION['dol_optimize_smallscreen'])) {
1262  $conf->dol_optimize_smallscreen = 1;
1263 }
1264 if (GETPOST('dol_no_mouse_hover', 'int') || !empty($_SESSION['dol_no_mouse_hover'])) {
1265  $conf->dol_no_mouse_hover = 1;
1266 }
1267 if (GETPOST('dol_use_jmobile', 'int') || !empty($_SESSION['dol_use_jmobile'])) {
1268  $conf->dol_use_jmobile = 1;
1269 }
1270 // If not on Desktop
1271 if (!empty($conf->browser->layout) && $conf->browser->layout != 'classic') {
1272  $conf->dol_no_mouse_hover = 1;
1273 }
1274 
1275 // If on smartphone or optmized for small screen
1276 if ((!empty($conf->browser->layout) && $conf->browser->layout == 'phone')
1277  || (!empty($_SESSION['dol_screenwidth']) && $_SESSION['dol_screenwidth'] < 400)
1278  || (!empty($_SESSION['dol_screenheight']) && $_SESSION['dol_screenheight'] < 400
1279  || !empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
1280 ) {
1281  $conf->dol_optimize_smallscreen = 1;
1282 
1283  if (isset($conf->global->PRODUIT_DESC_IN_FORM) && $conf->global->PRODUIT_DESC_IN_FORM == 1) {
1284  $conf->global->PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE = 0;
1285  }
1286 }
1287 // Replace themes bugged with jmobile with eldy
1288 if (!empty($conf->dol_use_jmobile) && in_array($conf->theme, array('bureau2crea', 'cameleo', 'amarok'))) {
1289  $conf->theme = 'eldy';
1290  $conf->css = "/theme/".$conf->theme."/style.css.php";
1291 }
1292 
1293 if (!defined('NOREQUIRETRAN')) {
1294  if (!GETPOST('lang', 'aZ09')) { // If language was not forced on URL
1295  // If user has chosen its own language
1296  if (!empty($user->conf->MAIN_LANG_DEFAULT)) {
1297  // If different than current language
1298  //print ">>>".$langs->getDefaultLang()."-".$user->conf->MAIN_LANG_DEFAULT;
1299  if ($langs->getDefaultLang() != $user->conf->MAIN_LANG_DEFAULT) {
1300  $langs->setDefaultLang($user->conf->MAIN_LANG_DEFAULT);
1301  }
1302  }
1303  }
1304 }
1305 
1306 if (!defined('NOLOGIN')) {
1307  // If the login is not recovered, it is identified with an account that does not exist.
1308  // Hacking attempt?
1309  if (!$user->login) {
1310  accessforbidden();
1311  }
1312 
1313  // Check if user is active
1314  if ($user->statut < 1) {
1315  // If not active, we refuse the user
1316  $langs->loadLangs(array("errors", "other"));
1317  dol_syslog("Authentication KO as login is disabled", LOG_NOTICE);
1318  accessforbidden("ErrorLoginDisabled");
1319  }
1320 
1321  // Load permissions
1322  $user->getrights();
1323 }
1324 
1325 dol_syslog("--- Access to ".(empty($_SERVER["REQUEST_METHOD"]) ? '' : $_SERVER["REQUEST_METHOD"].' ').$_SERVER["PHP_SELF"].' - action='.GETPOST('action', 'aZ09').', massaction='.GETPOST('massaction', 'aZ09').(defined('NOTOKENRENEWAL') ? ' NOTOKENRENEWAL='.constant('NOTOKENRENEWAL') : ''), LOG_NOTICE);
1326 //Another call for easy debugg
1327 //dol_syslog("Access to ".$_SERVER["PHP_SELF"].' '.$_SERVER["HTTP_REFERER"].' GET='.join(',',array_keys($_GET)).'->'.join(',',$_GET).' POST:'.join(',',array_keys($_POST)).'->'.join(',',$_POST));
1328 
1329 // Load main languages files
1330 if (!defined('NOREQUIRETRAN')) {
1331  // Load translation files required by page
1332  $langs->loadLangs(array('main', 'dict'));
1333 }
1334 
1335 // Define some constants used for style of arrays
1336 $bc = array(0=>'class="impair"', 1=>'class="pair"');
1337 $bcdd = array(0=>'class="drag drop oddeven"', 1=>'class="drag drop oddeven"');
1338 $bcnd = array(0=>'class="nodrag nodrop nohover"', 1=>'class="nodrag nodrop nohoverpair"'); // Used for tr to add new lines
1339 $bctag = array(0=>'class="impair tagtr"', 1=>'class="pair tagtr"');
1340 
1341 // Define messages variables
1342 $mesg = ''; $warning = ''; $error = 0;
1343 // deprecated, see setEventMessages() and dol_htmloutput_events()
1344 $mesgs = array(); $warnings = array(); $errors = array();
1345 
1346 // Constants used to defined number of lines in textarea
1347 if (empty($conf->browser->firefox)) {
1348  define('ROWS_1', 1);
1349  define('ROWS_2', 2);
1350  define('ROWS_3', 3);
1351  define('ROWS_4', 4);
1352  define('ROWS_5', 5);
1353  define('ROWS_6', 6);
1354  define('ROWS_7', 7);
1355  define('ROWS_8', 8);
1356  define('ROWS_9', 9);
1357 } else {
1358  define('ROWS_1', 0);
1359  define('ROWS_2', 1);
1360  define('ROWS_3', 2);
1361  define('ROWS_4', 3);
1362  define('ROWS_5', 4);
1363  define('ROWS_6', 5);
1364  define('ROWS_7', 6);
1365  define('ROWS_8', 7);
1366  define('ROWS_9', 8);
1367 }
1368 
1369 $heightforframes = 50;
1370 
1371 // Init menu manager
1372 if (!defined('NOREQUIREMENU')) {
1373  if (empty($user->socid)) { // If internal user or not defined
1374  $conf->standard_menu = (empty($conf->global->MAIN_MENU_STANDARD_FORCED) ? (empty($conf->global->MAIN_MENU_STANDARD) ? 'eldy_menu.php' : $conf->global->MAIN_MENU_STANDARD) : $conf->global->MAIN_MENU_STANDARD_FORCED);
1375  } else {
1376  // If external user
1377  $conf->standard_menu = (empty($conf->global->MAIN_MENUFRONT_STANDARD_FORCED) ? (empty($conf->global->MAIN_MENUFRONT_STANDARD) ? 'eldy_menu.php' : $conf->global->MAIN_MENUFRONT_STANDARD) : $conf->global->MAIN_MENUFRONT_STANDARD_FORCED);
1378  }
1379 
1380  // Load the menu manager (only if not already done)
1381  $file_menu = $conf->standard_menu;
1382  if (GETPOST('menu', 'alpha')) {
1383  $file_menu = GETPOST('menu', 'alpha'); // example: menu=eldy_menu.php
1384  }
1385  if (!class_exists('MenuManager')) {
1386  $menufound = 0;
1387  $dirmenus = array_merge(array("/core/menus/"), (array) $conf->modules_parts['menus']);
1388  foreach ($dirmenus as $dirmenu) {
1389  $menufound = dol_include_once($dirmenu."standard/".$file_menu);
1390  if (class_exists('MenuManager')) {
1391  break;
1392  }
1393  }
1394  if (!class_exists('MenuManager')) { // If failed to include, we try with standard eldy_menu.php
1395  dol_syslog("You define a menu manager '".$file_menu."' that can not be loaded.", LOG_WARNING);
1396  $file_menu = 'eldy_menu.php';
1397  include_once DOL_DOCUMENT_ROOT."/core/menus/standard/".$file_menu;
1398  }
1399  }
1400  $menumanager = new MenuManager($db, empty($user->socid) ? 0 : 1);
1401  $menumanager->loadMenu();
1402 }
1403 
1404 if (!empty(GETPOST('seteventmessages', 'alpha'))) {
1405  $message = GETPOST('seteventmessages', 'alpha');
1406  $messages = explode(',', $message);
1407  foreach ($messages as $key => $msg) {
1408  $tmp = explode(':', $msg);
1409  setEventMessages($tmp[0], null, !empty($tmp[1]) ? $tmp[1] : 'mesgs');
1410  }
1411 }
1412 
1413 // Functions
1414 
1415 if (!function_exists("llxHeader")) {
1436  function llxHeader($head = '', $title = '', $help_url = '', $target = '', $disablejs = 0, $disablehead = 0, $arrayofjs = '', $arrayofcss = '', $morequerystring = '', $morecssonbody = '', $replacemainareaby = '', $disablenofollow = 0, $disablenoindex = 0)
1437  {
1438  global $conf, $hookmanager;
1439 
1440  // html header
1441  top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss, 0, $disablenofollow, $disablenoindex);
1442 
1443  $tmpcsstouse = 'sidebar-collapse'.($morecssonbody ? ' '.$morecssonbody : '');
1444  // If theme MD and classic layer, we open the menulayer by default.
1445  if ($conf->theme == 'md' && !in_array($conf->browser->layout, array('phone', 'tablet')) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
1446  global $mainmenu;
1447  if ($mainmenu != 'website') {
1448  $tmpcsstouse = $morecssonbody; // We do not use sidebar-collpase by default to have menuhider open by default.
1449  }
1450  }
1451 
1452  if (!empty($conf->global->MAIN_OPTIMIZEFORCOLORBLIND)) {
1453  $tmpcsstouse .= ' colorblind-'.strip_tags($conf->global->MAIN_OPTIMIZEFORCOLORBLIND);
1454  }
1455 
1456  print '<body id="mainbody" class="'.$tmpcsstouse.'">'."\n";
1457 
1458  $parameters = array('help_url' => $help_url);
1459  $reshook = $hookmanager->executeHooks('changeHelpURL', $parameters);
1460  if ($reshook > 0) {
1461  $help_url = $hookmanager->resPrint;
1462  }
1463 
1464  // top menu and left menu area
1465  if ((empty($conf->dol_hide_topmenu) || GETPOST('dol_invisible_topmenu', 'int')) && !GETPOST('dol_openinpopup', 'aZ09')) {
1466  top_menu($head, $title, $target, $disablejs, $disablehead, $arrayofjs, $arrayofcss, $morequerystring, $help_url);
1467  }
1468 
1469  if (empty($conf->dol_hide_leftmenu) && !GETPOST('dol_openinpopup', 'aZ09')) {
1470  left_menu(array(), $help_url, '', '', 1, $title, 1); // $menumanager is retrieved with a global $menumanager inside this function
1471  }
1472 
1473  // main area
1474  if ($replacemainareaby) {
1475  print $replacemainareaby;
1476  return;
1477  }
1478  main_area($title);
1479  }
1480 }
1481 
1482 
1490 function top_httphead($contenttype = 'text/html', $forcenocache = 0)
1491 {
1492  global $db, $conf, $hookmanager;
1493 
1494  if ($contenttype == 'text/html') {
1495  header("Content-Type: text/html; charset=".$conf->file->character_set_client);
1496  } else {
1497  header("Content-Type: ".$contenttype);
1498  }
1499 
1500  // Security options
1501 
1502  // X-Content-Type-Options
1503  header("X-Content-Type-Options: nosniff"); // With the nosniff option, if the server says the content is text/html, the browser will render it as text/html (note that most browsers now force this option to on)
1504 
1505  // X-Frame-Options
1506  if (!defined('XFRAMEOPTIONS_ALLOWALL')) {
1507  header("X-Frame-Options: SAMEORIGIN"); // Frames allowed only if on same domain (stop some XSS attacks)
1508  } else {
1509  header("X-Frame-Options: ALLOWALL");
1510  }
1511 
1512  // X-XSS-Protection
1513  //header("X-XSS-Protection: 1"); // XSS filtering protection of some browsers (note: use of Content-Security-Policy is more efficient). Disabled as deprecated.
1514 
1515  // Content-Security-Policy-Report-Only
1516  if (!defined('MAIN_SECURITY_FORCECSPRO')) {
1517  // If CSP not forced from the page
1518 
1519  // A default security policy that keep usage of js external component like ckeditor, stripe, google, working
1520  // For example: to restrict to only local resources, except for css (cloudflare+google), and js (transifex + google tags) and object/iframe (youtube)
1521  // default-src 'self'; style-src: https://cdnjs.cloudflare.com https://fonts.googleapis.com; script-src: https://cdn.transifex.com https://www.googletagmanager.com; object-src https://youtube.com; frame-src https://youtube.com; img-src: *;
1522  // For example, to restrict everything to itself except img that can be on other servers:
1523  // default-src 'self'; img-src *;
1524  // Pre-existing site that uses too much js code to fix but wants to ensure resources are loaded only over https and disable plugins:
1525  // default-src https: 'unsafe-inline' 'unsafe-eval'; object-src 'none'
1526  //
1527  // $contentsecuritypolicy = "frame-ancestors 'self'; img-src * data:; font-src *; default-src 'self' 'unsafe-inline' 'unsafe-eval' *.paypal.com *.stripe.com *.google.com *.googleapis.com *.google-analytics.com *.googletagmanager.com;";
1528  // $contentsecuritypolicy = "frame-ancestors 'self'; img-src * data:; font-src *; default-src *; script-src 'self' 'unsafe-inline' *.paypal.com *.stripe.com *.google.com *.googleapis.com *.google-analytics.com *.googletagmanager.com; style-src 'self' 'unsafe-inline'; connect-src 'self';";
1529  $contentsecuritypolicy = getDolGlobalString('MAIN_SECURITY_FORCECSPRO');
1530 
1531  if (!is_object($hookmanager)) {
1532  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1533  $hookmanager = new HookManager($db);
1534  }
1535  $hookmanager->initHooks(array("main"));
1536 
1537  $parameters = array('contentsecuritypolicy'=>$contentsecuritypolicy, 'mode'=>'reportonly');
1538  $result = $hookmanager->executeHooks('setContentSecurityPolicy', $parameters); // Note that $action and $object may have been modified by some hooks
1539  if ($result > 0) {
1540  $contentsecuritypolicy = $hookmanager->resPrint; // Replace CSP
1541  } else {
1542  $contentsecuritypolicy .= $hookmanager->resPrint; // Concat CSP
1543  }
1544 
1545  if (!empty($contentsecuritypolicy)) {
1546  header("Content-Security-Policy-Report-Only: ".$contentsecuritypolicy);
1547  }
1548  } else {
1549  header("Content-Security-Policy: ".constant('MAIN_SECURITY_FORCECSPRO'));
1550  }
1551 
1552  // Content-Security-Policy
1553  if (!defined('MAIN_SECURITY_FORCECSP')) {
1554  // If CSP not forced from the page
1555 
1556  // A default security policy that keep usage of js external component like ckeditor, stripe, google, working
1557  // For example: to restrict to only local resources, except for css (cloudflare+google), and js (transifex + google tags) and object/iframe (youtube)
1558  // default-src 'self'; style-src: https://cdnjs.cloudflare.com https://fonts.googleapis.com; script-src: https://cdn.transifex.com https://www.googletagmanager.com; object-src https://youtube.com; frame-src https://youtube.com; img-src: *;
1559  // For example, to restrict everything to itself except img that can be on other servers:
1560  // default-src 'self'; img-src *;
1561  // Pre-existing site that uses too much js code to fix but wants to ensure resources are loaded only over https and disable plugins:
1562  // default-src https: 'unsafe-inline' 'unsafe-eval'; object-src 'none'
1563  //
1564  // $contentsecuritypolicy = "frame-ancestors 'self'; img-src * data:; font-src *; default-src 'self' 'unsafe-inline' 'unsafe-eval' *.paypal.com *.stripe.com *.google.com *.googleapis.com *.google-analytics.com *.googletagmanager.com;";
1565  // $contentsecuritypolicy = "frame-ancestors 'self'; img-src * data:; font-src *; default-src *; script-src 'self' 'unsafe-inline' *.paypal.com *.stripe.com *.google.com *.googleapis.com *.google-analytics.com *.googletagmanager.com; style-src 'self' 'unsafe-inline'; connect-src 'self';";
1566  $contentsecuritypolicy = getDolGlobalString('MAIN_SECURITY_FORCECSP');
1567 
1568  if (!is_object($hookmanager)) {
1569  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1570  $hookmanager = new HookManager($db);
1571  }
1572  $hookmanager->initHooks(array("main"));
1573 
1574  $parameters = array('contentsecuritypolicy'=>$contentsecuritypolicy, 'mode'=>'active');
1575  $result = $hookmanager->executeHooks('setContentSecurityPolicy', $parameters); // Note that $action and $object may have been modified by some hooks
1576  if ($result > 0) {
1577  $contentsecuritypolicy = $hookmanager->resPrint; // Replace CSP
1578  } else {
1579  $contentsecuritypolicy .= $hookmanager->resPrint; // Concat CSP
1580  }
1581 
1582  if (!empty($contentsecuritypolicy)) {
1583  header("Content-Security-Policy: ".$contentsecuritypolicy);
1584  }
1585  } else {
1586  header("Content-Security-Policy: ".constant('MAIN_SECURITY_FORCECSP'));
1587  }
1588 
1589  // Referrer-Policy
1590  // Say if we must provide the referrer when we jump onto another web page.
1591  // Default browser are 'strict-origin-when-cross-origin' (only domain is sent on other domain switching), we want more so we use 'same-origin' so browser doesn't send any referrer when going into another web site domain.
1592  if (!defined('MAIN_SECURITY_FORCERP')) {
1593  $referrerpolicy = getDolGlobalString('MAIN_SECURITY_FORCERP', "same-origin");
1594 
1595  header("Referrer-Policy: ".$referrerpolicy);
1596  }
1597 
1598  if ($forcenocache) {
1599  header("Cache-Control: no-cache, no-store, must-revalidate, max-age=0");
1600  }
1601 
1602  // No need to add this token in header, we use instead the one into the forms.
1603  //header("anti-csrf-token: ".newToken());
1604 }
1605 
1621 function top_htmlhead($head, $title = '', $disablejs = 0, $disablehead = 0, $arrayofjs = '', $arrayofcss = '', $disableforlogin = 0, $disablenofollow = 0, $disablenoindex = 0)
1622 {
1623  global $db, $conf, $langs, $user, $mysoc, $hookmanager;
1624 
1625  top_httphead();
1626 
1627  if (empty($conf->css)) {
1628  $conf->css = '/theme/eldy/style.css.php'; // If not defined, eldy by default
1629  }
1630 
1631  print '<!doctype html>'."\n";
1632 
1633  print '<html lang="'.substr($langs->defaultlang, 0, 2).'">'."\n";
1634 
1635  //print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">'."\n";
1636  if (empty($disablehead)) {
1637  if (!is_object($hookmanager)) {
1638  include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1639  $hookmanager = new HookManager($db);
1640  }
1641  $hookmanager->initHooks(array("main"));
1642 
1643  $ext = 'layout='.$conf->browser->layout.'&amp;version='.urlencode(DOL_VERSION);
1644 
1645  print "<head>\n";
1646 
1647  if (GETPOST('dol_basehref', 'alpha')) {
1648  print '<base href="'.dol_escape_htmltag(GETPOST('dol_basehref', 'alpha')).'">'."\n";
1649  }
1650 
1651  // Displays meta
1652  print '<meta charset="utf-8">'."\n";
1653  print '<meta name="robots" content="'.($disablenoindex ? 'index' : 'noindex').($disablenofollow ? ',follow' : ',nofollow').'">'."\n"; // Do not index
1654  print '<meta name="viewport" content="width=device-width, initial-scale=1.0">'."\n"; // Scale for mobile device
1655  print '<meta name="author" content="Dolibarr Development Team">'."\n";
1656  print '<meta name="anti-csrf-newtoken" content="'.newToken().'">'."\n";
1657  print '<meta name="anti-csrf-currenttoken" content="'.currentToken().'">'."\n";
1658  if (getDolGlobalInt('MAIN_FEATURES_LEVEL')) {
1659  print '<meta name="MAIN_FEATURES_LEVEL" content="'.getDolGlobalInt('MAIN_FEATURES_LEVEL').'">'."\n";
1660  }
1661  // Favicon
1662  $favicon = DOL_URL_ROOT.'/theme/dolibarr_256x256_color.png';
1663  if (!empty($mysoc->logo_squarred_mini)) {
1664  $favicon = DOL_URL_ROOT.'/viewimage.php?cache=1&modulepart=mycompany&file='.urlencode('logos/thumbs/'.$mysoc->logo_squarred_mini);
1665  }
1666  if (getDolGlobalString('MAIN_FAVICON_URL')) {
1667  $favicon = getDolGlobalString('MAIN_FAVICON_URL');
1668  }
1669  if (empty($conf->dol_use_jmobile)) {
1670  print '<link rel="shortcut icon" type="image/x-icon" href="'.$favicon.'"/>'."\n"; // Not required into an Android webview
1671  }
1672 
1673  //if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) print '<link rel="top" title="'.$langs->trans("Home").'" href="'.(DOL_URL_ROOT?DOL_URL_ROOT:'/').'">'."\n";
1674  //if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) print '<link rel="copyright" title="GNU General Public License" href="https://www.gnu.org/copyleft/gpl.html#SEC1">'."\n";
1675  //if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) print '<link rel="author" title="Dolibarr Development Team" href="https://www.dolibarr.org">'."\n";
1676 
1677  // Mobile appli like icon
1678  $manifest = DOL_URL_ROOT.'/theme/'.$conf->theme.'/manifest.json.php';
1679  if (!empty($manifest)) {
1680  print '<link rel="manifest" href="'.$manifest.'" />'."\n";
1681  }
1682 
1683  if (!empty($conf->global->THEME_ELDY_TOPMENU_BACK1)) {
1684  // TODO: use auto theme color switch
1685  print '<meta name="theme-color" content="rgb('.$conf->global->THEME_ELDY_TOPMENU_BACK1.')">'."\n";
1686  }
1687 
1688  // Auto refresh page
1689  if (GETPOST('autorefresh', 'int') > 0) {
1690  print '<meta http-equiv="refresh" content="'.GETPOST('autorefresh', 'int').'">';
1691  }
1692 
1693  // Displays title
1694  $appli = constant('DOL_APPLICATION_TITLE');
1695  if (!empty($conf->global->MAIN_APPLICATION_TITLE)) {
1696  $appli = $conf->global->MAIN_APPLICATION_TITLE;
1697  }
1698 
1699  print '<title>';
1700  $titletoshow = '';
1701  if ($title && !empty($conf->global->MAIN_HTML_TITLE) && preg_match('/noapp/', $conf->global->MAIN_HTML_TITLE)) {
1702  $titletoshow = dol_htmlentities($title);
1703  } elseif ($title) {
1704  $titletoshow = dol_htmlentities($appli.' - '.$title);
1705  } else {
1706  $titletoshow = dol_htmlentities($appli);
1707  }
1708 
1709  $parameters = array('title'=>$titletoshow);
1710  $result = $hookmanager->executeHooks('setHtmlTitle', $parameters); // Note that $action and $object may have been modified by some hooks
1711  if ($result > 0) {
1712  $titletoshow = $hookmanager->resPrint; // Replace Title to show
1713  } else {
1714  $titletoshow .= $hookmanager->resPrint; // Concat to Title to show
1715  }
1716 
1717  print $titletoshow;
1718  print '</title>';
1719 
1720  print "\n";
1721 
1722  if (GETPOST('version', 'int')) {
1723  $ext = 'version='.GETPOST('version', 'int'); // usefull to force no cache on css/js
1724  }
1725  // Refresh value of MAIN_IHM_PARAMS_REV before forging the parameter line.
1726  if (GETPOST('dol_resetcache')) {
1727  dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", ((int) $conf->global->MAIN_IHM_PARAMS_REV) + 1, 'chaine', 0, '', $conf->entity);
1728  }
1729 
1730  $themeparam = '?lang='.$langs->defaultlang.'&amp;theme='.$conf->theme.(GETPOST('optioncss', 'aZ09') ? '&amp;optioncss='.GETPOST('optioncss', 'aZ09', 1) : '').(empty($user->id) ? '' : ('&amp;userid='.$user->id)).'&amp;entity='.$conf->entity;
1731 
1732  $themeparam .= ($ext ? '&amp;'.$ext : '').'&amp;revision='.getDolGlobalInt("MAIN_IHM_PARAMS_REV");
1733  if (GETPOSTISSET('dol_hide_topmenu')) {
1734  $themeparam .= '&amp;dol_hide_topmenu='.GETPOST('dol_hide_topmenu', 'int');
1735  }
1736  if (GETPOSTISSET('dol_hide_leftmenu')) {
1737  $themeparam .= '&amp;dol_hide_leftmenu='.GETPOST('dol_hide_leftmenu', 'int');
1738  }
1739  if (GETPOSTISSET('dol_optimize_smallscreen')) {
1740  $themeparam .= '&amp;dol_optimize_smallscreen='.GETPOST('dol_optimize_smallscreen', 'int');
1741  }
1742  if (GETPOSTISSET('dol_no_mouse_hover')) {
1743  $themeparam .= '&amp;dol_no_mouse_hover='.GETPOST('dol_no_mouse_hover', 'int');
1744  }
1745  if (GETPOSTISSET('dol_use_jmobile')) {
1746  $themeparam .= '&amp;dol_use_jmobile='.GETPOST('dol_use_jmobile', 'int'); $conf->dol_use_jmobile = GETPOST('dol_use_jmobile', 'int');
1747  }
1748  if (GETPOSTISSET('THEME_DARKMODEENABLED')) {
1749  $themeparam .= '&amp;THEME_DARKMODEENABLED='.GETPOST('THEME_DARKMODEENABLED', 'int');
1750  }
1751  if (GETPOSTISSET('THEME_SATURATE_RATIO')) {
1752  $themeparam .= '&amp;THEME_SATURATE_RATIO='.GETPOST('THEME_SATURATE_RATIO', 'int');
1753  }
1754 
1755  if (!empty($conf->global->MAIN_ENABLE_FONT_ROBOTO)) {
1756  print '<link rel="preconnect" href="https://fonts.gstatic.com">'."\n";
1757  print '<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@200;300;400;500;600&display=swap" rel="stylesheet">'."\n";
1758  }
1759 
1760  if (!defined('DISABLE_JQUERY') && !$disablejs && $conf->use_javascript_ajax) {
1761  print '<!-- Includes CSS for JQuery (Ajax library) -->'."\n";
1762  $jquerytheme = 'base';
1763  if (!empty($conf->global->MAIN_USE_JQUERY_THEME)) {
1764  $jquerytheme = $conf->global->MAIN_USE_JQUERY_THEME;
1765  }
1766  if (constant('JS_JQUERY_UI')) {
1767  print '<link rel="stylesheet" type="text/css" href="'.JS_JQUERY_UI.'css/'.$jquerytheme.'/jquery-ui.min.css'.($ext ? '?'.$ext : '').'">'."\n"; // Forced JQuery
1768  } else {
1769  print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/css/'.$jquerytheme.'/jquery-ui.css'.($ext ? '?'.$ext : '').'">'."\n"; // JQuery
1770  }
1771  if (!defined('DISABLE_JQUERY_JNOTIFY')) {
1772  print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/jnotify/jquery.jnotify-alt.min.css'.($ext ? '?'.$ext : '').'">'."\n"; // JNotify
1773  }
1774  if (!defined('DISABLE_SELECT2') && (!empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT'))) { // jQuery plugin "mutiselect", "multiple-select", "select2"...
1775  $tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
1776  print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/'.$tmpplugin.'/dist/css/'.$tmpplugin.'.css'.($ext ? '?'.$ext : '').'">'."\n";
1777  }
1778  }
1779 
1780  if (!defined('DISABLE_FONT_AWSOME')) {
1781  print '<!-- Includes CSS for font awesome -->'."\n";
1782  print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/theme/common/fontawesome-5/css/all.min.css'.($ext ? '?'.$ext : '').'">'."\n";
1783  print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/theme/common/fontawesome-5/css/v4-shims.min.css'.($ext ? '?'.$ext : '').'">'."\n";
1784  }
1785 
1786  print '<!-- Includes CSS for Dolibarr theme -->'."\n";
1787  // Output style sheets (optioncss='print' or ''). Note: $conf->css looks like '/theme/eldy/style.css.php'
1788  $themepath = dol_buildpath($conf->css, 1);
1789  $themesubdir = '';
1790  if (!empty($conf->modules_parts['theme'])) { // This slow down
1791  foreach ($conf->modules_parts['theme'] as $reldir) {
1792  if (file_exists(dol_buildpath($reldir.$conf->css, 0))) {
1793  $themepath = dol_buildpath($reldir.$conf->css, 1);
1794  $themesubdir = $reldir;
1795  break;
1796  }
1797  }
1798  }
1799 
1800  //print 'themepath='.$themepath.' themeparam='.$themeparam;exit;
1801  print '<link rel="stylesheet" type="text/css" href="'.$themepath.$themeparam.'">'."\n";
1802  if (!empty($conf->global->MAIN_FIX_FLASH_ON_CHROME)) {
1803  print '<!-- Includes CSS that does not exists as a workaround of flash bug of chrome -->'."\n".'<link rel="stylesheet" type="text/css" href="filethatdoesnotexiststosolvechromeflashbug">'."\n";
1804  }
1805 
1806  // CSS forced by modules (relative url starting with /)
1807  if (!empty($conf->modules_parts['css'])) {
1808  $arraycss = (array) $conf->modules_parts['css'];
1809  foreach ($arraycss as $modcss => $filescss) {
1810  $filescss = (array) $filescss; // To be sure filecss is an array
1811  foreach ($filescss as $cssfile) {
1812  if (empty($cssfile)) {
1813  dol_syslog("Warning: module ".$modcss." declared a css path file into its descriptor that is empty.", LOG_WARNING);
1814  }
1815  // cssfile is a relative path
1816  $urlforcss = dol_buildpath($cssfile, 1);
1817  if ($urlforcss && $urlforcss != '/') {
1818  print '<!-- Includes CSS added by module '.$modcss.' -->'."\n".'<link rel="stylesheet" type="text/css" href="'.$urlforcss;
1819  // We add params only if page is not static, because some web server setup does not return content type text/css if url has parameters, so browser cache is not used.
1820  if (!preg_match('/\.css$/i', $cssfile)) {
1821  print $themeparam;
1822  }
1823  print '">'."\n";
1824  } else {
1825  dol_syslog("Warning: module ".$modcss." declared a css path file for a file we can't find.", LOG_WARNING);
1826  }
1827  }
1828  }
1829  }
1830  // CSS forced by page in top_htmlhead call (relative url starting with /)
1831  if (is_array($arrayofcss)) {
1832  foreach ($arrayofcss as $cssfile) {
1833  if (preg_match('/^(http|\/\/)/i', $cssfile)) {
1834  $urltofile = $cssfile;
1835  } else {
1836  $urltofile = dol_buildpath($cssfile, 1);
1837  }
1838  print '<!-- Includes CSS added by page -->'."\n".'<link rel="stylesheet" type="text/css" title="default" href="'.$urltofile;
1839  // We add params only if page is not static, because some web server setup does not return content type text/css if url has parameters and browser cache is not used.
1840  if (!preg_match('/\.css$/i', $cssfile)) {
1841  print $themeparam;
1842  }
1843  print '">'."\n";
1844  }
1845  }
1846 
1847  // Custom CSS
1848  if (getDolGlobalString('MAIN_IHM_CUSTOM_CSS')) {
1849  // If a custom CSS was set, we add link to the custom css php file
1850  print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/theme/custom.css.php">'."\n";
1851  }
1852 
1853  // Output standard javascript links
1854  if (!defined('DISABLE_JQUERY') && !$disablejs && !empty($conf->use_javascript_ajax)) {
1855  // JQuery. Must be before other includes
1856  print '<!-- Includes JS for JQuery -->'."\n";
1857  if (defined('JS_JQUERY') && constant('JS_JQUERY')) {
1858  print '<script nonce="'.getNonce().'" src="'.JS_JQUERY.'jquery.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1859  } else {
1860  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1861  }
1862  if (defined('JS_JQUERY_UI') && constant('JS_JQUERY_UI')) {
1863  print '<script nonce="'.getNonce().'" src="'.JS_JQUERY_UI.'jquery-ui.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1864  } else {
1865  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery-ui.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1866  }
1867  // jQuery jnotify
1868  if (empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) && !defined('DISABLE_JQUERY_JNOTIFY')) {
1869  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jnotify/jquery.jnotify.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1870  }
1871  // Table drag and drop lines
1872  if (empty($disableforlogin) && !defined('DISABLE_JQUERY_TABLEDND')) {
1873  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/tablednd/jquery.tablednd.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1874  }
1875  // Chart
1876  if (empty($disableforlogin) && (empty($conf->global->MAIN_JS_GRAPH) || $conf->global->MAIN_JS_GRAPH == 'chart') && !defined('DISABLE_JS_GRAPH')) {
1877  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/nnnick/chartjs/dist/chart.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1878  }
1879 
1880  // jQuery jeditable for Edit In Place features
1881  if (!empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && !defined('DISABLE_JQUERY_JEDITABLE')) {
1882  print '<!-- JS to manage editInPlace feature -->'."\n";
1883  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1884  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-datepicker.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1885  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-autocomplete.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1886  print '<script>'."\n";
1887  print 'var urlSaveInPlace = \''.DOL_URL_ROOT.'/core/ajax/saveinplace.php\';'."\n";
1888  print 'var urlLoadInPlace = \''.DOL_URL_ROOT.'/core/ajax/loadinplace.php\';'."\n";
1889  print 'var tooltipInPlace = \''.$langs->transnoentities('ClickToEdit').'\';'."\n"; // Added in title attribute of span
1890  print 'var placeholderInPlace = \'&nbsp;\';'."\n"; // If we put another string than $langs->trans("ClickToEdit") here, nothing is shown. If we put empty string, there is error, Why ?
1891  print 'var cancelInPlace = \''.$langs->trans("Cancel").'\';'."\n";
1892  print 'var submitInPlace = \''.$langs->trans('Ok').'\';'."\n";
1893  print 'var indicatorInPlace = \'<img src="'.DOL_URL_ROOT."/theme/".$conf->theme."/img/working.gif".'">\';'."\n";
1894  print 'var withInPlace = 300;'; // width in pixel for default string edit
1895  print '</script>'."\n";
1896  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/editinplace.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1897  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ckeditor.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1898  }
1899  // jQuery Timepicker
1900  if (!empty($conf->global->MAIN_USE_JQUERY_TIMEPICKER) || defined('REQUIRE_JQUERY_TIMEPICKER')) {
1901  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/timepicker/jquery-ui-timepicker-addon.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1902  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/timepicker.js.php?lang='.$langs->defaultlang.($ext ? '&amp;'.$ext : '').'"></script>'."\n";
1903  }
1904  if (!defined('DISABLE_SELECT2') && (!empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT'))) {
1905  // jQuery plugin "mutiselect", "multiple-select", "select2", ...
1906  $tmpplugin = empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) ?constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
1907  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/'.$tmpplugin.'/dist/js/'.$tmpplugin.'.full.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n"; // We include full because we need the support of containerCssClass
1908  }
1909  if (!defined('DISABLE_MULTISELECT')) { // jQuery plugin "mutiselect" to select with checkboxes. Can be removed once we have an enhanced search tool
1910  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/multiselect/jquery.multi-select.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1911  }
1912  }
1913 
1914  if (!$disablejs && !empty($conf->use_javascript_ajax)) {
1915  // CKEditor
1916  if (empty($disableforlogin) && (isModEnabled('fckeditor') && (empty($conf->global->FCKEDITOR_EDITORNAME) || $conf->global->FCKEDITOR_EDITORNAME == 'ckeditor') && !defined('DISABLE_CKEDITOR')) || defined('FORCE_CKEDITOR')) {
1917  print '<!-- Includes JS for CKEditor -->'."\n";
1918  $pathckeditor = DOL_URL_ROOT.'/includes/ckeditor/ckeditor/';
1919  $jsckeditor = 'ckeditor.js';
1920  if (constant('JS_CKEDITOR')) {
1921  // To use external ckeditor 4 js lib
1922  $pathckeditor = constant('JS_CKEDITOR');
1923  }
1924  print '<script nonce="'.getNonce().'">';
1925  print '/* enable ckeditor by main.inc.php */';
1926  print 'var CKEDITOR_BASEPATH = \''.dol_escape_js($pathckeditor).'\';'."\n";
1927  print 'var ckeditorConfig = \''.dol_escape_js(dol_buildpath($themesubdir.'/theme/'.$conf->theme.'/ckeditor/config.js'.($ext ? '?'.$ext : ''), 1)).'\';'."\n"; // $themesubdir='' in standard usage
1928  print 'var ckeditorFilebrowserBrowseUrl = \''.DOL_URL_ROOT.'/core/filemanagerdol/browser/default/browser.php?Connector='.DOL_URL_ROOT.'/core/filemanagerdol/connectors/php/connector.php\';'."\n";
1929  print 'var ckeditorFilebrowserImageBrowseUrl = \''.DOL_URL_ROOT.'/core/filemanagerdol/browser/default/browser.php?Type=Image&Connector='.DOL_URL_ROOT.'/core/filemanagerdol/connectors/php/connector.php\';'."\n";
1930  print '</script>'."\n";
1931  print '<script src="'.$pathckeditor.$jsckeditor.($ext ? '?'.$ext : '').'"></script>'."\n";
1932  print '<script>';
1933  if (GETPOST('mode', 'aZ09') == 'Full_inline') {
1934  print 'CKEDITOR.disableAutoInline = false;'."\n";
1935  } else {
1936  print 'CKEDITOR.disableAutoInline = true;'."\n";
1937  }
1938  print '</script>'."\n";
1939  }
1940 
1941  // Browser notifications (if NOREQUIREMENU is on, it is mostly a page for popup, so we do not enable notif too. We hide also for public pages).
1942  if (!defined('NOBROWSERNOTIF') && !defined('NOREQUIREMENU') && !defined('NOLOGIN')) {
1943  $enablebrowsernotif = false;
1944  if (isModEnabled('agenda') && !empty($conf->global->AGENDA_REMINDER_BROWSER)) {
1945  $enablebrowsernotif = true;
1946  }
1947  if ($conf->browser->layout == 'phone') {
1948  $enablebrowsernotif = false;
1949  }
1950  if ($enablebrowsernotif) {
1951  print '<!-- Includes JS of Dolibarr (browser layout = '.$conf->browser->layout.')-->'."\n";
1952  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/lib_notification.js.php'.($ext ? '?'.$ext : '').'"></script>'."\n";
1953  }
1954  }
1955 
1956  // Global js function
1957  print '<!-- Includes JS of Dolibarr -->'."\n";
1958  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/lib_head.js.php?lang='.$langs->defaultlang.($ext ? '&amp;'.$ext : '').'"></script>'."\n";
1959 
1960  // JS forced by modules (relative url starting with /)
1961  if (!empty($conf->modules_parts['js'])) { // $conf->modules_parts['js'] is array('module'=>array('file1','file2'))
1962  $arrayjs = (array) $conf->modules_parts['js'];
1963  foreach ($arrayjs as $modjs => $filesjs) {
1964  $filesjs = (array) $filesjs; // To be sure filejs is an array
1965  foreach ($filesjs as $jsfile) {
1966  // jsfile is a relative path
1967  $urlforjs = dol_buildpath($jsfile, 1);
1968  if ($urlforjs && $urlforjs != '/') {
1969  print '<!-- Include JS added by module '.$modjs.'-->'."\n";
1970  print '<script nonce="'.getNonce().'" src="'.$urlforjs.((strpos($jsfile, '?') === false) ? '?' : '&amp;').'lang='.$langs->defaultlang.'"></script>'."\n";
1971  } else {
1972  dol_syslog("Warning: module ".$modjs." declared a js path file for a file we can't find.", LOG_WARNING);
1973  }
1974  }
1975  }
1976  }
1977  // JS forced by page in top_htmlhead (relative url starting with /)
1978  if (is_array($arrayofjs)) {
1979  print '<!-- Includes JS added by page -->'."\n";
1980  foreach ($arrayofjs as $jsfile) {
1981  if (preg_match('/^(http|\/\/)/i', $jsfile)) {
1982  print '<script nonce="'.getNonce().'" src="'.$jsfile.((strpos($jsfile, '?') === false) ? '?' : '&amp;').'lang='.$langs->defaultlang.'"></script>'."\n";
1983  } else {
1984  print '<script nonce="'.getNonce().'" src="'.dol_buildpath($jsfile, 1).((strpos($jsfile, '?') === false) ? '?' : '&amp;').'lang='.$langs->defaultlang.'"></script>'."\n";
1985  }
1986  }
1987  }
1988  }
1989 
1990  //If you want to load custom javascript file from your selected theme directory
1991  if (!empty($conf->global->ALLOW_THEME_JS)) {
1992  $theme_js = dol_buildpath('/theme/'.$conf->theme.'/'.$conf->theme.'.js', 0);
1993  if (file_exists($theme_js)) {
1994  print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/'.$conf->theme.'.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1995  }
1996  }
1997 
1998  if (!empty($head)) {
1999  print $head."\n";
2000  }
2001  if (!empty($conf->global->MAIN_HTML_HEADER)) {
2002  print $conf->global->MAIN_HTML_HEADER."\n";
2003  }
2004 
2005  $parameters = array();
2006  $result = $hookmanager->executeHooks('addHtmlHeader', $parameters); // Note that $action and $object may have been modified by some hooks
2007  print $hookmanager->resPrint; // Replace Title to show
2008 
2009  print "</head>\n\n";
2010  }
2011 
2012  $conf->headerdone = 1; // To tell header was output
2013 }
2014 
2015 
2032 function top_menu($head, $title = '', $target = '', $disablejs = 0, $disablehead = 0, $arrayofjs = '', $arrayofcss = '', $morequerystring = '', $helppagename = '')
2033 {
2034  global $user, $conf, $langs, $db;
2035  global $dolibarr_main_authentication, $dolibarr_main_demo;
2036  global $hookmanager, $menumanager;
2037 
2038  $searchform = '';
2039 
2040  // Instantiate hooks for external modules
2041  $hookmanager->initHooks(array('toprightmenu'));
2042 
2043  $toprightmenu = '';
2044 
2045  // For backward compatibility with old modules
2046  if (empty($conf->headerdone)) {
2047  $disablenofollow = 0;
2048  top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss, 0, $disablenofollow);
2049  print '<body id="mainbody">';
2050  }
2051 
2052  /*
2053  * Top menu
2054  */
2055  if ((empty($conf->dol_hide_topmenu) || GETPOST('dol_invisible_topmenu', 'int')) && (!defined('NOREQUIREMENU') || !constant('NOREQUIREMENU'))) {
2056  if (!isset($form) || !is_object($form)) {
2057  include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
2058  $form = new Form($db);
2059  }
2060 
2061  print "\n".'<!-- Start top horizontal -->'."\n";
2062 
2063  print '<header id="id-top" class="side-nav-vert'.(GETPOST('dol_invisible_topmenu', 'int') ? ' hidden' : '').'">'; // dol_invisible_topmenu differs from dol_hide_topmenu: dol_invisible_topmenu means we output menu but we make it invisible.
2064 
2065  // Show menu entries
2066  print '<div id="tmenu_tooltip'.(empty($conf->global->MAIN_MENU_INVERT) ? '' : 'invert').'" class="tmenu">'."\n";
2067  $menumanager->atarget = $target;
2068  $menumanager->showmenu('top', array('searchform'=>$searchform)); // This contains a \n
2069  print "</div>\n";
2070 
2071  // Define link to login card
2072  $appli = constant('DOL_APPLICATION_TITLE');
2073  if (!empty($conf->global->MAIN_APPLICATION_TITLE)) {
2074  $appli = $conf->global->MAIN_APPLICATION_TITLE;
2075  if (preg_match('/\d\.\d/', $appli)) {
2076  if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) {
2077  $appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core
2078  }
2079  } else {
2080  $appli .= " ".DOL_VERSION;
2081  }
2082  } else {
2083  $appli .= " ".DOL_VERSION;
2084  }
2085 
2086  if (getDolGlobalInt('MAIN_FEATURES_LEVEL')) {
2087  $appli .= "<br>".$langs->trans("LevelOfFeature").': '.getDolGlobalInt('MAIN_FEATURES_LEVEL');
2088  }
2089 
2090  $logouttext = '';
2091  $logouthtmltext = '';
2092  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2093  //$logouthtmltext=$appli.'<br>';
2094  if ($_SESSION["dol_authmode"] != 'forceuser' && $_SESSION["dol_authmode"] != 'http') {
2095  $logouthtmltext .= $langs->trans("Logout").'<br>';
2096 
2097  $stringforfirstkey = $langs->trans("KeyboardShortcut");
2098  if ($conf->browser->name == 'chrome') {
2099  $stringforfirstkey .= ' ALT +';
2100  } elseif ($conf->browser->name == 'firefox') {
2101  $stringforfirstkey .= ' ALT + SHIFT +';
2102  } else {
2103  $stringforfirstkey .= ' CTL +';
2104  }
2105 
2106  $logouttext .= '<a accesskey="l" href="'.DOL_URL_ROOT.'/user/logout.php?token='.newToken().'">';
2107  $logouttext .= img_picto($langs->trans('Logout').' ('.$stringforfirstkey.' l)', 'sign-out', '', false, 0, 0, '', 'atoplogin valignmiddle');
2108  $logouttext .= '</a>';
2109  } else {
2110  $logouthtmltext .= $langs->trans("NoLogoutProcessWithAuthMode", $_SESSION["dol_authmode"]);
2111  $logouttext .= img_picto($langs->trans('Logout').' ('.$stringforfirstkey.' l)', 'sign-out', '', false, 0, 0, '', 'atoplogin valignmiddle opacitymedium');
2112  }
2113  }
2114 
2115  print '<div class="login_block usedropdown">'."\n";
2116 
2117  $toprightmenu .= '<div class="login_block_other">';
2118 
2119  // Execute hook printTopRightMenu (hooks should output string like '<div class="login"><a href="">mylink</a></div>')
2120  $parameters = array();
2121  $result = $hookmanager->executeHooks('printTopRightMenu', $parameters); // Note that $action and $object may have been modified by some hooks
2122  if (is_numeric($result)) {
2123  if ($result == 0) {
2124  $toprightmenu .= $hookmanager->resPrint; // add
2125  } else {
2126  $toprightmenu = $hookmanager->resPrint; // replace
2127  }
2128  } else {
2129  $toprightmenu .= $result; // For backward compatibility
2130  }
2131 
2132  // Link to module builder
2133  if (isModEnabled('modulebuilder')) {
2134  $text = '<a href="'.DOL_URL_ROOT.'/modulebuilder/index.php?mainmenu=home&leftmenu=admintools" target="modulebuilder">';
2135  //$text.= img_picto(":".$langs->trans("ModuleBuilder"), 'printer_top.png', 'class="printer"');
2136  $text .= '<span class="fa fa-bug atoplogin valignmiddle"></span>';
2137  $text .= '</a>';
2138  $toprightmenu .= $form->textwithtooltip('', $langs->trans("ModuleBuilder"), 2, 1, $text, 'login_block_elem', 2);
2139  }
2140 
2141  // Link to print main content area
2142  if (empty($conf->global->MAIN_PRINT_DISABLELINK) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2143  $qs = dol_escape_htmltag($_SERVER["QUERY_STRING"]);
2144 
2145  if (isset($_POST) && is_array($_POST)) {
2146  foreach ($_POST as $key => $value) {
2147  if ($key !== 'action' && $key !== 'password' && !is_array($value)) {
2148  $qs .= '&'.$key.'='.urlencode($value);
2149  }
2150  }
2151  }
2152  $qs .= (($qs && $morequerystring) ? '&' : '').$morequerystring;
2153  $text = '<a href="'.dol_escape_htmltag($_SERVER["PHP_SELF"]).'?'.$qs.($qs ? '&' : '').'optioncss=print" target="_blank" rel="noopener noreferrer">';
2154  //$text.= img_picto(":".$langs->trans("PrintContentArea"), 'printer_top.png', 'class="printer"');
2155  $text .= '<span class="fa fa-print atoplogin valignmiddle"></span>';
2156  $text .= '</a>';
2157  $toprightmenu .= $form->textwithtooltip('', $langs->trans("PrintContentArea"), 2, 1, $text, 'login_block_elem', 2);
2158  }
2159 
2160  // Link to Dolibarr wiki pages
2161  if (empty($conf->global->MAIN_HELP_DISABLELINK) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2162  $langs->load("help");
2163 
2164  $helpbaseurl = '';
2165  $helppage = '';
2166  $mode = '';
2167  $helppresent = '';
2168 
2169  if (empty($helppagename)) {
2170  $helppagename = 'EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios|DE:Benutzerdokumentation';
2171  } else {
2172  $helppresent = 'helppresent';
2173  }
2174 
2175  // Get helpbaseurl, helppage and mode from helppagename and langs
2176  $arrayres = getHelpParamFor($helppagename, $langs);
2177  $helpbaseurl = $arrayres['helpbaseurl'];
2178  $helppage = $arrayres['helppage'];
2179  $mode = $arrayres['mode'];
2180 
2181  // Link to help pages
2182  if ($helpbaseurl && $helppage) {
2183  $text = '';
2184  $title = $langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage' : 'GoToHelpPage').', ';
2185  if ($mode == 'wiki') {
2186  $title .= '<br>'.img_picto('', 'globe', 'class="pictofixedwidth"').$langs->trans("PageWiki").' '.dol_escape_htmltag('"'.strtr($helppage, '_', ' ').'"');
2187  if ($helppresent) {
2188  $title .= ' <span class="opacitymedium">('.$langs->trans("DedicatedPageAvailable").')</span>';
2189  } else {
2190  $title .= ' <span class="opacitymedium">('.$langs->trans("HomePage").')</span>';
2191  }
2192  }
2193  $text .= '<a class="help" target="_blank" rel="noopener noreferrer" href="';
2194  if ($mode == 'wiki') {
2195  $text .= sprintf($helpbaseurl, urlencode(html_entity_decode($helppage)));
2196  } else {
2197  $text .= sprintf($helpbaseurl, $helppage);
2198  }
2199  $text .= '">';
2200  $text .= '<span class="fa fa-question-circle atoplogin valignmiddle'.($helppresent ? ' '.$helppresent : '').'"></span>';
2201  $text .= '<span class="fa fa-long-arrow-alt-up helppresentcircle'.($helppresent ? '' : ' unvisible').'"></span>';
2202  $text .= '</a>';
2203  $toprightmenu .= $form->textwithtooltip('', $title, 2, 1, $text, 'login_block_elem', 2);
2204  }
2205 
2206  // Version
2207  if (!empty($conf->global->MAIN_SHOWDATABASENAMEINHELPPAGESLINK)) {
2208  $langs->load('admin');
2209  $appli .= '<br>'.$langs->trans("Database").': '.$db->database_name;
2210  }
2211  }
2212 
2213  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2214  $text = '<span class="aversion"><span class="hideonsmartphone small">'.DOL_VERSION.'</span></span>';
2215  $toprightmenu .= $form->textwithtooltip('', $appli, 2, 1, $text, 'login_block_elem', 2);
2216  }
2217 
2218  // Logout link
2219  $toprightmenu .= $form->textwithtooltip('', $logouthtmltext, 2, 1, $logouttext, 'login_block_elem logout-btn', 2);
2220 
2221  $toprightmenu .= '</div>'; // end div class="login_block_other"
2222 
2223 
2224  // Add login user link
2225  $toprightmenu .= '<div class="login_block_user">';
2226 
2227  // Login name with photo and tooltip
2228  $mode = -1;
2229  $toprightmenu .= '<div class="inline-block nowrap"><div class="inline-block login_block_elem login_block_elem_name" style="padding: 0px;">';
2230 
2231  if (!empty($conf->global->MAIN_USE_TOP_MENU_SEARCH_DROPDOWN)) {
2232  // Add search dropdown
2233  $toprightmenu .= top_menu_search();
2234  }
2235 
2236  if (!empty($conf->global->MAIN_USE_TOP_MENU_QUICKADD_DROPDOWN)) {
2237  // Add search dropdown
2238  $toprightmenu .= top_menu_quickadd();
2239  }
2240 
2241  // Add bookmark dropdown
2242  $toprightmenu .= top_menu_bookmark();
2243 
2244  // Add user dropdown
2245  $toprightmenu .= top_menu_user();
2246 
2247  $toprightmenu .= '</div></div>';
2248 
2249  $toprightmenu .= '</div>'."\n";
2250 
2251 
2252  print $toprightmenu;
2253 
2254  print "</div>\n"; // end div class="login_block"
2255 
2256  print '</header>';
2257  //print '<header class="header2">&nbsp;</header>';
2258 
2259  print '<div style="clear: both;"></div>';
2260  print "<!-- End top horizontal menu -->\n\n";
2261  }
2262 
2263  if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) {
2264  print '<!-- Begin div id-container --><div id="id-container" class="id-container">';
2265  }
2266 }
2267 
2268 
2276 function top_menu_user($hideloginname = 0, $urllogout = '')
2277 {
2278  global $langs, $conf, $db, $hookmanager, $user, $mysoc;
2279  global $dolibarr_main_authentication, $dolibarr_main_demo;
2280  global $menumanager;
2281 
2282  $langs->load('companies');
2283 
2284  $userImage = $userDropDownImage = '';
2285  if (!empty($user->photo)) {
2286  $userImage = Form::showphoto('userphoto', $user, 0, 0, 0, 'photouserphoto userphoto', 'small', 0, 1);
2287  $userDropDownImage = Form::showphoto('userphoto', $user, 0, 0, 0, 'dropdown-user-image', 'small', 0, 1);
2288  } else {
2289  $nophoto = '/public/theme/common/user_anonymous.png';
2290  if ($user->gender == 'man') {
2291  $nophoto = '/public/theme/common/user_man.png';
2292  }
2293  if ($user->gender == 'woman') {
2294  $nophoto = '/public/theme/common/user_woman.png';
2295  }
2296 
2297  $userImage = '<img class="photo photouserphoto userphoto" alt="No photo" src="'.DOL_URL_ROOT.$nophoto.'">';
2298  $userDropDownImage = '<img class="photo dropdown-user-image" alt="No photo" src="'.DOL_URL_ROOT.$nophoto.'">';
2299  }
2300 
2301  $dropdownBody = '';
2302  $dropdownBody .= '<span id="topmenulogincompanyinfo-btn"><i class="fa fa-caret-right"></i> '.$langs->trans("ShowCompanyInfos").'</span>';
2303  $dropdownBody .= '<div id="topmenulogincompanyinfo" >';
2304 
2305  $dropdownBody .= '<br><b>'.$langs->trans("Company").'</b>: <span>'.dol_escape_htmltag($mysoc->name).'</span>';
2306  if ($langs->transcountry("ProfId1", $mysoc->country_code) != '-') {
2307  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId1", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_SIREN"), 1).'</span>';
2308  }
2309  if ($langs->transcountry("ProfId2", $mysoc->country_code) != '-') {
2310  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId2", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_SIRET"), 2).'</span>';
2311  }
2312  if ($langs->transcountry("ProfId3", $mysoc->country_code) != '-') {
2313  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId3", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_APE"), 3).'</span>';
2314  }
2315  if ($langs->transcountry("ProfId4", $mysoc->country_code) != '-') {
2316  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId4", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_RCS"), 4).'</span>';
2317  }
2318  if ($langs->transcountry("ProfId5", $mysoc->country_code) != '-') {
2319  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId5", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_PROFID5"), 5).'</span>';
2320  }
2321  if ($langs->transcountry("ProfId6", $mysoc->country_code) != '-') {
2322  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId6", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_PROFID6"), 6).'</span>';
2323  }
2324  $dropdownBody .= '<br><b>'.$langs->trans("VATIntraShort").'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_TVAINTRA"), 'VAT').'</span>';
2325  $dropdownBody .= '<br><b>'.$langs->trans("Country").'</b>: <span>'.($mysoc->country_code ? $langs->trans("Country".$mysoc->country_code) : '').'</span>';
2326  if (isModEnabled('multicurrency')) {
2327  $dropdownBody .= '<br><b>'.$langs->trans("Currency").'</b>: <span>'.$conf->currency.'</span>';
2328  }
2329  $dropdownBody .= '</div>';
2330 
2331  $dropdownBody .= '<br>';
2332  $dropdownBody .= '<span id="topmenuloginmoreinfo-btn"><i class="fa fa-caret-right"></i> '.$langs->trans("ShowMoreInfos").'</span>';
2333  $dropdownBody .= '<div id="topmenuloginmoreinfo" >';
2334 
2335  // login infos
2336  if (!empty($user->admin)) {
2337  $dropdownBody .= '<br><b>'.$langs->trans("Administrator").'</b>: '.yn($user->admin);
2338  }
2339  if (!empty($user->socid)) { // Add thirdparty for external users
2340  $thirdpartystatic = new Societe($db);
2341  $thirdpartystatic->fetch($user->socid);
2342  $companylink = ' '.$thirdpartystatic->getNomUrl(2); // picto only of company
2343  $company = ' ('.$langs->trans("Company").': '.$thirdpartystatic->name.')';
2344  }
2345  $type = ($user->socid ? $langs->trans("External").$company : $langs->trans("Internal"));
2346  $dropdownBody .= '<br><b>'.$langs->trans("Type").':</b> '.$type;
2347  $dropdownBody .= '<br><b>'.$langs->trans("Status").'</b>: '.$user->getLibStatut(0);
2348  $dropdownBody .= '<br>';
2349 
2350  $dropdownBody .= '<br><u>'.$langs->trans("Session").'</u>';
2351  $dropdownBody .= '<br><b>'.$langs->trans("IPAddress").'</b>: '.dol_escape_htmltag($_SERVER["REMOTE_ADDR"]);
2352  if (!empty($conf->global->MAIN_MODULE_MULTICOMPANY)) {
2353  $dropdownBody .= '<br><b>'.$langs->trans("ConnectedOnMultiCompany").':</b> '.$conf->entity.' (user entity '.$user->entity.')';
2354  }
2355  $dropdownBody .= '<br><b>'.$langs->trans("AuthenticationMode").':</b> '.$_SESSION["dol_authmode"].(empty($dolibarr_main_demo) ? '' : ' (demo)');
2356  $dropdownBody .= '<br><b>'.$langs->trans("ConnectedSince").':</b> '.dol_print_date($user->datelastlogin, "dayhour", 'tzuser');
2357  $dropdownBody .= '<br><b>'.$langs->trans("PreviousConnexion").':</b> '.dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser');
2358  $dropdownBody .= '<br><b>'.$langs->trans("CurrentTheme").':</b> '.$conf->theme;
2359  $dropdownBody .= '<br><b>'.$langs->trans("CurrentMenuManager").':</b> '.(isset($menumanager) ? $menumanager->name : 'unknown');
2360  $langFlag = picto_from_langcode($langs->getDefaultLang());
2361  $dropdownBody .= '<br><b>'.$langs->trans("CurrentUserLanguage").':</b> '.($langFlag ? $langFlag.' ' : '').$langs->getDefaultLang();
2362 
2363  $tz = (int) $_SESSION['dol_tz'] + (int) $_SESSION['dol_dst'];
2364  $dropdownBody .= '<br><b>'.$langs->trans("ClientTZ").':</b> '.($tz ? ($tz >= 0 ? '+' : '').$tz : '');
2365  $dropdownBody .= ' ('.$_SESSION['dol_tz_string'].')';
2366  //$dropdownBody .= ' &nbsp; &nbsp; &nbsp; '.$langs->trans("DaylingSavingTime").': ';
2367  //if ($_SESSION['dol_dst'] > 0) $dropdownBody .= yn(1);
2368  //else $dropdownBody .= yn(0);
2369 
2370  $dropdownBody .= '<br><b>'.$langs->trans("Browser").':</b> '.$conf->browser->name.($conf->browser->version ? ' '.$conf->browser->version : '').' ('.dol_escape_htmltag($_SERVER['HTTP_USER_AGENT']).')';
2371  $dropdownBody .= '<br><b>'.$langs->trans("Layout").':</b> '.$conf->browser->layout;
2372  $dropdownBody .= '<br><b>'.$langs->trans("Screen").':</b> '.$_SESSION['dol_screenwidth'].' x '.$_SESSION['dol_screenheight'];
2373  if ($conf->browser->layout == 'phone') {
2374  $dropdownBody .= '<br><b>'.$langs->trans("Phone").':</b> '.$langs->trans("Yes");
2375  }
2376  if (!empty($_SESSION["disablemodules"])) {
2377  $dropdownBody .= '<br><b>'.$langs->trans("DisabledModules").':</b> <br>'.join(', ', explode(',', $_SESSION["disablemodules"]));
2378  }
2379  $dropdownBody .= '</div>';
2380 
2381  // Execute hook
2382  $parameters = array('user'=>$user, 'langs' => $langs);
2383  $result = $hookmanager->executeHooks('printTopRightMenuLoginDropdownBody', $parameters); // Note that $action and $object may have been modified by some hooks
2384  if (is_numeric($result)) {
2385  if ($result == 0) {
2386  $dropdownBody .= $hookmanager->resPrint; // add
2387  } else {
2388  $dropdownBody = $hookmanager->resPrint; // replace
2389  }
2390  }
2391 
2392  if (empty($urllogout)) {
2393  $urllogout = DOL_URL_ROOT.'/user/logout.php?token='.newToken();
2394  }
2395 
2396  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
2397  // accesskey is for Mac: CTRL + key for all browsers
2398  $stringforfirstkey = $langs->trans("KeyboardShortcut");
2399  if ($conf->browser->name == 'chrome') {
2400  $stringforfirstkey .= ' ALT +';
2401  } elseif ($conf->browser->name == 'firefox') {
2402  $stringforfirstkey .= ' ALT + SHIFT +';
2403  } else {
2404  $stringforfirstkey .= ' CTL +';
2405  }
2406 
2407  // Defined the links for bottom of card
2408  $profilLink = '<a accesskey="u" href="'.DOL_URL_ROOT.'/user/card.php?id='.$user->id.'" class="button-top-menu-dropdown" title="'.dol_escape_htmltag($langs->trans("YourUserFile").' ('.$stringforfirstkey.' u)').'"><i class="fa fa-user"></i> '.$langs->trans("Card").'</a>';
2409  $urltovirtualcard = '/user/virtualcard.php?id='.((int) $user->id);
2410  $virtuelcardLink = dolButtonToOpenUrlInDialogPopup('publicvirtualcardmenu', $langs->trans("PublicVirtualCardUrl").(is_object($user) ? ' - '.$user->getFullName($langs) : '').' ('.$stringforfirstkey.' v)', img_picto($langs->trans("PublicVirtualCardUrl").' ('.$stringforfirstkey.' v)', 'card', ''), $urltovirtualcard, '', 'button-top-menu-dropdown marginleftonly nohover', "closeTopMenuLoginDropdown()", '', 'v');
2411  $logoutLink = '<a accesskey="l" href="'.$urllogout.'" class="button-top-menu-dropdown" title="'.dol_escape_htmltag($langs->trans("Logout").' ('.$stringforfirstkey.' l)').'"><i class="fa fa-sign-out-alt padingright"></i><span class="hideonsmartphone">'.$langs->trans("Logout").'</span></a>';
2412 
2413  $profilName = $user->getFullName($langs).' ('.$user->login.')';
2414  if (!empty($user->admin)) {
2415  $profilName = '<i class="far fa-star classfortooltip" title="'.$langs->trans("Administrator").'" ></i> '.$profilName;
2416  }
2417 
2418  // Define version to show
2419  $appli = constant('DOL_APPLICATION_TITLE');
2420  if (!empty($conf->global->MAIN_APPLICATION_TITLE)) {
2421  $appli = $conf->global->MAIN_APPLICATION_TITLE;
2422  if (preg_match('/\d\.\d/', $appli)) {
2423  if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) {
2424  $appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core
2425  }
2426  } else {
2427  $appli .= " ".DOL_VERSION;
2428  }
2429  } else {
2430  $appli .= " ".DOL_VERSION;
2431  }
2432 
2433  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2434  $btnUser = '<!-- div for user link -->
2435  <div id="topmenu-login-dropdown" class="userimg atoplogin dropdown user user-menu inline-block">
2436  <a href="'.DOL_URL_ROOT.'/user/card.php?id='.$user->id.'" class="dropdown-toggle login-dropdown-a" data-toggle="dropdown">
2437  '.$userImage.(empty($user->photo) ? '<span class="hidden-xs maxwidth200 atoploginusername hideonsmartphone paddingleft">'.dol_trunc($user->firstname ? $user->firstname : $user->login, 10).'</span>' : '').'
2438  </a>
2439  <div class="dropdown-menu">
2440  <!-- User image -->
2441  <div class="user-header">
2442  '.$userDropDownImage.'
2443  <p>
2444  '.$profilName.'<br>';
2445  if ($user->datelastlogin) {
2446  $title = $langs->trans("ConnectedSince").' : '.dol_print_date($user->datelastlogin, "dayhour", 'tzuser');
2447  if ($user->datepreviouslogin) {
2448  $title .= '<br>'.$langs->trans("PreviousConnexion").' : '.dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser');
2449  }
2450  }
2451  $btnUser .= '<small class="classfortooltip" title="'.dol_escape_htmltag($title).'" ><i class="fa fa-user-clock"></i> '.dol_print_date($user->datelastlogin, "dayhour", 'tzuser').'</small><br>';
2452  if ($user->datepreviouslogin) {
2453  $btnUser .= '<small class="classfortooltip" title="'.dol_escape_htmltag($title).'" ><i class="fa fa-user-clock opacitymedium"></i> '.dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser').'</small><br>';
2454  }
2455 
2456  //$btnUser .= '<small class="classfortooltip"><i class="fa fa-cog"></i> '.$langs->trans("Version").' '.$appli.'</small>';
2457  $btnUser .= '
2458  </p>
2459  </div>
2460 
2461  <!-- Menu Body user-->
2462  <div class="user-body">'.$dropdownBody.'</div>
2463 
2464  <!-- Menu Footer-->
2465  <div class="user-footer">
2466  <div class="pull-left">
2467  '.$profilLink.'
2468  </div>
2469  <div class="pull-left">
2470  '.$virtuelcardLink.'
2471  </div>
2472  <div class="pull-right">
2473  '.$logoutLink.'
2474  </div>
2475  <div class="clearboth"></div>
2476  </div>
2477 
2478  </div>
2479  </div>';
2480  } else {
2481  $btnUser = '<!-- div for user link -->
2482  <div id="topmenu-login-dropdown" class="userimg atoplogin dropdown user user-menu inline-block">
2483  <a href="'.DOL_URL_ROOT.'/user/card.php?id='.$user->id.'">
2484  '.$userImage.'
2485  <span class="hidden-xs maxwidth200 atoploginusername hideonsmartphone">'.dol_trunc($user->firstname ? $user->firstname : $user->login, 10).'</span>
2486  </a>
2487  </div>';
2488  }
2489 
2490  if (!defined('JS_JQUERY_DISABLE_DROPDOWN') && !empty($conf->use_javascript_ajax)) { // This may be set by some pages that use different jquery version to avoid errors
2491  $btnUser .= '
2492  <!-- Code to show/hide the user drop-down -->
2493  <script>
2494  function closeTopMenuLoginDropdown() {
2495  //console.log("close login dropdown"); // This is call at each click on page, so we disable the log
2496  // Hide the menus.
2497  jQuery("#topmenu-login-dropdown").removeClass("open");
2498  }
2499  jQuery(document).ready(function() {
2500  jQuery(document).on("click", function(event) {
2501  // console.log("Click somewhere on screen");
2502  if (!$(event.target).closest("#topmenu-login-dropdown").length) {
2503  closeTopMenuLoginDropdown();
2504  }
2505  });
2506 
2507  jQuery(".butAction.dropdown-toggle").on("click", function(event) {
2508  console.log("Click on .butAction.dropdown-toggle");
2509  var parentholder = jQuery(".butAction.dropdown-toggle").closest(".dropdown");
2510  var offset = parentholder.offset();
2511  var widthdocument = $(document).width();
2512  var left = offset.left;
2513  var right = widthdocument - offset.left - parentholder.width();
2514  var widthpopup = parentholder.children(".dropdown-content").width();
2515  console.log("left="+left+" right="+right+" width="+widthpopup+" widthdocument="+widthdocument);
2516  if (widthpopup + right >= widthdocument) {
2517  right = 10;
2518  }
2519  parentholder.toggleClass("open");
2520  parentholder.children(".dropdown-content").css({"right": right+"px", "left": "auto"});
2521  });
2522  ';
2523 
2524 
2525  if ($conf->theme != 'md') {
2526  $btnUser .= '
2527  jQuery("#topmenu-login-dropdown .dropdown-toggle").on("click", function(event) {
2528  console.log("Click on #topmenu-login-dropdown .dropdown-toggle");
2529  event.preventDefault();
2530  jQuery("#topmenu-login-dropdown").toggleClass("open");
2531  });
2532 
2533  jQuery("#topmenulogincompanyinfo-btn").on("click", function() {
2534  console.log("Clik on #topmenulogincompanyinfo-btn");
2535  jQuery("#topmenulogincompanyinfo").slideToggle();
2536  });
2537 
2538  jQuery("#topmenuloginmoreinfo-btn").on("click", function() {
2539  console.log("Clik on #topmenuloginmoreinfo-btn");
2540  jQuery("#topmenuloginmoreinfo").slideToggle();
2541  });';
2542  }
2543 
2544  $btnUser .= '
2545  });
2546  </script>
2547  ';
2548  }
2549 
2550  return $btnUser;
2551 }
2552 
2559 {
2560  global $conf, $langs;
2561 
2562  $html = '';
2563 
2564  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
2565  // accesskey is for Mac: CTRL + key for all browsers
2566  $stringforfirstkey = $langs->trans("KeyboardShortcut");
2567  if ($conf->browser->name == 'chrome') {
2568  $stringforfirstkey .= ' ALT +';
2569  } elseif ($conf->browser->name == 'firefox') {
2570  $stringforfirstkey .= ' ALT + SHIFT +';
2571  } else {
2572  $stringforfirstkey .= ' CTL +';
2573  }
2574 
2575  $html .= '<!-- div for quick add link -->
2576  <div id="topmenu-quickadd-dropdown" class="atoplogin dropdown inline-block">
2577  <a accesskey="a" class="dropdown-toggle login-dropdown-a nofocusvisible" data-toggle="dropdown" href="#" title="'.$langs->trans('QuickAdd').' ('.$stringforfirstkey.' a)"><i class="fa fa-plus-circle"></i></a>
2578  <div class="dropdown-menu">'.printDropdownQuickadd().'</div>
2579  </div>';
2580  $html .= '
2581  <!-- Code to show/hide the user drop-down -->
2582  <script>
2583  jQuery(document).ready(function() {
2584  jQuery(document).on("click", function(event) {
2585  if (!$(event.target).closest("#topmenu-quickadd-dropdown").length) {
2586  // Hide the menus.
2587  $("#topmenu-quickadd-dropdown").removeClass("open");
2588  }
2589  });
2590  $("#topmenu-quickadd-dropdown .dropdown-toggle").on("click", function(event) {
2591  console.log("Click on #topmenu-quickadd-dropdown .dropdown-toggle");
2592  openQuickAddDropDown(event);
2593  });
2594 
2595  // Key map shortcut
2596  $(document).keydown(function(event){
2597  if ( event.which === 76 && event.ctrlKey && event.shiftKey ){
2598  console.log(\'control + shift + l : trigger open quick add dropdown\');
2599  openQuickAddDropDown(event);
2600  }
2601  });
2602 
2603  var openQuickAddDropDown = function(event) {
2604  event.preventDefault();
2605  $("#topmenu-quickadd-dropdown").toggleClass("open");
2606  //$("#top-quickadd-search-input").focus();
2607  }
2608  });
2609  </script>
2610  ';
2611  return $html;
2612 }
2613 
2620 {
2621  global $conf, $user, $langs, $hookmanager;
2622 
2623  $items = array(
2624  'items' => array(
2625  array(
2626  "url" => "/adherents/card.php?action=create&amp;mainmenu=members",
2627  "title" => "MenuNewMember@members",
2628  "name" => "Adherent@members",
2629  "picto" => "object_member",
2630  "activation" => isModEnabled('adherent') && $user->hasRight("adherent", "write"), // vs hooking
2631  "position" => 5,
2632  ),
2633  array(
2634  "url" => "/societe/card.php?action=create&amp;mainmenu=companies",
2635  "title" => "MenuNewThirdParty@companies",
2636  "name" => "ThirdParty@companies",
2637  "picto" => "object_company",
2638  "activation" => isModEnabled("societe") && $user->hasRight("societe", "write"), // vs hooking
2639  "position" => 10,
2640  ),
2641  array(
2642  "url" => "/contact/card.php?action=create&amp;mainmenu=companies",
2643  "title" => "NewContactAddress@companies",
2644  "name" => "Contact@companies",
2645  "picto" => "object_contact",
2646  "activation" => isModEnabled("societe") && $user->hasRight("societe", "contact", "write"), // vs hooking
2647  "position" => 20,
2648  ),
2649  array(
2650  "url" => "/comm/propal/card.php?action=create&amp;mainmenu=commercial",
2651  "title" => "NewPropal@propal",
2652  "name" => "Proposal@propal",
2653  "picto" => "object_propal",
2654  "activation" => isModEnabled("propal") && $user->hasRight("propal", "write"), // vs hooking
2655  "position" => 30,
2656  ),
2657 
2658  array(
2659  "url" => "/commande/card.php?action=create&amp;mainmenu=commercial",
2660  "title" => "NewOrder@orders",
2661  "name" => "Order@orders",
2662  "picto" => "object_order",
2663  "activation" => isModEnabled('commande') && $user->hasRight("commande", "write"), // vs hooking
2664  "position" => 40,
2665  ),
2666  array(
2667  "url" => "/compta/facture/card.php?action=create&amp;mainmenu=billing",
2668  "title" => "NewBill@bills",
2669  "name" => "Bill@bills",
2670  "picto" => "object_bill",
2671  "activation" => isModEnabled('facture') && $user->hasRight("facture", "write"), // vs hooking
2672  "position" => 50,
2673  ),
2674  array(
2675  "url" => "/contrat/card.php?action=create&amp;mainmenu=commercial",
2676  "title" => "NewContractSubscription@contracts",
2677  "name" => "Contract@contracts",
2678  "picto" => "object_contract",
2679  "activation" => isModEnabled('contrat') && $user->hasRight("contrat", "write"), // vs hooking
2680  "position" => 60,
2681  ),
2682  array(
2683  "url" => "/supplier_proposal/card.php?action=create&amp;mainmenu=commercial",
2684  "title" => "SupplierProposalNew@supplier_proposal",
2685  "name" => "SupplierProposal@supplier_proposal",
2686  "picto" => "supplier_proposal",
2687  "activation" => isModEnabled('supplier_proposal') && $user->hasRight("supplier_invoice", "write"), // vs hooking
2688  "position" => 70,
2689  ),
2690  array(
2691  "url" => "/fourn/commande/card.php?action=create&amp;mainmenu=commercial",
2692  "title" => "NewSupplierOrderShort@orders",
2693  "name" => "SupplierOrder@orders",
2694  "picto" => "supplier_order",
2695  "activation" => (isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "commande", "write")) || (isModEnabled("supplier_order") && $user->hasRight("supplier_invoice", "write")), // vs hooking
2696  "position" => 80,
2697  ),
2698  array(
2699  "url" => "/fourn/facture/card.php?action=create&amp;mainmenu=billing",
2700  "title" => "NewBill@bills",
2701  "name" => "SupplierBill@bills",
2702  "picto" => "supplier_invoice",
2703  "activation" => (isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "write")) || (isModEnabled("supplier_invoice") && $user->hasRight("supplier_invoice", "write")), // vs hooking
2704  "position" => 90,
2705  ),
2706  array(
2707  "url" => "/ticket/card.php?action=create&amp;mainmenu=ticket",
2708  "title" => "NewTicket@ticket",
2709  "name" => "Ticket@ticket",
2710  "picto" => "ticket",
2711  "activation" => isModEnabled('ticket') && $user->hasRight("ticket", "write"), // vs hooking
2712  "position" => 100,
2713  ),
2714  array(
2715  "url" => "/fichinter/card.php?action=create&mainmenu=commercial",
2716  "title" => "NewIntervention@interventions",
2717  "name" => "Intervention@interventions",
2718  "picto" => "intervention",
2719  "activation" => isModEnabled('ficheinter') && $user->hasRight("ficheinter", "creer"), // vs hooking
2720  "position" => 110,
2721  ),
2722  array(
2723  "url" => "/product/card.php?action=create&amp;type=0&amp;mainmenu=products",
2724  "title" => "NewProduct@products",
2725  "name" => "Product@products",
2726  "picto" => "object_product",
2727  "activation" => isModEnabled("product") && $user->hasRight("produit", "write"), // vs hooking
2728  "position" => 400,
2729  ),
2730  array(
2731  "url" => "/product/card.php?action=create&amp;type=1&amp;mainmenu=products",
2732  "title" => "NewService@products",
2733  "name" => "Service@products",
2734  "picto" => "object_service",
2735  "activation" => isModEnabled("service") && $user->hasRight("service", "write"), // vs hooking
2736  "position" => 410,
2737  ),
2738  array(
2739  "url" => "/user/card.php?action=create&amp;type=1&amp;mainmenu=home",
2740  "title" => "AddUser@users",
2741  "name" => "User@users",
2742  "picto" => "user",
2743  "activation" => $user->hasRight("user", "user", "write"), // vs hooking
2744  "position" => 500,
2745  ),
2746  ),
2747  );
2748 
2749  $dropDownQuickAddHtml = '';
2750 
2751  // Define $dropDownQuickAddHtml
2752  $dropDownQuickAddHtml .= '<div class="quickadd-body dropdown-body">';
2753  $dropDownQuickAddHtml .= '<div class="dropdown-quickadd-list">';
2754 
2755  // Allow the $items of the menu to be manipulated by modules
2756  $parameters = array();
2757  $hook_items = $items;
2758  $reshook = $hookmanager->executeHooks('menuDropdownQuickaddItems', $parameters, $hook_items); // Note that $action and $object may have been modified by some hooks
2759  if (is_numeric($reshook) && !empty($hookmanager->resArray) && is_array($hookmanager->resArray)) {
2760  if ($reshook == 0) {
2761  $items['items'] = array_merge($items['items'], $hookmanager->resArray); // add
2762  } else {
2763  $items = $hookmanager->resArray; // replace
2764  }
2765 
2766  // Sort menu items by 'position' value
2767  $position = array();
2768  foreach ($items['items'] as $key => $row) {
2769  $position[$key] = $row['position'];
2770  }
2771  $array1_sort_order = SORT_ASC;
2772  array_multisort($position, $array1_sort_order, $items['items']);
2773  }
2774 
2775  foreach ($items['items'] as $item) {
2776  if (!$item['activation']) {
2777  continue;
2778  }
2779  $langs->load(explode('@', $item['title'])[1]);
2780  $langs->load(explode('@', $item['name'])[1]);
2781  $dropDownQuickAddHtml .= '
2782  <a class="dropdown-item quickadd-item" href="'.DOL_URL_ROOT.$item['url'].'" title="'.$langs->trans(explode('@', $item['title'])[0]).'">
2783  '. img_picto('', $item['picto'], 'style="width:18px;"') . ' ' . $langs->trans(explode('@', $item['name'])[0]) . '</a>
2784  ';
2785  }
2786 
2787  $dropDownQuickAddHtml .= '</div>';
2788  $dropDownQuickAddHtml .= '</div>';
2789 
2790  return $dropDownQuickAddHtml;
2791 }
2792 
2799 {
2800  global $langs, $conf, $db, $user;
2801 
2802  $html = '';
2803 
2804  // Define $bookmarks
2805  if (!isModEnabled('bookmark') || empty($user->rights->bookmark->lire)) {
2806  return $html;
2807  }
2808 
2809  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
2810  // accesskey is for Mac: CTRL + key for all browsers
2811  $stringforfirstkey = $langs->trans("KeyboardShortcut");
2812  if ($conf->browser->name == 'chrome') {
2813  $stringforfirstkey .= ' ALT +';
2814  } elseif ($conf->browser->name == 'firefox') {
2815  $stringforfirstkey .= ' ALT + SHIFT +';
2816  } else {
2817  $stringforfirstkey .= ' CTL +';
2818  }
2819 
2820  if (!defined('JS_JQUERY_DISABLE_DROPDOWN') && !empty($conf->use_javascript_ajax)) { // This may be set by some pages that use different jquery version to avoid errors
2821  include_once DOL_DOCUMENT_ROOT.'/bookmarks/bookmarks.lib.php';
2822  $langs->load("bookmarks");
2823 
2824  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2825  $html .= '<div id="topmenu-bookmark-dropdown" class="dropdown inline-block">';
2826  $html .= printDropdownBookmarksList();
2827  $html .= '</div>';
2828  } else {
2829  $html .= '<!-- div for bookmark link -->
2830  <div id="topmenu-bookmark-dropdown" class="dropdown inline-block">
2831  <a accesskey="b" class="dropdown-toggle login-dropdown-a nofocusvisible" data-toggle="dropdown" href="#" title="'.$langs->trans('Bookmarks').' ('.$stringforfirstkey.' b)"><i class="fa fa-star"></i></a>
2832  <div class="dropdown-menu">
2834  </div>
2835  </div>';
2836 
2837  $html .= '
2838  <!-- Code to show/hide the bookmark drop-down -->
2839  <script>
2840  jQuery(document).ready(function() {
2841  jQuery(document).on("click", function(event) {
2842  if (!$(event.target).closest("#topmenu-bookmark-dropdown").length) {
2843  //console.log("close bookmark dropdown - we click outside");
2844  // Hide the menus.
2845  $("#topmenu-bookmark-dropdown").removeClass("open");
2846  }
2847  });
2848 
2849  jQuery("#topmenu-bookmark-dropdown .dropdown-toggle").on("click", function(event) {
2850  console.log("Click on #topmenu-bookmark-dropdown .dropdown-toggle");
2851  openBookMarkDropDown(event);
2852  });
2853 
2854  // Key map shortcut
2855  jQuery(document).keydown(function(event){
2856  if( event.which === 77 && event.ctrlKey && event.shiftKey ){
2857  console.log("Click on control + shift + m : trigger open bookmark dropdown");
2858  openBookMarkDropDown(event);
2859  }
2860  });
2861 
2862  var openBookMarkDropDown = function(event) {
2863  event.preventDefault();
2864  jQuery("#topmenu-bookmark-dropdown").toggleClass("open");
2865  jQuery("#top-bookmark-search-input").focus();
2866  }
2867 
2868  });
2869  </script>
2870  ';
2871  }
2872  }
2873  return $html;
2874 }
2875 
2882 {
2883  global $langs, $conf, $db, $user, $hookmanager;
2884 
2885  $html = '';
2886 
2887  $usedbyinclude = 1;
2888  $arrayresult = null;
2889  include DOL_DOCUMENT_ROOT.'/core/ajax/selectsearchbox.php'; // This set $arrayresult
2890 
2891  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
2892  // accesskey is for Mac: CTRL + key for all browsers
2893  $stringforfirstkey = $langs->trans("KeyboardShortcut");
2894  if ($conf->browser->name == 'chrome') {
2895  $stringforfirstkey .= ' ALT +';
2896  } elseif ($conf->browser->name == 'firefox') {
2897  $stringforfirstkey .= ' ALT + SHIFT +';
2898  } else {
2899  $stringforfirstkey .= ' CTL +';
2900  }
2901 
2902  $searchInput = '<input name="search_all"'.($stringforfirstkey ? ' title="'.dol_escape_htmltag($stringforfirstkey.' s').'"' : '').' accesskey="s" id="top-global-search-input" class="dropdown-search-input search_component_input" placeholder="'.$langs->trans('Search').'" autocomplete="off">';
2903 
2904  $defaultAction = '';
2905  $buttonList = '<div class="dropdown-global-search-button-list" >';
2906  // Menu with all searchable items
2907  foreach ($arrayresult as $keyItem => $item) {
2908  if (empty($defaultAction)) {
2909  $defaultAction = $item['url'];
2910  }
2911  $buttonList .= '<button class="dropdown-item global-search-item tdoverflowmax300" data-target="'.dol_escape_htmltag($item['url']).'" >';
2912  $buttonList .= $item['text'];
2913  $buttonList .= '</button>';
2914  }
2915  $buttonList .= '</div>';
2916 
2917  $dropDownHtml = '<form id="top-menu-action-search" name="actionsearch" method="GET" action="'.$defaultAction.'">';
2918 
2919  $dropDownHtml .= '
2920  <!-- search input -->
2921  <div class="dropdown-header search-dropdown-header">
2922  ' . $searchInput.'
2923  </div>
2924  ';
2925 
2926  $dropDownHtml .= '
2927  <!-- Menu Body search -->
2928  <div class="dropdown-body search-dropdown-body">
2929  '.$buttonList.'
2930  </div>
2931  ';
2932 
2933  $dropDownHtml .= '</form>';
2934 
2935  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
2936  // accesskey is for Mac: CTRL + key for all browsers
2937  $stringforfirstkey = $langs->trans("KeyboardShortcut");
2938  if ($conf->browser->name == 'chrome') {
2939  $stringforfirstkey .= ' ALT +';
2940  } elseif ($conf->browser->name == 'firefox') {
2941  $stringforfirstkey .= ' ALT + SHIFT +';
2942  } else {
2943  $stringforfirstkey .= ' CTL +';
2944  }
2945 
2946  $html .= '<!-- div for Global Search -->
2947  <div id="topmenu-global-search-dropdown" class="atoplogin dropdown inline-block">
2948  <a accesskey="s" class="dropdown-toggle login-dropdown-a nofocusvisible" data-toggle="dropdown" href="#" title="'.$langs->trans('Search').' ('.$stringforfirstkey.' s)">
2949  <i class="fa fa-search" ></i>
2950  </a>
2951  <div class="dropdown-menu dropdown-search">
2952  '.$dropDownHtml.'
2953  </div>
2954  </div>';
2955 
2956  $html .= '
2957  <!-- Code to show/hide the user drop-down -->
2958  <script>
2959  jQuery(document).ready(function() {
2960 
2961  // prevent submiting form on press ENTER
2962  jQuery("#top-global-search-input").keydown(function (e) {
2963  if (e.keyCode == 13) {
2964  var inputs = $(this).parents("form").eq(0).find(":button");
2965  if (inputs[inputs.index(this) + 1] != null) {
2966  inputs[inputs.index(this) + 1].focus();
2967  }
2968  e.preventDefault();
2969  return false;
2970  }
2971  });
2972 
2973  // arrow key nav
2974  jQuery(document).keydown(function(e) {
2975  // Get the focused element:
2976  var $focused = $(":focus");
2977  if($focused.length && $focused.hasClass("global-search-item")){
2978 
2979  // UP - move to the previous line
2980  if (e.keyCode == 38) {
2981  e.preventDefault();
2982  $focused.prev().focus();
2983  }
2984 
2985  // DOWN - move to the next line
2986  if (e.keyCode == 40) {
2987  e.preventDefault();
2988  $focused.next().focus();
2989  }
2990  }
2991  });
2992 
2993 
2994  // submit form action
2995  jQuery(".dropdown-global-search-button-list .global-search-item").on("click", function(event) {
2996  jQuery("#top-menu-action-search").attr("action", $(this).data("target"));
2997  jQuery("#top-menu-action-search").submit();
2998  });
2999 
3000  // close drop down
3001  jQuery(document).on("click", function(event) {
3002  if (!$(event.target).closest("#topmenu-global-search-dropdown").length) {
3003  console.log("click close search - we click outside");
3004  // Hide the menus.
3005  jQuery("#topmenu-global-search-dropdown").removeClass("open");
3006  }
3007  });
3008 
3009  // Open drop down
3010  jQuery("#topmenu-global-search-dropdown .dropdown-toggle").on("click", function(event) {
3011  console.log("click on toggle #topmenu-global-search-dropdown .dropdown-toggle");
3012  openGlobalSearchDropDown();
3013  });
3014 
3015  // Key map shortcut
3016  jQuery(document).keydown(function(e){
3017  if ( e.which === 70 && e.ctrlKey && e.shiftKey ) {
3018  console.log(\'control + shift + f : trigger open global-search dropdown\');
3019  openGlobalSearchDropDown();
3020  }
3021  if ( e.which === 70 && e.alKey ) {
3022  console.log(\'alt + f : trigger open global-search dropdown\');
3023  openGlobalSearchDropDown();
3024  }
3025  });
3026 
3027  var openGlobalSearchDropDown = function() {
3028  jQuery("#topmenu-global-search-dropdown").toggleClass("open");
3029  jQuery("#top-global-search-input").focus();
3030  }
3031 
3032  });
3033  </script>
3034  ';
3035 
3036  return $html;
3037 }
3038 
3053 function left_menu($menu_array_before, $helppagename = '', $notused = '', $menu_array_after = '', $leftmenuwithoutmainarea = 0, $title = '', $acceptdelayedhtml = 0)
3054 {
3055  global $user, $conf, $langs, $db, $form;
3056  global $hookmanager, $menumanager;
3057 
3058  $searchform = '';
3059 
3060  if (!empty($menu_array_before)) {
3061  dol_syslog("Deprecated parameter menu_array_before was used when calling main::left_menu function. Menu entries of module should now be defined into module descriptor and not provided when calling left_menu.", LOG_WARNING);
3062  }
3063 
3064  if (empty($conf->dol_hide_leftmenu) && (!defined('NOREQUIREMENU') || !constant('NOREQUIREMENU'))) {
3065  // Instantiate hooks for external modules
3066  $hookmanager->initHooks(array('leftblock'));
3067 
3068  print "\n".'<!-- Begin side-nav id-left -->'."\n".'<div class="side-nav"><div id="id-left">'."\n";
3069  print "\n";
3070 
3071  if (!is_object($form)) {
3072  $form = new Form($db);
3073  }
3074  $selected = -1;
3075  if (empty($conf->global->MAIN_USE_TOP_MENU_SEARCH_DROPDOWN)) {
3076  // Select into select2 is awfull on smartphone. TODO Is this still true with select2 v4 ?
3077  if ($conf->browser->layout == 'phone') {
3078  $conf->global->MAIN_USE_OLD_SEARCH_FORM = 1;
3079  }
3080 
3081  $usedbyinclude = 1;
3082  $arrayresult = array();
3083  include DOL_DOCUMENT_ROOT.'/core/ajax/selectsearchbox.php'; // This make initHooks('searchform') then set $arrayresult
3084 
3085  if ($conf->use_javascript_ajax && empty($conf->global->MAIN_USE_OLD_SEARCH_FORM)) {
3086  // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
3087  // accesskey is for Mac: CTRL + key for all browsers
3088  $stringforfirstkey = $langs->trans("KeyboardShortcut");
3089  if ($conf->browser->name == 'chrome') {
3090  $stringforfirstkey .= ' ALT +';
3091  } elseif ($conf->browser->name == 'firefox') {
3092  $stringforfirstkey .= ' ALT + SHIFT +';
3093  } else {
3094  $stringforfirstkey .= ' CTL +';
3095  }
3096 
3097  $searchform .= $form->selectArrayFilter('searchselectcombo', $arrayresult, $selected, 'accesskey="s"', 1, 0, (empty($conf->global->MAIN_SEARCHBOX_CONTENT_LOADED_BEFORE_KEY) ? 1 : 0), 'vmenusearchselectcombo', 1, $langs->trans("Search"), 1, $stringforfirstkey.' s');
3098  } else {
3099  if (is_array($arrayresult)) {
3100  foreach ($arrayresult as $key => $val) {
3101  $searchform .= printSearchForm($val['url'], $val['url'], $val['label'], 'maxwidth125', 'search_all', (empty($val['shortcut']) ? '' : $val['shortcut']), 'searchleft'.$key, $val['img']);
3102  }
3103  }
3104  }
3105 
3106  // Execute hook printSearchForm
3107  $parameters = array('searchform' => $searchform);
3108  $reshook = $hookmanager->executeHooks('printSearchForm', $parameters); // Note that $action and $object may have been modified by some hooks
3109  if (empty($reshook)) {
3110  $searchform .= $hookmanager->resPrint;
3111  } else {
3112  $searchform = $hookmanager->resPrint;
3113  }
3114 
3115  // Force special value for $searchform for text browsers or very old search form
3116  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) || empty($conf->use_javascript_ajax)) {
3117  $urltosearch = DOL_URL_ROOT.'/core/search_page.php?showtitlebefore=1';
3118  $searchform = '<div class="blockvmenuimpair blockvmenusearchphone"><div id="divsearchforms1"><a href="'.$urltosearch.'" accesskey="s" alt="'.dol_escape_htmltag($langs->trans("ShowSearchFields")).'">'.$langs->trans("Search").'...</a></div></div>';
3119  } elseif ($conf->use_javascript_ajax && !empty($conf->global->MAIN_USE_OLD_SEARCH_FORM)) {
3120  $searchform = '<div class="blockvmenuimpair blockvmenusearchphone"><div id="divsearchforms1"><a href="#" alt="'.dol_escape_htmltag($langs->trans("ShowSearchFields")).'">'.$langs->trans("Search").'...</a></div><div id="divsearchforms2" style="display: none">'.$searchform.'</div>';
3121  $searchform .= '<script>
3122  jQuery(document).ready(function () {
3123  jQuery("#divsearchforms1").click(function(){
3124  jQuery("#divsearchforms2").toggle();
3125  });
3126  });
3127  </script>' . "\n";
3128  $searchform .= '</div>';
3129  }
3130 
3131  // Key map shortcut
3132  $searchform .= '<script>
3133  jQuery(document).keydown(function(e){
3134  if( e.which === 70 && e.ctrlKey && e.shiftKey ){
3135  console.log(\'control + shift + f : trigger open global-search dropdown\');
3136  openGlobalSearchDropDown();
3137  }
3138  if( (e.which === 83 || e.which === 115) && e.altKey ){
3139  console.log(\'alt + s : trigger open global-search dropdown\');
3140  openGlobalSearchDropDown();
3141  }
3142  });
3143 
3144  var openGlobalSearchDropDown = function() {
3145  jQuery("#searchselectcombo").select2(\'open\');
3146  }
3147  </script>';
3148  }
3149 
3150  // Left column
3151  print '<!-- Begin left menu -->'."\n";
3152 
3153  print '<div class="vmenu"'.(empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? '' : ' title="Left menu"').'>'."\n\n";
3154 
3155  // Show left menu with other forms
3156  $menumanager->menu_array = $menu_array_before;
3157  $menumanager->menu_array_after = $menu_array_after;
3158  $menumanager->showmenu('left', array('searchform'=>$searchform)); // output menu_array and menu found in database
3159 
3160  // Dolibarr version + help + bug report link
3161  print "\n";
3162  print "<!-- Begin Help Block-->\n";
3163  print '<div id="blockvmenuhelp" class="blockvmenuhelp">'."\n";
3164 
3165  // Version
3166  if (!empty($conf->global->MAIN_SHOW_VERSION)) { // Version is already on help picto and on login page.
3167  $doliurl = 'https://www.dolibarr.org';
3168  //local communities
3169  if (preg_match('/fr/i', $langs->defaultlang)) {
3170  $doliurl = 'https://www.dolibarr.fr';
3171  }
3172  if (preg_match('/es/i', $langs->defaultlang)) {
3173  $doliurl = 'https://www.dolibarr.es';
3174  }
3175  if (preg_match('/de/i', $langs->defaultlang)) {
3176  $doliurl = 'https://www.dolibarr.de';
3177  }
3178  if (preg_match('/it/i', $langs->defaultlang)) {
3179  $doliurl = 'https://www.dolibarr.it';
3180  }
3181  if (preg_match('/gr/i', $langs->defaultlang)) {
3182  $doliurl = 'https://www.dolibarr.gr';
3183  }
3184 
3185  $appli = constant('DOL_APPLICATION_TITLE');
3186  if (!empty($conf->global->MAIN_APPLICATION_TITLE)) {
3187  $appli = $conf->global->MAIN_APPLICATION_TITLE; $doliurl = '';
3188  if (preg_match('/\d\.\d/', $appli)) {
3189  if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) {
3190  $appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core
3191  }
3192  } else {
3193  $appli .= " ".DOL_VERSION;
3194  }
3195  } else {
3196  $appli .= " ".DOL_VERSION;
3197  }
3198  print '<div id="blockvmenuhelpapp" class="blockvmenuhelp">';
3199  if ($doliurl) {
3200  print '<a class="help" target="_blank" rel="noopener noreferrer" href="'.$doliurl.'">';
3201  } else {
3202  print '<span class="help">';
3203  }
3204  print $appli;
3205  if ($doliurl) {
3206  print '</a>';
3207  } else {
3208  print '</span>';
3209  }
3210  print '</div>'."\n";
3211  }
3212 
3213  // Link to bugtrack
3214  if (!empty($conf->global->MAIN_BUGTRACK_ENABLELINK)) {
3215  require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
3216 
3217  if ($conf->global->MAIN_BUGTRACK_ENABLELINK == 'github') {
3218  $bugbaseurl = 'https://github.com/Dolibarr/dolibarr/issues/new?labels=Bug';
3219  $bugbaseurl .= '&title=';
3220  $bugbaseurl .= urlencode("Bug: ");
3221  $bugbaseurl .= '&body=';
3222  $bugbaseurl .= urlencode("# Instructions\n");
3223  $bugbaseurl .= urlencode("*This is a template to help you report good issues. You may use [Github Markdown](https://help.github.com/articles/getting-started-with-writing-and-formatting-on-github/) syntax to format your issue report.*\n");
3224  $bugbaseurl .= urlencode("*Please:*\n");
3225  $bugbaseurl .= urlencode("- *replace the bracket enclosed texts with meaningful information*\n");
3226  $bugbaseurl .= urlencode("- *remove any unused sub-section*\n");
3227  $bugbaseurl .= urlencode("\n");
3228  $bugbaseurl .= urlencode("\n");
3229  $bugbaseurl .= urlencode("# Bug\n");
3230  $bugbaseurl .= urlencode("[*Short description*]\n");
3231  $bugbaseurl .= urlencode("\n");
3232  $bugbaseurl .= urlencode("## Environment\n");
3233  $bugbaseurl .= urlencode("- **Version**: ".DOL_VERSION."\n");
3234  $bugbaseurl .= urlencode("- **OS**: ".php_uname('s')."\n");
3235  $bugbaseurl .= urlencode("- **Web server**: ".$_SERVER["SERVER_SOFTWARE"]."\n");
3236  $bugbaseurl .= urlencode("- **PHP**: ".php_sapi_name().' '.phpversion()."\n");
3237  $bugbaseurl .= urlencode("- **Database**: ".$db::LABEL.' '.$db->getVersion()."\n");
3238  $bugbaseurl .= urlencode("- **URL(s)**: ".$_SERVER["REQUEST_URI"]."\n");
3239  $bugbaseurl .= urlencode("\n");
3240  $bugbaseurl .= urlencode("## Expected and actual behavior\n");
3241  $bugbaseurl .= urlencode("[*Verbose description*]\n");
3242  $bugbaseurl .= urlencode("\n");
3243  $bugbaseurl .= urlencode("## Steps to reproduce the behavior\n");
3244  $bugbaseurl .= urlencode("[*Verbose description*]\n");
3245  $bugbaseurl .= urlencode("\n");
3246  $bugbaseurl .= urlencode("## [Attached files](https://help.github.com/articles/issue-attachments) (Screenshots, screencasts, dolibarr.log, debugging informations…)\n");
3247  $bugbaseurl .= urlencode("[*Files*]\n");
3248  $bugbaseurl .= urlencode("\n");
3249 
3250  $bugbaseurl .= urlencode("\n");
3251  $bugbaseurl .= urlencode("## Report\n");
3252  } elseif (!empty($conf->global->MAIN_BUGTRACK_ENABLELINK)) {
3253  $bugbaseurl = $conf->global->MAIN_BUGTRACK_ENABLELINK;
3254  } else {
3255  $bugbaseurl = "";
3256  }
3257 
3258  // Execute hook printBugtrackInfo
3259  $parameters = array('bugbaseurl' => $bugbaseurl);
3260  $reshook = $hookmanager->executeHooks('printBugtrackInfo', $parameters); // Note that $action and $object may have been modified by some hooks
3261  if (empty($reshook)) {
3262  $bugbaseurl .= $hookmanager->resPrint;
3263  } else {
3264  $bugbaseurl = $hookmanager->resPrint;
3265  }
3266 
3267  print '<div id="blockvmenuhelpbugreport" class="blockvmenuhelp">';
3268  print '<a class="help" target="_blank" rel="noopener noreferrer" href="'.$bugbaseurl.'"><i class="fas fa-bug"></i> '.$langs->trans("FindBug").'</a>';
3269  print '</div>';
3270  }
3271 
3272  print "</div>\n";
3273  print "<!-- End Help Block-->\n";
3274  print "\n";
3275 
3276  print "</div>\n";
3277  print "<!-- End left menu -->\n";
3278  print "\n";
3279 
3280  // Execute hook printLeftBlock
3281  $parameters = array();
3282  $reshook = $hookmanager->executeHooks('printLeftBlock', $parameters); // Note that $action and $object may have been modified by some hooks
3283  print $hookmanager->resPrint;
3284 
3285  print '</div></div> <!-- End side-nav id-left -->'; // End div id="side-nav" div id="id-left"
3286  }
3287 
3288  print "\n";
3289  print '<!-- Begin right area -->'."\n";
3290 
3291  if (empty($leftmenuwithoutmainarea)) {
3292  main_area($title);
3293  }
3294 }
3295 
3296 
3303 function main_area($title = '')
3304 {
3305  global $conf, $langs, $hookmanager;
3306 
3307  if (empty($conf->dol_hide_leftmenu) && !GETPOST('dol_openinpopup')) {
3308  print '<div id="id-right">';
3309  }
3310 
3311  print "\n";
3312 
3313  print '<!-- Begin div class="fiche" -->'."\n".'<div class="fiche">'."\n";
3314 
3315  $hookmanager->initHooks(array('main'));
3316  $parameters = array();
3317  $reshook = $hookmanager->executeHooks('printMainArea', $parameters); // Note that $action and $object may have been modified by some hooks
3318  print $hookmanager->resPrint;
3319 
3320  if (!empty($conf->global->MAIN_ONLY_LOGIN_ALLOWED)) {
3321  print info_admin($langs->trans("WarningYouAreInMaintenanceMode", $conf->global->MAIN_ONLY_LOGIN_ALLOWED), 0, 0, 1, 'warning maintenancemode');
3322  }
3323 
3324  // Permit to add user company information on each printed document by setting SHOW_SOCINFO_ON_PRINT
3325  if (!empty($conf->global->SHOW_SOCINFO_ON_PRINT) && GETPOST('optioncss', 'aZ09') == 'print' && empty(GETPOST('disable_show_socinfo_on_print', 'az09'))) {
3326  $parameters = array();
3327  $reshook = $hookmanager->executeHooks('showSocinfoOnPrint', $parameters);
3328  if (empty($reshook)) {
3329  print '<!-- Begin show mysoc info header -->'."\n";
3330  print '<div id="mysoc-info-header">'."\n";
3331  print '<table class="centpercent div-table-responsive">'."\n";
3332  print '<tbody>';
3333  print '<tr><td rowspan="0" class="width20p">';
3334  if ($conf->global->MAIN_SHOW_LOGO && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && !empty($conf->global->MAIN_INFO_SOCIETE_LOGO)) {
3335  print '<img id="mysoc-info-header-logo" style="max-width:100%" alt="" src="'.DOL_URL_ROOT.'/viewimage.php?cache=1&modulepart=mycompany&file='.urlencode('logos/'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_LOGO)).'">';
3336  }
3337  print '</td><td rowspan="0" class="width50p"></td></tr>'."\n";
3338  print '<tr><td class="titre bold">'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_NOM).'</td></tr>'."\n";
3339  print '<tr><td>'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_ADDRESS).'<br>'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_ZIP).' '.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_TOWN).'</td></tr>'."\n";
3340  if (!empty($conf->global->MAIN_INFO_SOCIETE_TEL)) {
3341  print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Phone").' : '.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_TEL).'</td></tr>';
3342  }
3343  if (!empty($conf->global->MAIN_INFO_SOCIETE_MAIL)) {
3344  print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Email").' : '.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_MAIL).'</td></tr>';
3345  }
3346  if (!empty($conf->global->MAIN_INFO_SOCIETE_WEB)) {
3347  print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Web").' : '.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_WEB).'</td></tr>';
3348  }
3349  print '</tbody>';
3350  print '</table>'."\n";
3351  print '</div>'."\n";
3352  print '<!-- End show mysoc info header -->'."\n";
3353  }
3354  }
3355 }
3356 
3357 
3365 function getHelpParamFor($helppagename, $langs)
3366 {
3367  $helpbaseurl = '';
3368  $helppage = '';
3369  $mode = '';
3370 
3371  if (preg_match('/^http/i', $helppagename)) {
3372  // If complete URL
3373  $helpbaseurl = '%s';
3374  $helppage = $helppagename;
3375  $mode = 'local';
3376  } else {
3377  // If WIKI URL
3378  $reg = array();
3379  if (preg_match('/^es/i', $langs->defaultlang)) {
3380  $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3381  if (preg_match('/ES:([^|]+)/i', $helppagename, $reg)) {
3382  $helppage = $reg[1];
3383  }
3384  }
3385  if (preg_match('/^fr/i', $langs->defaultlang)) {
3386  $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3387  if (preg_match('/FR:([^|]+)/i', $helppagename, $reg)) {
3388  $helppage = $reg[1];
3389  }
3390  }
3391  if (preg_match('/^de/i', $langs->defaultlang)) {
3392  $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3393  if (preg_match('/DE:([^|]+)/i', $helppagename, $reg)) {
3394  $helppage = $reg[1];
3395  }
3396  }
3397  if (empty($helppage)) { // If help page not already found
3398  $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3399  if (preg_match('/EN:([^|]+)/i', $helppagename, $reg)) {
3400  $helppage = $reg[1];
3401  }
3402  }
3403  $mode = 'wiki';
3404  }
3405  return array('helpbaseurl'=>$helpbaseurl, 'helppage'=>$helppage, 'mode'=>$mode);
3406 }
3407 
3408 
3425 function printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey = '', $prefhtmlinputname = '', $img = '', $showtitlebefore = 0, $autofocus = 0)
3426 {
3427  global $conf, $langs, $user;
3428 
3429  $ret = '';
3430  $ret .= '<form action="'.$urlaction.'" method="post" class="searchform nowraponall tagtr">';
3431  $ret .= '<input type="hidden" name="token" value="'.newToken().'">';
3432  $ret .= '<input type="hidden" name="savelogin" value="'.dol_escape_htmltag($user->login).'">';
3433  if ($showtitlebefore) {
3434  $ret .= '<div class="tagtd left">'.$title.'</div> ';
3435  }
3436  $ret .= '<div class="tagtd">';
3437  $ret .= img_picto('', $img, '', false, 0, 0, '', 'paddingright width20');
3438  $ret .= '<input type="text" class="flat '.$htmlmorecss.'"';
3439  $ret .= ' style="background-repeat: no-repeat; background-position: 3px;"';
3440  $ret .= ($accesskey ? ' accesskey="'.$accesskey.'"' : '');
3441  $ret .= ' placeholder="'.strip_tags($title).'"';
3442  $ret .= ($autofocus ? ' autofocus' : '');
3443  $ret .= ' name="'.$htmlinputname.'" id="'.$prefhtmlinputname.$htmlinputname.'" />';
3444  $ret .= '<button type="submit" class="button bordertransp" style="padding-top: 4px; padding-bottom: 4px; padding-left: 6px; padding-right: 6px">';
3445  $ret .= '<span class="fa fa-search"></span>';
3446  $ret .= '</button>';
3447  $ret .= '</div>';
3448  $ret .= "</form>\n";
3449  return $ret;
3450 }
3451 
3452 
3453 if (!function_exists("llxFooter")) {
3464  function llxFooter($comment = '', $zone = 'private', $disabledoutputofmessages = 0)
3465  {
3466  global $conf, $db, $langs, $user, $mysoc, $object, $hookmanager;
3467  global $delayedhtmlcontent;
3468  global $contextpage, $page, $limit, $mode;
3469  global $dolibarr_distrib;
3470 
3471  $ext = 'layout='.urlencode($conf->browser->layout).'&version='.urlencode(DOL_VERSION);
3472 
3473  // Hook to add more things on all pages within fiche DIV
3474  $llxfooter = '';
3475  $parameters = array();
3476  $reshook = $hookmanager->executeHooks('llxFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3477  if (empty($reshook)) {
3478  $llxfooter .= $hookmanager->resPrint;
3479  } elseif ($reshook > 0) {
3480  $llxfooter = $hookmanager->resPrint;
3481  }
3482  if ($llxfooter) {
3483  print $llxfooter;
3484  }
3485 
3486  // Global html output events ($mesgs, $errors, $warnings)
3487  dol_htmloutput_events($disabledoutputofmessages);
3488 
3489  // Code for search criteria persistence.
3490  // $user->lastsearch_values was set by the GETPOST when form field search_xxx exists
3491  if (is_object($user) && !empty($user->lastsearch_values_tmp) && is_array($user->lastsearch_values_tmp)) {
3492  // Clean and save data
3493  foreach ($user->lastsearch_values_tmp as $key => $val) {
3494  unset($_SESSION['lastsearch_values_tmp_'.$key]); // Clean array to rebuild it just after
3495  if (count($val) && empty($_POST['button_removefilter']) && empty($_POST['button_removefilter_x'])) {
3496  if (empty($val['sortfield'])) {
3497  unset($val['sortfield']);
3498  }
3499  if (empty($val['sortorder'])) {
3500  unset($val['sortorder']);
3501  }
3502  dol_syslog('Save lastsearch_values_tmp_'.$key.'='.json_encode($val, 0)." (systematic recording of last search criterias)");
3503  $_SESSION['lastsearch_values_tmp_'.$key] = json_encode($val);
3504  unset($_SESSION['lastsearch_values_'.$key]);
3505  }
3506  }
3507  }
3508 
3509 
3510  $relativepathstring = $_SERVER["PHP_SELF"];
3511  // Clean $relativepathstring
3512  if (constant('DOL_URL_ROOT')) {
3513  $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
3514  }
3515  $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
3516  $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
3517  if (preg_match('/list\.php$/', $relativepathstring)) {
3518  unset($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]);
3519  unset($_SESSION['lastsearch_page_tmp_'.$relativepathstring]);
3520  unset($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]);
3521  unset($_SESSION['lastsearch_mode_tmp_'.$relativepathstring]);
3522 
3523  if (!empty($contextpage)) {
3524  $_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring] = $contextpage;
3525  }
3526  if (!empty($page) && $page > 0) {
3527  $_SESSION['lastsearch_page_tmp_'.$relativepathstring] = $page;
3528  }
3529  if (!empty($limit) && $limit != $conf->liste_limit) {
3530  $_SESSION['lastsearch_limit_tmp_'.$relativepathstring] = $limit;
3531  }
3532  if (!empty($mode)) {
3533  $_SESSION['lastsearch_mode_tmp_'.$relativepathstring] = $mode;
3534  }
3535 
3536  unset($_SESSION['lastsearch_contextpage_'.$relativepathstring]);
3537  unset($_SESSION['lastsearch_page_'.$relativepathstring]);
3538  unset($_SESSION['lastsearch_limit_'.$relativepathstring]);
3539  unset($_SESSION['lastsearch_mode_'.$relativepathstring]);
3540  }
3541 
3542  // Core error message
3543  if (!empty($conf->global->MAIN_CORE_ERROR)) {
3544  // Ajax version
3545  if ($conf->use_javascript_ajax) {
3546  $title = img_warning().' '.$langs->trans('CoreErrorTitle');
3547  print ajax_dialog($title, $langs->trans('CoreErrorMessage'));
3548  } else {
3549  // html version
3550  $msg = img_warning().' '.$langs->trans('CoreErrorMessage');
3551  print '<div class="error">'.$msg.'</div>';
3552  }
3553 
3554  //define("MAIN_CORE_ERROR",0); // Constant was defined and we can't change value of a constant
3555  }
3556 
3557  print "\n\n";
3558 
3559  print '</div> <!-- End div class="fiche" -->'."\n"; // End div fiche
3560 
3561  if (empty($conf->dol_hide_leftmenu) && !GETPOST('dol_openinpopup')) {
3562  print '</div> <!-- End div id-right -->'."\n"; // End div id-right
3563  }
3564 
3565  if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) {
3566  print '</div> <!-- End div id-container -->'."\n"; // End div container
3567  }
3568 
3569  print "\n";
3570  if ($comment) {
3571  print '<!-- '.$comment.' -->'."\n";
3572  }
3573 
3574  printCommonFooter($zone);
3575 
3576  if (!empty($delayedhtmlcontent)) {
3577  print $delayedhtmlcontent;
3578  }
3579 
3580  if (!empty($conf->use_javascript_ajax)) {
3581  print "\n".'<!-- Includes JS Footer of Dolibarr -->'."\n";
3582  print '<script src="'.DOL_URL_ROOT.'/core/js/lib_foot.js.php?lang='.$langs->defaultlang.($ext ? '&'.$ext : '').'"></script>'."\n";
3583  }
3584 
3585  // Wrapper to add log when clicking on download or preview
3586  if (isModEnabled('blockedlog') && is_object($object) && !empty($object->id) && $object->id > 0) {
3587  if (in_array($object->element, array('facture')) && $object->statut > 0) { // Restrict for the moment to element 'facture'
3588  print "\n<!-- JS CODE TO ENABLE log when making a download or a preview of a document -->\n";
3589  ?>
3590  <script>
3591  jQuery(document).ready(function () {
3592  $('a.documentpreview').click(function() {
3593  $.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
3594  , {
3595  id:<?php echo $object->id; ?>
3596  , element:'<?php echo $object->element ?>'
3597  , action:'DOC_PREVIEW'
3598  , token: '<?php echo currentToken(); ?>'
3599  }
3600  );
3601  });
3602  $('a.documentdownload').click(function() {
3603  $.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
3604  , {
3605  id:<?php echo $object->id; ?>
3606  , element:'<?php echo $object->element ?>'
3607  , action:'DOC_DOWNLOAD'
3608  , token: '<?php echo currentToken(); ?>'
3609  }
3610  );
3611  });
3612  });
3613  </script>
3614  <?php
3615  }
3616  }
3617 
3618  // A div for the address popup
3619  print "\n<!-- A div to allow dialog popup by jQuery('#dialogforpopup').dialog() -->\n";
3620  print '<div id="dialogforpopup" style="display: none;"></div>'."\n";
3621 
3622  // Add code for the asynchronous anonymous first ping (for telemetry)
3623  // You can use &forceping=1 in parameters to force the ping if the ping was already sent.
3624  $forceping = GETPOST('forceping', 'alpha');
3625  if (($_SERVER["PHP_SELF"] == DOL_URL_ROOT.'/index.php') || $forceping) {
3626  //print '<!-- instance_unique_id='.$conf->file->instance_unique_id.' MAIN_FIRST_PING_OK_ID='.$conf->global->MAIN_FIRST_PING_OK_ID.' -->';
3627  $hash_unique_id = md5('dolibarr'.$conf->file->instance_unique_id); // Do not use dol_hash(), must not change if salt changes.
3628 
3629  if (empty($conf->global->MAIN_FIRST_PING_OK_DATE)
3630  || (!empty($conf->file->instance_unique_id) && ($hash_unique_id != $conf->global->MAIN_FIRST_PING_OK_ID) && ($conf->global->MAIN_FIRST_PING_OK_ID != 'disabled'))
3631  || $forceping) {
3632  // No ping done if we are into an alpha version
3633  if (strpos('alpha', DOL_VERSION) > 0 && !$forceping) {
3634  print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. It is an alpha version -->\n";
3635  } elseif (empty($_COOKIE['DOLINSTALLNOPING_'.$hash_unique_id]) || $forceping) { // Cookie is set when we uncheck the checkbox in the installation wizard.
3636  // MAIN_LAST_PING_KO_DATE
3637  // Disable ping if MAIN_LAST_PING_KO_DATE is set and is recent (this month)
3638  if (!empty($conf->global->MAIN_LAST_PING_KO_DATE) && substr($conf->global->MAIN_LAST_PING_KO_DATE, 0, 6) == dol_print_date(dol_now(), '%Y%m') && !$forceping) {
3639  print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. An error already occured this month, we will try later. -->\n";
3640  } else {
3641  include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
3642 
3643  print "\n".'<!-- Includes JS for Ping of Dolibarr forceping='.$forceping.' MAIN_FIRST_PING_OK_DATE='.getDolGlobalString("MAIN_FIRST_PING_OK_DATE").' MAIN_FIRST_PING_OK_ID='.getDolGlobalString("MAIN_FIRST_PING_OK_ID").' MAIN_LAST_PING_KO_DATE='.getDolGlobalString("MAIN_LAST_PING_KO_DATE").' -->'."\n";
3644  print "\n<!-- JS CODE TO ENABLE the anonymous Ping -->\n";
3645  $url_for_ping = (empty($conf->global->MAIN_URL_FOR_PING) ? "https://ping.dolibarr.org/" : $conf->global->MAIN_URL_FOR_PING);
3646  // Try to guess the distrib used
3647  $distrib = 'standard';
3648  if ($_SERVER["SERVER_ADMIN"] == 'doliwamp@localhost') {
3649  $distrib = 'doliwamp';
3650  }
3651  if (!empty($dolibarr_distrib)) {
3652  $distrib = $dolibarr_distrib;
3653  }
3654  ?>
3655  <script>
3656  jQuery(document).ready(function (tmp) {
3657  console.log("Try Ping with hash_unique_id is md5('dolibarr'+instance_unique_id)");
3658  $.ajax({
3659  method: "POST",
3660  url: "<?php echo $url_for_ping ?>",
3661  timeout: 500, // timeout milliseconds
3662  cache: false,
3663  data: {
3664  hash_algo: 'md5',
3665  hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>',
3666  action: 'dolibarrping',
3667  version: '<?php echo (float) DOL_VERSION; ?>',
3668  entity: '<?php echo (int) $conf->entity; ?>',
3669  dbtype: '<?php echo dol_escape_js($db->type); ?>',
3670  country_code: '<?php echo $mysoc->country_code ? dol_escape_js($mysoc->country_code) : 'unknown'; ?>',
3671  php_version: '<?php echo dol_escape_js(phpversion()); ?>',
3672  os_version: '<?php echo dol_escape_js(version_os('smr')); ?>',
3673  distrib: '<?php echo $distrib ? dol_escape_js($distrib) : 'unknown'; ?>',
3674  token: 'notrequired'
3675  },
3676  success: function (data, status, xhr) { // success callback function (data contains body of response)
3677  console.log("Ping ok");
3678  $.ajax({
3679  method: 'GET',
3680  url: '<?php echo DOL_URL_ROOT.'/core/ajax/pingresult.php'; ?>',
3681  timeout: 500, // timeout milliseconds
3682  cache: false,
3683  data: { hash_algo: 'md5', hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>', action: 'firstpingok', token: '<?php echo currentToken(); ?>' }, // for update
3684  });
3685  },
3686  error: function (data,status,xhr) { // error callback function
3687  console.log("Ping ko: " + data);
3688  $.ajax({
3689  method: 'GET',
3690  url: '<?php echo DOL_URL_ROOT.'/core/ajax/pingresult.php'; ?>',
3691  timeout: 500, // timeout milliseconds
3692  cache: false,
3693  data: { hash_algo: 'md5', hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>', action: 'firstpingko', token: '<?php echo currentToken(); ?>' },
3694  });
3695  }
3696  });
3697  });
3698  </script>
3699  <?php
3700  }
3701  } else {
3702  $now = dol_now();
3703  print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. It was disabled -->\n";
3704  include_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
3705  dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_DATE', dol_print_date($now, 'dayhourlog', 'gmt'), 'chaine', 0, '', $conf->entity);
3706  dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_ID', 'disabled', 'chaine', 0, '', $conf->entity);
3707  }
3708  }
3709  }
3710 
3711  $reshook = $hookmanager->executeHooks('beforeBodyClose'); // Note that $action and $object may have been modified by some hooks
3712  if ($reshook > 0) {
3713  print $hookmanager->resPrint;
3714  }
3715 
3716  print "</body>\n";
3717  print "</html>\n";
3718  }
3719 }
analyseVarsForSqlAndScriptsInjection
analyseVarsForSqlAndScriptsInjection(&$var, $type)
Return true if security check on parameters are OK, false otherwise.
Definition: main.inc.php:216
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:51
top_httphead
if(!defined('NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
Definition: main.inc.php:1490
yn
yn($yesno, $case=1, $color=0)
Return yes or no in current language.
Definition: functions.lib.php:6812
dol_escape_htmltag
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
Definition: functions.lib.php:1594
MenuManager
Class to manage menu Auguria.
Definition: auguria_menu.php:29
dol_trunc
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.
Definition: functions.lib.php:4049
realCharForNumericEntities
if(!empty($_SERVER['MAIN_SHOW_TUNING_INFO'])) realCharForNumericEntities($matches)
Return the real char for a numeric entities.
Definition: main.inc.php:63
dol_htmloutput_events
dol_htmloutput_events($disabledoutputofmessages=0)
Print formated messages to output (Used to show messages on html output).
Definition: functions.lib.php:8679
llxFooter
llxFooter()
Empty footer.
Definition: wrapper.php:70
left_menu
left_menu($menu_array_before, $helppagename='', $notused='', $menu_array_after='', $leftmenuwithoutmainarea=0, $title='', $acceptdelayedhtml=0)
Show left menu bar.
Definition: main.inc.php:3053
versioncompare
versioncompare($versionarray1, $versionarray2)
Compare 2 versions (stored into 2 arrays).
Definition: admin.lib.php:67
top_menu_bookmark
top_menu_bookmark()
Build the tooltip on top menu bookmark.
Definition: main.inc.php:2798
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:607
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:5096
top_menu
top_menu($head, $title='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $helppagename='')
Show an HTML header + a BODY + The top menu bar.
Definition: main.inc.php:2032
dol_include_once
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
Definition: functions.lib.php:1128
Translate
Class to manage translations.
Definition: translate.class.php:30
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1157
top_menu_user
top_menu_user($hideloginname=0, $urllogout='')
Build the tooltip on user login.
Definition: main.inc.php:2276
img_warning
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
Definition: functions.lib.php:4773
top_htmlhead
top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $disableforlogin=0, $disablenofollow=0, $disablenoindex=0)
Ouput html header of a page.
Definition: main.inc.php:1621
picto_from_langcode
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
Definition: functions.lib.php:9276
$form
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
printCommonFooter
printCommonFooter($zone='private')
Print common footer : conf->global->MAIN_HTML_FOOTER js for switch of menu hider js for conf->global-...
Definition: functions.lib.php:9709
$help_url
if(GETPOST('button_removefilter_x', 'alpha')||GETPOST('button_removefilter.x', 'alpha')||GETPOST('button_removefilter', 'alpha')) if(GETPOST('button_search_x', 'alpha')||GETPOST('button_search.x', 'alpha')||GETPOST('button_search', 'alpha')) if($action=="save" &&empty($cancel)) $help_url
View.
Definition: agenda.php:118
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2665
dol_print_profids
dol_print_profids($profID, $profIDtype, $countrycode='', $addcpButton=1, $separ='&nbsp;')
Format profIDs according to country.
Definition: functions.lib.php:3355
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:4125
llxHeader
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
dol_hash
dol_hash($chain, $type='0')
Returns a hash (non reversible encryption) of a string.
Definition: security.lib.php:219
printSearchForm
printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey='', $prefhtmlinputname='', $img='', $showtitlebefore=0, $autofocus=0)
Show a search area.
Definition: main.inc.php:3425
getHelpParamFor
getHelpParamFor($helppagename, $langs)
Return helpbaseurl, helppage and mode.
Definition: main.inc.php:3365
getBrowserInfo
getBrowserInfo($user_agent)
Return information about user browser.
Definition: functions.lib.php:378
ajax_dialog
ajax_dialog($title, $message, $w=350, $h=150)
Show an ajax dialog.
Definition: ajax.lib.php:404
checkLoginPassEntity
checkLoginPassEntity($usertotest, $passwordtotest, $entitytotest, $authmode, $context='')
Return a login if login/pass was successfull.
Definition: security2.lib.php:57
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1732
dolButtonToOpenUrlInDialogPopup
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.
Definition: functions.lib.php:1851
setEventMessages
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages in dol_events session object.
Definition: functions.lib.php:8644
info_admin
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
Definition: functions.lib.php:5052
main_area
main_area($title='')
Begin main area.
Definition: main.inc.php:3303
newToken
newToken()
Return the value of token currently saved into session with name 'newtoken'.
Definition: functions.lib.php:11620
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:207
getDolGlobalString
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
Definition: functions.lib.php:142
dolibarr_set_const
dolibarr_set_const($db, $name, $value, $type='chaine', $visible=0, $note='', $entity=1)
Insert a parameter (key,value) into database (delete old key then insert it again).
Definition: admin.lib.php:633
GETPOSTISSET
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
Definition: functions.lib.php:507
Form
Class to manage generation of HTML components Only common components must be here.
Definition: html.form.class.php:53
testSqlAndScriptInject
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition: main.inc.php:89
printDropdownBookmarksList
printDropdownBookmarksList()
Add area with bookmarks in top menu.
Definition: bookmarks.lib.php:30
DolibarrDebugBar
DolibarrDebugBar class.
Definition: DebugBar.php:45
isHTTPS
isHTTPS()
Return if we are using a HTTPS connexion Check HTTPS (no way to be modified by user but may be empty ...
Definition: functions.lib.php:3758
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:3046
printDropdownQuickadd
printDropdownQuickadd()
Generate list of quickadd items.
Definition: main.inc.php:2619
Form\showphoto
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
Definition: html.form.class.php:9618
accessforbidden
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.
Definition: security.lib.php:1152
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:156
top_menu_search
top_menu_search()
Build the tooltip on top menu tsearch.
Definition: main.inc.php:2881
dol_stringtotime
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition: date.lib.php:408
HookManager
Class to manage hooks.
Definition: hookmanager.class.php:30
top_menu_quickadd
top_menu_quickadd()
Build the tooltip on top menu quick add.
Definition: main.inc.php:2558
dol_htmlentities
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
Definition: functions.lib.php:7528
float
div float
Buy price without taxes.
Definition: style.css.php:921
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25