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