Test Failed
Push — master ( d56fde...b8c830 )
by Alxarafe
37:54
created

left_menu()   D

Complexity

Conditions 32

Size

Total Lines 168
Code Lines 98

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 32
eloc 98
nop 7
dl 0
loc 168
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* Copyright (C) 2002-2007  Rodolphe Quiedeville    <[email protected]>
3
 * Copyright (C) 2003       Xavier Dutoit           <[email protected]>
4
 * Copyright (C) 2004-2015  Laurent Destailleur     <[email protected]>
5
 * Copyright (C) 2004       Sebastien Di Cintio     <[email protected]>
6
 * Copyright (C) 2004       Benoit Mortier          <[email protected]>
7
 * Copyright (C) 2005-2015  Regis Houssin           <[email protected]>
8
 * Copyright (C) 2011-2014  Philippe Grand          <[email protected]>
9
 * Copyright (C) 2008       Matteli
10
 * Copyright (C) 2011-2016  Juanjo Menent           <[email protected]>
11
 * Copyright (C) 2012       Christophe Battarel     <[email protected]>
12
 * Copyright (C) 2014-2015  Marcos García           <[email protected]>
13
 * Copyright (C) 2015       Raphaël Doursenaud      <[email protected]>
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
29
/**
30
 *	\file       htdocs/main.inc.php
31
 *	\ingroup	core
32
 *	\brief      File that defines environment for Dolibarr GUI pages only (file not required by scripts)
33
 */
34
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);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for set_magic_quotes_runtime(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

67
		/** @scrutinizer ignore-unhandled */ @set_magic_quotes_runtime(0);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Deprecated Code introduced by
The function set_magic_quotes_runtime() has been deprecated: 5.3.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

67
		@/** @scrutinizer ignore-deprecated */ set_magic_quotes_runtime(0);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
68
	}
69
}
70
71
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps
72
/**
73
 * Security: SQL Injection and XSS Injection (scripts) protection (Filters on GET, POST, PHP_SELF).
74
 *
75
 * @param       string      $val        Value
76
 * @param       string      $type       1=GET, 0=POST, 2=PHP_SELF, 3=GET without sql reserved keywords (the less tolerant test)
77
 * @return      int                     >0 if there is an injection, 0 if none
78
 * @deprecated                          use testSqlAndScriptInject
79
 * @see testSqlAndScriptInject($val, $type)
80
 */
81
function test_sql_and_script_inject($val, $type)
82
{
83
    // phpcs:enable
84
    return testSqlAndScriptInject($val, $type);
85
}
86
87
/**
88
 * Security: SQL Injection and XSS Injection (scripts) protection (Filters on GET, POST, PHP_SELF).
89
 *
90
 * @param		string		$val		Value
91
 * @param		string		$type		1=GET, 0=POST, 2=PHP_SELF, 3=GET without sql reserved keywords (the less tolerant test)
92
 * @return		int						>0 if there is an injection, 0 if none
93
 */
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
150
/**
151
 * Return true if security check on parameters are OK, false otherwise.
152
 *
153
 * @param		string			$var		Variable name
154
 * @param		string			$type		1=GET, 0=POST, 2=PHP_SELF
155
 * @return		boolean|null				true if there is no injection. Stop code if injection found.
156
 */
