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