dolibarr  17.0.3
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  if ($key !== 'action' && $key !== 'password' && !is_array($value)) {
2081  $qs .= '&'.$key.'='.urlencode($value);
2082  }
2083  }
2084  }
2085  $qs .= (($qs && $morequerystring) ? '&' : '').$morequerystring;
2086  $text = '<a href="'.dol_escape_htmltag($_SERVER["PHP_SELF"]).'?'.$qs.($qs ? '&' : '').'optioncss=print" target="_blank" rel="noopener noreferrer">';
2087  //$text.= img_picto(":".$langs->trans("PrintContentArea"), 'printer_top.png', 'class="printer"');
2088  $text .= '<span class="fa fa-print atoplogin valignmiddle"></span>';
2089  $text .= '</a>';
2090  $toprightmenu .= $form->textwithtooltip('', $langs->trans("PrintContentArea"), 2, 1, $text, 'login_block_elem', 2);
2091  }
2092 
2093  // Link to Dolibarr wiki pages
2094  if (empty($conf->global->MAIN_HELP_DISABLELINK) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2095  $langs->load("help");
2096 
2097  $helpbaseurl = '';
2098  $helppage = '';
2099  $mode = '';
2100  $helppresent = '';
2101 
2102  if (empty($helppagename)) {
2103  $helppagename = 'EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios';
2104  } else {
2105  $helppresent = 'helppresent';
2106  }
2107 
2108  // Get helpbaseurl, helppage and mode from helppagename and langs
2109  $arrayres = getHelpParamFor($helppagename, $langs);
2110  $helpbaseurl = $arrayres['helpbaseurl'];
2111  $helppage = $arrayres['helppage'];
2112  $mode = $arrayres['mode'];
2113 
2114  // Link to help pages
2115  if ($helpbaseurl && $helppage) {
2116  $text = '';
2117  $title = $langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage' : 'GoToHelpPage').', ';
2118  if ($mode == 'wiki') {
2119  $title .= '<br>'.img_picto('', 'globe', 'class="pictofixedwidth"').$langs->trans("PageWiki").' '.dol_escape_htmltag('"'.strtr($helppage, '_', ' ').'"');
2120  if ($helppresent) {
2121  $title .= ' <span class="opacitymedium">('.$langs->trans("DedicatedPageAvailable").')</span>';
2122  } else {
2123  $title .= ' <span class="opacitymedium">('.$langs->trans("HomePage").')</span>';
2124  }
2125  }
2126  $text .= '<a class="help" target="_blank" rel="noopener noreferrer" href="';
2127  if ($mode == 'wiki') {
2128  $text .= sprintf($helpbaseurl, urlencode(html_entity_decode($helppage)));
2129  } else {
2130  $text .= sprintf($helpbaseurl, $helppage);
2131  }
2132  $text .= '">';
2133  $text .= '<span class="fa fa-question-circle atoplogin valignmiddle'.($helppresent ? ' '.$helppresent : '').'"></span>';
2134  $text .= '<span class="fa fa-long-arrow-alt-up helppresentcircle'.($helppresent ? '' : ' unvisible').'"></span>';
2135  $text .= '</a>';
2136  $toprightmenu .= $form->textwithtooltip('', $title, 2, 1, $text, 'login_block_elem', 2);
2137  }
2138 
2139  // Version
2140  if (!empty($conf->global->MAIN_SHOWDATABASENAMEINHELPPAGESLINK)) {
2141  $langs->load('admin');
2142  $appli .= '<br>'.$langs->trans("Database").': '.$db->database_name;
2143  }
2144  }
2145 
2146  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2147  $text = '<span class="aversion"><span class="hideonsmartphone small">'.DOL_VERSION.'</span></span>';
2148  $toprightmenu .= $form->textwithtooltip('', $appli, 2, 1, $text, 'login_block_elem', 2);
2149  }
2150 
2151  // Logout link
2152  $toprightmenu .= $form->textwithtooltip('', $logouthtmltext, 2, 1, $logouttext, 'login_block_elem logout-btn', 2);
2153 
2154  $toprightmenu .= '</div>'; // end div class="login_block_other"
2155 
2156 
2157  // Add login user link
2158  $toprightmenu .= '<div class="login_block_user">';
2159 
2160  // Login name with photo and tooltip
2161  $mode = -1;
2162  $toprightmenu .= '<div class="inline-block nowrap"><div class="inline-block login_block_elem login_block_elem_name" style="padding: 0px;">';
2163 
2164  if (!empty($conf->global->MAIN_USE_TOP_MENU_SEARCH_DROPDOWN)) {
2165  // Add search dropdown
2166  $toprightmenu .= top_menu_search();
2167  }
2168 
2169  if (!empty($conf->global->MAIN_USE_TOP_MENU_QUICKADD_DROPDOWN)) {
2170  // Add search dropdown
2171  $toprightmenu .= top_menu_quickadd();
2172  }
2173 
2174  // Add bookmark dropdown
2175  $toprightmenu .= top_menu_bookmark();
2176 
2177  // Add user dropdown
2178  $toprightmenu .= top_menu_user();
2179 
2180  $toprightmenu .= '</div></div>';
2181 
2182  $toprightmenu .= '</div>'."\n";
2183 
2184 
2185  print $toprightmenu;
2186 
2187  print "</div>\n"; // end div class="login_block"
2188 
2189  print '</header>';
2190  //print '<header class="header2">&nbsp;</header>';
2191 
2192  print '<div style="clear: both;"></div>';
2193  print "<!-- End top horizontal menu -->\n\n";
2194  }
2195 
2196  if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) {
2197  print '<!-- Begin div id-container --><div id="id-container" class="id-container">';
2198  }
2199 }
2200 
2201 
2209 function top_menu_user($hideloginname = 0, $urllogout = '')
2210 {
2211  global $langs, $conf, $db, $hookmanager, $user, $mysoc;
2212  global $dolibarr_main_authentication, $dolibarr_main_demo;
2213  global $menumanager;
2214 
2215  $langs->load('companies');
2216 
2217  $userImage = $userDropDownImage = '';
2218  if (!empty($user->photo)) {
2219  $userImage = Form::showphoto('userphoto', $user, 0, 0, 0, 'photouserphoto userphoto', 'small', 0, 1);
2220  $userDropDownImage = Form::showphoto('userphoto', $user, 0, 0, 0, 'dropdown-user-image', 'small', 0, 1);
2221  } else {
2222  $nophoto = '/public/theme/common/user_anonymous.png';
2223  if ($user->gender == 'man') {
2224  $nophoto = '/public/theme/common/user_man.png';
2225  }
2226  if ($user->gender == 'woman') {
2227  $nophoto = '/public/theme/common/user_woman.png';
2228  }
2229 
2230  $userImage = '<img class="photo photouserphoto userphoto" alt="No photo" src="'.DOL_URL_ROOT.$nophoto.'">';
2231  $userDropDownImage = '<img class="photo dropdown-user-image" alt="No photo" src="'.DOL_URL_ROOT.$nophoto.'">';
2232  }
2233 
2234  $dropdownBody = '';
2235  $dropdownBody .= '<span id="topmenulogincompanyinfo-btn"><i class="fa fa-caret-right"></i> '.$langs->trans("ShowCompanyInfos").'</span>';
2236  $dropdownBody .= '<div id="topmenulogincompanyinfo" >';
2237 
2238  if ($langs->transcountry("ProfId1", $mysoc->country_code) != '-') {
2239  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId1", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_SIREN"), 1).'</span>';
2240  }
2241  if ($langs->transcountry("ProfId2", $mysoc->country_code) != '-') {
2242  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId2", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_SIRET"), 2).'</span>';
2243  }
2244  if ($langs->transcountry("ProfId3", $mysoc->country_code) != '-') {
2245  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId3", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_APE"), 3).'</span>';
2246  }
2247  if ($langs->transcountry("ProfId4", $mysoc->country_code) != '-') {
2248  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId4", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_RCS"), 4).'</span>';
2249  }
2250  if ($langs->transcountry("ProfId5", $mysoc->country_code) != '-') {
2251  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId5", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_PROFID5"), 5).'</span>';
2252  }
2253  if ($langs->transcountry("ProfId6", $mysoc->country_code) != '-') {
2254  $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId6", $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_PROFID6"), 6).'</span>';
2255  }
2256  $dropdownBody .= '<br><b>'.$langs->trans("VATIntraShort").'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_TVAINTRA"), 'VAT').'</span>';
2257  $dropdownBody .= '<br><b>'.$langs->trans("Country").'</b>: <span>'.($mysoc->country_code ? $langs->trans("Country".$mysoc->country_code) : '').'</span>';
2258 
2259  $dropdownBody .= '</div>';
2260 
2261  $dropdownBody .= '<br>';
2262  $dropdownBody .= '<span id="topmenuloginmoreinfo-btn"><i class="fa fa-caret-right"></i> '.$langs->trans("ShowMoreInfos").'</span>';
2263  $dropdownBody .= '<div id="topmenuloginmoreinfo" >';
2264 
2265  // login infos
2266  if (!empty($user->admin)) {
2267  $dropdownBody .= '<br><b>'.$langs->trans("Administrator").'</b>: '.yn($user->admin);
2268  }
2269  if (!empty($user->socid)) { // Add thirdparty for external users
2270  $thirdpartystatic = new Societe($db);
2271  $thirdpartystatic->fetch($user->socid);
2272  $companylink = ' '.$thirdpartystatic->getNomUrl(2); // picto only of company
2273  $company = ' ('.$langs->trans("Company").': '.$thirdpartystatic->name.')';
2274  }
2275  $type = ($user->socid ? $langs->trans("External").$company : $langs->trans("Internal"));
2276  $dropdownBody .= '<br><b>'.$langs->trans("Type").':</b> '.$type;
2277  $dropdownBody .= '<br><b>'.$langs->trans("Status").'</b>: '.$user->getLibStatut(0);
2278  $dropdownBody .= '<br>';
2279 
2280  $dropdownBody .= '<br><u>'.$langs->trans("Session").'</u>';
2281  $dropdownBody .= '<br><b>'.$langs->trans("IPAddress").'</b>: '.dol_escape_htmltag($_SERVER["REMOTE_ADDR"]);
2282  if (!empty($conf->global->MAIN_MODULE_MULTICOMPANY)) {
2283  $dropdownBody .= '<br><b>'.$langs->trans("ConnectedOnMultiCompany").':</b> '.$conf->entity.' (user entity '.$user->entity.')';
2284  }
2285  $dropdownBody .= '<br><b>'.$langs->trans("AuthenticationMode").':</b> '.$_SESSION["dol_authmode"].(empty($dolibarr_main_demo) ? '' : ' (demo)');
2286  $dropdownBody .= '<br><b>'.$langs->trans("ConnectedSince").':</b> '.dol_print_date($user->datelastlogin, "dayhour", 'tzuser');
2287  $dropdownBody .= '<br><b>'.$langs->trans("PreviousConnexion").':</b> '.dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser');
2288  $dropdownBody .= '<br><b>'.$langs->trans("CurrentTheme").':</b> '.$conf->theme;
2289  $dropdownBody .= '<br><b>'.$langs->trans("CurrentMenuManager").':</b> '.(isset($menumanager) ? $menumanager->name : 'unknown');
2290  $langFlag = picto_from_langcode($langs->getDefaultLang());
2291  $dropdownBody .= '<br><b>'.$langs->trans("CurrentUserLanguage").':</b> '.($langFlag ? $langFlag.' ' : '').$langs->getDefaultLang();
2292 
2293  $tz = (int) $_SESSION['dol_tz'] + (int) $_SESSION['dol_dst'];
2294  $dropdownBody .= '<br><b>'.$langs->trans("ClientTZ").':</b> '.($tz ? ($tz >= 0 ? '+' : '').$tz : '');
2295  $dropdownBody .= ' ('.$_SESSION['dol_tz_string'].')';
2296  //$dropdownBody .= ' &nbsp; &nbsp; &nbsp; '.$langs->trans("DaylingSavingTime").': ';
2297  //if ($_SESSION['dol_dst'] > 0) $dropdownBody .= yn(1);
2298  //else $dropdownBody .= yn(0);
2299 
2300  $dropdownBody .= '<br><b>'.$langs->trans("Browser").':</b> '.$conf->browser->name.($conf->browser->version ? ' '.$conf->browser->version : '').' ('.dol_escape_htmltag($_SERVER['HTTP_USER_AGENT']).')';
2301  $dropdownBody .= '<br><b>'.$langs->trans("Layout").':</b> '.$conf->browser->layout;
2302  $dropdownBody .= '<br><b>'.$langs->trans("Screen").':</b> '.$_SESSION['dol_screenwidth'].' x '.$_SESSION['dol_screenheight'];
2303  if ($conf->browser->layout == 'phone') {
2304  $dropdownBody .= '<br><b>'.$langs->trans("Phone").':</b> '.$langs->trans("Yes");
2305  }
2306  if (!empty($_SESSION["disablemodules"])) {
2307  $dropdownBody .= '<br><b>'.$langs->trans("DisabledModules").':</b> <br>'.join(', ', explode(',', $_SESSION["disablemodules"]));
2308  }
2309  $dropdownBody .= '</div>';
2310 
2311  // Execute hook
2312  $parameters = array('user'=>$user, 'langs' => $langs);
2313  $result = $hookmanager->executeHooks('printTopRightMenuLoginDropdownBody', $parameters); // Note that $action and $object may have been modified by some hooks
2314  if (is_numeric($result)) {
2315  if ($result == 0) {
2316  $dropdownBody .= $hookmanager->resPrint; // add
2317  } else {
2318  $dropdownBody = $hookmanager->resPrint; // replace
2319  }
2320  }
2321 
2322  if (empty($urllogout)) {
2323  $urllogout = DOL_URL_ROOT.'/user/logout.php?token='.newToken();
2324  }
2325  $logoutLink = '<a accesskey="l" href="'.$urllogout.'" class="button-top-menu-dropdown" ><i class="fa fa-sign-out-alt"></i> '.$langs->trans("Logout").'</a>';
2326  $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>';
2327 
2328 
2329  $profilName = $user->getFullName($langs).' ('.$user->login.')';
2330 
2331  if (!empty($user->admin)) {
2332  $profilName = '<i class="far fa-star classfortooltip" title="'.$langs->trans("Administrator").'" ></i> '.$profilName;
2333  }
2334 
2335  // Define version to show
2336  $appli = constant('DOL_APPLICATION_TITLE');
2337  if (!empty($conf->global->MAIN_APPLICATION_TITLE)) {
2338  $appli = $conf->global->MAIN_APPLICATION_TITLE;
2339  if (preg_match('/\d\.\d/', $appli)) {
2340  if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) {
2341  $appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core
2342  }
2343  } else {
2344  $appli .= " ".DOL_VERSION;
2345  }
2346  } else {
2347  $appli .= " ".DOL_VERSION;
2348  }
2349 
2350  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2351  $btnUser = '<!-- div for user link -->
2352  <div id="topmenu-login-dropdown" class="userimg atoplogin dropdown user user-menu inline-block">
2353  <a href="'.DOL_URL_ROOT.'/user/card.php?id='.$user->id.'" class="dropdown-toggle login-dropdown-a" data-toggle="dropdown">
2354  '.$userImage.(empty($user->photo) ? '<span class="hidden-xs maxwidth200 atoploginusername hideonsmartphone paddingleft">'.dol_trunc($user->firstname ? $user->firstname : $user->login, 10).'</span>' : '').'
2355  </a>
2356  <div class="dropdown-menu">
2357  <!-- User image -->
2358  <div class="user-header">
2359  '.$userDropDownImage.'
2360  <p>
2361  '.$profilName.'<br>';
2362  if ($user->datelastlogin) {
2363  $title = $langs->trans("ConnectedSince").' : '.dol_print_date($user->datelastlogin, "dayhour", 'tzuser');
2364  if ($user->datepreviouslogin) {
2365  $title .= '<br>'.$langs->trans("PreviousConnexion").' : '.dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser');
2366  }
2367  }
2368  $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>';
2369  if ($user->datepreviouslogin) {
2370  $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>';
2371  }
2372 
2373  //$btnUser .= '<small class="classfortooltip"><i class="fa fa-cog"></i> '.$langs->trans("Version").' '.$appli.'</small>';
2374  $btnUser .= '
2375  </p>
2376  </div>
2377 
2378  <!-- Menu Body -->
2379  <div class="user-body">'.$dropdownBody.'</div>
2380 
2381  <!-- Menu Footer-->
2382  <div class="user-footer">
2383  <div class="pull-left">
2384  '.$profilLink.'
2385  </div>
2386  <div class="pull-right">
2387  '.$logoutLink.'
2388  </div>
2389  <div style="clear:both;"></div>
2390  </div>
2391 
2392  </div>
2393  </div>';
2394  } else {
2395  $btnUser = '<!-- div for user link -->
2396  <div id="topmenu-login-dropdown" class="userimg atoplogin dropdown user user-menu inline-block">
2397  <a href="'.DOL_URL_ROOT.'/user/card.php?id='.$user->id.'">
2398  '.$userImage.'
2399  <span class="hidden-xs maxwidth200 atoploginusername hideonsmartphone">'.dol_trunc($user->firstname ? $user->firstname : $user->login, 10).'</span>
2400  </a>
2401  </div>';
2402  }
2403 
2404  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
2405  $btnUser .= '
2406  <!-- Code to show/hide the user drop-down -->
2407  <script>
2408  jQuery(document).ready(function() {
2409  jQuery(document).on("click", function(event) {
2410  if (!$(event.target).closest("#topmenu-login-dropdown").length) {
2411  //console.log("close login dropdown");
2412  // Hide the menus.
2413  jQuery("#topmenu-login-dropdown").removeClass("open");
2414  }
2415  });
2416  ';
2417 
2418  if ($conf->theme != 'md') {
2419  $btnUser .= '
2420  jQuery("#topmenu-login-dropdown .dropdown-toggle").on("click", function(event) {
2421  console.log("toggle login dropdown");
2422  event.preventDefault();
2423  jQuery("#topmenu-login-dropdown").toggleClass("open");
2424  });
2425 
2426  jQuery("#topmenulogincompanyinfo-btn").on("click", function() {
2427  console.log("Clik on topmenulogincompanyinfo-btn");
2428  jQuery("#topmenulogincompanyinfo").slideToggle();
2429  });
2430 
2431  jQuery("#topmenuloginmoreinfo-btn").on("click", function() {
2432  console.log("Clik on topmenuloginmoreinfo-btn");
2433  jQuery("#topmenuloginmoreinfo").slideToggle();
2434  });';
2435  }
2436 
2437  $btnUser .= '
2438  });
2439  </script>
2440  ';
2441  }
2442 
2443  return $btnUser;
2444 }
2445 
2452 {
2453  global $langs;
2454 
2455  $html = '';
2456 
2457  $html .= '<!-- div for quick add link -->
2458  <div id="topmenu-quickadd-dropdown" class="atoplogin dropdown inline-block">
2459  <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>
2460  <div class="dropdown-menu">'.printDropdownQuickadd().'</div>
2461  </div>';
2462  $html .= '
2463  <!-- Code to show/hide the user drop-down -->
2464  <script>
2465  jQuery(document).ready(function() {
2466  jQuery(document).on("click", function(event) {
2467  if (!$(event.target).closest("#topmenu-quickadd-dropdown").length) {
2468  // Hide the menus.
2469  $("#topmenu-quickadd-dropdown").removeClass("open");
2470  }
2471  });
2472  $("#topmenu-quickadd-dropdown .dropdown-toggle").on("click", function(event) {
2473  openQuickAddDropDown();
2474  });
2475  // Key map shortcut
2476  $(document).keydown(function(e){
2477  if( e.which === 76 && e.ctrlKey && e.shiftKey ){
2478  console.log(\'control + shift + l : trigger open quick add dropdown\');
2479  openQuickAddDropDown();
2480  }
2481  });
2482 
2483 
2484  var openQuickAddDropDown = function() {
2485  event.preventDefault();
2486  $("#topmenu-quickadd-dropdown").toggleClass("open");
2487  //$("#top-quickadd-search-input").focus();
2488  }
2489  });
2490  </script>
2491  ';
2492  return $html;
2493 }
2494 
2501 {
2502  global $conf, $user, $langs, $hookmanager;
2503 
2504  $items = array(
2505  'items' => array(
2506  array(
2507  "url" => "/adherents/card.php?action=create&amp;mainmenu=members",
2508  "title" => "MenuNewMember@members",
2509  "name" => "Adherent@members",
2510  "picto" => "object_member",
2511  "activation" => isModEnabled('adherent') && $user->hasRight("adherent", "write"), // vs hooking
2512  "position" => 5,
2513  ),
2514  array(
2515  "url" => "/societe/card.php?action=create&amp;mainmenu=companies",
2516  "title" => "MenuNewThirdParty@companies",
2517  "name" => "ThirdParty@companies",
2518  "picto" => "object_company",
2519  "activation" => isModEnabled("societe") && $user->hasRight("societe", "write"), // vs hooking
2520  "position" => 10,
2521  ),
2522  array(
2523  "url" => "/contact/card.php?action=create&amp;mainmenu=companies",
2524  "title" => "NewContactAddress@companies",
2525  "name" => "Contact@companies",
2526  "picto" => "object_contact",
2527  "activation" => isModEnabled("societe") && $user->hasRight("societe", "contact", "write"), // vs hooking
2528  "position" => 20,
2529  ),
2530  array(
2531  "url" => "/comm/propal/card.php?action=create&amp;mainmenu=commercial",
2532  "title" => "NewPropal@propal",
2533  "name" => "Proposal@propal",
2534  "picto" => "object_propal",
2535  "activation" => isModEnabled("propal") && $user->hasRight("propal", "write"), // vs hooking
2536  "position" => 30,
2537  ),
2538 
2539  array(
2540  "url" => "/commande/card.php?action=create&amp;mainmenu=commercial",
2541  "title" => "NewOrder@orders",
2542  "name" => "Order@orders",
2543  "picto" => "object_order",
2544  "activation" => isModEnabled('commande') && $user->hasRight("commande", "write"), // vs hooking
2545  "position" => 40,
2546  ),
2547  array(
2548  "url" => "/compta/facture/card.php?action=create&amp;mainmenu=billing",
2549  "title" => "NewBill@bills",
2550  "name" => "Bill@bills",
2551  "picto" => "object_bill",
2552  "activation" => isModEnabled('facture') && $user->hasRight("facture", "write"), // vs hooking
2553  "position" => 50,
2554  ),
2555  array(
2556  "url" => "/contrat/card.php?action=create&amp;mainmenu=commercial",
2557  "title" => "NewContractSubscription@contracts",
2558  "name" => "Contract@contracts",
2559  "picto" => "object_contract",
2560  "activation" => isModEnabled('contrat') && $user->hasRight("contrat", "write"), // vs hooking
2561  "position" => 60,
2562  ),
2563  array(
2564  "url" => "/supplier_proposal/card.php?action=create&amp;mainmenu=commercial",
2565  "title" => "SupplierProposalNew@supplier_proposal",
2566  "name" => "SupplierProposal@supplier_proposal",
2567  "picto" => "supplier_proposal",
2568  "activation" => isModEnabled('supplier_proposal') && $user->hasRight("supplier_invoice", "write"), // vs hooking
2569  "position" => 70,
2570  ),
2571  array(
2572  "url" => "/fourn/commande/card.php?action=create&amp;mainmenu=commercial",
2573  "title" => "NewSupplierOrderShort@orders",
2574  "name" => "SupplierOrder@orders",
2575  "picto" => "supplier_order",
2576  "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
2577  "position" => 80,
2578  ),
2579  array(
2580  "url" => "/fourn/facture/card.php?action=create&amp;mainmenu=billing",
2581  "title" => "NewBill@bills",
2582  "name" => "SupplierBill@bills",
2583  "picto" => "supplier_invoice",
2584  "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
2585  "position" => 90,
2586  ),
2587  array(
2588  "url" => "/ticket/card.php?action=create&amp;mainmenu=ticket",
2589  "title" => "NewTicket@ticket",
2590  "name" => "Ticket@ticket",
2591  "picto" => "ticket",
2592  "activation" => isModEnabled('ticket') && $user->hasRight("ticket", "write"), // vs hooking
2593  "position" => 100,
2594  ),
2595  array(
2596  "url" => "/fichinter/card.php?action=create&mainmenu=commercial",
2597  "title" => "NewIntervention@interventions",
2598  "name" => "Intervention@interventions",
2599  "picto" => "intervention",
2600  "activation" => isModEnabled('ficheinter') && $user->hasRight("ficheinter", "creer"), // vs hooking
2601  "position" => 110,
2602  ),
2603  array(
2604  "url" => "/product/card.php?action=create&amp;type=0&amp;mainmenu=products",
2605  "title" => "NewProduct@products",
2606  "name" => "Product@products",
2607  "picto" => "object_product",
2608  "activation" => isModEnabled("product") && $user->hasRight("produit", "write"), // vs hooking
2609  "position" => 400,
2610  ),
2611  array(
2612  "url" => "/product/card.php?action=create&amp;type=1&amp;mainmenu=products",
2613  "title" => "NewService@products",
2614  "name" => "Service@products",
2615  "picto" => "object_service",
2616  "activation" => isModEnabled("service") && $user->hasRight("service", "write"), // vs hooking
2617  "position" => 410,
2618  ),
2619  array(
2620  "url" => "/user/card.php?action=create&amp;type=1&amp;mainmenu=home",
2621  "title" => "AddUser@users",
2622  "name" => "User@users",
2623  "picto" => "user",
2624  "activation" => $user->hasRight("user", "user", "write"), // vs hooking
2625  "position" => 500,
2626  ),
2627  ),
2628  );
2629 
2630  $dropDownQuickAddHtml = '';
2631 
2632  // Define $dropDownQuickAddHtml
2633  $dropDownQuickAddHtml .= '<div class="quickadd-body dropdown-body">';
2634  $dropDownQuickAddHtml .= '<div class="dropdown-quickadd-list">';
2635 
2636  // Allow the $items of the menu to be manipulated by modules
2637  $parameters = array();
2638  $hook_items = $items;
2639  $reshook = $hookmanager->executeHooks('menuDropdownQuickaddItems', $parameters, $hook_items); // Note that $action and $object may have been modified by some hooks
2640  if (is_numeric($reshook) && !empty($hookmanager->results) && is_array($hookmanager->results)) {
2641  if ($reshook == 0) {
2642  $items['items'] = array_merge($items['items'], $hookmanager->results); // add
2643  } else {
2644  $items = $hookmanager->results; // replace
2645  }
2646 
2647  // Sort menu items by 'position' value
2648  $position = array();
2649  foreach ($items['items'] as $key => $row) {
2650  $position[$key] = $row['position'];
2651  }
2652  $array1_sort_order = SORT_ASC;
2653  array_multisort($position, $array1_sort_order, $items['items']);
2654  }
2655 
2656  foreach ($items['items'] as $item) {
2657  if (!$item['activation']) {
2658  continue;
2659  }
2660  $langs->load(explode('@', $item['title'])[1]);
2661  $langs->load(explode('@', $item['name'])[1]);
2662  $dropDownQuickAddHtml .= '
2663  <a class="dropdown-item quickadd-item" href="'.DOL_URL_ROOT.$item['url'].'" title="'.$langs->trans(explode('@', $item['title'])[0]).'">
2664  '. img_picto('', $item['picto'], 'style="width:18px;"') . ' ' . $langs->trans(explode('@', $item['name'])[0]) . '</a>
2665  ';
2666  }
2667 
2668  $dropDownQuickAddHtml .= '</div>';
2669  $dropDownQuickAddHtml .= '</div>';
2670 
2671  return $dropDownQuickAddHtml;
2672 }
2673 
2680 {
2681  global $langs, $conf, $db, $user;
2682 
2683  $html = '';
2684 
2685  // Define $bookmarks
2686  if (!isModEnabled('bookmark') || empty($user->rights->bookmark->lire)) {
2687  return $html;
2688  }
2689 
2690  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
2691  include_once DOL_DOCUMENT_ROOT.'/bookmarks/bookmarks.lib.php';
2692  $langs->load("bookmarks");
2693 
2694  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2695  $html .= '<div id="topmenu-bookmark-dropdown" class="dropdown inline-block">';
2696  $html .= printDropdownBookmarksList();
2697  $html .= '</div>';
2698  } else {
2699  $html .= '<!-- div for bookmark link -->
2700  <div id="topmenu-bookmark-dropdown" class="dropdown inline-block">
2701  <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>
2702  <div class="dropdown-menu">
2704  </div>
2705  </div>';
2706 
2707  $html .= '
2708  <!-- Code to show/hide the bookmark drop-down -->
2709  <script>
2710  jQuery(document).ready(function() {
2711  jQuery(document).on("click", function(event) {
2712  if (!$(event.target).closest("#topmenu-bookmark-dropdown").length) {
2713  //console.log("close bookmark dropdown - we click outside");
2714  // Hide the menus.
2715  $("#topmenu-bookmark-dropdown").removeClass("open");
2716  }
2717  });
2718 
2719  jQuery("#topmenu-bookmark-dropdown .dropdown-toggle").on("click", function(event) {
2720  console.log("toggle bookmark dropdown");
2721  openBookMarkDropDown();
2722  });
2723 
2724  // Key map shortcut
2725  jQuery(document).keydown(function(e){
2726  if( e.which === 77 && e.ctrlKey && e.shiftKey ){
2727  console.log(\'control + shift + m : trigger open bookmark dropdown\');
2728  openBookMarkDropDown();
2729  }
2730  });
2731 
2732 
2733  var openBookMarkDropDown = function() {
2734  event.preventDefault();
2735  jQuery("#topmenu-bookmark-dropdown").toggleClass("open");
2736  jQuery("#top-bookmark-search-input").focus();
2737  }
2738 
2739  });
2740  </script>
2741  ';
2742  }
2743  }
2744  return $html;
2745 }
2746 
2753 {
2754  global $langs, $conf, $db, $user, $hookmanager;
2755 
2756  $html = '';
2757 
2758  $usedbyinclude = 1;
2759  $arrayresult = null;
2760  include DOL_DOCUMENT_ROOT.'/core/ajax/selectsearchbox.php'; // This set $arrayresult
2761 
2762  $defaultAction = '';
2763  $buttonList = '<div class="dropdown-global-search-button-list" >';
2764  // Menu with all searchable items
2765  foreach ($arrayresult as $keyItem => $item) {
2766  if (empty($defaultAction)) {
2767  $defaultAction = $item['url'];
2768  }
2769  $buttonList .= '<button class="dropdown-item global-search-item" data-target="'.dol_escape_htmltag($item['url']).'" >';
2770  $buttonList .= $item['text'];
2771  $buttonList .= '</button>';
2772  }
2773  $buttonList .= '</div>';
2774 
2775 
2776  $searchInput = '<input name="search_all" id="top-global-search-input" class="dropdown-search-input" placeholder="'.$langs->trans('Search').'" autocomplete="off" >';
2777 
2778  $dropDownHtml = '<form id="top-menu-action-search" name="actionsearch" method="GET" action="'.$defaultAction.'" >';
2779 
2780  $dropDownHtml .= '
2781  <!-- search input -->
2782  <div class="dropdown-header search-dropdown-header">
2783  ' . $searchInput.'
2784  </div>
2785  ';
2786 
2787  $dropDownHtml .= '
2788  <!-- Menu Body -->
2789  <div class="dropdown-body search-dropdown-body">
2790  '.$buttonList.'
2791  </div>
2792  ';
2793 
2794  $dropDownHtml .= '</form>';
2795 
2796 
2797  $html .= '<!-- div for Global Search -->
2798  <div id="topmenu-global-search-dropdown" class="atoplogin dropdown inline-block">
2799  <a class="dropdown-toggle login-dropdown-a" data-toggle="dropdown" href="#" title="'.$langs->trans('Search').' ('.$langs->trans('SearchMenuShortCut').')">
2800  <i class="fa fa-search" ></i>
2801  </a>
2802  <div class="dropdown-menu dropdown-search">
2803  '.$dropDownHtml.'
2804  </div>
2805  </div>';
2806 
2807  $html .= '
2808  <!-- Code to show/hide the user drop-down -->
2809  <script>
2810  jQuery(document).ready(function() {
2811 
2812  // prevent submiting form on press ENTER
2813  jQuery("#top-global-search-input").keydown(function (e) {
2814  if (e.keyCode == 13) {
2815  var inputs = $(this).parents("form").eq(0).find(":button");
2816  if (inputs[inputs.index(this) + 1] != null) {
2817  inputs[inputs.index(this) + 1].focus();
2818  }
2819  e.preventDefault();
2820  return false;
2821  }
2822  });
2823 
2824  // arrow key nav
2825  jQuery(document).keydown(function(e) {
2826  // Get the focused element:
2827  var $focused = $(":focus");
2828  if($focused.length && $focused.hasClass("global-search-item")){
2829 
2830  // UP - move to the previous line
2831  if (e.keyCode == 38) {
2832  e.preventDefault();
2833  $focused.prev().focus();
2834  }
2835 
2836  // DOWN - move to the next line
2837  if (e.keyCode == 40) {
2838  e.preventDefault();
2839  $focused.next().focus();
2840  }
2841  }
2842  });
2843 
2844 
2845  // submit form action
2846  jQuery(".dropdown-global-search-button-list .global-search-item").on("click", function(event) {
2847  jQuery("#top-menu-action-search").attr("action", $(this).data("target"));
2848  jQuery("#top-menu-action-search").submit();
2849  });
2850 
2851  // close drop down
2852  jQuery(document).on("click", function(event) {
2853  if (!$(event.target).closest("#topmenu-global-search-dropdown").length) {
2854  console.log("click close search - we click outside");
2855  // Hide the menus.
2856  jQuery("#topmenu-global-search-dropdown").removeClass("open");
2857  }
2858  });
2859 
2860  // Open drop down
2861  jQuery("#topmenu-global-search-dropdown .dropdown-toggle").on("click", function(event) {
2862  console.log("toggle search dropdown");
2863  openGlobalSearchDropDown();
2864  });
2865 
2866  // Key map shortcut
2867  jQuery(document).keydown(function(e){
2868  if( e.which === 70 && e.ctrlKey && e.shiftKey ){
2869  console.log(\'control + shift + f : trigger open global-search dropdown\');
2870  openGlobalSearchDropDown();
2871  }
2872  });
2873 
2874 
2875  var openGlobalSearchDropDown = function() {
2876  jQuery("#topmenu-global-search-dropdown").toggleClass("open");
2877  jQuery("#top-global-search-input").focus();
2878  }
2879 
2880  });
2881  </script>
2882  ';
2883 
2884  return $html;
2885 }
2886 
2901 function left_menu($menu_array_before, $helppagename = '', $notused = '', $menu_array_after = '', $leftmenuwithoutmainarea = 0, $title = '', $acceptdelayedhtml = 0)
2902 {
2903  global $user, $conf, $langs, $db, $form;
2904  global $hookmanager, $menumanager;
2905 
2906  $searchform = '';
2907 
2908  if (!empty($menu_array_before)) {
2909  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);
2910  }
2911 
2912  if (empty($conf->dol_hide_leftmenu) && (!defined('NOREQUIREMENU') || !constant('NOREQUIREMENU'))) {
2913  // Instantiate hooks for external modules
2914  $hookmanager->initHooks(array('leftblock'));
2915 
2916  print "\n".'<!-- Begin side-nav id-left -->'."\n".'<div class="side-nav"><div id="id-left">'."\n";
2917  print "\n";
2918 
2919  if (!is_object($form)) {
2920  $form = new Form($db);
2921  }
2922  $selected = -1;
2923  if (empty($conf->global->MAIN_USE_TOP_MENU_SEARCH_DROPDOWN)) {
2924  // Select into select2 is awfull on smartphone. TODO Is this still true with select2 v4 ?
2925  if ($conf->browser->layout == 'phone') {
2926  $conf->global->MAIN_USE_OLD_SEARCH_FORM = 1;
2927  }
2928 
2929  $usedbyinclude = 1;
2930  $arrayresult = null;
2931  include DOL_DOCUMENT_ROOT.'/core/ajax/selectsearchbox.php'; // This make initHooks('searchform') then set $arrayresult
2932 
2933  if ($conf->use_javascript_ajax && empty($conf->global->MAIN_USE_OLD_SEARCH_FORM)) {
2934  $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);
2935  } else {
2936  if (is_array($arrayresult)) {
2937  foreach ($arrayresult as $key => $val) {
2938  $searchform .= printSearchForm($val['url'], $val['url'], $val['label'], 'maxwidth125', 'sall', (empty($val['shortcut']) ? '' : $val['shortcut']), 'searchleft'.$key, $val['img']);
2939  }
2940  }
2941  }
2942 
2943  // Execute hook printSearchForm
2944  $parameters = array('searchform' => $searchform);
2945  $reshook = $hookmanager->executeHooks('printSearchForm', $parameters); // Note that $action and $object may have been modified by some hooks
2946  if (empty($reshook)) {
2947  $searchform .= $hookmanager->resPrint;
2948  } else {
2949  $searchform = $hookmanager->resPrint;
2950  }
2951 
2952  // Force special value for $searchform
2953  if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) || empty($conf->use_javascript_ajax)) {
2954  $urltosearch = DOL_URL_ROOT.'/core/search_page.php?showtitlebefore=1';
2955  $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>';
2956  } elseif ($conf->use_javascript_ajax && !empty($conf->global->MAIN_USE_OLD_SEARCH_FORM)) {
2957  $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>';
2958  $searchform .= '<script>
2959  jQuery(document).ready(function () {
2960  jQuery("#divsearchforms1").click(function(){
2961  jQuery("#divsearchforms2").toggle();
2962  });
2963  });
2964  </script>' . "\n";
2965  $searchform .= '</div>';
2966  }
2967  }
2968 
2969  // Left column
2970  print '<!-- Begin left menu -->'."\n";
2971 
2972  print '<div class="vmenu"'.(empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) ? '' : ' title="Left menu"').'>'."\n\n";
2973 
2974  // Show left menu with other forms
2975  $menumanager->menu_array = $menu_array_before;
2976  $menumanager->menu_array_after = $menu_array_after;
2977  $menumanager->showmenu('left', array('searchform'=>$searchform)); // output menu_array and menu found in database
2978 
2979  // Dolibarr version + help + bug report link
2980  print "\n";
2981  print "<!-- Begin Help Block-->\n";
2982  print '<div id="blockvmenuhelp" class="blockvmenuhelp">'."\n";
2983 
2984  // Version
2985  if (!empty($conf->global->MAIN_SHOW_VERSION)) { // Version is already on help picto and on login page.
2986  $doliurl = 'https://www.dolibarr.org';
2987  //local communities
2988  if (preg_match('/fr/i', $langs->defaultlang)) {
2989  $doliurl = 'https://www.dolibarr.fr';
2990  }
2991  if (preg_match('/es/i', $langs->defaultlang)) {
2992  $doliurl = 'https://www.dolibarr.es';
2993  }
2994  if (preg_match('/de/i', $langs->defaultlang)) {
2995  $doliurl = 'https://www.dolibarr.de';
2996  }
2997  if (preg_match('/it/i', $langs->defaultlang)) {
2998  $doliurl = 'https://www.dolibarr.it';
2999  }
3000  if (preg_match('/gr/i', $langs->defaultlang)) {
3001  $doliurl = 'https://www.dolibarr.gr';
3002  }
3003 
3004  $appli = constant('DOL_APPLICATION_TITLE');
3005  if (!empty($conf->global->MAIN_APPLICATION_TITLE)) {
3006  $appli = $conf->global->MAIN_APPLICATION_TITLE; $doliurl = '';
3007  if (preg_match('/\d\.\d/', $appli)) {
3008  if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) {
3009  $appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core
3010  }
3011  } else {
3012  $appli .= " ".DOL_VERSION;
3013  }
3014  } else {
3015  $appli .= " ".DOL_VERSION;
3016  }
3017  print '<div id="blockvmenuhelpapp" class="blockvmenuhelp">';
3018  if ($doliurl) {
3019  print '<a class="help" target="_blank" rel="noopener noreferrer" href="'.$doliurl.'">';
3020  } else {
3021  print '<span class="help">';
3022  }
3023  print $appli;
3024  if ($doliurl) {
3025  print '</a>';
3026  } else {
3027  print '</span>';
3028  }
3029  print '</div>'."\n";
3030  }
3031 
3032  // Link to bugtrack
3033  if (!empty($conf->global->MAIN_BUGTRACK_ENABLELINK)) {
3034  require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
3035 
3036  if ($conf->global->MAIN_BUGTRACK_ENABLELINK == 'github') {
3037  $bugbaseurl = 'https://github.com/Dolibarr/dolibarr/issues/new?labels=Bug';
3038  $bugbaseurl .= '&title=';
3039  $bugbaseurl .= urlencode("Bug: ");
3040  $bugbaseurl .= '&body=';
3041  $bugbaseurl .= urlencode("# Instructions\n");
3042  $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");
3043  $bugbaseurl .= urlencode("*Please:*\n");
3044  $bugbaseurl .= urlencode("- *replace the bracket enclosed texts with meaningful information*\n");
3045  $bugbaseurl .= urlencode("- *remove any unused sub-section*\n");
3046  $bugbaseurl .= urlencode("\n");
3047  $bugbaseurl .= urlencode("\n");
3048  $bugbaseurl .= urlencode("# Bug\n");
3049  $bugbaseurl .= urlencode("[*Short description*]\n");
3050  $bugbaseurl .= urlencode("\n");
3051  $bugbaseurl .= urlencode("## Environment\n");
3052  $bugbaseurl .= urlencode("- **Version**: ".DOL_VERSION."\n");
3053  $bugbaseurl .= urlencode("- **OS**: ".php_uname('s')."\n");
3054  $bugbaseurl .= urlencode("- **Web server**: ".$_SERVER["SERVER_SOFTWARE"]."\n");
3055  $bugbaseurl .= urlencode("- **PHP**: ".php_sapi_name().' '.phpversion()."\n");
3056  $bugbaseurl .= urlencode("- **Database**: ".$db::LABEL.' '.$db->getVersion()."\n");
3057  $bugbaseurl .= urlencode("- **URL(s)**: ".$_SERVER["REQUEST_URI"]."\n");
3058  $bugbaseurl .= urlencode("\n");
3059  $bugbaseurl .= urlencode("## Expected and actual behavior\n");
3060  $bugbaseurl .= urlencode("[*Verbose description*]\n");
3061  $bugbaseurl .= urlencode("\n");
3062  $bugbaseurl .= urlencode("## Steps to reproduce the behavior\n");
3063  $bugbaseurl .= urlencode("[*Verbose description*]\n");
3064  $bugbaseurl .= urlencode("\n");
3065  $bugbaseurl .= urlencode("## [Attached files](https://help.github.com/articles/issue-attachments) (Screenshots, screencasts, dolibarr.log, debugging informations…)\n");
3066  $bugbaseurl .= urlencode("[*Files*]\n");
3067  $bugbaseurl .= urlencode("\n");
3068 
3069  $bugbaseurl .= urlencode("\n");
3070  $bugbaseurl .= urlencode("## Report\n");
3071  } elseif (!empty($conf->global->MAIN_BUGTRACK_ENABLELINK)) {
3072  $bugbaseurl = $conf->global->MAIN_BUGTRACK_ENABLELINK;
3073  } else {
3074  $bugbaseurl = "";
3075  }
3076 
3077  // Execute hook printBugtrackInfo
3078  $parameters = array('bugbaseurl' => $bugbaseurl);
3079  $reshook = $hookmanager->executeHooks('printBugtrackInfo', $parameters); // Note that $action and $object may have been modified by some hooks
3080  if (empty($reshook)) {
3081  $bugbaseurl .= $hookmanager->resPrint;
3082  } else {
3083  $bugbaseurl = $hookmanager->resPrint;
3084  }
3085 
3086  print '<div id="blockvmenuhelpbugreport" class="blockvmenuhelp">';
3087  print '<a class="help" target="_blank" rel="noopener noreferrer" href="'.$bugbaseurl.'"><i class="fas fa-bug"></i> '.$langs->trans("FindBug").'</a>';
3088  print '</div>';
3089  }
3090 
3091  print "</div>\n";
3092  print "<!-- End Help Block-->\n";
3093  print "\n";
3094 
3095  print "</div>\n";
3096  print "<!-- End left menu -->\n";
3097  print "\n";
3098 
3099  // Execute hook printLeftBlock
3100  $parameters = array();
3101  $reshook = $hookmanager->executeHooks('printLeftBlock', $parameters); // Note that $action and $object may have been modified by some hooks
3102  print $hookmanager->resPrint;
3103 
3104  print '</div></div> <!-- End side-nav id-left -->'; // End div id="side-nav" div id="id-left"
3105  }
3106 
3107  print "\n";
3108  print '<!-- Begin right area -->'."\n";
3109 
3110  if (empty($leftmenuwithoutmainarea)) {
3111  main_area($title);
3112  }
3113 }
3114 
3115 
3122 function main_area($title = '')
3123 {
3124  global $conf, $langs, $hookmanager;
3125 
3126  if (empty($conf->dol_hide_leftmenu)) {
3127  print '<div id="id-right">';
3128  }
3129 
3130  print "\n";
3131 
3132  print '<!-- Begin div class="fiche" -->'."\n".'<div class="fiche">'."\n";
3133 
3134  $hookmanager->initHooks(array('main'));
3135  $parameters = array();
3136  $reshook = $hookmanager->executeHooks('printMainArea', $parameters); // Note that $action and $object may have been modified by some hooks
3137  print $hookmanager->resPrint;
3138 
3139  if (!empty($conf->global->MAIN_ONLY_LOGIN_ALLOWED)) {
3140  print info_admin($langs->trans("WarningYouAreInMaintenanceMode", $conf->global->MAIN_ONLY_LOGIN_ALLOWED), 0, 0, 1, 'warning maintenancemode');
3141  }
3142 
3143  // Permit to add user company information on each printed document by setting SHOW_SOCINFO_ON_PRINT
3144  if (!empty($conf->global->SHOW_SOCINFO_ON_PRINT) && GETPOST('optioncss', 'aZ09') == 'print' && empty(GETPOST('disable_show_socinfo_on_print', 'az09'))) {
3145  $parameters = array();
3146  $reshook = $hookmanager->executeHooks('showSocinfoOnPrint', $parameters);
3147  if (empty($reshook)) {
3148  print '<!-- Begin show mysoc info header -->'."\n";
3149  print '<div id="mysoc-info-header">'."\n";
3150  print '<table class="centpercent div-table-responsive">'."\n";
3151  print '<tbody>';
3152  print '<tr><td rowspan="0" class="width20p">';
3153  if ($conf->global->MAIN_SHOW_LOGO && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && !empty($conf->global->MAIN_INFO_SOCIETE_LOGO)) {
3154  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)).'">';
3155  }
3156  print '</td><td rowspan="0" class="width50p"></td></tr>'."\n";
3157  print '<tr><td class="titre bold">'.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_NOM).'</td></tr>'."\n";
3158  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";
3159  if (!empty($conf->global->MAIN_INFO_SOCIETE_TEL)) {
3160  print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Phone").' : '.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_TEL).'</td></tr>';
3161  }
3162  if (!empty($conf->global->MAIN_INFO_SOCIETE_MAIL)) {
3163  print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Email").' : '.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_MAIL).'</td></tr>';
3164  }
3165  if (!empty($conf->global->MAIN_INFO_SOCIETE_WEB)) {
3166  print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Web").' : '.dol_escape_htmltag($conf->global->MAIN_INFO_SOCIETE_WEB).'</td></tr>';
3167  }
3168  print '</tbody>';
3169  print '</table>'."\n";
3170  print '</div>'."\n";
3171  print '<!-- End show mysoc info header -->'."\n";
3172  }
3173  }
3174 }
3175 
3176 
3184 function getHelpParamFor($helppagename, $langs)
3185 {
3186  $helpbaseurl = '';
3187  $helppage = '';
3188  $mode = '';
3189 
3190  if (preg_match('/^http/i', $helppagename)) {
3191  // If complete URL
3192  $helpbaseurl = '%s';
3193  $helppage = $helppagename;
3194  $mode = 'local';
3195  } else {
3196  // If WIKI URL
3197  $reg = array();
3198  if (preg_match('/^es/i', $langs->defaultlang)) {
3199  $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3200  if (preg_match('/ES:([^|]+)/i', $helppagename, $reg)) {
3201  $helppage = $reg[1];
3202  }
3203  }
3204  if (preg_match('/^fr/i', $langs->defaultlang)) {
3205  $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3206  if (preg_match('/FR:([^|]+)/i', $helppagename, $reg)) {
3207  $helppage = $reg[1];
3208  }
3209  }
3210  if (empty($helppage)) { // If help page not already found
3211  $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3212  if (preg_match('/EN:([^|]+)/i', $helppagename, $reg)) {
3213  $helppage = $reg[1];
3214  }
3215  }
3216  $mode = 'wiki';
3217  }
3218  return array('helpbaseurl'=>$helpbaseurl, 'helppage'=>$helppage, 'mode'=>$mode);
3219 }
3220 
3221 
3238 function printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey = '', $prefhtmlinputname = '', $img = '', $showtitlebefore = 0, $autofocus = 0)
3239 {
3240  global $conf, $langs, $user;
3241 
3242  $ret = '';
3243  $ret .= '<form action="'.$urlaction.'" method="post" class="searchform nowraponall tagtr">';
3244  $ret .= '<input type="hidden" name="token" value="'.newToken().'">';
3245  $ret .= '<input type="hidden" name="mode" value="search">';
3246  $ret .= '<input type="hidden" name="savelogin" value="'.dol_escape_htmltag($user->login).'">';
3247  if ($showtitlebefore) {
3248  $ret .= '<div class="tagtd left">'.$title.'</div> ';
3249  }
3250  $ret .= '<div class="tagtd">';
3251  $ret .= img_picto('', $img, '', false, 0, 0, '', 'paddingright width20');
3252  $ret .= '<input type="text" class="flat '.$htmlmorecss.'"';
3253  $ret .= ' style="background-repeat: no-repeat; background-position: 3px;"';
3254  $ret .= ($accesskey ? ' accesskey="'.$accesskey.'"' : '');
3255  $ret .= ' placeholder="'.strip_tags($title).'"';
3256  $ret .= ($autofocus ? ' autofocus' : '');
3257  $ret .= ' name="'.$htmlinputname.'" id="'.$prefhtmlinputname.$htmlinputname.'" />';
3258  $ret .= '<button type="submit" class="button bordertransp" style="padding-top: 4px; padding-bottom: 4px; padding-left: 6px; padding-right: 6px">';
3259  $ret .= '<span class="fa fa-search"></span>';
3260  $ret .= '</button>';
3261  $ret .= '</div>';
3262  $ret .= "</form>\n";
3263  return $ret;
3264 }
3265 
3266 
3267 if (!function_exists("llxFooter")) {
3278  function llxFooter($comment = '', $zone = 'private', $disabledoutputofmessages = 0)
3279  {
3280  global $conf, $db, $langs, $user, $mysoc, $object, $hookmanager;
3281  global $delayedhtmlcontent;
3282  global $contextpage, $page, $limit, $mode;
3283  global $dolibarr_distrib;
3284 
3285  $ext = 'layout='.$conf->browser->layout.'&version='.urlencode(DOL_VERSION);
3286 
3287  // Global html output events ($mesgs, $errors, $warnings)
3288  dol_htmloutput_events($disabledoutputofmessages);
3289 
3290  // Code for search criteria persistence.
3291  // $user->lastsearch_values was set by the GETPOST when form field search_xxx exists
3292  if (is_object($user) && !empty($user->lastsearch_values_tmp) && is_array($user->lastsearch_values_tmp)) {
3293  // Clean and save data
3294  foreach ($user->lastsearch_values_tmp as $key => $val) {
3295  unset($_SESSION['lastsearch_values_tmp_'.$key]); // Clean array to rebuild it just after
3296  if (count($val) && empty($_POST['button_removefilter']) && empty($_POST['button_removefilter_x'])) {
3297  if (empty($val['sortfield'])) {
3298  unset($val['sortfield']);
3299  }
3300  if (empty($val['sortorder'])) {
3301  unset($val['sortorder']);
3302  }
3303  dol_syslog('Save lastsearch_values_tmp_'.$key.'='.json_encode($val, 0)." (systematic recording of last search criterias)");
3304  $_SESSION['lastsearch_values_tmp_'.$key] = json_encode($val);
3305  unset($_SESSION['lastsearch_values_'.$key]);
3306  }
3307  }
3308  }
3309 
3310 
3311  $relativepathstring = $_SERVER["PHP_SELF"];
3312  // Clean $relativepathstring
3313  if (constant('DOL_URL_ROOT')) {
3314  $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
3315  }
3316  $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
3317  $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
3318  if (preg_match('/list\.php$/', $relativepathstring)) {
3319  unset($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]);
3320  unset($_SESSION['lastsearch_page_tmp_'.$relativepathstring]);
3321  unset($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]);
3322  unset($_SESSION['lastsearch_mode_tmp_'.$relativepathstring]);
3323 
3324  if (!empty($contextpage)) {
3325  $_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring] = $contextpage;
3326  }
3327  if (!empty($page) && $page > 0) {
3328  $_SESSION['lastsearch_page_tmp_'.$relativepathstring] = $page;
3329  }
3330  if (!empty($limit) && $limit != $conf->liste_limit) {
3331  $_SESSION['lastsearch_limit_tmp_'.$relativepathstring] = $limit;
3332  }
3333  if (!empty($mode)) {
3334  $_SESSION['lastsearch_mode_tmp_'.$relativepathstring] = $mode;
3335  }
3336 
3337  unset($_SESSION['lastsearch_contextpage_'.$relativepathstring]);
3338  unset($_SESSION['lastsearch_page_'.$relativepathstring]);
3339  unset($_SESSION['lastsearch_limit_'.$relativepathstring]);
3340  unset($_SESSION['lastsearch_mode_'.$relativepathstring]);
3341  }
3342 
3343  // Core error message
3344  if (!empty($conf->global->MAIN_CORE_ERROR)) {
3345  // Ajax version
3346  if ($conf->use_javascript_ajax) {
3347  $title = img_warning().' '.$langs->trans('CoreErrorTitle');
3348  print ajax_dialog($title, $langs->trans('CoreErrorMessage'));
3349  } else {
3350  // html version
3351  $msg = img_warning().' '.$langs->trans('CoreErrorMessage');
3352  print '<div class="error">'.$msg.'</div>';
3353  }
3354 
3355  //define("MAIN_CORE_ERROR",0); // Constant was defined and we can't change value of a constant
3356  }
3357 
3358  print "\n\n";
3359 
3360  print '</div> <!-- End div class="fiche" -->'."\n"; // End div fiche
3361 
3362  if (empty($conf->dol_hide_leftmenu)) {
3363  print '</div> <!-- End div id-right -->'."\n"; // End div id-right
3364  }
3365 
3366  if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) {
3367  print '</div> <!-- End div id-container -->'."\n"; // End div container
3368  }
3369 
3370  print "\n";
3371  if ($comment) {
3372  print '<!-- '.$comment.' -->'."\n";
3373  }
3374 
3375  printCommonFooter($zone);
3376 
3377  if (!empty($delayedhtmlcontent)) {
3378  print $delayedhtmlcontent;
3379  }
3380 
3381  if (!empty($conf->use_javascript_ajax)) {
3382  print "\n".'<!-- Includes JS Footer of Dolibarr -->'."\n";
3383  print '<script src="'.DOL_URL_ROOT.'/core/js/lib_foot.js.php?lang='.$langs->defaultlang.($ext ? '&'.$ext : '').'"></script>'."\n";
3384  }
3385 
3386  // Wrapper to add log when clicking on download or preview
3387  if (isModEnabled('blockedlog') && is_object($object) && !empty($object->id) && $object->id > 0 && $object->statut > 0) {
3388  if (in_array($object->element, array('facture'))) { // Restrict for the moment to element 'facture'
3389  print "\n<!-- JS CODE TO ENABLE log when making a download or a preview of a document -->\n";
3390  ?>
3391  <script>
3392  jQuery(document).ready(function () {
3393  $('a.documentpreview').click(function() {
3394  $.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
3395  , {
3396  id:<?php echo $object->id; ?>
3397  , element:'<?php echo $object->element ?>'
3398  , action:'DOC_PREVIEW'
3399  , token: '<?php echo currentToken(); ?>'
3400  }
3401  );
3402  });
3403  $('a.documentdownload').click(function() {
3404  $.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
3405  , {
3406  id:<?php echo $object->id; ?>
3407  , element:'<?php echo $object->element ?>'
3408  , action:'DOC_DOWNLOAD'
3409  , token: '<?php echo currentToken(); ?>'
3410  }
3411  );
3412  });
3413  });
3414  </script>
3415  <?php
3416  }
3417  }
3418 
3419  // A div for the address popup
3420  print "\n<!-- A div to allow dialog popup by jQuery('#dialogforpopup').dialog() -->\n";
3421  print '<div id="dialogforpopup" style="display: none;"></div>'."\n";
3422 
3423  // Add code for the asynchronous anonymous first ping (for telemetry)
3424  // You can use &forceping=1 in parameters to force the ping if the ping was already sent.
3425  $forceping = GETPOST('forceping', 'alpha');
3426  if (($_SERVER["PHP_SELF"] == DOL_URL_ROOT.'/index.php') || $forceping) {
3427  //print '<!-- instance_unique_id='.$conf->file->instance_unique_id.' MAIN_FIRST_PING_OK_ID='.$conf->global->MAIN_FIRST_PING_OK_ID.' -->';
3428  $hash_unique_id = md5('dolibarr'.$conf->file->instance_unique_id); // Do not use dol_hash(), must not change if salt changes.
3429 
3430  if (empty($conf->global->MAIN_FIRST_PING_OK_DATE)
3431  || (!empty($conf->file->instance_unique_id) && ($hash_unique_id != $conf->global->MAIN_FIRST_PING_OK_ID) && ($conf->global->MAIN_FIRST_PING_OK_ID != 'disabled'))
3432  || $forceping) {
3433  // No ping done if we are into an alpha version
3434  if (strpos('alpha', DOL_VERSION) > 0 && !$forceping) {
3435  print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. It is an alpha version -->\n";
3436  } elseif (empty($_COOKIE['DOLINSTALLNOPING_'.$hash_unique_id]) || $forceping) { // Cookie is set when we uncheck the checkbox in the installation wizard.
3437  // MAIN_LAST_PING_KO_DATE
3438  // Disable ping if MAIN_LAST_PING_KO_DATE is set and is recent (this month)
3439  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) {
3440  print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. An error already occured this month, we will try later. -->\n";
3441  } else {
3442  include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
3443 
3444  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";
3445  print "\n<!-- JS CODE TO ENABLE the anonymous Ping -->\n";
3446  $url_for_ping = (empty($conf->global->MAIN_URL_FOR_PING) ? "https://ping.dolibarr.org/" : $conf->global->MAIN_URL_FOR_PING);
3447  // Try to guess the distrib used
3448  $distrib = 'standard';
3449  if ($_SERVER["SERVER_ADMIN"] == 'doliwamp@localhost') {
3450  $distrib = 'doliwamp';
3451  }
3452  if (!empty($dolibarr_distrib)) {
3453  $distrib = $dolibarr_distrib;
3454  }
3455  ?>
3456  <script>
3457  jQuery(document).ready(function (tmp) {
3458  console.log("Try Ping with hash_unique_id is md5('dolibarr'+instance_unique_id)");
3459  $.ajax({
3460  method: "POST",
3461  url: "<?php echo $url_for_ping ?>",
3462  timeout: 500, // timeout milliseconds
3463  cache: false,
3464  data: {
3465  hash_algo: 'md5',
3466  hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>',
3467  action: 'dolibarrping',
3468  version: '<?php echo (float) DOL_VERSION; ?>',
3469  entity: '<?php echo (int) $conf->entity; ?>',
3470  dbtype: '<?php echo dol_escape_js($db->type); ?>',
3471  country_code: '<?php echo $mysoc->country_code ? dol_escape_js($mysoc->country_code) : 'unknown'; ?>',
3472  php_version: '<?php echo dol_escape_js(phpversion()); ?>',
3473  os_version: '<?php echo dol_escape_js(version_os('smr')); ?>',
3474  distrib: '<?php echo $distrib ? dol_escape_js($distrib) : 'unknown'; ?>',
3475  token: 'notrequired'
3476  },
3477  success: function (data, status, xhr) { // success callback function (data contains body of response)
3478  console.log("Ping ok");
3479  $.ajax({
3480  method: 'GET',
3481  url: '<?php echo DOL_URL_ROOT.'/core/ajax/pingresult.php'; ?>',
3482  timeout: 500, // timeout milliseconds
3483  cache: false,
3484  data: { hash_algo: 'md5', hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>', action: 'firstpingok', token: '<?php echo currentToken(); ?>' }, // for update
3485  });
3486  },
3487  error: function (data,status,xhr) { // error callback function
3488  console.log("Ping ko: " + data);
3489  $.ajax({
3490  method: 'GET',
3491  url: '<?php echo DOL_URL_ROOT.'/core/ajax/pingresult.php'; ?>',
3492  timeout: 500, // timeout milliseconds
3493  cache: false,
3494  data: { hash_algo: 'md5', hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>', action: 'firstpingko', token: '<?php echo currentToken(); ?>' },
3495  });
3496  }
3497  });
3498  });
3499  </script>
3500  <?php
3501  }
3502  } else {
3503  $now = dol_now();
3504  print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. It was disabled -->\n";
3505  include_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
3506  dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_DATE', dol_print_date($now, 'dayhourlog', 'gmt'), 'chaine', 0, '', $conf->entity);
3507  dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_ID', 'disabled', 'chaine', 0, '', $conf->entity);
3508  }
3509  }
3510  }
3511 
3512  $reshook = $hookmanager->executeHooks('beforeBodyClose'); // Note that $action and $object may have been modified by some hooks
3513  if ($reshook > 0) {
3514  print $hookmanager->resPrint;
3515  }
3516 
3517  print "</body>\n";
3518  print "</html>\n";
3519  }
3520 }
analyseVarsForSqlAndScriptsInjection
analyseVarsForSqlAndScriptsInjection(&$var, $type)
Return true if security check on parameters are OK, false otherwise.
Definition: main.inc.php:214
Societe
Class to manage third parties objects (customers, suppliers, prospects...)
Definition: societe.class.php:49
yn
yn($yesno, $case=1, $color=0)
Return yes or no in current language.
Definition: functions.lib.php:6677
dol_escape_htmltag
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields.
Definition: functions.lib.php:1493
MenuManager
Class to manage menu Auguria.
Definition: auguria_menu.php:29
dol_trunc
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
Definition: functions.lib.php:3949
realCharForNumericEntities
if(!empty($_SERVER['MAIN_SHOW_TUNING_INFO'])) realCharForNumericEntities($matches)
Return the real char for a numeric entities.
Definition: main.inc.php:61
dol_htmloutput_events
dol_htmloutput_events($disabledoutputofmessages=0)
Print formated messages to output (Used to show messages on html output).
Definition: functions.lib.php:8500
llxFooter
llxFooter()
Empty footer.
Definition: wrapper.php:70
left_menu
left_menu($menu_array_before, $helppagename='', $notused='', $menu_array_after='', $leftmenuwithoutmainarea=0, $title='', $acceptdelayedhtml=0)
Show left menu bar.
Definition: main.inc.php:2901
versioncompare
versioncompare($versionarray1, $versionarray2)
Compare 2 versions (stored into 2 arrays).
Definition: admin.lib.php:66
top_menu_bookmark
top_menu_bookmark()
Build the tooltip on top menu bookmark.
Definition: main.inc.php:2679
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:520
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:4993
top_menu
top_menu($head, $title='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $helppagename='')
Show an HTML header + a BODY + The top menu bar.
Definition: main.inc.php:1974
dol_include_once
if(!function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
Definition: functions.lib.php:1032
Translate
Class to manage translations.
Definition: translate.class.php:30
dol_buildpath
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
Definition: functions.lib.php:1061
top_menu_user
top_menu_user($hideloginname=0, $urllogout='')
Build the tooltip on user login.
Definition: main.inc.php:2209
img_warning
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
Definition: functions.lib.php:4670
top_htmlhead
top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $disableforlogin=0, $disablenofollow=0, $disablenoindex=0)
Ouput html header of a page.
Definition: main.inc.php:1571
picto_from_langcode
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
Definition: functions.lib.php:9093
$form
if($cancel &&! $id) if($action=='add' &&! $cancel) if($action=='delete') if($id) $form
Actions.
Definition: card.php:143
top_httphead
if(!defined('NOREQUIREMENU')) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
Definition: main.inc.php:1440
printCommonFooter
printCommonFooter($zone='private')
Print common footer : conf->global->MAIN_HTML_FOOTER js for switch of menu hider js for conf->global-...
Definition: functions.lib.php:9526
$help_url
if(GETPOST('button_removefilter_x', 'alpha')||GETPOST('button_removefilter.x', 'alpha')||GETPOST('button_removefilter', 'alpha')) if(GETPOST('button_search_x', 'alpha')||GETPOST('button_search.x', 'alpha')||GETPOST('button_search', 'alpha')) if($action=="save" &&empty($cancel)) $help_url
View.
Definition: agenda.php:118
dol_print_date
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs='', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
Definition: functions.lib.php:2550
dol_print_profids
dol_print_profids($profID, $profIDtype, $countrycode='', $addcpButton=1, $separ='&nbsp;')
Format profIDs according to country.
Definition: functions.lib.php:3255
img_picto
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2)
Show picto whatever it's its name (generic function)
Definition: functions.lib.php:4024
llxHeader
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:56
dol_hash
dol_hash($chain, $type='0')
Returns a hash (non reversible encryption) of a string.
Definition: security.lib.php:215
printSearchForm
printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey='', $prefhtmlinputname='', $img='', $showtitlebefore=0, $autofocus=0)
Show a search area.
Definition: main.inc.php:3238
getHelpParamFor
getHelpParamFor($helppagename, $langs)
Return helpbaseurl, helppage and mode.
Definition: main.inc.php:3184
getBrowserInfo
getBrowserInfo($user_agent)
Return information about user browser.
Definition: functions.lib.php:292
ajax_dialog
ajax_dialog($title, $message, $w=350, $h=150)
Show an ajax dialog.
Definition: ajax.lib.php:404
checkLoginPassEntity
checkLoginPassEntity($usertotest, $passwordtotest, $entitytotest, $authmode, $context='')
Return a login if login/pass was successfull.
Definition: security2.lib.php:57
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1628
getDolGlobalString
if(!function_exists('utf8_encode')) if(!function_exists('utf8_decode')) getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
Definition: functions.lib.php:82
info_admin
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='')
Show information for admin users or standard users.
Definition: functions.lib.php:4949
main_area
main_area($title='')
Begin main area.
Definition: main.inc.php:3122
newToken
newToken()
Return the value of token currently saved into session with name 'newtoken'.
Definition: functions.lib.php:11290
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:137
dolibarr_set_const
dolibarr_set_const($db, $name, $value, $type='chaine', $visible=0, $note='', $entity=1)
Insert a parameter (key,value) into database (delete old key then insert it again).
Definition: admin.lib.php:632
GETPOSTISSET
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
Definition: functions.lib.php:421
Form
Class to manage generation of HTML components Only common components must be here.
Definition: html.form.class.php:53
testSqlAndScriptInject
testSqlAndScriptInject($val, $type)
Security: WAF layer for SQL Injection and XSS Injection (scripts) protection (Filters on GET,...
Definition: main.inc.php:87
printDropdownBookmarksList
printDropdownBookmarksList()
Add area with bookmarks in top menu.
Definition: bookmarks.lib.php:30
DolibarrDebugBar
DolibarrDebugBar class.
Definition: DebugBar.php:25
isHTTPS
isHTTPS()
Return if we are using a HTTPS connexion Check HTTPS (no way to be modified by user but may be empty ...
Definition: functions.lib.php:3658
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:2951
printDropdownQuickadd
printDropdownQuickadd()
Generate list of quickadd items.
Definition: main.inc.php:2500
Form\showphoto
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0)
Return HTML code to output a photo.
Definition: html.form.class.php:9419
setEventMessages
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
Definition: functions.lib.php:8465
accessforbidden
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.
Definition: security.lib.php:1120
getDolGlobalInt
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
Definition: functions.lib.php:96
top_menu_search
top_menu_search()
Build the tooltip on top menu tsearch.
Definition: main.inc.php:2752
dol_stringtotime
dol_stringtotime($string, $gm=1)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition: date.lib.php:407
HookManager
Class to manage hooks.
Definition: hookmanager.class.php:30
top_menu_quickadd
top_menu_quickadd()
Build the tooltip on top menu quick add.
Definition: main.inc.php:2451
dol_htmlentities
dol_htmlentities($string, $flags=ENT_QUOTES|ENT_SUBSTITUTE, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
Definition: functions.lib.php:7365
float
div float
Buy price without taxes.
Definition: style.css.php:913
if
if(!defined( 'CSRFCHECK_WITH_TOKEN'))
Definition: journals_list.php:25