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 if (!is_string($usertotest)) {
651 // An array-shaped username (ex: ?username[]=x) is not sanitized by GETPOST('alpha')
652 // (sanitizeVal only processes scalars for this check) and would otherwise flow unchanged into
653 // checkLoginPassEntity() -> User::fetch(), crashing on trim() with a TypeError (see user.class.php).
654 $usertotest = '';
655 }
656 $passwordtotest = GETPOST('password', 'password', $allowedmethodtopostusername);
657 $entitytotest = (GETPOSTINT('entity') ? GETPOSTINT('entity') : (!empty($conf->entity) ? $conf->entity : 1));
658
659 // Define if we received the correct data to go into the test of the login with the checkLoginPassEntity().
660 $goontestloop = false;
661 if (isset($_SERVER["REMOTE_USER"]) && in_array('http', $authmode)) { // For http basic login test
662 $goontestloop = true;
663 }
664 if ($dolibarr_main_authentication == 'forceuser' && !empty($dolibarr_auto_user)) { // For automatic login with a forced user
665 $goontestloop = true;
666 }
667 if (GETPOST("username", "alpha", $allowedmethodtopostusername)) { // For posting the login form
668 $goontestloop = true;
669 }
670 if (GETPOST('openid_mode', 'alpha')) { // For openid_connect ?
671 $goontestloop = true;
672 }
673 if (GETPOST('beforeoauthloginredirect') || GETPOST('afteroauthloginreturn')) { // For oauth login
674 $goontestloop = true;
675 }
676 if (!empty($_COOKIE['login_dolibarr'])) { // TODO For ? Remove this ?
677 $goontestloop = true;
678 }
679
680 if (!is_object($langs)) { // This can occurs when calling page with NOREQUIRETRAN defined, however we need langs for error messages.
681 include_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
682 $langs = new Translate("", $conf);
683 $langcode = (GETPOST('lang', 'aZ09', 1) ? GETPOST('lang', 'aZ09', 1) : getDolGlobalString('MAIN_LANG_DEFAULT', 'auto'));
684 if (defined('MAIN_LANG_DEFAULT')) {
685 $langcode = constant('MAIN_LANG_DEFAULT');
686 }
687 $langs->setDefaultLang($langcode);
688 }
689
690 // Test HTTP header
691 if (!empty($_SERVER['HTTP_EXPOSED_CREDENTIAL_CHECK'])) {
692 // TODO Read option $dolibarr_main_no_leaked_credentials with value 1, 2, ... and return
693 //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);
694 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);
695 }
696
697 // Validation of login/pass/entity
698 // If ok, the variable login will be returned
699 // If error, we will put error message in session under the name dol_loginmesg
700 if ($test && $goontestloop && GETPOST('actionlogin', 'aZ09') != 'disabled' && (GETPOST('actionlogin', 'aZ09') == 'login' || $dolibarr_main_authentication != 'dolibarr')) {
701 // Loop on each test mode defined into $authmode
702 // $authmode is an array for example: array('0'=>'dolibarr', '1'=>'googleoauth');
703 $oauthmodetotestarray = array('google');
704 foreach ($oauthmodetotestarray as $oauthmodetotest) {
705 if (in_array($oauthmodetotest.'oauth', $authmode)) { // This is an authmode that is currently qualified. Do we have to remove it ?
706 // If we click on the link to use OAuth authentication or if we go here after a callback return, we do nothing
707 if (GETPOST('beforeoauthloginredirect') == $oauthmodetotest || GETPOST('afteroauthloginreturn') == $oauthmodetotest) {
708 continue;
709 }
710 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);
711 foreach ($authmode as $tmpkey => $tmpval) {
712 if ($tmpval == $oauthmodetotest.'oauth') {
713 unset($authmode[$tmpkey]);
714 break;
715 }
716 }
717 }
718 }
719
720 // Check login for all qualified modes in array $authmode.
721 $login = checkLoginPassEntity($usertotest, $passwordtotest, $entitytotest, $authmode);
722 if ($login === '--bad-login-validity--') {
723 $login = '';
724 }
725
726 if ($login) {
727 $dol_authmode = $conf->authmode; // This property is defined only when logged, to say what mode was successfully used
728 $dol_tz = empty($_POST["tz"]) ? (empty($_SESSION["tz"]) ? '' : $_SESSION["tz"]) : $_POST["tz"];
729 $dol_tz_string = empty($_POST["tz_string"]) ? (empty($_SESSION["tz_string"]) ? '' : $_SESSION["tz_string"]) : $_POST["tz_string"];
730 $dol_tz_string = preg_replace('/\s*\‍(.+\‍)$/', '', $dol_tz_string);
731 $dol_tz_string = preg_replace('/,/', '/', $dol_tz_string);
732 $dol_tz_string = preg_replace('/\s/', '_', $dol_tz_string);
733 $dol_dst = 0;
734 // Keep $_POST here. Do not use GETPOSTISSET
735 $dol_dst_first = empty($_POST["dst_first"]) ? (empty($_SESSION["dst_first"]) ? '' : $_SESSION["dst_first"]) : $_POST["dst_first"];
736 $dol_dst_second = empty($_POST["dst_second"]) ? (empty($_SESSION["dst_second"]) ? '' : $_SESSION["dst_second"]) : $_POST["dst_second"];
737 if ($dol_dst_first && $dol_dst_second) {
738 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
739 $datenow = dol_now();
740 $datefirst = dol_stringtotime($dol_dst_first);
741 $datesecond = dol_stringtotime($dol_dst_second);
742 if ($datenow >= $datefirst && $datenow < $datesecond) {
743 $dol_dst = 1;
744 }
745 }
746 $dol_screenheight = empty($_POST["screenheight"]) ? (empty($_SESSION["dol_screenheight"]) ? '' : $_SESSION["dol_screenheight"]) : $_POST["screenheight"];
747 $dol_screenwidth = empty($_POST["screenwidth"]) ? (empty($_SESSION["dol_screenwidth"]) ? '' : $_SESSION["dol_screenwidth"]) : $_POST["screenwidth"];
748 //print $datefirst.'-'.$datesecond.'-'.$datenow.'-'.$dol_tz.'-'.$dol_tzstring.'-'.$dol_dst.'-'.sdol_screenheight.'-'.sdol_screenwidth; exit;
749 }
750
751 if (!$login) {
752 dol_syslog('Bad password, connection refused (see a previous notice message for more info)', LOG_NOTICE);
753 // Load translation files required by page
754 $langs->loadLangs(array('main', 'errors'));
755
756 // Bad password. No authmode has found a good password.
757 // We set a generic message if not defined inside function checkLoginPassEntity or subfunctions
758 if (empty($_SESSION["dol_loginmesg"])) {
759 $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorBadLoginPassword");
760 }
761
762 // Call trigger for the "security events" log
763 $user->context['audit'] = $langs->trans("ErrorBadLoginPassword").' - login='.GETPOST("username", "alpha", 2);
764
765 // Call trigger
766 $result = $user->call_trigger('USER_LOGIN_FAILED', $user);
767 if ($result < 0) {
768 $error++;
769 }
770 // End call triggers
771
772 // Hooks on failed login
773 $action = '';
774 $hookmanager->initHooks(array('login'));
775 $parameters = array('dol_authmode' => $dol_authmode, 'dol_loginmesg' => $_SESSION["dol_loginmesg"]);
776 $reshook = $hookmanager->executeHooks('afterLoginFailed', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
777 if ($reshook < 0) {
778 $error++;
779 }
780
781 // Note: exit is done in next chapter
782 }
783 }
784
785 // End test login / passwords
786 if (!$login || (in_array('ldap', $authmode) && !in_array('openid_connect', $authmode) && empty($passwordtotest))) { // With LDAP we refused empty password because some LDAP are "opened" for anonymous access so connection is a success.
787 // No data to test login, so we show the login page.
788 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);
789 if (defined('NOREDIRECTBYMAINTOLOGIN')) {
790 // When used with NOREDIRECTBYMAINTOLOGIN set, the http header must already be set when including the main.
791 // See example with selectsearchbox.php. This case is reserved for the selectesearchbox.php so we can
792 // report a message to ask to login when search ajax component is used after a timeout.
793 //top_httphead();
794 return 'ERROR_NOT_LOGGED';
795 } else {
796 if (!empty($_SERVER["HTTP_USER_AGENT"]) && $_SERVER["HTTP_USER_AGENT"] == 'securitytest') {
797 http_response_code(401); // It makes easier to understand if session was broken during security tests
798 }
799
800 // Show login form
801 dol_loginfunction($langs, $conf, (!empty($mysoc) ? $mysoc : '')); // This include http headers
802 }
803 exit;
804 }
805
806 $resultFetchUser = $user->fetch(0, $login, '', 1, ($entitytotest > 0 ? $entitytotest : -1)); // value for $login was retrieved previously when checking password.
807
808 if ($resultFetchUser <= 0 || $user->isNotIntoValidityDateRange()) {
809 dol_syslog('User not found or not valid, connection refused');
810 session_destroy();
811 session_set_cookie_params(0, '/', null, !empty($dolibarr_main_force_https), true); // Add tag secure and httponly on session cookie
812 session_name($sessionname);
814
815 if ($resultFetchUser == 0) {
816 // Load translation files required by page
817 $langs->loadLangs(array('main', 'errors'));
818
819 $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorCantLoadUserFromDolibarrDatabase", $login);
820
821 $user->context['audit'] = 'ErrorCantLoadUserFromDolibarrDatabase - login='.$login;
822 } elseif ($resultFetchUser < 0) {
823 $_SESSION["dol_loginmesg"] = $user->error;
824
825 $user->context['audit'] = $user->error;
826 } else {
827 // Load translation files required by the page
828 $langs->loadLangs(array('main', 'errors'));
829
830 $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorLoginDateValidity");
831
832 $user->context['audit'] = $langs->trans("ErrorLoginDateValidity").' - login='.$login;
833 }
834
835 // Call trigger
836 $result = $user->call_trigger('USER_LOGIN_FAILED', $user);
837 if ($result < 0) {
838 $error++;
839 }
840 // End call triggers
841
842
843 // Hooks on failed login
844 $action = '';
845 $hookmanager->initHooks(array('login'));
846 $parameters = array('dol_authmode' => $dol_authmode, 'dol_loginmesg' => $_SESSION["dol_loginmesg"]);
847 $reshook = $hookmanager->executeHooks('afterLoginFailed', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
848 if ($reshook < 0) {
849 $error++;
850 }
851
852 $paramsurl = array();
853 if (GETPOSTINT('textbrowser')) {
854 $paramsurl[] = 'textbrowser='.GETPOSTINT('textbrowser');
855 }
856 if (GETPOSTINT('nojs')) {
857 $paramsurl[] = 'nojs='.GETPOSTINT('nojs');
858 }
859 if (GETPOST('lang', 'aZ09')) {
860 $paramsurl[] = 'lang='.GETPOST('lang', 'aZ09');
861 }
862 header('Location: '.DOL_URL_ROOT.'/index.php'.(count($paramsurl) ? '?'.implode('&', $paramsurl) : ''));
863 exit;
864 } else {
865 // User is loaded, we may need to change language for him according to its choice
866 if (!empty($user->conf->MAIN_LANG_DEFAULT)) {
867 $langs->setDefaultLang($user->conf->MAIN_LANG_DEFAULT);
868 }
869 }
870 } else {
871 // We are already into an authenticated session
872 $login = $_SESSION["dol_login"];
873 $entity = isset($_SESSION["dol_entity"]) ? $_SESSION["dol_entity"] : 0;
874 dol_syslog("- This is an already logged session. _SESSION['dol_login']=".$login." _SESSION['dol_entity']=".$entity, LOG_DEBUG);
875
876 $resultFetchUser = $user->fetch(0, $login, '', 1, ($entity > 0 ? $entity : -1));
877
878 //var_dump(dol_print_date($user->flagdelsessionsbefore, 'dayhour', 'gmt')." ".dol_print_date($_SESSION["dol_logindate"], 'dayhour', 'gmt'));
879
880 if ($resultFetchUser <= 0
881 || ($user->flagdelsessionsbefore && !empty($_SESSION["dol_logindate"]) && $user->flagdelsessionsbefore > $_SESSION["dol_logindate"])
882 || ($user->status != $user::STATUS_ENABLED)
883 || ($user->isNotIntoValidityDateRange())) {
884 if ($resultFetchUser <= 0) {
885 // Account has been removed after login
886 dol_syslog("Can't load user even if session logged. _SESSION['dol_login']=".$login, LOG_WARNING);
887 } elseif ($user->flagdelsessionsbefore && !empty($_SESSION["dol_logindate"]) && $user->flagdelsessionsbefore > $_SESSION["dol_logindate"]) {
888 // Session is no more valid
889 dol_syslog("The user has a date for session invalidation = ".$user->flagdelsessionsbefore." and a session date = ".$_SESSION["dol_logindate"].". We must invalidate its sessions.");
890 } elseif ($user->status != $user::STATUS_ENABLED) {
891 // User is not enabled
892 dol_syslog("The user login is disabled");
893 } else {
894 // User validity dates are no more valid
895 dol_syslog("The user login has a validity between [".$user->datestartvalidity." and ".$user->dateendvalidity."], current date is ".dol_now());
896 }
897 session_destroy();
898 session_set_cookie_params(0, '/', null, !empty($dolibarr_main_force_https), true); // Add tag secure and httponly on session cookie
899 session_name($sessionname);
901
902 if ($resultFetchUser == 0) {
903 $langs->loadLangs(array('main', 'errors'));
904
905 $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorCantLoadUserFromDolibarrDatabase", $login);
906
907 $user->context['audit'] = 'ErrorCantLoadUserFromDolibarrDatabase - login='.$login;
908 } elseif ($resultFetchUser < 0) {
909 $_SESSION["dol_loginmesg"] = $user->error;
910
911 $user->context['audit'] = $user->error;
912 } else {
913 $langs->loadLangs(array('main', 'errors'));
914
915 $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorSessionInvalidatedAfterPasswordChange");
916
917 $user->context['audit'] = 'ErrorUserSessionWasInvalidated - login='.$login;
918 }
919
920 // Call trigger
921 $result = $user->call_trigger('USER_LOGIN_FAILED', $user);
922 if ($result < 0) {
923 $error++;
924 }
925 // End call triggers
926
927 // Hooks on failed login
928 $action = '';
929 $hookmanager->initHooks(array('login'));
930 $parameters = array('dol_authmode' => (string) $dol_authmode, 'dol_loginmesg' => $_SESSION["dol_loginmesg"]);
931 $reshook = $hookmanager->executeHooks('afterLoginFailed', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
932 if ($reshook < 0) {
933 $error++;
934 }
935
936 $paramsurl = array();
937 if (GETPOSTINT('textbrowser')) {
938 $paramsurl[] = 'textbrowser='.GETPOSTINT('textbrowser');
939 }
940 if (GETPOSTINT('nojs')) {
941 $paramsurl[] = 'nojs='.GETPOSTINT('nojs');
942 }
943 if (GETPOST('lang', 'aZ09')) {
944 $paramsurl[] = 'lang='.GETPOST('lang', 'aZ09');
945 }
946
947 header('Location: '.DOL_URL_ROOT.'/index.php'.(count($paramsurl) ? '?'.implode('&', $paramsurl) : ''));
948 exit;
949 } else {
950 // Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
951 $hookmanager->initHooks(array('main'));
952
953 // Code for search criteria persistence.
954 if (!empty($_GET['save_lastsearch_values']) && !empty($_SERVER["HTTP_REFERER"])) { // We must use $_GET here
955 $relativepathstring = preg_replace('/\?.*$/', '', $_SERVER["HTTP_REFERER"]);
956 $relativepathstring = preg_replace('/^https?:\/\/[^\/]*/', '', $relativepathstring); // Get full path except host server
957 // Clean $relativepathstring
958 if (constant('DOL_URL_ROOT')) {
959 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
960 }
961 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
962 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
963 //var_dump($relativepathstring);
964
965 // 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
966 if (!empty($_SESSION['lastsearch_values_tmp_'.$relativepathstring])) {
967 $_SESSION['lastsearch_values_'.$relativepathstring] = $_SESSION['lastsearch_values_tmp_'.$relativepathstring];
968 unset($_SESSION['lastsearch_values_tmp_'.$relativepathstring]);
969 }
970 if (!empty($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring])) {
971 $_SESSION['lastsearch_contextpage_'.$relativepathstring] = $_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring];
972 unset($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]);
973 }
974 if (!empty($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]) && $_SESSION['lastsearch_limit_tmp_'.$relativepathstring] != $conf->liste_limit) {
975 $_SESSION['lastsearch_limit_'.$relativepathstring] = $_SESSION['lastsearch_limit_tmp_'.$relativepathstring];
976 unset($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]);
977 }
978 if (!empty($_SESSION['lastsearch_page_tmp_'.$relativepathstring]) && $_SESSION['lastsearch_page_tmp_'.$relativepathstring] > 0) {
979 $_SESSION['lastsearch_page_'.$relativepathstring] = $_SESSION['lastsearch_page_tmp_'.$relativepathstring];
980 unset($_SESSION['lastsearch_page_tmp_'.$relativepathstring]);
981 }
982 if (!empty($_SESSION['lastsearch_mode_tmp_'.$relativepathstring])) {
983 $_SESSION['lastsearch_mode_'.$relativepathstring] = $_SESSION['lastsearch_mode_tmp_'.$relativepathstring];
984 unset($_SESSION['lastsearch_mode_tmp_'.$relativepathstring]);
985 }
986 }
987 if (!empty($_GET['save_pageforbacktolist']) && !empty($_SERVER["HTTP_REFERER"])) { // We must use $_GET here
988 if (empty($_SESSION['pageforbacktolist'])) {
989 $pageforbacktolistarray = array();
990 } else {
991 $pageforbacktolistarray = $_SESSION['pageforbacktolist'];
992 }
993 $tmparray = explode(':', $_GET['save_pageforbacktolist'], 2);
994 if (!empty($tmparray[0]) && !empty($tmparray[1])) {
995 $pageforbacktolistarray[$tmparray[0]] = $tmparray[1];
996 $_SESSION['pageforbacktolist'] = $pageforbacktolistarray;
997 }
998 }
999
1000 $action = '';
1001 $parameters = array();
1002 $reshook = $hookmanager->executeHooks('updateSession', $parameters, $user, $action);
1003 if ($reshook < 0) {
1004 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1005 }
1006 }
1007 }
1008
1009 // Is it a new session that has started ?
1010 // If we are here, this means authentication was successful.
1011 if (!isset($_SESSION["dol_login"])) {
1012 // New session for this login has started.
1013 $error = 0;
1014
1015 // Store value into session (values always stored)
1016 $_SESSION["dol_login"] = $user->login;
1017 $_SESSION["dol_logindate"] = dol_now('gmt');
1018 $_SESSION["dol_authmode"] = isset($dol_authmode) ? $dol_authmode : '';
1019 $_SESSION["dol_tz"] = isset($dol_tz) ? $dol_tz : '';
1020 $_SESSION["dol_tz_string"] = isset($dol_tz_string) ? $dol_tz_string : '';
1021 $_SESSION["dol_dst"] = isset($dol_dst) ? $dol_dst : '';
1022 $_SESSION["dol_dst_observed"] = isset($dol_dst_observed) ? $dol_dst_observed : '';
1023 $_SESSION["dol_dst_first"] = isset($dol_dst_first) ? $dol_dst_first : '';
1024 $_SESSION["dol_dst_second"] = isset($dol_dst_second) ? $dol_dst_second : '';
1025 $_SESSION["dol_screenwidth"] = isset($dol_screenwidth) ? $dol_screenwidth : '';
1026 $_SESSION["dol_screenheight"] = isset($dol_screenheight) ? $dol_screenheight : '';
1027 $_SESSION["dol_company"] = getDolGlobalString("MAIN_INFO_SOCIETE_NOM");
1028 $_SESSION["dol_entity"] = $conf->entity;
1029 // Store value into session (values stored only if defined)
1030 if (!empty($dol_hide_topmenu)) {
1031 $_SESSION['dol_hide_topmenu'] = $dol_hide_topmenu;
1032 }
1033 if (!empty($dol_hide_leftmenu)) {
1034 $_SESSION['dol_hide_leftmenu'] = $dol_hide_leftmenu;
1035 }
1036 if (!empty($dol_optimize_smallscreen)) {
1037 $_SESSION['dol_optimize_smallscreen'] = $dol_optimize_smallscreen;
1038 }
1039 if (!empty($dol_no_mouse_hover)) {
1040 $_SESSION['dol_no_mouse_hover'] = $dol_no_mouse_hover;
1041 }
1042 if (!empty($dol_use_jmobile)) {
1043 $_SESSION['dol_use_jmobile'] = $dol_use_jmobile;
1044 }
1045
1046 dol_syslog("This is a new started user session. _SESSION['dol_login']=".$_SESSION["dol_login"]." Session id=".session_id());
1047
1048 $db->begin();
1049
1050 $user->update_last_login_date();
1051
1052 $loginfo = 'TZ='.$_SESSION["dol_tz"].';TZString='.$_SESSION["dol_tz_string"].';Screen='.$_SESSION["dol_screenwidth"].'x'.$_SESSION["dol_screenheight"];
1053 $loginfo .= ' - authmode='.$dol_authmode.' - entity='.$conf->entity;
1054
1055 // Call triggers for the "security events" log
1056 $user->context['audit'] = $loginfo;
1057 $user->context['authentication_method'] = $dol_authmode;
1058
1059 // Call trigger
1060 $result = $user->call_trigger('USER_LOGIN', $user);
1061 if ($result < 0) {
1062 $error++;
1063 }
1064 // End call triggers
1065
1066 // Hooks on successful login
1067 $action = '';
1068 $hookmanager->initHooks(array('login'));
1069 $parameters = array('dol_authmode' => $dol_authmode, 'dol_loginfo' => $loginfo);
1070 $reshook = $hookmanager->executeHooks('afterLogin', $parameters, $user, $action); // Note that $action and $object may have been modified by some hooks
1071 if ($reshook < 0) {
1072 $error++;
1073 }
1074
1075 if ($error) {
1076 $db->rollback();
1077 session_destroy();
1078 dol_print_error($db, 'Error in some triggers USER_LOGIN or in some hooks afterLogin');
1079 exit;
1080 } else {
1081 $db->commit();
1082 }
1083
1084 // Change landing page if defined.
1085 $landingpage = getDolUserString('MAIN_LANDING_PAGE', getDolGlobalString('MAIN_LANDING_PAGE'));
1086 if (!empty($landingpage)) { // Example: /index.php
1087 $newpath = dol_buildpath($landingpage, 1);
1088 if ($_SERVER["PHP_SELF"] != $newpath) { // not already on landing page (avoid infinite loop)
1089 header('Location: '.$newpath);
1090 exit;
1091 }
1092 }
1093 }
1094
1095
1096 // If user admin, we force the rights-based modules
1097 if ($user->admin) {
1098 $user->rights->user->user->lire = 1;
1099 $user->rights->user->user->creer = 1;
1100 $user->rights->user->user->password = 1;
1101 $user->rights->user->user->supprimer = 1;
1102 $user->rights->user->self->creer = 1;
1103 $user->rights->user->self->password = 1;
1104
1105 //Required if advanced permissions are used with MAIN_USE_ADVANCED_PERMS
1106 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS')) {
1107 if (!$user->hasRight('user', 'user_advance')) {
1108 $user->rights->user->user_advance = new stdClass(); // To avoid warnings
1109 }
1110 if (!$user->hasRight('user', 'self_advance')) {
1111 $user->rights->user->self_advance = new stdClass(); // To avoid warnings
1112 }
1113 if (!$user->hasRight('user', 'group_advance')) {
1114 $user->rights->user->group_advance = new stdClass(); // To avoid warnings
1115 }
1116
1117 $user->rights->user->user_advance->readperms = 1;
1118 $user->rights->user->user_advance->write = 1;
1119 $user->rights->user->self_advance->readperms = 1;
1120 $user->rights->user->self_advance->writeperms = 1;
1121 $user->rights->user->group_advance->read = 1;
1122 $user->rights->user->group_advance->readperms = 1;
1123 $user->rights->user->group_advance->write = 1;
1124 $user->rights->user->group_advance->delete = 1;
1125 }
1126 }
1127
1128 /*
1129 * Overwrite some configs globals (try to avoid this and have code to use instead $user->conf->xxx)
1130 */
1131
1132 // Set liste_limit from user setup
1133 if (isset($user->conf->MAIN_SIZE_LISTE_LIMIT)) { // If a user setup exists
1134 $conf->liste_limit = getDolUserInt('MAIN_SIZE_LISTE_LIMIT'); // Can be 0
1135 }
1136 if ((int) $conf->liste_limit <= 0) {
1137 // Mode automatic. Similar code than into conf.class.php
1138 $conf->liste_limit = 15;
1139 if (!empty($_SESSION['dol_screenheight']) && $_SESSION['dol_screenheight'] < 700) {
1140 $conf->liste_limit = 8;
1141 } elseif (!empty($_SESSION['dol_screenheight']) && $_SESSION['dol_screenheight'] < 910) {
1142 $conf->liste_limit = 10;
1143 } elseif (!empty($_SESSION['dol_screenheight']) && $_SESSION['dol_screenheight'] > 1130) {
1144 $conf->liste_limit = 20;
1145 }
1146 }
1147 // Overwrite main_checkbox_left_column from user setup
1148 if (isset($user->conf->MAIN_CHECKBOX_LEFT_COLUMN)) { // If a user setup exists
1149 $conf->main_checkbox_left_column = getDolUserInt('MAIN_CHECKBOX_LEFT_COLUMN'); // Can be 0
1150 }
1151
1152 // Replace conf->css by personalized value if theme not forced
1153 if (!getDolGlobalString('MAIN_FORCETHEME') && getDolUserString('MAIN_THEME')) {
1154 $conf->theme = getDolUserString('MAIN_THEME');
1155 $conf->css = "/theme/".$conf->theme."/style.css.php";
1156 }
1157} else {
1158 // We may have NOLOGIN set, but NOREQUIREUSER not
1159 if (!empty($user) && method_exists($user, 'loadDefaultValues') && !defined('NODEFAULTVALUES')) {
1160 $user->loadDefaultValues(); // Load default values for everybody (works even if $user->id = 0
1161 }
1162}
1163
1164
1165// Case forcing style from url
1166if (GETPOST('theme', 'aZ09')) {
1167 $conf->theme = GETPOST('theme', 'aZ09', 1);
1168 $conf->css = "/theme/".$conf->theme."/style.css.php";
1169}
1170
1171// Set javascript option
1172if (GETPOSTINT('nojs')) { // If javascript was not disabled on URL
1173 $conf->use_javascript_ajax = 0;
1174} else {
1175 if (getDolUserString('MAIN_DISABLE_JAVASCRIPT')) {
1176 $conf->use_javascript_ajax = !getDolUserString('MAIN_DISABLE_JAVASCRIPT') ? 1 : 0;
1177 }
1178}
1179
1180// Set MAIN_OPTIMIZEFORTEXTBROWSER for user (must be after login part)
1181if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && getDolUserString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1182 $conf->global->MAIN_OPTIMIZEFORTEXTBROWSER = getDolUserString('MAIN_OPTIMIZEFORTEXTBROWSER');
1183 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') == 1) {
1184 $conf->global->THEME_TOPMENU_DISABLE_IMAGE = 1;
1185 }
1186}
1187//var_dump($conf->global->THEME_TOPMENU_DISABLE_IMAGE);
1188//var_dump($user->conf->THEME_TOPMENU_DISABLE_IMAGE);
1189
1190// set MAIN_OPTIMIZEFORCOLORBLIND for user
1191$conf->global->MAIN_OPTIMIZEFORCOLORBLIND = getDolUserString('MAIN_OPTIMIZEFORCOLORBLIND');
1192
1193// Set terminal output option according to conf->browser.
1194if (GETPOSTINT('dol_hide_leftmenu') || !empty($_SESSION['dol_hide_leftmenu'])) {
1195 $conf->dol_hide_leftmenu = 1;
1196}
1197if (GETPOSTINT('dol_hide_topmenu') || !empty($_SESSION['dol_hide_topmenu'])) {
1198 $conf->dol_hide_topmenu = 1;
1199}
1200if (GETPOSTINT('dol_optimize_smallscreen') || !empty($_SESSION['dol_optimize_smallscreen'])) {
1201 $conf->dol_optimize_smallscreen = 1;
1202}
1203if (GETPOSTINT('dol_no_mouse_hover') || !empty($_SESSION['dol_no_mouse_hover'])) {
1204 $conf->dol_no_mouse_hover = 1;
1205}
1206if (GETPOSTINT('dol_use_jmobile') || !empty($_SESSION['dol_use_jmobile'])) {
1207 $conf->dol_use_jmobile = 1;
1208}
1209// If not on Desktop
1210if (!empty($conf->browser->layout) && $conf->browser->layout != 'classic') {
1211 $conf->dol_no_mouse_hover = 1;
1212}
1213
1214// If on smartphone or optimized for small screen
1215if ((!empty($conf->browser->layout) && $conf->browser->layout == 'phone')
1216 || (!empty($_SESSION['dol_screenwidth']) && $_SESSION['dol_screenwidth'] < 400)
1217 || (!empty($_SESSION['dol_screenheight']) && $_SESSION['dol_screenheight'] < 400
1218 || getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER'))
1219) {
1220 $conf->dol_optimize_smallscreen = 1;
1221
1222 if (getDolGlobalInt('PRODUIT_DESC_IN_FORM') == 1) {
1223 $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
1224 }
1225}
1226// Replace themes bugged with jmobile with eldy
1227if (!empty($conf->dol_use_jmobile) && in_array($conf->theme, array('bureau2crea', 'cameleo', 'amarok'))) {
1228 $conf->theme = 'eldy';
1229 $conf->css = "/theme/".$conf->theme."/style.css.php";
1230}
1231
1232if (!defined('NOREQUIRETRAN')) {
1233 if (!GETPOST('lang', 'aZ09')) { // If language was not forced on URL
1234 // If user has chosen its own language
1235 if (!empty($user->conf->MAIN_LANG_DEFAULT)) {
1236 // If different than current language
1237 //print ">>>".$langs->getDefaultLang()."-".$user->conf->MAIN_LANG_DEFAULT;
1238 if ($langs->getDefaultLang() != $user->conf->MAIN_LANG_DEFAULT) {
1239 $langs->setDefaultLang($user->conf->MAIN_LANG_DEFAULT);
1240 }
1241 }
1242 }
1243}
1244
1245if (!defined('NOLOGIN')) {
1246 // If the login is not recovered, it is identified with an account that does not exist.
1247 // Hacking attempt?
1248 if (!$user->login) {
1250 }
1251
1252 // Check if user is active
1253 if ($user->statut < 1) {
1254 // If not active, we refuse the user
1255 $langs->loadLangs(array("errors", "other"));
1256 dol_syslog("Authentication KO as login is disabled", LOG_NOTICE);
1257 accessforbidden("ErrorLoginDisabled");
1258 }
1259
1260 // Load permissions
1261 $user->loadRights();
1262}
1263
1264dol_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);
1265//Another call for easy debug
1266//dol_syslog("Access to ".$_SERVER["PHP_SELF"].' '.$_SERVER["HTTP_REFERER"].' GET='.join(',',array_keys($_GET)).'->'.join(',',$_GET).' POST:'.join(',',array_keys($_POST)).'->'.join(',',$_POST));
1267
1268// Load main languages files
1269if (!defined('NOREQUIRETRAN')) {
1270 // Load translation files required by page
1271 $langs->loadLangs(array('main', 'dict'));
1272}
1273
1274// Define some constants used for style of arrays
1275$bc = array(0 => 'class="impair"', 1 => 'class="pair"');
1276$bcdd = array(0 => 'class="drag drop oddeven"', 1 => 'class="drag drop oddeven"');
1277$bcnd = array(0 => 'class="nodrag nodrop nohover"', 1 => 'class="nodrag nodrop nohoverpair"'); // Used for tr to add new lines
1278
1279// Define messages variables
1280$mesg = '';
1281$warning = '';
1282$error = 0;
1283// deprecated, see setEventMessages() and dol_htmloutput_events()
1284$mesgs = array();
1285$warnings = array();
1286$errors = array();
1287
1288// Constants used to defined number of lines in textarea
1289if (empty($conf->browser->firefox)) {
1290 define('ROWS_1', 1);
1291 define('ROWS_2', 2);
1292 define('ROWS_3', 3);
1293 define('ROWS_4', 4);
1294 define('ROWS_5', 5);
1295 define('ROWS_6', 6);
1296 define('ROWS_7', 7);
1297 define('ROWS_8', 8);
1298 define('ROWS_9', 9);
1299} else {
1300 define('ROWS_1', 0);
1301 define('ROWS_2', 1);
1302 define('ROWS_3', 2);
1303 define('ROWS_4', 3);
1304 define('ROWS_5', 4);
1305 define('ROWS_6', 5);
1306 define('ROWS_7', 6);
1307 define('ROWS_8', 7);
1308 define('ROWS_9', 8);
1309}
1310
1311$heightforframes = 52; // Used by frames.php page
1312
1313// Init menu manager
1314if (!defined('NOREQUIREMENU')) {
1315 if (empty($user->socid)) { // If internal user or not defined
1316 $conf->standard_menu = getDolGlobalString('MAIN_MENU_STANDARD_FORCED', getDolGlobalString('MAIN_MENU_STANDARD', 'eldy_menu.php'));
1317 } else {
1318 // If external user
1319 $conf->standard_menu = getDolGlobalString('MAIN_MENUFRONT_STANDARD_FORCED', getDolGlobalString('MAIN_MENUFRONT_STANDARD', 'eldy_menu.php'));
1320 }
1321
1322 // Load the menu manager (only if not already done)
1323 $file_menu = $conf->standard_menu;
1324 if (GETPOST('menu', 'alpha')) {
1325 $file_menu = GETPOST('menu', 'alpha'); // example: menu=eldy_menu.php
1326 }
1327
1328 if (!class_exists('MenuManager')) {
1329 $menufound = 0;
1330 $dirmenus = array_merge(array("/core/menus/"), (array) $conf->modules_parts['menus']);
1331 foreach ($dirmenus as $dirmenu) {
1332 $menufound = dol_include_once($dirmenu."standard/".$file_menu);
1333 if (class_exists('MenuManager')) {
1334 break;
1335 }
1336 }
1337 if (!class_exists('MenuManager')) { // If failed to include, we try with standard eldy_menu.php
1338 dol_syslog("You define a menu manager '".$file_menu."' that can not be loaded.", LOG_WARNING);
1339 $file_menu = 'eldy_menu.php';
1340 include_once DOL_DOCUMENT_ROOT."/core/menus/standard/".$file_menu;
1341 }
1342 }
1343 // @phan-suppress-next-line PhanRedefinedClassReference
1344 $menumanager = new MenuManager($db, empty($user->socid) ? 0 : 1);
1345 // @phan-suppress-next-line PhanRedefinedClassReference
1346 $menumanager->loadMenu();
1347}
1348
1349if (!empty(GETPOST('seteventmessages', 'alpha'))) {
1350 $message = GETPOST('seteventmessages', 'alpha');
1351 $messages = explode(',', $message);
1352 foreach ($messages as $key => $msg) {
1353 $tmp = explode(':', $msg);
1354 setEventMessages($tmp[0], null, !empty($tmp[1]) ? $tmp[1] : 'mesgs');
1355 }
1356}
1357
1358// Functions
1359
1360if (!function_exists("llxHeader")) {
1384 function llxHeader($head = '', $title = '', $help_url = '', $target = '', $disablejs = 0, $disablehead = 0, $arrayofjs = '', $arrayofcss = '', $morequerystring = '', $morecssonbody = '', $replacemainareaby = '', $disablenofollow = 0, $disablenoindex = 0)
1385 {
1386 global $conf, $hookmanager;
1387
1388 $parameters = array(
1389 'head' => & $head,
1390 'title' => & $title,
1391 'help_url' => & $help_url,
1392 'target' => & $target,
1393 'disablejs' => & $disablejs,
1394 'disablehead' => & $disablehead,
1395 'arrayofjs' => & $arrayofjs,
1396 'arrayofcss' => & $arrayofcss,
1397 'morequerystring' => & $morequerystring,
1398 'morecssonbody' => & $morecssonbody,
1399 'replacemainareaby' => & $replacemainareaby,
1400 'disablenofollow' => & $disablenofollow,
1401 'disablenoindex' => & $disablenoindex
1402
1403 );
1404 $reshook = $hookmanager->executeHooks('llxHeader', $parameters);
1405 if ($reshook > 0) {
1406 print $hookmanager->resPrint;
1407 return;
1408 }
1409
1410 // html header
1411 top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss, 0, $disablenofollow, $disablenoindex);
1412
1413 $tmpcsstouse = 'sidebar-collapse'.($morecssonbody ? ' '.$morecssonbody : '');
1414 // If theme MD and classic layer, we open the menulayer by default.
1415 if ($conf->theme == 'md' && !in_array($conf->browser->layout, array('phone', 'tablet')) && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
1416 global $mainmenu;
1417 if ($mainmenu != 'website') {
1418 $tmpcsstouse = $morecssonbody; // We do not use sidebar-collpase by default to have menuhider open by default.
1419 }
1420 }
1421
1422 if (getDolGlobalString('MAIN_OPTIMIZEFORCOLORBLIND')) {
1423 $tmpcsstouse .= ' colorblind-'.strip_tags(getDolGlobalString('MAIN_OPTIMIZEFORCOLORBLIND'));
1424 }
1425
1426 if (GETPOST('dol_openinpopup', 'aZ09')) {
1427 $tmpcsstouse .= ' dol_openinpopup';
1428 }
1429
1430 print '<body id="mainbody" class="'.$tmpcsstouse.'">'."\n";
1431
1432 // top menu and left menu area
1433 if ((empty($conf->dol_hide_topmenu) || GETPOSTINT('dol_invisible_topmenu')) && !GETPOST('dol_openinpopup', 'aZ09')) {
1434 top_menu($head, $title, $target, $disablejs, $disablehead, $arrayofjs, $arrayofcss, $morequerystring, $help_url);
1435 }
1436
1437 if (empty($conf->dol_hide_leftmenu) && !GETPOST('dol_openinpopup', 'aZ09')) {
1438 left_menu('', $help_url, '', array(), 1, $title, 1); // $menumanager is retrieved with a global $menumanager inside this function
1439 }
1440
1441 // main area
1442 if ($replacemainareaby) {
1443 print $replacemainareaby;
1444 return;
1445 }
1446
1447 main_area($title);
1448 }
1449}
1450
1451
1459function top_httphead($contenttype = 'text/html', $forcenocache = 0)
1460{
1461 global $db, $conf, $hookmanager;
1462
1463 if ($contenttype == 'text/html') {
1464 header("Content-Type: text/html; charset=".$conf->file->character_set_client);
1465 } else {
1466 header("Content-Type: ".$contenttype);
1467 }
1468
1469 // Security options
1470
1471 // X-Content-Type-Options
1472 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)
1473
1474 // X-Frame-Options
1475 if (!defined('XFRAMEOPTIONS_ALLOWALL')) {
1476 header("X-Frame-Options: SAMEORIGIN"); // By default, frames allowed only if on same domain (stop some XSS attacks)
1477 } else {
1478 header("X-Frame-Options: ALLOWALL");
1479 }
1480
1481 if (getDolGlobalString('MAIN_SECURITY_FORCE_ACCESS_CONTROL_ALLOW_ORIGIN')) {
1482 $tmpurl = constant('DOL_MAIN_URL_ROOT');
1483 $tmpurl = preg_replace('/^(https?:\/\/[^\/]+)\/.*$/', '\1', $tmpurl);
1484 header('Access-Control-Allow-Origin: '.$tmpurl);
1485 header('Vary: Origin');
1486 }
1487
1488 // X-XSS-Protection
1489 //header("X-XSS-Protection: 1"); // XSS filtering protection of some browsers (note: use of Content-Security-Policy is more efficient). Disabled as deprecated.
1490
1491 // Content-Security-Policy-Report-Only
1492 if (!defined('MAIN_SECURITY_FORCECSPRO')) {
1493 // If CSP not forced from the page
1494
1495 // A default security policy that keep usage of js external component like ckeditor, stripe, google, working
1496 // For example: to restrict to only local resources, except for css (cloudflare+google), and js (transifex + google tags) and object/iframe (youtube)
1497 // 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: *;
1498 // For example, to restrict everything to itself except img that can be on other servers:
1499 // default-src 'self'; img-src *;
1500 // Pre-existing site that uses too much js code to fix but wants to ensure resources are loaded only over https and disable plugins:
1501 // default-src https: 'unsafe-inline' 'unsafe-eval'; object-src 'none'
1502 //
1503 // $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;";
1504 // $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';";
1505 $contentsecuritypolicy = getDolGlobalString('MAIN_SECURITY_FORCECSPRO');
1506
1507 if (!is_object($hookmanager)) {
1508 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1509 $hookmanager = new HookManager($db);
1510 }
1511 $hookmanager->initHooks(array("main"));
1512
1513 $parameters = array('contentsecuritypolicy' => $contentsecuritypolicy, 'mode' => 'reportonly');
1514 $result = $hookmanager->executeHooks('setContentSecurityPolicy', $parameters); // Note that $action and $object may have been modified by some hooks
1515 if ($result > 0) {
1516 $contentsecuritypolicy = $hookmanager->resPrint; // Replace CSP
1517 } else {
1518 $contentsecuritypolicy .= $hookmanager->resPrint; // Concat CSP
1519 }
1520
1521 if (!empty($contentsecuritypolicy)) {
1522 header("Content-Security-Policy-Report-Only: ".$contentsecuritypolicy);
1523 }
1524 } else {
1525 header("Content-Security-Policy: ".constant('MAIN_SECURITY_FORCECSPRO'));
1526 }
1527
1528 // Content-Security-Policy
1529 if (!defined('MAIN_SECURITY_FORCECSP')) {
1530 // If CSP not forced from the page
1531
1532 // A default security policy that keep usage of js external component like ckeditor, stripe, google, working
1533 // For example: to restrict to only local resources, except for css (cloudflare+google), and js (transifex + google tags) and object/iframe (youtube)
1534 // 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: *;
1535 // For example, to restrict everything to itself except img that can be on other servers:
1536 // default-src 'self'; img-src *;
1537 // Pre-existing site that uses too much js code to fix but wants to ensure resources are loaded only over https and disable plugins:
1538 // default-src https: 'unsafe-inline' 'unsafe-eval'; object-src 'none'
1539 //
1540 // $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;";
1541 // $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';";
1542 $contentsecuritypolicy = getDolGlobalString('MAIN_SECURITY_FORCECSP');
1543
1544 if (!is_object($hookmanager)) {
1545 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1546 $hookmanager = new HookManager($db);
1547 }
1548 $hookmanager->initHooks(array("main"));
1549
1550 $parameters = array('contentsecuritypolicy' => $contentsecuritypolicy, 'mode' => 'active');
1551 $result = $hookmanager->executeHooks('setContentSecurityPolicy', $parameters); // Note that $action and $object may have been modified by some hooks
1552 if ($result > 0) {
1553 $contentsecuritypolicy = $hookmanager->resPrint; // Replace CSP
1554 } else {
1555 $contentsecuritypolicy .= $hookmanager->resPrint; // Concat CSP
1556 }
1557
1558 if (!empty($contentsecuritypolicy)) {
1559 header("Content-Security-Policy: ".$contentsecuritypolicy);
1560 }
1561 } else {
1562 header("Content-Security-Policy: ".constant('MAIN_SECURITY_FORCECSP'));
1563 }
1564
1565 // Referrer-Policy
1566 // Say if we must provide the referrer when we jump onto another web page.
1567 // 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.
1568 // 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.
1569 if (!defined('MAIN_SECURITY_FORCERP')) {
1570 $referrerpolicy = getDolGlobalString('MAIN_SECURITY_FORCERP', "same-origin");
1571
1572 header("Referrer-Policy: ".$referrerpolicy);
1573 }
1574
1575 if ($forcenocache) {
1576 header("Cache-Control: no-cache, no-store, must-revalidate, max-age=0");
1577 }
1578
1579 // No need to add this token in header, we use instead the one into the forms.
1580 //header("anti-csrf-token: ".newToken());
1581}
1582
1598function top_htmlhead($head, $title = '', $disablejs = 0, $disablehead = 0, $arrayofjs = array(), $arrayofcss = array(), $disableforlogin = 0, $disablenofollow = 0, $disablenoindex = 0)
1599{
1600 global $db, $conf, $langs, $user, $mysoc, $hookmanager;
1601
1602 top_httphead();
1603
1604 if (empty($conf->css)) {
1605 $conf->css = '/theme/eldy/style.css.php'; // If not defined, eldy by default
1606 }
1607
1608 print '<!doctype html>'."\n";
1609
1610 print '<html lang="'.substr($langs->defaultlang, 0, 2).'">'."\n";
1611
1612 //print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">'."\n";
1613 if (empty($disablehead)) {
1614 if (!is_object($hookmanager)) {
1615 include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php';
1616 $hookmanager = new HookManager($db);
1617 }
1618 $hookmanager->initHooks(array("main"));
1619
1620 $ext = 'layout='.(empty($conf->browser->layout) ? '' : $conf->browser->layout).'&amp;version='.urlencode(DOL_VERSION);
1621
1622 print "<head>\n";
1623
1624 if (GETPOST('dol_basehref', 'alpha')) {
1625 print '<base href="'.dol_escape_htmltag(GETPOST('dol_basehref', 'alpha')).'">'."\n";
1626 }
1627
1628 // Displays meta
1629 print '<meta charset="utf-8">'."\n";
1630 print '<meta name="robots" content="'.($disablenoindex ? 'index' : 'noindex').($disablenofollow ? ',follow' : ',nofollow').'">'."\n"; // Do not index
1631 print '<meta name="viewport" content="width=device-width, initial-scale=1.0">'."\n"; // Scale for mobile device
1632 print '<meta name="author" content="Dolibarr Development Team">'."\n";
1633 print '<meta name="anti-csrf-newtoken" content="'.newToken().'">'."\n";
1634 print '<meta name="anti-csrf-currenttoken" content="'.currentToken().'">'."\n";
1635 if (getDolGlobalInt('MAIN_FEATURES_LEVEL')) {
1636 print '<meta name="MAIN_FEATURES_LEVEL" content="'.getDolGlobalInt('MAIN_FEATURES_LEVEL').'">'."\n";
1637 }
1638 // Favicon
1639 $favicon = DOL_URL_ROOT.'/theme/dolibarr_256x256_color.png';
1640 $appletouchicon = DOL_URL_ROOT.'/theme/apple-touch-icon.png';
1641 if (!empty($mysoc->logo_squarred_mini)) {
1642 $favicon = DOL_URL_ROOT.'/viewimage.php?cache=1&modulepart=mycompany&file='.urlencode('logos/thumbs/'.$mysoc->logo_squarred_mini);
1643 }
1644 if (getDolGlobalString('MAIN_FAVICON_URL')) {
1645 $favicon = getDolGlobalString('MAIN_FAVICON_URL');
1646 }
1647 if (empty($conf->dol_use_jmobile)) {
1648 print '<link rel="shortcut icon" type="image/x-icon" href="'.$favicon.'"/>'."\n"; // Not required into an Android webview
1649 print '<link rel="apple-touch-icon" href="'.$appletouchicon.'"/>'."\n";
1650 }
1651
1652 // Mobile appli like icon
1653 $manifest = DOL_URL_ROOT.'/theme/'.$conf->theme.'/manifest.json.php';
1654 $parameters = array('manifest' => $manifest);
1655 $resHook = $hookmanager->executeHooks('hookSetManifest', $parameters); // Note that $action and $object may have been modified by some hooks
1656 if ($resHook > 0) {
1657 $manifest = $hookmanager->resPrint; // Replace manifest.json
1658 } else {
1659 $manifest .= $hookmanager->resPrint; // Concat to actual manifest declaration
1660 }
1661 if (!empty($manifest)) {
1662 print '<link rel="manifest" href="'.$manifest.'" />'."\n";
1663 }
1664
1665 if (getDolGlobalString('THEME_ELDY_TOPMENU_BACK1')) {
1666 print '<meta name="theme-color" content="rgb(' . getDolGlobalString('THEME_ELDY_TOPMENU_BACK1').')">'."\n";
1667 }
1668
1669 // Auto refresh page
1670 if (GETPOSTINT('autorefresh') > 0) {
1671 print '<meta http-equiv="refresh" content="'.GETPOSTINT('autorefresh').'">';
1672 }
1673
1674 // Displays title
1675 $appli = constant('DOL_APPLICATION_TITLE');
1676 $applicustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
1677 if ($applicustom) {
1678 $appli = (preg_match('/^\+/', $applicustom) ? $appli : '').$applicustom;
1679 }
1680
1681 print '<title>';
1682 $titletoshow = '';
1683 if ($title && preg_match('/showapp/', getDolGlobalString('MAIN_HTML_TITLE'))) {
1684 $titletoshow = dol_htmlentities($appli.' - '.$title);
1685 } elseif ($title) {
1686 $titletoshow = dol_htmlentities($title);
1687 } else {
1688 $titletoshow = dol_htmlentities($appli);
1689 }
1690
1691 $parameters = array('title' => $titletoshow);
1692 $result = $hookmanager->executeHooks('setHtmlTitle', $parameters); // Note that $action and $object may have been modified by some hooks
1693 if ($result > 0) {
1694 $titletoshow = $hookmanager->resPrint; // Replace Title to show
1695 } else {
1696 $titletoshow .= $hookmanager->resPrint; // Concat to Title to show
1697 }
1698
1699 print $titletoshow;
1700 print '</title>';
1701
1702 print "\n";
1703
1704 if (GETPOSTINT('version')) {
1705 $ext = 'version='.GETPOSTINT('version'); // useful to force no cache on css/js
1706 }
1707 // Refresh value of MAIN_IHM_PARAMS_REV before forging the parameter line.
1708 if (GETPOST('dol_resetcache')) {
1709 include_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
1710 dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity);
1711 }
1712
1713 $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;
1714
1715 $themeparam .= ($ext ? '&amp;'.$ext : '').'&amp;revision='.getDolGlobalInt("MAIN_IHM_PARAMS_REV");
1716 if (GETPOSTISSET('dol_hide_topmenu')) {
1717 $themeparam .= '&amp;dol_hide_topmenu='.GETPOSTINT('dol_hide_topmenu');
1718 }
1719 if (GETPOSTISSET('dol_hide_leftmenu')) {
1720 $themeparam .= '&amp;dol_hide_leftmenu='.GETPOSTINT('dol_hide_leftmenu');
1721 }
1722 if (GETPOSTISSET('dol_openinpopup')) {
1723 $themeparam .= '&amp;dol_openinpopup='.GETPOST('dol_openinpopup', 'aZ09');
1724 }
1725 if (GETPOSTISSET('dol_optimize_smallscreen')) {
1726 $themeparam .= '&amp;dol_optimize_smallscreen='.GETPOSTINT('dol_optimize_smallscreen');
1727 }
1728 if (GETPOSTISSET('dol_no_mouse_hover')) {
1729 $themeparam .= '&amp;dol_no_mouse_hover='.GETPOSTINT('dol_no_mouse_hover');
1730 }
1731 if (GETPOSTISSET('dol_use_jmobile')) {
1732 $themeparam .= '&amp;dol_use_jmobile='.GETPOSTINT('dol_use_jmobile');
1733 $conf->dol_use_jmobile = GETPOSTINT('dol_use_jmobile');
1734 }
1735 if (GETPOSTISSET('THEME_DARKMODEENABLED')) {
1736 $themeparam .= '&amp;THEME_DARKMODEENABLED='.GETPOSTINT('THEME_DARKMODEENABLED');
1737 }
1738 if (GETPOSTISSET('THEME_SATURATE_RATIO')) {
1739 $themeparam .= '&amp;THEME_SATURATE_RATIO='.GETPOSTINT('THEME_SATURATE_RATIO');
1740 }
1741
1742 if (getDolGlobalString('MAIN_ENABLE_FONT_ROBOTO')) {
1743 print '<link rel="preconnect" href="https://fonts.gstatic.com">'."\n";
1744 print '<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@200;300;400;500;600&display=swap" rel="stylesheet">'."\n";
1745 }
1746
1747 if (!defined('DISABLE_JQUERY') && !$disablejs && $conf->use_javascript_ajax) {
1748 print '<!-- Includes CSS for JQuery (Ajax library) -->'."\n";
1749 if (!defined('DISABLE_JQUERY_UI')) {
1750 $jquerytheme = 'base';
1751 if (getDolGlobalString('MAIN_USE_JQUERY_THEME')) {
1752 $jquerytheme = getDolGlobalString('MAIN_USE_JQUERY_THEME');
1753 }
1754 if (constant('JS_JQUERY_UI')) {
1755 print '<link rel="stylesheet" type="text/css" href="' . JS_JQUERY_UI . 'css/' . $jquerytheme . '/jquery-ui.min.css' . ($ext ? '?' . $ext : '') . '">' . "\n"; // Forced JQuery
1756 } else {
1757 print '<link rel="stylesheet" type="text/css" href="' . DOL_URL_ROOT . '/includes/jquery/css/' . $jquerytheme . '/jquery-ui.css' . ($ext ? '?' . $ext : '') . '">' . "\n"; // JQuery
1758 }
1759 }
1760 if (!defined('DISABLE_JQUERY_JNOTIFY')) {
1761 print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/jnotify/jquery.jnotify-alt.min.css'.($ext ? '?'.$ext : '').'">'."\n"; // JNotify
1762 }
1763 if (!defined('DISABLE_SELECT2') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) { // jQuery plugin "mutiselect", "multiple-select", "select2"...
1764 $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT');
1765 print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/'.$tmpplugin.'/dist/css/'.$tmpplugin.'.css'.($ext ? '?'.$ext : '').'">'."\n";
1766 }
1767 }
1768
1769 if (!defined('DISABLE_FONT_AWSOME')) {
1770 print '<!-- Includes CSS for font awesome -->'."\n";
1771 $fontawesome_directory = getDolGlobalString('MAIN_FONTAWESOME_DIRECTORY', '/theme/common/fontawesome-5');
1772 print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.$fontawesome_directory.'/css/all.min.css'.($ext ? '?'.$ext : '').'">'."\n";
1773 }
1774
1775 // Output style sheets (optioncss='print' or ''). Note: $conf->css looks like '/theme/eldy/style.css.php'
1776 $themepath = dol_buildpath($conf->css, 1);
1777 $themesubdir = '';
1778 if (!empty($conf->modules_parts['theme'])) { // This slow down
1779 foreach ($conf->modules_parts['theme'] as $reldir) {
1780 if (file_exists(dol_buildpath($reldir.$conf->css, 0))) {
1781 $themepath = dol_buildpath($reldir.$conf->css, 1);
1782 $themesubdir = $reldir;
1783 break;
1784 }
1785 }
1786 }
1787
1788 if (!defined('DISABLE_CSS_DEFAULT_THEME')) {
1789 print '<!-- Includes CSS for Dolibarr theme -->'."\n";
1790 print '<link rel="stylesheet" type="text/css" href="' . $themepath . $themeparam . '">' . "\n";
1791 }
1792
1793 if (getDolGlobalString('MAIN_FIX_FLASH_ON_CHROME')) {
1794 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";
1795 }
1796
1797 // LEAFLET AND GEOMAN
1798 if (getDolGlobalString('MAIN_USE_GEOPHP')) {
1799 print '<link rel="stylesheet" href="'.DOL_URL_ROOT.'/includes/leaflet/leaflet.css'.($ext ? '?'.$ext : '')."\">\n";
1800 print '<link rel="stylesheet" href="'.DOL_URL_ROOT.'/includes/leaflet/leaflet-geoman.css'.($ext ? '?'.$ext : '')."\">\n";
1801 }
1802
1803 // CSS forced by modules (relative url starting with /)
1804 if (!empty($conf->modules_parts['css'])) {
1805 $arraycss = (array) $conf->modules_parts['css'];
1806 foreach ($arraycss as $modcss => $filescss) {
1807 $filescss = (array) $filescss; // To be sure filecss is an array
1808 foreach ($filescss as $cssfile) {
1809 if (empty($cssfile)) {
1810 dol_syslog("Warning: module ".$modcss." declared a css path file into its descriptor that is empty.", LOG_WARNING);
1811 }
1812 // cssfile is a relative path
1813 $urlforcss = dol_buildpath($cssfile, 1);
1814 if ($urlforcss && $urlforcss != '/') {
1815 print '<!-- Includes CSS added by module '.$modcss.' -->'."\n".'<link rel="stylesheet" type="text/css" href="'.$urlforcss;
1816 // 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.
1817 if (!preg_match('/\.css$/i', $cssfile)) {
1818 print $themeparam;
1819 }
1820 print '">'."\n";
1821 } else {
1822 dol_syslog("Warning: module ".$modcss." declared a css path file for a file we can't find.", LOG_WARNING);
1823 }
1824 }
1825 }
1826 }
1827 // CSS forced by page in top_htmlhead call (relative url starting with /)
1828 if (is_array($arrayofcss)) {
1829 foreach ($arrayofcss as $cssfile) {
1830 if (preg_match('/^(http|\/\/)/i', $cssfile)) {
1831 $urltofile = $cssfile;
1832 } else {
1833 $urltofile = dol_buildpath($cssfile, 1);
1834 }
1835 print '<!-- Includes CSS added by page -->'."\n".'<link rel="stylesheet" type="text/css" title="default" href="'.$urltofile;
1836 // 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.
1837 if (!preg_match('/\.css$/i', $cssfile)) {
1838 print $themeparam;
1839 }
1840 print '">'."\n";
1841 }
1842 }
1843
1844 // Custom CSS
1845 if (getDolGlobalString('MAIN_IHM_CUSTOM_CSS')) {
1846 // If a custom CSS was set, we add link to the custom css php file
1847 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";
1848 }
1849
1850 // Output standard javascript links
1851 if (!defined('DISABLE_JQUERY') && !$disablejs && !empty($conf->use_javascript_ajax)) {
1852 // JQuery. Must be before other includes
1853 print '<!-- Includes JS for JQuery -->'."\n";
1854 if (defined('JS_JQUERY') && constant('JS_JQUERY')) {
1855 print '<script nonce="'.getNonce().'" src="'.JS_JQUERY.'jquery.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1856 } else {
1857 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1858 }
1859 if (!defined('DISABLE_JQUERY_UI')) {
1860 if (defined('JS_JQUERY_UI') && constant('JS_JQUERY_UI')) {
1861 print '<script nonce="' . getNonce() . '" src="' . JS_JQUERY_UI . 'jquery-ui.min.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
1862 } else {
1863 print '<script nonce="' . getNonce() . '" src="' . DOL_URL_ROOT . '/includes/jquery/js/jquery-ui.min.js' . ($ext ? '?' . $ext : '') . '"></script>' . "\n";
1864 }
1865 }
1866 // jQuery jnotify
1867 if (!getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') && !defined('DISABLE_JQUERY_JNOTIFY')) {
1868 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jnotify/jquery.jnotify.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1869 }
1870 // Table drag and drop lines
1871 if (empty($disableforlogin) && !defined('DISABLE_JQUERY_TABLEDND')) {
1872 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/tablednd/jquery.tablednd.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1873 }
1874 // Chart
1875 if (empty($disableforlogin) && (!getDolGlobalString('MAIN_JS_GRAPH') || getDolGlobalString('MAIN_JS_GRAPH') == 'chart') && !defined('DISABLE_JS_GRAPH')) {
1876 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/nnnick/chartjs/dist/chart.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1877 }
1878
1879 // jQuery jeditable for Edit In Place features
1880 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !defined('DISABLE_JQUERY_JEDITABLE')) {
1881 print '<!-- JS to manage editInPlace feature -->'."\n";
1882 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1883 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-datepicker.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1884 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-autocomplete.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1885 print '<script>'."\n";
1886 print 'var urlSaveInPlace = \''.DOL_URL_ROOT.'/core/ajax/saveinplace.php\';'."\n";
1887 print 'var urlLoadInPlace = \''.DOL_URL_ROOT.'/core/ajax/loadinplace.php\';'."\n";
1888 print 'var tooltipInPlace = \''.$langs->transnoentities('ClickToEdit').'\';'."\n"; // Added in title attribute of span
1889 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 ?
1890 print 'var cancelInPlace = \''.$langs->trans("Cancel").'\';'."\n";
1891 print 'var submitInPlace = \''.$langs->trans('Ok').'\';'."\n";
1892 print 'var indicatorInPlace = \'<img src="'.DOL_URL_ROOT."/theme/".$conf->theme."/img/working.gif".'">\';'."\n";
1893 print 'var withInPlace = 300;'; // width in pixel for default string edit
1894 print '</script>'."\n";
1895 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/editinplace.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1896 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ckeditor.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1897 }
1898 // jQuery Timepicker
1899 if (getDolGlobalString('MAIN_USE_JQUERY_TIMEPICKER') || defined('REQUIRE_JQUERY_TIMEPICKER')) {
1900 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/timepicker/jquery-ui-timepicker-addon.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1901 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/timepicker.js.php?lang='.$langs->defaultlang.($ext ? '&amp;'.$ext : '').'"></script>'."\n";
1902 }
1903 if (!defined('DISABLE_SELECT2') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
1904 // jQuery plugin "mutiselect", "multiple-select", "select2", ...
1905 $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT');
1906 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
1907 }
1908 if (!defined('DISABLE_MULTISELECT')) { // jQuery plugin "mutiselect" to select with checkboxes. Can be removed once we have an enhanced search tool
1909 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/multiselect/jquery.multi-select.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1910 }
1911 }
1912
1913 if (!$disablejs && !empty($conf->use_javascript_ajax)) {
1914 // CKEditor
1915 if (empty($disableforlogin) && (isModEnabled('fckeditor') && (!getDolGlobalString('FCKEDITOR_EDITORNAME') || getDolGlobalString('FCKEDITOR_EDITORNAME') == 'ckeditor') && !defined('DISABLE_CKEDITOR')) || defined('FORCE_CKEDITOR')) {
1916 print '<!-- Includes JS for CKEditor -->'."\n";
1917 $pathckeditor = DOL_URL_ROOT.'/includes/ckeditor/ckeditor/';
1918 $jsckeditor = 'ckeditor.js';
1919 if (constant('JS_CKEDITOR')) {
1920 // To use external ckeditor 4 js lib
1921 $pathckeditor = constant('JS_CKEDITOR');
1922 }
1923 print '<script nonce="'.getNonce().'">';
1924 print '/* enable ckeditor by main.inc.php */';
1925 print 'var CKEDITOR_BASEPATH = \''.dol_escape_js($pathckeditor).'\';'."\n";
1926 print 'var ckeditorConfig = \''.dol_escape_js(dol_buildpath($themesubdir.'/theme/'.$conf->theme.'/ckeditor/config.js'.($ext ? '?'.$ext : ''), 1)).'\';'."\n"; // $themesubdir='' in standard usage
1927 print 'var ckeditorFilebrowserBrowseUrl = \''.DOL_URL_ROOT.'/core/filemanagerdol/browser/default/browser.php?Connector='.DOL_URL_ROOT.'/core/filemanagerdol/connectors/php/connector.php\';'."\n";
1928 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";
1929 print '</script>'."\n";
1930 print '<script src="'.$pathckeditor.$jsckeditor.($ext ? '?'.$ext : '').'"></script>'."\n";
1931 print '<script>';
1932 if (GETPOST('mode', 'aZ09') == 'Full_inline') {
1933 print 'CKEDITOR.disableAutoInline = false;'."\n";
1934 } else {
1935 print 'CKEDITOR.disableAutoInline = true;'."\n";
1936 }
1937 print '</script>'."\n";
1938 }
1939
1940 // 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).
1941 if (!defined('NOBROWSERNOTIF') && !defined('NOREQUIREMENU') && !defined('NOLOGIN')) {
1942 $enablebrowsernotif = false;
1943 if (isModEnabled('agenda') && getDolGlobalString('AGENDA_REMINDER_BROWSER')) {
1944 $enablebrowsernotif = true;
1945 }
1946 if ($conf->browser->layout == 'phone') {
1947 $enablebrowsernotif = false;
1948 }
1949 if ($enablebrowsernotif) {
1950 print '<!-- Includes JS of Dolibarr (browser layout = '.$conf->browser->layout.')-->'."\n";
1951 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/lib_notification.js.php?lang='.$langs->defaultlang.($ext ? '&amp;'.$ext : '').'"></script>'."\n";
1952 }
1953 }
1954
1955 // Global js function
1956 print '<!-- Includes JS of Dolibarr -->'."\n";
1957 if (!defined('DISABLE_LIB_HEAD_JS')) {
1958 print '<script nonce="' . getNonce() . '" src="' . DOL_URL_ROOT . '/core/js/lib_head.js.php?lang=' . $langs->defaultlang . ($ext ? '&amp;' . $ext : '') . '"></script>' . "\n";
1959 }
1960
1961 // Leaflet
1962 if (getDolGlobalString('MAIN_USE_GEOPHP')) {
1963 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/leaflet/leaflet.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1964 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/leaflet/leaflet-geoman.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
1965 }
1966
1967 // JS forced by modules (relative url starting with /)
1968 if (!empty($conf->modules_parts['js'])) { // $conf->modules_parts['js'] is array('module'=>array('file1','file2'))
1969 $arrayjs = (array) $conf->modules_parts['js'];
1970 foreach ($arrayjs as $modjs => $filesjs) {
1971 $filesjs = (array) $filesjs; // To be sure filejs is an array
1972 foreach ($filesjs as $jsfile) {
1973 // jsfile is a relative path
1974 $urlforjs = dol_buildpath($jsfile, 1);
1975 if ($urlforjs && $urlforjs != '/') {
1976 print '<!-- Include JS added by module '.$modjs.'-->'."\n";
1977 print '<script nonce="'.getNonce().'" src="'.$urlforjs.((strpos($jsfile, '?') === false) ? '?' : '&amp;').'lang='.$langs->defaultlang.'"></script>'."\n";
1978 } else {
1979 dol_syslog("Warning: module ".$modjs." declared a js path file for a file we can't find.", LOG_WARNING);
1980 }
1981 }
1982 }
1983 }
1984 // JS forced by page in top_htmlhead (relative url starting with /)
1985 if (is_array($arrayofjs)) {
1986 print '<!-- Includes JS added by page -->'."\n";
1987 foreach ($arrayofjs as $jsfile) {
1988 if (preg_match('/^(http|\/\/)/i', $jsfile)) {
1989 print '<script nonce="'.getNonce().'" src="'.$jsfile.((strpos($jsfile, '?') === false) ? '?' : '&amp;').'lang='.$langs->defaultlang.'"></script>'."\n";
1990 } else {
1991 print '<script nonce="'.getNonce().'" src="'.dol_buildpath($jsfile, 1).((strpos($jsfile, '?') === false) ? '?' : '&amp;').'lang='.$langs->defaultlang.'"></script>'."\n";
1992 }
1993 }
1994 }
1995 }
1996
1997 //If you want to load custom javascript file from your selected theme directory
1998 if (getDolGlobalString('ALLOW_THEME_JS')) {
1999 $theme_js = dol_buildpath('/theme/'.$conf->theme.'/'.$conf->theme.'.js', 0);
2000 if (file_exists($theme_js)) {
2001 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/'.$conf->theme.'.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2002 }
2003 }
2004
2005 if (!empty($head)) {
2006 print $head."\n";
2007 }
2008 if (getDolGlobalString('MAIN_HTML_HEADER')) {
2009 print getDolGlobalString('MAIN_HTML_HEADER') . "\n";
2010 }
2011
2012 $parameters = array();
2013 $result = $hookmanager->executeHooks('addHtmlHeader', $parameters); // Note that $action and $object may have been modified by some hooks
2014 print $hookmanager->resPrint; // Replace Title to show
2015
2016 print "</head>\n\n";
2017 }
2018
2019 $conf->headerdone = 1; // To tell header was output
2020}
2021
2022
2039function top_menu($head, $title = '', $target = '', $disablejs = 0, $disablehead = 0, $arrayofjs = array(), $arrayofcss = array(), $morequerystring = '', $helppagename = '')
2040{
2041 global $user, $conf, $langs, $db, $form;
2042 global $dolibarr_main_authentication, $dolibarr_main_demo;
2043 global $hookmanager, $menumanager;
2044
2045 $searchform = '';
2046
2047 // Instantiate hooks for external modules
2048 $hookmanager->initHooks(array('toprightmenu'));
2049
2050 $toprightmenu = '';
2051
2052 // For backward compatibility with old modules
2053 if (empty($conf->headerdone)) {
2054 $disablenofollow = 0;
2055 top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss, 0, $disablenofollow);
2056 print '<body id="mainbody">';
2057 }
2058
2059 /*
2060 * Top menu
2061 */
2062 if ((empty($conf->dol_hide_topmenu) || GETPOSTINT('dol_invisible_topmenu')) && (!defined('NOREQUIREMENU') || !constant('NOREQUIREMENU'))) {
2063 if (!isset($form) || !is_object($form)) {
2064 include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
2065 $form = new Form($db);
2066 }
2067
2068 print "\n".'<!-- Start top horizontal -->'."\n";
2069
2070 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.
2071
2072 // Show menu entries
2073 print '<div id="tmenu_tooltip'.(!getDolGlobalString('MAIN_MENU_INVERT') ? '' : 'invert').'" class="tmenu">'."\n";
2074 // @phan-suppress-next-line PhanRedefinedClassReference
2075 $menumanager->atarget = $target;
2076 // @phan-suppress-next-line PhanRedefinedClassReference
2077 $menumanager->showmenu('top', array('searchform' => $searchform)); // This contains a \n
2078 print "</div>\n";
2079
2080 // Define link to login card
2081 $appli = constant('DOL_APPLICATION_TITLE');
2082 $applicustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
2083 if ($applicustom) {
2084 $appli = (preg_match('/^\+/', $applicustom) ? $appli : '').$applicustom;
2085 } else {
2086 $appli .= " ".DOL_VERSION;
2087 }
2088
2089 if (getDolGlobalInt('MAIN_FEATURES_LEVEL')) {
2090 $appli .= "<br>".$langs->trans("LevelOfFeature").': '.getDolGlobalInt('MAIN_FEATURES_LEVEL');
2091 }
2092
2093 $logouttext = '';
2094 $logouthtmltext = '';
2095 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2096 //$logouthtmltext=$appli.'<br>';
2097 $stringforfirstkey = $langs->trans("KeyboardShortcut");
2098 if ($conf->browser->name == 'chrome') {
2099 $stringforfirstkey .= ' ALT +';
2100 } elseif ($conf->browser->name == 'firefox') {
2101 $stringforfirstkey .= ' ALT + SHIFT +';
2102 } else {
2103 $stringforfirstkey .= ' CTL +';
2104 }
2105 if ($_SESSION["dol_authmode"] != 'forceuser' && $_SESSION["dol_authmode"] != 'http') {
2106 $logouthtmltext .= $langs->trans("Logout").'<br>';
2107 $logouttext .= '<a accesskey="l" href="'.DOL_URL_ROOT.'/user/logout.php?token='.newToken().'">';
2108 $logouttext .= img_picto($langs->trans('Logout').' ('.$stringforfirstkey.' l)', 'sign-out', '', 0, 0, 0, '', 'atoplogin valignmiddle');
2109 $logouttext .= '</a>';
2110 } else {
2111 $logouthtmltext .= $langs->trans("NoLogoutProcessWithAuthMode", $_SESSION["dol_authmode"]);
2112 $logouttext .= img_picto($langs->trans('Logout').' ('.$stringforfirstkey.' l)', 'sign-out', '', 0, 0, 0, '', 'atoplogin valignmiddle opacitymedium');
2113 }
2114 }
2115
2116
2117 print '<div class="login_block usedropdown">'."\n";
2118
2119
2120 // Add block for tools
2121 $toprightmenu .= '<div class="login_block_tools valignmiddle">';
2122
2123 $mode = -1;
2124 $toprightmenu .= '<div class="inline-block nowrap" style="padding: 0px;">';
2125
2126 if (getDolGlobalString('MAIN_USE_TOP_MENU_SEARCH_DROPDOWN')) {
2127 // Add search dropdown
2128 $toprightmenu .= top_menu_search();
2129 }
2130
2131 if (getDolGlobalString('MAIN_USE_TOP_MENU_QUICKADD_DROPDOWN')) {
2132 // Add the quick add object dropdown
2133 $toprightmenu .= top_menu_quickadd();
2134 }
2135
2136 // Add bookmark dropdown
2137 $toprightmenu .= top_menu_bookmark();
2138
2139 if (getDolGlobalString('MAIN_USE_TOP_MENU_IMPORT_FILE')) {
2140 // Add the import file link
2141 $toprightmenu .= top_menu_importfile();
2142 }
2143
2144 $toprightmenu .= '</div>';
2145
2146 $toprightmenu .= '</div>'."\n"; // end div class="login_block_tools"
2147
2148
2149 // Add block for other tools
2150 $toprightmenu .= '<div class="login_block_other valignmiddle">';
2151
2152 // Execute hook printTopRightMenu (hooks should output string like '<div class="login"><a href="">mylink</a></div>')
2153 $parameters = array();
2154 $result = $hookmanager->executeHooks('printTopRightMenu', $parameters); // Note that $action and $object may have been modified by some hooks
2155 if (is_numeric($result)) {
2156 if ($result == 0) {
2157 $toprightmenu .= $hookmanager->resPrint; // add
2158 } else {
2159 $toprightmenu = $hookmanager->resPrint; // replace
2160 }
2161 } else {
2162 $toprightmenu .= $result; // For backward compatibility
2163 }
2164
2165 // Link to module builder
2166 if (isModEnabled('modulebuilder')) {
2167 $text = '<a href="'.DOL_URL_ROOT.'/modulebuilder/index.php?mainmenu=home&leftmenu=admintools" target="modulebuilder">';
2168 //$text.= img_picto(":".$langs->trans("ModuleBuilder"), 'printer_top.png', 'class="printer"');
2169 $text .= '<span class="fa fa-bug atoplogin valignmiddle"></span>';
2170 $text .= '</a>';
2171 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
2172 $toprightmenu .= $form->textwithtooltip('', $langs->trans("ModuleBuilder"), 2, 1, $text, 'login_block_elem', 2);
2173 }
2174
2175 // Link to print main content area (optioncss=print)
2176 if (!getDolGlobalString('MAIN_PRINT_DISABLELINK') && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2177 $qs = dol_escape_htmltag($_SERVER["QUERY_STRING"]);
2178
2179 if (isset($_POST) && is_array($_POST)) {
2180 foreach ($_POST as $key => $value) {
2181 $key = preg_replace('/[^a-z0-9_\.\-\[\]]/i', '', $key);
2182 if (in_array($key, array('action', 'massaction', 'password'))) {
2183 continue;
2184 }
2185 if (!is_array($value)) {
2186 if ($value !== '') {
2187 $qs .= '&'.urlencode($key).'='.urlencode($value);
2188 }
2189 } else {
2190 foreach ($value as $value2) {
2191 if (($value2 !== '') && (!is_array($value2))) {
2192 $qs .= '&'.urlencode($key).'[]='.urlencode($value2);
2193 }
2194 }
2195 }
2196 }
2197 }
2198 $qs .= (($qs && $morequerystring) ? '&' : '').$morequerystring;
2199 $text = '<a href="'.dol_escape_htmltag($_SERVER["PHP_SELF"]).'?'.$qs.($qs ? '&' : '').'optioncss=print" target="_blank" rel="noopener noreferrer">';
2200 //$text.= img_picto(":".$langs->trans("PrintContentArea"), 'printer_top.png', 'class="printer"');
2201 $text .= '<span class="fa fa-print atoplogin valignmiddle"></span>';
2202 $text .= '</a>';
2203 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
2204 $toprightmenu .= $form->textwithtooltip('', $langs->trans("PrintContentArea"), 2, 1, $text, 'login_block_elem', 2);
2205 }
2206
2207 // Link to Dolibarr wiki pages
2208 if (!getDolGlobalString('MAIN_HELP_DISABLELINK') && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2209 $langs->load("help");
2210
2211 $helpbaseurl = '';
2212 $helppage = '';
2213 $mode = '';
2214 $helppresent = '';
2215
2216 if (empty($helppagename)) {
2217 $helppagename = 'EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios|DE:Benutzerdokumentation';
2218 } else {
2219 $helppresent = 'helppresent';
2220 }
2221
2222 // Get helpbaseurl, helppage and mode from helppagename and langs
2223 $arrayres = getHelpParamFor($helppagename, $langs);
2224 $helpbaseurl = $arrayres['helpbaseurl'];
2225 $helppage = $arrayres['helppage'];
2226 $mode = $arrayres['mode'];
2227
2228 // Link to help pages
2229 if ($helpbaseurl && $helppage) {
2230 $text = '';
2231 $title = $langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage' : 'GoToHelpPage').', ';
2232 if ($mode == 'wiki') {
2233 $title .= '<br>'.img_picto('', 'globe', 'class="pictofixedwidth"').$langs->trans("PageWiki").' '.dol_escape_htmltag('"'.strtr($helppage, '_', ' ').'"');
2234 if ($helppresent) {
2235 $title .= ' <span class="opacitymedium">('.$langs->trans("DedicatedPageAvailable").')</span>';
2236 } else {
2237 $title .= ' <span class="opacitymedium">('.$langs->trans("HomePage").')</span>';
2238 }
2239 }
2240 $text .= '<a class="help" target="_blank" rel="noopener noreferrer" href="';
2241 if ($mode == 'wiki') {
2242 // @phan-suppress-next-line PhanPluginPrintfVariableFormatString
2243 $text .= sprintf($helpbaseurl, urlencode(html_entity_decode($helppage)));
2244 } else {
2245 // @phan-suppress-next-line PhanPluginPrintfVariableFormatString
2246 $text .= sprintf($helpbaseurl, $helppage);
2247 }
2248 $text .= '">';
2249 $text .= '<span class="fa fa-question-circle atoplogin valignmiddle'.($helppresent ? ' '.$helppresent : '').'"></span>';
2250 $text .= '<span class="fa fa-long-arrow-alt-up helppresentcircle'.($helppresent ? '' : ' unvisible').'"></span>';
2251 $text .= '</a>';
2252 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
2253 $toprightmenu .= $form->textwithtooltip('', $title, 2, 1, $text, 'login_block_elem', 2);
2254 }
2255
2256 // Version
2257 if (getDolGlobalString('MAIN_SHOWDATABASENAMEINHELPPAGESLINK')) {
2258 $langs->load('admin');
2259 $appli .= '<br>'.$langs->trans("Database").': '.$db->database_name;
2260 }
2261 }
2262
2263 // Version
2264 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && getDolGlobalInt('MAIN_HIDE_VERSION') == 0) {
2265 $text = '<span class="aversion"><span class="hideonsmartphone small">'.DOL_VERSION.'</span></span>';
2266 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
2267 $toprightmenu .= $form->textwithtooltip('', $appli, 2, 1, $text, 'login_block_elem', 2);
2268 }
2269
2270 // Logout link
2271 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2272 $toprightmenu .= $form->textwithtooltip('', $logouthtmltext, 2, 1, $logouttext, 'login_block_elem logout-btn', 2);
2273 }
2274
2275 $toprightmenu .= '</div>'; // end div class="login_block_other"
2276
2277
2278 // Add block for user photo and name
2279 $toprightmenu .= '<div class="login_block_user">';
2280
2281 $mode = -1;
2282 $toprightmenu .= '<div class="inline-block login_block_elem login_block_elem_name nowrap centpercent" style="padding: 0px;">';
2283
2284 // Add user dropdown
2285 $toprightmenu .= top_menu_user();
2286
2287 $toprightmenu .= '</div>';
2288
2289 $toprightmenu .= '</div>'."\n";
2290
2291
2292 print $toprightmenu;
2293
2294 print "</div>\n"; // end div class="login_block"
2295
2296 print '</header>';
2297 //print '<header class="header2">&nbsp;</header>';
2298
2299 print '<div style="clear: both;"></div>';
2300 print "<!-- End top horizontal menu -->\n\n";
2301 }
2302
2303 if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) {
2304 print '<!-- Begin div id-container --><div id="id-container" class="id-container">';
2305 }
2306}
2307
2308
2316function top_menu_user($hideloginname = 0, $urllogout = '')
2317{
2318 global $langs, $conf, $db, $hookmanager, $user, $mysoc;
2319 global $dolibarr_main_authentication, $dolibarr_main_demo;
2320 global $menumanager, $form;
2321
2322 // Return empty in some case
2323 if ($conf->browser->name == 'textbrowser') {
2324 return '';
2325 }
2326
2327 $langs->load('companies');
2328
2329 $userImage = $userDropDownImage = '';
2330 if (!empty($user->photo) || isModEnabled('gravatar')) {
2331 $userImage = Form::showphoto('userphoto', $user, 0, 0, 0, 'photouserphoto userphoto', 'small', 0, 1);
2332 $userDropDownImage = Form::showphoto('userphoto', $user, 0, 0, 0, 'dropdown-user-image', 'small', 0, 1);
2333 } else {
2334 $nophoto = '/public/theme/common/user_anonymous.png';
2335 if ($user->gender == 'man') {
2336 $nophoto = '/public/theme/common/user_man.png';
2337 }
2338 if ($user->gender == 'woman') {
2339 $nophoto = '/public/theme/common/user_woman.png';
2340 }
2341
2342 $userImage = '<img class="photo photouserphoto userphoto" alt="" src="'.DOL_URL_ROOT.$nophoto.'" aria-hidden="true">';
2343 $userDropDownImage = '<img class="photo dropdown-user-image" alt="" src="'.DOL_URL_ROOT.$nophoto.'">';
2344 }
2345
2346 $dropdownBody = '';
2347 $dropdownBody .= '<span id="topmenulogincompanyinfo-btn"><i class="fa fa-caret-right"></i> '.$langs->trans("ShowCompanyInfos").'</span>';
2348 $dropdownBody .= '<div id="topmenulogincompanyinfo" >';
2349
2350 $dropdownBody .= '<br><b>'.$langs->trans("Company").'</b>: <span>'.dol_escape_htmltag($mysoc->name).'</span>';
2351 $idprofcursor = 0;
2352 while ($idprofcursor < 10) {
2353 $idprofcursor++;
2354 $constkeyforprofid = 'MAIN_INFO_PROFID'.$idprofcursor;
2355 if ($idprofcursor == 1) {
2356 $constkeyforprofid = 'MAIN_INFO_SIREN';
2357 }
2358 if ($idprofcursor == 2) {
2359 $constkeyforprofid = 'MAIN_INFO_SIRET';
2360 }
2361 if ($idprofcursor == 3) {
2362 $constkeyforprofid = 'MAIN_INFO_APE';
2363 }
2364 if ($idprofcursor == 4) {
2365 $constkeyforprofid = 'MAIN_INFO_RCS';
2366 }
2367 $showprofid = (($idprofcursor <= 6) && $langs->transcountry("ProfId".$idprofcursor, $mysoc->country_code) != '-');
2368 if ($idprofcursor > 6 && getDolGlobalString($constkeyforprofid)) {
2369 $showprofid = true;
2370 }
2371 if ($showprofid) {
2372 $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId".$idprofcursor, $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString($constkeyforprofid), '1').'</span>';
2373 }
2374 }
2375 $dropdownBody .= '<br><b>'.$langs->trans("VATIntraShort").'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_TVAINTRA"), 'VAT').'</span>';
2376 $dropdownBody .= '<br><b>'.$langs->trans("Country").'</b>: <span>'.($mysoc->country_code ? $langs->trans("Country".$mysoc->country_code) : '').'</span>';
2377 if (isModEnabled('multicurrency')) {
2378 $dropdownBody .= '<br><b>'.$langs->trans("Currency").'</b>: <span>'.$conf->currency.'</span>';
2379 }
2380 $dropdownBody .= '</div>';
2381
2382 $dropdownBody .= '<br>';
2383 $dropdownBody .= '<span id="topmenuloginmoreinfo-btn"><i class="fa fa-caret-right"></i> '.$langs->trans("ShowMoreInfos").'</span>';
2384 $dropdownBody .= '<div id="topmenuloginmoreinfo" >';
2385
2386 // login infos
2387 if (!empty($user->admin)) {
2388 $dropdownBody .= '<br><b>'.$langs->trans("Administrator").'</b>: '.yn($user->admin);
2389 }
2390 $company = '';
2391 if (!empty($user->socid)) { // Add third party for external users
2392 $thirdpartystatic = new Societe($db);
2393 $thirdpartystatic->fetch($user->socid);
2394 $companylink = ' '.$thirdpartystatic->getNomUrl(2); // picto only of company
2395 $company = ' ('.$langs->trans("Company").': '.$thirdpartystatic->name.')';
2396 }
2397 $type = ($user->socid ? $langs->trans("External").$company : $langs->trans("Internal"));
2398 $dropdownBody .= '<br><b>'.$langs->trans("Type").':</b> '.$type;
2399 $dropdownBody .= '<br><b>'.$langs->trans("Status").'</b>: '.$user->getLibStatut(0);
2400 $dropdownBody .= '<br>';
2401
2402 $dropdownBody .= '<br><u>'.$langs->trans("Session").'</u>';
2403 $dropdownBody .= '<br><b>'.$langs->trans("IPAddress").'</b>: '.dol_escape_htmltag($_SERVER["REMOTE_ADDR"]);
2404 if (getDolGlobalString('MAIN_MODULE_MULTICOMPANY')) {
2405 $dropdownBody .= '<br><b>'.$langs->trans("ConnectedOnMultiCompany").':</b> '.$conf->entity.' (user entity '.$user->entity.')';
2406 }
2407 $dropdownBody .= '<br><b>'.$langs->trans("AuthenticationMode").':</b> '.$_SESSION["dol_authmode"].(empty($dolibarr_main_demo) ? '' : ' (demo)');
2408 $dropdownBody .= '<br><b>'.$langs->trans("ConnectedSince").':</b> '.dol_print_date($user->datelastlogin, "dayhour", 'tzuser');
2409 $dropdownBody .= '<br><b>'.$langs->trans("PreviousConnexion").':</b> '.dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser');
2410 $dropdownBody .= '<br><b>'.$langs->trans("CurrentTheme").':</b> '.$conf->theme;
2411 // @phan-suppress-next-line PhanRedefinedClassReference
2412 $dropdownBody .= '<br><b>'.$langs->trans("CurrentMenuManager").':</b> '.(isset($menumanager) ? $menumanager->name : 'unknown');
2413 $langFlag = picto_from_langcode($langs->getDefaultLang());
2414 $dropdownBody .= '<br><b>'.$langs->trans("CurrentUserLanguage").':</b> '.($langFlag ? $langFlag.' ' : '').$langs->getDefaultLang();
2415
2416 $tz = (int) $_SESSION['dol_tz'] + (int) $_SESSION['dol_dst'];
2417 $dropdownBody .= '<br><b>'.$langs->trans("ClientTZ").':</b> '.($tz ? ($tz >= 0 ? '+' : '').$tz : '');
2418 $dropdownBody .= ' <span class="opacitymedium">('.$_SESSION['dol_tz_string'].')</span>';
2419 //$dropdownBody .= ' &nbsp; &nbsp; &nbsp; '.$langs->trans("DaylingSavingTime").': ';
2420 //if ($_SESSION['dol_dst'] > 0) $dropdownBody .= yn(1);
2421 //else $dropdownBody .= yn(0);
2422
2423 $dropdownBody .= '<br><b>'.$langs->trans("Browser").':</b> '.ucfirst($conf->browser->name).($conf->browser->version ? ' '.$conf->browser->version : '');
2424 $dropdownBody .= $form->textwithpicto('', dol_escape_htmltag($_SERVER['HTTP_USER_AGENT']), 1, 'help', 'valignmiddle', 0, 3, 'useragent');
2425 $dropdownBody .= '<br><b>'.$langs->trans("Layout").':</b> '.$conf->browser->layout;
2426 $dropdownBody .= '<br><b>'.$langs->trans("Screen").':</b> '.$_SESSION['dol_screenwidth'].' x '.$_SESSION['dol_screenheight'];
2427 if ($conf->browser->layout == 'phone') {
2428 $dropdownBody .= '<br><b>'.$langs->trans("Phone").':</b> '.$langs->trans("Yes");
2429 }
2430 if (!empty($_SESSION["disablemodules"])) {
2431 $dropdownBody .= '<br><b>'.$langs->trans("DisabledModules").':</b> <br>'.implode(', ', explode(',', $_SESSION["disablemodules"]));
2432 }
2433 $dropdownBody .= '</div>';
2434
2435 // Execute hook
2436 $parameters = array('user' => $user, 'langs' => $langs);
2437 $result = $hookmanager->executeHooks('printTopRightMenuLoginDropdownBody', $parameters); // Note that $action and $object may have been modified by some hooks
2438 if (is_numeric($result)) {
2439 if ($result == 0) {
2440 $dropdownBody .= $hookmanager->resPrint; // add
2441 } else {
2442 $dropdownBody = $hookmanager->resPrint; // replace
2443 }
2444 }
2445
2446 if (empty($urllogout)) {
2447 $urllogout = DOL_URL_ROOT.'/user/logout.php?token='.newToken();
2448 }
2449
2450 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
2451 // accesskey is for Mac: CTRL + key for all browsers
2452 $stringforfirstkey = $langs->trans("KeyboardShortcut");
2453 if ($conf->browser->name == 'chrome') {
2454 $stringforfirstkey .= ' ALT +';
2455 } elseif ($conf->browser->name == 'firefox') {
2456 $stringforfirstkey .= ' ALT + SHIFT +';
2457 } else {
2458 $stringforfirstkey .= ' CTL +';
2459 }
2460
2461 // Defined the links for bottom of card
2462 $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>';
2463 $urltovirtualcard = '/user/virtualcard.php?id='.((int) $user->id);
2464 $jsonopen = "closeTopMenuLoginDropdown()";
2465 $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');
2466 $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>';
2467
2468 $profilName = $user->getFullName($langs).' ('.$user->login.')';
2469 if (!empty($user->admin)) {
2470 $profilName = '<i class="far fa-star classfortooltip" title="'.$langs->trans("Administrator").'" ></i> '.$profilName;
2471 }
2472
2473 // Define version to show
2474 $appli = constant('DOL_APPLICATION_TITLE');
2475 $applicustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
2476 if ($applicustom) {
2477 $appli = (preg_match('/^\+/', $applicustom) ? $appli : '').$applicustom;
2478 } else {
2479 $appli .= " ".DOL_VERSION;
2480 }
2481
2482 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2483 $btnUser = '<!-- div for user link -->
2484 <div id="topmenu-login-dropdown" class="userimg atoplogin dropdown user user-menu inline-block">
2485 <a href="'.DOL_URL_ROOT.'/user/card.php?id='.$user->id.'" class="dropdown-toggle login-dropdown-a valignmiddle" data-toggle="dropdown">
2486 '.$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>' : '').'
2487 </a>
2488 <div class="dropdown-menu">
2489 <!-- User image -->
2490 <div class="user-header">
2491 '.$userDropDownImage.'
2492 <p>
2493 '.$profilName.'<br>';
2494 $title = '';
2495 if ($user->datelastlogin) {
2496 $title = $langs->trans("ConnectedSince").' : '.dol_print_date($user->datelastlogin, "dayhour", 'tzuser');
2497 if ($user->datepreviouslogin) {
2498 $title .= '<br>'.$langs->trans("PreviousConnexion").' : '.dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser');
2499 }
2500 }
2501 $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>';
2502 if ($user->datepreviouslogin) {
2503 $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>';
2504 }
2505
2506 //$btnUser .= '<small class="classfortooltip"><i class="fa fa-cog"></i> '.$langs->trans("Version").' '.$appli.'</small>';
2507 $btnUser .= '
2508 </p>
2509 </div>
2510
2511 <!-- Menu Body user-->
2512 <div class="user-body">'.$dropdownBody.'</div>
2513
2514 <!-- Menu Footer-->
2515 <div class="user-footer">
2516 <div class="pull-left">
2517 '.$profilLink.'
2518 </div>
2519 <div class="pull-left">
2520 '.$virtuelcardLink.'
2521 </div>
2522 <div class="pull-right">
2523 '.$logoutLink.'
2524 </div>
2525 <div class="clearboth"></div>
2526 </div>
2527
2528 </div>
2529 </div>';
2530 } else {
2531 $btnUser = '<!-- div for user link text browser -->
2532 <div id="topmenu-login-dropdown" class="userimg atoplogin dropdown user user-menu inline-block">
2533 <a href="'.DOL_URL_ROOT.'/user/card.php?id='.$user->id.'" class="valignmiddle" alt="'.$langs->trans("MyUserCard").'">
2534 '.$userImage.(empty($user->photo) ? '<span class="hidden-xs maxwidth200 atoploginusername hideonsmartphone paddingleft small valignmiddle">'.dol_trunc($user->firstname ? $user->firstname : $user->login, 10).'</span>' : '').'
2535 </a>
2536 </div>';
2537 }
2538
2539 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
2540 $btnUser .= '
2541 <!-- Code to show/hide the user drop-down -->
2542 <script>
2543 function closeTopMenuLoginDropdown() {
2544 console.log("close login dropdown"); // This is called at each click on page, so we disable the log
2545 // Hide the menus.
2546 jQuery("#topmenu-login-dropdown").removeClass("open");
2547 }
2548 jQuery(document).ready(function() {
2549 jQuery(document).on("click", function(event) {
2550 if (!$(event.target).closest("#topmenu-login-dropdown").length) {
2551 /* console.log("click close login - we click outside"); */
2552 closeTopMenuLoginDropdown();
2553 }
2554 });
2555 ';
2556
2557
2558 $btnUser .= '
2559 jQuery("#topmenu-login-dropdown .dropdown-toggle").on("click", function(event) {
2560 console.log("Click on #topmenu-login-dropdown .dropdown-toggle");
2561 event.preventDefault();
2562 jQuery("#topmenu-login-dropdown").toggleClass("open");
2563 });
2564
2565 jQuery("#topmenulogincompanyinfo-btn").on("click", function() {
2566 console.log("Click on #topmenulogincompanyinfo-btn");
2567 if (!jQuery("#topmenuloginmoreinfo").is(\':hidden\')) {
2568 jQuery("#topmenuloginmoreinfo").slideToggle();
2569 }
2570 jQuery("#topmenulogincompanyinfo").slideToggle();
2571 });
2572
2573 jQuery("#topmenuloginmoreinfo-btn").on("click", function() {
2574 console.log("Click on #topmenuloginmoreinfo-btn");
2575 if (!jQuery("#topmenulogincompanyinfo").is(\':hidden\')) {
2576 jQuery("#topmenulogincompanyinfo").slideToggle();
2577 }
2578 jQuery("#topmenuloginmoreinfo").slideToggle();
2579 });';
2580
2581 $btnUser .= '
2582 });
2583 </script>
2584 ';
2585 }
2586
2587 return $btnUser;
2588}
2589
2597{
2598 global $conf, $langs;
2599
2600 // Button disabled on text browser
2601 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2602 return '';
2603 }
2604
2605 $html = '';
2606
2607 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
2608 // accesskey is for Mac: CTRL + key for all browsers
2609 $stringforfirstkey = $langs->trans("KeyboardShortcut");
2610 if ($conf->browser->os === 'macintosh') {
2611 $stringforfirstkey .= ' CTL +';
2612 } else {
2613 if ($conf->browser->name == 'chrome') {
2614 $stringforfirstkey .= ' ALT +';
2615 } elseif ($conf->browser->name == 'firefox') {
2616 $stringforfirstkey .= ' ALT + SHIFT +';
2617 } else {
2618 $stringforfirstkey .= ' CTL +';
2619 }
2620 }
2621
2622 if (!empty($conf->use_javascript_ajax)) {
2623 $html .= '<!-- div for quick add link -->
2624 <div id="topmenu-quickadd-dropdown" class="atoplogin dropdown inline-block">
2625 <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>
2626 <div class="dropdown-menu">'.printDropdownQuickadd().'</div>
2627 </div>';
2628 if (!defined('JS_JQUERY_DISABLE_DROPDOWN')) { // This may be set by some pages that use different jquery version to avoid errors
2629 $html .= '
2630 <!-- Code to show/hide the user drop-down for the quick add -->
2631 <script>
2632 jQuery(document).ready(function() {
2633 jQuery(document).on("click", function(event) {
2634 if (!$(event.target).closest("#topmenu-quickadd-dropdown").length) {
2635 /* console.log("click close quick add - we click outside"); */
2636 // Hide the menus.
2637 $("#topmenu-quickadd-dropdown").removeClass("open");
2638 }
2639 });
2640 $("#topmenu-quickadd-dropdown .dropdown-toggle").on("click", function(event) {
2641 console.log("Click on #topmenu-quickadd-dropdown .dropdown-toggle");
2642 openQuickAddDropDown(event);
2643 });
2644
2645 // Key map shortcut
2646 $(document).keydown(function(event){
2647 var ostype = \''.dol_escape_js($conf->browser->os).'\';
2648 if (ostype === "macintosh") {
2649 if ( event.which === 65 && event.ctrlKey ) {
2650 console.log(\'control + a : trigger open quick add dropdown\');
2651 openQuickAddDropDown(event);
2652 }
2653 } else {
2654 if ( event.which === 65 && event.ctrlKey && event.shiftKey ) {
2655 console.log(\'control + shift + a : trigger open quick add dropdown\');
2656 openQuickAddDropDown(event);
2657 }
2658 }
2659 });
2660
2661 var openQuickAddDropDown = function(event) {
2662 event.preventDefault();
2663 $("#topmenu-quickadd-dropdown").toggleClass("open");
2664 }
2665 });
2666 </script>
2667 ';
2668 }
2669 }
2670
2671 return $html;
2672}
2673
2674
2682{
2683 global $conf, $langs;
2684
2685 // Button disabled on text browser
2686 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2687 return '';
2688 }
2689
2690 $html = '';
2691
2692 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
2693 // accesskey is for Mac: CTRL + key for all browsers
2694 $stringforfirstkey = $langs->trans("KeyboardShortcut");
2695 if ($conf->browser->os === 'macintosh') {
2696 $stringforfirstkey .= ' CTL +';
2697 } else {
2698 if ($conf->browser->name == 'chrome') {
2699 $stringforfirstkey .= ' ALT +';
2700 } elseif ($conf->browser->name == 'firefox') {
2701 $stringforfirstkey .= ' ALT + SHIFT +';
2702 } else {
2703 $stringforfirstkey .= ' CTL +';
2704 }
2705 }
2706
2707
2708 if (!empty($conf->use_javascript_ajax)) {
2709 $urlforuploadpage = DOL_URL_ROOT.'/core/upload_page.php';
2710 if (!is_numeric(getDolGlobalString('MAIN_USE_TOP_MENU_IMPORT_FILE'))) {
2711 $urlforuploadpage = getDolGlobalString('MAIN_USE_TOP_MENU_IMPORT_FILE');
2712 }
2713
2714 $html .= '<!-- div for link to upload file -->
2715 <div id="topmenu-uploadfile-dropdown" class="atoplogin dropdown inline-block">
2716 <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>
2717 </div>';
2718 }
2719
2720 return $html;
2721}
2722
2723
2730function printDropdownQuickadd($mode = 0)
2731{
2732 global $user, $langs, $hookmanager;
2733
2734 $items = array(
2735 'items' => array(
2736 array(
2737 "url" => "/adherents/card.php?action=create&amp;mainmenu=members",
2738 "title" => "MenuNewMember@members",
2739 "name" => "Adherent@members",
2740 "picto" => "object_member",
2741 "activation" => isModEnabled('member') && $user->hasRight("adherent", "write"), // vs hooking
2742 "position" => 5,
2743 ),
2744 array(
2745 "url" => "/societe/card.php?action=create&amp;mainmenu=companies",
2746 "title" => "MenuNewThirdParty@companies",
2747 "name" => "ThirdParty@companies",
2748 "picto" => "object_company",
2749 "activation" => isModEnabled("societe") && $user->hasRight("societe", "write"), // vs hooking
2750 "position" => 10,
2751 ),
2752 array(
2753 "url" => "/contact/card.php?action=create&amp;mainmenu=companies",
2754 "title" => "NewContactAddress@companies",
2755 "name" => "Contact@companies",
2756 "picto" => "object_contact",
2757 "activation" => isModEnabled("societe") && $user->hasRight("societe", "contact", "write"), // vs hooking
2758 "position" => 20,
2759 ),
2760 array(
2761 "url" => "/comm/propal/card.php?action=create&amp;mainmenu=commercial",
2762 "title" => "NewPropal@propal",
2763 "name" => "Proposal@propal",
2764 "picto" => "object_propal",
2765 "activation" => isModEnabled("propal") && $user->hasRight("propal", "write"), // vs hooking
2766 "position" => 30,
2767 ),
2768
2769 array(
2770 "url" => "/commande/card.php?action=create&amp;mainmenu=commercial",
2771 "title" => "NewOrder@orders",
2772 "name" => "Order@orders",
2773 "picto" => "object_order",
2774 "activation" => isModEnabled('order') && $user->hasRight("commande", "write"), // vs hooking
2775 "position" => 40,
2776 ),
2777 array(
2778 "url" => "/compta/facture/card.php?action=create&amp;mainmenu=billing",
2779 "title" => "NewBill@bills",
2780 "name" => "Bill@bills",
2781 "picto" => "object_bill",
2782 "activation" => isModEnabled('invoice') && $user->hasRight("facture", "write"), // vs hooking
2783 "position" => 50,
2784 ),
2785 array(
2786 "url" => "/contrat/card.php?action=create&amp;mainmenu=commercial",
2787 "title" => "NewContractSubscription@contracts",
2788 "name" => "Contract@contracts",
2789 "picto" => "object_contract",
2790 "activation" => isModEnabled('contract') && $user->hasRight("contrat", "write"), // vs hooking
2791 "position" => 60,
2792 ),
2793 array(
2794 "url" => "/supplier_proposal/card.php?action=create&amp;mainmenu=commercial",
2795 "title" => "SupplierProposalNew@supplier_proposal",
2796 "name" => "SupplierProposal@supplier_proposal",
2797 "picto" => "supplier_proposal",
2798 "activation" => isModEnabled('supplier_proposal') && $user->hasRight("supplier_invoice", "write"), // vs hooking
2799 "position" => 70,
2800 ),
2801 array(
2802 "url" => "/fourn/commande/card.php?action=create&amp;mainmenu=commercial",
2803 "title" => "NewSupplierOrderShort@orders",
2804 "name" => "SupplierOrder@orders",
2805 "picto" => "supplier_order",
2806 "activation" => (isModEnabled("fournisseur") && !getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "commande", "write")) || (isModEnabled("supplier_order") && $user->hasRight("supplier_invoice", "write")), // vs hooking
2807 "position" => 80,
2808 ),
2809 array(
2810 "url" => "/fourn/facture/card.php?action=create&amp;mainmenu=billing",
2811 "title" => "NewBill@bills",
2812 "name" => "SupplierBill@bills",
2813 "picto" => "supplier_invoice",
2814 "activation" => (isModEnabled("fournisseur") && !getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "write")) || (isModEnabled("supplier_invoice") && $user->hasRight("supplier_invoice", "write")), // vs hooking
2815 "position" => 90,
2816 ),
2817 array(
2818 "url" => "/ticket/card.php?action=create&amp;mainmenu=ticket",
2819 "title" => "NewTicket@ticket",
2820 "name" => "Ticket@ticket",
2821 "picto" => "ticket",
2822 "activation" => isModEnabled('ticket') && $user->hasRight("ticket", "write"), // vs hooking
2823 "position" => 100,
2824 ),
2825 array(
2826 "url" => "/fichinter/card.php?action=create&mainmenu=commercial",
2827 "title" => "NewIntervention@interventions",
2828 "name" => "Intervention@interventions",
2829 "picto" => "intervention",
2830 "activation" => isModEnabled('intervention') && $user->hasRight("ficheinter", "creer"), // vs hooking
2831 "position" => 110,
2832 ),
2833 array(
2834 "url" => "/product/card.php?action=create&amp;type=0&amp;mainmenu=products",
2835 "title" => "NewProduct@products",
2836 "name" => "Product@products",
2837 "picto" => "object_product",
2838 "activation" => isModEnabled("product") && $user->hasRight("produit", "write"), // vs hooking
2839 "position" => 400,
2840 ),
2841 array(
2842 "url" => "/product/card.php?action=create&amp;type=1&amp;mainmenu=products",
2843 "title" => "NewService@products",
2844 "name" => "Service@products",
2845 "picto" => "object_service",
2846 "activation" => isModEnabled("service") && $user->hasRight("service", "write"), // vs hooking
2847 "position" => 410,
2848 ),
2849 array(
2850 "url" => "/user/card.php?action=create&amp;type=1&amp;mainmenu=home",
2851 "title" => "AddUser@users",
2852 "name" => "User@users",
2853 "picto" => "user",
2854 "activation" => $user->hasRight("user", "user", "write"), // vs hooking
2855 "position" => 500,
2856 ),
2857 ),
2858 );
2859
2860 $dropDownQuickAddHtml = '';
2861
2862 // Define $dropDownQuickAddHtml
2863 if (empty($mode)) {
2864 $dropDownQuickAddHtml .= '<div class="quickadd-body dropdown-body">';
2865 }
2866 $dropDownQuickAddHtml .= '<div class="dropdown-quickadd-list">';
2867
2868 // Allow the $items of the menu to be manipulated by modules
2869 $parameters = array();
2870 $hook_items = $items;
2871 $reshook = $hookmanager->executeHooks('menuDropdownQuickaddItems', $parameters, $hook_items); // Note that $action and $object may have been modified by some hooks @phan-suppress-current-line PhanTypeMismatchArgument
2872 if (is_numeric($reshook) && !empty($hookmanager->resArray) && is_array($hookmanager->resArray)) {
2873 if ($reshook == 0) {
2874 $items['items'] = array_merge($items['items'], $hookmanager->resArray); // add
2875 } else {
2876 $items = $hookmanager->resArray; // replace
2877 }
2878
2879 // Sort menu items by 'position' value
2880 $position = array();
2881 foreach ($items['items'] as $key => $row) {
2882 $position[$key] = $row['position'];
2883 }
2884 $array1_sort_order = SORT_ASC;
2885 array_multisort($position, $array1_sort_order, $items['items']);
2886 }
2887
2888 foreach ($items['items'] as $item) {
2889 if (!$item['activation']) {
2890 continue;
2891 }
2892 $langs->load(explode('@', $item['title'])[1]);
2893 $langs->load(explode('@', $item['name'])[1]);
2894 $dropDownQuickAddHtml .= '
2895 <a class="dropdown-item quickadd-item" href="'.DOL_URL_ROOT.$item['url'].'" title="'.$langs->trans(explode('@', $item['title'])[0]).'">
2896 '. img_picto('', $item['picto'], 'style="width:18px;"') . ' ' . $langs->trans(explode('@', $item['name'])[0]) . '</a>
2897 ';
2898 }
2899
2900 if (empty($mode)) {
2901 $dropDownQuickAddHtml .= '</div>';
2902 }
2903 $dropDownQuickAddHtml .= '</div>';
2904
2905 return $dropDownQuickAddHtml;
2906}
2907
2914{
2915 global $langs, $conf, $user;
2916
2917 $html = '';
2918
2919 // Return empty in some case
2920 if (!isModEnabled('bookmark') || !$user->hasRight('bookmark', 'lire')) {
2921 return '';
2922 }
2923 /*
2924 if ($conf->browser->name == 'textbrowser') {
2925 return $html;
2926 }
2927 */
2928
2929 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
2930 // accesskey is for Mac: CTRL + key for all browsers
2931 $stringforfirstkey = $langs->trans("KeyboardShortcut");
2932 if ($conf->browser->os === 'macintosh') {
2933 $stringforfirstkey .= ' CTL +';
2934 } else {
2935 if ($conf->browser->name == 'chrome') {
2936 $stringforfirstkey .= ' ALT +';
2937 } elseif ($conf->browser->name == 'firefox') {
2938 $stringforfirstkey .= ' ALT + SHIFT +';
2939 } else {
2940 $stringforfirstkey .= ' CTL +';
2941 }
2942 }
2943
2944 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
2945 include_once DOL_DOCUMENT_ROOT.'/bookmarks/bookmarks.lib.php';
2946 $langs->load("bookmarks");
2947
2948 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2949 $html .= '<div id="topmenu-bookmark-dropdown" class="dropdown inline-block">';
2950 $html .= printDropdownBookmarksList();
2951 $html .= '</div>';
2952 } else {
2953 $html .= '<!-- div for bookmark link -->
2954 <div id="topmenu-bookmark-dropdown" class="dropdown inline-block">
2955 <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>
2956 <div class="dropdown-menu">
2958 </div>
2959 </div>';
2960
2961 $html .= '
2962 <!-- Code to show/hide the bookmark drop-down -->
2963 <script>
2964 jQuery(document).ready(function() {
2965 jQuery(document).on("click", function(event) {
2966 if (!$(event.target).closest("#topmenu-bookmark-dropdown").length) {
2967 /* console.log("close bookmark dropdown - we click outside"); */
2968 // Hide the menus.
2969 $("#topmenu-bookmark-dropdown").removeClass("open");
2970 }
2971 });
2972
2973 jQuery("#topmenu-bookmark-dropdown .dropdown-toggle").on("click", function(event) {
2974 console.log("Click on #topmenu-bookmark-dropdown .dropdown-toggle");
2975 openBookMarkDropDown(event);
2976 });
2977
2978 // Key map shortcut
2979 jQuery(document).keydown(function(event) {
2980 var ostype = \''.dol_escape_js($conf->browser->os).'\';
2981 if (ostype === "macintosh") {
2982 if ( event.which === 66 && event.ctrlKey ) {
2983 console.log("Click on control + b : trigger open bookmark dropdown");
2984 openBookMarkDropDown(event);
2985 }
2986 } else {
2987 if ( event.which === 66 && event.ctrlKey && event.shiftKey ) {
2988 console.log("Click on control + shift + b : trigger open bookmark dropdown");
2989 openBookMarkDropDown(event);
2990 }
2991 }
2992 });
2993
2994 var openBookMarkDropDown = function(event) {
2995 console.log("toggle #topmenu-bookmark-dropdown and force focus");
2996 event.preventDefault();
2997 jQuery("#topmenu-bookmark-dropdown").toggleClass("open");
2998 jQuery("#top-bookmark-search-input").focus();
2999 }
3000
3001 });
3002 </script>
3003 ';
3004 }
3005 }
3006 return $html;
3007}
3008
3014function top_menu_search()
3015{
3016 global $langs, $conf, $db, $user, $hookmanager; // used by htdocs/core/ajax/selectsearchbox.php
3017
3018 $html = '';
3019
3020 $usedbyinclude = 1;
3021 $arrayresult = array();
3022 include DOL_DOCUMENT_ROOT.'/core/ajax/selectsearchbox.php'; // This sets $arrayresult
3023
3024 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
3025 // accesskey is for Mac: CTRL + key for all browsers
3026 $stringforfirstkey = $langs->trans("KeyboardShortcut");
3027 if ($conf->browser->name == 'chrome') {
3028 $stringforfirstkey .= ' ALT +';
3029 } elseif ($conf->browser->name == 'firefox') {
3030 $stringforfirstkey .= ' ALT + SHIFT +';
3031 } else {
3032 $stringforfirstkey .= ' CTL +';
3033 }
3034
3035 $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">';
3036
3037 $defaultAction = '';
3038 $buttonList = '<div class="dropdown-global-search-button-list" >';
3039 // Menu with all searchable items
3040 // @phan-suppress-next-line PhanEmptyForeach // array is really empty
3041 foreach ($arrayresult as $keyItem => $item) {
3042 if (empty($defaultAction)) {
3043 $defaultAction = $item['url'];
3044 }
3045 $buttonList .= '<button class="dropdown-item global-search-item tdoverflowmax300" data-target="'.dol_escape_htmltag($item['url']).'" >';
3046 $buttonList .= $item['text'];
3047 $buttonList .= '</button>';
3048 }
3049 $buttonList .= '</div>';
3050
3051 $dropDownHtml = '<form role="search" id="top-menu-action-search" name="actionsearch" method="GET" action="'.$defaultAction.'">';
3052
3053 $dropDownHtml .= '
3054 <!-- search input -->
3055 <div class="dropdown-header search-dropdown-header">
3056 ' . $searchInput.'
3057 </div>
3058 ';
3059
3060 $dropDownHtml .= '
3061 <!-- Menu Body search -->
3062 <div class="dropdown-body search-dropdown-body">
3063 '.$buttonList.'
3064 </div>
3065 ';
3066
3067 $dropDownHtml .= '</form>';
3068
3069 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
3070 // accesskey is for Mac: CTRL + key for all browsers
3071 $stringforfirstkey = $langs->trans("KeyboardShortcut");
3072 if ($conf->browser->name == 'chrome') {
3073 $stringforfirstkey .= ' ALT +';
3074 } elseif ($conf->browser->name == 'firefox') {
3075 $stringforfirstkey .= ' ALT + SHIFT +';
3076 } else {
3077 $stringforfirstkey .= ' CTL +';
3078 }
3079
3080 $html .= '<!-- div for Global Search -->
3081 <div id="topmenu-global-search-dropdown" class="atoplogin dropdown inline-block">
3082 <a accesskey="s" class="dropdown-toggle login-dropdown-a nofocusvisible" data-toggle="dropdown" href="#" title="'.$langs->trans('Search').' ('.$stringforfirstkey.' s)">
3083 <i class="fa fa-search" aria-hidden="true" ></i>
3084 </a>
3085 <div class="dropdown-menu dropdown-search">
3086 '.$dropDownHtml.'
3087 </div>
3088 </div>';
3089
3090 $html .= '
3091 <!-- Code to show/hide the user drop-down -->
3092 <script>
3093 jQuery(document).ready(function() {
3094
3095 // prevent submitting form on press ENTER
3096 jQuery("#top-global-search-input").keydown(function (e) {
3097 if (e.keyCode == 13 || e.keyCode == 40) {
3098 var inputs = $(this).parents("form").eq(0).find(":button");
3099 if (inputs[inputs.index(this) + 1] != null) {
3100 console.log("Force focus after keydow on #top-global-search-input");
3101 inputs[inputs.index(this) + 1].focus();
3102 if (e.keyCode == 13){
3103 inputs[inputs.index(this) + 1].trigger("click");
3104 }
3105
3106 }
3107 e.preventDefault();
3108 return false;
3109 }
3110 });
3111
3112 // arrow key nav
3113 jQuery(document).keydown(function(e) {
3114 // Get the focused element:
3115 var $focused = $(":focus");
3116 if($focused.length && $focused.hasClass("global-search-item")){
3117
3118 // UP - move to the previous line
3119 if (e.keyCode == 38) {
3120 e.preventDefault();
3121 console.log("Force focus after keycode 38");
3122 $focused.prev().focus();
3123 }
3124
3125 // DOWN - move to the next line
3126 if (e.keyCode == 40) {
3127 e.preventDefault();
3128 console.log("Force focus after keycode 40");
3129 $focused.next().focus();
3130 }
3131 }
3132 });
3133
3134
3135 // submit form action
3136 jQuery(".dropdown-global-search-button-list .global-search-item").on("click", function(event) {
3137 jQuery("#top-menu-action-search").attr("action", $(this).data("target"));
3138 jQuery("#top-menu-action-search").submit();
3139 });
3140
3141 // close drop down
3142 jQuery(document).on("click", function(event) {
3143 if (!$(event.target).closest("#topmenu-global-search-dropdown").length) {
3144 console.log("click close search - we click outside");
3145 // Hide the menus.
3146 jQuery("#topmenu-global-search-dropdown").removeClass("open");
3147 }
3148 });
3149
3150 // Open drop down
3151 jQuery("#topmenu-global-search-dropdown .dropdown-toggle").on("click", function(event) {
3152 console.log("click on toggle #topmenu-global-search-dropdown .dropdown-toggle");
3153 openGlobalSearchDropDown();
3154 });
3155
3156 // Key map shortcut
3157 jQuery(document).keydown(function(e){
3158 if ( e.which === 70 && e.ctrlKey && e.shiftKey ) {
3159 console.log(\'control + shift + f : trigger open global-search dropdown\');
3160 openGlobalSearchDropDown();
3161 }
3162 if ( e.which === 70 && e.alKey ) {
3163 console.log(\'alt + f : trigger open global-search dropdown\');
3164 openGlobalSearchDropDown();
3165 }
3166 });
3167
3168 var openGlobalSearchDropDown = function() {
3169 jQuery("#topmenu-global-search-dropdown").toggleClass("open");
3170 jQuery("#top-global-search-input").focus();
3171 }
3172
3173 });
3174 </script>
3175 ';
3176
3177 return $html;
3178}
3179
3194function left_menu($menu_array_before, $helppagename = '', $notused = '', $menu_array_after = array(), $leftmenuwithoutmainarea = 0, $title = '', $acceptdelayedhtml = 0)
3195{
3196 global $user, $conf, $langs, $db, $form;
3197 global $hookmanager, $menumanager;
3198
3199 $searchform = '';
3200
3201 if (!empty($menu_array_before)) {
3202 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);
3203 }
3204
3205 if (empty($conf->dol_hide_leftmenu) && (!defined('NOREQUIREMENU') || !constant('NOREQUIREMENU'))) {
3206 // Instantiate hooks for external modules
3207 $hookmanager->initHooks(array('leftblock'));
3208
3209 print "\n".'<!-- Begin side-nav id-left -->'."\n".'<div class="side-nav"><div id="id-left">'."\n";
3210 print "\n";
3211
3212 if (!is_object($form)) {
3213 $form = new Form($db);
3214 }
3215 $selected = -1;
3216 if (!getDolGlobalString('MAIN_USE_TOP_MENU_SEARCH_DROPDOWN')) {
3217 // Select with select2 is awful on smartphone. TODO Is this still true with select2 v4 ?
3218 if ($conf->browser->layout == 'phone') {
3219 $conf->global->MAIN_USE_OLD_SEARCH_FORM = 1;
3220 }
3221
3222 $usedbyinclude = 1;
3223 $arrayresult = array();
3224 include DOL_DOCUMENT_ROOT.'/core/ajax/selectsearchbox.php'; // This make initHooks('searchform') then set $arrayresult
3225
3226 if ($conf->use_javascript_ajax && !getDolGlobalString('MAIN_USE_OLD_SEARCH_FORM')) {
3227 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
3228 // accesskey is for Mac: CTRL + key for all browsers
3229 $stringforfirstkey = $langs->trans("KeyboardShortcut");
3230 if ($conf->browser->name == 'chrome') {
3231 $stringforfirstkey .= ' ALT +';
3232 } elseif ($conf->browser->name == 'firefox') {
3233 $stringforfirstkey .= ' ALT + SHIFT +';
3234 } else {
3235 $stringforfirstkey .= ' CTL +';
3236 }
3237
3238 //$textsearch = $langs->trans("Search");
3239 $textsearch = '<span class="fa fa-search paddingright pictofixedwidth"></span>'.$langs->trans("Search");
3240 $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');
3241 } else {
3242 if (is_array($arrayresult)) {
3243 // @phan-suppress-next-line PhanEmptyForeach // array is really empty in else case.
3244 foreach ($arrayresult as $key => $val) {
3245 $searchform .= printSearchForm($val['url'], $val['url'], $val['label'], 'maxwidth125', 'search_all', (empty($val['shortcut']) ? '' : $val['shortcut']), 'searchleft'.$key, $val['img']);
3246 }
3247 }
3248 }
3249
3250 // Execute hook printSearchForm
3251 $parameters = array('searchform' => $searchform);
3252 $reshook = $hookmanager->executeHooks('printSearchForm', $parameters); // Note that $action and $object may have been modified by some hooks
3253 if (empty($reshook)) {
3254 $searchform .= $hookmanager->resPrint;
3255 } else {
3256 $searchform = $hookmanager->resPrint;
3257 }
3258
3259 // Force special value for $searchform for text browsers or very old search form
3260 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') || empty($conf->use_javascript_ajax)) {
3261 $urltosearch = DOL_URL_ROOT.'/core/search_page.php?showtitlebefore=1';
3262 $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>';
3263 } elseif ($conf->use_javascript_ajax && getDolGlobalString('MAIN_USE_OLD_SEARCH_FORM')) {
3264 $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>';
3265 $searchform .= '<script>
3266 jQuery(document).ready(function () {
3267 jQuery("#divsearchforms1").click(function(){
3268 jQuery("#divsearchforms2").toggle();
3269 });
3270 });
3271 </script>' . "\n";
3272 $searchform .= '</div>';
3273 }
3274
3275 // Key map shortcut
3276 $searchform .= '<script>
3277 jQuery(document).keydown(function(e){
3278 if( e.which === 70 && e.ctrlKey && e.shiftKey ){
3279 console.log(\'control + shift + f : trigger open global-search dropdown\');
3280 openGlobalSearchDropDown();
3281 }
3282 if( (e.which === 83 || e.which === 115) && e.altKey ){
3283 console.log(\'alt + s : trigger open global-search dropdown\');
3284 openGlobalSearchDropDown();
3285 }
3286 });
3287
3288 var openGlobalSearchDropDown = function() {
3289 jQuery("#searchselectcombo").select2(\'open\');
3290 }
3291 </script>';
3292 }
3293
3294 // Left column
3295 print '<!-- Begin left menu -->'."\n";
3296
3297 print '<div class="vmenu"'.(getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') ? ' alt="Left menu"' : '').'>'."\n\n";
3298
3299 // Show left menu with other forms
3300 // @phan-suppress-next-line PhanRedefinedClassReference
3301 $menumanager->menu_array = $menu_array_before;
3302 // @phan-suppress-next-line PhanRedefinedClassReference
3303 $menumanager->menu_array_after = $menu_array_after;
3304 if (getDolGlobalInt('MAIN_MENU_LEFT_DROPDOWN')) {
3305 // @phan-suppress-next-line PhanRedefinedClassReference
3306 $menumanager->showmenu('leftdropdown', array('searchform' => $searchform)); // output menu_array and menu found in database
3307 } else {
3308 // @phan-suppress-next-line PhanRedefinedClassReference
3309 $menumanager->showmenu('left', array('searchform' => $searchform)); // output menu_array and menu found in database
3310 }
3311
3312 // Dolibarr version + help + bug report link
3313 print "\n";
3314 print "<!-- Begin Help Block-->\n";
3315 print '<div id="blockvmenuhelp" class="blockvmenuhelp">'."\n";
3316
3317 // Version
3318 if (getDolGlobalString('MAIN_SHOW_VERSION')) { // Version is already on help picto and on login page.
3319 $doliurl = 'https://www.dolibarr.org';
3320 //local communities
3321 if (preg_match('/fr/i', $langs->defaultlang)) {
3322 $doliurl = 'https://www.dolibarr.fr';
3323 }
3324 if (preg_match('/es/i', $langs->defaultlang)) {
3325 $doliurl = 'https://www.dolibarr.es';
3326 }
3327 if (preg_match('/de/i', $langs->defaultlang)) {
3328 $doliurl = 'https://www.dolibarr.de';
3329 }
3330 if (preg_match('/it/i', $langs->defaultlang)) {
3331 $doliurl = 'https://www.dolibarr.it';
3332 }
3333 if (preg_match('/gr/i', $langs->defaultlang)) {
3334 $doliurl = 'https://www.dolibarr.gr';
3335 }
3336
3337 $appli = constant('DOL_APPLICATION_TITLE');
3338 $applicustom = getDolGlobalString('MAIN_APPLICATION_TITLE');
3339 if ($applicustom) {
3340 $appli = (preg_match('/^\+/', $applicustom) ? $appli : '').$applicustom;
3341 } else {
3342 $appli .= " ".DOL_VERSION;
3343 }
3344
3345 // Clean doliurl if we use a custom application name
3346 if ($applicustom) {
3347 $doliurl = '';
3348 }
3349
3350 print '<div id="blockvmenuhelpapp" class="blockvmenuhelp">';
3351 if ($doliurl) {
3352 print '<a class="help" target="_blank" rel="noopener noreferrer" href="'.$doliurl.'">';
3353 } else {
3354 print '<span class="help">';
3355 }
3356 print $appli;
3357 if ($doliurl) {
3358 print '</a>';
3359 } else {
3360 print '</span>';
3361 }
3362 print '</div>'."\n";
3363 }
3364
3365 // Link to bugtrack
3366 if (getDolGlobalString('MAIN_BUGTRACK_ENABLELINK')) {
3367 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
3368
3369 if (getDolGlobalString('MAIN_BUGTRACK_ENABLELINK') == 'github') {
3370 $bugbaseurl = 'https://github.com/Dolibarr/dolibarr/issues/new?labels=Bug';
3371 $bugbaseurl .= '&title=';
3372 $bugbaseurl .= urlencode("Bug: ");
3373 $bugbaseurl .= '&body=';
3374 $bugbaseurl .= urlencode("# Instructions\n");
3375 $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");
3376 $bugbaseurl .= urlencode("*Please:*\n");
3377 $bugbaseurl .= urlencode("- *replace the bracket enclosed texts with meaningful information*\n");
3378 $bugbaseurl .= urlencode("- *remove any unused sub-section*\n");
3379 $bugbaseurl .= urlencode("\n");
3380 $bugbaseurl .= urlencode("\n");
3381 $bugbaseurl .= urlencode("# Bug\n");
3382 $bugbaseurl .= urlencode("[*Short description*]\n");
3383 $bugbaseurl .= urlencode("\n");
3384 $bugbaseurl .= urlencode("## Environment\n");
3385 $bugbaseurl .= urlencode("- **Version**: ".DOL_VERSION."\n");
3386 $bugbaseurl .= urlencode("- **OS**: ".php_uname('s')."\n");
3387 $bugbaseurl .= urlencode("- **Web server**: ".$_SERVER["SERVER_SOFTWARE"]."\n");
3388 $bugbaseurl .= urlencode("- **PHP**: ".php_sapi_name().' '.phpversion()."\n");
3389 $bugbaseurl .= urlencode("- **Database**: ".$db::LABEL.' '.$db->getVersion()."\n");
3390 $bugbaseurl .= urlencode("- **URL(s)**: ".$_SERVER["REQUEST_URI"]."\n");
3391 $bugbaseurl .= urlencode("\n");
3392 $bugbaseurl .= urlencode("## Expected and actual behavior\n");
3393 $bugbaseurl .= urlencode("[*Verbose description*]\n");
3394 $bugbaseurl .= urlencode("\n");
3395 $bugbaseurl .= urlencode("## Steps to reproduce the behavior\n");
3396 $bugbaseurl .= urlencode("[*Verbose description*]\n");
3397 $bugbaseurl .= urlencode("\n");
3398 $bugbaseurl .= urlencode("## [Attached files](https://help.github.com/articles/issue-attachments) (Screenshots, screencasts, dolibarr.log, debugging information…)\n");
3399 $bugbaseurl .= urlencode("[*Files*]\n");
3400 $bugbaseurl .= urlencode("\n");
3401
3402 $bugbaseurl .= urlencode("\n");
3403 $bugbaseurl .= urlencode("## Report\n");
3404 } elseif (getDolGlobalString('MAIN_BUGTRACK_ENABLELINK')) {
3405 $bugbaseurl = getDolGlobalString('MAIN_BUGTRACK_ENABLELINK');
3406 } else {
3407 $bugbaseurl = "";
3408 }
3409
3410 // Execute hook printBugtrackInfo
3411 $parameters = array('bugbaseurl' => $bugbaseurl);
3412 $reshook = $hookmanager->executeHooks('printBugtrackInfo', $parameters); // Note that $action and $object may have been modified by some hooks
3413 if (empty($reshook)) {
3414 $bugbaseurl .= $hookmanager->resPrint;
3415 } else {
3416 $bugbaseurl = $hookmanager->resPrint;
3417 }
3418
3419 print '<div id="blockvmenuhelpbugreport" class="blockvmenuhelp">';
3420 print '<a class="help" target="_blank" rel="noopener noreferrer" href="'.$bugbaseurl.'"><i class="fas fa-bug"></i> '.$langs->trans("FindBug").'</a>';
3421 print '</div>';
3422 }
3423
3424 print "</div>\n";
3425 print "<!-- End Help Block-->\n";
3426 print "\n";
3427
3428 print "</div>\n";
3429 print "<!-- End left menu -->\n";
3430 print "\n";
3431
3432 // Execute hook printLeftBlock
3433 $parameters = array();
3434 $reshook = $hookmanager->executeHooks('printLeftBlock', $parameters); // Note that $action and $object may have been modified by some hooks
3435 print $hookmanager->resPrint;
3436
3437 print '</div></div> <!-- End side-nav id-left -->'; // End div id="side-nav" div id="id-left"
3438 }
3439
3440 print "\n";
3441 print '<!-- Begin right area -->'."\n";
3442
3443 if (empty($leftmenuwithoutmainarea)) {
3444 main_area($title);
3445 }
3446}
3447
3448
3455function main_area($title = '')
3456{
3457 global $conf, $langs, $hookmanager;
3458
3459 if (empty($conf->dol_hide_leftmenu) && !GETPOST('dol_openinpopup', 'aZ09')) {
3460 print '<div id="id-right">';
3461 }
3462
3463 print "\n";
3464
3465 print '<!-- Begin div class="fiche" -->'."\n".'<div class="fiche">'."\n";
3466
3467 $hookmanager->initHooks(array('main'));
3468 $parameters = array();
3469 $reshook = $hookmanager->executeHooks('printMainArea', $parameters); // Note that $action and $object may have been modified by some hooks
3470 print $hookmanager->resPrint;
3471
3472 if (getDolGlobalString('MAIN_ONLY_LOGIN_ALLOWED')) {
3473 print info_admin($langs->trans("WarningYouAreInMaintenanceMode", getDolGlobalString('MAIN_ONLY_LOGIN_ALLOWED')), 0, 0, '1', 'warning maintenancemode');
3474 }
3475
3476 // Permit to add user company information on each printed document by setting SHOW_SOCINFO_ON_PRINT
3477 if (getDolGlobalString('SHOW_SOCINFO_ON_PRINT') && GETPOST('optioncss', 'aZ09') == 'print' && empty(GETPOST('disable_show_socinfo_on_print', 'aZ09'))) {
3478 $parameters = array();
3479 $reshook = $hookmanager->executeHooks('showSocinfoOnPrint', $parameters);
3480 if (empty($reshook)) {
3481 print '<!-- Begin show mysoc info header -->'."\n";
3482 print '<div id="mysoc-info-header">'."\n";
3483 print '<table class="centpercent div-table-responsive">'."\n";
3484 print '<tbody>';
3485 print '<tr><td rowspan="0" class="width20p">';
3486 if (getDolGlobalString('MAIN_SHOW_LOGO') && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && getDolGlobalString('MAIN_INFO_SOCIETE_LOGO')) {
3487 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'))).'">';
3488 }
3489 print '</td><td rowspan="0" class="width50p"></td></tr>'."\n";
3490 print '<tr><td class="titre bold">'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_NOM')).'</td></tr>'."\n";
3491 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";
3492 if (getDolGlobalString('MAIN_INFO_SOCIETE_TEL')) {
3493 print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Phone").' : '.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_TEL')).'</td></tr>';
3494 }
3495 if (getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) {
3496 print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Email").' : '.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')).'</td></tr>';
3497 }
3498 if (getDolGlobalString('MAIN_INFO_SOCIETE_WEB')) {
3499 print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Web").' : '.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_WEB')).'</td></tr>';
3500 }
3501 print '</tbody>';
3502 print '</table>'."\n";
3503 print '</div>'."\n";
3504 print '<!-- End show mysoc info header -->'."\n";
3505 }
3506 }
3507}
3508
3509
3517function getHelpParamFor($helppagename, $langs)
3518{
3519 $helpbaseurl = '';
3520 $helppage = '';
3521 $mode = '';
3522
3523 if (preg_match('/^http/i', $helppagename)) {
3524 // If complete URL
3525 $helpbaseurl = '%s';
3526 $helppage = $helppagename;
3527 $mode = 'local';
3528 } else {
3529 // If WIKI URL
3530 $reg = array();
3531 if (preg_match('/^es/i', $langs->defaultlang)) {
3532 $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3533 if (preg_match('/ES:([^|]+)/i', $helppagename, $reg)) {
3534 $helppage = $reg[1];
3535 }
3536 }
3537 if (preg_match('/^fr/i', $langs->defaultlang)) {
3538 $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3539 if (preg_match('/FR:([^|]+)/i', $helppagename, $reg)) {
3540 $helppage = $reg[1];
3541 }
3542 }
3543 if (preg_match('/^de/i', $langs->defaultlang)) {
3544 $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3545 if (preg_match('/DE:([^|]+)/i', $helppagename, $reg)) {
3546 $helppage = $reg[1];
3547 }
3548 }
3549 if (empty($helppage)) { // If help page not already found
3550 $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3551 if (preg_match('/EN:([^|]+)/i', $helppagename, $reg)) {
3552 $helppage = $reg[1];
3553 }
3554 }
3555 $mode = 'wiki';
3556 }
3557 return array('helpbaseurl' => $helpbaseurl, 'helppage' => $helppage, 'mode' => $mode);
3558}
3559
3560
3577function printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey = '', $prefhtmlinputname = '', $img = '', $showtitlebefore = 0, $autofocus = 0)
3578{
3579 global $langs, $user;
3580
3581 $ret = '';
3582 $ret .= '<form action="'.$urlaction.'" method="post" class="searchform nowraponall tagtr">';
3583 $ret .= '<input type="hidden" name="token" value="'.newToken().'">';
3584 $ret .= '<input type="hidden" name="savelogin" value="'.dol_escape_htmltag($user->login).'">';
3585 if ($showtitlebefore) {
3586 $ret .= '<div class="tagtd left">'.$title.'</div> ';
3587 }
3588 $ret .= '<div class="tagtd">';
3589 $ret .= img_picto('', $img, '', 0, 0, 0, '', 'paddingright width20');
3590 $ret .= '<input type="text" class="flat '.$htmlmorecss.'"';
3591 $ret .= ' style="background-repeat: no-repeat; background-position: 3px;"';
3592 $ret .= ($accesskey ? ' accesskey="'.$accesskey.'"' : '');
3593 $ret .= ' placeholder="'.strip_tags($title).'"';
3594 $ret .= ($autofocus ? ' autofocus' : '');
3595 $ret .= ' name="'.$htmlinputname.'" id="'.$prefhtmlinputname.$htmlinputname.'" />';
3596 $ret .= '<button type="submit" class="button bordertransp" style="padding-top: 4px; padding-bottom: 4px; padding-left: 6px; padding-right: 6px">';
3597 $ret .= '<span class="fa fa-search"></span>';
3598 $ret .= '</button>';
3599 $ret .= '</div>';
3600 $ret .= "</form>\n";
3601 return $ret;
3602}
3603
3604
3605if (!function_exists("llxFooter")) {
3619 function llxFooter($comment = '', $zone = 'private', $disabledoutputofmessages = 0)
3620 {
3621 global $conf, $db, $langs, $user, $mysoc, $object, $hookmanager, $action;
3622 global $delayedhtmlcontent;
3623 global $contextpage, $page, $limit, $mode;
3624 global $dolibarr_distrib;
3625
3626 $ext = 'layout='.urlencode($conf->browser->layout).'&version='.urlencode(DOL_VERSION);
3627
3628 // Hook to add more things on all pages within fiche DIV
3629 $llxfooter = '';
3630 $parameters = array();
3631 $reshook = $hookmanager->executeHooks('llxFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3632 if (empty($reshook)) {
3633 $llxfooter .= $hookmanager->resPrint;
3634 } elseif ($reshook > 0) {
3635 $llxfooter = $hookmanager->resPrint;
3636 }
3637 if ($llxfooter) {
3638 print $llxfooter;
3639 }
3640
3641 // Global html output events ($mesgs, $errors, $warnings)
3642 dol_htmloutput_events($disabledoutputofmessages);
3643
3644 // Code for search criteria persistence.
3645 // $user->lastsearch_values was set by the GETPOST when form field search_xxx exists
3646 if (is_object($user) && !empty($user->lastsearch_values_tmp) && is_array($user->lastsearch_values_tmp)) {
3647 // Clean and save data
3648 foreach ($user->lastsearch_values_tmp as $key => $val) {
3649 unset($_SESSION['lastsearch_values_tmp_'.$key]); // Clean array to rebuild it just after
3650 if (count($val) && empty($_POST['button_removefilter']) && empty($_POST['button_removefilter_x'])) {
3651 if (empty($val['sortfield'])) {
3652 unset($val['sortfield']);
3653 }
3654 if (empty($val['sortorder'])) {
3655 unset($val['sortorder']);
3656 }
3657 dol_syslog('Save lastsearch_values_tmp_'.$key.'='.json_encode($val, 0)." (systematic recording of last search criteria)");
3658 $_SESSION['lastsearch_values_tmp_'.$key] = json_encode($val);
3659 unset($_SESSION['lastsearch_values_'.$key]);
3660 }
3661 }
3662 }
3663
3664
3665 $relativepathstring = $_SERVER["PHP_SELF"];
3666 // Clean $relativepathstring
3667 if (constant('DOL_URL_ROOT')) {
3668 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
3669 }
3670 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
3671 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
3672 if (preg_match('/list\.php$/', $relativepathstring)) {
3673 unset($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]);
3674 unset($_SESSION['lastsearch_page_tmp_'.$relativepathstring]);
3675 unset($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]);
3676 unset($_SESSION['lastsearch_mode_tmp_'.$relativepathstring]);
3677
3678 if (!empty($contextpage)) {
3679 $_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring] = $contextpage;
3680 }
3681 if (!empty($page) && $page > 0) {
3682 $_SESSION['lastsearch_page_tmp_'.$relativepathstring] = $page;
3683 }
3684 if (!empty($limit) && $limit != $conf->liste_limit) {
3685 $_SESSION['lastsearch_limit_tmp_'.$relativepathstring] = $limit;
3686 }
3687 if (!empty($mode)) {
3688 $_SESSION['lastsearch_mode_tmp_'.$relativepathstring] = $mode;
3689 }
3690
3691 unset($_SESSION['lastsearch_contextpage_'.$relativepathstring]);
3692 unset($_SESSION['lastsearch_page_'.$relativepathstring]);
3693 unset($_SESSION['lastsearch_limit_'.$relativepathstring]);
3694 unset($_SESSION['lastsearch_mode_'.$relativepathstring]);
3695 }
3696
3697 // Core error message
3698 if (getDolGlobalString('MAIN_CORE_ERROR')) {
3699 // Ajax version
3700 if ($conf->use_javascript_ajax) {
3701 $title = img_warning().' '.$langs->trans('CoreErrorTitle');
3702 print ajax_dialog($title, $langs->trans('CoreErrorMessage'));
3703 } else {
3704 // html version
3705 $msg = img_warning().' '.$langs->trans('CoreErrorMessage');
3706 print '<div class="error">'.$msg.'</div>';
3707 }
3708
3709 //define("MAIN_CORE_ERROR",0); // Constant was defined and we can't change value of a constant
3710 }
3711
3712 print "\n\n";
3713
3714 print '</div> <!-- End div class="fiche" -->'."\n"; // End div fiche
3715
3716 if (empty($conf->dol_hide_leftmenu) && !GETPOST('dol_openinpopup', 'aZ09')) {
3717 print '</div> <!-- End div id-right -->'."\n"; // End div id-right
3718 }
3719
3720 if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) {
3721 print '</div> <!-- End div id-container -->'."\n"; // End div container
3722 }
3723
3724 print "\n";
3725 if ($comment) {
3726 print '<!-- '.$comment.' -->'."\n";
3727 }
3728
3729 printCommonFooter($zone);
3730
3731 if (!empty($delayedhtmlcontent)) {
3732 print $delayedhtmlcontent;
3733 }
3734
3735 if (!empty($conf->use_javascript_ajax)) {
3736 print "\n".'<!-- Includes JS Footer of Dolibarr -->'."\n";
3737 print '<script src="'.DOL_URL_ROOT.'/core/js/lib_foot.js.php?lang='.$langs->defaultlang.($ext ? '&'.$ext : '').'"></script>'."\n";
3738 }
3739
3740 // JS wrapper to add log when clicking on download or preview
3741 if (isModEnabled('blockedlog') && is_object($object) && !empty($object->id) && $object->id > 0) {
3742 if (in_array($object->element, array('facture')) && $object->statut > 0) { // Restrict for the moment to element 'facture'
3743 print "\n<!-- JS CODE TO ENABLE log when making a download or a preview of a document -->\n";
3744 ?>
3745 <script>
3746 jQuery(document).ready(function () {
3747 $('a.documentpreview').click(function() {
3748 console.log("Call /blockedlog/ajax/block-add on a.documentpreview");
3749 $.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
3750 , {
3751 id:<?php echo $object->id; ?>
3752 , element:'<?php echo dol_escape_js($object->element) ?>'
3753 , action:'DOC_PREVIEW'
3754 , token: '<?php echo currentToken(); ?>'
3755 }
3756 );
3757 });
3758 $('a.documentdownload').click(function() {
3759 console.log("Call /blockedlog/ajax/block-add a.documentdownload");
3760 $.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
3761 , {
3762 id:<?php echo $object->id; ?>
3763 , element:'<?php echo dol_escape_js($object->element) ?>'
3764 , action:'DOC_DOWNLOAD'
3765 , token: '<?php echo currentToken(); ?>'
3766 }
3767 );
3768 });
3769 });
3770 </script>
3771 <?php
3772 }
3773 }
3774
3775 // A div for the #dialogforpopup popup
3776 print "\n<!-- A div to allow dialog popup by jQuery('#dialogforpopup').dialog() -->\n";
3777 print '<div id="dialogforpopup" style="display: none;"></div>'."\n";
3778
3779 // A div for the #uiblock
3780 print "\n<!-- A div to allow uiblock by dolBlockUI(message) -->\n";
3781 print '<div id="dol-block-ui" style="display: none;"><div class="message">Loading...</div></div>'."\n";
3782
3783
3784 // Add code for the asynchronous anonymous first ping (for telemetry)
3785 // You can use &forceping=1 in parameters to force the ping if the ping was already sent.
3786 $forceping = GETPOST('forceping', 'alpha');
3787 if (($_SERVER["PHP_SELF"] == DOL_URL_ROOT.'/index.php') || $forceping) {
3788 //print '<!-- instance_unique_id='.$conf->file->instance_unique_id.' MAIN_FIRST_PING_OK_ID='.getDolGlobalString('MAIN_FIRST_PING_OK_ID').' -->';
3789 $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.
3790
3791 if (!getDolGlobalString('MAIN_FIRST_PING_OK_DATE')
3792 || (!empty($conf->file->instance_unique_id) && ($hash_unique_id != getDolGlobalString('MAIN_FIRST_PING_OK_ID')) && (getDolGlobalString('MAIN_FIRST_PING_OK_ID') != 'disabled'))
3793 || $forceping) {
3794 // No ping done if we are into an alpha version
3795 if (strpos('alpha', DOL_VERSION) > 0 && !$forceping) {
3796 print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. It is an alpha version -->\n";
3797 } elseif (empty($_COOKIE['DOLINSTALLNOPING_'.$hash_unique_id]) || $forceping) { // Cookie is set when we uncheck the checkbox in the installation wizard.
3798 // MAIN_LAST_PING_KO_DATE
3799 // Disable ping if MAIN_LAST_PING_KO_DATE is set and is recent (this month)
3800 if (getDolGlobalString('MAIN_LAST_PING_KO_DATE') && substr(getDolGlobalString('MAIN_LAST_PING_KO_DATE'), 0, 6) == dol_print_date(dol_now(), '%Y%m') && !$forceping) {
3801 print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. An error already occurred this month, we will try later. -->\n";
3802 } else {
3803 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
3804
3805 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";
3806 print "\n<!-- JS CODE TO ENABLE the anonymous Ping -->\n";
3807 $url_for_ping = getDolGlobalString('MAIN_URL_FOR_PING', "https://ping.dolibarr.org/");
3808 // Try to guess the distrib used
3809 $distrib = 'standard';
3810 if (isset($_SERVER["SERVER_ADMIN"]) && $_SERVER["SERVER_ADMIN"] == 'doliwamp@localhost') {
3811 $distrib = 'doliwamp';
3812 }
3813 if (!empty($dolibarr_distrib)) {
3814 $distrib = $dolibarr_distrib;
3815 }
3816 ?>
3817 <script>
3818 jQuery(document).ready(function (tmp) {
3819 console.log("Try Ping with hash_unique_id is dol_hash('dolibarr'+instance_unique_id, 'sha256')");
3820 $.ajax({
3821 method: "POST",
3822 url: "<?php echo $url_for_ping ?>",
3823 timeout: 500, // timeout milliseconds
3824 cache: false,
3825 data: {
3826 hash_algo: 'dol_hash-sha256',
3827 hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>',
3828 action: 'dolibarrping',
3829 version: '<?php echo (float) DOL_VERSION; ?>',
3830 entity: '<?php echo (int) $conf->entity; ?>',
3831 dbtype: '<?php echo dol_escape_js($db->type); ?>',
3832 country_code: '<?php echo $mysoc->country_code ? dol_escape_js($mysoc->country_code) : 'unknown'; ?>',
3833 php_version: '<?php echo dol_escape_js(phpversion()); ?>',
3834 os_version: '<?php echo dol_escape_js(version_os('smr')); ?>',
3835 db_version: '<?php echo dol_escape_js(version_db()); ?>',
3836 distrib: '<?php echo $distrib ? dol_escape_js($distrib) : 'unknown'; ?>',
3837 token: 'notrequired'
3838 },
3839 success: function (data, status, xhr) { // success callback function (data contains body of response)
3840 console.log("Ping ok");
3841 $.ajax({
3842 method: 'GET',
3843 url: '<?php echo DOL_URL_ROOT.'/core/ajax/pingresult.php'; ?>',
3844 timeout: 500, // timeout milliseconds
3845 cache: false,
3846 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
3847 });
3848 },
3849 error: function (data,status,xhr) { // error callback function
3850 console.log("Ping ko: " + data);
3851 $.ajax({
3852 method: 'GET',
3853 url: '<?php echo DOL_URL_ROOT.'/core/ajax/pingresult.php'; ?>',
3854 timeout: 500, // timeout milliseconds
3855 cache: false,
3856 data: { hash_algo: 'dol_hash-sha256', hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>', action: 'firstpingko', token: '<?php echo currentToken(); ?>' },
3857 });
3858 }
3859 });
3860 });
3861 </script>
3862 <?php
3863 }
3864 } else {
3865 $now = dol_now();
3866 print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. It was disabled -->\n";
3867 include_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
3868 dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_DATE', dol_print_date($now, 'dayhourlog', 'gmt'), 'chaine', 0, '', $conf->entity);
3869 dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_ID', 'disabled', 'chaine', 0, '', $conf->entity);
3870 }
3871 }
3872 }
3873
3874 $parameters = array();
3875 $reshook = $hookmanager->executeHooks('beforeBodyClose', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
3876 if ($reshook > 0) {
3877 print $hookmanager->resPrint;
3878 }
3879
3880 print "</body>\n";
3881 print "</html>\n";
3882 }
3883}
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.