dolibarr  9.0.0
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-2015 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-2015 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  *
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  * GNU General Public License for more details.
24  *
25  * You should have received a copy of the GNU General Public License
26  * along with this program. If not, see <http://www.gnu.org/licenses/>.
27  */
28 
35 //@ini_set('memory_limit', '128M'); // This may be useless if memory is hard limited by your PHP
36 
37 // For optional tuning. Enabled if environment variable MAIN_SHOW_TUNING_INFO is defined.
38 $micro_start_time=0;
39 if (! empty($_SERVER['MAIN_SHOW_TUNING_INFO']))
40 {
41  list($usec, $sec) = explode(" ", microtime());
42  $micro_start_time=((float) $usec + (float) $sec);
43  // Add Xdebug code coverage
44  //define('XDEBUGCOVERAGE',1);
45  if (defined('XDEBUGCOVERAGE')) {
46  xdebug_start_code_coverage();
47  }
48 }
49 
50 // Removed magic_quotes
51 if (function_exists('get_magic_quotes_gpc')) // magic_quotes_* deprecated in PHP 5.0 and removed in PHP 5.5
52 {
53  if (get_magic_quotes_gpc())
54  {
55  // Forcing parameter setting magic_quotes_gpc and cleaning parameters
56  // (Otherwise he would have for each position, condition
57  // Reading stripslashes variable according to state get_magic_quotes_gpc).
58  // Off mode recommended (just do $db->escape for insert / update).
59  function stripslashes_deep($value)
60  {
61  return (is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value));
62  }
63  $_GET = array_map('stripslashes_deep', $_GET);
64  $_POST = array_map('stripslashes_deep', $_POST);
65  $_FILES = array_map('stripslashes_deep', $_FILES);
66  //$_COOKIE = array_map('stripslashes_deep', $_COOKIE); // Useless because a cookie should never be outputed on screen nor used into sql
67  @set_magic_quotes_runtime(0);
68  }
69 }
70 
71 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
81 function test_sql_and_script_inject($val, $type)
82 {
83  // phpcs:enable
84  return testSqlAndScriptInject($val, $type);
85 }
86 
94 function testSqlAndScriptInject($val, $type)
95 {
96  $inj = 0;
97  // For SQL Injection (only GET are used to be included into bad escaped SQL requests)
98  if ($type == 1 || $type == 3)
99  {
100  $inj += preg_match('/delete\s+from/i', $val);
101  $inj += preg_match('/create\s+table/i', $val);
102  $inj += preg_match('/insert\s+into/i', $val);
103  $inj += preg_match('/select\s+from/i', $val);
104  $inj += preg_match('/into\s+(outfile|dumpfile)/i', $val);
105  $inj += preg_match('/user\s*\(/i', $val); // avoid to use function user() that return current database login
106  $inj += preg_match('/information_schema/i', $val); // avoid to use request that read information_schema database
107  }
108  if ($type == 3)
109  {
110  $inj += preg_match('/select|update|delete|replace|group\s+by|concat|count|from/i', $val);
111  }
112  if ($type != 2) // Not common key strings, so we can check them both on GET and POST
113  {
114  $inj += preg_match('/updatexml\(/i', $val);
115  $inj += preg_match('/update.+set.+=/i', $val);
116  $inj += preg_match('/union.+select/i', $val);
117  $inj += preg_match('/(\.\.%2f)+/i', $val);
118  }
119  // For XSS Injection done by adding javascript with script
120  // This is all cases a browser consider text is javascript:
121  // When it found '<script', 'javascript:', '<style', 'onload\s=' on body tag, '="&' on a tag size with old browsers
122  // All examples on page: http://ha.ckers.org/xss.html#XSScalc
123  // More on https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
124  $inj += preg_match('/<script/i', $val);
125  $inj += preg_match('/<iframe/i', $val);
126  $inj += preg_match('/<audio/i', $val);
127  $inj += preg_match('/Set\.constructor/i', $val); // ECMA script 6
128  if (! defined('NOSTYLECHECK')) $inj += preg_match('/<style/i', $val);
129  $inj += preg_match('/base[\s]+href/si', $val);
130  $inj += preg_match('/<.*onmouse/si', $val); // onmousexxx can be set on img or any html tag like <img title='...' onmouseover=alert(1)>
131  $inj += preg_match('/onerror\s*=/i', $val); // onerror can be set on img or any html tag like <img title='...' onerror = alert(1)>
132  $inj += preg_match('/onfocus\s*=/i', $val); // onfocus can be set on input text html tag like <input type='text' value='...' onfocus = alert(1)>
133  $inj += preg_match('/onload\s*=/i', $val); // onload can be set on svg tag <svg/onload=alert(1)> or other tag like body <body onload=alert(1)>
134  $inj += preg_match('/onloadstart\s*=/i', $val); // onload can be set on audio tag <audio onloadstart=alert(1)>
135  $inj += preg_match('/onclick\s*=/i', $val); // onclick can be set on img text html tag like <img onclick = alert(1)>
136  $inj += preg_match('/onscroll\s*=/i', $val); // onscroll can be on textarea
137  //$inj += preg_match('/on[A-Z][a-z]+\*=/', $val); // To lock event handlers onAbort(), ...
138  $inj += preg_match('/&#58;|&#0000058|&#x3A/i', $val); // refused string ':' encoded (no reason to have it encoded) to lock 'javascript:...'
139  //if ($type == 1)
140  //{
141  $inj += preg_match('/javascript:/i', $val);
142  $inj += preg_match('/vbscript:/i', $val);
143  //}
144  // For XSS Injection done by adding javascript closing html tags like with onmousemove, etc... (closing a src or href tag with not cleaned param)
145  if ($type == 1) $inj += preg_match('/"/i', $val); // We refused " in GET parameters value
146  if ($type == 2) $inj += preg_match('/[;"]/', $val); // PHP_SELF is a file system path. It can contains spaces.
147  return $inj;
148 }
149 
158 {
159  if (is_array($var))
160  {
161  foreach ($var as $key => $value) // Warning, $key may also be used for attacks
162  {
164  {
165  //$var[$key] = $value; // This is useless
166  }
167  else
168  {
169  print 'Access refused by SQL/Script injection protection in main.inc.php (type='.htmlentities($type).' key='.htmlentities($key).' value='.htmlentities($value).' page='.htmlentities($_SERVER["REQUEST_URI"]).')';
170  exit;
171  }
172  }
173  return true;
174  }
175  else
176  {
177  return (testSqlAndScriptInject($var, $type) <= 0);
178  }
179 }
180 
181 
182 // Check consistency of NOREQUIREXXX DEFINES
183 if ((defined('NOREQUIREDB') || defined('NOREQUIRETRAN')) && ! defined('NOREQUIREMENU'))
184 {
185  print 'If define NOREQUIREDB or NOREQUIRETRAN are set, you must also set NOREQUIREMENU or not set them';
186  exit;
187 }
188 
189 // Sanity check on URL
190 if (! empty($_SERVER["PHP_SELF"]))
191 {
192  $morevaltochecklikepost=array($_SERVER["PHP_SELF"]);
193  analyseVarsForSqlAndScriptsInjection($morevaltochecklikepost,2);
194 }
195 // Sanity check on GET parameters
196 if (! defined('NOSCANGETFORINJECTION') && ! empty($_SERVER["QUERY_STRING"]))
197 {
198  $morevaltochecklikeget=array($_SERVER["QUERY_STRING"]);
199  analyseVarsForSqlAndScriptsInjection($morevaltochecklikeget,1);
200 }
201 // Sanity check on POST
202 if (! defined('NOSCANPOSTFORINJECTION'))
203 {
205 }
206 
207 // This is to make Dolibarr working with Plesk
208 if (! empty($_SERVER['DOCUMENT_ROOT']) && substr($_SERVER['DOCUMENT_ROOT'], -6) !== 'htdocs')
209 {
210  set_include_path($_SERVER['DOCUMENT_ROOT'] . '/htdocs');
211 }
212 
213 // Include the conf.php and functions.lib.php
214 require_once 'filefunc.inc.php';
215 
216 // If there is a POST parameter to tell to save automatically some POST parameters into cookies, we do it.
217 // This is used for example by form of boxes to save personalization of some options.
218 // DOL_AUTOSET_COOKIE=cookiename:val1,val2 and cookiename_val1=aaa cookiename_val2=bbb will set cookie_name with value json_encode(array('val1'=> , ))
219 if (! empty($_POST["DOL_AUTOSET_COOKIE"]))
220 {
221  $tmpautoset=explode(':',$_POST["DOL_AUTOSET_COOKIE"],2);
222  $tmplist=explode(',',$tmpautoset[1]);
223  $cookiearrayvalue=array();
224  foreach ($tmplist as $tmpkey)
225  {
226  $postkey=$tmpautoset[0].'_'.$tmpkey;
227  //var_dump('tmpkey='.$tmpkey.' postkey='.$postkey.' value='.$_POST[$postkey]);
228  if (! empty($_POST[$postkey])) $cookiearrayvalue[$tmpkey]=$_POST[$postkey];
229  }
230  $cookiename=$tmpautoset[0];
231  $cookievalue=json_encode($cookiearrayvalue);
232  //var_dump('setcookie cookiename='.$cookiename.' cookievalue='.$cookievalue);
233  setcookie($cookiename, empty($cookievalue)?'':$cookievalue, empty($cookievalue)?0:(time()+(86400*354)), '/', null, false, true); // keep cookie 1 year and add tag httponly
234  if (empty($cookievalue)) unset($_COOKIE[$cookiename]);
235 }
236 
237 
238 // Init session. Name of session is specific to Dolibarr instance.
239 // Note: the function dol_getprefix may have been redefined to return a different key to manage another area to protect.
240 $prefix=dol_getprefix('');
241 
242 $sessionname='DOLSESSID_'.$prefix;
243 $sessiontimeout='DOLSESSTIMEOUT_'.$prefix;
244 if (! empty($_COOKIE[$sessiontimeout])) ini_set('session.gc_maxlifetime',$_COOKIE[$sessiontimeout]);
245 session_name($sessionname);
246 session_set_cookie_params(0, '/', null, false, true); // Add tag httponly on session cookie (same as setting session.cookie_httponly into php.ini). Must be called before the session_start.
247 // This create lock, released when session_write_close() or end of page.
248 // We need this lock as long as we read/write $_SESSION ['vars']. We can remove lock when finished.
249 if (! defined('NOSESSION'))
250 {
251  session_start();
252  /*if (ini_get('register_globals')) // Deprecated in 5.3 and removed in 5.4. To solve bug in using $_SESSION
253  {
254  foreach ($_SESSION as $key=>$value)
255  {
256  if (isset($GLOBALS[$key])) unset($GLOBALS[$key]);
257  }
258  }*/
259 }
260 
261 // Init the 5 global objects, this include will make the new and set properties for: $conf, $db, $langs, $user, $mysoc
262 require_once 'master.inc.php';
263 
264 // Activate end of page function
265 register_shutdown_function('dol_shutdown');
266 
267 // Detection browser
268 if (isset($_SERVER["HTTP_USER_AGENT"]))
269 {
270  $tmp=getBrowserInfo($_SERVER["HTTP_USER_AGENT"]);
271  $conf->browser->name=$tmp['browsername'];
272  $conf->browser->os=$tmp['browseros'];
273  $conf->browser->version=$tmp['browserversion'];
274  $conf->browser->layout=$tmp['layout']; // 'classic', 'phone', 'tablet'
275  //var_dump($conf->browser);
276 
277  if ($conf->browser->layout == 'phone') $conf->dol_no_mouse_hover=1;
278  if ($conf->browser->layout == 'phone') $conf->global->MAIN_TESTMENUHIDER=1;
279 }
280 
281 // Force HTTPS if required ($conf->file->main_force_https is 0/1 or https dolibarr root url)
282 // $_SERVER["HTTPS"] is 'on' when link is https, otherwise $_SERVER["HTTPS"] is empty or 'off'
283 if (! empty($conf->file->main_force_https) && (empty($_SERVER["HTTPS"]) || $_SERVER["HTTPS"] != 'on'))
284 {
285  $newurl='';
286  if (is_numeric($conf->file->main_force_https))
287  {
288  if ($conf->file->main_force_https == '1' && ! empty($_SERVER["SCRIPT_URI"])) // If SCRIPT_URI supported by server
289  {
290  if (preg_match('/^http:/i',$_SERVER["SCRIPT_URI"]) && ! preg_match('/^https:/i',$_SERVER["SCRIPT_URI"])) // If link is http
291  {
292  $newurl=preg_replace('/^http:/i','https:',$_SERVER["SCRIPT_URI"]);
293  }
294  }
295  else // Check HTTPS environment variable (Apache/mod_ssl only)
296  {
297  $newurl=preg_replace('/^http:/i','https:',DOL_MAIN_URL_ROOT).$_SERVER["REQUEST_URI"];
298  }
299  }
300  else
301  {
302  // Check HTTPS environment variable (Apache/mod_ssl only)
303  $newurl=$conf->file->main_force_https.$_SERVER["REQUEST_URI"];
304  }
305  // Start redirect
306  if ($newurl)
307  {
308  dol_syslog("main.inc: dolibarr_main_force_https is on, we make a redirect to ".$newurl);
309  header("Location: ".$newurl);
310  exit;
311  }
312  else
313  {
314  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);
315  }
316 }
317 
318 if (! defined('NOLOGIN') && ! defined('NOIPCHECK') && ! empty($dolibarr_main_restrict_ip))
319 {
320  $listofip=explode(',', $dolibarr_main_restrict_ip);
321  $found = false;
322  foreach($listofip as $ip)
323  {
324  $ip=trim($ip);
325  if ($ip == $_SERVER['REMOTE_ADDR'])
326  {
327  $found = true;
328  break;
329  }
330  }
331  if (! $found)
332  {
333  print 'Access refused by IP protection';
334  exit;
335  }
336 }
337 
338 // Loading of additional presentation includes
339 if (! defined('NOREQUIREHTML')) require_once DOL_DOCUMENT_ROOT .'/core/class/html.form.class.php'; // Need 660ko memory (800ko in 2.2)
340 if (! defined('NOREQUIREAJAX') && $conf->use_javascript_ajax) require_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; // Need 22ko memory
341 
342 // If install or upgrade process not done or not completely finished, we call the install page.
343 if (! empty($conf->global->MAIN_NOT_INSTALLED) || ! empty($conf->global->MAIN_NOT_UPGRADED))
344 {
345  dol_syslog("main.inc: A previous install or upgrade was not complete. Redirect to install page.", LOG_WARNING);
346  header("Location: ".DOL_URL_ROOT."/install/index.php");
347  exit;
348 }
349 // If an upgrade process is required, we call the install page.
350 if ((! empty($conf->global->MAIN_VERSION_LAST_UPGRADE) && ($conf->global->MAIN_VERSION_LAST_UPGRADE != DOL_VERSION))
351 || (empty($conf->global->MAIN_VERSION_LAST_UPGRADE) && ! empty($conf->global->MAIN_VERSION_LAST_INSTALL) && ($conf->global->MAIN_VERSION_LAST_INSTALL != DOL_VERSION)))
352 {
353  $versiontocompare=empty($conf->global->MAIN_VERSION_LAST_UPGRADE)?$conf->global->MAIN_VERSION_LAST_INSTALL:$conf->global->MAIN_VERSION_LAST_UPGRADE;
354  require_once DOL_DOCUMENT_ROOT .'/core/lib/admin.lib.php';
355  $dolibarrversionlastupgrade=preg_split('/[.-]/',$versiontocompare);
356  $dolibarrversionprogram=preg_split('/[.-]/',DOL_VERSION);
357  $rescomp=versioncompare($dolibarrversionprogram,$dolibarrversionlastupgrade);
358  if ($rescomp > 0) // Programs have a version higher than database. We did not add "&& $rescomp < 3" because we want upgrade process for build upgrades
359  {
360  dol_syslog("main.inc: database version ".$versiontocompare." is lower than programs version ".DOL_VERSION.". Redirect to install page.", LOG_WARNING);
361  header("Location: ".DOL_URL_ROOT."/install/index.php");
362  exit;
363  }
364 }
365 
366 // Creation of a token against CSRF vulnerabilities
367 if (! defined('NOTOKENRENEWAL'))
368 {
369  // Rolling token at each call ($_SESSION['token'] contains token of previous page)
370  if (isset($_SESSION['newtoken'])) $_SESSION['token'] = $_SESSION['newtoken'];
371 
372  // Save in $_SESSION['newtoken'] what will be next token. Into forms, we will add param token = $_SESSION['newtoken']
373  $token = dol_hash(uniqid(mt_rand(), true)); // Generates a hash of a random number
374  $_SESSION['newtoken'] = $token;
375 }
376 if ((! defined('NOCSRFCHECK') && empty($dolibarr_nocsrfcheck) && ! empty($conf->global->MAIN_SECURITY_CSRF_WITH_TOKEN))
377  || defined('CSRFCHECK_WITH_TOKEN')) // Check validity of token, only if option MAIN_SECURITY_CSRF_WITH_TOKEN enabled or if constant CSRFCHECK_WITH_TOKEN is set
378 {
379  if ($_SERVER['REQUEST_METHOD'] == 'POST' && ! GETPOST('token','alpha')) // Note, offender can still send request by GET
380  {
381  print "Access refused by CSRF protection in main.inc.php. Token not provided.\n";
382  print "If you access your server behind a proxy using url rewriting, you might check that all HTTP header is propagated (or add the line \$dolibarr_nocsrfcheck=1 into your conf.php file).\n";
383  die;
384  }
385  if ($_SERVER['REQUEST_METHOD'] === 'POST') // This test must be after loading $_SESSION['token'].
386  {
387  if (GETPOST('token', 'alpha') != $_SESSION['token'])
388  {
389  dol_syslog("Invalid token in ".$_SERVER['HTTP_REFERER'].", action=".GETPOST('action','aZ09').", _POST['token']=".GETPOST('token','alpha').", _SESSION['token']=".$_SESSION['token'], LOG_WARNING);
390  //print 'Unset POST by CSRF protection in main.inc.php.'; // Do not output anything because this create problems when using the BACK button on browsers.
391  unset($_POST);
392  }
393  }
394 }
395 
396 // Disable modules (this must be after session_start and after conf has been loaded)
397 if (GETPOST('disablemodules','alpha')) $_SESSION["disablemodules"]=GETPOST('disablemodules','alpha');
398 if (! empty($_SESSION["disablemodules"]))
399 {
400  $disabled_modules=explode(',',$_SESSION["disablemodules"]);
401  foreach($disabled_modules as $module)
402  {
403  if ($module)
404  {
405  if (empty($conf->$module)) $conf->$module=new stdClass();
406  $conf->$module->enabled=false;
407  if ($module == 'fournisseur') // Special case
408  {
409  $conf->supplier_order->enabled=0;
410  $conf->supplier_invoice->enabled=0;
411  }
412  }
413  }
414 }
415 
416 /*
417  * Phase authentication / login
418  */
419 $login='';
420 if (! defined('NOLOGIN'))
421 {
422  // $authmode lists the different means of identification to be tested in order of preference.
423  // Example: 'http', 'dolibarr', 'ldap', 'http,forceuser', '...'
424 
425  if (defined('MAIN_AUTHENTICATION_MODE'))
426  {
427  $dolibarr_main_authentication = constant('MAIN_AUTHENTICATION_MODE');
428  }
429  else
430  {
431  // Authentication mode
432  if (empty($dolibarr_main_authentication)) $dolibarr_main_authentication='http,dolibarr';
433  // Authentication mode: forceuser
434  if ($dolibarr_main_authentication == 'forceuser' && empty($dolibarr_auto_user)) $dolibarr_auto_user='auto';
435  }
436  // Set authmode
437  $authmode=explode(',',$dolibarr_main_authentication);
438 
439  // No authentication mode
440  if (! count($authmode))
441  {
442  $langs->load('main');
443  dol_print_error('',$langs->trans("ErrorConfigParameterNotDefined",'dolibarr_main_authentication'));
444  exit;
445  }
446 
447  // If login request was already post, we retrieve login from the session
448  // Call module if not realized that his request.
449  // At the end of this phase, the variable $login is defined.
450  $resultFetchUser='';
451  $test=true;
452  if (! isset($_SESSION["dol_login"]))
453  {
454  // It is not already authenticated and it requests the login / password
455  include_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
456 
457  $dol_dst_observed=GETPOST("dst_observed",'int',3);
458  $dol_dst_first=GETPOST("dst_first",'int',3);
459  $dol_dst_second=GETPOST("dst_second",'int',3);
460  $dol_screenwidth=GETPOST("screenwidth",'int',3);
461  $dol_screenheight=GETPOST("screenheight",'int',3);
462  $dol_hide_topmenu=GETPOST('dol_hide_topmenu','int',3);
463  $dol_hide_leftmenu=GETPOST('dol_hide_leftmenu','int',3);
464  $dol_optimize_smallscreen=GETPOST('dol_optimize_smallscreen','int',3);
465  $dol_no_mouse_hover=GETPOST('dol_no_mouse_hover','int',3);
466  $dol_use_jmobile=GETPOST('dol_use_jmobile','int',3);
467  //dol_syslog("POST key=".join(array_keys($_POST),',').' value='.join($_POST,','));
468 
469  // If in demo mode, we check we go to home page through the public/demo/index.php page
470  if (! empty($dolibarr_main_demo) && $_SERVER['PHP_SELF'] == DOL_URL_ROOT.'/index.php') // We ask index page
471  {
472  if (empty($_SERVER['HTTP_REFERER']) || ! preg_match('/public/',$_SERVER['HTTP_REFERER']))
473  {
474  dol_syslog("Call index page from another url than demo page (call is done from page ".$_SERVER['HTTP_REFERER'].")");
475  $url='';
476  $url.=($url?'&':'').($dol_hide_topmenu?'dol_hide_topmenu='.$dol_hide_topmenu:'');
477  $url.=($url?'&':'').($dol_hide_leftmenu?'dol_hide_leftmenu='.$dol_hide_leftmenu:'');
478  $url.=($url?'&':'').($dol_optimize_smallscreen?'dol_optimize_smallscreen='.$dol_optimize_smallscreen:'');
479  $url.=($url?'&':'').($dol_no_mouse_hover?'dol_no_mouse_hover='.$dol_no_mouse_hover:'');
480  $url.=($url?'&':'').($dol_use_jmobile?'dol_use_jmobile='.$dol_use_jmobile:'');
481  $url=DOL_URL_ROOT.'/public/demo/index.php'.($url?'?'.$url:'');
482  header("Location: ".$url);
483  exit;
484  }
485  }
486 
487  // Verification security graphic code
488  if (GETPOST("username","alpha",2) && ! empty($conf->global->MAIN_SECURITY_ENABLECAPTCHA))
489  {
490  $sessionkey = 'dol_antispam_value';
491  $ok=(array_key_exists($sessionkey, $_SESSION) === true && (strtolower($_SESSION[$sessionkey]) == strtolower($_POST['code'])));
492 
493  // Check code
494  if (! $ok)
495  {
496  dol_syslog('Bad value for code, connexion refused');
497  // Load translation files required by page
498  $langs->loadLangs(array('main', 'errors'));
499 
500  $_SESSION["dol_loginmesg"]=$langs->trans("ErrorBadValueForCode");
501  $test=false;
502 
503  // Call trigger for the "security events" log
504  $user->trigger_mesg='ErrorBadValueForCode - login='.GETPOST("username","alpha",2);
505  // Call of triggers
506  include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
507  $interface=new Interfaces($db);
508  $result=$interface->run_triggers('USER_LOGIN_FAILED',$user,$user,$langs,$conf);
509  if ($result < 0) {
510  $error++;
511  }
512  // End Call of triggers
513 
514  // Hooks on failed login
515  $action='';
516  $hookmanager->initHooks(array('login'));
517  $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
518  $reshook=$hookmanager->executeHooks('afterLoginFailed',$parameters,$user,$action); // Note that $action and $object may have been modified by some hooks
519  if ($reshook < 0) $error++;
520 
521  // Note: exit is done later
522  }
523  }
524 
525  $allowedmethodtopostusername = 2;
526  if (defined('MAIN_AUTHENTICATION_POST_METHOD')) $allowedmethodtopostusername = constant('MAIN_AUTHENTICATION_POST_METHOD');
527  $usertotest = (! empty($_COOKIE['login_dolibarr']) ? $_COOKIE['login_dolibarr'] : GETPOST("username","alpha",$allowedmethodtopostusername));
528  $passwordtotest = GETPOST('password','none',$allowedmethodtopostusername);
529  $entitytotest = (GETPOST('entity','int') ? GETPOST('entity','int') : (!empty($conf->entity) ? $conf->entity : 1));
530 
531  // Define if we received data to test the login.
532  $goontestloop=false;
533  if (isset($_SERVER["REMOTE_USER"]) && in_array('http',$authmode)) $goontestloop=true;
534  if ($dolibarr_main_authentication == 'forceuser' && ! empty($dolibarr_auto_user)) $goontestloop=true;
535  if (GETPOST("username","alpha",$allowedmethodtopostusername) || ! empty($_COOKIE['login_dolibarr']) || GETPOST('openid_mode','alpha',1)) $goontestloop=true;
536 
537  if (! is_object($langs)) // This can occurs when calling page with NOREQUIRETRAN defined, however we need langs for error messages.
538  {
539  include_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
540  $langs=new Translate("",$conf);
541  $langcode=(GETPOST('lang','aZ09',1)?GETPOST('lang','aZ09',1):(empty($conf->global->MAIN_LANG_DEFAULT)?'auto':$conf->global->MAIN_LANG_DEFAULT));
542  if (defined('MAIN_LANG_DEFAULT')) $langcode=constant('MAIN_LANG_DEFAULT');
543  $langs->setDefaultLang($langcode);
544  }
545 
546  // Validation of login/pass/entity
547  // If ok, the variable login will be returned
548  // If error, we will put error message in session under the name dol_loginmesg
549  if ($test && $goontestloop)
550  {
551  $login = checkLoginPassEntity($usertotest,$passwordtotest,$entitytotest,$authmode);
552  if ($login)
553  {
554  $dol_authmode=$conf->authmode; // This properties is defined only when logged, to say what mode was successfully used
555  $dol_tz=$_POST["tz"];
556  $dol_tz_string=$_POST["tz_string"];
557  $dol_tz_string=preg_replace('/\s*\(.+\)$/','',$dol_tz_string);
558  $dol_tz_string=preg_replace('/,/','/',$dol_tz_string);
559  $dol_tz_string=preg_replace('/\s/','_',$dol_tz_string);
560  $dol_dst=0;
561  if (isset($_POST["dst_first"]) && isset($_POST["dst_second"]))
562  {
563  include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
564  $datenow=dol_now();
565  $datefirst=dol_stringtotime($_POST["dst_first"]);
566  $datesecond=dol_stringtotime($_POST["dst_second"]);
567  if ($datenow >= $datefirst && $datenow < $datesecond) $dol_dst=1;
568  }
569  //print $datefirst.'-'.$datesecond.'-'.$datenow.'-'.$dol_tz.'-'.$dol_tzstring.'-'.$dol_dst; exit;
570  }
571 
572  if (! $login)
573  {
574  dol_syslog('Bad password, connexion refused',LOG_DEBUG);
575  // Load translation files required by page
576  $langs->loadLangs(array('main', 'errors'));
577 
578  // Bad password. No authmode has found a good password.
579  // We set a generic message if not defined inside function checkLoginPassEntity or subfunctions
580  if (empty($_SESSION["dol_loginmesg"])) $_SESSION["dol_loginmesg"]=$langs->trans("ErrorBadLoginPassword");
581 
582  // Call trigger for the "security events" log
583  $user->trigger_mesg=$langs->trans("ErrorBadLoginPassword").' - login='.GETPOST("username","alpha",2);
584  // Call of triggers
585  include_once DOL_DOCUMENT_ROOT.'/core/class/interfaces.class.php';
586  $interface=new Interfaces($db);
587  $result=$interface->run_triggers('USER_LOGIN_FAILED',$user,$user,$langs,$conf,GETPOST("username","alpha",2));
588  if ($result < 0) {
589  $error++;
590  }
591  // End Call of triggers
592 
593  // Hooks on failed login
594  $action='';
595  $hookmanager->initHooks(array('login'));
596  $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
597  $reshook=$hookmanager->executeHooks('afterLoginFailed',$parameters,$user,$action); // Note that $action and $object may have been modified by some hooks
598  if ($reshook < 0) $error++;
599 
600  // Note: exit is done in next chapter
601  }
602  }
603 
604  // End test login / passwords
605  if (! $login || (in_array('ldap',$authmode) && empty($passwordtotest))) // With LDAP we refused empty password because some LDAP are "opened" for anonymous access so connexion is a success.
606  {
607  // No data to test login, so we show the login page
608  dol_syslog("--- Access to ".$_SERVER["PHP_SELF"]." showing the login form and exit");
609  if (defined('NOREDIRECTBYMAINTOLOGIN')) return 'ERROR_NOT_LOGGED';
610  else dol_loginfunction($langs,$conf,(! empty($mysoc)?$mysoc:''));
611  exit;
612  }
613 
614  $resultFetchUser=$user->fetch('', $login, '', 1, ($entitytotest > 0 ? $entitytotest : -1));
615  if ($resultFetchUser <= 0)
616  {
617  dol_syslog('User not found, connexion refused');
618  session_destroy();
619  session_name($sessionname);
620  session_set_cookie_params(0, '/', null, false, true); // Add tag httponly on session cookie
621  session_start(); // Fixing the bug of register_globals here is useless since session is empty
622 
623  if ($resultFetchUser == 0)
624  {
625  // Load translation files required by page
626  $langs->loadLangs(array('main', 'errors'));
627 
628  $_SESSION["dol_loginmesg"]=$langs->trans("ErrorCantLoadUserFromDolibarrDatabase",$login);
629 
630  $user->trigger_mesg='ErrorCantLoadUserFromDolibarrDatabase - login='.$login;
631  }
632  if ($resultFetchUser < 0)
633  {
634  $_SESSION["dol_loginmesg"]=$user->error;
635 
636  $user->trigger_mesg=$user->error;
637  }
638 
639  // Call triggers for the "security events" log
640  include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
641  $interface=new Interfaces($db);
642  $result=$interface->run_triggers('USER_LOGIN_FAILED',$user,$user,$langs,$conf);
643  if ($result < 0) {
644  $error++;
645  }
646  // End call triggers
647 
648  // Hooks on failed login
649  $action='';
650  $hookmanager->initHooks(array('login'));
651  $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
652  $reshook=$hookmanager->executeHooks('afterLoginFailed',$parameters,$user,$action); // Note that $action and $object may have been modified by some hooks
653  if ($reshook < 0) $error++;
654 
655  $paramsurl=array();
656  if (GETPOST('textbrowser','int')) $paramsurl[]='textbrowser='.GETPOST('textbrowser','int');
657  if (GETPOST('nojs','int')) $paramsurl[]='nojs='.GETPOST('nojs','int');
658  if (GETPOST('lang','aZ09')) $paramsurl[]='lang='.GETPOST('lang','aZ09');
659  header('Location: '.DOL_URL_ROOT.'/index.php'.(count($paramsurl)?'?'.implode('&',$paramsurl):''));
660  exit;
661  }
662  }
663  else
664  {
665  // We are already into an authenticated session
666  $login=$_SESSION["dol_login"];
667  $entity=$_SESSION["dol_entity"];
668  dol_syslog("- This is an already logged session. _SESSION['dol_login']=".$login." _SESSION['dol_entity']=".$entity, LOG_DEBUG);
669 
670  $resultFetchUser=$user->fetch('', $login, '', 1, ($entity > 0 ? $entity : -1));
671  if ($resultFetchUser <= 0)
672  {
673  // Account has been removed after login
674  dol_syslog("Can't load user even if session logged. _SESSION['dol_login']=".$login, LOG_WARNING);
675  session_destroy();
676  session_name($sessionname);
677  session_set_cookie_params(0, '/', null, false, true); // Add tag httponly on session cookie
678  session_start(); // Fixing the bug of register_globals here is useless since session is empty
679 
680  if ($resultFetchUser == 0)
681  {
682  // Load translation files required by page
683  $langs->loadLangs(array('main', 'errors'));
684 
685  $_SESSION["dol_loginmesg"]=$langs->trans("ErrorCantLoadUserFromDolibarrDatabase",$login);
686 
687  $user->trigger_mesg='ErrorCantLoadUserFromDolibarrDatabase - login='.$login;
688  }
689  if ($resultFetchUser < 0)
690  {
691  $_SESSION["dol_loginmesg"]=$user->error;
692 
693  $user->trigger_mesg=$user->error;
694  }
695 
696  // Call triggers for the "security events" log
697  include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
698  $interface=new Interfaces($db);
699  $result=$interface->run_triggers('USER_LOGIN_FAILED',$user,$user,$langs,$conf);
700  if ($result < 0) {
701  $error++;
702  }
703  // End call triggers
704 
705  // Hooks on failed login
706  $action='';
707  $hookmanager->initHooks(array('login'));
708  $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginmesg'=>$_SESSION["dol_loginmesg"]);
709  $reshook=$hookmanager->executeHooks('afterLoginFailed',$parameters,$user,$action); // Note that $action and $object may have been modified by some hooks
710  if ($reshook < 0) $error++;
711 
712  $paramsurl=array();
713  if (GETPOST('textbrowser','int')) $paramsurl[]='textbrowser='.GETPOST('textbrowser','int');
714  if (GETPOST('nojs','int')) $paramsurl[]='nojs='.GETPOST('nojs','int');
715  if (GETPOST('lang','aZ09')) $paramsurl[]='lang='.GETPOST('lang','aZ09');
716  header('Location: '.DOL_URL_ROOT.'/index.php'.(count($paramsurl)?'?'.implode('&',$paramsurl):''));
717  exit;
718  }
719  else
720  {
721  // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
722  $hookmanager->initHooks(array('main'));
723 
724  // Code for search criteria persistence.
725  if (! empty($_GET['save_lastsearch_values'])) // We must use $_GET here
726  {
727  $relativepathstring = preg_replace('/\?.*$/','',$_SERVER["HTTP_REFERER"]);
728  $relativepathstring = preg_replace('/^https?:\/\/[^\/]*/','',$relativepathstring); // Get full path except host server
729  // Clean $relativepathstring
730  if (constant('DOL_URL_ROOT')) $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'),'/').'/', '', $relativepathstring);
731  $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
732  $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
733  //var_dump($relativepathstring);
734 
735  // We click on a link that leave a page we have to save search criteria, contextpage, limit and page. We save them from tmp to no tmp
736  if (! empty($_SESSION['lastsearch_values_tmp_'.$relativepathstring]))
737  {
738  $_SESSION['lastsearch_values_'.$relativepathstring]=$_SESSION['lastsearch_values_tmp_'.$relativepathstring];
739  unset($_SESSION['lastsearch_values_tmp_'.$relativepathstring]);
740  }
741  if (! empty($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]))
742  {
743  $_SESSION['lastsearch_contextpage_'.$relativepathstring]=$_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring];
744  unset($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]);
745  }
746  if (! empty($_SESSION['lastsearch_page_tmp_'.$relativepathstring]) && $_SESSION['lastsearch_page_tmp_'.$relativepathstring] > 1)
747  {
748  $_SESSION['lastsearch_page_'.$relativepathstring]=$_SESSION['lastsearch_page_tmp_'.$relativepathstring];
749  unset($_SESSION['lastsearch_page_tmp_'.$relativepathstring]);
750  }
751  if (! empty($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]) && $_SESSION['lastsearch_limit_tmp_'.$relativepathstring] != $conf->liste_limit)
752  {
753  $_SESSION['lastsearch_limit_'.$relativepathstring]=$_SESSION['lastsearch_limit_tmp_'.$relativepathstring];
754  unset($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]);
755  }
756  }
757 
758  $action = '';
759  $reshook = $hookmanager->executeHooks('updateSession', array(), $user, $action);
760  if ($reshook < 0) {
761  setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
762  }
763  }
764  }
765 
766  // Is it a new session that has started ?
767  // If we are here, this means authentication was successfull.
768  if (! isset($_SESSION["dol_login"]))
769  {
770  // New session for this login has started.
771  $error=0;
772 
773  // Store value into session (values always stored)
774  $_SESSION["dol_login"]=$user->login;
775  $_SESSION["dol_authmode"]=isset($dol_authmode)?$dol_authmode:'';
776  $_SESSION["dol_tz"]=isset($dol_tz)?$dol_tz:'';
777  $_SESSION["dol_tz_string"]=isset($dol_tz_string)?$dol_tz_string:'';
778  $_SESSION["dol_dst"]=isset($dol_dst)?$dol_dst:'';
779  $_SESSION["dol_dst_observed"]=isset($dol_dst_observed)?$dol_dst_observed:'';
780  $_SESSION["dol_dst_first"]=isset($dol_dst_first)?$dol_dst_first:'';
781  $_SESSION["dol_dst_second"]=isset($dol_dst_second)?$dol_dst_second:'';
782  $_SESSION["dol_screenwidth"]=isset($dol_screenwidth)?$dol_screenwidth:'';
783  $_SESSION["dol_screenheight"]=isset($dol_screenheight)?$dol_screenheight:'';
784  $_SESSION["dol_company"]=$conf->global->MAIN_INFO_SOCIETE_NOM;
785  $_SESSION["dol_entity"]=$conf->entity;
786  // Store value into session (values stored only if defined)
787  if (! empty($dol_hide_topmenu)) $_SESSION['dol_hide_topmenu']=$dol_hide_topmenu;
788  if (! empty($dol_hide_leftmenu)) $_SESSION['dol_hide_leftmenu']=$dol_hide_leftmenu;
789  if (! empty($dol_optimize_smallscreen)) $_SESSION['dol_optimize_smallscreen']=$dol_optimize_smallscreen;
790  if (! empty($dol_no_mouse_hover)) $_SESSION['dol_no_mouse_hover']=$dol_no_mouse_hover;
791  if (! empty($dol_use_jmobile)) $_SESSION['dol_use_jmobile']=$dol_use_jmobile;
792 
793  dol_syslog("This is a new started user session. _SESSION['dol_login']=".$_SESSION["dol_login"]." Session id=".session_id());
794 
795  $db->begin();
796 
797  $user->update_last_login_date();
798 
799  $loginfo = 'TZ='.$_SESSION["dol_tz"].';TZString='.$_SESSION["dol_tz_string"].';Screen='.$_SESSION["dol_screenwidth"].'x'.$_SESSION["dol_screenheight"];
800 
801  // Call triggers for the "security events" log
802  $user->trigger_mesg = $loginfo;
803  // Call triggers
804  include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php';
805  $interface=new Interfaces($db);
806  $result=$interface->run_triggers('USER_LOGIN',$user,$user,$langs,$conf);
807  if ($result < 0) {
808  $error++;
809  }
810  // End call triggers
811 
812  // Hooks on successfull login
813  $action='';
814  $hookmanager->initHooks(array('login'));
815  $parameters=array('dol_authmode'=>$dol_authmode, 'dol_loginfo'=>$loginfo);
816  $reshook=$hookmanager->executeHooks('afterLogin',$parameters,$user,$action); // Note that $action and $object may have been modified by some hooks
817  if ($reshook < 0) $error++;
818 
819  if ($error)
820  {
821  $db->rollback();
822  session_destroy();
823  dol_print_error($db,'Error in some triggers USER_LOGIN or in some hooks afterLogin');
824  exit;
825  }
826  else
827  {
828  $db->commit();
829  }
830 
831  // Change landing page if defined.
832  $landingpage=(empty($user->conf->MAIN_LANDING_PAGE)?(empty($conf->global->MAIN_LANDING_PAGE)?'':$conf->global->MAIN_LANDING_PAGE):$user->conf->MAIN_LANDING_PAGE);
833  if (! empty($landingpage)) // Example: /index.php
834  {
835  $newpath=dol_buildpath($landingpage, 1);
836  if ($_SERVER["PHP_SELF"] != $newpath) // not already on landing page (avoid infinite loop)
837  {
838  header('Location: '.$newpath);
839  exit;
840  }
841  }
842  }
843 
844 
845  // If user admin, we force the rights-based modules
846  if ($user->admin)
847  {
848  $user->rights->user->user->lire=1;
849  $user->rights->user->user->creer=1;
850  $user->rights->user->user->password=1;
851  $user->rights->user->user->supprimer=1;
852  $user->rights->user->self->creer=1;
853  $user->rights->user->self->password=1;
854  }
855 
856  /*
857  * Overwrite some configs globals (try to avoid this and have code to use instead $user->conf->xxx)
858  */
859 
860  // Set liste_limit
861  if (isset($user->conf->MAIN_SIZE_LISTE_LIMIT)) $conf->liste_limit = $user->conf->MAIN_SIZE_LISTE_LIMIT; // Can be 0
862  if (isset($user->conf->PRODUIT_LIMIT_SIZE)) $conf->product->limit_size = $user->conf->PRODUIT_LIMIT_SIZE; // Can be 0
863 
864  // Replace conf->css by personalized value if theme not forced
865  if (empty($conf->global->MAIN_FORCETHEME) && ! empty($user->conf->MAIN_THEME))
866  {
867  $conf->theme=$user->conf->MAIN_THEME;
868  $conf->css = "/theme/".$conf->theme."/style.css.php";
869  }
870 }
871 
872 // Case forcing style from url
873 if (GETPOST('theme','alpha'))
874 {
875  $conf->theme=GETPOST('theme','alpha',1);
876  $conf->css = "/theme/".$conf->theme."/style.css.php";
877 }
878 
879 
880 // Set javascript option
881 if (! GETPOST('nojs','int')) // If javascript was not disabled on URL
882 {
883  if (! empty($user->conf->MAIN_DISABLE_JAVASCRIPT))
884  {
885  $conf->use_javascript_ajax=! $user->conf->MAIN_DISABLE_JAVASCRIPT;
886  }
887 }
888 else $conf->use_javascript_ajax=0;
889 // Set MAIN_OPTIMIZEFORTEXTBROWSER
890 if (GETPOST('textbrowser','int') || (! empty($conf->browser->name) && $conf->browser->name == 'lynxlinks') || ! empty($user->conf->MAIN_OPTIMIZEFORTEXTBROWSER)) // If we must enable text browser
891 {
892  $conf->global->MAIN_OPTIMIZEFORTEXTBROWSER=1;
893 }
894 elseif (! empty($user->conf->MAIN_OPTIMIZEFORTEXTBROWSER))
895 {
896  $conf->global->MAIN_OPTIMIZEFORTEXTBROWSER=$user->conf->MAIN_OPTIMIZEFORTEXTBROWSER;
897 }
898 
899 // Set terminal output option according to conf->browser.
900 if (GETPOST('dol_hide_leftmenu','int') || ! empty($_SESSION['dol_hide_leftmenu'])) $conf->dol_hide_leftmenu=1;
901 if (GETPOST('dol_hide_topmenu','int') || ! empty($_SESSION['dol_hide_topmenu'])) $conf->dol_hide_topmenu=1;
902 if (GETPOST('dol_optimize_smallscreen','int') || ! empty($_SESSION['dol_optimize_smallscreen'])) $conf->dol_optimize_smallscreen=1;
903 if (GETPOST('dol_no_mouse_hover','int') || ! empty($_SESSION['dol_no_mouse_hover'])) $conf->dol_no_mouse_hover=1;
904 if (GETPOST('dol_use_jmobile','int') || ! empty($_SESSION['dol_use_jmobile'])) $conf->dol_use_jmobile=1;
905 if (! empty($conf->browser->layout) && $conf->browser->layout != 'classic') $conf->dol_no_mouse_hover=1;
906 if ((! empty($conf->browser->layout) && $conf->browser->layout == 'phone')
907  || (! empty($_SESSION['dol_screenwidth']) && $_SESSION['dol_screenwidth'] < 400)
908  || (! empty($_SESSION['dol_screenheight']) && $_SESSION['dol_screenheight'] < 400)
909 )
910 {
911  $conf->dol_optimize_smallscreen=1;
912 }
913 // If we force to use jmobile, then we reenable javascript
914 if (! empty($conf->dol_use_jmobile)) $conf->use_javascript_ajax=1;
915 // Replace themes bugged with jmobile with eldy
916 if (! empty($conf->dol_use_jmobile) && in_array($conf->theme, array('bureau2crea','cameleo','amarok')))
917 {
918  $conf->theme='eldy';
919  $conf->css = "/theme/".$conf->theme."/style.css.php";
920 }
921 
922 if (! defined('NOREQUIRETRAN'))
923 {
924  if (! GETPOST('lang','aZ09')) // If language was not forced on URL
925  {
926  // If user has chosen its own language
927  if (! empty($user->conf->MAIN_LANG_DEFAULT))
928  {
929  // If different than current language
930  //print ">>>".$langs->getDefaultLang()."-".$user->conf->MAIN_LANG_DEFAULT;
931  if ($langs->getDefaultLang() != $user->conf->MAIN_LANG_DEFAULT)
932  {
933  $langs->setDefaultLang($user->conf->MAIN_LANG_DEFAULT);
934  }
935  }
936  }
937 }
938 
939 if (! defined('NOLOGIN'))
940 {
941  // If the login is not recovered, it is identified with an account that does not exist.
942  // Hacking attempt?
943  if (! $user->login) accessforbidden();
944 
945  // Check if user is active
946  if ($user->statut < 1)
947  {
948  // If not active, we refuse the user
949  $langs->load("other");
950  dol_syslog("Authentification ko as login is disabled");
951  accessforbidden($langs->trans("ErrorLoginDisabled"));
952  exit;
953  }
954 
955  // Load permissions
956  $user->getrights();
957 }
958 
959 
960 dol_syslog("--- Access to ".$_SERVER["PHP_SELF"].' - action='.GETPOST('action','az09').', massaction='.GETPOST('massaction','az09'));
961 //Another call for easy debugg
962 //dol_syslog("Access to ".$_SERVER["PHP_SELF"].' GET='.join(',',array_keys($_GET)).'->'.join(',',$_GET).' POST:'.join(',',array_keys($_POST)).'->'.join(',',$_POST));
963 
964 // Load main languages files
965 if (! defined('NOREQUIRETRAN'))
966 {
967  // Load translation files required by page
968  $langs->loadLangs(array('main', 'dict'));
969 }
970 
971 // Define some constants used for style of arrays
972 $bc=array(0=>'class="impair"',1=>'class="pair"');
973 $bcdd=array(0=>'class="drag drop oddeven"',1=>'class="drag drop oddeven"');
974 $bcnd=array(0=>'class="nodrag nodrop nohover"',1=>'class="nodrag nodrop nohoverpair"'); // Used for tr to add new lines
975 $bctag=array(0=>'class="impair tagtr"',1=>'class="pair tagtr"');
976 
977 // Define messages variables
978 $mesg=''; $warning=''; $error=0;
979 // deprecated, see setEventMessages() and dol_htmloutput_events()
980 $mesgs=array(); $warnings=array(); $errors=array();
981 
982 // Constants used to defined number of lines in textarea
983 if (empty($conf->browser->firefox))
984 {
985  define('ROWS_1',1);
986  define('ROWS_2',2);
987  define('ROWS_3',3);
988  define('ROWS_4',4);
989  define('ROWS_5',5);
990  define('ROWS_6',6);
991  define('ROWS_7',7);
992  define('ROWS_8',8);
993  define('ROWS_9',9);
994 }
995 else
996 {
997  define('ROWS_1',0);
998  define('ROWS_2',1);
999  define('ROWS_3',2);
1000  define('ROWS_4',3);
1001  define('ROWS_5',4);
1002  define('ROWS_6',5);
1003  define('ROWS_7',6);
1004  define('ROWS_8',7);
1005  define('ROWS_9',8);
1006 }
1007 
1008 $heightforframes=50;
1009 
1010 // Init menu manager
1011 if (! defined('NOREQUIREMENU'))
1012 {
1013  if (empty($user->societe_id)) // If internal user or not defined
1014  {
1015  $conf->standard_menu=(empty($conf->global->MAIN_MENU_STANDARD_FORCED)?(empty($conf->global->MAIN_MENU_STANDARD)?'eldy_menu.php':$conf->global->MAIN_MENU_STANDARD):$conf->global->MAIN_MENU_STANDARD_FORCED);
1016  }
1017  else // If external user
1018  {
1019  $conf->standard_menu=(empty($conf->global->MAIN_MENUFRONT_STANDARD_FORCED)?(empty($conf->global->MAIN_MENUFRONT_STANDARD)?'eldy_menu.php':$conf->global->MAIN_MENUFRONT_STANDARD):$conf->global->MAIN_MENUFRONT_STANDARD_FORCED);
1020  }
1021 
1022  // Load the menu manager (only if not already done)
1023  $file_menu=$conf->standard_menu;
1024  if (GETPOST('menu','alpha')) $file_menu=GETPOST('menu','alpha'); // example: menu=eldy_menu.php
1025  if (! class_exists('MenuManager'))
1026  {
1027  $menufound=0;
1028  $dirmenus=array_merge(array("/core/menus/"),(array) $conf->modules_parts['menus']);
1029  foreach($dirmenus as $dirmenu)
1030  {
1031  $menufound=dol_include_once($dirmenu."standard/".$file_menu);
1032  if (class_exists('MenuManager')) break;
1033  }
1034  if (! class_exists('MenuManager')) // If failed to include, we try with standard eldy_menu.php
1035  {
1036  dol_syslog("You define a menu manager '".$file_menu."' that can not be loaded.", LOG_WARNING);
1037  $file_menu='eldy_menu.php';
1038  include_once DOL_DOCUMENT_ROOT."/core/menus/standard/".$file_menu;
1039  }
1040  }
1041  $menumanager = new MenuManager($db, empty($user->societe_id)?0:1);
1042  $menumanager->loadMenu();
1043 }
1044 
1045 
1046 
1047 // Functions
1048 
1049 if (! function_exists("llxHeader"))
1050 {
1069  function llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='')
1070  {
1071  global $conf;
1072 
1073  // html header
1074  top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
1075 
1076  print '<body id="mainbody"'.($morecssonbody?' class="'.$morecssonbody.'"':'').'>' . "\n";
1077 
1078  // top menu and left menu area
1079  if (empty($conf->dol_hide_topmenu) || GETPOST('dol_invisible_topmenu','int'))
1080  {
1081  top_menu($head, $title, $target, $disablejs, $disablehead, $arrayofjs, $arrayofcss, $morequerystring, $help_url);
1082  }
1083 
1084  if (empty($conf->dol_hide_leftmenu))
1085  {
1086  left_menu('', $help_url, '', '', 1, $title, 1); // $menumanager is retreived with a global $menumanager inside this function
1087  }
1088 
1089  // main area
1090  if ($replacemainareaby)
1091  {
1092  print $replacemainareaby;
1093  return;
1094  }
1095  main_area($title);
1096  }
1097 }
1098 
1099 
1107 function top_httphead($contenttype='text/html', $forcenocache=0)
1108 {
1109  global $db, $conf, $hookmanager;
1110 
1111  if ($contenttype == 'text/html' ) header("Content-Type: text/html; charset=".$conf->file->character_set_client);
1112  else header("Content-Type: ".$contenttype);
1113  // Security options
1114  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)
1115  header("X-Frame-Options: SAMEORIGIN"); // Frames allowed only if on same domain (stop some XSS attacks)
1116  //header("X-XSS-Protection: 1"); // XSS protection of some browsers (note: use of Content-Security-Policy is more efficient). Disabled as deprecated.
1117  if (! defined('FORCECSP'))
1118  {
1119  //if (! isset($conf->global->MAIN_HTTP_CONTENT_SECURITY_POLICY))
1120  //{
1121  // // A default security policy that keep usage of js external component like ckeditor, stripe, google, working
1122  // $contentsecuritypolicy = "font-src *; img-src *; style-src * 'unsafe-inline' 'unsafe-eval'; default-src 'self' *.stripe.com 'unsafe-inline' 'unsafe-eval'; script-src 'self' *.stripe.com 'unsafe-inline' 'unsafe-eval'; frame-src 'self' *.stripe.com; connect-src 'self';";
1123  //}
1124  //else $contentsecuritypolicy = $conf->global->MAIN_HTTP_CONTENT_SECURITY_POLICY;
1125  $contentsecuritypolicy = $conf->global->MAIN_HTTP_CONTENT_SECURITY_POLICY;
1126 
1127  if (! is_object($hookmanager)) $hookmanager = new HookManager($db);
1128  $hookmanager->initHooks("main");
1129 
1130  $parameters=array('contentsecuritypolicy'=>$contentsecuritypolicy);
1131  $result=$hookmanager->executeHooks('setContentSecurityPolicy',$parameters); // Note that $action and $object may have been modified by some hooks
1132  if ($result > 0) $contentsecuritypolicy = $hookmanager->resPrint; // Replace CSP
1133  else $contentsecuritypolicy .= $hookmanager->resPrint; // Concat CSP
1134 
1135  if (! empty($contentsecuritypolicy))
1136  {
1137  // For example, to restrict 'script', 'object', 'frames' or 'img' to some domains:
1138  // script-src https://api.google.com https://anotherhost.com; object-src https://youtube.com; frame-src https://youtube.com; img-src: https://static.example.com
1139  // For example, to restrict everything to one domain, except 'object', ...:
1140  // default-src https://cdn.example.net; object-src 'none'
1141  // For example, to restrict everything to itself except img that can be on other servers:
1142  // default-src 'self'; img-src *;
1143  // Pre-existing site that uses too much inline code to fix but wants to ensure resources are loaded only over https and disable plugins:
1144  // default-src http: https: 'unsafe-eval' 'unsafe-inline'; object-src 'none'
1145  header("Content-Security-Policy: ".$contentsecuritypolicy);
1146  }
1147  }
1148  elseif (constant('FORCECSP'))
1149  {
1150  header("Content-Security-Policy: ".constant('FORCECSP'));
1151  }
1152  if ($forcenocache)
1153  {
1154  header("Cache-Control: no-cache, no-store, must-revalidate, max-age=0");
1155  }
1156 }
1157 
1172 function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $disablejmobile=0, $disablenofollow=0)
1173 {
1174  global $db, $conf, $langs, $user, $hookmanager;
1175 
1176  top_httphead();
1177 
1178  if (empty($conf->css)) $conf->css = '/theme/eldy/style.css.php'; // If not defined, eldy by default
1179 
1180  print '<!doctype html>'."\n";
1181 
1182  if (! empty($conf->global->MAIN_USE_CACHE_MANIFEST)) print '<html lang="'.substr($langs->defaultlang,0,2).'" manifest="'.DOL_URL_ROOT.'/cache.manifest">'."\n";
1183  else print '<html lang="'.substr($langs->defaultlang,0,2).'">'."\n";
1184  //print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr">'."\n";
1185  if (empty($disablehead))
1186  {
1187  $ext='layout='.$conf->browser->layout.'&version='.urlencode(DOL_VERSION);
1188 
1189  print "<head>\n";
1190 
1191  if (GETPOST('dol_basehref','alpha')) print '<base href="'.dol_escape_htmltag(GETPOST('dol_basehref','alpha')).'">'."\n";
1192 
1193  // Displays meta
1194  print '<meta charset="UTF-8">'."\n";
1195  print '<meta name="robots" content="noindex'.($disablenofollow?'':',nofollow').'">'."\n"; // Do not index
1196  print '<meta name="viewport" content="width=device-width, initial-scale=1.0">'."\n"; // Scale for mobile device
1197  print '<meta name="author" content="Dolibarr Development Team">'."\n";
1198 
1199  // Favicon
1200  $favicon=dol_buildpath('/theme/'.$conf->theme.'/img/favicon.ico',1);
1201  if (! empty($conf->global->MAIN_FAVICON_URL)) $favicon=$conf->global->MAIN_FAVICON_URL;
1202  if (empty($conf->dol_use_jmobile)) print '<link rel="shortcut icon" type="image/x-icon" href="'.$favicon.'"/>'."\n"; // Not required into an Android webview
1203  //if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) print '<link rel="top" title="'.$langs->trans("Home").'" href="'.(DOL_URL_ROOT?DOL_URL_ROOT:'/').'">'."\n";
1204  //if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) print '<link rel="copyright" title="GNU General Public License" href="http://www.gnu.org/copyleft/gpl.html#SEC1">'."\n";
1205  //if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) print '<link rel="author" title="Dolibarr Development Team" href="https://www.dolibarr.org">'."\n";
1206 
1207  // Auto refresh page
1208  if (GETPOST('autorefresh','int') > 0) print '<meta http-equiv="refresh" content="'.GETPOST('autorefresh','int').'">';
1209 
1210  // Displays title
1211  $appli=constant('DOL_APPLICATION_TITLE');
1212  if (!empty($conf->global->MAIN_APPLICATION_TITLE)) $appli=$conf->global->MAIN_APPLICATION_TITLE;
1213 
1214  print '<title>';
1215  $titletoshow='';
1216  if ($title && ! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/noapp/',$conf->global->MAIN_HTML_TITLE)) $titletoshow = dol_htmlentities($title);
1217  else if ($title) $titletoshow = dol_htmlentities($appli.' - '.$title);
1218  else $titletoshow = dol_htmlentities($appli);
1219 
1220  if (! is_object($hookmanager)) $hookmanager = new HookManager($db);
1221  $hookmanager->initHooks("main");
1222  $parameters=array('title'=>$titletoshow);
1223  $result=$hookmanager->executeHooks('setHtmlTitle',$parameters); // Note that $action and $object may have been modified by some hooks
1224  if ($result > 0) $titletoshow = $hookmanager->resPrint; // Replace Title to show
1225  else $titletoshow .= $hookmanager->resPrint; // Concat to Title to show
1226 
1227  print $titletoshow;
1228  print '</title>';
1229 
1230  print "\n";
1231 
1232  if (GETPOST('version','int')) $ext='version='.GETPOST('version','int'); // usefull to force no cache on css/js
1233  if (GETPOST('testmenuhider','int') || ! empty($conf->global->MAIN_TESTMENUHIDER)) $ext.='&testmenuhider='.(GETPOST('testmenuhider','int')?GETPOST('testmenuhider','int'):$conf->global->MAIN_TESTMENUHIDER);
1234 
1235  $themeparam='?lang='.$langs->defaultlang.'&amp;theme='.$conf->theme.(GETPOST('optioncss','aZ09')?'&amp;optioncss='.GETPOST('optioncss','aZ09',1):'').'&amp;userid='.$user->id.'&amp;entity='.$conf->entity;
1236  $themeparam.=($ext?'&amp;'.$ext:'');
1237  if (! empty($_SESSION['dol_resetcache'])) $themeparam.='&amp;dol_resetcache='.$_SESSION['dol_resetcache'];
1238  if (GETPOST('dol_hide_topmenu','int')) { $themeparam.='&amp;dol_hide_topmenu='.GETPOST('dol_hide_topmenu','int'); }
1239  if (GETPOST('dol_hide_leftmenu','int')) { $themeparam.='&amp;dol_hide_leftmenu='.GETPOST('dol_hide_leftmenu','int'); }
1240  if (GETPOST('dol_optimize_smallscreen','int')) { $themeparam.='&amp;dol_optimize_smallscreen='.GETPOST('dol_optimize_smallscreen','int'); }
1241  if (GETPOST('dol_no_mouse_hover','int')) { $themeparam.='&amp;dol_no_mouse_hover='.GETPOST('dol_no_mouse_hover','int'); }
1242  if (GETPOST('dol_use_jmobile','int')) { $themeparam.='&amp;dol_use_jmobile='.GETPOST('dol_use_jmobile','int'); $conf->dol_use_jmobile=GETPOST('dol_use_jmobile','int'); }
1243 
1244  if (! defined('DISABLE_JQUERY') && ! $disablejs && $conf->use_javascript_ajax)
1245  {
1246  print '<!-- Includes CSS for JQuery (Ajax library) -->'."\n";
1247  $jquerytheme = 'base';
1248  if (!empty($conf->global->MAIN_USE_JQUERY_THEME)) $jquerytheme = $conf->global->MAIN_USE_JQUERY_THEME;
1249  if (constant('JS_JQUERY_UI')) print '<link rel="stylesheet" type="text/css" href="'.JS_JQUERY_UI.'css/'.$jquerytheme.'/jquery-ui.min.css'.($ext?'?'.$ext:'').'">'."\n"; // JQuery
1250  else print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/css/'.$jquerytheme.'/jquery-ui.css'.($ext?'?'.$ext:'').'">'."\n"; // JQuery
1251  if (! defined('DISABLE_JQUERY_JNOTIFY')) print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/jnotify/jquery.jnotify-alt.min.css'.($ext?'?'.$ext:'').'">'."\n"; // JNotify
1252  if (! defined('DISABLE_SELECT2') && (! empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT'))) // jQuery plugin "mutiselect", "multiple-select", "select2"...
1253  {
1254  $tmpplugin=empty($conf->global->MAIN_USE_JQUERY_MULTISELECT)?constant('REQUIRE_JQUERY_MULTISELECT'):$conf->global->MAIN_USE_JQUERY_MULTISELECT;
1255  print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/includes/jquery/plugins/'.$tmpplugin.'/dist/css/'.$tmpplugin.'.css'.($ext?'?'.$ext:'').'">'."\n";
1256  }
1257  }
1258 
1259  if (! defined('DISABLE_FONT_AWSOME'))
1260  {
1261  print '<!-- Includes CSS for font awesome -->'."\n";
1262  print '<link rel="stylesheet" type="text/css" href="'.DOL_URL_ROOT.'/theme/common/fontawesome/css/font-awesome.min.css'.($ext?'?'.$ext:'').'">'."\n";
1263  }
1264 
1265  print '<!-- Includes CSS for Dolibarr theme -->'."\n";
1266  // Output style sheets (optioncss='print' or ''). Note: $conf->css looks like '/theme/eldy/style.css.php'
1267  $themepath=dol_buildpath($conf->css,1);
1268  $themesubdir='';
1269  if (! empty($conf->modules_parts['theme'])) // This slow down
1270  {
1271  foreach($conf->modules_parts['theme'] as $reldir)
1272  {
1273  if (file_exists(dol_buildpath($reldir.$conf->css, 0)))
1274  {
1275  $themepath=dol_buildpath($reldir.$conf->css, 1);
1276  $themesubdir=$reldir;
1277  break;
1278  }
1279  }
1280  }
1281 
1282  //print 'themepath='.$themepath.' themeparam='.$themeparam;exit;
1283  print '<link rel="stylesheet" type="text/css" href="'.$themepath.$themeparam.'">'."\n";
1284  if (! empty($conf->global->MAIN_FIX_FLASH_ON_CHROME)) 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";
1285 
1286  // CSS forced by modules (relative url starting with /)
1287  if (! empty($conf->modules_parts['css']))
1288  {
1289  $arraycss=(array) $conf->modules_parts['css'];
1290  foreach($arraycss as $modcss => $filescss)
1291  {
1292  $filescss=(array) $filescss; // To be sure filecss is an array
1293  foreach($filescss as $cssfile)
1294  {
1295  if (empty($cssfile)) dol_syslog("Warning: module ".$modcss." declared a css path file into its descriptor that is empty.", LOG_WARNING);
1296  // cssfile is a relative path
1297  print '<!-- Includes CSS added by module '.$modcss. ' -->'."\n".'<link rel="stylesheet" type="text/css" href="'.dol_buildpath($cssfile,1);
1298  // 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.
1299  if (!preg_match('/\.css$/i',$cssfile)) print $themeparam;
1300  print '">'."\n";
1301  }
1302  }
1303  }
1304  // CSS forced by page in top_htmlhead call (relative url starting with /)
1305  if (is_array($arrayofcss))
1306  {
1307  foreach($arrayofcss as $cssfile)
1308  {
1309  print '<!-- Includes CSS added by page -->'."\n".'<link rel="stylesheet" type="text/css" title="default" href="'.dol_buildpath($cssfile,1);
1310  // 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.
1311  if (!preg_match('/\.css$/i',$cssfile)) print $themeparam;
1312  print '">'."\n";
1313  }
1314  }
1315 
1316  // Output standard javascript links
1317  if (! defined('DISABLE_JQUERY') && ! $disablejs && ! empty($conf->use_javascript_ajax))
1318  {
1319  // JQuery. Must be before other includes
1320  print '<!-- Includes JS for JQuery -->'."\n";
1321  if (defined('JS_JQUERY') && constant('JS_JQUERY')) print '<script type="text/javascript" src="'.JS_JQUERY.'jquery.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1322  else print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1323  if (! empty($conf->global->MAIN_FEATURES_LEVEL) && ! defined('JS_JQUERY_MIGRATE_DISABLED'))
1324  {
1325  if (defined('JS_JQUERY_MIGRATE') && constant('JS_JQUERY_MIGRATE')) print '<script type="text/javascript" src="'.JS_JQUERY_MIGRATE.'jquery-migrate.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1326  else print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery-migrate.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1327  }
1328  if (defined('JS_JQUERY_UI') && constant('JS_JQUERY_UI')) print '<script type="text/javascript" src="'.JS_JQUERY_UI.'jquery-ui.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1329  else print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/js/jquery-ui.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1330  if (! defined('DISABLE_JQUERY_TABLEDND')) print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/tablednd/jquery.tablednd.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1331  // jQuery jnotify
1332  if (empty($conf->global->MAIN_DISABLE_JQUERY_JNOTIFY) && ! defined('DISABLE_JQUERY_JNOTIFY'))
1333  {
1334  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jnotify/jquery.jnotify.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1335  }
1336  // Flot
1337  if (empty($conf->global->MAIN_DISABLE_JQUERY_FLOT) && ! defined('DISABLE_JQUERY_FLOT'))
1338  {
1339  if (constant('JS_JQUERY_FLOT'))
1340  {
1341  print '<script type="text/javascript" src="'.JS_JQUERY_FLOT.'jquery.flot.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1342  print '<script type="text/javascript" src="'.JS_JQUERY_FLOT.'jquery.flot.pie.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1343  print '<script type="text/javascript" src="'.JS_JQUERY_FLOT.'jquery.flot.stack.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1344  }
1345  else
1346  {
1347  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/flot/jquery.flot.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1348  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/flot/jquery.flot.pie.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1349  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/flot/jquery.flot.stack.min.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1350  }
1351  }
1352  // jQuery jeditable
1353  if (! empty($conf->global->MAIN_USE_JQUERY_JEDITABLE) && ! defined('DISABLE_JQUERY_JEDITABLE'))
1354  {
1355  print '<!-- JS to manage editInPlace feature -->'."\n";
1356  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1357  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-datepicker.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1358  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ui-autocomplete.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1359  print '<script type="text/javascript">'."\n";
1360  print 'var urlSaveInPlace = \''.DOL_URL_ROOT.'/core/ajax/saveinplace.php\';'."\n";
1361  print 'var urlLoadInPlace = \''.DOL_URL_ROOT.'/core/ajax/loadinplace.php\';'."\n";
1362  print 'var tooltipInPlace = \''.$langs->transnoentities('ClickToEdit').'\';'."\n"; // Added in title attribute of span
1363  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 ?
1364  print 'var cancelInPlace = \''.$langs->trans('Cancel').'\';'."\n";
1365  print 'var submitInPlace = \''.$langs->trans('Ok').'\';'."\n";
1366  print 'var indicatorInPlace = \'<img src="'.DOL_URL_ROOT."/theme/".$conf->theme."/img/working.gif".'">\';'."\n";
1367  print 'var withInPlace = 300;'; // width in pixel for default string edit
1368  print '</script>'."\n";
1369  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/editinplace.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1370  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/jeditable/jquery.jeditable.ckeditor.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1371  }
1372  // jQuery Timepicker
1373  if (! empty($conf->global->MAIN_USE_JQUERY_TIMEPICKER) || defined('REQUIRE_JQUERY_TIMEPICKER'))
1374  {
1375  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/timepicker/jquery-ui-timepicker-addon.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1376  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/timepicker.js.php?lang='.$langs->defaultlang.($ext?'&amp;'.$ext:'').'"></script>'."\n";
1377  }
1378  if (! defined('DISABLE_SELECT2') && (! empty($conf->global->MAIN_USE_JQUERY_MULTISELECT) || defined('REQUIRE_JQUERY_MULTISELECT'))) // jQuery plugin "mutiselect", "multiple-select", "select2", ...
1379  {
1380  $tmpplugin=empty($conf->global->MAIN_USE_JQUERY_MULTISELECT)?constant('REQUIRE_JQUERY_MULTISELECT'):$conf->global->MAIN_USE_JQUERY_MULTISELECT;
1381  print '<script type="text/javascript" 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
1382  }
1383  if (! defined('DISABLE_MULTISELECT')) // jQuery plugin "mutiselect" to select with checkboxes
1384  {
1385  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/includes/jquery/plugins/multiselect/jquery.multi-select.js'.($ext?'?'.$ext:'').'"></script>'."\n";
1386  }
1387  }
1388 
1389  if (! $disablejs && ! empty($conf->use_javascript_ajax))
1390  {
1391  // CKEditor
1392  if (! empty($conf->fckeditor->enabled) && (empty($conf->global->FCKEDITOR_EDITORNAME) || $conf->global->FCKEDITOR_EDITORNAME == 'ckeditor') && ! defined('DISABLE_CKEDITOR'))
1393  {
1394  print '<!-- Includes JS for CKEditor -->'."\n";
1395  $pathckeditor = DOL_URL_ROOT . '/includes/ckeditor/ckeditor/';
1396  $jsckeditor='ckeditor.js';
1397  if (constant('JS_CKEDITOR')) // To use external ckeditor 4 js lib
1398  {
1399  $pathckeditor=constant('JS_CKEDITOR');
1400  }
1401  print '<script type="text/javascript">';
1402  print 'var CKEDITOR_BASEPATH = \''.$pathckeditor.'\';'."\n";
1403  print 'var ckeditorConfig = \''.dol_buildpath($themesubdir.'/theme/'.$conf->theme.'/ckeditor/config.js'.($ext?'?'.$ext:''),1).'\';'."\n"; // $themesubdir='' in standard usage
1404  print 'var ckeditorFilebrowserBrowseUrl = \''.DOL_URL_ROOT.'/core/filemanagerdol/browser/default/browser.php?Connector='.DOL_URL_ROOT.'/core/filemanagerdol/connectors/php/connector.php\';'."\n";
1405  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";
1406  print '</script>'."\n";
1407  print '<script type="text/javascript" src="'.$pathckeditor.$jsckeditor.($ext?'?'.$ext:'').'"></script>'."\n";
1408  }
1409 
1410  // Browser notifications
1411  if (! defined('DISABLE_BROWSER_NOTIF'))
1412  {
1413  $enablebrowsernotif=false;
1414  if (! empty($conf->agenda->enabled) && ! empty($conf->global->AGENDA_REMINDER_BROWSER)) $enablebrowsernotif=true;
1415  if ($conf->browser->layout == 'phone') $enablebrowsernotif=false;
1416  if ($enablebrowsernotif)
1417  {
1418  print '<!-- Includes JS of Dolibarr (brwoser layout = '.$conf->browser->layout.')-->'."\n";
1419  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/lib_notification.js.php'.($ext?'?'.$ext:'').'"></script>'."\n";
1420  }
1421  }
1422 
1423  // Global js function
1424  print '<!-- Includes JS of Dolibarr -->'."\n";
1425  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/lib_head.js.php?lang='.$langs->defaultlang.($ext?'&'.$ext:'').'"></script>'."\n";
1426 
1427  // JS forced by modules (relative url starting with /)
1428  if (! empty($conf->modules_parts['js'])) // $conf->modules_parts['js'] is array('module'=>array('file1','file2'))
1429  {
1430  $arrayjs=(array) $conf->modules_parts['js'];
1431  foreach($arrayjs as $modjs => $filesjs)
1432  {
1433  $filesjs=(array) $filesjs; // To be sure filejs is an array
1434  foreach($filesjs as $jsfile)
1435  {
1436  // jsfile is a relative path
1437  print '<!-- Include JS added by module '.$modjs. '-->'."\n".'<script type="text/javascript" src="'.dol_buildpath($jsfile,1).'"></script>'."\n";
1438  }
1439  }
1440  }
1441  // JS forced by page in top_htmlhead (relative url starting with /)
1442  if (is_array($arrayofjs))
1443  {
1444  print '<!-- Includes JS added by page -->'."\n";
1445  foreach($arrayofjs as $jsfile)
1446  {
1447  if (preg_match('/^http/i',$jsfile))
1448  {
1449  print '<script type="text/javascript" src="'.$jsfile.'"></script>'."\n";
1450  }
1451  else
1452  {
1453  print '<script type="text/javascript" src="'.dol_buildpath($jsfile,1).'"></script>'."\n";
1454  }
1455  }
1456  }
1457  }
1458 
1459  if (! empty($head)) print $head."\n";
1460  if (! empty($conf->global->MAIN_HTML_HEADER)) print $conf->global->MAIN_HTML_HEADER."\n";
1461 
1462  print "</head>\n\n";
1463  }
1464 
1465  $conf->headerdone=1; // To tell header was output
1466 }
1467 
1468 
1485 function top_menu($head, $title='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $helppagename='')
1486 {
1487  global $user, $conf, $langs, $db;
1488  global $dolibarr_main_authentication, $dolibarr_main_demo;
1489  global $hookmanager,$menumanager;
1490 
1491  $searchform='';
1492  $bookmarks='';
1493 
1494  // Instantiate hooks of thirdparty module
1495  $hookmanager->initHooks(array('toprightmenu'));
1496 
1497  $toprightmenu='';
1498 
1499  // For backward compatibility with old modules
1500  if (empty($conf->headerdone))
1501  {
1502  top_htmlhead($head, $title, $disablejs, $disablehead, $arrayofjs, $arrayofcss);
1503  print '<body id="mainbody">';
1504  }
1505 
1506  /*
1507  * Top menu
1508  */
1509  if ((empty($conf->dol_hide_topmenu) || GETPOST('dol_invisible_topmenu','int')) && (! defined('NOREQUIREMENU') || ! constant('NOREQUIREMENU')))
1510  {
1511  print "\n".'<!-- Start top horizontal -->'."\n";
1512 
1513  print '<div class="side-nav-vert'.(GETPOST('dol_invisible_topmenu','int')?' hidden':'').'"><div id="id-top">'; // dol_invisible_topmenu differs from dol_hide_topmenu: dol_invisible_topmenu means we output menu but we make it invisible.
1514 
1515  // Show menu entries
1516  print '<div id="tmenu_tooltip'.(empty($conf->global->MAIN_MENU_INVERT)?'':'invert').'" class="tmenu">'."\n";
1517  $menumanager->atarget=$target;
1518  $menumanager->showmenu('top', array('searchform'=>$searchform, 'bookmarks'=>$bookmarks)); // This contains a \n
1519  print "</div>\n";
1520 
1521  // Define link to login card
1522  $appli=constant('DOL_APPLICATION_TITLE');
1523  if (! empty($conf->global->MAIN_APPLICATION_TITLE))
1524  {
1525  $appli=$conf->global->MAIN_APPLICATION_TITLE;
1526  if (preg_match('/\d\.\d/', $appli))
1527  {
1528  if (! preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) $appli.=" (".DOL_VERSION.")"; // If new title contains a version that is different than core
1529  }
1530  else $appli.=" ".DOL_VERSION;
1531  }
1532  else $appli.=" ".DOL_VERSION;
1533 
1534  if (! empty($conf->global->MAIN_FEATURES_LEVEL)) $appli.="<br>".$langs->trans("LevelOfFeature").': '.$conf->global->MAIN_FEATURES_LEVEL;
1535 
1536  $logouttext='';
1537  if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
1538  {
1539  //$logouthtmltext=$appli.'<br>';
1540  if ($_SESSION["dol_authmode"] != 'forceuser' && $_SESSION["dol_authmode"] != 'http')
1541  {
1542  $logouthtmltext.=$langs->trans("Logout").'<br>';
1543 
1544  $logouttext .='<a href="'.DOL_URL_ROOT.'/user/logout.php">';
1545  //$logouttext .= img_picto($langs->trans('Logout').":".$langs->trans('Logout'), 'logout_top.png', 'class="login"', 0, 0, 1);
1546  $logouttext .='<span class="fa fa-sign-out atoplogin"></span>';
1547  $logouttext .='</a>';
1548  }
1549  else
1550  {
1551  $logouthtmltext.=$langs->trans("NoLogoutProcessWithAuthMode",$_SESSION["dol_authmode"]);
1552  $logouttext .= img_picto($langs->trans('Logout').":".$langs->trans('Logout'), 'logout_top.png', 'class="login"', 0, 0, 1);
1553  }
1554  }
1555 
1556  print '<div class="login_block">'."\n";
1557 
1558  // Add login user link
1559  $toprightmenu.='<div class="login_block_user">';
1560 
1561  // Login name with photo and tooltip
1562  $mode=-1;
1563  $toprightmenu.='<div class="inline-block nowrap"><div class="inline-block login_block_elem login_block_elem_name" style="padding: 0px;">';
1564  $toprightmenu.=$user->getNomUrl($mode, '', 1, 0, 11, 0, ($user->firstname ? 'firstname' : -1),'atoplogin');
1565  $toprightmenu.='</div></div>';
1566 
1567  $toprightmenu.='</div>'."\n";
1568 
1569  $toprightmenu.='<div class="login_block_other">';
1570 
1571  // Execute hook printTopRightMenu (hooks should output string like '<div class="login"><a href="">mylink</a></div>')
1572  $parameters=array();
1573  $result=$hookmanager->executeHooks('printTopRightMenu',$parameters); // Note that $action and $object may have been modified by some hooks
1574  if (is_numeric($result))
1575  {
1576  if ($result == 0)
1577  $toprightmenu.=$hookmanager->resPrint; // add
1578  else
1579  $toprightmenu=$hookmanager->resPrint; // replace
1580  }
1581  else
1582  {
1583  $toprightmenu.=$result; // For backward compatibility
1584  }
1585 
1586  // Link to module builder
1587  if (! empty($conf->modulebuilder->enabled))
1588  {
1589  $text ='<a href="'.DOL_URL_ROOT.'/modulebuilder/index.php?mainmenu=home&leftmenu=admintools" target="_modulebuilder">';
1590  //$text.= img_picto(":".$langs->trans("ModuleBuilder"), 'printer_top.png', 'class="printer"');
1591  $text.='<span class="fa fa-bug atoplogin"></span>';
1592  $text.='</a>';
1593  $toprightmenu.=@Form::textwithtooltip('',$langs->trans("ModuleBuilder"),2,1,$text,'login_block_elem',2);
1594  }
1595 
1596  // Link to print main content area
1597  if (empty($conf->global->MAIN_PRINT_DISABLELINK) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && $conf->browser->layout != 'phone')
1598  {
1599  $qs=dol_escape_htmltag($_SERVER["QUERY_STRING"]);
1600 
1601  if (is_array($_POST))
1602  {
1603  foreach($_POST as $key=>$value) {
1604  if ($key!=='action' && $key!=='password' && !is_array($value)) $qs.='&'.$key.'='.urlencode($value);
1605  }
1606  }
1607  $qs.=(($qs && $morequerystring)?'&':'').$morequerystring;
1608  $text ='<a href="'.dol_escape_htmltag($_SERVER["PHP_SELF"]).'?'.$qs.($qs?'&':'').'optioncss=print" target="_blank">';
1609  //$text.= img_picto(":".$langs->trans("PrintContentArea"), 'printer_top.png', 'class="printer"');
1610  $text.='<span class="fa fa-print atoplogin"></span>';
1611  $text.='</a>';
1612  $toprightmenu.=@Form::textwithtooltip('',$langs->trans("PrintContentArea"),2,1,$text,'login_block_elem',2);
1613  }
1614 
1615  // Link to Dolibarr wiki pages
1616  if (empty($conf->global->MAIN_HELP_DISABLELINK) && empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
1617  {
1618  $langs->load("help");
1619 
1620  $helpbaseurl='';
1621  $helppage='';
1622  $mode='';
1623 
1624  if (empty($helppagename)) $helppagename='EN:User_documentation|FR:Documentation_utilisateur|ES:Documentación_usuarios';
1625 
1626  // Get helpbaseurl, helppage and mode from helppagename and langs
1627  $arrayres=getHelpParamFor($helppagename,$langs);
1628  $helpbaseurl=$arrayres['helpbaseurl'];
1629  $helppage=$arrayres['helppage'];
1630  $mode=$arrayres['mode'];
1631 
1632  // Link to help pages
1633  if ($helpbaseurl && $helppage)
1634  {
1635  $text='';
1636  if(!empty($conf->global->MAIN_SHOWDATABASENAMEINHELPPAGESLINK)) {
1637  $langs->load('admin');
1638  $appli .= '<br>' . $langs->trans("Database") . ': ' . $db->database_name;
1639  }
1640  $title=$appli.'<br>';
1641  $title.=$langs->trans($mode == 'wiki' ? 'GoToWikiHelpPage': 'GoToHelpPage');
1642  if ($mode == 'wiki') $title.=' - '.$langs->trans("PageWiki").' &quot;'.dol_escape_htmltag(strtr($helppage,'_',' ')).'&quot;';
1643  $text.='<a class="help" target="_blank" rel="noopener" href="';
1644  if ($mode == 'wiki') $text.=sprintf($helpbaseurl,urlencode(html_entity_decode($helppage)));
1645  else $text.=sprintf($helpbaseurl,$helppage);
1646  $text.='">';
1647  //$text.=img_picto('', 'helpdoc_top').' ';
1648  $text.='<span class="fa fa-question-circle atoplogin"></span>';
1649  //$toprightmenu.=$langs->trans($mode == 'wiki' ? 'OnlineHelp': 'Help');
1650  //if ($mode == 'wiki') $text.=' ('.dol_trunc(strtr($helppage,'_',' '),8).')';
1651  $text.='</a>';
1652  //$toprightmenu.='</div>'."\n";
1653  $toprightmenu.=@Form::textwithtooltip('',$title,2,1,$text,'login_block_elem',2);
1654  }
1655  }
1656 
1657  // Logout link
1658  $toprightmenu.=@Form::textwithtooltip('',$logouthtmltext,2,1,$logouttext,'login_block_elem',2);
1659 
1660  $toprightmenu.='</div>';
1661 
1662  print $toprightmenu;
1663 
1664  print "</div>\n"; // end div class="login_block"
1665 
1666  print '</div></div>';
1667 
1668  print '<div style="clear: both;"></div>';
1669  print "<!-- End top horizontal menu -->\n\n";
1670  }
1671 
1672  if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) print '<!-- Begin div id-container --><div id="id-container" class="id-container'.($morecss?' '.$morecss:'').'">';
1673 }
1674 
1675 
1690 function left_menu($menu_array_before, $helppagename='', $notused='', $menu_array_after='', $leftmenuwithoutmainarea=0, $title='', $acceptdelayedhtml=0)
1691 {
1692  global $user, $conf, $langs, $db, $form;
1693  global $hookmanager, $menumanager;
1694 
1695  $searchform='';
1696  $bookmarks='';
1697 
1698  if (! empty($menu_array_before)) 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);
1699 
1700  if (empty($conf->dol_hide_leftmenu) && (! defined('NOREQUIREMENU') || ! constant('NOREQUIREMENU')))
1701  {
1702  // Instantiate hooks of thirdparty module
1703  $hookmanager->initHooks(array('searchform','leftblock'));
1704 
1705  print "\n".'<!-- Begin side-nav id-left -->'."\n".'<div class="side-nav"><div id="id-left">'."\n";
1706 
1707  if ($conf->browser->layout == 'phone') $conf->global->MAIN_USE_OLD_SEARCH_FORM=1; // Select into select2 is awfull on smartphone. TODO Is this still true with select2 v4 ?
1708 
1709  print "\n";
1710 
1711  if (! is_object($form)) $form=new Form($db);
1712  $selected=-1;
1713  $usedbyinclude=1;
1714  include_once DOL_DOCUMENT_ROOT.'/core/ajax/selectsearchbox.php'; // This set $arrayresult
1715 
1716  if ($conf->use_javascript_ajax && empty($conf->global->MAIN_USE_OLD_SEARCH_FORM))
1717  {
1718  //$searchform.=$form->selectArrayAjax('searchselectcombo', DOL_URL_ROOT.'/core/ajax/selectsearchbox.php', $selected, '', '', 0, 1, 'vmenusearchselectcombo', 1, $langs->trans("Search"), 1);
1719  $searchform.=$form->selectArrayFilter('searchselectcombo', $arrayresult, $selected, '', 1, 0, (empty($conf->global->MAIN_SEARCHBOX_CONTENT_LOADED_BEFORE_KEY)?1:0), 'vmenusearchselectcombo', 1, $langs->trans("Search"), 1);
1720  }
1721  else
1722  {
1723  foreach($arrayresult as $key => $val)
1724  {
1725  //$searchform.=printSearchForm($val['url'], $val['url'], $val['label'], 'maxwidth100', 'sall', $val['shortcut'], 'searchleft', img_picto('',$val['img']));
1726  $searchform.=printSearchForm($val['url'], $val['url'], $val['label'], 'maxwidth125', 'sall', $val['shortcut'], 'searchleft', img_picto('', $val['img'], '', false, 1, 1));
1727  }
1728  }
1729 
1730  // Execute hook printSearchForm
1731  $parameters=array('searchform'=>$searchform);
1732  $reshook=$hookmanager->executeHooks('printSearchForm',$parameters); // Note that $action and $object may have been modified by some hooks
1733  if (empty($reshook))
1734  {
1735  $searchform.=$hookmanager->resPrint;
1736  }
1737  else $searchform=$hookmanager->resPrint;
1738 
1739  // Force special value for $searchform
1740  if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) || empty($conf->use_javascript_ajax))
1741  {
1742  $urltosearch=DOL_URL_ROOT.'/core/search_page.php?showtitlebefore=1';
1743  $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>';
1744  }
1745  elseif ($conf->use_javascript_ajax && ! empty($conf->global->MAIN_USE_OLD_SEARCH_FORM))
1746  {
1747  $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>';
1748  $searchform.='<script type="text/javascript">
1749  jQuery(document).ready(function () {
1750  jQuery("#divsearchforms1").click(function(){
1751  jQuery("#divsearchforms2").toggle();
1752  });
1753  });
1754  </script>' . "\n";
1755  $searchform.='</div>';
1756  }
1757 
1758  // Define $bookmarks
1759  if (! empty($conf->bookmark->enabled) && $user->rights->bookmark->lire)
1760  {
1761  include_once DOL_DOCUMENT_ROOT.'/bookmarks/bookmarks.lib.php';
1762  $langs->load("bookmarks");
1763 
1764  $bookmarks=printBookmarksList($db, $langs);
1765  }
1766 
1767  // Left column
1768  print '<!-- Begin left menu -->'."\n";
1769 
1770  print '<div class="vmenu"'.(empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)?'':' title="Left menu"').'>'."\n\n";
1771 
1772  // Show left menu with other forms
1773  $menumanager->menu_array = $menu_array_before;
1774  $menumanager->menu_array_after = $menu_array_after;
1775  $menumanager->showmenu('left', array('searchform'=>$searchform, 'bookmarks'=>$bookmarks)); // output menu_array and menu found in database
1776 
1777  // Dolibarr version + help + bug report link
1778  print "\n";
1779  print "<!-- Begin Help Block-->\n";
1780  print '<div id="blockvmenuhelp" class="blockvmenuhelp">'."\n";
1781 
1782  // Version
1783  if (empty($conf->global->MAIN_HIDE_VERSION)) // Version is already on help picto and on login page.
1784  {
1785  $doliurl='https://www.dolibarr.org';
1786  //local communities
1787  if (preg_match('/fr/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.fr';
1788  if (preg_match('/es/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.es';
1789  if (preg_match('/de/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.de';
1790  if (preg_match('/it/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.it';
1791  if (preg_match('/gr/i',$langs->defaultlang)) $doliurl='https://www.dolibarr.gr';
1792 
1793  $appli=constant('DOL_APPLICATION_TITLE');
1794  if (! empty($conf->global->MAIN_APPLICATION_TITLE))
1795  {
1796  $appli=$conf->global->MAIN_APPLICATION_TITLE; $doliurl='';
1797  if (preg_match('/\d\.\d/', $appli))
1798  {
1799  if (! preg_match('/'.preg_quote(DOL_VERSION).'/', $appli)) $appli.=" (".DOL_VERSION.")"; // If new title contains a version that is different than core
1800  }
1801  else $appli.=" ".DOL_VERSION;
1802  }
1803  else $appli.=" ".DOL_VERSION;
1804  print '<div id="blockvmenuhelpapp" class="blockvmenuhelp">';
1805  if ($doliurl) print '<a class="help" target="_blank" rel="noopener" href="'.$doliurl.'">';
1806  else print '<span class="help">';
1807  print $appli;
1808  if ($doliurl) print '</a>';
1809  else print '</span>';
1810  print '</div>'."\n";
1811  }
1812 
1813  // Link to bugtrack
1814  if (! empty($conf->global->MAIN_BUGTRACK_ENABLELINK))
1815  {
1816  require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
1817 
1818  $bugbaseurl = 'https://github.com/Dolibarr/dolibarr/issues/new';
1819  $bugbaseurl.= '?title=';
1820  $bugbaseurl.= urlencode("Bug: ");
1821  $bugbaseurl.= '&body=';
1822  $bugbaseurl.= urlencode("# Bug\n");
1823  $bugbaseurl.= urlencode("\n");
1824  $bugbaseurl.= urlencode("## Environment\n");
1825  $bugbaseurl.= urlencode("- **Version**: " . DOL_VERSION . "\n");
1826  $bugbaseurl.= urlencode("- **OS**: " . php_uname('s') . "\n");
1827  $bugbaseurl.= urlencode("- **Web server**: " . $_SERVER["SERVER_SOFTWARE"] . "\n");
1828  $bugbaseurl.= urlencode("- **PHP**: " . php_sapi_name() . ' ' . phpversion() . "\n");
1829  $bugbaseurl.= urlencode("- **Database**: " . $db::LABEL . ' ' . $db->getVersion() . "\n");
1830  $bugbaseurl.= urlencode("- **URL**: " . $_SERVER["REQUEST_URI"] . "\n");
1831  $bugbaseurl.= urlencode("\n");
1832  $bugbaseurl.= urlencode("## Report\n");
1833  print '<div id="blockvmenuhelpbugreport" class="blockvmenuhelp">';
1834  print '<a class="help" target="_blank" rel="noopener" href="'.$bugbaseurl.'">'.$langs->trans("FindBug").'</a>';
1835  print '</div>';
1836  }
1837 
1838  print "</div>\n";
1839  print "<!-- End Help Block-->\n";
1840  print "\n";
1841 
1842  print "</div>\n";
1843  print "<!-- End left menu -->\n";
1844  print "\n";
1845 
1846  // Execute hook printLeftBlock
1847  $parameters=array();
1848  $reshook=$hookmanager->executeHooks('printLeftBlock',$parameters); // Note that $action and $object may have been modified by some hooks
1849  print $hookmanager->resPrint;
1850 
1851  print '</div></div> <!-- End side-nav id-left -->'; // End div id="side-nav" div id="id-left"
1852  }
1853 
1854  print "\n";
1855  print '<!-- Begin right area -->'."\n";
1856 
1857  if (empty($leftmenuwithoutmainarea)) main_area($title);
1858 }
1859 
1860 
1867 function main_area($title='')
1868 {
1869  global $conf, $langs;
1870 
1871  if (empty($conf->dol_hide_leftmenu)) print '<div id="id-right">';
1872 
1873  print "\n";
1874 
1875  print '<!-- Begin div class="fiche" -->'."\n".'<div class="fiche">'."\n";
1876 
1877  if (! empty($conf->global->MAIN_ONLY_LOGIN_ALLOWED)) print info_admin($langs->trans("WarningYouAreInMaintenanceMode",$conf->global->MAIN_ONLY_LOGIN_ALLOWED));
1878 }
1879 
1880 
1888 function getHelpParamFor($helppagename,$langs)
1889 {
1890  $helpbaseurl='';
1891  $helppage='';
1892  $mode='';
1893 
1894  if (preg_match('/^http/i',$helppagename))
1895  {
1896  // If complete URL
1897  $helpbaseurl='%s';
1898  $helppage=$helppagename;
1899  $mode='local';
1900  }
1901  else
1902  {
1903  // If WIKI URL
1904  if (preg_match('/^es/i',$langs->defaultlang))
1905  {
1906  $helpbaseurl='http://wiki.dolibarr.org/index.php/%s';
1907  if (preg_match('/ES:([^|]+)/i',$helppagename,$reg)) $helppage=$reg[1];
1908  }
1909  if (preg_match('/^fr/i',$langs->defaultlang))
1910  {
1911  $helpbaseurl='http://wiki.dolibarr.org/index.php/%s';
1912  if (preg_match('/FR:([^|]+)/i',$helppagename,$reg)) $helppage=$reg[1];
1913  }
1914  if (empty($helppage)) // If help page not already found
1915  {
1916  $helpbaseurl='http://wiki.dolibarr.org/index.php/%s';
1917  if (preg_match('/EN:([^|]+)/i',$helppagename,$reg)) $helppage=$reg[1];
1918  }
1919  $mode='wiki';
1920  }
1921  return array('helpbaseurl'=>$helpbaseurl,'helppage'=>$helppage,'mode'=>$mode);
1922 }
1923 
1924 
1941 function printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey='', $prefhtmlinputname='',$img='', $showtitlebefore=0, $autofocus=0)
1942 {
1943  global $conf,$langs,$user;
1944 
1945  $ret='';
1946  $ret.='<form action="'.$urlaction.'" method="post" class="searchform">';
1947  $ret.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
1948  $ret.='<input type="hidden" name="mode" value="search">';
1949  $ret.='<input type="hidden" name="savelogin" value="'.dol_escape_htmltag($user->login).'">';
1950  if ($showtitlebefore) $ret.=$title.' ';
1951  $ret.='<input type="text" class="flat '.$htmlmorecss.'"';
1952  $ret.=' style="text-indent: 22px; background-image: url(\''.$img.'\'); background-repeat: no-repeat; background-position: 3px;"';
1953  $ret.=($accesskey?' accesskey="'.$accesskey.'"':'');
1954  $ret.=' placeholder="'.strip_tags($title).'"';
1955  $ret.=($autofocus?' autofocus':'');
1956  $ret.=' name="'.$htmlinputname.'" id="'.$prefhtmlinputname.$htmlinputname.'" />';
1957  //$ret.='<input type="submit" class="button" style="padding-top: 4px; padding-bottom: 4px; padding-left: 6px; padding-right: 6px" value="'.$langs->trans("Go").'">';
1958  $ret.='<button type="submit" class="button" style="padding-top: 4px; padding-bottom: 4px; padding-left: 6px; padding-right: 6px">';
1959  $ret.='<span class="fa fa-search"></span>';
1960  $ret.='</button>';
1961  $ret.="</form>\n";
1962  return $ret;
1963 }
1964 
1965 
1966 if (! function_exists("llxFooter"))
1967 {
1978  function llxFooter($comment='',$zone='private', $disabledoutputofmessages=0)
1979  {
1980  global $conf, $langs, $user, $object;
1981  global $delayedhtmlcontent;
1982  global $contextpage, $page, $limit;
1983 
1984  $ext='layout='.$conf->browser->layout.'&version='.urlencode(DOL_VERSION);
1985 
1986  // Global html output events ($mesgs, $errors, $warnings)
1987  dol_htmloutput_events($disabledoutputofmessages);
1988 
1989  // Code for search criteria persistence.
1990  // $user->lastsearch_values was set by the GETPOST when form field search_xxx exists
1991  if (is_object($user) && ! empty($user->lastsearch_values_tmp) && is_array($user->lastsearch_values_tmp))
1992  {
1993  // Clean and save data
1994  foreach($user->lastsearch_values_tmp as $key => $val)
1995  {
1996  unset($_SESSION['lastsearch_values_tmp_'.$key]); // Clean array to rebuild it just after
1997  if (count($val) && empty($_POST['button_removefilter'])) // If there is search criteria to save and we did not click on 'Clear filter' button
1998  {
1999  if (empty($val['sortfield'])) unset($val['sortfield']);
2000  if (empty($val['sortorder'])) unset($val['sortorder']);
2001  dol_syslog('Save lastsearch_values_tmp_'.$key.'='.json_encode($val, 0)." (systematic recording of last search criterias)");
2002  $_SESSION['lastsearch_values_tmp_'.$key]=json_encode($val);
2003  unset($_SESSION['lastsearch_values_'.$key]);
2004  }
2005  }
2006  }
2007 
2008 
2009  $relativepathstring = $_SERVER["PHP_SELF"];
2010  // Clean $relativepathstring
2011  if (constant('DOL_URL_ROOT')) $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'),'/').'/', '', $relativepathstring);
2012  $relativepathstring = preg_replace('/^\//', '', $relativepathstring);
2013  $relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
2014  if (preg_match('/list\.php$/', $relativepathstring))
2015  {
2016  unset($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]);
2017  unset($_SESSION['lastsearch_page_tmp_'.$relativepathstring]);
2018  unset($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]);
2019 
2020  if (! empty($contextpage)) $_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]=$contextpage;
2021  if (! empty($page) && $page > 1) $_SESSION['lastsearch_page_tmp_'.$relativepathstring]=$page;
2022  if (! empty($limit) && $limit != $conf->limit) $_SESSION['lastsearch_limit_tmp_'.$relativepathstring]=$limit;
2023 
2024  unset($_SESSION['lastsearch_contextpage_'.$relativepathstring]);
2025  unset($_SESSION['lastsearch_page_'.$relativepathstring]);
2026  unset($_SESSION['lastsearch_limit_'.$relativepathstring]);
2027  }
2028 
2029  // Core error message
2030  if (! empty($conf->global->MAIN_CORE_ERROR))
2031  {
2032  // Ajax version
2033  if ($conf->use_javascript_ajax)
2034  {
2035  $title = img_warning().' '.$langs->trans('CoreErrorTitle');
2036  print ajax_dialog($title, $langs->trans('CoreErrorMessage'));
2037  }
2038  // html version
2039  else
2040  {
2041  $msg = img_warning().' '.$langs->trans('CoreErrorMessage');
2042  print '<div class="error">'.$msg.'</div>';
2043  }
2044 
2045  //define("MAIN_CORE_ERROR",0); // Constant was defined and we can't change value of a constant
2046  }
2047 
2048  print "\n\n";
2049 
2050  print '</div> <!-- End div class="fiche" -->'."\n"; // End div fiche
2051 
2052  if (empty($conf->dol_hide_leftmenu)) print '</div> <!-- End div id-right -->'."\n"; // End div id-right
2053 
2054  if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) print '</div> <!-- End div id-container -->'."\n"; // End div container
2055 
2056  print "\n";
2057  if ($comment) print '<!-- '.$comment.' -->'."\n";
2058 
2059  printCommonFooter($zone);
2060 
2061  if (! empty($delayedhtmlcontent)) print $delayedhtmlcontent;
2062 
2063  if (! empty($conf->use_javascript_ajax))
2064  {
2065  print "\n".'<!-- Includes JS Footer of Dolibarr -->'."\n";
2066  print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/lib_foot.js.php?lang='.$langs->defaultlang.($ext?'&'.$ext:'').'"></script>'."\n";
2067  }
2068 
2069  // Wrapper to add log when clicking on download or preview
2070  if (! empty($conf->blockedlog->enabled) && is_object($object) && $object->id > 0 && $object->statut > 0)
2071  {
2072  if (in_array($object->element, array('facture'))) // Restrict for the moment to element 'facture'
2073  {
2074  print "\n<!-- JS CODE TO ENABLE log when making a download or a preview of a document -->\n";
2075  ?>
2076  <script type="text/javascript">
2077  jQuery(document).ready(function () {
2078  $('a.documentpreview').click(function() {
2079  $.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
2080  , {
2081  id:<?php echo $object->id; ?>
2082  , element:'<?php echo $object->element ?>'
2083  , action:'DOC_PREVIEW'
2084  }
2085  );
2086  });
2087  $('a.documentdownload').click(function() {
2088  $.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
2089  , {
2090  id:<?php echo $object->id; ?>
2091  , element:'<?php echo $object->element ?>'
2092  , action:'DOC_DOWNLOAD'
2093  }
2094  );
2095  });
2096  });
2097  </script>
2098  <?php
2099  }
2100  }
2101 
2102  // A div for the address popup
2103  print "\n<!-- A div to allow dialog popup -->\n";
2104  print '<div id="dialogforpopup" style="display: none;"></div>'."\n";
2105 
2106  print "</body>\n";
2107  print "</html>\n";
2108  }
2109 }
llxFooter()
Empty footer.
Definition: wrapper.php:56
GETPOST($paramname, $check='none', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
print
Draft customers invoices.
Definition: index.php:91
setEventMessages($mesg, $mesgs, $style='mesgs')
Set event messages in dol_events session object.
left_menu($menu_array_before, $helppagename='', $notused='', $menu_array_after='', $leftmenuwithoutmainarea=0, $title='', $acceptdelayedhtml=0)
Show left menu bar.
Definition: main.inc.php:1690
if(! defined('NOREQUIREMENU')) if(! function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
Definition: main.inc.php:1107
if(! empty($_SERVER['MAIN_SHOW_TUNING_INFO'])) if(function_exists('get_magic_quotes_gpc')) test_sql_and_script_inject($val, $type)
Security: SQL Injection and XSS Injection (scripts) protection (Filters on GET, POST, PHP_SELF).
Definition: main.inc.php:81
loadMenu($forcemainmenu='', $forceleftmenu='')
Load this->tabMenu.
Class to manage menu Auguria.
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:295
dol_print_error($db='', $error='', $errors=null)
Affiche message erreur system avec toutes les informations pour faciliter le diagnostic et la remonte...
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0)
Returns text escaped for inclusion in HTML alt or title tags, or into values of HTML input fields...
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0)
Show a message to say access is forbidden and stop program Calling this function terminate execution ...
Class to manage hooks.
Class to manage generation of HTML components Only common components must be here.
printBookmarksList($aDb, $aLangs)
Add area with bookmarks in menu.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='')
Write log message into outputs.
if(! function_exists('dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='')
Show information for admin users or standard users.
llxHeader()
Empty header.
Definition: wrapper.php:44
versioncompare($versionarray1, $versionarray2)
Compare 2 versions (stored into 2 arrays).
Definition: admin.lib.php:58
getBrowserInfo($user_agent)
Return information about user browser.
Class to manage translations.
if(GETPOST('cancel', 'alpha')) if(! GETPOST( 'confirmmassaction', 'alpha') &&$massaction !='presend' &&$massaction !='confirm_presend')
Draft customers invoices.
Definition: list.php:156
dol_now($mode='gmt')
Return date for now.
getHelpParamFor($helppagename, $langs)
Return helpbaseurl, helppage and mode.
Definition: main.inc.php:1888
top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $disablejmobile=0, $disablenofollow=0)
Ouput html header of a page.
Definition: main.inc.php:1172
testSqlAndScriptInject($val, $type)
Security: SQL Injection and XSS Injection (scripts) protection (Filters on GET, POST, PHP_SELF).
Definition: main.inc.php:94
checkLoginPassEntity($usertotest, $passwordtotest, $entitytotest, $authmode)
Return a login if login/pass was successfull.
dol_hash($chain, $type='0')
Returns a hash of a string.
printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey='', $prefhtmlinputname='', $img='', $showtitlebefore=0, $autofocus=0)
Show a search area.
Definition: main.inc.php:1941
dol_htmlentities($string, $flags=null, $encoding='UTF-8', $double_encode=false)
Replace htmlentities functions.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=false, $srconly=0, $notitle=0, $alt='', $morecss='')
Show picto whatever it&#39;s its name (generic function)
main_area($title='')
Begin main area.
Definition: main.inc.php:1867
div float
Buy price without taxes.
Definition: style.css.php:564
top_menu($head, $title='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $helppagename='')
Show an HTML header + a BODY + The top menu bar.
Definition: main.inc.php:1485
Class to manage triggers.
analyseVarsForSqlAndScriptsInjection(&$var, $type)
Return true if security check on parameters are OK, false otherwise.
Definition: main.inc.php:157
textwithtooltip($text, $htmltext, $tooltipon=1, $direction=0, $img='', $extracss='', $notabs=2, $incbefore='', $noencodehtmltext=0, $tooltiptrigger='', $forcenowrap=0)
Show a text and picto with tooltip on text or picto.