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