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