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