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 == 'lynxlinks')) { // 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', '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')) && !GETPOSTINT('dol_openinpopup')) {
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_optimize_smallscreen')) {
1932 $themeparam .= '&amp;dol_optimize_smallscreen='.GETPOSTINT('dol_optimize_smallscreen');
1933 }
1934 if (GETPOSTISSET('dol_no_mouse_hover')) {
1935 $themeparam .= '&amp;dol_no_mouse_hover='.GETPOSTINT('dol_no_mouse_hover');
1936 }
1937 if (GETPOSTISSET('dol_use_jmobile')) {
1938 $themeparam .= '&amp;dol_use_jmobile='.GETPOSTINT('dol_use_jmobile');
1939 $conf->dol_use_jmobile = GETPOSTINT('dol_use_jmobile');
1940 }
1941 if (GETPOSTISSET('THEME_DARKMODEENABLED')) {
1942 $themeparam .= '&amp;THEME_DARKMODEENABLED='.GETPOSTINT('THEME_DARKMODEENABLED');
1943 }
1944 if (GETPOSTISSET('THEME_SATURATE_RATIO')) {
1945 $themeparam .= '&amp;THEME_SATURATE_RATIO='.GETPOSTINT('THEME_SATURATE_RATIO');
1946 }
1947
1948 if (getDolGlobalString('MAIN_ENABLE_FONT_ROBOTO')) {
1949 print '<link rel="preconnect" href="https://fonts.gstatic.com">'."\n";
1950 print '<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@200;300;400;500;600&display=swap" rel="stylesheet">'."\n";
1951 }
1952
1953 if (!defined('DISABLE_JQUERY') && !$disablejs && $conf->use_javascript_ajax) {
1954 print '<!-- Includes CSS for JQuery (Ajax library) -->'."\n";
1955 $jquerytheme = 'base';
1956 if (getDolGlobalString('MAIN_USE_JQUERY_THEME')) {
1957 $jquerytheme = getDolGlobalString('MAIN_USE_JQUERY_THEME');
1958 }
1959 if (constant('JS_JQUERY_UI')) {
1960 print '<link rel="stylesheet" type="text/css" href="'.JS_JQUERY_UI.'css/'.$jquerytheme.'/jquery-ui.min.css'.($ext ? '?'.$ext : '').'">'."\n"; // Forced JQuery
1961 } else {
1962 print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/css/'.$jquerytheme.'/jquery-ui.css'.($ext ? '?'.$ext : '').'">'."\n"; // JQuery
1963 }
1964 if (!defined('DISABLE_JQUERY_JNOTIFY')) {
1965 print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/jnotify/jquery.jnotify-alt.min.css'.($ext ? '?'.$ext : '').'">'."\n"; // JNotify
1966 }
1967 if (!defined('DISABLE_SELECT2') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) { // jQuery plugin "mutiselect", "multiple-select", "select2"...
1968 $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
1969 print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/'.$tmpplugin.'/dist/css/'.$tmpplugin.'.css'.($ext ? '?'.$ext : '').'">'."\n";
1970 }
1971 }
1972
1973 if (!defined('DISABLE_FONT_AWSOME')) {
1974 print '<!-- Includes CSS for font awesome -->'."\n";
1975 $fontawesome_directory = getDolGlobalString('MAIN_FONTAWESOME_DIRECTORY', '/theme/common/fontawesome-5');
1976 print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.$fontawesome_directory.'/css/all.min.css'.($ext ? '?'.$ext : '').'">'."\n";
1977 }
1978
1979 print '<!-- Includes CSS for Dolibarr theme -->'."\n";
1980 // Output style sheets (optioncss='print' or ''). Note: $conf->css looks like '/theme/eldy/style.css.php'
1981 $themepath = dol_buildpath($conf->css, 1);
1982 $themesubdir = '';
1983 if (!empty($conf->modules_parts['theme'])) { // This slow down
1984 foreach ($conf->modules_parts['theme'] as $reldir) {
1985 if (file_exists(dol_buildpath($reldir.$conf->css, 0))) {
1986 $themepath = dol_buildpath($reldir.$conf->css, 1);
1987 $themesubdir = $reldir;
1988 break;
1989 }
1990 }
1991 }
1992
1993 //print 'themepath='.$themepath.' themeparam='.$themeparam;exit;
1994 print '<link rel="stylesheet" type="text/css" href="'.$themepath.$themeparam.'">'."\n";
1995 if (getDolGlobalString('MAIN_FIX_FLASH_ON_CHROME')) {
1996 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";
1997 }
1998
1999 // LEAFLET AND GEOMAN
2000 if (getDolGlobalString('MAIN_USE_GEOPHP')) {
2001 print '<link rel="stylesheet" href="'.DOL_URL_ROOT.'/includes/leaflet/leaflet.css'.($ext ? '?'.$ext : '')."\">\n";
2002 print '<link rel="stylesheet" href="'.DOL_URL_ROOT.'/includes/leaflet/leaflet-geoman.css'.($ext ? '?'.$ext : '')."\">\n";
2003 }
2004
2005 // CSS forced by modules (relative url starting with /)
2006 if (!empty($conf->modules_parts['css'])) {
2007 $arraycss = (array) $conf->modules_parts['css'];
2008 foreach ($arraycss as $modcss => $filescss) {
2009 $filescss = (array) $filescss; // To be sure filecss is an array
2010 foreach ($filescss as $cssfile) {
2011 if (empty($cssfile)) {
2012 dol_syslog("Warning: module ".$modcss." declared a css path file into its descriptor that is empty.", LOG_WARNING);
2013 }
2014 // cssfile is a relative path
2015 $urlforcss = dol_buildpath($cssfile, 1);
2016 if ($urlforcss && $urlforcss != '/') {
2017 print '<!-- Includes CSS added by module '.$modcss.' -->'."\n".'<link rel="stylesheet" type="text/css" href="'.$urlforcss;
2018 // 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.
2019 if (!preg_match('/\.css$/i', $cssfile)) {
2020 print $themeparam;
2021 }
2022 print '">'."\n";
2023 } else {
2024 dol_syslog("Warning: module ".$modcss." declared a css path file for a file we can't find.", LOG_WARNING);
2025 }
2026 }
2027 }
2028 }
2029 // CSS forced by page in top_htmlhead call (relative url starting with /)
2030 if (is_array($arrayofcss)) {
2031 foreach ($arrayofcss as $cssfile) {
2032 if (preg_match('/^(http|\/\/)/i', $cssfile)) {
2033 $urltofile = $cssfile;
2034 } else {
2035 $urltofile = dol_buildpath($cssfile, 1);
2036 }
2037 print '<!-- Includes CSS added by page -->'."\n".'<link rel="stylesheet" type="text/css" title="default" href="'.$urltofile;
2038 // 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.
2039 if (!preg_match('/\.css$/i', $cssfile)) {
2040 print $themeparam;
2041 }
2042 print '">'."\n";
2043 }
2044 }
2045
2046 // Custom CSS
2047 if (getDolGlobalString('MAIN_IHM_CUSTOM_CSS')) {
2048 // If a custom CSS was set, we add link to the custom css php file
2049 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";
2050 }
2051
2052 // Output standard javascript links
2053 if (!defined('DISABLE_JQUERY') && !$disablejs && !empty($conf->use_javascript_ajax)) {
2054 // JQuery. Must be before other includes
2055 print '<!-- Includes JS for JQuery -->'."\n";
2056 if (defined('JS_JQUERY') && constant('JS_JQUERY')) {
2057 print '<script nonce="'.getNonce().'" src="'.JS_JQUERY.'jquery.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2058 } else {
2059 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2060 }
2061 if (defined('JS_JQUERY_UI') && constant('JS_JQUERY_UI')) {
2062 print '<script nonce="'.getNonce().'" src="'.JS_JQUERY_UI.'jquery-ui.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2063 } else {
2064 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery-ui.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2065 }
2066 // jQuery jnotify
2067 if (!getDolGlobalString('MAIN_DISABLE_JQUERY_JNOTIFY') && !defined('DISABLE_JQUERY_JNOTIFY')) {
2068 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jnotify/jquery.jnotify.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2069 }
2070 // Table drag and drop lines
2071 if (empty($disableforlogin) && !defined('DISABLE_JQUERY_TABLEDND')) {
2072 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/tablednd/jquery.tablednd.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2073 }
2074 // Chart
2075 if (empty($disableforlogin) && (!getDolGlobalString('MAIN_JS_GRAPH') || getDolGlobalString('MAIN_JS_GRAPH') == 'chart') && !defined('DISABLE_JS_GRAPH')) {
2076 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/nnnick/chartjs/dist/chart.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2077 }
2078
2079 // jQuery jeditable for Edit In Place features
2080 if (getDolGlobalString('MAIN_USE_JQUERY_JEDITABLE') && !defined('DISABLE_JQUERY_JEDITABLE')) {
2081 print '<!-- JS to manage editInPlace feature -->'."\n";
2082 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2083 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-datepicker.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2084 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-autocomplete.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2085 print '<script>'."\n";
2086 print 'var urlSaveInPlace = \''.DOL_URL_ROOT.'/core/ajax/saveinplace.php\';'."\n";
2087 print 'var urlLoadInPlace = \''.DOL_URL_ROOT.'/core/ajax/loadinplace.php\';'."\n";
2088 print 'var tooltipInPlace = \''.$langs->transnoentities('ClickToEdit').'\';'."\n"; // Added in title attribute of span
2089 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 ?
2090 print 'var cancelInPlace = \''.$langs->trans("Cancel").'\';'."\n";
2091 print 'var submitInPlace = \''.$langs->trans('Ok').'\';'."\n";
2092 print 'var indicatorInPlace = \'<img src="'.DOL_URL_ROOT."/theme/".$conf->theme."/img/working.gif".'">\';'."\n";
2093 print 'var withInPlace = 300;'; // width in pixel for default string edit
2094 print '</script>'."\n";
2095 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/editinplace.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2096 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ckeditor.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2097 }
2098 // jQuery Timepicker
2099 if (getDolGlobalString('MAIN_USE_JQUERY_TIMEPICKER') || defined('REQUIRE_JQUERY_TIMEPICKER')) {
2100 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/timepicker/jquery-ui-timepicker-addon.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2101 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/timepicker.js.php?lang='.$langs->defaultlang.($ext ? '&amp;'.$ext : '').'"></script>'."\n";
2102 }
2103 if (!defined('DISABLE_SELECT2') && (getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') || defined('REQUIRE_JQUERY_MULTISELECT'))) {
2104 // jQuery plugin "mutiselect", "multiple-select", "select2", ...
2105 $tmpplugin = !getDolGlobalString('MAIN_USE_JQUERY_MULTISELECT') ? constant('REQUIRE_JQUERY_MULTISELECT') : $conf->global->MAIN_USE_JQUERY_MULTISELECT;
2106 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
2107 }
2108 if (!defined('DISABLE_MULTISELECT')) { // jQuery plugin "mutiselect" to select with checkboxes. Can be removed once we have an enhanced search tool
2109 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/multiselect/jquery.multi-select.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2110 }
2111 }
2112
2113 if (!$disablejs && !empty($conf->use_javascript_ajax)) {
2114 // CKEditor
2115 if (empty($disableforlogin) && (isModEnabled('fckeditor') && (!getDolGlobalString('FCKEDITOR_EDITORNAME') || getDolGlobalString('FCKEDITOR_EDITORNAME') == 'ckeditor') && !defined('DISABLE_CKEDITOR')) || defined('FORCE_CKEDITOR')) {
2116 print '<!-- Includes JS for CKEditor -->'."\n";
2117 $pathckeditor = DOL_URL_ROOT.'/includes/ckeditor/ckeditor/';
2118 $jsckeditor = 'ckeditor.js';
2119 if (constant('JS_CKEDITOR')) {
2120 // To use external ckeditor 4 js lib
2121 $pathckeditor = constant('JS_CKEDITOR');
2122 }
2123 print '<script nonce="'.getNonce().'">';
2124 print '/* enable ckeditor by main.inc.php */';
2125 print 'var CKEDITOR_BASEPATH = \''.dol_escape_js($pathckeditor).'\';'."\n";
2126 print 'var ckeditorConfig = \''.dol_escape_js(dol_buildpath($themesubdir.'/theme/'.$conf->theme.'/ckeditor/config.js'.($ext ? '?'.$ext : ''), 1)).'\';'."\n"; // $themesubdir='' in standard usage
2127 print 'var ckeditorFilebrowserBrowseUrl = \''.DOL_URL_ROOT.'/core/filemanagerdol/browser/default/browser.php?Connector='.DOL_URL_ROOT.'/core/filemanagerdol/connectors/php/connector.php\';'."\n";
2128 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";
2129 print '</script>'."\n";
2130 print '<script src="'.$pathckeditor.$jsckeditor.($ext ? '?'.$ext : '').'"></script>'."\n";
2131 print '<script>';
2132 if (GETPOST('mode', 'aZ09') == 'Full_inline') {
2133 print 'CKEDITOR.disableAutoInline = false;'."\n";
2134 } else {
2135 print 'CKEDITOR.disableAutoInline = true;'."\n";
2136 }
2137 print '</script>'."\n";
2138 }
2139
2140 // 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).
2141 if (!defined('NOBROWSERNOTIF') && !defined('NOREQUIREMENU') && !defined('NOLOGIN')) {
2142 $enablebrowsernotif = false;
2143 if (isModEnabled('agenda') && getDolGlobalString('AGENDA_REMINDER_BROWSER')) {
2144 $enablebrowsernotif = true;
2145 }
2146 if ($conf->browser->layout == 'phone') {
2147 $enablebrowsernotif = false;
2148 }
2149 if ($enablebrowsernotif) {
2150 print '<!-- Includes JS of Dolibarr (browser layout = '.$conf->browser->layout.')-->'."\n";
2151 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/lib_notification.js.php'.($ext ? '?'.$ext : '').'"></script>'."\n";
2152 }
2153 }
2154
2155 // Global js function
2156 print '<!-- Includes JS of Dolibarr -->'."\n";
2157 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/core/js/lib_head.js.php?lang='.$langs->defaultlang.($ext ? '&amp;'.$ext : '').'"></script>'."\n";
2158
2159 // Leaflet TODO use dolibarr files
2160 if (getDolGlobalString('MAIN_USE_GEOPHP')) {
2161 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/leaflet/leaflet.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2162 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/includes/leaflet/leaflet-geoman.min.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2163 }
2164
2165 // JS forced by modules (relative url starting with /)
2166 if (!empty($conf->modules_parts['js'])) { // $conf->modules_parts['js'] is array('module'=>array('file1','file2'))
2167 $arrayjs = (array) $conf->modules_parts['js'];
2168 foreach ($arrayjs as $modjs => $filesjs) {
2169 $filesjs = (array) $filesjs; // To be sure filejs is an array
2170 foreach ($filesjs as $jsfile) {
2171 // jsfile is a relative path
2172 $urlforjs = dol_buildpath($jsfile, 1);
2173 if ($urlforjs && $urlforjs != '/') {
2174 print '<!-- Include JS added by module '.$modjs.'-->'."\n";
2175 print '<script nonce="'.getNonce().'" src="'.$urlforjs.((strpos($jsfile, '?') === false) ? '?' : '&amp;').'lang='.$langs->defaultlang.'"></script>'."\n";
2176 } else {
2177 dol_syslog("Warning: module ".$modjs." declared a js path file for a file we can't find.", LOG_WARNING);
2178 }
2179 }
2180 }
2181 }
2182 // JS forced by page in top_htmlhead (relative url starting with /)
2183 if (is_array($arrayofjs)) {
2184 print '<!-- Includes JS added by page -->'."\n";
2185 foreach ($arrayofjs as $jsfile) {
2186 if (preg_match('/^(http|\/\/)/i', $jsfile)) {
2187 print '<script nonce="'.getNonce().'" src="'.$jsfile.((strpos($jsfile, '?') === false) ? '?' : '&amp;').'lang='.$langs->defaultlang.'"></script>'."\n";
2188 } else {
2189 print '<script nonce="'.getNonce().'" src="'.dol_buildpath($jsfile, 1).((strpos($jsfile, '?') === false) ? '?' : '&amp;').'lang='.$langs->defaultlang.'"></script>'."\n";
2190 }
2191 }
2192 }
2193 }
2194
2195 //If you want to load custom javascript file from your selected theme directory
2196 if (getDolGlobalString('ALLOW_THEME_JS')) {
2197 $theme_js = dol_buildpath('/theme/'.$conf->theme.'/'.$conf->theme.'.js', 0);
2198 if (file_exists($theme_js)) {
2199 print '<script nonce="'.getNonce().'" src="'.DOL_URL_ROOT.'/theme/'.$conf->theme.'/'.$conf->theme.'.js'.($ext ? '?'.$ext : '').'"></script>'."\n";
2200 }
2201 }
2202
2203 if (!empty($head)) {
2204 print $head."\n";
2205 }
2206 if (getDolGlobalString('MAIN_HTML_HEADER')) {
2207 print getDolGlobalString('MAIN_HTML_HEADER') . "\n";
2208 }
2209
2210 $parameters = array();
2211 $result = $hookmanager->executeHooks('addHtmlHeader', $parameters); // Note that $action and $object may have been modified by some hooks
2212 print $hookmanager->resPrint; // Replace Title to show
2213
2214 print "</head>\n\n";
2215 }
2216
2217 $conf->headerdone = 1; // To tell header was output
2218}
2219
2220
2237function top_menu($head, $title = '', $target = '', $disablejs = 0, $disablehead = 0, $arrayofjs = array(), $arrayofcss = array(), $morequerystring = '', $helppagename = '')
2238{
2239 global $user, $conf, $langs, $db, $form;
2240 global $dolibarr_main_authentication, $dolibarr_main_demo;
2241 global $hookmanager, $menumanager;
2242
2243 $searchform = '';
2244
2245 // Instantiate hooks for external modules
2246 $hookmanager->initHooks(array('toprightmenu'));
2247
2248 $toprightmenu = '';
2249
2250 // For backward compatibility with old modules
2251 if (empty($conf->headerdone)) {
2252 $disablenofollow = 0;
2253 top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss, 0, $disablenofollow);
2254 print '<body id="mainbody">';
2255 }
2256
2257 /*
2258 * Top menu
2259 */
2260 if ((empty($conf->dol_hide_topmenu) || GETPOSTINT('dol_invisible_topmenu')) && (!defined('NOREQUIREMENU') || !constant('NOREQUIREMENU'))) {
2261 if (!isset($form) || !is_object($form)) {
2262 include_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php';
2263 $form = new Form($db);
2264 }
2265
2266 print "\n".'<!-- Start top horizontal -->'."\n";
2267
2268 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.
2269
2270 // Show menu entries
2271 print '<div id="tmenu_tooltip'.(!getDolGlobalString('MAIN_MENU_INVERT') ? '' : 'invert').'" class="tmenu">'."\n";
2272 // @phan-suppress-next-line PhanRedefinedClassReference
2273 $menumanager->atarget = $target;
2274 // @phan-suppress-next-line PhanRedefinedClassReference
2275 $menumanager->showmenu('top', array('searchform' => $searchform)); // This contains a \n
2276 print "</div>\n";
2277
2278 // Define link to login card
2279 $appli = constant('DOL_APPLICATION_TITLE');
2280 if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
2281 $appli = getDolGlobalString('MAIN_APPLICATION_TITLE');
2282 if (preg_match('/\d\.\d/', $appli)) {
2283 if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) {
2284 $appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core
2285 }
2286 } else {
2287 $appli .= " ".DOL_VERSION;
2288 }
2289 } else {
2290 $appli .= " ".DOL_VERSION;
2291 }
2292
2293 if (getDolGlobalInt('MAIN_FEATURES_LEVEL')) {
2294 $appli .= "<br>".$langs->trans("LevelOfFeature").': '.getDolGlobalInt('MAIN_FEATURES_LEVEL');
2295 }
2296
2297 $logouttext = '';
2298 $logouthtmltext = '';
2299 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2300 //$logouthtmltext=$appli.'<br>';
2301 $stringforfirstkey = $langs->trans("KeyboardShortcut");
2302 if ($conf->browser->name == 'chrome') {
2303 $stringforfirstkey .= ' ALT +';
2304 } elseif ($conf->browser->name == 'firefox') {
2305 $stringforfirstkey .= ' ALT + SHIFT +';
2306 } else {
2307 $stringforfirstkey .= ' CTL +';
2308 }
2309 if ($_SESSION["dol_authmode"] != 'forceuser' && $_SESSION["dol_authmode"] != 'http') {
2310 $logouthtmltext .= $langs->trans("Logout").'<br>';
2311 $logouttext .= '<a accesskey="l" href="'.DOL_URL_ROOT.'/user/logout.php?token='.newToken().'">';
2312 $logouttext .= img_picto($langs->trans('Logout').' ('.$stringforfirstkey.' l)', 'sign-out', '', 0, 0, 0, '', 'atoplogin valignmiddle');
2313 $logouttext .= '</a>';
2314 } else {
2315 $logouthtmltext .= $langs->trans("NoLogoutProcessWithAuthMode", $_SESSION["dol_authmode"]);
2316 $logouttext .= img_picto($langs->trans('Logout').' ('.$stringforfirstkey.' l)', 'sign-out', '', 0, 0, 0, '', 'atoplogin valignmiddle opacitymedium');
2317 }
2318 }
2319
2320 print '<div class="login_block usedropdown">'."\n";
2321
2322 $toprightmenu .= '<div class="login_block_other valignmiddle">';
2323
2324 // Execute hook printTopRightMenu (hooks should output string like '<div class="login"><a href="">mylink</a></div>')
2325 $parameters = array();
2326 $result = $hookmanager->executeHooks('printTopRightMenu', $parameters); // Note that $action and $object may have been modified by some hooks
2327 if (is_numeric($result)) {
2328 if ($result == 0) {
2329 $toprightmenu .= $hookmanager->resPrint; // add
2330 } else {
2331 $toprightmenu = $hookmanager->resPrint; // replace
2332 }
2333 } else {
2334 $toprightmenu .= $result; // For backward compatibility
2335 }
2336
2337 // Link to module builder
2338 if (isModEnabled('modulebuilder')) {
2339 $text = '<a href="'.DOL_URL_ROOT.'/modulebuilder/index.php?mainmenu=home&leftmenu=admintools" target="modulebuilder">';
2340 //$text.= img_picto(":".$langs->trans("ModuleBuilder"), 'printer_top.png', 'class="printer"');
2341 $text .= '<span class="fa fa-bug atoplogin valignmiddle"></span>';
2342 $text .= '</a>';
2343 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
2344 $toprightmenu .= $form->textwithtooltip('', $langs->trans("ModuleBuilder"), 2, 1, $text, 'login_block_elem', 2);
2345 }
2346
2347 // Link to print main content area (optioncss=print)
2348 if (!getDolGlobalString('MAIN_PRINT_DISABLELINK') && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2349 $qs = dol_escape_htmltag($_SERVER["QUERY_STRING"]);
2350
2351 if (isset($_POST) && is_array($_POST)) {
2352 foreach ($_POST as $key => $value) {
2353 $key = preg_replace('/[^a-z0-9_\.\-\[\]]/i', '', $key);
2354 if (in_array($key, array('action', 'massaction', 'password'))) {
2355 continue;
2356 }
2357 if (!is_array($value)) {
2358 if ($value !== '') {
2359 $qs .= '&'.urlencode($key).'='.urlencode($value);
2360 }
2361 } else {
2362 foreach ($value as $value2) {
2363 if (($value2 !== '') && (!is_array($value2))) {
2364 $qs .= '&'.urlencode($key).'[]='.urlencode($value2);
2365 }
2366 }
2367 }
2368 }
2369 }
2370 $qs .= (($qs && $morequerystring) ? '&' : '').$morequerystring;
2371 $text = '<a href="'.dol_escape_htmltag($_SERVER["PHP_SELF"]).'?'.$qs.($qs ? '&' : '').'optioncss=print" target="_blank" rel="noopener noreferrer">';
2372 //$text.= img_picto(":".$langs->trans("PrintContentArea"), 'printer_top.png', 'class="printer"');
2373 $text .= '<span class="fa fa-print atoplogin valignmiddle"></span>';
2374 $text .= '</a>';
2375 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
2376 $toprightmenu .= $form->textwithtooltip('', $langs->trans("PrintContentArea"), 2, 1, $text, 'login_block_elem', 2);
2377 }
2378
2379 // Link to Dolibarr wiki pages
2380 if (!getDolGlobalString('MAIN_HELP_DISABLELINK') && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2381 $langs->load("help");
2382
2383 $helpbaseurl = '';
2384 $helppage = '';
2385 $mode = '';
2386 $helppresent = '';
2387
2388 if (empty($helppagename)) {
2389 $helppagename = 'EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios|DE:Benutzerdokumentation';
2390 } else {
2391 $helppresent = 'helppresent';
2392 }
2393
2394 // Get helpbaseurl, helppage and mode from helppagename and langs
2395 $arrayres = getHelpParamFor($helppagename, $langs);
2396 $helpbaseurl = $arrayres['helpbaseurl'];
2397 $helppage = $arrayres['helppage'];
2398 $mode = $arrayres['mode'];
2399
2400 // Link to help pages
2401 if ($helpbaseurl && $helppage) {
2402 $text = '';
2403 $title = $langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage' : 'GoToHelpPage').', ';
2404 if ($mode == 'wiki') {
2405 $title .= '<br>'.img_picto('', 'globe', 'class="pictofixedwidth"').$langs->trans("PageWiki").' '.dol_escape_htmltag('"'.strtr($helppage, '_', ' ').'"');
2406 if ($helppresent) {
2407 $title .= ' <span class="opacitymedium">('.$langs->trans("DedicatedPageAvailable").')</span>';
2408 } else {
2409 $title .= ' <span class="opacitymedium">('.$langs->trans("HomePage").')</span>';
2410 }
2411 }
2412 $text .= '<a class="help" target="_blank" rel="noopener noreferrer" href="';
2413 if ($mode == 'wiki') {
2414 // @phan-suppress-next-line PhanPluginPrintfVariableFormatString
2415 $text .= sprintf($helpbaseurl, urlencode(html_entity_decode($helppage)));
2416 } else {
2417 // @phan-suppress-next-line PhanPluginPrintfVariableFormatString
2418 $text .= sprintf($helpbaseurl, $helppage);
2419 }
2420 $text .= '">';
2421 $text .= '<span class="fa fa-question-circle atoplogin valignmiddle'.($helppresent ? ' '.$helppresent : '').'"></span>';
2422 $text .= '<span class="fa fa-long-arrow-alt-up helppresentcircle'.($helppresent ? '' : ' unvisible').'"></span>';
2423 $text .= '</a>';
2424 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
2425 $toprightmenu .= $form->textwithtooltip('', $title, 2, 1, $text, 'login_block_elem', 2);
2426 }
2427
2428 // Version
2429 if (getDolGlobalString('MAIN_SHOWDATABASENAMEINHELPPAGESLINK')) {
2430 $langs->load('admin');
2431 $appli .= '<br>'.$langs->trans("Database").': '.$db->database_name;
2432 }
2433 }
2434
2435 // Version
2436 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && getDolGlobalInt('MAIN_HIDE_VERSION') == 0) {
2437 $text = '<span class="aversion"><span class="hideonsmartphone small">'.DOL_VERSION.'</span></span>';
2438 // @phan-suppress-next-line PhanPluginSuspiciousParamPosition
2439 $toprightmenu .= $form->textwithtooltip('', $appli, 2, 1, $text, 'login_block_elem', 2);
2440 }
2441
2442 // Logout link
2443 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2444 $toprightmenu .= $form->textwithtooltip('', $logouthtmltext, 2, 1, $logouttext, 'login_block_elem logout-btn', 2);
2445 }
2446
2447 $toprightmenu .= '</div>'; // end div class="login_block_other"
2448
2449
2450 // Add block for tools
2451 $toprightmenu .= '<div class="login_block_tools valignmiddle">';
2452
2453 $mode = -1;
2454 $toprightmenu .= '<div class="inline-block nowrap" style="padding: 0px;">';
2455
2456 if (getDolGlobalString('MAIN_USE_TOP_MENU_SEARCH_DROPDOWN')) {
2457 // Add search dropdown
2458 $toprightmenu .= top_menu_search();
2459 }
2460
2461 if (getDolGlobalString('MAIN_USE_TOP_MENU_QUICKADD_DROPDOWN')) {
2462 // Add search dropdown
2463 $toprightmenu .= top_menu_quickadd();
2464 }
2465
2466 // Add bookmark dropdown
2467 $toprightmenu .= top_menu_bookmark();
2468
2469 $toprightmenu .= '</div>';
2470
2471 $toprightmenu .= '</div>'."\n";
2472
2473 // Add block for user photo and name
2474 $toprightmenu .= '<div class="login_block_user">';
2475
2476 $mode = -1;
2477 $toprightmenu .= '<div class="inline-block login_block_elem login_block_elem_name nowrap centpercent" style="padding: 0px;">';
2478
2479 // Add user dropdown
2480 $toprightmenu .= top_menu_user();
2481
2482 $toprightmenu .= '</div>';
2483
2484 $toprightmenu .= '</div>'."\n";
2485
2486
2487 print $toprightmenu;
2488
2489 print "</div>\n"; // end div class="login_block"
2490
2491 print '</header>';
2492 //print '<header class="header2">&nbsp;</header>';
2493
2494 print '<div style="clear: both;"></div>';
2495 print "<!-- End top horizontal menu -->\n\n";
2496 }
2497
2498 if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) {
2499 print '<!-- Begin div id-container --><div id="id-container" class="id-container">';
2500 }
2501}
2502
2503
2511function top_menu_user($hideloginname = 0, $urllogout = '')
2512{
2513 global $langs, $conf, $db, $hookmanager, $user, $mysoc;
2514 global $dolibarr_main_authentication, $dolibarr_main_demo;
2515 global $menumanager;
2516
2517 $langs->load('companies');
2518
2519 $userImage = $userDropDownImage = '';
2520 if (!empty($user->photo)) {
2521 $userImage = Form::showphoto('userphoto', $user, 0, 0, 0, 'photouserphoto userphoto', 'small', 0, 1);
2522 $userDropDownImage = Form::showphoto('userphoto', $user, 0, 0, 0, 'dropdown-user-image', 'small', 0, 1);
2523 } else {
2524 $nophoto = '/public/theme/common/user_anonymous.png';
2525 if ($user->gender == 'man') {
2526 $nophoto = '/public/theme/common/user_man.png';
2527 }
2528 if ($user->gender == 'woman') {
2529 $nophoto = '/public/theme/common/user_woman.png';
2530 }
2531
2532 $userImage = '<img class="photo photouserphoto userphoto" alt="" src="'.DOL_URL_ROOT.$nophoto.'" aria-hidden="true">';
2533 $userDropDownImage = '<img class="photo dropdown-user-image" alt="" src="'.DOL_URL_ROOT.$nophoto.'">';
2534 }
2535
2536 $dropdownBody = '';
2537 $dropdownBody .= '<span id="topmenulogincompanyinfo-btn"><i class="fa fa-caret-right"></i> '.$langs->trans("ShowCompanyInfos").'</span>';
2538 $dropdownBody .= '<div id="topmenulogincompanyinfo" >';
2539
2540 $dropdownBody .= '<br><b>'.$langs->trans("Company").'</b>: <span>'.dol_escape_htmltag($mysoc->name).'</span>';
2541 $idprofcursor = 0;
2542 while ($idprofcursor < 10) {
2543 $idprofcursor++;
2544 $constkeyforprofid = 'MAIN_INFO_PROFID'.$idprofcursor;
2545 if ($idprofcursor == 1) {
2546 $constkeyforprofid = 'MAIN_INFO_SIREN';
2547 }
2548 if ($idprofcursor == 2) {
2549 $constkeyforprofid = 'MAIN_INFO_SIRET';
2550 }
2551 if ($idprofcursor == 3) {
2552 $constkeyforprofid = 'MAIN_INFO_APE';
2553 }
2554 if ($idprofcursor == 4) {
2555 $constkeyforprofid = 'MAIN_INFO_RCS';
2556 }
2557 $showprofid = (($idprofcursor <= 6) && $langs->transcountry("ProfId".$idprofcursor, $mysoc->country_code) != '-');
2558 if ($idprofcursor > 6 && getDolGlobalString($constkeyforprofid)) {
2559 $showprofid = true;
2560 }
2561 if ($showprofid) {
2562 $dropdownBody .= '<br><b>'.$langs->transcountry("ProfId".$idprofcursor, $mysoc->country_code).'</b>: <span>'.dol_print_profids(getDolGlobalString($constkeyforprofid), '1').'</span>';
2563 }
2564 }
2565 $dropdownBody .= '<br><b>'.$langs->trans("VATIntraShort").'</b>: <span>'.dol_print_profids(getDolGlobalString("MAIN_INFO_TVAINTRA"), 'VAT').'</span>';
2566 $dropdownBody .= '<br><b>'.$langs->trans("Country").'</b>: <span>'.($mysoc->country_code ? $langs->trans("Country".$mysoc->country_code) : '').'</span>';
2567 if (isModEnabled('multicurrency')) {
2568 $dropdownBody .= '<br><b>'.$langs->trans("Currency").'</b>: <span>'.$conf->currency.'</span>';
2569 }
2570 $dropdownBody .= '</div>';
2571
2572 $dropdownBody .= '<br>';
2573 $dropdownBody .= '<span id="topmenuloginmoreinfo-btn"><i class="fa fa-caret-right"></i> '.$langs->trans("ShowMoreInfos").'</span>';
2574 $dropdownBody .= '<div id="topmenuloginmoreinfo" >';
2575
2576 // login infos
2577 if (!empty($user->admin)) {
2578 $dropdownBody .= '<br><b>'.$langs->trans("Administrator").'</b>: '.yn($user->admin);
2579 }
2580 $company = '';
2581 if (!empty($user->socid)) { // Add third party for external users
2582 $thirdpartystatic = new Societe($db);
2583 $thirdpartystatic->fetch($user->socid);
2584 $companylink = ' '.$thirdpartystatic->getNomUrl(2); // picto only of company
2585 $company = ' ('.$langs->trans("Company").': '.$thirdpartystatic->name.')';
2586 }
2587 $type = ($user->socid ? $langs->trans("External").$company : $langs->trans("Internal"));
2588 $dropdownBody .= '<br><b>'.$langs->trans("Type").':</b> '.$type;
2589 $dropdownBody .= '<br><b>'.$langs->trans("Status").'</b>: '.$user->getLibStatut(0);
2590 $dropdownBody .= '<br>';
2591
2592 $dropdownBody .= '<br><u>'.$langs->trans("Session").'</u>';
2593 $dropdownBody .= '<br><b>'.$langs->trans("IPAddress").'</b>: '.dol_escape_htmltag($_SERVER["REMOTE_ADDR"]);
2594 if (getDolGlobalString('MAIN_MODULE_MULTICOMPANY')) {
2595 $dropdownBody .= '<br><b>'.$langs->trans("ConnectedOnMultiCompany").':</b> '.$conf->entity.' (user entity '.$user->entity.')';
2596 }
2597 $dropdownBody .= '<br><b>'.$langs->trans("AuthenticationMode").':</b> '.$_SESSION["dol_authmode"].(empty($dolibarr_main_demo) ? '' : ' (demo)');
2598 $dropdownBody .= '<br><b>'.$langs->trans("ConnectedSince").':</b> '.dol_print_date($user->datelastlogin, "dayhour", 'tzuser');
2599 $dropdownBody .= '<br><b>'.$langs->trans("PreviousConnexion").':</b> '.dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser');
2600 $dropdownBody .= '<br><b>'.$langs->trans("CurrentTheme").':</b> '.$conf->theme;
2601 // @phan-suppress-next-line PhanRedefinedClassReference
2602 $dropdownBody .= '<br><b>'.$langs->trans("CurrentMenuManager").':</b> '.(isset($menumanager) ? $menumanager->name : 'unknown');
2603 $langFlag = picto_from_langcode($langs->getDefaultLang());
2604 $dropdownBody .= '<br><b>'.$langs->trans("CurrentUserLanguage").':</b> '.($langFlag ? $langFlag.' ' : '').$langs->getDefaultLang();
2605
2606 $tz = (int) $_SESSION['dol_tz'] + (int) $_SESSION['dol_dst'];
2607 $dropdownBody .= '<br><b>'.$langs->trans("ClientTZ").':</b> '.($tz ? ($tz >= 0 ? '+' : '').$tz : '');
2608 $dropdownBody .= ' ('.$_SESSION['dol_tz_string'].')';
2609 //$dropdownBody .= ' &nbsp; &nbsp; &nbsp; '.$langs->trans("DaylingSavingTime").': ';
2610 //if ($_SESSION['dol_dst'] > 0) $dropdownBody .= yn(1);
2611 //else $dropdownBody .= yn(0);
2612
2613 $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>';
2614 $dropdownBody .= '<br><b>'.$langs->trans("Layout").':</b> '.$conf->browser->layout;
2615 $dropdownBody .= '<br><b>'.$langs->trans("Screen").':</b> '.$_SESSION['dol_screenwidth'].' x '.$_SESSION['dol_screenheight'];
2616 if ($conf->browser->layout == 'phone') {
2617 $dropdownBody .= '<br><b>'.$langs->trans("Phone").':</b> '.$langs->trans("Yes");
2618 }
2619 if (!empty($_SESSION["disablemodules"])) {
2620 $dropdownBody .= '<br><b>'.$langs->trans("DisabledModules").':</b> <br>'.implode(', ', explode(',', $_SESSION["disablemodules"]));
2621 }
2622 $dropdownBody .= '</div>';
2623
2624 // Execute hook
2625 $parameters = array('user' => $user, 'langs' => $langs);
2626 $result = $hookmanager->executeHooks('printTopRightMenuLoginDropdownBody', $parameters); // Note that $action and $object may have been modified by some hooks
2627 if (is_numeric($result)) {
2628 if ($result == 0) {
2629 $dropdownBody .= $hookmanager->resPrint; // add
2630 } else {
2631 $dropdownBody = $hookmanager->resPrint; // replace
2632 }
2633 }
2634
2635 if (empty($urllogout)) {
2636 $urllogout = DOL_URL_ROOT.'/user/logout.php?token='.newToken();
2637 }
2638
2639 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
2640 // accesskey is for Mac: CTRL + key for all browsers
2641 $stringforfirstkey = $langs->trans("KeyboardShortcut");
2642 if ($conf->browser->name == 'chrome') {
2643 $stringforfirstkey .= ' ALT +';
2644 } elseif ($conf->browser->name == 'firefox') {
2645 $stringforfirstkey .= ' ALT + SHIFT +';
2646 } else {
2647 $stringforfirstkey .= ' CTL +';
2648 }
2649
2650 // Defined the links for bottom of card
2651 $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>';
2652 $urltovirtualcard = '/user/virtualcard.php?id='.((int) $user->id);
2653 $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');
2654 $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>';
2655
2656 $profilName = $user->getFullName($langs).' ('.$user->login.')';
2657 if (!empty($user->admin)) {
2658 $profilName = '<i class="far fa-star classfortooltip" title="'.$langs->trans("Administrator").'" ></i> '.$profilName;
2659 }
2660
2661 // Define version to show
2662 $appli = constant('DOL_APPLICATION_TITLE');
2663 if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
2664 $appli = getDolGlobalString('MAIN_APPLICATION_TITLE');
2665 if (preg_match('/\d\.\d/', $appli)) {
2666 if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) {
2667 $appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core
2668 }
2669 } else {
2670 $appli .= " ".DOL_VERSION;
2671 }
2672 } else {
2673 $appli .= " ".DOL_VERSION;
2674 }
2675
2676 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2677 $btnUser = '<!-- div for user link -->
2678 <div id="topmenu-login-dropdown" class="userimg atoplogin dropdown user user-menu inline-block">
2679 <a href="'.DOL_URL_ROOT.'/user/card.php?id='.$user->id.'" class="dropdown-toggle login-dropdown-a valignmiddle" data-toggle="dropdown">
2680 '.$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>' : '').'
2681 </a>
2682 <div class="dropdown-menu">
2683 <!-- User image -->
2684 <div class="user-header">
2685 '.$userDropDownImage.'
2686 <p>
2687 '.$profilName.'<br>';
2688 $title = '';
2689 if ($user->datelastlogin) {
2690 $title = $langs->trans("ConnectedSince").' : '.dol_print_date($user->datelastlogin, "dayhour", 'tzuser');
2691 if ($user->datepreviouslogin) {
2692 $title .= '<br>'.$langs->trans("PreviousConnexion").' : '.dol_print_date($user->datepreviouslogin, "dayhour", 'tzuser');
2693 }
2694 }
2695 $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>';
2696 if ($user->datepreviouslogin) {
2697 $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>';
2698 }
2699
2700 //$btnUser .= '<small class="classfortooltip"><i class="fa fa-cog"></i> '.$langs->trans("Version").' '.$appli.'</small>';
2701 $btnUser .= '
2702 </p>
2703 </div>
2704
2705 <!-- Menu Body user-->
2706 <div class="user-body">'.$dropdownBody.'</div>
2707
2708 <!-- Menu Footer-->
2709 <div class="user-footer">
2710 <div class="pull-left">
2711 '.$profilLink.'
2712 </div>
2713 <div class="pull-left">
2714 '.$virtuelcardLink.'
2715 </div>
2716 <div class="pull-right">
2717 '.$logoutLink.'
2718 </div>
2719 <div class="clearboth"></div>
2720 </div>
2721
2722 </div>
2723 </div>';
2724 } else {
2725 $btnUser = '<!-- div for user link text browser -->
2726 <div id="topmenu-login-dropdown" class="userimg atoplogin dropdown user user-menu inline-block">
2727 <a href="'.DOL_URL_ROOT.'/user/card.php?id='.$user->id.'" class="valignmiddle" alt="'.$langs->trans("MyUserCard").'">
2728 '.$userImage.(empty($user->photo) ? '<span class="hidden-xs maxwidth200 atoploginusername hideonsmartphone paddingleft small valignmiddle">'.dol_trunc($user->firstname ? $user->firstname : $user->login, 10).'</span>' : '').'
2729 </a>
2730 </div>';
2731 }
2732
2733 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
2734 $btnUser .= '
2735 <!-- Code to show/hide the user drop-down -->
2736 <script>
2737 function closeTopMenuLoginDropdown() {
2738 //console.log("close login dropdown"); // This is call at each click on page, so we disable the log
2739 // Hide the menus.
2740 jQuery("#topmenu-login-dropdown").removeClass("open");
2741 }
2742 jQuery(document).ready(function() {
2743 jQuery(document).on("click", function(event) {
2744 // console.log("Click somewhere on screen");
2745 if (!$(event.target).closest("#topmenu-login-dropdown").length) {
2746 closeTopMenuLoginDropdown();
2747 }
2748 });
2749 ';
2750
2751
2752 //if ($conf->theme != 'md') {
2753 $btnUser .= '
2754 jQuery("#topmenu-login-dropdown .dropdown-toggle").on("click", function(event) {
2755 console.log("Click on #topmenu-login-dropdown .dropdown-toggle");
2756 event.preventDefault();
2757 jQuery("#topmenu-login-dropdown").toggleClass("open");
2758 });
2759
2760 jQuery("#topmenulogincompanyinfo-btn").on("click", function() {
2761 console.log("Click on #topmenulogincompanyinfo-btn");
2762 jQuery("#topmenulogincompanyinfo").slideToggle();
2763 });
2764
2765 jQuery("#topmenuloginmoreinfo-btn").on("click", function() {
2766 console.log("Click on #topmenuloginmoreinfo-btn");
2767 jQuery("#topmenuloginmoreinfo").slideToggle();
2768 });';
2769 //}
2770
2771 $btnUser .= '
2772 });
2773 </script>
2774 ';
2775 }
2776
2777 return $btnUser;
2778}
2779
2786{
2787 global $conf, $langs;
2788
2789 // Button disabled on text browser
2790 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
2791 return '';
2792 }
2793
2794 $html = '';
2795
2796 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
2797 // accesskey is for Mac: CTRL + key for all browsers
2798 $stringforfirstkey = $langs->trans("KeyboardShortcut");
2799 if ($conf->browser->os === 'macintosh') {
2800 $stringforfirstkey .= ' CTL +';
2801 } else {
2802 if ($conf->browser->name == 'chrome') {
2803 $stringforfirstkey .= ' ALT +';
2804 } elseif ($conf->browser->name == 'firefox') {
2805 $stringforfirstkey .= ' ALT + SHIFT +';
2806 } else {
2807 $stringforfirstkey .= ' CTL +';
2808 }
2809 }
2810
2811 if (!empty($conf->use_javascript_ajax)) {
2812 $html .= '<!-- div for quick add link -->
2813 <div id="topmenu-quickadd-dropdown" class="atoplogin dropdown inline-block">
2814 <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>
2815 <div class="dropdown-menu">'.printDropdownQuickadd().'</div>
2816 </div>';
2817 if (!defined('JS_JQUERY_DISABLE_DROPDOWN')) { // This may be set by some pages that use different jquery version to avoid errors
2818 $html .= '
2819 <!-- Code to show/hide the user drop-down for the quick add -->
2820 <script>
2821 jQuery(document).ready(function() {
2822 jQuery(document).on("click", function(event) {
2823 if (!$(event.target).closest("#topmenu-quickadd-dropdown").length) {
2824 // Hide the menus.
2825 $("#topmenu-quickadd-dropdown").removeClass("open");
2826 }
2827 });
2828 $("#topmenu-quickadd-dropdown .dropdown-toggle").on("click", function(event) {
2829 console.log("Click on #topmenu-quickadd-dropdown .dropdown-toggle");
2830 openQuickAddDropDown(event);
2831 });
2832
2833 // Key map shortcut
2834 $(document).keydown(function(event){
2835 var ostype = \''.dol_escape_js($conf->browser->os).'\';
2836 if (ostype === "macintosh") {
2837 if ( event.which === 65 && event.ctrlKey ) {
2838 console.log(\'control + a : trigger open quick add dropdown\');
2839 openQuickAddDropDown(event);
2840 }
2841 } else {
2842 if ( event.which === 65 && event.ctrlKey && event.shiftKey ) {
2843 console.log(\'control + shift + a : trigger open quick add dropdown\');
2844 openQuickAddDropDown(event);
2845 }
2846 }
2847 });
2848
2849 var openQuickAddDropDown = function(event) {
2850 event.preventDefault();
2851 $("#topmenu-quickadd-dropdown").toggleClass("open");
2852 //$("#top-quickadd-search-input").focus();
2853 }
2854 });
2855 </script>
2856 ';
2857 }
2858 }
2859
2860 return $html;
2861}
2862
2869{
2870 global $user, $langs, $hookmanager;
2871
2872 $items = array(
2873 'items' => array(
2874 array(
2875 "url" => "/adherents/card.php?action=create&amp;mainmenu=members",
2876 "title" => "MenuNewMember@members",
2877 "name" => "Adherent@members",
2878 "picto" => "object_member",
2879 "activation" => isModEnabled('member') && $user->hasRight("adherent", "write"), // vs hooking
2880 "position" => 5,
2881 ),
2882 array(
2883 "url" => "/societe/card.php?action=create&amp;mainmenu=companies",
2884 "title" => "MenuNewThirdParty@companies",
2885 "name" => "ThirdParty@companies",
2886 "picto" => "object_company",
2887 "activation" => isModEnabled("societe") && $user->hasRight("societe", "write"), // vs hooking
2888 "position" => 10,
2889 ),
2890 array(
2891 "url" => "/contact/card.php?action=create&amp;mainmenu=companies",
2892 "title" => "NewContactAddress@companies",
2893 "name" => "Contact@companies",
2894 "picto" => "object_contact",
2895 "activation" => isModEnabled("societe") && $user->hasRight("societe", "contact", "write"), // vs hooking
2896 "position" => 20,
2897 ),
2898 array(
2899 "url" => "/comm/propal/card.php?action=create&amp;mainmenu=commercial",
2900 "title" => "NewPropal@propal",
2901 "name" => "Proposal@propal",
2902 "picto" => "object_propal",
2903 "activation" => isModEnabled("propal") && $user->hasRight("propal", "write"), // vs hooking
2904 "position" => 30,
2905 ),
2906
2907 array(
2908 "url" => "/commande/card.php?action=create&amp;mainmenu=commercial",
2909 "title" => "NewOrder@orders",
2910 "name" => "Order@orders",
2911 "picto" => "object_order",
2912 "activation" => isModEnabled('order') && $user->hasRight("commande", "write"), // vs hooking
2913 "position" => 40,
2914 ),
2915 array(
2916 "url" => "/compta/facture/card.php?action=create&amp;mainmenu=billing",
2917 "title" => "NewBill@bills",
2918 "name" => "Bill@bills",
2919 "picto" => "object_bill",
2920 "activation" => isModEnabled('invoice') && $user->hasRight("facture", "write"), // vs hooking
2921 "position" => 50,
2922 ),
2923 array(
2924 "url" => "/contrat/card.php?action=create&amp;mainmenu=commercial",
2925 "title" => "NewContractSubscription@contracts",
2926 "name" => "Contract@contracts",
2927 "picto" => "object_contract",
2928 "activation" => isModEnabled('contract') && $user->hasRight("contrat", "write"), // vs hooking
2929 "position" => 60,
2930 ),
2931 array(
2932 "url" => "/supplier_proposal/card.php?action=create&amp;mainmenu=commercial",
2933 "title" => "SupplierProposalNew@supplier_proposal",
2934 "name" => "SupplierProposal@supplier_proposal",
2935 "picto" => "supplier_proposal",
2936 "activation" => isModEnabled('supplier_proposal') && $user->hasRight("supplier_invoice", "write"), // vs hooking
2937 "position" => 70,
2938 ),
2939 array(
2940 "url" => "/fourn/commande/card.php?action=create&amp;mainmenu=commercial",
2941 "title" => "NewSupplierOrderShort@orders",
2942 "name" => "SupplierOrder@orders",
2943 "picto" => "supplier_order",
2944 "activation" => (isModEnabled("fournisseur") && !getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "commande", "write")) || (isModEnabled("supplier_order") && $user->hasRight("supplier_invoice", "write")), // vs hooking
2945 "position" => 80,
2946 ),
2947 array(
2948 "url" => "/fourn/facture/card.php?action=create&amp;mainmenu=billing",
2949 "title" => "NewBill@bills",
2950 "name" => "SupplierBill@bills",
2951 "picto" => "supplier_invoice",
2952 "activation" => (isModEnabled("fournisseur") && !getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "write")) || (isModEnabled("supplier_invoice") && $user->hasRight("supplier_invoice", "write")), // vs hooking
2953 "position" => 90,
2954 ),
2955 array(
2956 "url" => "/ticket/card.php?action=create&amp;mainmenu=ticket",
2957 "title" => "NewTicket@ticket",
2958 "name" => "Ticket@ticket",
2959 "picto" => "ticket",
2960 "activation" => isModEnabled('ticket') && $user->hasRight("ticket", "write"), // vs hooking
2961 "position" => 100,
2962 ),
2963 array(
2964 "url" => "/fichinter/card.php?action=create&mainmenu=commercial",
2965 "title" => "NewIntervention@interventions",
2966 "name" => "Intervention@interventions",
2967 "picto" => "intervention",
2968 "activation" => isModEnabled('intervention') && $user->hasRight("ficheinter", "creer"), // vs hooking
2969 "position" => 110,
2970 ),
2971 array(
2972 "url" => "/product/card.php?action=create&amp;type=0&amp;mainmenu=products",
2973 "title" => "NewProduct@products",
2974 "name" => "Product@products",
2975 "picto" => "object_product",
2976 "activation" => isModEnabled("product") && $user->hasRight("produit", "write"), // vs hooking
2977 "position" => 400,
2978 ),
2979 array(
2980 "url" => "/product/card.php?action=create&amp;type=1&amp;mainmenu=products",
2981 "title" => "NewService@products",
2982 "name" => "Service@products",
2983 "picto" => "object_service",
2984 "activation" => isModEnabled("service") && $user->hasRight("service", "write"), // vs hooking
2985 "position" => 410,
2986 ),
2987 array(
2988 "url" => "/user/card.php?action=create&amp;type=1&amp;mainmenu=home",
2989 "title" => "AddUser@users",
2990 "name" => "User@users",
2991 "picto" => "user",
2992 "activation" => $user->hasRight("user", "user", "write"), // vs hooking
2993 "position" => 500,
2994 ),
2995 ),
2996 );
2997
2998 $dropDownQuickAddHtml = '';
2999
3000 // Define $dropDownQuickAddHtml
3001 $dropDownQuickAddHtml .= '<div class="quickadd-body dropdown-body">';
3002 $dropDownQuickAddHtml .= '<div class="dropdown-quickadd-list">';
3003
3004 // Allow the $items of the menu to be manipulated by modules
3005 $parameters = array();
3006 $hook_items = $items;
3007 $reshook = $hookmanager->executeHooks('menuDropdownQuickaddItems', $parameters, $hook_items); // Note that $action and $object may have been modified by some hooks
3008 if (is_numeric($reshook) && !empty($hookmanager->resArray) && is_array($hookmanager->resArray)) {
3009 if ($reshook == 0) {
3010 $items['items'] = array_merge($items['items'], $hookmanager->resArray); // add
3011 } else {
3012 $items = $hookmanager->resArray; // replace
3013 }
3014
3015 // Sort menu items by 'position' value
3016 $position = array();
3017 foreach ($items['items'] as $key => $row) {
3018 $position[$key] = $row['position'];
3019 }
3020 $array1_sort_order = SORT_ASC;
3021 array_multisort($position, $array1_sort_order, $items['items']);
3022 }
3023
3024 foreach ($items['items'] as $item) {
3025 if (!$item['activation']) {
3026 continue;
3027 }
3028 $langs->load(explode('@', $item['title'])[1]);
3029 $langs->load(explode('@', $item['name'])[1]);
3030 $dropDownQuickAddHtml .= '
3031 <a class="dropdown-item quickadd-item" href="'.DOL_URL_ROOT.$item['url'].'" title="'.$langs->trans(explode('@', $item['title'])[0]).'">
3032 '. img_picto('', $item['picto'], 'style="width:18px;"') . ' ' . $langs->trans(explode('@', $item['name'])[0]) . '</a>
3033 ';
3034 }
3035
3036 $dropDownQuickAddHtml .= '</div>';
3037 $dropDownQuickAddHtml .= '</div>';
3038
3039 return $dropDownQuickAddHtml;
3040}
3041
3048{
3049 global $langs, $conf, $user;
3050
3051 $html = '';
3052
3053 // Define $bookmarks
3054 if (!isModEnabled('bookmark') || !$user->hasRight('bookmark', 'lire')) {
3055 return $html;
3056 }
3057
3058 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
3059 // accesskey is for Mac: CTRL + key for all browsers
3060 $stringforfirstkey = $langs->trans("KeyboardShortcut");
3061 if ($conf->browser->os === 'macintosh') {
3062 $stringforfirstkey .= ' CTL +';
3063 } else {
3064 if ($conf->browser->name == 'chrome') {
3065 $stringforfirstkey .= ' ALT +';
3066 } elseif ($conf->browser->name == 'firefox') {
3067 $stringforfirstkey .= ' ALT + SHIFT +';
3068 } else {
3069 $stringforfirstkey .= ' CTL +';
3070 }
3071 }
3072
3073 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
3074 include_once DOL_DOCUMENT_ROOT.'/bookmarks/bookmarks.lib.php';
3075 $langs->load("bookmarks");
3076
3077 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
3078 $html .= '<div id="topmenu-bookmark-dropdown" class="dropdown inline-block">';
3079 $html .= printDropdownBookmarksList();
3080 $html .= '</div>';
3081 } else {
3082 $html .= '<!-- div for bookmark link -->
3083 <div id="topmenu-bookmark-dropdown" class="dropdown inline-block">
3084 <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>
3085 <div class="dropdown-menu">
3087 </div>
3088 </div>';
3089
3090 $html .= '
3091 <!-- Code to show/hide the bookmark drop-down -->
3092 <script>
3093 jQuery(document).ready(function() {
3094 jQuery(document).on("click", function(event) {
3095 if (!$(event.target).closest("#topmenu-bookmark-dropdown").length) {
3096 //console.log("close bookmark dropdown - we click outside");
3097 // Hide the menus.
3098 $("#topmenu-bookmark-dropdown").removeClass("open");
3099 }
3100 });
3101
3102 jQuery("#topmenu-bookmark-dropdown .dropdown-toggle").on("click", function(event) {
3103 console.log("Click on #topmenu-bookmark-dropdown .dropdown-toggle");
3104 openBookMarkDropDown(event);
3105 });
3106
3107 // Key map shortcut
3108 jQuery(document).keydown(function(event) {
3109 var ostype = \''.dol_escape_js($conf->browser->os).'\';
3110 if (ostype === "macintosh") {
3111 if ( event.which === 66 && event.ctrlKey ) {
3112 console.log("Click on control + b : trigger open bookmark dropdown");
3113 openBookMarkDropDown(event);
3114 }
3115 } else {
3116 if ( event.which === 66 && event.ctrlKey && event.shiftKey ) {
3117 console.log("Click on control + shift + b : trigger open bookmark dropdown");
3118 openBookMarkDropDown(event);
3119 }
3120 }
3121 });
3122
3123 var openBookMarkDropDown = function(event) {
3124 event.preventDefault();
3125 jQuery("#topmenu-bookmark-dropdown").toggleClass("open");
3126 jQuery("#top-bookmark-search-input").focus();
3127 }
3128
3129 });
3130 </script>
3131 ';
3132 }
3133 }
3134 return $html;
3135}
3136
3142function top_menu_search()
3143{
3144 global $langs, $conf, $db, $user, $hookmanager; // used by htdocs/core/ajax/selectsearchbox.php
3145
3146 $html = '';
3147
3148 $usedbyinclude = 1;
3149 $arrayresult = array();
3150 include DOL_DOCUMENT_ROOT.'/core/ajax/selectsearchbox.php'; // This sets $arrayresult
3151
3152 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
3153 // accesskey is for Mac: CTRL + key for all browsers
3154 $stringforfirstkey = $langs->trans("KeyboardShortcut");
3155 if ($conf->browser->name == 'chrome') {
3156 $stringforfirstkey .= ' ALT +';
3157 } elseif ($conf->browser->name == 'firefox') {
3158 $stringforfirstkey .= ' ALT + SHIFT +';
3159 } else {
3160 $stringforfirstkey .= ' CTL +';
3161 }
3162
3163 $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">';
3164
3165 $defaultAction = '';
3166 $buttonList = '<div class="dropdown-global-search-button-list" >';
3167 // Menu with all searchable items
3168 // @phan-suppress-next-line PhanEmptyForeach // array is really empty
3169 foreach ($arrayresult as $keyItem => $item) {
3170 if (empty($defaultAction)) {
3171 $defaultAction = $item['url'];
3172 }
3173 $buttonList .= '<button class="dropdown-item global-search-item tdoverflowmax300" data-target="'.dol_escape_htmltag($item['url']).'" >';
3174 $buttonList .= $item['text'];
3175 $buttonList .= '</button>';
3176 }
3177 $buttonList .= '</div>';
3178
3179 $dropDownHtml = '<form role="search" id="top-menu-action-search" name="actionsearch" method="GET" action="'.$defaultAction.'">';
3180
3181 $dropDownHtml .= '
3182 <!-- search input -->
3183 <div class="dropdown-header search-dropdown-header">
3184 ' . $searchInput.'
3185 </div>
3186 ';
3187
3188 $dropDownHtml .= '
3189 <!-- Menu Body search -->
3190 <div class="dropdown-body search-dropdown-body">
3191 '.$buttonList.'
3192 </div>
3193 ';
3194
3195 $dropDownHtml .= '</form>';
3196
3197 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
3198 // accesskey is for Mac: CTRL + key for all browsers
3199 $stringforfirstkey = $langs->trans("KeyboardShortcut");
3200 if ($conf->browser->name == 'chrome') {
3201 $stringforfirstkey .= ' ALT +';
3202 } elseif ($conf->browser->name == 'firefox') {
3203 $stringforfirstkey .= ' ALT + SHIFT +';
3204 } else {
3205 $stringforfirstkey .= ' CTL +';
3206 }
3207
3208 $html .= '<!-- div for Global Search -->
3209 <div id="topmenu-global-search-dropdown" class="atoplogin dropdown inline-block">
3210 <a accesskey="s" class="dropdown-toggle login-dropdown-a nofocusvisible" data-toggle="dropdown" href="#" title="'.$langs->trans('Search').' ('.$stringforfirstkey.' s)">
3211 <i class="fa fa-search" aria-hidden="true" ></i>
3212 </a>
3213 <div class="dropdown-menu dropdown-search">
3214 '.$dropDownHtml.'
3215 </div>
3216 </div>';
3217
3218 $html .= '
3219 <!-- Code to show/hide the user drop-down -->
3220 <script>
3221 jQuery(document).ready(function() {
3222
3223 // prevent submitting form on press ENTER
3224 jQuery("#top-global-search-input").keydown(function (e) {
3225 if (e.keyCode == 13 || e.keyCode == 40) {
3226 var inputs = $(this).parents("form").eq(0).find(":button");
3227 if (inputs[inputs.index(this) + 1] != null) {
3228 inputs[inputs.index(this) + 1].focus();
3229 if (e.keyCode == 13){
3230 inputs[inputs.index(this) + 1].trigger("click");
3231 }
3232
3233 }
3234 e.preventDefault();
3235 return false;
3236 }
3237 });
3238
3239 // arrow key nav
3240 jQuery(document).keydown(function(e) {
3241 // Get the focused element:
3242 var $focused = $(":focus");
3243 if($focused.length && $focused.hasClass("global-search-item")){
3244
3245 // UP - move to the previous line
3246 if (e.keyCode == 38) {
3247 e.preventDefault();
3248 $focused.prev().focus();
3249 }
3250
3251 // DOWN - move to the next line
3252 if (e.keyCode == 40) {
3253 e.preventDefault();
3254 $focused.next().focus();
3255 }
3256 }
3257 });
3258
3259
3260 // submit form action
3261 jQuery(".dropdown-global-search-button-list .global-search-item").on("click", function(event) {
3262 jQuery("#top-menu-action-search").attr("action", $(this).data("target"));
3263 jQuery("#top-menu-action-search").submit();
3264 });
3265
3266 // close drop down
3267 jQuery(document).on("click", function(event) {
3268 if (!$(event.target).closest("#topmenu-global-search-dropdown").length) {
3269 console.log("click close search - we click outside");
3270 // Hide the menus.
3271 jQuery("#topmenu-global-search-dropdown").removeClass("open");
3272 }
3273 });
3274
3275 // Open drop down
3276 jQuery("#topmenu-global-search-dropdown .dropdown-toggle").on("click", function(event) {
3277 console.log("click on toggle #topmenu-global-search-dropdown .dropdown-toggle");
3278 openGlobalSearchDropDown();
3279 });
3280
3281 // Key map shortcut
3282 jQuery(document).keydown(function(e){
3283 if ( e.which === 70 && e.ctrlKey && e.shiftKey ) {
3284 console.log(\'control + shift + f : trigger open global-search dropdown\');
3285 openGlobalSearchDropDown();
3286 }
3287 if ( e.which === 70 && e.alKey ) {
3288 console.log(\'alt + f : trigger open global-search dropdown\');
3289 openGlobalSearchDropDown();
3290 }
3291 });
3292
3293 var openGlobalSearchDropDown = function() {
3294 jQuery("#topmenu-global-search-dropdown").toggleClass("open");
3295 jQuery("#top-global-search-input").focus();
3296 }
3297
3298 });
3299 </script>
3300 ';
3301
3302 return $html;
3303}
3304
3319function left_menu($menu_array_before, $helppagename = '', $notused = '', $menu_array_after = array(), $leftmenuwithoutmainarea = 0, $title = '', $acceptdelayedhtml = 0)
3320{
3321 global $user, $conf, $langs, $db, $form;
3322 global $hookmanager, $menumanager;
3323
3324 $searchform = '';
3325
3326 if (!empty($menu_array_before)) {
3327 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);
3328 }
3329
3330 if (empty($conf->dol_hide_leftmenu) && (!defined('NOREQUIREMENU') || !constant('NOREQUIREMENU'))) {
3331 // Instantiate hooks for external modules
3332 $hookmanager->initHooks(array('leftblock'));
3333
3334 print "\n".'<!-- Begin side-nav id-left -->'."\n".'<div class="side-nav"><div id="id-left">'."\n";
3335 print "\n";
3336
3337 if (!is_object($form)) {
3338 $form = new Form($db);
3339 }
3340 $selected = -1;
3341 if (!getDolGlobalString('MAIN_USE_TOP_MENU_SEARCH_DROPDOWN')) {
3342 // Select with select2 is awful on smartphone. TODO Is this still true with select2 v4 ?
3343 if ($conf->browser->layout == 'phone') {
3344 $conf->global->MAIN_USE_OLD_SEARCH_FORM = 1;
3345 }
3346
3347 $usedbyinclude = 1;
3348 $arrayresult = array();
3349 include DOL_DOCUMENT_ROOT.'/core/ajax/selectsearchbox.php'; // This make initHooks('searchform') then set $arrayresult
3350
3351 if ($conf->use_javascript_ajax && !getDolGlobalString('MAIN_USE_OLD_SEARCH_FORM')) {
3352 // accesskey is for Windows or Linux: ALT + key for chrome, ALT + SHIFT + KEY for firefox
3353 // accesskey is for Mac: CTRL + key for all browsers
3354 $stringforfirstkey = $langs->trans("KeyboardShortcut");
3355 if ($conf->browser->name == 'chrome') {
3356 $stringforfirstkey .= ' ALT +';
3357 } elseif ($conf->browser->name == 'firefox') {
3358 $stringforfirstkey .= ' ALT + SHIFT +';
3359 } else {
3360 $stringforfirstkey .= ' CTL +';
3361 }
3362
3363 //$textsearch = $langs->trans("Search");
3364 $textsearch = '<span class="fa fa-search paddingright pictofixedwidth"></span>'.$langs->trans("Search");
3365 $searchform .= $form->selectArrayFilter('searchselectcombo', $arrayresult, $selected, 'accesskey="s"', 1, 0, (!getDolGlobalString('MAIN_SEARCHBOX_CONTENT_LOADED_BEFORE_KEY') ? 1 : 0), 'vmenusearchselectcombo', 1, $textsearch, 1, $stringforfirstkey.' s');
3366 } else {
3367 if (is_array($arrayresult)) {
3368 // @phan-suppress-next-line PhanEmptyForeach // array is really empty in else case.
3369 foreach ($arrayresult as $key => $val) {
3370 $searchform .= printSearchForm($val['url'], $val['url'], $val['label'], 'maxwidth125', 'search_all', (empty($val['shortcut']) ? '' : $val['shortcut']), 'searchleft'.$key, $val['img']);
3371 }
3372 }
3373 }
3374
3375 // Execute hook printSearchForm
3376 $parameters = array('searchform' => $searchform);
3377 $reshook = $hookmanager->executeHooks('printSearchForm', $parameters); // Note that $action and $object may have been modified by some hooks
3378 if (empty($reshook)) {
3379 $searchform .= $hookmanager->resPrint;
3380 } else {
3381 $searchform = $hookmanager->resPrint;
3382 }
3383
3384 // Force special value for $searchform for text browsers or very old search form
3385 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') || empty($conf->use_javascript_ajax)) {
3386 $urltosearch = DOL_URL_ROOT.'/core/search_page.php?showtitlebefore=1';
3387 $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>';
3388 } elseif ($conf->use_javascript_ajax && getDolGlobalString('MAIN_USE_OLD_SEARCH_FORM')) {
3389 $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>';
3390 $searchform .= '<script>
3391 jQuery(document).ready(function () {
3392 jQuery("#divsearchforms1").click(function(){
3393 jQuery("#divsearchforms2").toggle();
3394 });
3395 });
3396 </script>' . "\n";
3397 $searchform .= '</div>';
3398 }
3399
3400 // Key map shortcut
3401 $searchform .= '<script>
3402 jQuery(document).keydown(function(e){
3403 if( e.which === 70 && e.ctrlKey && e.shiftKey ){
3404 console.log(\'control + shift + f : trigger open global-search dropdown\');
3405 openGlobalSearchDropDown();
3406 }
3407 if( (e.which === 83 || e.which === 115) && e.altKey ){
3408 console.log(\'alt + s : trigger open global-search dropdown\');
3409 openGlobalSearchDropDown();
3410 }
3411 });
3412
3413 var openGlobalSearchDropDown = function() {
3414 jQuery("#searchselectcombo").select2(\'open\');
3415 }
3416 </script>';
3417 }
3418
3419 // Left column
3420 print '<!-- Begin left menu -->'."\n";
3421
3422 print '<div class="vmenu"'.(getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') ? ' alt="Left menu"' : '').'>'."\n\n";
3423
3424 // Show left menu with other forms
3425 // @phan-suppress-next-line PhanRedefinedClassReference
3426 $menumanager->menu_array = $menu_array_before;
3427 // @phan-suppress-next-line PhanRedefinedClassReference
3428 $menumanager->menu_array_after = $menu_array_after;
3429 if (getDolGlobalInt('MAIN_MENU_LEFT_DROPDOWN')) {
3430 // @phan-suppress-next-line PhanRedefinedClassReference
3431 $menumanager->showmenu('leftdropdown', array('searchform' => $searchform)); // output menu_array and menu found in database
3432 } else {
3433 // @phan-suppress-next-line PhanRedefinedClassReference
3434 $menumanager->showmenu('left', array('searchform' => $searchform)); // output menu_array and menu found in database
3435 }
3436
3437 // Dolibarr version + help + bug report link
3438 print "\n";
3439 print "<!-- Begin Help Block-->\n";
3440 print '<div id="blockvmenuhelp" class="blockvmenuhelp">'."\n";
3441
3442 // Version
3443 if (getDolGlobalString('MAIN_SHOW_VERSION')) { // Version is already on help picto and on login page.
3444 $doliurl = 'https://www.dolibarr.org';
3445 //local communities
3446 if (preg_match('/fr/i', $langs->defaultlang)) {
3447 $doliurl = 'https://www.dolibarr.fr';
3448 }
3449 if (preg_match('/es/i', $langs->defaultlang)) {
3450 $doliurl = 'https://www.dolibarr.es';
3451 }
3452 if (preg_match('/de/i', $langs->defaultlang)) {
3453 $doliurl = 'https://www.dolibarr.de';
3454 }
3455 if (preg_match('/it/i', $langs->defaultlang)) {
3456 $doliurl = 'https://www.dolibarr.it';
3457 }
3458 if (preg_match('/gr/i', $langs->defaultlang)) {
3459 $doliurl = 'https://www.dolibarr.gr';
3460 }
3461
3462 $appli = constant('DOL_APPLICATION_TITLE');
3463 if (getDolGlobalString('MAIN_APPLICATION_TITLE')) {
3464 $appli = getDolGlobalString('MAIN_APPLICATION_TITLE');
3465 $doliurl = '';
3466 if (preg_match('/\d\.\d/', $appli)) {
3467 if (!preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) {
3468 $appli .= " (".DOL_VERSION.")"; // If new title contains a version that is different than core
3469 }
3470 } else {
3471 $appli .= " ".DOL_VERSION;
3472 }
3473 } else {
3474 $appli .= " ".DOL_VERSION;
3475 }
3476 print '<div id="blockvmenuhelpapp" class="blockvmenuhelp">';
3477 if ($doliurl) {
3478 print '<a class="help" target="_blank" rel="noopener noreferrer" href="'.$doliurl.'">';
3479 } else {
3480 print '<span class="help">';
3481 }
3482 print $appli;
3483 if ($doliurl) {
3484 print '</a>';
3485 } else {
3486 print '</span>';
3487 }
3488 print '</div>'."\n";
3489 }
3490
3491 // Link to bugtrack
3492 if (getDolGlobalString('MAIN_BUGTRACK_ENABLELINK')) {
3493 require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
3494
3495 if (getDolGlobalString('MAIN_BUGTRACK_ENABLELINK') == 'github') {
3496 $bugbaseurl = 'https://github.com/Dolibarr/dolibarr/issues/new?labels=Bug';
3497 $bugbaseurl .= '&title=';
3498 $bugbaseurl .= urlencode("Bug: ");
3499 $bugbaseurl .= '&body=';
3500 $bugbaseurl .= urlencode("# Instructions\n");
3501 $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");
3502 $bugbaseurl .= urlencode("*Please:*\n");
3503 $bugbaseurl .= urlencode("- *replace the bracket enclosed texts with meaningful information*\n");
3504 $bugbaseurl .= urlencode("- *remove any unused sub-section*\n");
3505 $bugbaseurl .= urlencode("\n");
3506 $bugbaseurl .= urlencode("\n");
3507 $bugbaseurl .= urlencode("# Bug\n");
3508 $bugbaseurl .= urlencode("[*Short description*]\n");
3509 $bugbaseurl .= urlencode("\n");
3510 $bugbaseurl .= urlencode("## Environment\n");
3511 $bugbaseurl .= urlencode("- **Version**: ".DOL_VERSION."\n");
3512 $bugbaseurl .= urlencode("- **OS**: ".php_uname('s')."\n");
3513 $bugbaseurl .= urlencode("- **Web server**: ".$_SERVER["SERVER_SOFTWARE"]."\n");
3514 $bugbaseurl .= urlencode("- **PHP**: ".php_sapi_name().' '.phpversion()."\n");
3515 $bugbaseurl .= urlencode("- **Database**: ".$db::LABEL.' '.$db->getVersion()."\n");
3516 $bugbaseurl .= urlencode("- **URL(s)**: ".$_SERVER["REQUEST_URI"]."\n");
3517 $bugbaseurl .= urlencode("\n");
3518 $bugbaseurl .= urlencode("## Expected and actual behavior\n");
3519 $bugbaseurl .= urlencode("[*Verbose description*]\n");
3520 $bugbaseurl .= urlencode("\n");
3521 $bugbaseurl .= urlencode("## Steps to reproduce the behavior\n");
3522 $bugbaseurl .= urlencode("[*Verbose description*]\n");
3523 $bugbaseurl .= urlencode("\n");
3524 $bugbaseurl .= urlencode("## [Attached files](https://help.github.com/articles/issue-attachments) (Screenshots, screencasts, dolibarr.log, debugging information…)\n");
3525 $bugbaseurl .= urlencode("[*Files*]\n");
3526 $bugbaseurl .= urlencode("\n");
3527
3528 $bugbaseurl .= urlencode("\n");
3529 $bugbaseurl .= urlencode("## Report\n");
3530 } elseif (getDolGlobalString('MAIN_BUGTRACK_ENABLELINK')) {
3531 $bugbaseurl = getDolGlobalString('MAIN_BUGTRACK_ENABLELINK');
3532 } else {
3533 $bugbaseurl = "";
3534 }
3535
3536 // Execute hook printBugtrackInfo
3537 $parameters = array('bugbaseurl' => $bugbaseurl);
3538 $reshook = $hookmanager->executeHooks('printBugtrackInfo', $parameters); // Note that $action and $object may have been modified by some hooks
3539 if (empty($reshook)) {
3540 $bugbaseurl .= $hookmanager->resPrint;
3541 } else {
3542 $bugbaseurl = $hookmanager->resPrint;
3543 }
3544
3545 print '<div id="blockvmenuhelpbugreport" class="blockvmenuhelp">';
3546 print '<a class="help" target="_blank" rel="noopener noreferrer" href="'.$bugbaseurl.'"><i class="fas fa-bug"></i> '.$langs->trans("FindBug").'</a>';
3547 print '</div>';
3548 }
3549
3550 print "</div>\n";
3551 print "<!-- End Help Block-->\n";
3552 print "\n";
3553
3554 print "</div>\n";
3555 print "<!-- End left menu -->\n";
3556 print "\n";
3557
3558 // Execute hook printLeftBlock
3559 $parameters = array();
3560 $reshook = $hookmanager->executeHooks('printLeftBlock', $parameters); // Note that $action and $object may have been modified by some hooks
3561 print $hookmanager->resPrint;
3562
3563 print '</div></div> <!-- End side-nav id-left -->'; // End div id="side-nav" div id="id-left"
3564 }
3565
3566 print "\n";
3567 print '<!-- Begin right area -->'."\n";
3568
3569 if (empty($leftmenuwithoutmainarea)) {
3570 main_area($title);
3571 }
3572}
3573
3574
3581function main_area($title = '')
3582{
3583 global $conf, $langs, $hookmanager;
3584
3585 if (empty($conf->dol_hide_leftmenu) && !GETPOST('dol_openinpopup')) {
3586 print '<div id="id-right">';
3587 }
3588
3589 print "\n";
3590
3591 print '<!-- Begin div class="fiche" -->'."\n".'<div class="fiche">'."\n";
3592
3593 $hookmanager->initHooks(array('main'));
3594 $parameters = array();
3595 $reshook = $hookmanager->executeHooks('printMainArea', $parameters); // Note that $action and $object may have been modified by some hooks
3596 print $hookmanager->resPrint;
3597
3598 if (getDolGlobalString('MAIN_ONLY_LOGIN_ALLOWED')) {
3599 print info_admin($langs->trans("WarningYouAreInMaintenanceMode", getDolGlobalString('MAIN_ONLY_LOGIN_ALLOWED')), 0, 0, '1', 'warning maintenancemode');
3600 }
3601
3602 // Permit to add user company information on each printed document by setting SHOW_SOCINFO_ON_PRINT
3603 if (getDolGlobalString('SHOW_SOCINFO_ON_PRINT') && GETPOST('optioncss', 'aZ09') == 'print' && empty(GETPOST('disable_show_socinfo_on_print', 'aZ09'))) {
3604 $parameters = array();
3605 $reshook = $hookmanager->executeHooks('showSocinfoOnPrint', $parameters);
3606 if (empty($reshook)) {
3607 print '<!-- Begin show mysoc info header -->'."\n";
3608 print '<div id="mysoc-info-header">'."\n";
3609 print '<table class="centpercent div-table-responsive">'."\n";
3610 print '<tbody>';
3611 print '<tr><td rowspan="0" class="width20p">';
3612 if (getDolGlobalString('MAIN_SHOW_LOGO') && !getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && getDolGlobalString('MAIN_INFO_SOCIETE_LOGO')) {
3613 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'))).'">';
3614 }
3615 print '</td><td rowspan="0" class="width50p"></td></tr>'."\n";
3616 print '<tr><td class="titre bold">'.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_NOM')).'</td></tr>'."\n";
3617 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";
3618 if (getDolGlobalString('MAIN_INFO_SOCIETE_TEL')) {
3619 print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Phone").' : '.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_TEL')).'</td></tr>';
3620 }
3621 if (getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')) {
3622 print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Email").' : '.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_MAIL')).'</td></tr>';
3623 }
3624 if (getDolGlobalString('MAIN_INFO_SOCIETE_WEB')) {
3625 print '<tr><td style="padding-left: 1em" class="small">'.$langs->trans("Web").' : '.dol_escape_htmltag(getDolGlobalString('MAIN_INFO_SOCIETE_WEB')).'</td></tr>';
3626 }
3627 print '</tbody>';
3628 print '</table>'."\n";
3629 print '</div>'."\n";
3630 print '<!-- End show mysoc info header -->'."\n";
3631 }
3632 }
3633}
3634
3635
3643function getHelpParamFor($helppagename, $langs)
3644{
3645 $helpbaseurl = '';
3646 $helppage = '';
3647 $mode = '';
3648
3649 if (preg_match('/^http/i', $helppagename)) {
3650 // If complete URL
3651 $helpbaseurl = '%s';
3652 $helppage = $helppagename;
3653 $mode = 'local';
3654 } else {
3655 // If WIKI URL
3656 $reg = array();
3657 if (preg_match('/^es/i', $langs->defaultlang)) {
3658 $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3659 if (preg_match('/ES:([^|]+)/i', $helppagename, $reg)) {
3660 $helppage = $reg[1];
3661 }
3662 }
3663 if (preg_match('/^fr/i', $langs->defaultlang)) {
3664 $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3665 if (preg_match('/FR:([^|]+)/i', $helppagename, $reg)) {
3666 $helppage = $reg[1];
3667 }
3668 }
3669 if (preg_match('/^de/i', $langs->defaultlang)) {
3670 $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3671 if (preg_match('/DE:([^|]+)/i', $helppagename, $reg)) {
3672 $helppage = $reg[1];
3673 }
3674 }
3675 if (empty($helppage)) { // If help page not already found
3676 $helpbaseurl = 'http://wiki.dolibarr.org/index.php/%s';
3677 if (preg_match('/EN:([^|]+)/i', $helppagename, $reg)) {
3678 $helppage = $reg[1];
3679 }
3680 }
3681 $mode = 'wiki';
3682 }
3683 return array('helpbaseurl' => $helpbaseurl, 'helppage' => $helppage, 'mode' => $mode);
3684}
3685
3686
3703function printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey = '', $prefhtmlinputname = '', $img = '', $showtitlebefore = 0, $autofocus = 0)
3704{
3705 global $langs, $user;
3706
3707 $ret = '';
3708 $ret .= '<form action="'.$urlaction.'" method="post" class="searchform nowraponall tagtr">';
3709 $ret .= '<input type="hidden" name="token" value="'.newToken().'">';
3710 $ret .= '<input type="hidden" name="savelogin" value="'.dol_escape_htmltag($user->login).'">';
3711 if ($showtitlebefore) {
3712 $ret .= '<div class="tagtd left">'.$title.'</div> ';
3713 }
3714 $ret .= '<div class="tagtd">';
3715 $ret .= img_picto('', $img, '', 0, 0, 0, '', 'paddingright width20');
3716 $ret .= '<input type="text" class="flat '.$htmlmorecss.'"';
3717 $ret .= ' style="background-repeat: no-repeat; background-position: 3px;"';
3718 $ret .= ($accesskey ? ' accesskey="'.$accesskey.'"' : '');
3719 $ret .= ' placeholder="'.strip_tags($title).'"';
3720 $ret .= ($autofocus ? ' autofocus' : '');
3721 $ret .= ' name="'.$htmlinputname.'" id="'.$prefhtmlinputname.$htmlinputname.'" />';
3722 $ret .= '<button type="submit" class="button bordertransp" style="padding-top: 4px; padding-bottom: 4px; padding-left: 6px; padding-right: 6px">';
3723 $ret .= '<span class="fa fa-search"></span>';
3724 $ret .= '</button>';
3725 $ret .= '</div>';
3726 $ret .= "</form>\n";
3727 return $ret;
3728}
3729
3730
3731if (!function_exists("llxFooter")) {
3743 function llxFooter($comment = '', $zone = 'private', $disabledoutputofmessages = 0)
3744 {
3745 global $conf, $db, $langs, $user, $mysoc, $object, $hookmanager, $action;
3746 global $delayedhtmlcontent;
3747 global $contextpage, $page, $limit, $mode;
3748 global $dolibarr_distrib;
3749
3750 $ext = 'layout='.urlencode($conf->browser->layout).'&version='.urlencode(DOL_VERSION);
3751
3752 // Hook to add more things on all pages within fiche DIV
3753 $llxfooter = '';
3754 $parameters = array();
3755 $reshook = $hookmanager->executeHooks('llxFooter', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3756 if (empty($reshook)) {
3757 $llxfooter .= $hookmanager->resPrint;
3758 } elseif ($reshook > 0) {
3759 $llxfooter = $hookmanager->resPrint;
3760 }
3761 if ($llxfooter) {
3762 print $llxfooter;
3763 }
3764
3765 // Global html output events ($mesgs, $errors, $warnings)
3766 dol_htmloutput_events($disabledoutputofmessages);
3767
3768 // Code for search criteria persistence.
3769 // $user->lastsearch_values was set by the GETPOST when form field search_xxx exists
3770 if (is_object($user) && !empty($user->lastsearch_values_tmp) && is_array($user->lastsearch_values_tmp)) {
3771 // Clean and save data
3772 foreach ($user->lastsearch_values_tmp as $key => $val) {
3773 unset($_SESSION['lastsearch_values_tmp_'.$key]); // Clean array to rebuild it just after
3774 if (count($val) && empty($_POST['button_removefilter']) && empty($_POST['button_removefilter_x'])) {
3775 if (empty($val['sortfield'])) {
3776 unset($val['sortfield']);
3777 }
3778 if (empty($val['sortorder'])) {
3779 unset($val['sortorder']);
3780 }
3781 dol_syslog('Save lastsearch_values_tmp_'.$key.'='.json_encode($val, 0)." (systematic recording of last search criteria)");
3782 $_SESSION['lastsearch_values_tmp_'.$key] = json_encode($val);
3783 unset($_SESSION['lastsearch_values_'.$key]);
3784 }
3785 }
3786 }
3787
3788
3789 $relativepathstring = $_SERVER["PHP_SELF"];
3790 // Clean $relativepathstring
3791 if (constant('DOL_URL_ROOT')) {
3792 $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'), '/').'/', '', $relativepathstring);
3793 }
3794 $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
3795 $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
3796 if (preg_match('/list\.php$/', $relativepathstring)) {
3797 unset($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]);
3798 unset($_SESSION['lastsearch_page_tmp_'.$relativepathstring]);
3799 unset($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]);
3800 unset($_SESSION['lastsearch_mode_tmp_'.$relativepathstring]);
3801
3802 if (!empty($contextpage)) {
3803 $_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring] = $contextpage;
3804 }
3805 if (!empty($page) && $page > 0) {
3806 $_SESSION['lastsearch_page_tmp_'.$relativepathstring] = $page;
3807 }
3808 if (!empty($limit) && $limit != $conf->liste_limit) {
3809 $_SESSION['lastsearch_limit_tmp_'.$relativepathstring] = $limit;
3810 }
3811 if (!empty($mode)) {
3812 $_SESSION['lastsearch_mode_tmp_'.$relativepathstring] = $mode;
3813 }
3814
3815 unset($_SESSION['lastsearch_contextpage_'.$relativepathstring]);
3816 unset($_SESSION['lastsearch_page_'.$relativepathstring]);
3817 unset($_SESSION['lastsearch_limit_'.$relativepathstring]);
3818 unset($_SESSION['lastsearch_mode_'.$relativepathstring]);
3819 }
3820
3821 // Core error message
3822 if (getDolGlobalString('MAIN_CORE_ERROR')) {
3823 // Ajax version
3824 if ($conf->use_javascript_ajax) {
3825 $title = img_warning().' '.$langs->trans('CoreErrorTitle');
3826 print ajax_dialog($title, $langs->trans('CoreErrorMessage'));
3827 } else {
3828 // html version
3829 $msg = img_warning().' '.$langs->trans('CoreErrorMessage');
3830 print '<div class="error">'.$msg.'</div>';
3831 }
3832
3833 //define("MAIN_CORE_ERROR",0); // Constant was defined and we can't change value of a constant
3834 }
3835
3836 print "\n\n";
3837
3838 print '</div> <!-- End div class="fiche" -->'."\n"; // End div fiche
3839
3840 if (empty($conf->dol_hide_leftmenu) && !GETPOST('dol_openinpopup')) {
3841 print '</div> <!-- End div id-right -->'."\n"; // End div id-right
3842 }
3843
3844 if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) {
3845 print '</div> <!-- End div id-container -->'."\n"; // End div container
3846 }
3847
3848 print "\n";
3849 if ($comment) {
3850 print '<!-- '.$comment.' -->'."\n";
3851 }
3852
3853 printCommonFooter($zone);
3854
3855 if (!empty($delayedhtmlcontent)) {
3856 print $delayedhtmlcontent;
3857 }
3858
3859 if (!empty($conf->use_javascript_ajax)) {
3860 print "\n".'<!-- Includes JS Footer of Dolibarr -->'."\n";
3861 print '<script src="'.DOL_URL_ROOT.'/core/js/lib_foot.js.php?lang='.$langs->defaultlang.($ext ? '&'.$ext : '').'"></script>'."\n";
3862 }
3863
3864 // Wrapper to add log when clicking on download or preview
3865 if (isModEnabled('blockedlog') && is_object($object) && !empty($object->id) && $object->id > 0) {
3866 if (in_array($object->element, array('facture')) && $object->statut > 0) { // Restrict for the moment to element 'facture'
3867 print "\n<!-- JS CODE TO ENABLE log when making a download or a preview of a document -->\n";
3868 ?>
3869 <script>
3870 jQuery(document).ready(function () {
3871 $('a.documentpreview').click(function() {
3872 console.log("Call /blockedlog/ajax/block-add on a.documentpreview");
3873 $.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
3874 , {
3875 id:<?php echo $object->id; ?>
3876 , element:'<?php echo dol_escape_js($object->element) ?>'
3877 , action:'DOC_PREVIEW'
3878 , token: '<?php echo currentToken(); ?>'
3879 }
3880 );
3881 });
3882 $('a.documentdownload').click(function() {
3883 console.log("Call /blockedlog/ajax/block-add a.documentdownload");
3884 $.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
3885 , {
3886 id:<?php echo $object->id; ?>
3887 , element:'<?php echo dol_escape_js($object->element) ?>'
3888 , action:'DOC_DOWNLOAD'
3889 , token: '<?php echo currentToken(); ?>'
3890 }
3891 );
3892 });
3893 });
3894 </script>
3895 <?php
3896 }
3897 }
3898
3899 // A div for the address popup
3900 print "\n<!-- A div to allow dialog popup by jQuery('#dialogforpopup').dialog() -->\n";
3901 print '<div id="dialogforpopup" style="display: none;"></div>'."\n";
3902
3903 // Add code for the asynchronous anonymous first ping (for telemetry)
3904 // You can use &forceping=1 in parameters to force the ping if the ping was already sent.
3905 $forceping = GETPOST('forceping', 'alpha');
3906 if (($_SERVER["PHP_SELF"] == DOL_URL_ROOT.'/index.php') || $forceping) {
3907 //print '<!-- instance_unique_id='.$conf->file->instance_unique_id.' MAIN_FIRST_PING_OK_ID='.$conf->global->MAIN_FIRST_PING_OK_ID.' -->';
3908 $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.
3909
3910 if (!getDolGlobalString('MAIN_FIRST_PING_OK_DATE')
3911 || (!empty($conf->file->instance_unique_id) && ($hash_unique_id != $conf->global->MAIN_FIRST_PING_OK_ID) && (getDolGlobalString('MAIN_FIRST_PING_OK_ID') != 'disabled'))
3912 || $forceping) {
3913 // No ping done if we are into an alpha version
3914 if (strpos('alpha', DOL_VERSION) > 0 && !$forceping) {
3915 print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. It is an alpha version -->\n";
3916 } elseif (empty($_COOKIE['DOLINSTALLNOPING_'.$hash_unique_id]) || $forceping) { // Cookie is set when we uncheck the checkbox in the installation wizard.
3917 // MAIN_LAST_PING_KO_DATE
3918 // Disable ping if MAIN_LAST_PING_KO_DATE is set and is recent (this month)
3919 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) {
3920 print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. An error already occurred this month, we will try later. -->\n";
3921 } else {
3922 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
3923
3924 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";
3925 print "\n<!-- JS CODE TO ENABLE the anonymous Ping -->\n";
3926 $url_for_ping = getDolGlobalString('MAIN_URL_FOR_PING', "https://ping.dolibarr.org/");
3927 // Try to guess the distrib used
3928 $distrib = 'standard';
3929 if ($_SERVER["SERVER_ADMIN"] == 'doliwamp@localhost') {
3930 $distrib = 'doliwamp';
3931 }
3932 if (!empty($dolibarr_distrib)) {
3933 $distrib = $dolibarr_distrib;
3934 }
3935 ?>
3936 <script>
3937 jQuery(document).ready(function (tmp) {
3938 console.log("Try Ping with hash_unique_id is dol_hash('dolibarr'+instance_unique_id, 'sha256')");
3939 $.ajax({
3940 method: "POST",
3941 url: "<?php echo $url_for_ping ?>",
3942 timeout: 500, // timeout milliseconds
3943 cache: false,
3944 data: {
3945 hash_algo: 'dol_hash-sha256',
3946 hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>',
3947 action: 'dolibarrping',
3948 version: '<?php echo (float) DOL_VERSION; ?>',
3949 entity: '<?php echo (int) $conf->entity; ?>',
3950 dbtype: '<?php echo dol_escape_js($db->type); ?>',
3951 country_code: '<?php echo $mysoc->country_code ? dol_escape_js($mysoc->country_code) : 'unknown'; ?>',
3952 php_version: '<?php echo dol_escape_js(phpversion()); ?>',
3953 os_version: '<?php echo dol_escape_js(version_os('smr')); ?>',
3954 db_version: '<?php echo dol_escape_js(version_db()); ?>',
3955 distrib: '<?php echo $distrib ? dol_escape_js($distrib) : 'unknown'; ?>',
3956 token: 'notrequired'
3957 },
3958 success: function (data, status, xhr) { // success callback function (data contains body of response)
3959 console.log("Ping ok");
3960 $.ajax({
3961 method: 'GET',
3962 url: '<?php echo DOL_URL_ROOT.'/core/ajax/pingresult.php'; ?>',
3963 timeout: 500, // timeout milliseconds
3964 cache: false,
3965 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
3966 });
3967 },
3968 error: function (data,status,xhr) { // error callback function
3969 console.log("Ping ko: " + data);
3970 $.ajax({
3971 method: 'GET',
3972 url: '<?php echo DOL_URL_ROOT.'/core/ajax/pingresult.php'; ?>',
3973 timeout: 500, // timeout milliseconds
3974 cache: false,
3975 data: { hash_algo: 'dol_hash-sha256', hash_unique_id: '<?php echo dol_escape_js($hash_unique_id); ?>', action: 'firstpingko', token: '<?php echo currentToken(); ?>' },
3976 });
3977 }
3978 });
3979 });
3980 </script>
3981 <?php
3982 }
3983 } else {
3984 $now = dol_now();
3985 print "\n<!-- NO JS CODE TO ENABLE the anonymous Ping. It was disabled -->\n";
3986 include_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
3987 dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_DATE', dol_print_date($now, 'dayhourlog', 'gmt'), 'chaine', 0, '', $conf->entity);
3988 dolibarr_set_const($db, 'MAIN_FIRST_PING_OK_ID', 'disabled', 'chaine', 0, '', $conf->entity);
3989 }
3990 }
3991 }
3992
3993 $parameters = array();
3994 $reshook = $hookmanager->executeHooks('beforeBodyClose', $parameters); // Note that $action and $object may have been modified by some hooks
3995 if ($reshook > 0) {
3996 print $hookmanager->resPrint;
3997 }
3998
3999 print "</body>\n";
4000 print "</html>\n";
4001 }
4002}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
print $langs trans("AuditedSecurityEvents").'</strong >< span class="opacitymedium"></span >< br > status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition security.php:640
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.
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:426
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.
yn($yesno, $case=1, $color=0)
Return yes or no in current language.
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.
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_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.