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