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