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