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