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