157
function analyseVarsForSqlAndScriptsInjection(&$var, $type)
158
{
159
	if (is_array($var))
160
	{
161
		foreach ($var as $key => $value)	// Warning, $key may also be used for attacks
162
		{
163
			if (analyseVarsForSqlAndScriptsInjection($key, $type) && analyseVarsForSqlAndScriptsInjection($value, $type))
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;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
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
{
204
	analyseVarsForSqlAndScriptsInjection($_POST,0);
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
	// roulement des jetons car cree a chaque appel
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
{
1051
	/**
1052
	 *	Show HTML header HTML + BODY + Top menu + left menu + DIV
1053
	 *
1054
	 * @param 	string 	$head				Optionnal head lines
1055
	 * @param 	string 	$title				HTML title
1056
	 * @param	string	$help_url			Url links to help page
1057
	 * 		                            	Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage
1058
	 *                                  	For other external page: http://server/url
1059
	 * @param	string	$target				Target to use on links
1060
	 * @param 	int    	$disablejs			More content into html header
1061
	 * @param 	int    	$disablehead		More content into html header
1062
	 * @param 	array  	$arrayofjs			Array of complementary js files
1063
	 * @param 	array  	$arrayofcss			Array of complementary css files
1064
	 * @param	string	$morequerystring	Query string to add to the link "print" to get same parameters (use only if autodetect fails)
1065
	 * @param   string  $morecssonbody      More CSS on body tag.
1066
	 * @param	string	$replacemainareaby	Replace call to main_area() by a print of this string
1067
	 * @return	void
1068
	 */
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
1100
/**
1101
 *  Show HTTP header
1102
 *
1103
 *  @param  string  $contenttype    Content type. For example, 'text/html'
1104
 *  @param	int		$forcenocache	Force disabling of cache for the page
1105
 *  @return	void
1106
 */
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
1158
/**
1159
 * Ouput html header of a page.
1160
 * This code is also duplicated into security2.lib.php::dol_loginfunction
1161
 *
1162
 * @param 	string 	$head			 Optionnal head lines
1163
 * @param 	string 	$title			 HTML title
1164
 * @param 	int    	$disablejs		 Disable js output
1165
 * @param 	int    	$disablehead	 Disable head output
1166
 * @param 	array  	$arrayofjs		 Array of complementary js files
1167
 * @param 	array  	$arrayofcss		 Array of complementary css files
1168
 * @param 	int    	$disablejmobile	 Disable jmobile (No more used)
1169
 * @param   int     $disablenofollow Disable no follow tag
1170
 * @return	void
1171
 */
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";
0 ignored issues
show
Bug introduced by
The constant JS_JQUERY_MIGRATE was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
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
1469
/**
1470
 *  Show an HTML header + a BODY + The top menu bar
1471
 *
1472
 *  @param      string	$head    			Lines in the HEAD
1473
 *  @param      string	$title   			Title of web page
1474
 *  @param      string	$target  			Target to use in menu links (Example: '' or '_top')
1475
 *	@param		int		$disablejs			Do not output links to js (Ex: qd fonction utilisee par sous formulaire Ajax)
1476
 *	@param		int		$disablehead		Do not output head section
1477
 *	@param		array	$arrayofjs			Array of js files to add in header
1478
 *	@param		array	$arrayofcss			Array of css files to add in header
1479
 *  @param		string	$morequerystring	Query string to add to the link "print" to get same parameters (use only if autodetect fails)
1480
 *  @param      string	$helppagename    	Name of wiki page for help ('' by default).
1481
 * 				     		                Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage
1482
 * 						                    For other external page: http://server/url
1483
 *  @return		void
1484
 */
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>';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $logouthtmltext does not exist. Did you maybe mean $logouttext?
Loading history...
1543
1544
				$logouttext .='<a accesskey="l" 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:'').'">';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $morecss seems to be never defined.
Loading history...
1673
}
1674
1675
1676
/**
1677
 *  Show left menu bar
1678
 *
1679
 *  @param  array	$menu_array_before 	       	Table of menu entries to show before entries of menu handler. This param is deprectaed and must be provided to ''.
1680
 *  @param  string	$helppagename    	       	Name of wiki page for help ('' by default).
1681
 * 				     		                   	Syntax is: For a wiki page: EN:EnglishPage|FR:FrenchPage|ES:SpanishPage
1682
 * 									         	For other external page: http://server/url
1683
 *  @param  string	$notused             		Deprecated. Used in past to add content into left menu. Hooks can be used now.
1684
 *  @param  array	$menu_array_after           Table of menu entries to show after entries of menu handler
1685
 *  @param  int		$leftmenuwithoutmainarea    Must be set to 1. 0 by default for backward compatibility with old modules.
1686
 *  @param  string	$title                      Title of web page
1687
 *  @param  string  $acceptdelayedhtml          1 if caller request to have html delayed content not returned but saved into global $delayedhtmlcontent (so caller can show it at end of page to avoid flash FOUC effect)
1688
 *  @return	void
1689
 */
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);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $arrayresult seems to be never defined.
Loading history...
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.'" 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
1861
/**
1862
 *  Begin main area
1863
 *
1864
 *  @param	string	$title		Title
1865
 *  @return	void
1866
 */
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
1881
/**
1882
 *  Return helpbaseurl, helppage and mode
1883
 *
1884
 *  @param	string		$helppagename		Page name ('EN:xxx,ES:eee,FR:fff...' or 'http://localpage')
1885
 *  @param  Translate	$langs				Language
1886
 *  @return	array		Array of help urls
1887
 */
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
1925
/**
1926
 *  Show a search area.
1927
 *  Used when the javascript quick search is not used.
1928
 *
1929
 *  @param  string	$urlaction          Url post
1930
 *  @param  string	$urlobject          Url of the link under the search box
1931
 *  @param  string	$title              Title search area
1932
 *  @param  string	$htmlmorecss        Add more css
1933
 *  @param  string	$htmlinputname      Field Name input form
1934
 *  @param	string	$accesskey			Accesskey
1935
 *  @param  string  $prefhtmlinputname  Complement for id to avoid multiple same id in the page
1936
 *  @param	string	$img				Image to use
1937
 *  @param	string	$showtitlebefore	Show title before input text instead of into placeholder. This can be set when output is dedicated for text browsers.
1938
 *  @return	string
1939
 */
1940
function printSearchForm($urlaction, $urlobject, $title, $htmlmorecss, $htmlinputname, $accesskey='', $prefhtmlinputname='',$img='', $showtitlebefore=0)
1941
{
1942
	global $conf,$langs,$user;
1943
1944
	$ret='';
1945
	$ret.='<form action="'.$urlaction.'" method="post" class="searchform">';
1946
	$ret.='<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
1947
	$ret.='<input type="hidden" name="mode" value="search">';
1948
	$ret.='<input type="hidden" name="savelogin" value="'.dol_escape_htmltag($user->login).'">';
1949
	if ($showtitlebefore) $ret.=$title.' ';
1950
	$ret.='<input type="text" class="flat '.$htmlmorecss.'"';
1951
	$ret.=' style="text-indent: 22px; background-image: url(\''.$img.'\'); background-repeat: no-repeat; background-position: 3px;"';
1952
	$ret.=($accesskey?' accesskey="'.$accesskey.'"':'');
1953
	$ret.=' placeholder="'.strip_tags($title).'"';
1954
	$ret.=' name="'.$htmlinputname.'" id="'.$prefhtmlinputname.$htmlinputname.'" />';
1955
	//$ret.='<input type="submit" class="button" style="padding-top: 4px; padding-bottom: 4px; padding-left: 6px; padding-right: 6px" value="'.$langs->trans("Go").'">';
1956
	$ret.='<button type="submit" class="button" style="padding-top: 4px; padding-bottom: 4px; padding-left: 6px; padding-right: 6px">';
1957
	$ret.='<span class="fa fa-search"></span>';
1958
	$ret.='</button>';
1959
	$ret.="</form>\n";
1960
	return $ret;
1961
}
1962
1963
1964
if (! function_exists("llxFooter"))
1965
{
1966
	/**
1967
	 * Show HTML footer
1968
	 * Close div /DIV class=fiche + /DIV id-right + /DIV id-container + /BODY + /HTML.
1969
	 * If global var $delayedhtmlcontent was filled, we output it just before closing the body.
1970
	 *
1971
	 * @param	string	$comment    				A text to add as HTML comment into HTML generated page
1972
	 * @param	string	$zone						'private' (for private pages) or 'public' (for public pages)
1973
	 * @param	int		$disabledoutputofmessages	Clear all messages stored into session without diplaying them
1974
	 * @return	void
1975
	 */
1976
	function llxFooter($comment='',$zone='private', $disabledoutputofmessages=0)
1977
	{
1978
		global $conf, $langs, $user, $object;
1979
		global $delayedhtmlcontent;
1980
		global $contextpage, $page, $limit;
1981
1982
		$ext='layout='.$conf->browser->layout.'&version='.urlencode(DOL_VERSION);
1983
1984
		// Global html output events ($mesgs, $errors, $warnings)
1985
		dol_htmloutput_events($disabledoutputofmessages);
1986
1987
		// Code for search criteria persistence.
1988
		// $user->lastsearch_values was set by the GETPOST when form field search_xxx exists
1989
		if (is_object($user) && ! empty($user->lastsearch_values_tmp) && is_array($user->lastsearch_values_tmp))
1990
		{
1991
			// Clean and save data
1992
			foreach($user->lastsearch_values_tmp as $key => $val)
1993
			{
1994
				unset($_SESSION['lastsearch_values_tmp_'.$key]);			// Clean array to rebuild it just after
1995
				if (count($val) && empty($_POST['button_removefilter']))	// If there is search criteria to save and we did not click on 'Clear filter' button
1996
				{
1997
					if (empty($val['sortfield'])) unset($val['sortfield']);
1998
					if (empty($val['sortorder'])) unset($val['sortorder']);
1999
					dol_syslog('Save lastsearch_values_tmp_'.$key.'='.json_encode($val, 0)." (systematic recording of last search criterias)");
2000
					$_SESSION['lastsearch_values_tmp_'.$key]=json_encode($val);
2001
					unset($_SESSION['lastsearch_values_'.$key]);
2002
				}
2003
			}
2004
		}
2005
2006
2007
		$relativepathstring = $_SERVER["PHP_SELF"];
2008
		// Clean $relativepathstring
2009
		if (constant('DOL_URL_ROOT')) $relativepathstring = preg_replace('/^'.preg_quote(constant('DOL_URL_ROOT'),'/').'/', '', $relativepathstring);
2010
		$relativepathstring = preg_replace('/^\//', '', $relativepathstring);
2011
		$relativepathstring = preg_replace('/^custom\//', '', $relativepathstring);
2012
		if (preg_match('/list\.php$/', $relativepathstring))
2013
		{
2014
			unset($_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]);
2015
			unset($_SESSION['lastsearch_page_tmp_'.$relativepathstring]);
2016
			unset($_SESSION['lastsearch_limit_tmp_'.$relativepathstring]);
2017
2018
			if (! empty($contextpage))                     $_SESSION['lastsearch_contextpage_tmp_'.$relativepathstring]=$contextpage;
2019
			if (! empty($page) && $page > 1)               $_SESSION['lastsearch_page_tmp_'.$relativepathstring]=$page;
2020
			if (! empty($limit) && $limit != $conf->limit) $_SESSION['lastsearch_limit_tmp_'.$relativepathstring]=$limit;
2021
2022
			unset($_SESSION['lastsearch_contextpage_'.$relativepathstring]);
2023
			unset($_SESSION['lastsearch_page_'.$relativepathstring]);
2024
			unset($_SESSION['lastsearch_limit_'.$relativepathstring]);
2025
		}
2026
2027
		// Core error message
2028
		if (! empty($conf->global->MAIN_CORE_ERROR))
2029
		{
2030
			// Ajax version
2031
			if ($conf->use_javascript_ajax)
2032
			{
2033
				$title = img_warning().' '.$langs->trans('CoreErrorTitle');
2034
				print ajax_dialog($title, $langs->trans('CoreErrorMessage'));
0 ignored issues
show
Bug introduced by
Are you sure the usage of ajax_dialog($title, $lan...ns('CoreErrorMessage')) is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
2035
			}
2036
			// html version
2037
			else
2038
			{
2039
				$msg = img_warning().' '.$langs->trans('CoreErrorMessage');
2040
				print '<div class="error">'.$msg.'</div>';
2041
			}
2042
2043
			//define("MAIN_CORE_ERROR",0);      // Constant was defined and we can't change value of a constant
2044
		}
2045
2046
		print "\n\n";
2047
2048
		print '</div> <!-- End div class="fiche" -->'."\n"; // End div fiche
2049
2050
		if (empty($conf->dol_hide_leftmenu)) print '</div> <!-- End div id-right -->'."\n"; // End div id-right
2051
2052
		if (empty($conf->dol_hide_leftmenu) && empty($conf->dol_use_jmobile)) print '</div> <!-- End div id-container -->'."\n";	// End div container
2053
2054
		print "\n";
2055
		if ($comment) print '<!-- '.$comment.' -->'."\n";
2056
2057
		printCommonFooter($zone);
2058
2059
		if (! empty($delayedhtmlcontent)) print $delayedhtmlcontent;
2060
2061
		if (! empty($conf->use_javascript_ajax))
2062
		{
2063
			print "\n".'<!-- Includes JS Footer of Dolibarr -->'."\n";
2064
			print '<script type="text/javascript" src="'.DOL_URL_ROOT.'/core/js/lib_foot.js.php?lang='.$langs->defaultlang.($ext?'&'.$ext:'').'"></script>'."\n";
2065
		}
2066
2067
		// Wrapper to add log when clicking on download or preview
2068
		if (! empty($conf->blockedlog->enabled) && is_object($object) && $object->id > 0 && $object->statut > 0)
2069
		{
2070
			if (in_array($object->element, array('facture')))       // Restrict for the moment to element 'facture'
2071
			{
2072
				print "\n<!-- JS CODE TO ENABLE log when making a download or a preview of a document -->\n";
2073
				?>
2074
    			<script type="text/javascript">
2075
    			jQuery(document).ready(function () {
2076
    				$('a.documentpreview').click(function() {
2077
    					$.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
2078
    							, {
2079
    								id:<?php echo $object->id; ?>
2080
    								, element:'<?php echo $object->element ?>'
2081
    								, action:'DOC_PREVIEW'
2082
    							}
2083
    					);
2084
    				});
2085
    				$('a.documentdownload').click(function() {
2086
    					$.post('<?php echo DOL_URL_ROOT."/blockedlog/ajax/block-add.php" ?>'
2087
    							, {
2088
    								id:<?php echo $object->id; ?>
2089
    								, element:'<?php echo $object->element ?>'
2090
    								, action:'DOC_DOWNLOAD'
2091
    							}
2092
    					);
2093
    				});
2094
    			});
2095
    			</script>
2096
				<?php
2097
			}
2098
	   	}
2099
2100
		// A div for the address popup
2101
		print "\n<!-- A div to allow dialog popup -->\n";
2102
		print '<div id="dialogforpopup" style="display: none;"></div>'."\n";
2103
2104
		print "</body>\n";
2105
		print "</html>\n";
2106
	}
2107
}
2108